MATLAB: Pass class function handle to ode45()? - matlab

I have a class function that uses ODE45 to solve some equations. I have another, private class function that represents the odefunction that ODE45 needs to solve. However, I can't figure out how to pass a handle of the class's ode function to ODE45. Here is the sample code:
class ODESolver < handle
methods (Access = public)
function obj = RunODE(obj, t, y0)
[~, Z] = ode45(#ODEFunction, t, y0);
end
end
methods (Access = private)
function dy = ODEFunction(t,y)
% Calculate dy here.
end
end
end
When I run this, i get an error saying:
Undefined function 'ODEFunction' for input arguments of type 'double'.
If I move ODEFunction outside of the class and put it in its own *.m file, the code runs fine. I've also tried using "#obj.ODEFunction" in the ode45 call, but then it says:
Too many input arguments.
What's the best way to keep ODEFunction inside of my class and still be able to pass it's handle to ode45?

Your private ODEFunction is not a static method, so you should write:
classdef ODESolver < handle
methods (Access = public)
function obj = RunODE(obj, t, y0)
[~, Z] = ode45(#(tt, yy)obj.ODEFunction(tt, yy), t, y0);
end
end
methods (Access = private)
function dy = ODEFunction(obj, t,y)
dy = 0.1; % Calculate dy here.
end
end
end
NB: You also forgot to pass obj as first argument of private ODEFunction ... I'm writing example with static method and will paste it here once tested.
Edit
Here is how you should write things if you intented to have private static ODEFunction in your class:
classdef ODESolver < handle
methods (Access = public)
function obj = RunODE(obj, t, y0)
[~, Z] = ode45(#(tt, yy)ODESolver.ODEFunction(tt, yy), t, y0);
end
end
methods (Static, Access = private)
function dy = ODEFunction(t,y)
dy = 0.1; % Calculate dy here.
end
end
end

Related

The Secant Method: a variant of the Newton-Raphson method

I have to code the Secant Method: a variant of the Newton-Raphson method.
I have done the following:
function [SecantMethod] = SecantMethod(x0, x1);
%this is a variation on the Newton-Raphson MEthod, uses two inital guesses
%so that we do not have to explicitly work of the derivative of f(x).
x0 = 2;
x1 = 1;
%the two guesses
f0 = f(x0);
f1 = f(x1);
%two coressponding values of the function evaluated at x0 and x1
x = x1 - (f1*((x1 - x0)/(f1 - f0)));
%actual Secant Method (finds x axis intercept between two guesses
end
When I run the code in Matlab, an error appears "Undefined function or variable 'f'."
I dont have any particular function that I want to solve I just have to code it so I am not sure how to do so.
You can have a function take a function as an argument as follows:
function [SecantMethod] = SecantMethod(f,x0, x1);
disp(f(x0));
end
Then in your code:
%make anonymous function:
f=#(x)(x.^2);
%or:
f=#sin;
%and simply:
SecantMethod(f,1,2)
% or just:
SecantMethod(#myfucntion,1,2)

Calling a Function in Matlab with Symbolic Functions as Arguments

I have written the following Matlab function:
function EulerMethod(t_min,t_max,h,f,Y,yzero)
tlist = t_min:h:t_max;
N = (t_max - t_min)/h;
ylist = transpose(zeros(N+1,1));
ylist(1) = yzero;
for i=1:N
term = f(tlist(i),ylist(i))*h;
ylist(i+1) = ylist(i) + term;
end
yrange = Y(tlist);
% modified to generate a new figure window each time.
figure;
plot(tlist,yrange,'red','LineWidth', 2);
hold;
plot(tlist,ylist,'blue','LineWidth', 2);
plot(tlist, abs(yrange - ylist),'magenta','LineWidth', 2)
% modified to wrap the title.
title({'Graphs of the True Solution, Euler Solution,', 'and the Absolute Value of the Global Error (GE)'})
xlabel('t')
ylabel('Y(t)')
legend({'True Solution','Euler Solution', 'Absolute Value of the GE'},'Location','southwest')
end
I now try and call this function in another script. The variables f and Y in the function are symbolic functions; so, in the other file, I first declare these functions before calling this function. Here's the code:
clc
syms f(t,y)
syms Y(t)
f(t,y) = -y + 2.0*cos(t); %This the derivative of the function whose solution we're trying to computed
Y(t) = sin(t) + cos(t); %This is the true solution;
% Calling function
EulerMethod(0.0, 6.0, 0.2, f, Y, 1.0);
I, however, get errors when I run the second script. Can anyone help me figure out what's going wrong? I suspect this may be because of the way I have both input and used the symbolic functions f and Y but I am not sure.

Delete MATLAB subclass of graphics primitive

I'm trying to create a class similar to the Line object's class in MATLAB 2017b but having problem with the destructor. I want to achieve a similar behavior with other graphic objects that when deleted the handle is no longer referencing to that object, like in the following example:
>> l1 = line([0 1], [0 1]);
If the figure containing line l1 is now closed, the variable shows that l1 is referencing to a deleted object:
>> l1
l1 =
handle to deleted Line
I created the following class:
classdef circle < handle ...
& matlab.mixin.CustomDisplay & matlab.mixin.SetGet
properties
Center = [];
Color = [0 0.4470 0.7410];
Radius = [];
end
properties (SetAccess = 'protected')
LineHandle = [];
end
methods
function obj = circle(radius, center, varargin)
if nargin > 0
% assign property values
obj.Radius = radius;
obj.Center = center;
% generate plotting variables
phi = linspace(0, 2*pi, 90);
x = radius*cos(phi) + center(1);
y = radius*sin(phi) + center(2);
% draw circle
obj.LineHandle = line(x, y);
% create listeners in line object
obj.createListener;
% set variable properties
for k = 1:2:length(varargin)
% set superclass properties
if (isprop(obj.LineHandle, varargin{k}))
set(obj.LineHandle, varargin{k},varargin{k+1});
if (isprop(obj, varargin{k}))
set(obj, varargin{k}, varargin{k+1});
end
end
end
end
end
% listener to invoke delete if line is closed
function createListener(obj)
set(obj.LineHandle,'DeleteFcn',...
#obj.delete);
end
function delete(obj,varargin)
disp('deleted')
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% command to delete class ???
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
end
end
end
If the figure containing a circle object is closed, the line is deleted but the circle object still existst. Is there a way to also delete the reference to the circle object?
I found out the answer myself. The function just needs to have a different name than delete:
function delete_obj(obj, varargin)
% delete handle
delete(obj)
end

Matlab functions handles and variable and unknown number of outputs

With an anonymous function, you can return any number of outputs. What I need is to be able to use functors (anonymous functions as arguments of other functions), while not knowing how many outputs I will get.
This is to avoid code duplication by injecting functions calls inside a while loop which is reused in many functions.
Example:
function y = foo( x )
y = x;
end
function [y1, y2] = goo( x1, x2 )
y1 = x1;
y2 = x2;
end
function [ varargout ] = yolo( functor, varargin )
varargout = functor(varargin{:});
end
I want to be able to call:
y = yolo(#foo, 2)
[y1, y2] = yolo(#goo, 3, 4);
Is there any way to achieve this ?
Thanks
It is not possible to get the number of outputs of an anonymous function (a function handle to an inline function) because the output is always varargout and therefore nargout is always going to return -1
myfunc = #(x, y) x + y;
nargout(myfunc)
% -1
However, it looks like you don't have anonymous functions, but rather just function handles to normal functions that are defined in an .m file and have an explicit number of output arguments. In this case, you can combine nargout with {:} indexing to fill varargout with all of the output arguments.
function y = foo(x)
y = x;
end
function [y1, y2] = goo(x1, x2)
y1 = x1;
y2 = x2;
end
function varargout = yolo(functor, varargin)
[varargout{1:nargout(functor)}] = functor(varargin{:});
end
y = yolo(#foo, 2)
[y1, y2] = yolo(#goo, 3, 4)

Integrate function of two variables with respect to only one variable in matlab

I want to integrate a 1D function using quadgk but for a different value of a parameter which is contained inside the integrand. Is there an easy way to do this? Below hopefully illustrates my problem:
function [out] = integrand(x,t)
#Calculations
end
t = linspace(0,1,10);
q = quadgk(#integrand,0,Inf, OPT_PARAM = t); #Apply quadgk on integrand for each value in t
plot(t, q) # q is a function of t
Can you do it with a for loop?
function [out] = integrand(x,t)
%Calculations
end
t = linspace(0,1,10);
q = zeros(size(t)); % pre-allocate q
for k=1:length(t)
q(k) = quadgk(#(x)integrand(x,t(k)),0,Inf); %Apply quadgk on integrand for each value in t
end
plot(t, q) % q is a function of t
More details on parameterising functions at http://www.mathworks.co.uk/help/matlab/math/parameterizing-functions.html.