Compiling A Mexfile using R CMD SHLIB - r
I am trying to import a number of Fortran 90 codes into R for a project. They were initially written with a mex (matlab integration of Fortran routines) type compilation in mind. This is what one of the codes look like:
# include <fintrf.h>
subroutine mexFunction(nlhs, plhs, nrhs, prhs)
!--------------------------------------------------------------
! MEX file for VFI3FCN routine
!
! log M_{t,t+1} = log \beta + gamma (x_t - x_{t+1})
! gamma = gamA + gamB (x_t - xbar)
!
!--------------------------------------------------------------
implicit none
mwPointer plhs(*), prhs(*)
integer nlhs, nrhs
mwPointer mxGetM, mxGetPr, mxCreateDoubleMatrix
mwPointer nk, nkp, nz, nx, nh
mwSize col_hxz, col_hz, col_xz
! check for proper number of arguments.
if(nrhs .ne. 31) then
call mexErrMsgTxt('31 input variables required.')
elseif(nlhs .ne. 4) then
call mexErrMsgTxt('4 output variables required.')
endif
! get the size of the input array.
nk = mxGetM(prhs(5))
nx = mxGetM(prhs(7))
nz = mxGetM(prhs(11))
nh = mxGetM(prhs(14))
nkp = mxGetM(prhs(16))
col_hxz = nx*nz*nh
col_xz = nx*nz
col_hz = nz*nh
! create matrix for the return arguments.
plhs(1) = mxCreateDoubleMatrix(nk, col_hxz, 0)
plhs(2) = mxCreateDoubleMatrix(nk, col_hxz, 0)
plhs(3) = mxCreateDoubleMatrix(nk, col_hxz, 0)
plhs(4) = mxCreateDoubleMatrix(nk, col_hxz, 0)
call vfi3fcnIEccB(%val(mxGetPr(plhs(1))), nkp)
return
end
subroutine vfi3fcnIEccB(optK, V, I, div, & ! output variables
alp1, alp2, alp3, V0, k, nk, x, xbar, nx, Qx, z, nz, Qz, h, nh, kp, &
alpha, beta, delta, f, gamA, gamB, gP, gN, istar, kmin, kmtrx, ksubm, hmtrx, xmtrx, zmtrx, &
nkp, col_hxz, col_xz, col_hz)
use ifwin
implicit none
! specify input and output variables
integer, intent(in) :: nk, nkp, nx, nz, nh, col_hxz, col_xz, col_hz
real*8, intent(out) :: V(nk, col_hxz), optK(nk, col_hxz), I(nk, col_hxz), div(nk, col_hxz)
real*8, intent(in) :: V0(nk, col_hxz), k(nk), kp(nkp), x(nx), z(nz), Qx(nx, nx), Qz(nz, nz), h(nh)
real*8, intent(in) :: alp1, alp2, alp3, xbar, kmin, alpha, gP, gN, beta, delta, gamA, gamB, f, istar
real*8, intent(in) :: kmtrx(nk, col_hxz), ksubm(nk, col_hz), zmtrx(nk, col_hxz), xmtrx(nk, col_hxz), hmtrx(nk, col_hxz)
! specify intermediate variables
real*8 :: Res(nk, col_hxz), Obj(nk, col_hxz), optKold(nk, col_hxz), Vold(nk, col_hxz), tmpEMV(nkp, col_hz), tmpI(nkp), &
tmpObj(nkp, col_hz), tmpA(nk, col_hxz), tmpQ(nx*nh, nh), detM(nx), stoM(nx), g(nkp), tmpInd(nh, nz)
real*8 :: Qh(nh, nh, nx), Qxh(nx*nh, nx*nh), Qzxh(col_hxz, col_hxz)
real*8 :: hp, d(nh), errK, errV, T1, lapse
integer :: ix, ih, iter, optJ(col_hz), ik, iz, ind(nh, col_xz), subindex(nx, col_hz)
logical*4 :: statConsole
! construct the transition matrix for kh --- there are nx number of these transition matrix: 3-d
Qh = 0.0
do ix = 1, nx
do ih = 1, nh
! compute the predicted next period kh
hp = alp1 + alp2*h(ih) + alp3*(x(ix) - xbar)
! construct transition probability vector
d = abs(h - hp) + 1D-32
Qh(:, ih, ix) = (1/d)/sum(1/d)
end do
end do
! construct the compound transition matrix over (z x h) space
! compound the (x h) space
Qxh = 0.0
do ix = 1, nx
call kron(tmpQ, Qx(:, ix), Qh(:, :, ix), nx, 1, nh, nh)
Qxh(:, (ix - 1)*nh + 1 : ix*nh) = tmpQ
end do
! compound the (z x h) space: h changes the faster, followed by x, and z changes the slowest
call kron(Qzxh, Qz, Qxh, nz, nz, nx*nh, nx*nh)
! available funds for the firm
Res = dexp(xmtrx + zmtrx + hmtrx)*(kmtrx**alpha) + (1 - delta)*kmtrx - f
! initializing
Obj = 0.0
optK = 0.0
optKold = optK + 1.0
Vold = V0
! Some Intermediate Variables Used in Stochastic Discount Factor
detM = beta*dexp((gamA - gamB*xbar)*x + gamB*x**2)
stoM = -(gamA - gamB*xbar + gamB*x)
! Intermediate index vector to facilitate submatrix extracting
ind = reshape((/1 : col_hxz : 1/), (/nh, col_xz/))
do ix = 1, nx
tmpInd = ind(:, ix : col_xz : nx)
do iz = 1, nz
subindex(ix, (iz - 1)*nh + 1 : iz*nh) = tmpInd(:, iz)
end do
end do
! start iterations
errK = 1.0
errV = 1.0
iter = 0
T1 = secnds(0.0)
do
if (errV <= 1D-3 .AND. errK <= 1D-8) then
exit
else
iter = iter + 1
do ix = 1, nx
! next period value function by linear interpolation: nkp by nz*nh matrix
call interp1(tmpEMV, k, detM(ix)*(matmul(dexp(stoM(ix)*xmtrx)*Vold, Qzxh(:, subindex(ix, :)))) - ksubm, kp, &
nk, nkp, col_hz)
! maximize the right-hand size of Bellman equation on EACH grid point of capital stock
do ik = 1, nk
! with istar tmpI is no longer investment but a linear transformation of that
tmpI = (kp - (1.0 - delta)*k(ik))/k(ik) - istar
where (tmpI >= 0.0)
g = gP
elsewhere
g = gN
end where
tmpObj = tmpEMV - spread((g/2.0)*(tmpI**2)*k(ik), 2, col_hz)
! direct discrete maximization
Obj(ik, subindex(ix, :)) = maxval(tmpObj, 1)
optJ = maxloc(tmpObj, 1)
optK(ik, subindex(ix, :)) = kp(optJ)
end do
end do
! update value function and impose limited liability condition
V = max(Res + Obj, 1D-16)
! convergence criterion
errK = maxval(abs(optK - optKold))
errV = maxval(abs(V - Vold))
! revise Initial Guess
Vold = V
optKold = optK
! visual
if (modulo(iter, 50) == 0) then
lapse = secnds(T1)
statConsole = AllocConsole()
print "(a, f10.7, a, f10.7, a, f8.1, a)", " errV:", errV, " errK:", errK, " Time:", lapse, "s"
end if
end if
end do
! visual check on errors
lapse = secnds(T1)
statConsole = AllocConsole()
print "(a, f10.7, a, f10.7, a, f8.1, a)", " errV:", errV, " errK:", errK, " Time:", lapse, "s"
! optimal investment and dividend
I = optK - (1.0 - delta)*kmtrx
tmpA = I/kmtrx - istar
where (tmpA >= 0)
div = Res - optK - (gP/2.0)*(tmpA**2)*kmtrx
elsewhere
div = Res - optK - (gN/2.0)*(tmpA**2)*kmtrx
end where
return
end
subroutine interp1(v, x, y, u, m, n, col)
!-------------------------------------------------------------------------------------------------------
! Linear interpolation routine similar to interp1 with 'linear' as method parameter in Matlab
!
! OUTPUT:
! v - function values on non-grid points (n by col matrix)
!
! INPUT:
! x - grid (m by one vector)
! y - function defined on the grid x (m by col matrix)
! u - non-grid points on which y(x) is to be interpolated (n by one vector)
! m - length of x and y vectors
! n - length of u and v vectors
! col - number of columns of v and y matrices
!
! Four ways to pass array arguments:
! 1. Use explicit-shape arrays and pass the dimension as an argument(most efficient)
! 2. Use assumed-shape arrays and use interface to call external subroutine
! 3. Use assumed-shape arrays and make subroutine internal by using "contains"
! 4. Use assumed-shape arrays and put interface in a module then use module
!
! This subroutine is equavilent to the following matlab call
! v = interp1(x, y, u, 'linear', 'extrap') with x (m by 1), y (m by col), u (n by 1), and v (n by col)
!------------------------------------------------------------------------------------------------------
implicit none
integer :: m, n, col, i, j
real*8, intent(out) :: v(n, col)
real*8, intent(in) :: x(m), y(m, col), u(n)
real*8 :: prob
do i = 1, n
if (u(i) < x(1)) then
! extrapolation to the left
v(i, :) = y(1, :) - (y(2, :) - y(1, :)) * ((x(1) - u(i))/(x(2) - x(1)))
else if (u(i) > x(m)) then
! extrapolation to the right
v(i, :) = y(m, :) + (y(m, :) - y(m-1, :)) * ((u(i) - x(m))/(x(m) - x(m-1)))
else
! interpolation
! find the j such that x(j) <= u(i) < x(j+1)
call bisection(x, u(i), m, j)
prob = (u(i) - x(j))/(x(j+1) - x(j))
v(i, :) = y(j, :)*(1 - prob) + y(j+1, :)*prob
end if
end do
end subroutine interp1
subroutine bisection(list, element, m, k)
!--------------------------------------------------------------------------------
! find index k in list such that (list(k) <= element < list(k+1)
!--------------------------------------------------------------------------------
implicit none
integer*4 :: m, k, first, last, half
real*8 :: list(m), element
first = 1
last = m
do
if (first == (last-1)) exit
half = (first + last)/2
if ( element < list(half) ) then
! discard second half
last = half
else
! discard first half
first = half
end if
end do
k = first
end subroutine bisection
subroutine kron(K, A, B, rowA, colA, rowB, colB)
!--------------------------------------------------------------------------------
! Perform K = kron(A, B); translated directly from kron.m
!
! OUTPUT:
! K -- rowA*rowB by colA*colB matrix
!
! INPUT:
! A -- rowA by colA matrix
! B -- rowB by colB matrix
! rowA, colA, rowB, colB -- integers containing shape information
!--------------------------------------------------------------------------------
implicit none
integer, intent(in) :: rowA, colA, rowB, colB
real*8, intent(in) :: A(rowA, colA), B(rowB, colB)
real*8, intent(out) :: K(rowA*rowB, colA*colB)
integer :: t1(rowA*rowB), t2(colA*colB), i, ia(rowA*rowB), ja(colA*colB), ib(rowA*rowB), jb(colA*colB)
t1 = (/ (i, i = 0, (rowA*rowB - 1)) /)
ia = int(t1/rowB) + 1
ib = mod(t1, rowB) + 1
t2 = (/ (i, i = 0, (colA*colB - 1)) /)
ja = int(t2/colB) + 1
jb = mod(t2, colB) + 1
K = A(ia, ja)*B(ib, jb)
end subroutine kron
My initial plan was to remove the mexFunction subroutine and compile the main Fortran subroutines using the R CMD SHLIB command but then I run into the Rtools compiler not knowing where to find the ifwin library even though I have the library in my intel fortran compiler folder.
So my first question is:
1) Is there a way for me to tell rtools where to find the ifwin library and any other library I need to include? Or is there a way to include the dependency libraries in the R CMD SHLIB command so the compiler can find the necessary libraries and compile?
2) If the answer to two is no, can I some how use the compiled version from Matlab in R. I can compile the file as is in matlab using the mex Zhang_4.f90 command with no errors.
3) Is there a way of setting up an environment in Visual Studio 2015 so I can compile Fortran subroutines for use in R using the Intel compiler?
When I take out the mexFunction subroutine and try compiling the rest of the code, I get the following error:
D:\SS_Programming\Fortran>R CMD SHLIB Zhang_4.f90
c:/Rtools/mingw_64/bin/gfortran -O2 -mtune=core2 -c Zhang_4.f90 -o
Zhang_4.o
Zhang_4.f90:6.4:
use ifwin
1
Fatal Error: Can't open module file 'ifwin.mod' for reading at (1): No
such file or directory
make: *** [Zhang_4.o] Error 1
Warning message:
running command 'make -f "C:/PROGRA~1/R/R-34~1.2/etc/x64/Makeconf" -f
"C:/PROGRA~1/R/R-34~1.2/share/make/winshlib.mk"
SHLIB_LDFLAGS='$(SHLIB_FCLDFLAGS)' SHLIB_LD='$(SHLIB_FCLD)'
SHLIB="Zhang_4.dll" SHLIB_LIBADD='$(FCLIBS)' WIN=64 TCLBIN=64
OBJECTS="Zhang_4.o"' had status 2
I don't think there is any other way then rewrite the code to not use IFWIN. Unless you manage to use Intel Fortran for R (that might require recompiling the whole R distribution...). Matlab is tied to Intel Fortran, that's why the code worked there.
You have to adjust the code anyway, you cannot use it as it stands.
Just get rid of the AllocConsole() calls and the print statements. You will need to use the R routines to print to console. See https://cran.r-project.org/doc/manuals/R-exts.html#Printing-from-FORTRAN
Related
Gamma function implementation not producing correct values
Function programmed in Fortran 95 to compute values of the Gamma function from mathematics is not producing the correct values. I am trying to implement a recursive function in Fortran 95 that computes values of the Gamma function using the Lanczos approximation (yes I know that there is an intrinsic function for this in the 2003 standard and later). I've followed the standard formula very closely so I'm not certain what is wrong. Correct values for the Gamma function are crucial for some other numerical computations I am doing involving the numerical computation of the Jacobi polynomials by means of a recursion relation. program testGam implicit none integer, parameter :: dp = selected_real_kind(15,307) real(dp), parameter :: pi = 3.14159265358979324 real(dp), dimension(10) :: xGam, Gam integer :: n xGam = (/ -3.5, -2.5, -1.5, -0.5, 0.5, 1.5, 2.5, 3.5, 4.5, 5.5 /) do n = 1,10 Gam(n) = GammaFun(xGam(n)) end do do n = 1,10 write(*,*) xGam(n), Gam(n) end do contains recursive function GammaFun(x) result(G) real(dp), intent(in) :: x real(dp) :: G real(dp), dimension(0:8), parameter :: q = & (/ 0.99999999999980993, 676.5203681218851, -1259.1392167224028, & 771.32342877765313, -176.61502916214059, 12.507343278686905, & -0.13857109526572012, 9.9843695780195716e-6, 1.5056327351493116e-7 /) real(dp) :: t, w, xx integer :: n xx = x if ( xx < 0.5_dp ) then G = pi / ( sin(pi*xx)*GammaFun(1.0_dp - xx) ) else xx = xx - 1.0_dp t = q(0) do n = 1,9 t = t + q(n) / (xx + real(n, dp)) end do w = xx + 7.5_dp G = sqrt(2.0_dp*pi)*(w**(xx + 0.5_dp))*exp(-w)*t end if end function GammaFun end program testGam Whereas this code should be producing correct values for the Gamma function over the whole real line, it seems only to produce a constant value close to 122 regardless of the input. I suspect that there is some weird floating point arithmetic issue that I am not seeing.
There are two obvious issues with your code Most seriously the code accesses an array out of bounds at line 42, i.e. in the loop do n = 1,9 t = t + q(n) / (xx + real(n, dp)) end do You have mixed up your precision somewhat, with some of the constants being of kind dp, other being of default kind Making what I believe are the appropriate fixes to these your program compiles, links and runs correctly, at least as far as I can see. See below: ian#eris:~/work/stackoverflow$ cat g.f90 program testGam implicit none integer, parameter :: dp = selected_real_kind(15,307) real(dp), parameter :: pi = 3.14159265358979324_dp real(dp), dimension(10) :: xGam, Gam integer :: n xGam = (/ -3.5_dp, -2.5_dp, -1.5_dp, -0.5_dp, 0.5_dp, 1.5_dp, 2.5_dp, 3.5_dp, 4.5_dp, 5.5_dp /) do n = 1,10 Gam(n) = GammaFun(xGam(n)) end do do n = 1,10 write(*,*) xGam(n), Gam(n), gamma( xGam( n ) ), Abs( Gam( n ) - gamma( xGam( n ) ) ) end do contains recursive function GammaFun(x) result(G) real(dp), intent(in) :: x real(dp) :: G real(dp), dimension(0:8), parameter :: q = & (/ 0.99999999999980993_dp, 676.5203681218851_dp, -1259.1392167224028_dp, & 771.32342877765313_dp, -176.61502916214059_dp, 12.507343278686905_dp, & -0.13857109526572012_dp, 9.9843695780195716e-6_dp, 1.5056327351493116e-7_dp /) real(dp) :: t, w, xx integer :: n xx = x if ( xx < 0.5_dp ) then G = pi / ( sin(pi*xx)*GammaFun(1.0_dp - xx) ) else xx = xx - 1.0_dp t = q(0) do n = 1,8 t = t + q(n) / (xx + real(n, dp)) end do w = xx + 7.5_dp G = sqrt(2.0_dp*pi)*(w**(xx + 0.5_dp))*exp(-w)*t end if end function GammaFun end program testGam ian#eris:~/work/stackoverflow$ gfortran -O -std=f2008 -Wall -Wextra -fcheck=all g.f90 ian#eris:~/work/stackoverflow$ ./a.out -3.5000000000000000 0.27008820585226917 0.27008820585226906 1.1102230246251565E-016 -2.5000000000000000 -0.94530872048294168 -0.94530872048294179 1.1102230246251565E-016 -1.5000000000000000 2.3632718012073521 2.3632718012073548 2.6645352591003757E-015 -0.50000000000000000 -3.5449077018110295 -3.5449077018110318 2.2204460492503131E-015 0.50000000000000000 1.7724538509055159 1.7724538509055161 2.2204460492503131E-016 1.5000000000000000 0.88622692545275861 0.88622692545275805 5.5511151231257827E-016 2.5000000000000000 1.3293403881791384 1.3293403881791370 1.3322676295501878E-015 3.5000000000000000 3.3233509704478430 3.3233509704478426 4.4408920985006262E-016 4.5000000000000000 11.631728396567446 11.631728396567450 3.5527136788005009E-015 5.5000000000000000 52.342777784553583 52.342777784553519 6.3948846218409017E-014 ian#eris:~/work/stackoverflow$
Numerical integration in Fortran 90
In Fortran 90, I want to numerically integrate a mathematical function with one variable within a given limit. For example, integrating f(x) = x**2 from 0 to 10. The function I have is more complicated than this one and I have to run it several times changing the integration limits. I found out on internet that the 'QUADPACK' library might help me with this. But how can I install this library so that I can call this in my code? Provide some details as I won't be able to follow advanced instructions quickly.
I've provided a simple program where midpoint method is used to integrate x^2. A more complicated formula may be entered, so long the mesh is fine enough (and the function is smooth), this should work.. program integrate implicit none integer,parameter :: cp = selected_real_kind(14) integer,parameter :: N = 1000 real(cp),dimension(N) :: f,xc real(cp),dimension(N+1) :: x real(cp) :: s,xmax,xmin,dx integer :: i xmin = 0.0_cp xmax = 10.0_cp dx = (xmax - xmin)/real(N,cp) x = (/(xmin + dx*(i-1),i=1,N+1)/) ! Define x at center do i=1,N xc(i) = x(i) + 0.5_cp*dx enddo ! Define f do i=1,N f(i) = xc(i)**2 enddo ! Integrate (Midpoint method) s = 0.0_cp do i=1,N s = s + f(i)*dx enddo write(*,*) 'sum = ',s end program
Here is one possible solution to integrate your function f(x) = x**2 from 0 to 10. This uses the Gaussian quadrature formula for 8 and 16 points. program quadrature implicit none ! Declare variables integer, parameter :: n8 = 8, n16 = 16 real(8) :: r, m, c real(8) :: a, b, result8, result16 real(8), dimension (n8) :: x8, w8 real(8), dimension(n16) :: x16, w16 integer :: i ! Define the limits of integration a = 0.D0 b = 10.D0 ! Define the abscissas and weights for 8-point Gauss quadrature data x8 /-0.1834346424956498D0, 0.1834346424956498D0, -0.5255324099163290D0, 0.5255324099163290D0, & -0.7966664774136267D0, 0.7966664774136267D0, -0.9602898564975363D0, 0.9602898564975363D0/ data w8 / 0.3626837833783620D0, 0.3626837833783620D0, 0.3137066458778873D0, 0.3137066458778873D0, & 0.2223810344533745D0, 0.2223810344533745D0, 0.1012285362903763D0, 0.1012285362903763D0/ ! Define the abscissas and weights for 16-point Gauss quadrature data x16 /-0.0950125098376374D0, 0.0950125098376374D0, -0.2816035507792589D0, 0.2816035507792589D0, & -0.4580167776572274D0, 0.4580167776572274D0, -0.6178762444026438D0, 0.6178762444026438D0, & -0.7554044083550030D0, 0.7554044083550030D0, -0.8656312023878318D0, 0.8656312023878318D0, & -0.9445750230732326D0, 0.9445750230732326D0, -0.9894009349916499D0, 0.9894009349916499D0 / data w16 /0.1894506104550685D0, 0.1894506104550685D0, 0.1826034150449236D0, 0.1826034150449236D0, & 0.1691565193950025D0, 0.1691565193950025D0, 0.1495959888165767D0, 0.1495959888165767D0, & 0.1246289712555339D0, 0.1246289712555339D0, 0.0951585116824928D0, 0.0951585116824928D0, & 0.0622535239386479D0, 0.0622535239386479D0, 0.0271524594117541D0, 0.0271524594117541D0 / ! Compute the results using 8-point and 16-point Gauss quadrature r = 0.D0 m = (b-a)/2.D0 c = (b+a)/2.D0 result8 = 0.D0 result16 = 0.D0 do i = 1, n8 result8 = result8 + w8(i) * f(m*x8(i) + c) end do result8 = result8*m do i = 1, n16 result16 = result16 + w16(i) * f(m*x16(i) + c) end do result16 = result16*m ! Print the results print *, "Result using 8-point Gauss quadrature: ", result8 print *, "Result using 16-point Gauss quadrature: ", result16 contains ! Function to be integrated real(8) function f(x) real(8), intent(in) :: x f = x**2.D0 end function end program
Unclassified statement at (1) in a mathematical expression
My first Fortran lesson is to plot the probability density function of the radial Sturmian functions. In case you are interested, the radial Sturmian functions are used to graph the momentum space eigenfunctions for the hydrogen atom. In order to produce these radial functions, one needs to first produce some polynomials called the Gegenbauer polynomials, denoted Cba(x), where a and b should be stacked atop each other. One needs these polynomials because the Sturmians (let's call them R_n,l) are defined like so, R_n,l(p) = N pl⁄(p2 + k2)l+2 Cn - l - 1l + 1(p2 - k2⁄p2 + k2), where N is a normalisation constant, p is the momentum, n is the principle quantum number, l is the angular momentum and k is a constant. The normalisation constant is there so that when I come to square this function, it will produce a probability distribution for the momentum of the electron in a hydrogen atom. Gegenbauer polynomials are generated using the following recurrence relation: Cnl(x) = 1⁄n[2(l + n - 1) x Cn - 1l(x) - (2l + n - 2)Cn - 2l(x)], with C0l(x) = 1 and C1l(x) = 2lx, as you may have noticed, l is fixed but n is not. At the start of my program, I will specify both l and n and work out the Gegenbauer polynomial I need for the radial function I wish to plot. The problems I am having with my code at the moment are all in my subroutine for working out the value of the Gegenbauer polynomial Cn-l-1l+1(p2 - k2⁄p2 + k2) for incremental values of p between 0 and 3. I keep getting the error Unclassified statement at (1) but I cannot see what the issue is. program Radial_Plot implicit none real, parameter :: pi = 4*atan(1.0) integer, parameter :: top = 1000, l = 50, n = 100 real, dimension(1:top) :: x, y real increment real :: a=0.0, b = 2.5, k = 0.3 integer :: i real, dimension(1:top) :: C increment = (b-a)/(real(top)-1) x(1) = 0.0 do i = 2, top x(i) = x(i-1) + increment end do Call Gegenbauer(top, n, l, k, C) y = x*C ! y is the function that I shall be plotting between values a and b. end program Radial_Plot Subroutine Gegenbauer(top1, n1, l1, k1, CSub) ! This subroutine is my attempt to calculate the Gegenbauer polynomials evaluated at a certain number of values between c and d. implicit none integer :: top1, i, j, n1, l1 real :: k1, increment1, c, d real, dimension(1:top1) :: x1 real, dimension(1:n1 - l1, 1:top1) :: C1 real, dimension(1:n1 - l1) :: CSub c = 0.0 d = 3.0 k1 = 0.3 n1 = 50 l1 = 25 top1 = 1000 increment1 = (d - c)/(real(top1) - 1) x1(1) = 0.0 do i = 2, top1 x1(i) = x1(i-1) + increment1 end do do j = 1, top1 C1(1,j) = 1 C1(2,j) = 2(l1 + 1)(x1(i)^2 - k1^2)/(x1(i)^2 + k1^2) ! All the errors occurring here are all due to, and I quote, 'Unclassifiable statement at (1)', I can't see what the heck I have done wrong. do i = 3, n1 - l1 C1(i,j) = 2(((l1 + 1)/n1) + 1)(x1(i)^2 - k1^2)/(x1(i)^2 + k1^2)C1(i,j-1) - ((2(l1+1)/n1) + 1)C1(i,j-2) end do CSub(j) = Cn(n1 - l1,j)^2 end do return end Subroutine Gegenbauer
As francesalus correctly pointed out, the problem is because you use ^ instead of ** for exponentiation. Additionally, you do not put * between the terms you are multiplying. C1(1,j) = 1 C1(2,j) = 2*(l1 + 1)*(x1(i)**2 - k1**2)/(x1(i)**2 + k1**2) do i = 3, n1 - l1 C1(i,j) = 2 * (((l1 + 1)/n1) + 1) * (x1(i)**2 - k1**2) / & (x1(i)**2 + k1**2)*C1(i,j-1) - ((2(l1+1)/n1) + 1) * & C1(i,j-2) end do CSub(j) = Cn(n1 - l1,j)**2 Since you are beginning I have some advice. Learn to put all subroutines and functions to modules (unless they are internal). There is no reason for the return statement at the and of the subroutine, similarly as a stop statement isn't necessary at the and of the program.
idl/gdl ERROR: function not found or scalar subscript out of range
i try to solve this problem with my code. When i compile i have the follow error message: % POINCARE: Ambiguous: POINCARE: Function not found: XT or: POINCARE: Scalar subscript out of range [>].e % Execution halted at: POINCARE 38 poincare.pro % $MAIN$ It's very simple: 1) i OPEN THE FILE AND COUNT THE NUMBER OF ROWS AND COLUMNS, 2) save the fle in a matrix of ROWSxCOLUMNS, 3) take the rows that i want and save them as vectors, Now i want to modify the columns as follow: A) translate each element of first and second column (x and y) by a costant factor (xc, yc ....) B) apply some manipulation of each new element of this two new columns (xn ,yn ...) C) if the value pyn is greater than 0. then save the rows with the four value of xn ,pxn. Here the code: pro poincare file = "orbitm.txt" rows =File_Lines(file) ; per le righe openr,lun,file,/Get_lun ; per le colonne line="" readf,lun,line cols = n_elements(StrSplit(line, /RegEx, /extract)) openr,1,"orbitm.txt" data = dblarr(cols,rows) readf,1,data close,1 x = data(0,*) ; colonne e righe y = data(1,*) px = data(2,*) py = data(3,*) mu =0.001 xc = 0.5-mu yc = 0.5*sqrt(3.) openw,3,"section.txt" for i=1, rows-2 do begin xt = x(i)-xc yt = y(i)-yc pxt = px(i)-yc pyt = py(i)+xc tau = y(i)/(y(i)-y(i+1)) xn = xt(i) + (xt(i+1)-xt(i))*tau yn = yt(i) + (yt(i+1)-yt(i))*tau pxn = pxt(i) + (pxt(i+1)-pxt(i))*tau pyn = pyt(i) + (pyt(i+1)-pyt(i))*tau if (pyt(i) GT 0.) then begin printf,3, xt(i), pxt(i) endif endfor close,3 end I attach also the first rows of my input orbitm.txt: 0.73634 0.66957 0.66062 -0.73503 0.86769 0.54316 0.51413 -0.82823 0.82106 0.66553 0.60353 -0.74436 0.59526 0.88356 0.79569 -0.52813 0.28631 1.0193 0.92796 -0.24641 -0.29229E-02 1.0458 0.96862 0.21874E-01 -0.21583 1.0090 0.95142 0.22650 -0.33994 0.96091 0.92099 0.35144 -0.38121 0.93413 0.90831 0.39745 -0.34462 0.93959 0.92534 0.36561 -0.22744 0.96833 0.96431 0.25054 -0.24560E-01 0.99010 0.99480 0.45173E-01 0.25324 0.95506 0.96459 -0.24000 0.55393 0.81943 0.82584 -0.54830 0.78756 0.61644 0.61023 -0.77367 0.88695 0.53076 0.50350 -0.82814
I can see a few issues that are immediately obvious. The first is that you define the variables XT, YT, PXT, and PYT inside your FOR loop as scalars. Shortly after, you try to index them as if they are arrays with multiple elements. Either your definition for these variables needs to change, or you need to change your definition of XN, YN, PXN, and PYN. Otherwise, this will not work as written. I have attached a modified version of your code with some suggestions and comments included. pro poincare file = "orbitm.txt" rows =File_Lines(file) ; per le righe openr,lun,file,/Get_lun ; per le colonne line="" readf,lun,line cols = n_elements(StrSplit(line, /RegEx, /extract)) free_lun,lun ;; need to close this LUN ;; define data array data = dblarr(cols,rows) ;;openr,1,"orbitm.txt" ;;readf,1,data ;; data = dblarr(cols,rows) ;;close,1 openr,lun,"orbitm.txt",/get_lun readf,lun,data free_lun,lun ;; close this LUN ;;x = data(0,*) ; colonne e righe ;;y = data(1,*) ;;px = data(2,*) ;;py = data(3,*) x = data[0,*] ;; use []'s instead of ()'s in IDL y = data[1,*] px = data[2,*] py = data[3,*] mu = 0.001 xc = 0.5 - mu ;; currently a scalar yc = 0.5*sqrt(3.) ;; currently a scalar ;; Perhaps you want to define XT, YT, PXT, and PYT as: ;; xt = x - xc[0] ;; yt = y - yc[0] ;; pxt = px - yc[0] ;; pyt = py + xc[0] ;; Then you could index these inside the FOR loop and ;; remove their definitions therein. ;;openw,3,"section.txt" openw,lun,"section.txt",/get_lun for i=1L, rows[0] - 2L do begin xt = x[i] - xc ;; currently a scalar yt = y[i] - yc ;; currently a scalar pxt = px[i] - yc ;; currently a scalar pyt = py[i] + xc ;; currently a scalar tau = y[i]/(y[i] - y[i+1]) ;; currently a scalar ;; In the following you are trying to index XT, YT, PXT, and PYT but ;; each are scalars, not arrays! xn = xt[i] + (xt[i+1] - xt[i])*tau yn = yt[i] + (yt[i+1] - yt[i])*tau pxn = pxt[i] + (pxt[i+1] - pxt[i])*tau pyn = pyt[i] + (pyt[i+1] - pyt[i])*tau if (pyt[i] GT 0.) then begin printf,lun, xt[i], pxt[i] endif endfor free_lun,lun ;; close this LUN ;;close,3 ;; Return return end General IDL Notes: You should use []'s instead of ()'s to index arrays to avoid confusion with functions. It is generally better to let IDL define a logical unit number (LUN) and then free the LUN than use CLOSE.
Draw from a conditional multivariate normal distribution in fortran
I am trying to write a fortran subroutine to draw a subsample from a multivariate normal distribution conditional on the state of the other subspace. Basically: (x1, x2)' ~ N( (mu1, mu2)', Sigma) where the covariance matrix Sigma can be partitioned in the four submatrices Sigma=( S11, S12; S21, S22) Textbooks & Wikipedia tell me that the conditional distribution of x1 on x2=a is: x1|x1=a ~ N( mu, Sigma*) where mu = mu1 + S12 * S22^-1 * (a - mu2) Sigma* = S11 - S12 * S22^-1 * S21 When writing this up in R it works like a charm. In Fortran not so much. SUBROUTINE dCondMVnorm ( DIdx, NDraw, Sigma, NSigma, Mu, TMCurr) IMPLICIT NONE INTEGER :: I, NSigma, NDraw, INFO INTEGER :: DIdx(NDraw), NIdx(NSigma-NDraw), AllIdx(NSigma) LOGICAL :: IdxMask(NSigma) DOUBLE PRECISION :: Sigma11(NDraw, NDraw), Sigma22(NSigma-NDraw,NSigma-NDraw) DOUBLE PRECISION :: Sigma(NSigma,NSigma) DOUBLE PRECISION :: Sigma12minv22(NSigma-NDraw,NDraw), iSigma22(NSigma-NDraw,NSigma-NDraw) DOUBLE PRECISION :: RandNums(NDraw), Dummy1(NDraw), MeanDiff(NSigma-NDraw ) DOUBLE PRECISION :: TMcurr(NSigma), Mu(NSigma) ! create the indeces to _not_ draw from (NIdx) IdxMask = .FALSE. IdxMask(DIdx) = .TRUE. AllIdx = (/ (I, I=1, NSigma) /) NIdx = pack( AllIdx, .NOT. IdxMask) Sigma11 = Sigma( DIdx, DIdx) Sigma22 = Sigma( NIdx, NIdx) iSigma22 =0.0D0 DO I = 1, NSigma-NDraw iSigma22(I,I) = 1.0D0 END DO CALL DPOSV( 'U', NSigma-NDraw,NSigma-NDraw, Sigma22, NSigma-NDraw, iSigma22, NSigma-NDraw, INFO) CALL DGEMM ( 'N', 'N', NDraw, NSigma-NDraw, NSigma-NDraw, 1.0D0, Sigma(DIdx,NIdx), NDraw, & iSigma22, NSigma-NDraw, 0.0D0, Sigma12minv22, NDraw ) CALL DGEMM ( 'N', 'N', NDraw, NDraw, NSigma-NDraw, -1.0D0, Sigma12minv22, NDraw, & Sigma(NIdx,DIdx), NSigma-NDraw, +1.0D0, Sigma11, NDraw) CALL DPOTRF( 'U', NDraw, Sigma11, NDraw, INFO) DO I = 1, NDraw-1 Sigma11(I+1:NDraw,I) = 0.0D0 END DO ! now Sigma11 actually is the cholesky decomposition of the matrix Sigma* MeanDiff = TMcurr(NIdx) - Mu(NIdx) CALL DGEMV( 'N', NDraw, NSigma-NDraw, 1.0D0, Sigma12minv22, NDraw, MeanDiff, 1, 0.0D0, Dummy1(1), 1) ! sorry, this one is self written and returns NDraw random numbers that are i.i.d. N(0,1) using Marsaglia's algorithm CALL getzig(RandNums, NDraw) CALL DGEMV( 'N', NDraw, NDraw, 1.0D0, Sigma11, NDraw, RandNums(1), 1, 1.0D0, Dummy1(1), 1) TMcurr(DIdx) = Dummy1 END SUBROUTINE dCondMVnorm So I now build this (it is part of a larger module I am working on) call this from R using CovMat <- diag(4) CovMat[1:3,2:4] <- CovMat[1:3,2:4] + diag(3)*.5 CovMat[2:4,1:3] <- CovMat[2:4,1:3] + diag(3)*.5 CovMat[3:4,1:2] <- CovMat[3:4,1:2] + diag(2)*.2 CovMat[1:2,3:4] <- CovMat[1:2,3:4] + diag(2)*.2 library(MASS) dyn.load("TM_Updater.so") testMat2 <- matrix(NA,0,4) for (a in seq(500) ){ y <- mvrnorm(1,rep(0,2), CovMat[3:4,3:4]) x <- .Fortran("dCondMVnorm", as.integer(c(1,2)),as.integer(2), CovMat, as.integer(4), c(0.0,0.0,0.0,0.0), c(0.0,0.0,y))[[6]] testMat2 <- rbind(testMat2, c(x[1:2],y) ) } dyn.unload("TM_Updater.so") cov(testMat2) and this returns > cov(testMat2) [,1] [,2] [,3] [,4] [1,] 1.179618573 0.4183372 0.1978489 0.002156081 [2,] 0.418337156 0.8317497 0.4891746 0.204091537 [3,] 0.197848928 0.4891746 0.9649001 0.498660858 [4,] 0.002156081 0.2040915 0.4986609 1.032272666 clearly, the covariance of [1,1] is much too high and it is that way no matter how often (or for how long) I run it. What am I missing? The covariance matrix calculated by Fortran matches the one calculated by hand, as do the means... some issues with different accuracies? Plus there's this weirdness with the DGEMV that you need to give the exact starting address (see last call to DGEMV) of the vector y (as it is called in the documentary) in order to get y := alpha A *x + beta * y, beta != 0 Any help would greatly be appreciated!
I feel embarrassed, but for future reference this blunder shall remain available for all to see. The problem is converting a vector of i.i.d. N(0,1) random numbers to the target multivariate normal. Checking the textbooks you need the cholesky decomposition A of the covariance matrix S S = AA' Note that it is the lower triangular matrix we are interested in, not the upper that I calculated. Solution: in the last call to DGEMV change 'N' to 'T' or calculate the 'L' triangle in the call to DPOSV and rewrite the zeroing out of the upper triangle in the following lines.