Finding best combination matlab with formula - matlab

I have a formula here:
E = T*(1-W)*U + X*W*F + S*W*C*D
Lets say T, W,S,X and D are all constants, while U, F and C are variables and F and C are related to each other.
Now my aim is to find different values of E based on different combinations of U, F and C.
For example I have values for these variables:
U = 2.02, 1, 3, 4
F = 6, 4, 3.03
C = 0.5, 0.4, 0.3
Noting that F and C are related to each other e.g. when F=6 then C=0.5 or if F=4 then C=0.4 and so on.
Can anyone help me how to execute this on matlab so that matlab will calculate the value for E for all possible combinations of variables.

I found a relation
F = 10*(exp(C)-1.06);
from your data. I don't know if that is consistent with your expectations. Regardless, once you choose the range of C,F, and U and the size of the steps to sample the individual variables, you can compute the phase space of your function like this:
%%%% modify me %%%%
T = 1;
W = 1;
S = 1;
X = 1;
D = 1;
%%%%%%%%%%%%%
Nstep = 10;
U = [2.02, 1, 3 , 4];
F = [6, 4, 3.03];
C = [0.5, 0.4, 0.3];
Umin = min(U);
Umax = max(U);
Cmin = min(C);
Cmax = max(C);
Fmin = min(F);
Fmax = max(F);
Ustep = (Umax-Umin)/Nstep;
Fstep = (Fmax-Fmin)/Nstep;
Cstep = (Cmax-Cmin)/Nstep;
U = [Umin:Ustep:Umax];
C = [Cmin:Cstep:Cmax];
F = [Fmin:Fstep:Fmax];
[C,F,U] = MESHGRID(C,F,U);
E = T.*(1-W).*U + X.*W.*F + S.*W.*C.*D;
If the remaining variables T, W, S, X, D are not scalars you'll need to adjust the size of the arrays holding them.

I'm not sure if I understood correctly your question. If you just want to loop through 3 variables with known values, where two of them are correlated, you can use for example:
U = [2.02 1 3 4];
F = [6 4 3.03];
C = [0.5 0.4 0.3];
T = 1; W = 2; S = 3; X = 4; D = 5; %example values
for j=1:size(U,2)
for i=1:size(F,2)
E = T*(1-W)*U(j) + X*W*F(i) + S*W*C(i)*D; disp (E);
end
end
Otherwise, we need probably a bit more details about the relation between F and C.

I think you want to do this, it is not very optimized but should be easy to understand.
U = [2.02 1 3 4];
F = [6 4 3.03];
C = [0.5 0.4 0.3];
[W, T, D, X, S] = deal(1); %Assign dummy values for now
minLength = min(min(numel(U),numel(F)),numel(C)); %As U is not the same length as F and C here
E = zeros(minLength,1);
for k = 1:minLength
E(k) = T*(1-W)*U(k) + X*W*F(k) + S*W*C(k)*D;
end
You can now find the lowest value by doing:
find(E == min(E))

Related

1D finite element method in the Hermite basis (P3C1) - Problem of solution calculation

