Error when Passing matrices from MATLAB to FORTRAN dll - matlab

I have a simple intel fortran dll compiled from below:
function add1(A,n)
!Expose function add1 to users of this DLL
!DEC$ ATTRIBUTES C,DLLEXPORT:: add1
implicit none
double precision A(n,n),add1(n,n)
integer n
call add2(A,n)
A=A+1.0
add1=A
end function add1
subroutine add2(a,n)
double precision a(n,n)
integer n
a=a+1
endsubroutine
I also have a header file for the dll:
double* add1(double*,int);
I use MATLAB to load the dll:
library='trydll.dll';
header='add1.h';
loadlibrary(library, header);
n=3;
haha=ones(n,n);
A=calllib('trydll','add1',haha,n)
unloadlibrary('trydll')
The sent matrix and the integer to the dll are severely wrong, and seem to be random numbers in the memory. Anyone has any idea where the mistake is?

Like Barron suggested, use a subroutine to make life easier. Let MATLAB allocate the memory.
Here's a full working example using Intel Fortran 12.1:
subroutine CopyArray(A, B, n)
!DEC$ ATTRIBUTES DLLEXPORT :: CopyArray
!DEC$ ATTRIBUTES ALIAS: 'CopyArray' :: CopyArray
!DEC$ ATTRIBUTES REFERENCE :: A, B
!DEC$ ATTRIBUTES VALUE :: n
real(8), intent(in), dimension(n,n) :: A(n,n)
real(8), intent(out), dimension(n,n) :: B(n,n)
integer, intent(in) :: n
B = A
end subroutine
Header file:
void CopyArray(double*, double*, int);
MATLAB script:
n = 3;
A = rand(n, n);
B = zeros(n, n);
[A2, B2] = calllib(libname, 'CopyArray', A, B, n);
Using the libpointer appears to be optional here. It appears that MATLAB automatically converts the array arguments to pointers. Also, note that the arguments that are passed by reference (A, B) are translated to function return values in MATLAB.

I'm not currently able to code up your example for thorough testing, but I can say from experience that I've never had much luck calling Fortran libraries from Matlab the way you've shown. Here's what I do:
Use subroutines instead of functions. So, convert add1 to be more like:
SUBROUTINE add1(n,Ain,Aout)
INTEGER, INTENT(in) :: n
REAL*8, INTENT(in) :: Ain(n,n)
REAL*8, INTENT(out) :: Aout(n,n)
Aout = Ain + 1d0
END SUBROUTINE
Then call from Matlab with something like:
n = 3;
Ain = ones(n,n);
Aout = libpointer('doublePtr',zeros(1,n));
calllib('trydll','add1',n,Ain,Aout);
Aout = Aout.value;
It's possible that it's only that last .value part that you really need, but I'm running off of memory here.

I guess that is a initialization problem. You can try the following script in MATLAB:
library='trydll.dll';
header='add1.h';
loadlibrary(library, header);
n=3;
arg_1 = libpointer('doublePtr',double(ones(1,n)))
arg_2 = libpointer('int32',n)
out_raw = libpointer('doublePtr')
[output, arg_1] = calllib('trydll','add1',arg_1, arg_2)
unloadlibrary('trydll')
To see the FORTRAN/DLL output:
out = get(out_raw,'Value')
for i=1:n
display(out[i]);
end

Related

How to convert 1D matlab array code into Fortran code and to get the values

I want to convert this Matlab code into Fortran code. I have provided the codes here for both Matlab and Fortran. The parameters are also given here.
Matlab code
L_10 = 1.0e-10;
e = 0.4;
n = 100000;
R = 3.1e+5;
K0_10 = 1.0e-10;
Ci = 1.0e-15;
zv = 1.2;
Dv = 1
Rho = 2.0e-4
dt = 0.01
for i=1:n
L_10(i+1) = L_10(i) + dt*(e*K0_10- R*L_10(i)*Ci- zv*Dv*L_10(i)*Rho);
end
I have written the following Fortran code but it does not work
real, dimension (:), allocatable:: L_10
real, parameter :: e = 0.4
integer, parameter :: n = 100000
real, parameter :: R = 3.1e+5
real, parameter :: K0_10 = 1.0e-10
real, parameter :: Ci = 1.0e-15
real, parameter :: zv = 1.2
real, parameter :: Dv = 1.0
real, parameter :: Rho = 2.0e-4
real, parameter :: dt = 0.01
integer:: i
do i=1:n
L_10(i+1) = L_10(i) + dt*(e*K0_10- R*L_10(i)*Ci- zv*Dv*L_10(i)*Rho);
end
How to initialize the array value in the Fortran code? How the iteration will work in Fortran? It works perfectly well in Matlab.
This program in Fortran is producing the same output as in Matlab. The iteration of array is different in do loop in Fortran as shown below. The iteration is saved in Fortran without indexing but in Matlab, it is done with indexed as shown in Matlab code.
program oneDimention
implicit none
integer, parameter :: n = 10
real, dimension (n):: L_10
real, parameter :: e = 0.4
real, parameter :: R = 3.1e+5
real, parameter :: K0_10 = 1.0e-10
real, parameter :: Ci = 1.0e-15
real, parameter :: zv = 1.2
real, parameter :: Dv = 1.0
real, parameter :: Rho = 2.0e-4
real, parameter :: dt = 0.01
integer:: i
L_10 = 1.0e-10
do i=1,n
L_10 = L_10(i) + dt*(e*K0_10- R*L_10(i)*Ci- zv*Dv*L_10(i)*Rho);
print*,L_10(i)
end do
end program oneDimention
I can immediately see two problems with the Fortran. You've chosen to make L_10 allocatable, but the code doesn't allocate it. You could either make it static, by changing its declaration to
real, dimension (n+1) :: L_10
If you choose this approach you'll have to move the declaration until after the declaration of n itself, the compiler won't work with forward declarations. The alternative would be to leave the declaration as it is but to insert the statement
allocate(L_10(n+1))
after the declarations but before you try to make first use of the array. Review your documentation for the allocate statement and learn how to get a status code reported in case things go awry.
You can then set the value of all elements in the same way you do in Matlab,
L_10 = 1.0e-10
You have the syntax for the do statement wrong, it should start with the line
do i = 1, n
with a comma where Matlab uses the colon.
There may be other problems in the Fortran which I haven't spotted, but your compiler will help you there.

