I would like to implement a function duration = timer(n, f, arguments_of_f) that would measure how much time does a method f with arguments arguments_of_f need to run n times. My attempt was the following:
function duration = timer(n, f, arguments_of_f)
duration = 0;
for i=1:n
t0 = cputime;
f(arguments_of_f);
t1 = cputime;
duration += t1 - t0;
end
In another file, I have
function y = f(x)
y = x + 1;
end
The call d1 = timer(100, #f, 3); works as expected.
In another file, I have
function y = g(x1, x2)
y = x1 + x2;
end
but the call d2 = timer(100, #g, 1, 2); gives an error about undefined
argument x2, which is, when I look back, somehow expected, since I pass only
1 to g and 2 is never used.
So, how to implement the function timer in Octave, so that the call like
timer(4, #g, x1, ... , xK) would work? How can one pack the xs together?
So, I am looking for the analogue of Pythons *args trick:
def use_f(f, *args):
f(*args)
works if we define def f(x, y): return x + y and call use_f(f, 3, 4).
You don't need to pack all the arguments together, you just need to tell Octave that there is more than one argument coming and that they are all necessary. This is very easy to do using variadic arguments.
Your original implementation is nearly spot on: the necessary change is minimal. You need to change the variable arguments_to_f to the special name varargin, which is a magical cell array containing all your arbitrary undeclared arguments, and pass it with expansion instead of directly:
function duration = timer(n, f, varargin)
duration = 0;
for i=1:n
t0 = cputime;
f(varargin{:});
t1 = cputime;
duration += t1 - t0;
end
That's it. None of the other functions need to change.
Related
I have a simple model where I want to minimize the RMSE between my dependent variable y and my model values. The model is: y = alpha + beta'*x.
For minimization, I am using Matlab's fmincon function and am struggling with multiplying my parameter p(2) by x.
MWE:
% data
y = [5.072, 7.1588, 7.263, 4.255, 6.282, 6.9118, 4.044, 7.2595, 6.898, 4.8744, 6.5179, 7.3434, 5.4316, 3.38, 5.464, 5.90, 6.80, 6.193, 6.070, 5.737]
x = [18.3447, 79.86538, 85.09788, 10.5211, 44.4556, 69.567, 8.960, 86.197, 66.857, 16.875, 52.2697, 93.971, 24.35, 5.118, 25.126, 34.037, 61.4445, 42.704, 39.531, 29.988]
% initial values
p_initial = [0, 0];
% function: SEE BELOW
objective = #(p) sqrt(mean((y - y_mod(p)).^2));
% optimization
[param_opt, fval] = fmincon(objective, p_initial)
If I specify my function as follows then it works.
y_mod = #(p) p(1) + p(2).*x
However, it does not work if I use the following code. How can I multiply p(2) with x? Where x is not optimized, because the values are given.
function f = y_mod(p)
f = p(1) + p(2).*x
end
Here is the output from a script that has the function declaration:
>> modelFitExample2a
RMS Error=0.374, intercept=4.208, slope=0.0388
And here is code for the above. It has many commented lines because it includes alternate ways to fit the data: an inline declaration of y_mod(), or a multi-line declaration of y_mod(), or no y_mod() at all. This version uses the multi-line declaration of y_mod().
%modelFitExample2a.m WCR 2021-01-19
%Reply to stack exchange question on parameter fitting
clear;
global x %need this if define y_mod() separately, and in that case y_mod() must declare x global
% data
y = [5.0720, 7.1588, 7.2630, 4.2550, 6.2820, 6.9118, 4.0440, 7.2595, 6.8980, 4.8744...
6.5179, 7.3434, 5.4316, 3.3800, 5.4640, 5.9000, 6.8000, 6.1930, 6.0700, 5.7370];
x = [18.3447,79.8654,85.0979,10.5211,44.4556,69.5670, 8.9600,86.1970,66.8570,16.8750,...
52.2697,93.9710,24.3500, 5.1180,25.1260,34.0370,61.4445,42.7040,39.5310,29.9880];
% initial values
p_initial = [0, 0];
%predictive model with parameter p
%y_mod = #(p) p(1) + p(2)*x;
% objective function
%If you use y_mod(), then you must define it somewhere
objective = #(p) sqrt(mean((y - y_mod(p)).^2));
%objective = #(p) sqrt(mean((y-p(1)-p(2)*x).^2));
% optimization
options = optimset('Display','Notify');
[param_opt, fval] = fmincon(objective,p_initial,[],[],[],[],[],[],[],options);
% display results
fprintf('RMS Error=%.3f, intercept=%.3f, slope=%.4f\n',...
fval,param_opt(1),param_opt(2));
%function declaration: predictive model
%This is an alternative to the inline definition of y_mod() above.
function f = y_mod(p)
global x
f = p(1) + p(2)*x;
end
carl,
The second method, in which you declare y_mod() explicitly (at the end of your script, or in a separate file y_mod.m), does not work because y_mod() does not know what x is. Fix it by declaring x global in the main program at the top, and declare x global in y_mod().
%function declaration
function f = y_mod(p)
global x
f = p(1) + p(2)*x;
end
Of course you don't need y_mod() at all. The code also works if you use the following, and in this case, no global x is needed:
% objective function
objective = #(p) sqrt(mean((y-p(1)-p(2)*x).^2));
By the way, you don't need to multiply with .* in y_mod. You may use *, because you are multiplying a scalar by a vector.
I have a function that I want to solve with lsode, like that:
function f = fcn(x,t)
% Set spring stiffness and mass
k = 500;
m = 5;
% Assign function
f1 = x(2);
f2 = -(k/m)*x(1);
f = [f1; f2];
endfunction
And this is the script that call this function:
% Initial value
x0 = [0.2, 0];
%time
t = linspace(0,1,500);
[X] = lsode (#fcn, x0, t);
plot(t,X(:,1));
Now, I want to loop this script, but every time I want a different value of "k". The function to be solved with lsode must accept only "x" and "t" as argument, then I can't put "k" on the argument-list.
I can't use an anonymous function, because the real function that I'm studying is more complicated (not just a linear oscillator).
How to make a function func2(func1,t,y0) which receives another function func1 as an argument, but where func1 is a function that returns a 1D real(kind=8), dimension(:) array?
I have the following code written in Matlab, and I would like to write an equivalent one in Modern Fortran for speed and portability. I have written one for first order differential equations, but I'm struggling with the task of writing the code for a code for second and higher order differential equations because the external variable corresponding to differential equations must return an array with dimension(:). I want a code to be general purpose, i.e. I want a function or subroutine to which I can pass any differential equation.
The MatLab code is:
%---------------------------------------------------------------------------
clear all
close all
clc
t = [0:0.01:20]';
y0 = [2, 0]';
y = func_runge_kutta(#func_my_ode,t,y0);
function dy=func_my_ode(t,y)
% Second order differential equation y'' - (1-y^2)*y'+y = 0
dy = zeros(size(y));
dy(1) = y(2);
dy(2) = (1-y(1)^2)*y(2)-y(1);
end
function y = func_runge_kutta(func_my_ode,t,y0)
y = zeros(length(t),length(y0));
y(1,:) = y0';
for i=1:(length(t)-1)
h = t(i+1)-t(i);
F_1 = func_my_ode(t(i),y(i,:)');
F_2 = func_my_ode(t(i)+h/2,y(i,:)'+h/2*F_1);
F_3 = func_my_ode(t(i)+h/2,y(i,:)'+h/2*F_2);
F_4 = func_my_ode(t(i)+h,y(i,:)'+h*F_3);
y(i+1,:) = y(i,:)+h/6*(F_1+2*F_2+2*F_3+F_4)';
end
end
%---------------------------------------------------------------------------
If a function returns an array its interface must be explicit in the caller. The easiest way to achieve this for a dummy argument function is to use the PROCEDURE statement to clone the interface from a function that may be used as an actual argument. Starting with your code, translating to Fortran and adding declarations, we get:
module everything
use ISO_FORTRAN_ENV, only : wp => REAL64
implicit none
contains
function func_my_ode_1(t,y) result(dy)
! Second order differential equation y'' - (1-y**2)*y'+y = 0
real(wp) t
real(wp) y(:)
real(wp) dy(size(y))
dy(1) = y(2);
dy(2) = (1-y(1)**2)*y(2)-y(1);
end
function func_runge_kutta(func_my_ode,t,y0) result(y)
procedure(func_my_ode_1) func_my_ode
real(wp) t(:)
real(wp) y0(:)
real(wp) y(size(t),size(y0))
integer i
real(wp) h
real(wp) F_1(size(y0)),F_2(size(y0)),F_3(size(y0)),F_4(size(y0))
y(1,:) = y0;
do i=1,(size(t)-1)
h = t(i+1)-t(i);
F_1 = func_my_ode(t(i),y(i,:));
F_2 = func_my_ode(t(i)+h/2,y(i,:)+h/2*F_1);
F_3 = func_my_ode(t(i)+h/2,y(i,:)+h/2*F_2);
F_4 = func_my_ode(t(i)+h,y(i,:)+h*F_3);
y(i+1,:) = y(i,:)+h/6*(F_1+2*F_2+2*F_3+F_4);
end do
end
end module everything
program main
!clear all
!close all
!clc
use everything
implicit none
real(wp), allocatable :: t(:)
real(wp), allocatable :: y0(:)
real(wp), allocatable :: y(:,:)
integer i
integer iunit
t = [(0+0.01_wp*i,i=0,nint(20/0.01_wp))];
y0 = [2, 0];
y = func_runge_kutta(func_my_ode_1,t,y0);
open(newunit=iunit,file='rk4.txt',status='replace')
do i = 1,size(t)
write(iunit,*) t(i),y(i,1)
end do
end program main
I had Matlab read the data file and it plotted the same picture as the original Matlab program would have, had it plotted its results.
Please the following is my question.
I have two functions to be solved using Runge Kutta (Not ODE solver)
dy/dt=y*t/SUM
dz/dt=k*t^2/CP
My problem is I need to calculate CP and SUM by passing m1,N,N2,TP,W from a caller function (Caller function later used to call RK4 function outputs).
This was my solution
function f =fun1(t,Pdiff,m1,N,N2,TP,W)
x=m1/N % one of the calculations steps to obtain SUM
[K]= KIND(Pdiff(2),TP,N); %one of the calls made to calculate SUM
SUM=x/K;
dy/dt=y*t/SUM;
f=y*t/SUM;
The second function f=fun2(t,Pdiff,m1,N,N2,TP,W)
r=m1*N % one of the calculations steps to obtain CP
[K2]= KIND1(Pdiff(2),TP,N,W) %one of the calls made to calculate SUM
CP=K2/r;
dz/dt=k*t^2/CP % k is a constant
f=k*t^2/CP;
% note that Pdiff=[y z] and t is the independent variable
%These are then substituted into RK4 coefficients and solved with RK4 function:
function [t, Pdiff]=RK(t,Pdiff,m1,N,N2,TP,W);
k1 = h*fun1(t(I),Pdiff(I,:));
k2 = h*fun1(t(I)+0.5*h,Pdiff(I,:)+0.5*k1);
k3 = h*fun1(t(I)+0.5*h,Pdiff(I,:)+(0.5*(-1+sqrt(2)*k1))+(1-0.5*sqrt(2)*k2));
k4 = h*fun1(t(I)+h,Pdiff(I,:)-(0.5*(sqrt(2))*k2)+(1+0.5*sqrt(2))*k3);
k1 = h*fun1(t(I),Pdiff(I,:));
k2 = h*fun1(t(I)+0.5*h,Pdiff(I,:)+0.5*k1);
k3 = h*fun1(t(I)+0.5*h,Pdiff(I,:)+(0.5*(-1+sqrt(2)*k1))+(1-0.5*sqrt(2)*k2));
k4 = h*fun1(t(I)+h,Pdiff(I,:)-(0.5*(sqrt(2))*k2)+(1+0.5*sqrt(2))*k3);
Pdiff(I+1,kj) = Pdiff(I,1) + (k1 + (2-sqrt(2))*k2 + (2+sqrt(2))*k3 +k4)/6;
Pdiff(I+1,kj) = Pdiff(I,1) + (k1 + (2-sqrt(2))*k2 + (2+sqrt(2))*k3 +k4)/6;
My question is: Is it proper to pass parameters m1, N, N2, TP and W along with t,Pdiff in fun1 and fun2? Because I get error message
Not enough inputs in one of the calls.
Thank you.
I am new to Octave although I can say I am an expert Matlab user. I am running Octave on a Linux server (Red Hat) remotely through PuTTY, from a windows machine.
I am observing a very strange behavior in Octave. I call myfun(a) which performs as expected giving the sought results. Now, if I run, say, myfun(b) with b!=a, I get again myfun(a). Clear -f does not solve the problem. I need to reboot octave to change the parameters.
What am I doing wrong?
Thanks a lot
Francesco
This is the code for the function I mentioned:
function [a, v, obj, infos, iter] = mle_garch( p )
#{
% this function estimates the GARCH(1,1) parameters
% it is assumed we pass the adjusted price level p
#}
global y = (diff(log(p))-mean(diff(log(p))))*100;
global h = zeros(size(y));
a0 = [var(y)*0.9; 0.8; 0.1];
[a, obj, infos, iter] = sqp(a0, #loglike_garch, [], #loglike_con, [], [], 1000);
v = sqrt(h * 260);
endfunction
function g = loglike_garch( a )
global y h
n = length(y);
h(1) = var(y);
for i = 2 : n,
h(i) = a(1) + a(2) * h(i-1) + a(3) * y(i-1)^2;
endfor
g = 0.5 * ( sum(log(h)) + sum(y.^2./h) ) / n;
endfunction
function f = loglike_con( a )
f = [1;0;0;0] + [0 -1 -1;eye(3)] * a;
endfunction
I'm assuming the myfun you mentioned is mle_garch. The problem is the way you're initializing the global h and v variables (do you really need them to be global?). When you have a piece of code like this
global y = (diff(log(p))-mean(diff(log(p))))*100;
global h = zeros(size(y));
the values of y and h are defined the first time only. You can change their values later on, but this specific lines will never be ran again. Since your code only uses the input argument to define these two variables, the value which you use to run the function the first time will be used every single other time. If you really want to keep those variables global, replace it with the following:
global y;
global h;
y = (diff(log(p))-mean(diff(log(p))))*100;
h = zeros(size(y));
But I don't see any reason to keep them global so just don't make them global.
Also, you mentioned this code worked fine in Matlab. I was under the impression that you couldn't initialize global and persistent variables in Matlab which would make your code illegal in Matlab.