Calling Octave interpolation function within function body - function

I'm trying to wrap Octave interpolation function in a function body,
function FUN = inter(p);
FUN = interpn (x1, x2, x3, x4, x5, A, p(1), p(2), p(3), p(4), p(5), "spline");
end
The reason why I'm doing this is because I'm using a package which function needs a string name function which would be in this case packageFunction("inter", argument1);
The issue is calling now for instance like,
disp("value = "), inter([10 2 4 3 4])
doesn't work; Doesn't see the vectors error: 'x1' undefined ,
Of course the vectors xi and matrix A are defined above the function body. Would appreciate advice on this,
thanks, Damir
------------- in file example1.m
[a b c] = fminuit('gaussian','mnplot',[10 166 33],[x;y;dy])
------------- in file gaussian.m
function f = gaussian(par,data);
%theoretical function
f = par(1)/(sqrt(2*pi)*par(3)) * exp(-.5*((data(1,:)-
par(2))./par(3)).^2);
if (size(data,1)==2), %chi-square, error = 1
f = sum((data(2,:) - f).^2);
elseif (size(data,1)>2), %chi-square, error = 3rd row of data
f = sum(((data(2,:) - f)./data(3,:)).^2);
end

Given you are using an old function that requires a string as the function, the first solution below will not work. This is, however, the right way to do it. Changing the old function to use function handles instead of strings would be my preferred solution. However, you can also use an alternative solution further down below, which uses global variables. This is not the recommended approach (we should strive to avoid globals), but will solve your near-term problems.
Correct approach: use an anonymous function
You should use an anonymous function, these can capture variables when they're defined:
inter = #(p)interpn (x1, x2, x3, x4, x5, A, p(1), p(2), p(3), p(4), p(5), "spline");
Now inter(p) works just as if inter had been declared as a normal function. But the values of x1, x2, etc as they were defined when inter was defined will be stored inside inter.
As stated, the function you pass inter to must be written to accept function handles.
Bad, quick solution: use global variables
First, create a file inter.m with the following contents:
function FUN = inter(p);
global x1 x2 x3 x4 x5 A
FUN = interpn (x1, x2, x3, x4, x5, A, p(1), p(2), p(3), p(4), p(5), "spline");
end
Next, in your function of script that calls inter, again declare the global variables (currently MATLAB warns that you should declare them as globals before giving them a value, in future versions this will be required):
global x1 x2 x3 x4 x5 A
x1 = ...
x2 = ...
% etc
inter([10 2 4 3 4])
% or:
fminuit('inter',...)

Related

What is the correct way to use DolphinDB function tmbeta?

I want to run the script in DolphinDB:
T = 1..25
X = 2..26
Y1 = 3..27
Y2 = 4..28
y_matrix = matrix(table(Y1 as y1, Y2 as y2))
y_matrix.rename!(1..25,`y1`y2).setIndexedMatrix!()
x_series = indexedSeries(1..25,X)
tmbeta(T=1..25, Y=y_matrix[0], X=x_series[0],window=10)
It returns an error: tmbeta(1 .. 25, y_matrix[0], x_series[0], 10) => Usage: tmbeta(T, X, Y, window). X must be a vector with the same length as T.
I’d like to calculate the coefficient estimate of an ordinary-least-squares regression of Y on X. What is the correct usage of tmbeta?
For function tmbeta, the parameter X (y_matrix[0] in the script) must be a vector. The error is caused by the incorrect data type of y_matrix[0].
typestr(y_matrix[0])
FAST INT MATRIX
As the y_matrix is an indexed matrix in DolphinDB, you can use mbeta instead of tmbeta as no index (T) is needed.
mbeta(X=x_series,Y=y_matrix,window=10)
The correct way to apply function tmbeta is:
y1_matrix=matrix(table(Y1 as y1, Y2 as y2))
tmbeta(T,X=x_series[0],Y=y1_matrix[0],window=10)
Here y1_matrix[0] is a vector:
typestr(y1_matrix[0])
FAST INT VECTOR

General purpose runge-kutta function for second order differential equations in Modern Fortran

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.

How to pass variadic arguments in Octave

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.

Function with more arguments and integration

