Use value of variable instead of its name lambdas matlab - matlab

How to use value of variable instead of its name during the description of a lambda expression? This is part of my code:
eq1 = k*x1+b==y1;
eq2 = k*x2+b==y2;
sol=solve([eq1,eq2],[k,b]);
linEq1 = #(x) sol.k*x+sol.b;
if (defY<linEq1(defX))
ineq = #(x,y) y<=sol.k*x+sol.b;
else
ineq = #(x,y) y>=sol.k*x+sol.b;
end
I need to use value of sol.b and sol.k in lambda expression instead of their names. When I use function which contains this code I can see in workspace:
y<=sol.k*x+sol.b
instead of
y<=5x+3
for example.

I tried to condense your code a bit. Please provide a minimal working example next time.
a = 5
b = 3
y = #(x) a*x + b % note that a and b are evaluated at definition
a = 4
y(1) % this is 8 (even though we changed the value of a)
% but if you really really want to do what you are asking, this is how:
eval(['y = #(x) ' num2str(a) '*x + ' num2str(b)]) % yields y = #(x)4*x+3

Related

Using Adams-Bashforth method in Matlab to solve Lorenz-System Equation

I am trying to use my second order Adams-Bashforth function here:
function [t,x] = Adams(f,t_max,x0,N)
h = t_max/N;
t = linspace(0,t_max,N+1);
x = zeros(2,N+1);
x(:,1) = x0;
x(:,2) = x0 + h.*(f(t(1),x(:,1)));
for i=2:N
x(:,i+1) = x(:,i) + h.*((3/2.*f(t(i),x(:,i))-(1/2).*f(t(i-1),x(:,i-1))));
end
end
In order to solve the Lorenz System Equation. However, whenever I try to call the function, I get an error.
sigma = 10;
beta = 8/3;
rho = 28;
f = #(t,a) [-sigma*a(1) + sigma*a(2); rho*a(1) - a(2) - a(1)*a(3); -beta*a(3) + a(1)*a(2)];
[t,a] = Adams(f,10,[1 1 1],100);
plot3(a(:,1),a(:,2),a(:,3))
Output:
"Unable to perform assignment because
the size of the left side is 2-by-1 and
the size of the right side is 1-by-3.
Error in Project>Adams (line 55)
x(:,1) = x0;"
Is the issue with my function, or with how I am calling my function? Any help would be appreciated.
in line 5 of your Adams function: x(:,1) = x0;
the input x0 is the initial conditions [1 1 1] a row vector of size [3x1], but x is an array of size zeros(2,N+1), or [2x101].
There are several mistakes here, the first you assign a row vector to a colon vector, not only that, but the size of the container in that first column of array x which is [2x1] , that is a different size than the size of x0. that is what the error tells you.
The function is buggy there , and it wont work unless you debug it according to the original intent of that method you are trying to implement.
note that also in the script f=#(t,... is expected to have an input t, but there is not t in the expression [-sigma*a(1) + sigma*a(2); rho*a(1) - a(2) - a(1)*a(3); -beta*a(3) + a(1)*a(2)];

Is there any way to define a variable from a formula depending on what variables are given?

Imagine you have the following formula:
a=4*b*c^2
Is there any way in Matlab to program this is in a way that the if 2 of 3 variables are provided, Matlab will solve and provide the missing one?
Because the only alternative I am seeing is using switch-case and solving the equation myself.
if isempty(a)
switchVar=1
elseif isempty(b)
switchVar=2;
else
switchVar=3;
end
switch switchVar
case 1
a=4*b*c^2;
case 2
b=a/4/c^2;
case 3
c=sqrt(a/4/b);
end
Thanky you very much in advance!
For a numeric (rather than symbolic) solution...
You can do this with some faffing around and anonymous functions. See the comments for details:
% For the target function: 0 = 4*b*c - a
% Let x = [a,b,c]
% Define the values we know about, i.e. not "c"
% You could put any values in for the known variables, and NaN for the unknown.
x0 = [5, 10, NaN];
% Define an index for the unknown, and then clear any NaNs
idx = isnan(x0);
x0(idx) = 0;
% Make sure we have 1 unknown
assert( nnz( idx ) == 1 );
% Define a function which handles which elements of "x"
% actually influence the equation
X = #(x,ii) ( x*idx(ii) + x0(ii)*(~idx(ii)) );
% Define the function to solve, 0 = 4*b*c - a = 4*x(2)*x(3)^2 - x(1) = ...
f = #(x) 4 * X(x,2) * X(x,3).^2 - X(x,1);
% Solve using fzero. Note this requires an initial guess
x0(idx) = fzero( f, 1 );
We can check these results are correct by plotting the function for a range of c values, and checking the intersection with the x-axis aligns to the output x0(3):
c = -1:0.01:1;
y = 4*x(2)*c.^2-x(1);
figure
hold on
plot(t,y);
plot(t,y.*0,'r');
plot(x0(3),0,'ok','markersize',10,'linewidth',2)
Note that there were 2 valid solutions, since this is a quadratic. The initial condition provided to fzero will largely dictate which solution is found.
Edit:
You can condense this down a bit with some tweaks to my earlier syntax:
% Define all initial conditions. This includes known variable values
% i.e. a = 5, b = 10
% As well as the initial guess for unknown variable values
% i.e. c = 1 (maybe? ish?)
x0 = [5, 10, 1];
% Specify the index of the unknown variable in x
idx = 3;
% Define the helper function which handles the influence of each variable
X = #(x,ii) x*(ii==idx) + x0(ii)*(ii~=idx);
% Define the function to solve, as before
f = #(x) 4 * X(x,2) * X(x,3).^2 - X(x,1);
% Solve
x0(idx) = fzero( f, x0(idx) )
This approach has the benefit that you can just change idx (and re-run the definition steps for X and f) to switch the variable of choice!
First, specify the given known variables
Then rewrite the equation as 0 = 4*b*c - a
Finally use solve to find the missing value
Code is as follows
syms a b c
% define known variable
a = 2; c = 5;
% equation rewritten
f = 4*b*c^2 - a == 0;
missing_value = solve(f);

