How to iterate over functions? - matlab

I would like to apply loop over a function. I have the following "mother" code:
v = 1;
fun = #root;
x0 = [0,0]
options = optimset('MaxFunEvals',100000,'MaxIter', 10000 );
x = fsolve(fun,x0, options)
In addition, I have the following function in a separate file:
function D = root(x)
v = 1;
D(1) = x(1) + x(2) + v - 2;
D(2) = x(1) - x(2) + v - 1.8;
end
Now, I would like to find roots when v = sort(rand(1,1000)). In other words, I would like to iterate over function for each values of v.

You will need to modify root to accept an additional variable (v) and then change the function handle to root to an anonymous function which feeds in the v that you want
function D = root(x, v)
D(1) = x(1) + x(2) + v - 2;
D(2) = x(1) - x(2) + v - 1.8;
end
% Creates a function handle to root using a specific value of v
fun = #(x)root(x, v(k))

Just in case that equation is your actual equation (and not a dummy example): that equation is linear, meaning, you can solve it for all v with a simple mldivide:
v = sort(rand(1,1000));
x = [1 1; 1 -1] \ bsxfun(#plus, -v, [2; 1.8])
And, in case those are not your actual equations, you don't need to loop, you can vectorize the whole thing:
function x = solver()
options = optimset('Display' , 'off',...
'MaxFunEvals', 1e5,...
'MaxIter' , 1e4);
v = sort(rand(1, 1000));
x0 = repmat([0 0], numel(v), 1);
x = fsolve(#(x)root(x,v'), x0, options);
end
function D = root(x,v)
D = [x(:,1) + x(:,2) + v - 2
x(:,1) - x(:,2) + v - 1.8];
end
This may or may not be faster than looping, it depends on your actual equations.
It may be slower because fsolve will need to compute a Jacobian of 2000×2000 (4M elements), instead of 2×2, 1000 times (4k elements).
But, it may be faster because the startup cost of fsolve can be large, meaning, the overhead of many calls may in fact outweigh the cost of computing the larger Jacobian.
In any case, providing the Jacobian as a second output will speed everything up rather enormously:
function solver()
options = optimset('Display' , 'off',...
'MaxFunEvals', 1e5,...
'MaxIter' , 1e4,...
'Jacobian' , 'on');
v = sort(rand(1, 1000));
x0 = repmat([1 1], numel(v), 1);
x = fsolve(#(x)root(x,v'), x0, options);
end
function [D, J] = root(x,v)
% Jacobian is constant:
persistent J_out
if isempty(J_out)
one = speye(numel(v));
J_out = [+one +one
+one -one];
end
% Function values at x
D = [x(:,1) + x(:,2) + v - 2
x(:,1) - x(:,2) + v - 1.8];
% Jacobian at x:
J = J_out;
end

vvec = sort(rand(1,2));
x0 = [0,0];
for v = vvec,
fun = #(x) root(v, x);
options = optimset('MaxFunEvals',100000,'MaxIter', 10000 );
x = fsolve(fun, x0, options);
end
with function definition:
function D = root(v, x)
D(1) = x(1) + x(2) + v - 2;
D(2) = x(1) - x(2) + v - 1.8;
end

Related

Matlab newton method with finite differences

I would like some help with my program. I still don’t understand where my problem is, since it’s kind of a big mess. So it consists of the main program:
function x = NewtonM(funcF,JacF)
x= zeros(2,1);
x(1) = 1
x(2) = 5
k = 1;
kmax = 100;
TOL = 10^(-7);
while k < kmax
s = J(x)\(-F(x));
x= x + s
if (norm(s,2)< TOL)
break;
endif
end
and these are the fellow functions:
function y = F(x)
x1 = x(1);
x2 = x(2);
y = zeros(2,1);
y(1) = x1+x2-3;
y(2) = x1^2 + x2^2 -9;
end
function z = Z(x)
x1 = x(1);
x2 = x(2);
z = zeros(3,1);
z(1) = x1+x2-3+10^(-7);
z(2) = (x1+10^(-7))^2 + x2^2 -9;
z(3) = x1^2 + (x2+10^(-7))^2 -9;
end
function J = J(x)
x1 = x(1);
x2 = x(2);
J = zeros(2,2);
J(1,1) = (Z(1)-F(1))/(10^(-7))
J(1,2) = (Z(1)-F(1))/(10^(-7))
J(2,1) = (Z(2)-F(2))/(10^(-7))
J(2,2) = (Z(3)-F(2))/(10^(-7))
end
These are the error messages:
The problem is that you are calling both Z and F with only one input, in the function J.
Then, the first thing you do is try to interpret the input as a 2 valued array (x1,x2) but they don't exist, as you defined x as e.g. 1, by doing Z(1).
I wonder if instead of using Z(1) etc, you meant to do z=Z(x) and then use z(1), inside J.

Solving System of Second Order Ordinary Differential Equation in Matlab

Introduction
I am using Matlab to simulate some dynamic systems through numerically solving systems of Second Order Ordinary Differential Equations using ODE45. I found a great tutorial from Mathworks (link for tutorial at end) on how to do this.
In the tutorial the system of equations is explicit in x and y as shown below:
x''=-D(y) * x' * sqrt(x'^2 + y'^2)
y''=-D(y) * y' * sqrt(x'^2 + y'^2) + g(y)
Both equations above have form y'' = f(x, x', y, y')
Question
However, I am coming across systems of equations where the variables can not be solved for explicitly as shown in the example. For example one of the systems has the following set of 3 second order ordinary differential equations:
y double prime equation
y'' - .5*L*(x''*sin(x) + x'^2*cos(x) + (k/m)*y - g = 0
x double prime equation
.33*L^2*x'' - .5*L*y''sin(x) - .33*L^2*C*cos(x) + .5*g*L*sin(x) = 0
A single prime is first derivative
A double prime is second derivative
L, g, m, k, and C are given parameters.
How can Matlab be used to numerically solve a set of second order ordinary differential equations where second order can not be explicitly solved for?
Thanks!
Your second system has the form
a11*x'' + a12*y'' = f1(x,y,x',y')
a21*x'' + a22*y'' = f2(x,y,x',y')
which you can solve as a linear system
[x'', y''] = A\f
or in this case explicitly using Cramer's rule
x'' = ( a22*f1 - a12*f2 ) / (a11*a22 - a12*a21)
y'' accordingly.
I would strongly recommend leaving the intermediate variables in the code to reduce chances for typing errors and avoid multiple computation of the same expressions.
Code could look like this (untested)
function dz = odefunc(t,z)
x=z(1); dx=z(2); y=z(3); dy=z(4);
A = [ [-.5*L*sin(x), 1] ; [.33*L^2, -0.5*L*sin(x)] ]
b = [ [dx^2*cos(x) + (k/m)*y-g]; [-.33*L^2*C*cos(x) + .5*g*L*sin(x)] ]
d2 = A\b
dz = [ dx, d2(1), dy, d2(2) ]
end
Yes your method is correct!
I post the following code below:
%Rotating Pendulum Sym Main
clc
clear all;
%Define parameters
global M K L g C;
M = 1;
K = 25.6;
L = 1;
C = 1;
g = 9.8;
% define initial values for theta, thetad, del, deld
e_0 = 1;
ed_0 = 0;
theta_0 = 0;
thetad_0 = .5;
initialValues = [e_0, ed_0, theta_0, thetad_0];
% Set a timespan
t_initial = 0;
t_final = 36;
dt = .01;
N = (t_final - t_initial)/dt;
timeSpan = linspace(t_final, t_initial, N);
% Run ode45 to get z (theta, thetad, del, deld)
[t, z] = ode45(#RotSpngHndl, timeSpan, initialValues);
%initialize variables
e = zeros(N,1);
ed = zeros(N,1);
theta = zeros(N,1);
thetad = zeros(N,1);
T = zeros(N,1);
V = zeros(N,1);
x = zeros(N,1);
y = zeros(N,1);
for i = 1:N
e(i) = z(i, 1);
ed(i) = z(i, 2);
theta(i) = z(i, 3);
thetad(i) = z(i, 4);
T(i) = .5*M*(ed(i)^2 + (1/3)*L^2*C*sin(theta(i)) + (1/3)*L^2*thetad(i)^2 - L*ed(i)*thetad(i)*sin(theta(i)));
V(i) = -M*g*(e(i) + .5*L*cos(theta(i)));
E(i) = T(i) + V(i);
end
figure(1)
plot(t, T,'r');
hold on;
plot(t, V,'b');
plot(t,E,'y');
title('Energy');
xlabel('time(sec)');
legend('Kinetic Energy', 'Potential Energy', 'Total Energy');
Here is function handle file for ode45:
function dz = RotSpngHndl(~, z)
% Define Global Parameters
global M K L g C
A = [1, -.5*L*sin(z(3));
-.5*L*sin(z(3)), (1/3)*L^2];
b = [.5*L*z(4)^2*cos(z(3)) - (K/M)*z(1) + g;
(1/3)*L^2*C*cos(z(3)) + .5*g*L*sin(z(3))];
X = A\b;
% return column vector [ed; edd; ed; edd]
dz = [z(2);
X(1);
z(4);
X(2)];

The Fastest Method of Solving System of Non-linear Equations in MATLAB

Assume we have three equations:
eq1 = x1 + (x1 - x2) * t - X == 0;
eq2 = z1 + (z1 - z2) * t - Z == 0;
eq3 = ((X-x1)/a)^2 + ((Z-z1)/b)^2 - 1 == 0;
while six of known variables are:
a = 42 ;
b = 12 ;
x1 = 316190;
z1 = 234070;
x2 = 316190;
z2 = 234070;
So we are looking for three unknown variables that are:
X , Z and t
I wrote two method to solve it. But, since I need to run these code for 5.7 million data, it become really slow.
Method one (using "solve"):
tic
S = solve( eq1 , eq2 , eq3 , X , Z , t ,...
'ReturnConditions', true, 'Real', true);
toc
X = double(S.X(1))
Z = double(S.Z(1))
t = double(S.t(1))
results of method one:
X = 316190;
Z = 234060;
t = -2.9280;
Elapsed time is 0.770429 seconds.
Method two (using "fsolve"):
coeffs = [a,b,x1,x2,z1,z2]; % Known parameters
x0 = [ x2 ; z2 ; 1 ].'; % Initial values for iterations
f_d = #(x0) myfunc(x0,coeffs); % f_d considers x0 as variables
options = optimoptions('fsolve','Display','none');
tic
M = fsolve(f_d,x0,options);
toc
results of method two:
X = 316190; % X = M(1)
Z = 234060; % Z = M(2)
t = -2.9280; % t = M(3)
Elapsed time is 0.014 seconds.
Although, the second method is faster, but it still needs to be improved. Please let me know if you have a better solution for that. Thanks
* extra information:
if you are interested to know what those 3 equations are, the first two are equations of a line in 2D and the third equation is an ellipse equation. I need to find the intersection of the line with the ellipse. Obviously, we have two points as result. But, let's forget about the second answer for simplicity.
My suggestion it's to use the second approce,which it's the recommended by matlab for nonlinear equation system.
Declare a M-function
function Y=mysistem(X)
%X(1) = X
%X(2) = t
%X(3) = Z
a = 42 ;
b = 12 ;
x1 = 316190;
z1 = 234070;
x2 = 316190;
z2 = 234070;
Y(1,1) = x1 + (x1 - x2) * X(2) - X(1);
Y(2,1) = z1 + (z1 - z2) * X(2) - X(3);
Y(3,1) = ((X-x1)/a)^2 + ((Z-z1)/b)^2 - 1;
end
Then for solving use
x0 = [ x2 , z2 , 1 ];
M = fsolve(#mysistem,x0,options);
If you may want to reduce the default precision by changing StepTolerance (default 1e-6).
Also for more increare you may want to use the jacobian matrix for greater efficencies.
For more reference take a look in official documentation:
fsolve Nonlinear Equations with Analytic Jacobian
Basically giving the solver the Jacobian matrix of the system(and special options) you can increase method efficency.

Solving Multiple Equations For Repeated Times With Different Initial Conditions Matlab

I have the following set of values in an array.
a = [a(1) a(2) ... a(1907)]
Gamma(1)= (u*f(1))+(r*a(1))
u and r are constant and f(n) changes during each step and its initial value is f(1) = zero.
f(n) next values will be generated from solving these equations.
h(1) = x(1) + Gamma(1) for which x(1)=0 and in next steps is constant. (c)
Z(1)= constant(T) * h(1)
f(2) = constant(G) * Z(1)
These steps will repeated 1907 times. Any idea what should I do at all?
You can input your initial conditions into a very simple for loop.
% a, u, r, T, G are assumed available.
f = zeros(1908, 1);
Z = zeros(1907 ,1);
Gamma = zeros(1907, 1);
x = [0; c*ones(1906, 1)];
for ii = 1:1907
Gamma(ii) = u*f(ii) + r*a(ii);
h(ii) = x(ii) + Gamma(ii);
Z(ii) = T*h(ii);
f(ii+1) = G*Z(ii);
end

Implement Fitzhugh-Nagumo model via Crank-Nicolson

For a problem, I need to implement the Fitzhugh-Nagumo model with spatial diffusion via Crank-Nicolson's scheme. Now the problem lays withing the spatial diffusion.
(V_{t}) (DV_{xx} + V(V-a)(1-V) - W + I)
(W_{t}) (epsilon(V - b*W )
whereas DV_{xx} is the spatial diffusion.
Using Matlab, the following function can be given to i.e. an ODE45 solver. However it does not yet implement the spatial diffusion...
function dy = FHN( t, Y, D, a, b, eps, I )
V = Y(1);
W = Y(2);
dY = zeros(2,1);
% FHN-model w/o spatial diffusion
Vxx = 0;
dY(0) = D .* Vxx + V .* (V-a) .* (1-V) - W + I;
dY(1) = eps .* (V-b .* W);
The question: How to implement V_{xx} ?
Besides, what matrix shape does V need to be? Normally V is depending only on t, and is thus a [1 by t] vector. Now V is depending on both x as t, thus i would expect it to be a [x by y] vector, correct?
Thank you
It took long, but hey its not a normal everyday problem.
function f = FN( t, Y, dx, xend, D, a, b, eps, I )
% Fitzhug-Nagumo model with spatial diffusion.
% t = Tijd
% X = [V; W]
% dx = stepsize
% xend = Size van x
% Get the column vectors dV and dW from Y
V = Y( 1:xend/dx );
W = Y( xend/dx+1:end );
% Function
Vxx = (V([2:end 1])+V([end 1:end-1])-2*V)/dx^2;
dVdt = D*Vxx + V .* (V-a) .* (1-V) - W + I ;
dWdt = epsilon .* (V-b*W);
f = [dVdt ; dWdt];
Both V as W are column vectors with a size of 1:(xend/dx)
Method of calling:
V = zeros(xend/dx,1);
W = zeros(xend/dx,1);
% Start Boundaries
% V(x, 0) = 0.8 for 4 < x < 5
% V(x, 0) = 0.1 for 3 < x < 4
V( (4/dx+1):(5/dx-1) ) = 0.8;
V( (3/dx+1):(4/dx-1) ) = 0.1;
Y0 = [V; W];
t = 0:0.1:400;
options = '';
[T, Y] = ode45( #FN, t, Y0, options, dx, xend, D, a, b, eps, I );