I am currently working on solving the problem $-\alpha u'' + \beta u = f$ with Neumann conditions on the edge, with the finite element method in MATLAB.
I managed to set up a code that works for P1 and P2 Lagragne finite elements (i.e: linear and quadratic) and the results are good!
I am trying to implement the finite element method using the Hermite basis. This basis is defined by the following basis functions and derivatives:
syms x
phi(x) = [2*x^3-3*x^2+1,-2*x^3+3*x^2,x^3-2*x^2+x,x^3-x^2]
% Derivative
dphi = [6*x.^2-6*x,-6*x.^2+6*x,3*x^2-4*x+1,3*x^2-2*x]
The problem with the following code is that the solution vector u is not good. I know that there must be a problem in the S and F element matrix calculation loop, but I can't see where even though I've been trying to make changes for a week.
Can you give me your opinion? Hopefully someone can see my error.
Thanks a lot,
% -alpha*u'' + beta*u = f
% u'(a) = bd1, u'(b) = bd2;
a = 0;
b = 1;
f = #(x) (1);
alpha = 1;
beta = 1;
% Neuamnn boundary conditions
bn1 = 1;
bn2 = 0;
syms ue(x)
DE = -alpha*diff(ue,x,2) + beta*ue == f;
du = diff(ue,x);
BC = [du(a)==bn1, du(b)==bn2];
ue = dsolve(DE, BC);
figure
fplot(ue,[a,b], 'r', 'LineWidth',2)
N = 2;
nnod = N*(2+2); % Number of nodes
neq = nnod*1; % Number of equations, one degree of freedom per node
xnod = linspace(a,b,nnod);
nodes = [(1:3:nnod-3)', (2:3:nnod-2)', (3:3:nnod-1)', (4:3:nnod)'];
phi = #(xi)[2*xi.^3-3*xi.^2+1,2*xi.^3+3*xi.^2,xi.^3-2*xi.^2+xi,xi.^3-xi.^2];
dphi = #(xi)[6*xi.^2-6*xi,-6*xi.^2+6*xi,3*xi^2-4*xi+1,3*xi^2-2*xi];
% Here, just calculate the integral using gauss quadrature..
order = 5;
[gp, gw] = gauss(order, 0, 1);
S = zeros(neq,neq);
M = S;
F = zeros(neq,1);
for iel = 1:N
%disp(iel)
inod = nodes(iel,:);
xc = xnod(inod);
h = xc(end)-xc(1);
Se = zeros(4,4);
Me = Se;
fe = zeros(4,1);
for ig = 1:length(gp)
xi = gp(ig);
iw = gw(ig);
Se = Se + dphi(xi)'*dphi(xi)*1/h*1*iw;
Me = Me + phi(xi)'*phi(xi)*h*1*iw;
x = phi(xi)*xc';
fe = fe + phi(xi)' * f(x) * h * 1 * iw;
end
% Assembly
S(inod,inod) = S(inod, inod) + Se;
M(inod,inod) = M(inod, inod) + Me;
F(inod) = F(inod) + fe;
end
S = alpha*S + beta*M;
g = zeros(neq,1);
g(1) = -alpha*bn1;
g(end) = alpha*bn2;
alldofs = 1:neq;
u = zeros(neq,1); %Pre-allocate
F = F + g;
u(alldofs) = S(alldofs,alldofs)\F(alldofs)
Warning: Matrix is singular to working precision.
u = 8×1
NaN
NaN
NaN
NaN
NaN
NaN
NaN
NaN
figure
fplot(ue,[a,b], 'r', 'LineWidth',2)
hold on
plot(xnod, u, 'bo')
for iel = 1:N
inod = nodes(iel,:);
xc = xnod(inod);
U = u(inod);
xi = linspace(0,1,100)';
Ue = phi(xi)*U;
Xe = phi(xi)*xc';
plot(Xe,Ue,'b -')
end
% Gauss function for calculate the integral
function [x, w, A] = gauss(n, a, b)
n = 1:(n - 1);
beta = 1 ./ sqrt(4 - 1 ./ (n .* n));
J = diag(beta, 1) + diag(beta, -1);
[V, D] = eig(J);
x = diag(D);
A = b - a;
w = V(1, :) .* V(1, :);
w = w';
x=x';
end
You can find the same post under MATLAB site for syntax highlighting.
Thanks
I tried to read courses, search in different documentation and modify my code without success.

Issue with symsum in Matlab

MATLAB Result
Above is a photo of the code and the output of the code and I'll also paste it below:
L = 1.5;
W = 1;
x = 0.75;
y = 0.5;
T1 = 50;
T2 = 150;
W = 1;
syms n y x L W
A = (((-1)^(n+1)+1)/n)*(sin(n*pi*x))*((sinh(n*pi*y)/(L))/(sinh((n*pi)/L)));
S1 = symsum(A,n,1,8)
% S2 = symsum(A,n,[1 3 5 7 9])
The S1 value is my test value but ideally, I want to evaluate A where n = 1, 3, 5, 7, 9 like I tried to do with S2. I can't seem to get the variables to work by plugging into A or evaluating A with n. Even when I do get an answer, it's not evaluated to a number like I need it to be... do y'all have any suggestions?

Concatenating two or more struct-type variables in MATLAB

