Matlab: link to variable, not variable value - matlab

It has been very difficult to use google, MATLAB documentation, I've spent a few hours, and I cannot learn how to
x = 1
y = x
x = 10
y
ans = 10
what happens instead is:
x = 1
y = x
x = 10
y
ans = 1
The value of x is stored into y. But I want to dynamically update the value of y to equal x.
What operation do I use to do this?
Thanks.M

Matlab is 99% a pass-by-value environment, which is what you have just demonstrated. The 1% which is pass-by-reference is handles, either handle graphics (not relevant here) or handle classes, which are pretty close to what you want.
To use a handle class to do what you describe, put the following into a file call RefValue.
classdef RefValue < handle
properties
data = [];
end
end
This creates a "handle" class, with a single property called "data".
Now you can try:
x = RefValue;
x.data = 1;
y = x;
x.data = 10;
disp(y.data) %Displays 10.

you can try something of the following;
x=10;
y='x'
y
y =
x
eval(y)
x =
10

You can also define an implicit handle on x by defining a function on y and referring to it:
x = 1;
y = #(x) x;
y(x) % displays 1
x = 10;
y(x) % displays 10

In MATLAB, this is not possible. However, there are many ways to get similar behavior. For example, you could have an array a = [1, 5, 3, 1] and then index it by x and y. For x = 2, you could assign a(x) = 7, y = x, and once you change a(x) = 4, a(y) == 4.
So indexing may be the fastest way to emulate references, but if you want some elegant solution, you could go through symbolic variables as #natan points out. What's important to take from this is that there are no pointers in MATLAB.

Related

How to use matlab to quickly judge whether a function is convex?

For example, FX = x ^ 2 + sin (x)
Just for curiosity, I don't want to use the CVX toolbox to do this.
You can check this within some interval [a,b] by checking if the second derivative is nonnegative. For this you have to define a vector of x-values, find the numerical second derivative and check whether it is not too negative:
a = 0;
b = 1;
margin = 1e-5;
point_count = 100;
f=#(x) x.^2 + sin(x);
x = linspace(a, b, point_count)
is_convex = all(diff(x, 2) > -margin);
Since this is a numerical test, you need to adjust the parameter to the properties of the function, that is if the function does wild things on a small scale we might not be able to pick it up. E.g. with the parameters above the test will falsely report the function f=#(x)sin(99.5*2*pi*x-3) as convex.
clear
syms x real
syms f(x) d(x) d1(x)
f = x^2 + sin(x)
d = diff(f,x,2)==0
d1 = diff(f,x,2)
expSolution = solve(d, x)
if size(expSolution,1) == 0
if eval(subs(d1,x,0))>0
disp("condition 1- the graph is concave upward");
else
disp("condition 2 - the graph is concave download");
end
else
disp("condition 3 -- not certain")
end

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);

Create a variable number of terms in an anonymous function that outputs a vector

