In the q 3.6 32bit I see something that I can not explain. Having the same parse trees these two expressions for y1 and for y2 give way too different results:
q)x:3
q)parse"y :: x*10"
::
`y
(*;`x;10)
q)parse"y:: x*10"
::
`y
(*;`x;10)
q)y1 :: x*10
q)y2:: x*10
q)x:5
q)y1
30
q)y2
50
Why the space is so meaningful here?
I believe defining a view in kdb has the condition that there should be no whitespace between the variable and ::
So in your example, y2 is a view and y1 is not, hence when you redefine x, the value of y2 is updated when referenced and y1 is not
Related
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.
I have a sort of obscure question. I am wanting to do something with two separate set of syms and manipulate the syms. This is a little difficult for me to explain without including my code firsts so:
syms x Wg Iyy b
S = syms;
Pz1 = (Wg*n)/(2*b);
Vzx1 = int(Pz1,x,x,b)
Myx1 = -int(Vzx1,x,x,b)
dw_dx = (-1/(E*Iyy))*int(Myx1,x,0,x);
wx1 = int(dw_dx,x,0,x)
% Get the numerical output of the value using b as wing
clear S;
% assume(S,'clear');
% cellfun(#clear, S);
L = 6;
b = (1490+10*L)/2;
Vzx1_num = Vzx1
Myx1_num = Myx1
wx1_num = wx1
% need to sub b for b=b_prime*cos(40)
% Not really sure how to do this, I know I have to redclare the syms
syms x Wg Iyy
So to expand on more what is going on and what I am looking to do. The first syms (syms = x Wg Iyy b), I would like to keep as is because based on my needs I want to output the value of Vzx1 in terms of those variables. This part works perfectly for what I am intending to do. The error lies in how I would like to manipulate the value I have generated. So secondly, I would like to ouput the numerical value of these generated expression by using the value of b. I am trying to clear the value of syms.
When using
S= syms
clear S
The value of S gets clear. So b would no longer be a symbol and I can set the value of b, allowing Vzx1_num to ouput the value of Vzx1 with b replaced with a number. This is not the case as b remains a sym
Then thirdly I want to substitute the variable value of b for the value of b_prime*cos(40). I have tried to mess with this but based on how I have previously declared b as a syms I am having a hard time manipulating this variable. So when I use syms x Wg Iyy. That is not the value of syms the value of syms outputs
syms
Your symbolic variables are:
Iyy Myx1_num Vzx1 Wg wx1 x
Myx1 Pz1 Vzx1_num dw_dx wx1_num
I am extremely confused why syms gets built using the values I have manipulated previously.
Any and all help would be greatly appreciated.
I am translating a Matlab code into Fortran 90 and am trying to translate the following piece of code:
func= inline('x+ y+ z', 'x', 'y', 'z')
x(1)= 1, y(1)= 1, z(1)= 1
for n= 1:5
output= 5+ func(x(n), y(n), z(n))
x(n+ 1)= x(n)+ 1
y(n+ 1)= y(n)+ 1
z(n+ 1)= z(n)+ 1
end
In Fortran I am using the statement (inline) function as func(x, y, z)= x+ y+ z, however, I am not able to insert the array part into the function.
How can I negotiate the dependence on 'n' into the statement function? I am trying something like the following but am not quite there yet.
func(x, y, z)= x+ y+ z
x(1)= 1, y(1)= 1, z(1)= 1
do n= 1, 5
func(x(n), y(n), z(n))= x(n)+ y(n)+ z(n)
end
Any help would be greatly appreciated.
This is an extended and formatted comment rather than an answer.
The general advice with statement functions in modern Fortran is Don't, just don't. They're not big and they're not clever. They were also deprecated in, I think, the Fortran 90 standard so, to be pedantic, your requirements are inconsistent.
Beyond that, it's difficult to provide any specific advice. If I understand the Matlab correctly the code you show is a convoluted way to calculate 5+3*1+3*2+...+3*5. In Fortran 90 you might write
sum([5, (3*k,k=1,5)])
to calculate that.
Perhaps if we knew more of the context of your problem we'd be able to provide better advice.
I did realize that statement functions in modern Fortran is not the way to go. Instead I have created subroutines for the functions and then call them in the loop. This way all the values of the function in the loop can be put into an array (instead of just the last values). The correct piece of code looks like this:
subroutine funcsub(func, x, y, z, funcn)
implicit none
real, dimension(funcn), intent(out) :: func
real, dimension(funcn), intent(in) :: x, y, z
integer, intent(in) :: funky
func= x+ y+ z
end subroutine funcsub
do i= 1, 5
funcn= size(func)
call funcsub(func, x(i), y(i), z(i), funcn)
x(i+ 1)= x(i)+ 1
y(i+ 1)= y(i)+ 1
z(i+ 1)= z(i)+ 1
end do
In Matlab, I generally do things such as
f = #(x) x.^2;
xx = 0:.1:1;
ff = f(xx);
So that f is a function handle and both xx and ff are 1x11 vectors.
However, if for some reason I need to define my function handle f like this
f = #(x) 1;
and do not change the code for xx and ff, then xx will still be a vector but ff will NOT: it will be a double.
This is annoying of course, because the sequel of my code assumes that ff is a 11x1 vector, so I would need to change my code any time f happens to be constant.
So my first question is whether or not my code is sound to begin with.
If so, what should I do to make it work in the "constant f" case?
If not, how should I rewrite it?
This is admittedly similar to
matlab constant anonymous function returns only one value instead of an array
but I can't quite find an answer in that thread.
A minor modification of the answer you linked will provide the required result:
f = #(x) ones(size(x));
The size of f(x) will match the size of the input x since f outputs a vector of ones the same size as x.
I found a better way of doing this. This shows how stupid Matlab is:
f = #(x) (x-x)+1
Try it!
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