I want to find the local minimum of the function using loop.
Basically, the function has 2 choice variables say f(x,y).
But I want to find the minimum of f(x,y) with y values starting from 1,2,3...10 using for loop.
For example,
obj = #(x,y) x^2 + x*y + y^2
for i = 1:30
fminsearch(...)
end
but I am not sure how to use it correctly.
Can anyone help me with this issue?
Thanks in advance.
You can use a wrapper function:
obj = #(x,y) x^2 + x*y + y^2;
for i = 1:30
y_i = generate_ith_y_value(i);
fminsearch(#(x) obj(x,y_i), x0)
end
If you want to find the pair (x,y) so that obj(x,y) is a local minimum rather than finding the local minimum when y is a fixed value (like what you tried to do with for loop), then it's better to combine x and y into a single vector.
You can modify obj directly:
% x(1) = x, x(2) = y
obj = #(x) x(1)^2 + x(1)*x(2) + x(2)^2;
fminsearch(#(x) obj(x), [x0; y0])
If you can't modify obj directly, use a wrapper function that takes one input parameter and seperates it:
obj = #(x,y) x^2 + x*y + y^2;
% xx(1) = x, xx(2) = y
fminsearch(#(xx) obj(xx(1),xx(2)), [x0; y0])
Related
I am trying to plot and then to use it with Matlab
in an ODE as coefficient, the function
f : [2,500] -> [0,1],
But I don't know how to write the code for the definition of the function, since it is given on different subintervals.
Below is an example that uses anonymous functions/function handles. It uses each region/condition and evaluates the boundaries numerically and stores them into variables Bounds_1 and Bounds_2. These boundaries are then used to truncate each signal by multiplying each section of the piecewise function by its corresponding condition which is a logical array. It's also good to note that this plot will almost be seen as an impulse since the bounds are really small. Alternatively, you can probably achieve the same results using the built-in piecewise() function but I think this method gives a little more insight. As i increases you'll see a plot that resembles more and more of an impulse. To plot this for multiple values or i this can be run in a for-loop.
clc;
i = 3;
Bounds_1 = [i - (1/i^2),i];
Bounds_2 = [i,i + (1/i^2)];
Bounds = [Bounds_1 Bounds_2];
Min = min(Bounds);
Max = max(Bounds);
f1 = #(x) (i^2.*x - i^3 + 1).*(Bounds_1(1) < x & x <= Bounds_1(2));
f2 = #(x) (-i^2.*x + i^3 + 1).*(Bounds_2(1) < x & x <= Bounds_2(2));
f = #(x) f1(x) + f2(x);
fplot(f);
xlim([Min-2 Max+2]);
ylim([0 1.1]);
Here is another solution. You can specify the steps along the x-axis withxstep. With xlower and xupper you can specify the range of the x-axis:
figure ; hold on;
xlabel('x'); ylabel('f(x)');
for i= 2:500
[f,x] = myfunction(0.5,i);
plot (x,f,'DisplayName',sprintf('%i',i));
end
% legend
function [f,x]=myfunction(xstep,i)
%xstep: specifies steps for the x values
% specify max range x \in = [xlower -> xupper]
xlower = -10;
xupper = 600;
x2 = (i-1/i^2): xstep: i;
f2 = i^2*x2 - i^3 + 1;
x3 = i+xstep:xstep:(1+1/i^2);
f3 = -i^2*x3 + i^3 +1;
x1 = xlower:xstep:(i-1/i^2);
f1 = 0*x1;
x4 = (i+1/i^2):xstep:xupper;
f4 = 0*x4;
f = [f1,f2,f3,f4];
x = [x1,x2,x3,x4];
end
Here is what I get
Besides, I am not exactly sure what you mean with ODE (ordinary differential equation) in f(x). For me it seems like an algebraic equation.
I have a function like
f = #(x) x(1).^2 + x(2);
I want to draw its plot via surf, so I used meshgrid to generate input data:
[x, y] = meshgrid(-2:.2:2);
But if I try to pass it to the function like this
z = f([x; y])
I get just a single value in result.
Is there any way to do it except making a function that accepts two parameters (x, y) instead of a vector?
I think that you really do wany to make f take 2 parameters and I can't think of a good reason not to do it that way but this might be what you're after:
f = #(x) x(:,1).^2 + x(:,2)
Then you might need to call
z = f([x(:),y(:)])
After which you will probably need to call reshape on z so maybe reshape(z,size(x))
But I really think a 2 parameter function is a better way to go:
f2 = #(x1,x2)x1.^2 + x2
and now you can just go
z = f2(x,y)
Another way to go might be to use a wrapper function so if
f = #(x1,x2)x1.^2 + x2
but you really need a function that takes only one parameter then what about
f_wrapper = #(x) f(x{1},x{2}) %// using a cell array
or if you don't want to use a cell array then you could use a struct or a 3D array
f_wrapper = #(x) f(x.x1,x.x2) %// using structs
f_wrapper = #(x) f(x(:,:,1),x(:,:,2)) %// using a 3D matrix
Now you can use f_wrapper in something like fmincon after you package your x and y into a single variable so either a cell array, a struct or a 3D matrix. So for example if you are using the cell-array version above then try
inputVariable = {x,y}
So writing out the example in full
[x, y] = meshgrid(-2:.2:2);
f = #(x1,x2)x1.^2 + x2;
f_wrapper = #(x) f(x{1},x{2});
inputVar = {x,y};
z = f_wrapper(inputVar)
clear
f = #(x) (x(:,:,1) - 1).^2 + 5 * (x(:,:,2) - 1).^2;
[x, y] = meshgrid(-2:.05:2);
q(:,:,1)=x;
q(:,:,2)=y;
z = f(q);
surf(x,y,z)
I'm trying to vectorise this double for loop which calculates co-ordinates, so I've got
A = zeros(100,100);
for x = 1:100
for y = 1:100
A(x,y) = x^2 + y %or other functions with x and y
end
end
Though trying to vectorise it by using something like meshgrid like some examples I've seen gives me a whole load of errors like "Dimensions of matrices being concatenated are not consistent."
Is there a way to vectorise this? Thanks very much for the help.
I'm actually using
A = zeros(31,31);
for x = 1:31
for y = 1:31
A(y,x) = f(1.5, (x-16)/10 + i*((y-16)/10), 1000);
end
end
where f(1.5,...) is some other function I'm using to calculate the points of A which would output just a number.
Trying something like
A = zeros(31,31);
[X,Y] = ndgrid(1:31,1:31);
A(Y,X) = f(1.5, (X-16)/10 + i*((Y-16)/10), 1000);
Gives me:
Error using horzcat
Dimensions of matrices being concatenated are not consistent.
An error in f
Error in line 3:
A(Y,X) = f(1.5, (X-16)/10 + i*((Y-16)/10), 1000);
Let N = 100 be the datasize. You have few approaches here to play with.
Approach #1: bsxfun with built-in #plus
A = bsxfun(#plus,[1:N]'.^2,1:N)
Approach #2: bsxfun with anonymous function -
func = #(x,y) x.^2 + y
A = bsxfun(func,[1:N]',1:N)
For a general function with x and y, you can use ndgrid or meshgrid as discussed next.
Approach #3: With ndgrid -
[X,Y] = ndgrid(1:N,1:N);
A = X.^2 + Y
Approach #4: With meshgrid -
[Y,X] = meshgrid(1:N,1:N);
A = X.^2 + Y
I am trying to write a function that implements Newton's method in two dimensions and whilst I have done this, I have to now adjust my script so that the input parameters of my function must be f(x) in a column vector, the Jacobian matrix of f(x), the initial guess x0 and the tolerance where the function f(x) and its Jacobian matrix are in separate .m files.
As an example of a script I wrote that implements Newton's method, I have:
n=0; %initialize iteration counter
eps=1; %initialize error
x=[1;1]; %set starting value
%Computation loop
while eps>1e-10&n<100
g=[x(1)^2+x(2)^3-1;x(1)^4-x(2)^4+x(1)*x(2)]; %g(x)
eps=abs(g(1))+abs(g(2)); %error
Jg=[2*x(1),3*x(2)^2;4*x(1)^3+x(2),-4*x(2)^3+x(1)]; %Jacobian
y=x-Jg\g; %iterate
x=y; %update x
n=n+1; %counter+1
end
n,x,eps %display end values
So with this script, I had implemented the function and the Jacobian matrix into the actual script and I am struggling to work out how I can actually create a script with the input parameters required.
Thanks!
If you don't mind, I'd like to restructure your code so that it is more dynamic and more user friendly to read.
Let's start with some preliminaries. If you want to make your script truly dynamic, then I would recommend that you use the Symbolic Math Toolbox. This way, you can use MATLAB to tackle derivatives of functions for you. You first need to use the syms command, followed by any variable you want. This tells MATLAB that you are now going to treat this variable as "symbolic" (i.e. not a constant). Let's start with some basics:
syms x;
y = 2*x^2 + 6*x + 3;
dy = diff(y); % Derivative with respect to x. Should give 4*x + 6;
out = subs(y, 3); % The subs command will substitute all x's in y with the value 3
% This should give 2*(3^2) + 6*3 + 3 = 39
Because this is 2D, we're going to need 2D functions... so let's define x and y as variables. The way you call the subs command will be slightly different:
syms x, y; % Two variables now
z = 2*x*y^2 + 6*y + x;
dzx = diff(z, 'x'); % Differentiate with respect to x - Should give 2*y^2 + 1
dzy = diff(z, 'y'); % Differentiate with respect to y - Should give 4*x*y + 6
out = subs(z, {x, y}, [2, 3]); % For z, with variables x,y, substitute x = 2, y = 3
% Should give 56
One more thing... we can place equations into vectors or matrices and use subs to simultaneously substitute all values of x and y into each equation.
syms x, y;
z1 = 3*x + 6*y + 3;
z2 = 3*y + 4*y + 4;
f = [z1; z2];
out = subs(f, {x,y}, [2, 3]); % Produces a 2 x 1 vector with [27; 25]
We can do the same thing for matrices, but for brevity I won't show you how to do that. I will defer to the code and you can see it then.
Now that we have that established, let's tackle your code one piece at a time to truly make this dynamic. Your function requires the initial guess x0, the function f(x) as a column vector, the Jacobian matrix as a 2 x 2 matrix and the tolerance tol.
Before you run your script, you will need to generate your parameters:
syms x y; % Make x,y symbolic
f1 = x^2 + y^3 - 1; % Make your two equations (from your example)
f2 = x^4 - y^4 + x*y;
f = [f1; f2]; % f(x) vector
% Jacobian matrix
J = [diff(f1, 'x') diff(f1, 'y'); diff(f2, 'x') diff(f2, 'y')];
% Initial vector
x0 = [1; 1];
% Tolerance:
tol = 1e-10;
Now, make your script into a function:
% To run in MATLAB, do:
% [n, xout, tol] = Jacobian2D(f, J, x0, tol);
% disp('n = '); disp(n); disp('x = '); disp(xout); disp('tol = '); disp(tol);
function [n, xout, tol] = Jacobian2D(f, J, x0, tol)
% Just to be sure...
syms x, y;
% Initialize error
ep = 1; % Note: eps is a reserved keyword in MATLAB
% Initialize counter
n = 0;
% For the beginning of the loop
% Must transpose into a row vector as this is required by subs
xout = x0';
% Computation loop
while ep > tol && n < 100
g = subs(f, {x,y}, xout); %g(x)
ep = abs(g(1)) + abs(g(2)); %error
Jg = subs(J, {x,y}, xout); %Jacobian
yout = xout - Jg\g; %iterate
xout = yout; %update x
n = n + 1; %counter+1
end
% Transpose and convert back to number representation
xout = double(xout');
I should probably tell you that when you're doing computation using the Symbolic Math Toolbox, the data type of the numbers as you're calculating them are a sym object. You probably want to convert these back into real numbers and so you can use double to cast them back. However, if you leave them in the sym format, it displays your numbers as neat fractions if that's what you're looking for. Cast to double if you want the decimal point representation.
Now when you run this function, it should give you what you're looking for. I have not tested this code, but I'm pretty sure this will work.
Happy to answer any more questions you may have. Hope this helps.
Cheers!
I try to use contour to plot this function
3y + y^3 - x^3 = 5
I try contour(3*y+y^3-x^3-5) but it doesn't work.
How can I use contour to plot this function?
Are x and y properly defined as 2x2 matrices? If so then the "power" operator needs to be done on a component-wise basis (.^3 instead of ^3).
This works:
[x,y] = meshgrid(-2:.2:2,-2:.2:2);
contour(3*y+y.^3-x.^3-5)
Maybe you can try fcontour, which plots the contour lines of the function z = f(x,y) for constant levels of z over the default interval [-5 5] for x and y.
f = #(x,y) 3*y + y.^3 - x.^3 - 5;
fcontour(f)
Output:
I'm not convinced this addresses all parts of your question but it's a start. If you absolutely want contour to call a function, you can adjust my example to contour(X,Y,fh(X,Y)).
Better Approach
fh=#(x,y) 3*y + y.^3 - x.^3 -5; % <--- This is your function
x = (-4:.25:4)';
y = (-2:.25:2)';
[X,Y] = meshgrid(x,y);
Z = fh(X,Y);
contour(X,Y,fh(X,Y))
The Direct Approach (not preferred but works)
Notice the Z is transposed to make this work.
fh=#(x,y) 3*y + y.^3 - x.^3 -5; % <----this is your function
X = (-4:.25:4)';
Y = (-2:.25:2)';
Z = zeros(length(X),length(Y));
for i = 1:length(X)
for j = 1:length(Y)
xi = X(i);
yj = Y(j);
Z(i,j) = fh(xi,yj);
end
end
contour(X,Y,Z','LevelList',-60:10:60,'ShowText','on','LineWidth',1.4) % Fancied it up a bit