I have I simple problem but I cannot find a solution anywhere.
I have to integrate a function (for example using a Simpson's rule subroutine) but I am obliged to pass to my function more than one argument: one is the variable that I want to integrate later and another one is just a value coming from a different calculation which I cannot perform inside the function.
The problem is that the Simpson subroutine only accept f(x) to perform the integral and not f(x,y).
After Vladimir suggestions I modified the code.
Below the example:
Program main2
!------------------------------------------------------------------
! Integration of a function using Simpson rule
! with doubling number of intervals
!------------------------------------------------------------------
! to compile:
! gfortran main2.f90 -o simp2
implicit none
double precision r, rb, rmin, rmax, rstep, integral, eps
double precision F_int
integer nint, i, rbins
double precision t
rbins = 4
rmin = 0.0
rmax = 4.0
rstep = (rmax-rmin)/rbins
rb = rmin
eps = 1.0e-8
func = 0.0
t=2.0
do i=1,rbins
call func(rb,t,res)
write(*,*)'r, f(rb) (in main) = ', rb, res
!test = F_int(rb)
!write(*,*)'test F_int (in loop) = ', test
call simpson2(F_int(rb),rmin,rb,eps,integral,nint)
write(*,*)'r, integral = ', rb, integral
rb = rb+rstep
end do
end program main2
subroutine func(x,y,res)
!----------------------------------------
! Real Function
!----------------------------------------
implicit none
double precision res
double precision, intent(in) :: x
double precision y
res = 2.0*x + y
write(*,*)'f(x,y) (in func) = ',res
return
end subroutine func
function F_int(x)
!Function to integrate
implicit none
double precision F_int, res
double precision, intent(in) :: x
double precision y
call func(x,y,res)
F_int = res
end function F_int
Subroutine simpson2(f,a,b,eps,integral,nint)
!==========================================================
! Integration of f(x) on [a,b]
! Method: Simpson rule with doubling number of intervals
! till error = coeff*|I_n - I_2n| < eps
! written by: Alex Godunov (October 2009)
!----------------------------------------------------------
! IN:
! f - Function to integrate (supplied by a user)
! a - Lower limit of integration
! b - Upper limit of integration
! eps - tolerance
! OUT:
! integral - Result of integration
! nint - number of intervals to achieve accuracy
!==========================================================
implicit none
double precision f, a, b, eps, integral
double precision sn, s2n, h, x
integer nint
double precision, parameter :: coeff = 1.0/15.0 ! error estimate coeff
integer, parameter :: nmax=1048576 ! max number of intervals
integer n, i
! evaluate integral for 2 intervals (three points)
h = (b-a)/2.0
sn = (1.0/3.0)*h*(f(a)+4.0*f(a+h)+f(b))
write(*,*)'a, b, h, sn (in simp) = ', a, b, h, sn
! loop over number of intervals (starting from 4 intervals)
n=4
do while (n <= nmax)
s2n = 0.0
h = (b-a)/dfloat(n)
do i=2, n-2, 2
x = a+dfloat(i)*h
s2n = s2n + 2.0*f(x) + 4.0*f(x+h)
end do
s2n = (s2n + f(a) + f(b) + 4.0*f(a+h))*h/3.0
if(coeff*abs(s2n-sn) <= eps) then
integral = s2n + coeff*(s2n-sn)
nint = n
exit
end if
sn = s2n
n = n*2
end do
return
end subroutine simpson2
I think I'm pretty close to the solution but I cannot figure it out...
If I call simpson2(F_int, ..) without putting the argument in F_int I receive this message:
call simpson2(F_int,rmin,rb,eps,integral,nint)
1
Warning: Expected a procedure for argument 'f' at (1)
Any help?
Thanks in advance!
Now you have a code we can work with, good job!
You need to tell the compiler, that F_int is a function. That can be done by
external F_int
but it is much better to learn Fortran 90 and use modules or at least interface blocks.
module my_functions
implicit none
contains
subroutine func(x,y,res)
!----------------------------------------
! Real Function
!----------------------------------------
implicit none
double precision res
double precision, intent(in) :: x
double precision y
res = 2.0*x + y
write(*,*)'f(x,y) (in func) = ',res
return
end subroutine func
function F_int(x)
!Function to integrate
implicit none
double precision F_int, res
double precision, intent(in) :: x
double precision y
call func(x,y,res)
F_int = res
end function F_int
end module
Now you can easily use the module and integrate the function
use my_functions
call simpson2(F_int,rmin,rb,eps,integral,nint)
But you will find that F_int still does not know what y is! It has it's own y with undefined value! You should put y into the module instead so that everyone can see it.
module my_functions
implicit none
double precision :: y
contains
Don't forget to remove all other declarations of y! Both in function F_int and in the main program. Probably it is also better to call it differently.
Don't forget to set the value of y somewhere inside your main loop!

Use the same plot for different subfunctions

I am calling a functions recursively and I want them all to draw in the same plot. When i try to create a handler and pass it on with the parameters I get the following error:
??? Error using ==> set Invalid handle object.
Error in ==> triangle at 23
set(h, 'xdata', [x1,x3], 'ydata', [y1,y3]);
Before calling my function I've created a handler and set my preferences:
h = plot([0,1],[0,0]);
set(h, 'erasemode', 'none');
triangle(0,0,1,0,10,0,h)
This is my function:
function triangle(x1,y1,x2,y2, deepth , n,h)
%Paints a equilateral triangle for two given Points
if depth > n
shg
clf reset
%vector
v_12 = [x2-x1;y2-y1];
%rotate vector
g_uz = [0.5,-sqrt(3)/2;sqrt(3)/2, 0.5];
p = g_uz * v_12;
x3 = p(1) + x1;
y3 = p(2) + y1;
axis([-10 10 -10 10]);
axis off
drawnow
set(h, 'xdata', [x1,x3], 'ydata', [y1,y3]);
drawnow
set(h, 'xdata', [x2,x3], 'ydata', [y2,y3]);
drawnow
v_13 = [x3-x1,y3-y1];
v_23 = [x3-x2,y3-y2];
% 1-3 triangle
triangle(x1+v_13(1)/3,y1 + v_13(1)/3, x1+ 2*v_13(1)/3,y1 + 2*v_13(1)/3, tiefe, n+1 );
end
Do you know any solutions? How can I Plot in an object form a function i called?
The clf on line 6 clears the figure, removing the line that you want to use as your graphic output.
Remove that line and see if it works.
Try using hold all. It lets you plot new lines in the figure without clearing existing lines.
figure
hold all
triangle(...)
Inside your function just call plot.
plot(x, y)
plot(x, z)