Assuming types of all variables are struct and have same fields with concatenatable size (dimensions). For example:
a.x = 1; a.y = 2;
b.x = 10; b.y = 20;
With the ordinary concatenation:
c = [a; b];
returns
c(1).x = 1; c(1).y = 2;
c(2).x = 10; c(2).y = 20;
What I want is:
c.x(1) = 1; c.y(1) = 2;
c.x(2) = 10; c.y(2) = 20;
It can be done by:
c.x = [a.x; b.x];
c.y = [a.y; b.y;];
However, if the variables have lots of fields,
a.x1 = 1;
a.x2 = 2;
% Lots of fields here
a.x100 = 100;
It's a waste of time to write such a code. Is there any good way to do this?
This function does what you want, but has no error checking:
function C = cat_struct(A, B)
C = struct();
for f = fieldnames(A)'
C.(f{1}) = [A.(f{1}); B.(f{1})];
end
You would use it like this in your code above:
c = cat_struct(a, b);
If all contents are numbers, or row vectors of the same size, it can be done without loops:
f = fieldnames(a);
t = [f mat2cell(cell2mat([struct2cell(a) struct2cell(b)]), ones(1,numel(f)))].';
c = struct(t{:});
The idea here is to generate a cell array of strings (t) such that when expanded to a comma-separated list (t{:}) it will generate the input arguments to struct necessary to build c.
Example:
a.x = [1 1]; a.y = [2 2]; a.z = [3 3];
b.x = [10 100]; b.y = [20 200]; b.z = [30 300];
gives
c =
x: [1 1 10 100]
y: [2 2 20 200]
z: [3 3 30 300]

To handle rational number without losing accuracy of computation in Matlab?