Undefined function or variable

I have a simple function as below:
function dz = statespace(t,z)
dz = A*z + B*k*z
end
My main script is :
clear all;close all;format short;clc;
% step 1 -- input system parameters
% structure data
M1 = 1; M2= 1; M3= 1; %Lumped Mass(Tons)
M= diag([M1,M2,M3]);
k(1)= 980; k(2)= 980; k(3)= 980; %Stiffness Coefficient(KN/M)
K = zeros(3,3);
for i=1:2
K(i,i)=k(i)+k(i+1);
end
K(3,3)=k(3);
for i=1:2
K(i,i+1)=-k(i+1);
end
for i=2:3
K(i,i-1)=-k(i);
end %Stiffness Matrix(KN/M)
c(1)= 1.407; c(2)= 1.407; c(3)= 1.407; %Damping Coefficient(KN.sec/M)
C = zeros(3,3);
for i=1:2
C(i,i)=c(i)+c(i+1);
end
C(3,3)=c(3);
for i=1:2
C(i,i+1)=-c(i+1);
end
for i=2:3
C(i,i-1)=-c(i);
end %Damping Matrix(KN.sec/M)
A = [zeros(3) eye(3);-inv(M)*K -inv(M)*C]
H = [1;0;0]
B = [0;0;0;inv(M)*H]
k = [-1 -1 -1 -1 -1 -1]
t = 0:0.004:10;
[t,z] = ode45(statespace,t);
When I run my main script it comes with following error:
Undefined function or variable 'A'.
Error in statespace (line 2)
dz = A*z + B*k*z
As you can see I defined A in main script. Why this problem happening?
There multiple things wrong with your code. First, you need to supply the values of A and B to your function but as you are invoking it (incorrectly without the # and additional parameter y0 as I commented below) in the toolbox ode45, you have to keep just two parameters so you cannot supply A and B as additional parameters. If you define A and B within your function or share them via global variables you will get further. However, as noted below the definitions don't seem to be correct as A * z and B * k * z don't have the same dimensions. z is a scalar so B * k needs to be same size and shape as A which currently it is not.
Edit from:
As Jubobs suggested change your function's parameters to include A, B and k. Also you don't need t as it is never used in the function. So:
function dz = statespace(A, B, k, z)
dz = A*z + B*k*z
end
As others have pointed out, A, B and k are not defined in the function workspace, so you either need to define them again (ugly, not recommended), declare them as global variables (slightly better, but still not good practice), or pass them as arguments to your function (the better solution). However, because you then want to use the function with ode45, you need to be a bit careful with how you do it:
function dz = statespace(t,z,A,B,k)
dz = A*z + B*k*z
end
and then the call to ode45 would like this:
[t,z] = ode45(#(t,z)statespace(t,z,A,B,k),[0 Tf],z0); % where Tf is your final time and z0 your initial conditions
See Error using ode45 and deval for a similar problem.

How to call automatically symbolic variables in a loop in Matlab

Is there anyway to use a loop index to call symbolic variables in Matlab? For example, consider the following code whose goal is to store the symbolic expression "x1+x2+x3" in "y".
syms x1 x2 x3
y = 0;
for i = 1:3
y = y + xi;
end
The code does not work because on each iteration Matlab reads "y = y + xi" and returns the error "xi is undefined", instead of reading "y = y + x1", "y = y + x2" and "y = y + x3", is there anyway around this?
Thanks.
I'd suggest this, provided that you can create your numbered symbolic variable slightly differently:
x = sym('x',[1 3]); % or: syms x1 x2 x3; x = [x1 x2 x3];
y = x(1);
for i = 2:numel(x)
y = y+x(i);
end
Of course in this simple example, the entire for loop and everything else can be replaced with:
y = sum(sym('x',[1 3]));
See the documentation on sym for more details.
EDIT: Note that, as #pm89 points out, by allocating the 1-by-3 symbolic vector x, you of course won't have direct access to the symbolic variables x1,x2, and x3 in your workspace, but will have to index them as shown. This is similar to working with arrays or cells and has many of the same benefits as my second vectorized example illustrates.
If your Matlab does not support the matrix declaration of symbolics directly (as sym('x',[3 1])) you can write your own function for that:
function out = Matrix_Sym(name, size) %#ok<STOUT>
rows = size(1);
cols = size(2);
S = '';
for k1 = 1:rows
for k2 = 1:cols
if rows == 1
S = [S name int2str(k2) ' '];
elseif cols == 1
S = [S name int2str(k1) ' '];
else
S = [S name int2str(k1) int2str(k2) ' '];
end
end
end
eval(['syms ' S]);
eval (['out = reshape([' S '], [rows, cols]);']);
Then you could get the same result with:
x = Matrix_Sym('x', [3 1])
...

Using inline function with constant arguments in MATLAB

This is a part of my code.
clear all;
clc;
p = 50;
t = [-6 : 0.01 : 6];
f = inline('(t+2).*sin(t)', 't')
v = inline('3*f(p*t+2)','t','f','p')
plot(t,f(t));
v(t,f,p);
figure;
plot(t,v(t,f,p));
Here I have two questions.
Why I have to pass p into the function v even though p is a constant which has already declared ?
How I can get an expression for v completely in terms of t as 3*[(50*t+2)*sin(50*t+2)] or in its simplified form ?
Update
This is an update for the second question
Let
f(x) = 1 + x - x^2
g(x) = sin(x)
If I give f(g(x)), I wanna get the output in words, like this
f(g(x)) = (cos(X))^2 + sin(x)
not in numerical value. Is there any function capable to do that?
1) Why do I have to pass p to v even though p is a constant which has already been declared?
Well, a MATLAB's inline function object has an eval wrapper, so the only variables in its scope are those which were automatically captured from the expression or explicitly specified.
In other words, if you want v to recognize p, you have no other option but declaring it when creating the inline object and passing it to v explicitly. The same goes for f as well!
2) How I can get an expression for v completely in terms of t as 3*[(50*t+2)*sin(50*t+2)] or in its simplified form?
Use anonymous functions, like Shai suggested. They are more powerful, more elegant and much faster. For instance:
v = #(t)(3*(50*t+2)*sin(50*t+2))
Note that if you use a name, which is already in use by a variable, as an argument, the anonymous function will treat it as an argument first. It does see other variables in the scope, so doing something like g = #(x)(x + p) is also possible.
EDIT #1:
Here's another example, this time a function of a function:
x = 1:5;
f = #(x)(x .^ 3); %// Here x is a local variable, not as defined above
g = #(x)(x + 2); %// Here x is also a local variable
result = f(g(x));
or alternatively define yet another function that implements that:
h = #(x)f(g(x)); %// Same result as h = #(x)((x + 2) .^ 3)
result = h(x);
The output should be the same.
EDIT #2:
If you want to make an anonymous function out of the expression string, concatenate the '#(x)' (or the correct anonymous header, as you see fit) to the beginning and apply eval, for example:
expr = '(x + 2) .^ 3';
f = eval(['#(x)', expr]) %// Same result as f = #(x)((x + 2) .^ 3)
Note that you can also do char(f) to convert it back into a string, but you'll have to manually get rid of the '#(...)' part.
EDIT #3:
If you're looking for a different solution, you can explore the Symbolic Toolbox. For example, try:
syms x
f(x) = x + 2
g(x) = x ^ 3
or can also use sym, like so:
f(x) = sym('x + 2');
g(x) = sym('x ^ 3');
Use subs to substitute values and evaluate the symbolic expression.
How about using anonymous functions:
p = 50;
t = -6:0.01:6;
f = #(x) (x+2).*sin(x);
v = #(x) 3*f(p*x+2);
figure;
subplot(1,2,1); plot( t, f(t) ); title('f(t)');
subplot(1,2,2); plot( t, v(t) ); title('v(t)');
Is this what you wanted?
Adding a constant into an inline can be done during its definition.
Instead of
p = 50;
v = inline('3*f(p*t+2)','t','f','p')
You can write
p = 50;
v = inline( sprintf('3*f(%f*t+2)', p), 't','f')