Tải bản đầy đủ (.pdf) (17 trang)

Calling Fortran from MATLAB

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (133.25 KB, 17 trang )


61
10. Calling Fortran from MATLAB
C is a great language for numerical calculations,
particularly if the data structures are complicated.
MATLAB itself is written in C. No single language is
best for all tasks, however, and that holds for C as well.
In this chapter we will look at how to call a Fortran
subroutine from MATLAB. A Fortran subroutine is
accessed via a mexFunction in much the same way as a C
subroutine is called. Normally, the mexFunction acts as a
gateway routine that gets its input arguments from
MATLAB, calls a computational routine, and then returns
its output arguments to MATLAB, just like the C
example in the previous chapter.
10.1 Solving a transposed system
The
linsolve
function was introduced in Section 5.5.
Here is a Fortran subroutine
utsolve
that computes
x=A'\b
when
A
is dense, square, real, and upper
triangular. It has no calls to MATLAB-specific
mx
or
mex
routines.


subroutine utsolve (n, x, A, b)
integer n
real*8 x(n), A(n,n), b(n), xi
integer i, j
do 1 i = 1,n
xi = b(i)
do 2 j = 1,i-1
xi = xi - A(j,i) * x(j)
2 continue
x(i) = xi / A(i,i)
1 continue
return
end

62
10.2 A Fortran mexFunction with %val
To call this computational subroutine from MATLAB as
x=utsolve(A,b)
, we need a gateway routine, the first
lines of which must be:
subroutine mexFunction
$ (nargout, pargout, nargin, pargin)
integer nargout, nargin
integer pargout (*), pargin (*)
where the
$
is in column 6. These lines must be the same
for any Fortran
mexFunction
(you do not need to split

the first line). Note that
pargin
and
pargout
are arrays
of integers. MATLAB passes its inputs and outputs as
pointers to objects of type
mxArray
, but Fortran cannot
handle pointers. Most Fortran compilers can convert
integer “pointers” to references to Fortran arrays via the
non-standard
%val
construct. We will use this in our
gateway routine. The next two lines of the gateway
routine declare some MATLAB
mx
-routines.
integer mxGetN, mxGetPr
integer mxCreateDoubleMatrix
This is required because Fortran has no include-file
mechanism. The next lines determine the size of the
input matrix and create the
n
-by-
1
output vector
x
.
integer n

n = mxGetN (pargin (1))
pargout (1) =
$ mxCreateDoubleMatrix (n, 1, 0)
We can now convert “pointers” into Fortran array
references and call the computational routine.

63
call utsolve (n,
$ %val (mxGetPr (pargout (1))),
$ %val (mxGetPr (pargin (1))),
$ %val (mxGetPr (pargin (2))))
return
end
The arrays in both MATLAB and Fortran are column-
oriented and one-based, so translation is not necessary as
it was in the C mexFunction.
Combine the two routines into a single file called
utsolve.f
and type:
mex utsolve.f
in the MATLAB command window. Error checking
could be added to ensure that the two input arguments are
of the correct size and type. The code would look much
like the C example in Chapter 9, so it is not included.
Test this routine on as large a matrix that your computer
can handle.
n = 5000
A = triu(rand(n,n)) ;
b = rand(n,1) ;
tic ; x = A'\b ; toc

opts.UT = true
opts.TRANSA = true
tic ; x2 = linsolve(A,b,opts) ; toc
tic ; x3 = utsolve(A,b) ; toc
norm(x-x2)
norm(x-x3)
The solutions should agree quite closely. On a Pentium 4,
both
linsolve
and
utsolve
are about 15 times faster
than
x=A'\b
. They require less memory, as well, since
they do not have to construct
A'
.

64
10.3 If you cannot use %val
If your Fortran compiler does not support the
%val

construct, then you will need to call MATLAB
mx
-
routines to copy the MATLAB arrays into Fortran arrays,
and vice versa. The GNU
f77

compiler supports
%val
,
but issues a warning that you can safely ignore.
In this
utsolve
example, add this to your
mexFunction

gateway routine:
integer nmax
parameter (nmax = 5000)
real*8 A(nmax,nmax), x(nmax), b(nmax)
where
nmax
is the largest dimension you want your
function to handle. Unless you want to live dangerously,
you should check
n
to make sure it is not too big:
if (n .gt. nmax) then
call mexErrMsgTxt ("n too big")
endif
Replace the call to
utsolve
with this code.
call mxCopyPtrToReal8
$ (mxGetPr (pargin (1)), A, n**2)
call mxCopyPtrToReal8
$ (mxGetPr (pargin (2)), b, n)

call lsolve (n, x, A, b)
call mxCopyReal8ToPtr
$ (x, mxGetPr (pargout (1)), n)
This copies the input MATLAB arrays
A
and
b
to their
Fortran counterparts, calls the
utsolve
routine, and then
copies the solution
x
to its MATLAB counterpart.
Although this is more portable, it takes more memory and
is significantly slower. If possible, use
%val
.

65
11. Calling Java from MATLAB
While C and Fortran excel at numerical computations,
Java is well-suited to web-related applications and
graphical user interfaces. MATLAB can handle native
Java objects in its workspace and can directly call Java
methods on those objects. No mexFunction is required.
11.1 A simple example
Try this in the MATLAB Command window
t = 'hello world'
s = java.lang.String(t)

s.indexOf('w') + 1
find(s == 'w')
whos
You have just created a Java string in the MATLAB
workspace, and determined that the character
'w'
appears
as the seventh entry in the string using both the
indexOf

Java method and the
find
MATLAB function.
11.2 Encryption/decryption
MATLAB can handle strings on its own, without help
from Java, of course. Here is a more interesting example.
Type in the following as the M-file
getkey.m
.
function key = getkey(password)
%GETKEY: key = getkey(password)
% Converts a string into a key for use
% in the encrypt and decrypt functions.
% Uses triple DES.
import javax.crypto.spec.*
b = int8(password) ;
n = length(b) ;
b((n+1):24) = 0 ;
b = b(1:24) ;
key = SecretKeySpec(b, 'DESede') ;


66
The
getkey
routine takes a password string and converts
it into a 24-byte triple DES key using the
javax.crypto

package. You can then encrypt a string with the
encrypt
function:
function e = encrypt(t, key)
%ENCRYPT: e = encrypt(t, key)
% Encrypt the plaintext string t into
% the encrypted byte array e using a key
% from getkey.
import javax.crypto.*
cipher = Cipher.getInstance('DESede') ;
cipher.init(Cipher.ENCRYPT_MODE, key) ;
e = cipher.doFinal(int8(t))' ;
Except for the function statement and the comments, this
looks almost exactly the same as the equivalent Java
code. This is not a Java program, however, but a
MATLAB M-file that uses Java objects and methods.
Finally, the
decrypt
function undoes the encryption: .
function t = decrypt(e, key)
%DECRYPT: t = decrypt(e, key)
% Decrypt the encrypted byte array e

% into to plaintext string t using a key
% from getkey.
import javax.crypto.*
cipher = Cipher.getInstance('DESede') ;
cipher.init(Cipher.DECRYPT_MODE, key) ;
t = char(cipher.doFinal(e))' ;
With these three functions in place, try:
k = getkey('this is a secret password')
e = encrypt('a hidden message',k)
decrypt(e,k)
Now you encrypt and decrypt strings in MATLAB.

Tài liệu bạn tìm kiếm đã sẵn sàng tải về

Tải bản đầy đủ ngay
×