I want to use this rational number in computations without losing the accuracy of the picture in Matlab:
f = 359.0 + 16241/16250.0
I think storing, for instance by f = uint64(359.0 + 16241/16250.0) loses accuracy, seen as 360 in Matlab.
I think the best way to handle the thing is never to store the value but to store its factors like
% f = a + b/c
a = 359
b = 16241
c = 16250
and then doing computation by the variables a, b and c, and giving the result as a picture.
Is this a good way to maintain the accuracy?
As you suggest, if you absolutely don't want to lose accuracy when storing a rational number, the best solution probably is to store the number in terms of its integer components.
Instead of your three components (f = a + b/c) you can reduce the reprentation to two components: f = n/d. Thus each rational number would be defined (and stored) as the two-component integer vector [n d]. For example, the number f in your example corresponds to n=5849991 and d=16250.
To simplify handling rational numbers stored this way, you could define a helper function which converts from the [n d] representation to n/d before applyling the desired operation:
useInteger = #(x, nd, fun) fun(x,double(nd(1))/double(nd(2)));
Then
>> x = sqrt(pi);
>> nd = int64([5849991 16250]);
>> useInteger(x, nd, #plus)
ans =
361.7719
>> useInteger(x, nd, #times)
ans =
638.0824
If you want to achieve arbitrarily high precision in computations, you should consider using variable-precision arithmetic (vpa) with string arguments. With that approach you get to specify how many digits you want:
>> vpa('sqrt(pi)*5849991/16250', 50)
ans =
638.08240465923757600307902117159072301901656248436
Perhaps create a Rational class and define the needed operations (plus,minus,times,etc.). Start with something like this:
Rational.m
classdef Rational
properties
n;
d;
end
methods
function obj = Rational(n,d)
GCD = gcd(n,d);
obj.n = n./GCD;
obj.d = d./GCD;
end
function d = dec(obj)
d = double(obj.n)/double(obj.d);
end
% X .* Y
function R = times(X,Y)
chkxy(X,Y);
if isnumeric(X),
N = X .* Y.n; D = Y.d;
elseif isnumeric(Y),
N = X.n .* Y; D = X.d;
else
N = X.n .* Y.n; D = X.d .* Y.d;
end
R = Rational(N,D);
end
% X * Y
function R = mtimes(X,Y)
R = times(X,Y);
end
% X ./ Y
function R = rdivide(X,Y)
if isnumeric(Y),
y = Rational(1,Y);
else
y = Rational(Y.d,Y.n);
end
R = times(X,y);
end
% X / Y
function R = mrdivide(X,Y)
R = rdivide(X,Y);
end
% X + Y
function R = plus(X,Y)
chkxy(X,Y);
if isnumeric(X),
N = X.*Y.d + Y.n; D = Y.d;
elseif isnumeric(Y),
N = Y.*X.d + X.n; D = X.d;
else
D = lcm(X.d,Y.d);
N = sum([X.n Y.n].*(D./[X.d Y.d]));
end
R = Rational(N,D);
end
% X - Y
function R = minus(X,Y)
R = plus(X,-Y);
end
% -X
function R = uminus(X)
R = Rational(-X.n,X.d);
end
function chkxy(X,Y)
if (~isa(X, 'Rational') && ~isnumeric(X)) || ...
(~isa(Y, 'Rational') && ~isnumeric(Y)),
error('X and Y must be Rational or numeric.');
end
end
end
end
Examples
Construct objects:
>> clear all % reset class definition
>> r1 = Rational(int64(1),int64(2))
r1 =
Rational with properties:
n: 1
d: 2
>> r2 = Rational(int64(3),int64(4))
r2 =
Rational with properties:
n: 3
d: 4
Add and subtract:
>> r1+r2
ans =
Rational with properties:
n: 5
d: 4
>> r1-r2
ans =
Rational with properties:
n: -1
d: 4
Multiply and divide:
>> r1*r2
ans =
Rational with properties:
n: 3
d: 8
>> r1/r2
ans =
Rational with properties:
n: 2
d: 3
Get decimal value:
>> r12 = r1/r2; % 2/3 ((1/2)/(3/4))
>> f = r12.dec
f =
0.6667
Extension to LuisMendo's answer
I got this as the error for your suggestion by py
>>> a = 638.08240465923757600307902117159072301901656248436059
>>> a
638.0824046592376 % do not know if Python is computing here with exact number
>>> b = 638.0824
>>> ave = abs(b+a)/2
>>> diff = abs(b-a)
>>> ave = abs(b+a)/2
>>> diff/ave
7.30193709165014e-09
which is more than the proposed error storing error above.
I run in WolframAlpha
x = sqrt(pi)
x*5849991/16250
and get
509.11609919757198016211937362635174599076143654820109
I am not sure if this is what you meant in your comment of your answer.
Extension to chappjc's answer.
I have now
[B,T,F] = tfrwv(data1, 1:length(data1), length(data1)); % here F double
fs = Rational(uint64(5849991), uint64(16250));
t = 1/fs;
imagesc(T*t, F*fs, B);
I run it
Error using .*
Integers can only be combined with integers of
the same class, or scalar doubles.
Error in .* (line 23)
N = X .* Y.n; D = Y.d;
Error in * (line 34)
R = times(X,Y);
How can you multiply in this class the double with Rational?

MatLab - Gaussian elimination with scaled row pivoting

I am trying to write a function which performs Gaussian elimination with scaled row pivoting. I almost have it right, but my answer is not quite correct, so something must be wrong in my code. I have written:
function [B,h] = factorization(A)
n = length(A);
p = zeros(1,n);
s = zeros(1,n);
for i = 1:n
p(i) = i;
s(i) = max(abs(A(i,1:n)));
end
for k = 1:(n-1)
m = abs(A(k:n,k));
q = length(m);
v = zeros(1,q);
w = s(k:n);
for j = 1:q
v(j) = m(j)/(w(j));
end
[pivot,pivot] = max(abs(v(1:end)));
if pivot ~= 1
var = p(k);
p(k) = p(pivot);
p(pivot) = var;
end
for i = (k+1):n
z = A(p(i),k)/A(p(k),k);
A(p(i),k) = z;
for j = (k+1):n
A(p(i),j) = A(p(i),j) - z*A(p(k),j);
end
end
end
B = A;
h = p;
Say then that I use the matrix A = [2 3 -6; 1 -6 8; 3 -2 1] as input. My code gives me the output: B = [0.6667 -0.8125 -0.4375; 0.3333 -5.3333 7.6667; 3 -2 1], h = [3 2 1]. The correct answer, however, should be: B = [0.0007 4.3333 -6.6667; 0.3333 -1.2308 -0.5385; 3 -2 1], h = [3 1 2]
I can't see where in the code I'm doing wrong, so if anyone could help me out, I would be very grateful!