Are there any way to solve for an unknown variable instead of using solve?

I write code to do optimization to solve a problem taking the form min_x f(x,c) s.t. sum(x)=1 and g(x,c)=1, where x is a vector and c is a function of x such that c(x) is a constant when x is fixed. Indeed, g(x,c) takes the following form
n=5; N=1000000; idx = 1:1:n; df=4; theta=2; alpha=2.4;
central_Simulation_Points=mvtrnd(eyes(n),df,N);
x=sym('x_%d',[n,1]); syms c
g(x,c)=1./N.*sum((theta.*(alpha-1).*central_Simulation_Points*x).^2+c).^(1./(alpha-1)))==1;
Constraint_equ = solve(g(x,c), c);
Constraint_equ_handle = matlabFunction(Constraint_equ);
The use of solve is to express c in terms of x, while matlabFunction changes the symbolic function to function handle for input. I then define an objective function obj_fun=#(x)f(x,c(x)). The objective function for optimization is
(alpha-1)/alpha*sum_{i=1}^N[(theta*(alpha-1)*V(x,Xi)+c)^(1/(alpha-1))*V(x,Xi)]+c/(theta*alpha*(1-alpha))
V(x,Xi) is any function. I use (x^{T}Xi)^2. Xi is the i-th row of central_Simulation_Points.
When I count the the time, Equ = 1./N.*sum((theta.*(alpha-1).*central_Simulation_Points*x).^2+c).^(1./(alpha-1)))==1; takes 203 seconds to run, but it seems that Constraint_equ = solve(Equ, c); never makes the program stops. I wonder if any other methods could be used instead of using
Constraint_equ = solve(Equ, c);
Constraint_equ_handle = matlabFunction(Constraint_equ);
Are there any ways to find c in terms of x, or any ways to modify the code?

How to fix nan in anonymous function?

Suppose I have a function f(x) defined, which gives nan when it is very large, say x>100. Fortunately, when x>100, I can replace f by another function g. So I would like to define:
h = #(x)isnan(f(x)).*f(x)+isnan(f(x)).*g(x)
However, when I substitute h(1001), it gives nan. Is it possible to define h so that it gives g(1001) instead of nan? The only restriction is that I need to have anonymous function h for later use, say I would like to use it in integration, i.e., integral(h,0,inf).
Example: Suppose I have a function:
f = #(x)x.*1./x
This function is very easy and must be 1. I construct a function:
g = #(x)isnan(f(x)).*0+isnan(f(x)).*1
How to make g to be well defined so that I can still evaluate integral(g,-1,1)? For this example, I know I can evaluate it easily, but my restriction is that I need to define anonymous function g and use integral to do it.
You would need to make a regular function and wrap it with the anonymous function.
i.e.
function r = ternary(a, b, c)
if (a)
r = b;
else
r = c;
end
end
h = #(x)ternary(isnan(f(x)), g(x), f(x));
Note that this will evaluate your function twice. A less generalized solution for your particular case that won't evaluate the function twice.
function r = avoidNAN(a, b)
if (isnan(a))
r = b;
else
r = a;
end
end
There is a solution without any additional functions:
f = #(x)x.*1./x;
g = #(x)100+x;
h= #(x)getfield(struct('a',f(x),'b',g(x)),char(isnan(f(x))+'a'))

Matlab: passing more arguments to `nlinfit` function

I am in interested in passing extra arguments to nlinfit function in Matlab
beta = nlinfit(X,Y,modelfun,beta0)
and let the modelfun is
function y = modelfun(beta, c, X)
y = beta(1)*x.^(beta2) + c;
My interest is estimate beta and also to provide c externally. X and Y have their obvious meanings.
Can it be done?
If c is a value generated before you call nlinfit (i.e. its value is fixed while nlinfit is running), then you can use an anonymous function wrapper to pass the extra parameter like so:
beta = nlinfit(X, Y, #(beta, X) modelfun(beta, c, X), beta0);

Use symbolic matlab for flexible number of arguments and functions

I have a function F which takes as an input a vector a. Both the output of the function and a are vectors of length N, where N is arbitrary. Each component Fn is of the form g(a(n),a(n-k)), where g is the same for each component.
I want to implement this function in matlab using its symbolic functionality and calculate its Jacobian (and then store both the function and its jacobian as a regular .m file using matlabFunction). I know how to do this for a function where each input is a scalar that can be handled manually. But here I want a script that is capable of producing these files for any N. Is there a nice way to do this?
One solution I came up with is to generate an array of strings "a0","a1", ..., "aN" and define each component of the output using eval. But this is messy and I was wondering if there is a better way.
Thank you!
[EDIT]
Here is a minimal working example of my current solution:
function F = F_symbolically(N)
%generate symbols
for n = 1:N
syms(['a',num2str(n)]);
end
%define output
F(1) = a1;
for n = 2:N
F(n) = eval(sprintf('a%i + a%i',n,n-1));
end
Try this:
function F = F_symbolically(N)
a = sym('a',[1 N]);
F = a(1);
for i=2:N
F(i) = a(i) + a(i-1);
end
end
Note the use of sym function (not syms) to create an array of symbolic variables.