I'd like to create an anonymous function that does something like this:
n = 5;
x = linspace(-4,4,1000);
f = #(x,a,b,n) a(1)*exp(b(1)^2*x.^2) + a(2)*exp(b(2)^2*x.^2) + ... a(n)*exp(b(n)^2*x.^2);
I can do this as such, without passing explicit parameter n:
f1 = #(x,a,b) a(1)*exp(-b(1)^2*x.^2);
for j = 2:n
f1 = #(x,a,b) f1(x,a,b) + a(j)*exp(b(j)^2*x.^2);
end
but it seems, well, kind of hacky. Does someone have a better solution for this? I'd like to know how someone else would treat this.
Your hacky solution is definitely not the best, as recursive function calls in MATLAB are not very efficient, and you can quickly run into the maximum recursion depth (500 by default).
You can introduce a new dimension along which you can sum up your arrays a and b. Assuming that x, a and b are row vectors:
f = #(x,a,b,n) a(1:n)*exp((b(1:n).^2).'*x.^2)
This will use the first dimension as summing dimension: (b(1:n).^2).' is a column vector, which produces a matrix when multiplied by x (this is a dyadic product, to be precise). The resulting n * length(x) matrix can be multiplied by a(1:n), since the latter is a matrix of size [1,n]. This vector-matrix product will also perform the summation for us.
Mini-proof:
n = 5;
x = linspace(-4,4,1000);
a = rand(1,10);
b = rand(1,10);
y = 0;
for k=1:n
y = y + a(k)*exp(b(k)^2*x.^2);
end
y2 = a(1:n)*exp((b(1:n).^2).'*x.^2); %'
all(abs(y-y2))<1e-10
The last command returns 1, so the two are essentially identical.

Custom-made linspace and logspace in MATLAB

I decided to take a look at two functions linspace and logspace. Below I give two examples, one using MATLAB's built-in linspace and one for logspace along with their hand made implementation. In the first case both the built-in function linspace and the handmade code give the same results. However, this is not true when examining the logspace function. Could you please help me to found the error in the handmade code?
a = 1; b = 5; n = 7;
y = linspace(1,5,7);
yy = zeros(1,n); yy(1) = a;
for i=2:n
yy(i) = yy(i-1) + (b-a)/(n-1);
end
x = logspace(1,5,7);
xx = zeros(1,n); xx(1) = 10^a;
for i=2:n
xx(i) = xx(i-1) + (10^b-10^a)/(n-1);
end
Thank you!
The only difference between linspace and logspace is that they go one step further and take the power of 10 for every element in the linspace array.
As such, you'd simply take your equation for linspace you generated, take the result and raise it to the power of 10. However, with your code, you are relying on the previous result and that is already raised to the power of 10. Therefore, you'll need to take the anti-log to convert the previous result back to a linear form, then use the same logic was used to generate the linspace, then raise it back to the power of 10. Therefore, the relationship is:
xx[n] = 10^(log10(xx[n-1]) + ((b-a)/(n-1)))
You can certainly simplify this, taking advantage of the fact that 10^(log10(z)) = z, as long as z > 0. We can also split up the terms in the power using the property that 10^(m + n) = (10^m) * (10^n). Therefore:
xx[n] = xx[n-1] * (10^((b-a)/(n-1)))
As such, simply take your previous result multiply with 10^((b-a)/(n-1))
a = 1; b = 5; n = 7;
x = logspace(1,5,7);
xx = zeros(1,n); xx(1) = 10^a;
for i=2:n
xx(i) = xx(i-1)*(10^((b-a)/(n-1))); %// Change
end
We get for both x and xx:
>> format long g;
>> x
x =
Columns 1 through 4
10 46.4158883361278 215.443469003188 1000
Columns 5 through 7
4641.58883361278 21544.3469003189 100000
>> xx
xx =
Columns 1 through 4
10 46.4158883361278 215.443469003188 1000
Columns 5 through 7
4641.58883361278 21544.3469003188 100000

Writen Convolution function in matlab giving trouble

Hey there, I've been having difficulty writing the matlab equivalent of the conv(x,y) function. I cant figure out why this gives the incorrect output. For the arrays
x1 = [1 2 1] and x2 = [3 1 1].
Here's what I have
x1 = [1 2 1];
x2 = [3 1 1];
x1len = leng(x1);
x2len = leng(x2);
len = x1len + x2len - 1;
x1 = zeros(1,len);
x2 = zeros(1,len);
buffer = zeros(1,len);
answer = zeros(1,len);
for n = 1:len
buffer(n) = x(n);
answer(n) = 0;
for i = 1:len
answer(n) = answer(n) + x(i) * buffer(i);
end
end
The matlab conv(x1,x2) gives 3 7 6 3 1 as the output but this is giving me 3 5 6 6 6 for answer.
Where have I gone wrong?
Also, sorry for the formatting I am on opera mini.
Aside from not having x defined, and having all zeroes for your variables x1, x2, buffer, and answer, I'm not certain why you have your nested loops set up like they are. I don't know why you need to reproduce the behavior of CONV this way, but here's how I would set up a nested for-loop solution:
X = [1 2 1];
Y = [3 1 1];
nX = length(X);
nY = length(Y);
nOutput = nX+nY-1;
output = zeros(1,nOutput);
for indexY = 1:nY
for indexX = 1:nX
indexOutput = indexY+indexX-1;
output(indexOutput) = output(indexOutput) + X(indexX)*Y(indexY);
end
end
However, since this is MATLAB, there are vectorized alternatives to looping in this way. One such solution is the following, which uses the functions SUM, SPDIAGS, and FLIPUD:
output = sum(spdiags(flipud(X(:))*Y));
In the code as given, all vectors are zeroed out before you start, except for x which is never defined. So it's hard to see exactly what you're getting at. But a couple of things to note:
In your inner for loop you are using values of buffer which have not yet been set by your outer loop.
The inner loop always covers the full range 1:len rather than shifting one vector relative to the other.
You might also want to think about "vectorizing" some of this rather than nesting for loops -- eg, your inner loop is just calculating a dot product, for which a perfectly good Matlab function already exists.
(Of course the same can be said for conv -- but I guess you're reimplementing either as homework or to understand how it works?)