├── example ├── fem │ ├── init.m │ ├── Makefile │ ├── interface │ │ ├── Makefile │ │ ├── elements.mw │ │ ├── assembler.mw │ │ └── mesh.mw │ ├── README │ ├── src │ │ ├── gauss2by2.cc │ │ ├── Makefile │ │ ├── etype.h │ │ ├── scalar1d.h │ │ ├── feshapes.h │ │ ├── scalar2d.h │ │ ├── quad2d.h │ │ ├── gauss2by2.h │ │ ├── elastic2d.h │ │ ├── scalar1d.cc │ │ ├── feintegrals.h │ │ ├── quad2d.cc │ │ ├── scalar2d.cc │ │ ├── mesh.cc │ │ ├── assembler.h │ │ ├── assembler2.h │ │ ├── mesh.h │ │ ├── assembler.cc │ │ ├── assembler2.cc │ │ ├── elastic2d.cc │ │ ├── quad2d1.cc │ │ └── elastic2d1.cc │ ├── test_simple.m │ ├── test_assembler.m │ └── test_patch.m ├── foobar │ ├── foobar.mw │ └── Makefile ├── zlib │ ├── README │ ├── Makefile │ ├── testgz.m │ └── gzfile.mw ├── eventq2 │ ├── Makefile │ ├── README │ ├── testq2.m │ └── eventq2.mw ├── Makefile └── eventq │ ├── testq_plain.m │ ├── Makefile │ ├── testq_class.m │ ├── testq_handle.m │ ├── README │ ├── eventq_plain.mw │ ├── eventq_handle.mw │ └── eventq_class.mw ├── mwrap.pdf ├── testing ├── test_include2.mw ├── test_gpu.m ├── test_gpu.txt ├── test_gpu_complex.m ├── test_redirect.mw ├── test_syntax.ref ├── test_all.m ├── test_syntax.mw ├── test_catch.mw ├── test_include.mw ├── test_fortran2.mw ├── test_cpu.mw ├── test_fortran1.mw ├── test_cpu_int32.mw ├── test_gpu_int32.txt ├── test_c99_complex.mw ├── test_typecheck.ref ├── test_char.mw ├── test_cpp_complex.mw ├── test_typecheck.mw ├── test_gpu.mw ├── test_gpu_int32.mw ├── test_gpu_complex.mw ├── test_char.m ├── test_single.mw ├── test_single_humanreadable.m ├── test_single.m ├── Makefile └── test_transfers.mw ├── doc ├── Makefile └── mwrap.1 ├── Makefile ├── make.inc ├── src ├── stringify.c ├── Makefile ├── mwrap-mgen.cc ├── mwrap-ast.h ├── mwrap.l ├── mwrap-ast.cc ├── mwrap.y.in └── mwrap-typecheck.cc ├── COPYING ├── README └── NEWS /example/fem/init.m: -------------------------------------------------------------------------------- 1 | if ~exist('femex'), addpath([pwd, '/mwfem']); end 2 | -------------------------------------------------------------------------------- /mwrap.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zgimbutas/mwrap/HEAD/mwrap.pdf -------------------------------------------------------------------------------- /testing/test_include2.mw: -------------------------------------------------------------------------------- 1 | $int add2(int i) { return i+2; } 2 | # int j = add2(int 2); 3 | -------------------------------------------------------------------------------- /testing/test_gpu.m: -------------------------------------------------------------------------------- 1 | % test_gpu driver 2 | 3 | mexcuda test_gpu.cu 4 | 5 | a = ones(7,1) 6 | agpu = gpuArray(a) 7 | timestwo(agpu) 8 | -------------------------------------------------------------------------------- /doc/Makefile: -------------------------------------------------------------------------------- 1 | all: mwrap.pdf 2 | 3 | mwrap.pdf: mwrap.tex 4 | pdflatex mwrap.tex 5 | 6 | clean: 7 | rm -f mwrap.aux mwrap.log mwrap.pdf 8 | -------------------------------------------------------------------------------- /testing/test_gpu.txt: -------------------------------------------------------------------------------- 1 | % test_gpu driver 2 | 3 | mexcuda test_gpu.cu 4 | 5 | a = ones(7,1,'int32') 6 | agpu = gpuArray(a) 7 | timestwo_int32(agpu) 8 | -------------------------------------------------------------------------------- /testing/test_gpu_complex.m: -------------------------------------------------------------------------------- 1 | % test_gpu_complex driver 2 | 3 | mexcuda test_gpu_complex.cu 4 | 5 | a = complex(ones(7,1)) 6 | agpu = gpuArray(a) 7 | timestwo_complex(agpu) 8 | -------------------------------------------------------------------------------- /testing/test_redirect.mw: -------------------------------------------------------------------------------- 1 | @function test_redirect 2 | if test_redirect1(42) ~= 42, fprint('Failure: Redirection failed?'); end 3 | 4 | @function x = test_redirect1(y) 5 | x = y; 6 | -------------------------------------------------------------------------------- /testing/test_syntax.ref: -------------------------------------------------------------------------------- 1 | Parse error (test_syntax.mw:4): syntax error, unexpected NON_C_LINE, expecting ';' 2 | Parse error (test_syntax.mw:8): syntax error, unexpected $end, expecting ';' 3 | -------------------------------------------------------------------------------- /example/foobar/foobar.mw: -------------------------------------------------------------------------------- 1 | $ #include 2 | function foobar; 3 | 4 | s1 = 'foo'; 5 | s2 = 'bar'; 6 | # strncat(inout cstring[128] s1, cstring s2, int 127); 7 | fprintf('Should be foobar: %s\n', s1); 8 | -------------------------------------------------------------------------------- /example/zlib/README: -------------------------------------------------------------------------------- 1 | This example illustrates bindings for the Zlib compression library 2 | (http://www.zlib.net/). The test illustrates how these bindings can 3 | be used to read and write MATLAB matrices in compressed storage. 4 | -------------------------------------------------------------------------------- /example/eventq2/Makefile: -------------------------------------------------------------------------------- 1 | include ../../make.inc 2 | MW=../../mwrap 3 | 4 | mex: 5 | $(MW) -mex eventq2mex -c eventq2mex.cc -mb eventq2.mw 6 | $(MEX) eventq2mex.cc 7 | 8 | clean: 9 | rm -f EventQ_*.m 10 | rm -f eventq2mex.* *.o *~ 11 | -------------------------------------------------------------------------------- /testing/test_all.m: -------------------------------------------------------------------------------- 1 | test_transfers; 2 | test_cpp_complex; 3 | if exist('test_c99_complex.m'), test_c99_complex; end 4 | test_catch; 5 | test_fortran1; 6 | test_fortran2; 7 | test_redirect; 8 | test_include; 9 | test_single; 10 | test_char; 11 | -------------------------------------------------------------------------------- /testing/test_syntax.mw: -------------------------------------------------------------------------------- 1 | 2 | function badmojo 3 | # double z = sumpair(double x) 4 | // Missing semicolon should result in error 5 | // Another line just to double check lines 6 | # double z = sumpair(double x); 7 | # double z = sumpair(double x) 8 | -------------------------------------------------------------------------------- /example/fem/Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | mkdir -p mwfem 3 | (cd src; make) 4 | (cd interface; make) 5 | 6 | clean: 7 | (cd src; make clean) 8 | (cd interface; make clean) 9 | rm -rf mwfem 10 | 11 | realclean: clean 12 | (cd src; make realclean) 13 | -------------------------------------------------------------------------------- /example/foobar/Makefile: -------------------------------------------------------------------------------- 1 | include ../../make.inc 2 | MW=../../mwrap 3 | 4 | all: 5 | $(MW) -mex fbmex -m foobar.m foobar.mw 6 | $(MW) -mex fbmex -c fbmex.c foobar.mw 7 | $(MEX) fbmex.c 8 | 9 | clean: 10 | rm -f foobar.m fbmex.c fbmex.mex* *.o* *~ 11 | -------------------------------------------------------------------------------- /example/zlib/Makefile: -------------------------------------------------------------------------------- 1 | # See www.zlib.net 2 | include ../../make.inc 3 | MW=../../mwrap 4 | 5 | gzmex: 6 | $(MW) -mex gzmex -mb gzfile.mw 7 | $(MW) -mex gzmex -c gzmex.c gzfile.mw 8 | $(MEX) gzmex.c -lz 9 | 10 | clean: 11 | rm -f gz*.m gzmex.* *.o* eye.gz 12 | -------------------------------------------------------------------------------- /testing/test_catch.mw: -------------------------------------------------------------------------------- 1 | function test_catch 2 | 3 | $ void toss() 4 | $ { 5 | $ throw("Cookies"); 6 | $ } 7 | 8 | try 9 | # toss(); 10 | disp('Failed to properly catch exception'); 11 | catch 12 | fprintf('Correctly caught message: %s\n', lasterr); 13 | end 14 | -------------------------------------------------------------------------------- /testing/test_include.mw: -------------------------------------------------------------------------------- 1 | function test_include() 2 | 3 | @include test_include2.mw 4 | tassert(j == 4, 'Include test'); 5 | 6 | % ================================================================ 7 | function tassert(pred, msg) 8 | 9 | if ~pred, fprintf('Failure: %s\n', msg); end 10 | -------------------------------------------------------------------------------- /example/Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | (cd foobar; make) 3 | (cd eventq; make) 4 | (cd eventq2; make) 5 | (cd zlib; make) 6 | (cd fem; make) 7 | 8 | clean: 9 | (cd foobar; make clean) 10 | (cd eventq; make clean) 11 | (cd eventq2; make clean) 12 | (cd zlib; make clean) 13 | (cd fem; make clean) 14 | -------------------------------------------------------------------------------- /example/fem/interface/Makefile: -------------------------------------------------------------------------------- 1 | include ../../../make.inc 2 | MW=../../../mwrap 3 | 4 | mex: wrap 5 | $(MEX) -I../src femex.cc ../src/*.o 6 | mv femex.* *.m ../mwfem 7 | 8 | wrap: 9 | $(MW) -mex femex -c femex.cc \ 10 | -mb assembler.mw mesh.mw elements.mw 11 | 12 | clean: 13 | rm -f *~ 14 | -------------------------------------------------------------------------------- /example/eventq2/README: -------------------------------------------------------------------------------- 1 | Example of bindings using the mxArray wrapper. In this case, we wrap 2 | an STL priority queue of (mxArray, time) pairs. This is a variant of the 3 | event queue example in the example/eventq subdirectory, except in this 4 | version we can store arbitrary MATLAB data objects in the queue, 5 | rather than just integers. 6 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | include make.inc 2 | 3 | bin: 4 | (cd src; make) 5 | 6 | doc: 7 | (cd doc; make) 8 | 9 | test: 10 | (cd testing; make) 11 | 12 | demo: 13 | (cd example; make) 14 | 15 | clean: 16 | rm -f mwrap 17 | (cd src; make clean) 18 | (cd example; make clean) 19 | (cd testing; make clean) 20 | 21 | realclean: clean 22 | (cd src; make realclean) 23 | -------------------------------------------------------------------------------- /testing/test_fortran2.mw: -------------------------------------------------------------------------------- 1 | function test_fortran2 2 | 3 | $ #ifdef __cplusplus 4 | $ extern "C" 5 | $ #endif 6 | $ int foo_(int* a, int* b, int* c) 7 | $ { 8 | $ *a = *b + *c; 9 | $ } 10 | 11 | # FORTRAN foo(output int* a, int 1, int 2); 12 | tassert(a == 3, 'FORTRAN bindings'); 13 | 14 | function tassert(pred, msg) 15 | if ~pred, fprintf('Failure: %s\n', msg); end 16 | -------------------------------------------------------------------------------- /testing/test_cpu.mw: -------------------------------------------------------------------------------- 1 | $void TimesTwo_cpu(double *A, 2 | $ double *B, 3 | $ int const N) 4 | ${ 5 | $ int i; 6 | $ for(i = 0; i elastic2d1.cc 18 | 19 | quad2d1.cc: 20 | matexpr quad2d.cc > quad2d1.cc 21 | 22 | clean: 23 | rm -f *.o *~ 24 | 25 | realclean: 26 | rm -f *.o elastic2d1.cc quad2d1.cc 27 | -------------------------------------------------------------------------------- /example/eventq/testq_handle.m: -------------------------------------------------------------------------------- 1 | % testq_class.m 2 | % Test case / demo of MWrap bindings to a C++ event queue class. 3 | % 4 | % Copyright (c) 2007 David Bindel 5 | % See the file COPYING for copying permissions 6 | 7 | if ~exist('ishandle') | ~exist('isobject') 8 | fprintf('MATLAB object system not supported\n'); 9 | return; 10 | end 11 | 12 | q = eventqh(); 13 | 14 | push(q, 1, 1.5); 15 | push(q, 2, 0.4); 16 | push(q, 3, 10); 17 | push(q, [4, 5], [8, 11]); 18 | 19 | while ~empty(q) 20 | [id,t] = pop(q); 21 | fprintf('Time %g: Saw %d\n', t, id); 22 | end 23 | 24 | clear q 25 | -------------------------------------------------------------------------------- /example/fem/src/etype.h: -------------------------------------------------------------------------------- 1 | /* 2 | * etype.h 3 | * Element type interface definition. 4 | * 5 | * Copyright (c) 2007 David Bindel 6 | * See the file COPYING for copying permissions 7 | */ 8 | 9 | #ifndef ETYPE_H 10 | #define ETYPE_H 11 | 12 | #include "assembler.h" 13 | 14 | class Mesh; 15 | 16 | class EType { 17 | public: 18 | virtual ~EType(); 19 | virtual void assign_ids(Mesh* mesh, int eltid) = 0; 20 | virtual void assemble_f(Mesh* mesh, int eltid) = 0; 21 | virtual void assemble_K(Mesh* mesh, int eltid, 22 | MatrixAssembler* K_assembler) = 0; 23 | }; 24 | 25 | #endif /* ETYPE_H */ 26 | -------------------------------------------------------------------------------- /example/fem/src/scalar1d.h: -------------------------------------------------------------------------------- 1 | /* 2 | * scalar1d.h 3 | * Element type for 1D Laplacian. 4 | * 5 | * Copyright (c) 2007 David Bindel 6 | * See the file COPYING for copying permissions 7 | */ 8 | 9 | #ifndef SCALAR1D_H 10 | #define SCALAR1D_H 11 | 12 | #include "etype.h" 13 | #include "mesh.h" 14 | 15 | class Scalar1D : public EType { 16 | public: 17 | Scalar1D(double k) : k(k) {} 18 | 19 | void assign_ids(Mesh* mesh, int eltid); 20 | void assemble_f(Mesh* mesh, int eltid); 21 | void assemble_K(Mesh* mesh, int eltid, 22 | MatrixAssembler* K_assembler); 23 | 24 | private: 25 | double k; 26 | }; 27 | 28 | #endif /* SCALAR1D_H */ 29 | -------------------------------------------------------------------------------- /make.inc: -------------------------------------------------------------------------------- 1 | # === Compilers === 2 | 3 | # (You don't need flex and bison unless you're planning to modify the 4 | # grammar -- the default installation comes with the relevant files 5 | # already in place.) 6 | 7 | # Uncomment this line for new-style classdef support 8 | OOFLAG=-DR2008OO 9 | 10 | # Uncomment this line for C99 complex support 11 | TESTC99COMPLEX=test_c99_complex 12 | 13 | CC := $(if $(CC),$(CC),gcc) 14 | CXX := $(if $(CXX),$(CXX),g++) 15 | MEX= mex $(OOFLAG) 16 | 17 | # Use the following for 64-bit MEX 18 | # MEX= mex -largeArrayDims $(OOFLAG) 19 | 20 | # Use the following for GNU Octave. 21 | MEX= mkoctfile --mex 22 | 23 | FLEX= flex 24 | BISON= bison 25 | -------------------------------------------------------------------------------- /example/fem/src/feshapes.h: -------------------------------------------------------------------------------- 1 | /* 2 | * feshapes.h 3 | * Interface for element shape functions. 4 | * 5 | * Copyright (c) 2007 David Bindel 6 | * See the file COPYING for copying permissions 7 | */ 8 | 9 | #ifndef FESHAPES_H 10 | #define FESHAPES_H 11 | 12 | class FEShapes { 13 | public: 14 | virtual ~FEShapes() {} 15 | 16 | virtual void set_node(int nodenum, const double* x) = 0; 17 | virtual void set_nodes(const double* x) = 0; 18 | 19 | virtual void eval(const double *XX, double* xx, 20 | double* N, double* dN, 21 | double& J) const = 0; 22 | 23 | virtual int nshape() const = 0; 24 | }; 25 | 26 | #endif /* FESHAPES_H */ 27 | -------------------------------------------------------------------------------- /testing/test_c99_complex.mw: -------------------------------------------------------------------------------- 1 | function test_c99_complex; 2 | 3 | $ #include 4 | $ 5 | $ _Complex double zsum(_Complex double* zarray, int n) { 6 | $ int i; 7 | $ _Complex double sum = 0; 8 | $ for (i = 0; i < n; ++i) sum += zarray[i]; 9 | $ return sum; 10 | $ } 11 | 12 | zarray = rand(10,1) + 1i*rand(10,1); 13 | n = length(zarray); 14 | # dcomplex result = zsum(dcomplex[] zarray, int n); 15 | tassert(abs(result-sum(zarray)) < 1e-10*norm(zarray), 'C++ complex support'); 16 | # dcomplex cresult = conj(dcomplex result); 17 | tassert(conj(result) == cresult, 'C++ complex support (2)'); 18 | 19 | 20 | function tassert(pred, msg) 21 | if ~pred, fprintf('Failure: %s\n', msg); end 22 | -------------------------------------------------------------------------------- /testing/test_typecheck.ref: -------------------------------------------------------------------------------- 1 | Error (3): Object p cannot be output 2 | Error (4): Object p cannot be output 3 | Error (5): Scalar y cannot be output 4 | Error (6): Scalar y cannot be output 5 | Error (7): String s1 cannot be output without size 6 | Error (8): String s1 cannot be output without size 7 | Error (9): Object p cannot be output 8 | Error (10): Object p cannot be output 9 | Error (11): Object p cannot be output 10 | Error (12): Object p cannot be output 11 | Error (13): Output array z must have dims 12 | Error (14): Output array z must have dims 13 | Error (15): Output array z must have dims 14 | Error (16): Array z should be 1D or 2D 15 | Unrecognized typespace: bozo 16 | test_typecheck.mw: 15 type errors detected 17 | -------------------------------------------------------------------------------- /testing/test_char.mw: -------------------------------------------------------------------------------- 1 | % test char type, scalars and arrays, in mwrap. 2 | % based on test_single.m, Barnett & Gimbutas 7/5/20-7/20/20. 3 | 4 | % make as in Makefile, 5 | % then pass-fail test in octave/matlab with: 6 | % test_char.m 7 | 8 | % CHAR====================================================== 9 | 10 | % scalar char......... 11 | 12 | $ void addchar(char a, char b, char *c) { *c = a + b; } 13 | @function c=addchar(a,b) 14 | # addchar(char a, char b, output char[1]c); 15 | 16 | % array char........ 17 | 18 | $ void arraddchar(char *a, char *b, char *c, int n) 19 | $ { for (int i=0;i 4 | $ using std::complex; 5 | $ using std::conj; 6 | $ 7 | $ complex zsum(complex* zarray, int n) { 8 | $ complex sum(0); 9 | $ for (int i = 0; i < n; ++i) sum += zarray[i]; 10 | $ return sum; 11 | $ } 12 | 13 | zarray = rand(10,1) + 1i*rand(10,1); 14 | n = length(zarray); 15 | # dcomplex result = zsum(dcomplex[] zarray, int n); 16 | tassert(abs(result-sum(zarray)) < 1e-10*norm(zarray), 'C++ complex support'); 17 | # dcomplex cresult = conj(dcomplex result); 18 | tassert(conj(result) == cresult, 'C++ complex support (2)'); 19 | 20 | 21 | function tassert(pred, msg) 22 | if ~pred, fprintf('Failure: %s\n', msg); end 23 | 24 | -------------------------------------------------------------------------------- /testing/test_typecheck.mw: -------------------------------------------------------------------------------- 1 | 2 | function badmojo 3 | # double z = sumpair(inout Pair p); 4 | # double z = sumpair(output Pair p); 5 | # dble(inout int y); 6 | # dble(output int y); 7 | # strcat(inout cstring s1, cstring s2); 8 | # strcat(output cstring s1, cstring s2); 9 | # double z = sumpair(inout Pair& p); 10 | # double z = sumpair(inout Pair* p); 11 | # double z = sumpair(output Pair& p); 12 | # double z = sumpair(output Pair* p); 13 | # get34(output int[] z); 14 | # get34(output fcomplex[] z); 15 | # get34(output dcomplex[] z); 16 | # get(output int[1,2,3] z); 17 | # typedef bozo byte; 18 | %# An okay line -- should be ignored, since it doesn't start with # 19 | # // Another okay line -- comments should be ignored 20 | // Another okay line -- comments should be ignored 21 | -------------------------------------------------------------------------------- /example/fem/src/scalar2d.h: -------------------------------------------------------------------------------- 1 | /* 2 | * scalar2d.h 3 | * Element type for 2D Laplacian. 4 | * 5 | * Copyright (c) 2007 David Bindel 6 | * See the file COPYING for copying permissions 7 | */ 8 | 9 | #ifndef SCALAR2D_H 10 | #define SCALAR2D_H 11 | 12 | #include "etype.h" 13 | #include "mesh.h" 14 | #include "feshapes.h" 15 | 16 | 17 | class Scalar2D : public EType { 18 | public: 19 | Scalar2D(double k) : k(k) {} 20 | 21 | void assign_ids(Mesh* mesh, int eltid); 22 | void assemble_f(Mesh* mesh, int eltid); 23 | void assemble_K(Mesh* mesh, int eltid, 24 | MatrixAssembler* K_assembler); 25 | 26 | private: 27 | double k; 28 | int id[4]; 29 | void get_quad(FEShapes& quad, Mesh* mesh, int eltid); 30 | }; 31 | 32 | #endif /* SCALAR2D_H */ 33 | -------------------------------------------------------------------------------- /example/eventq/README: -------------------------------------------------------------------------------- 1 | Example of bindings to encapsulate a C++ class. In this case, we bind 2 | the methods for an event queue of (id, time) pairs based on the STL 3 | priority queue class. 4 | 5 | This directory contains two different versions of the example. The "plain" 6 | version uses the prefix "EventQ_" to disambiguate references to class methods. 7 | For example, "EventQ_empty" would refer to the "empty" method of the event 8 | queue class. The "class" version uses the object-oriented features in MATLAB 9 | to wrap the C++ class in a MATLAB class, so that the "empty" method in C++ can 10 | be mapped to the "empty" method in MATLAB without fear of conflict with any 11 | other methods of the same name. Because Octave does not support MATLAB-style 12 | OO, this latter version does not work with Octave. 13 | -------------------------------------------------------------------------------- /testing/test_gpu.mw: -------------------------------------------------------------------------------- 1 | $void __global__ TimesTwoKernel(double *A, 2 | $ double *B, 3 | $ int const N) 4 | ${ 5 | $ /* Calculate the global linear index, assuming a 1-d grid. */ 6 | $ int const i = blockDim.x * blockIdx.x + threadIdx.x; 7 | $ if (i < N) { 8 | $ B[i] = 2.0 * A[i]; 9 | $ } 10 | $} 11 | 12 | $void TimesTwo(double *A, 13 | $ double *B, 14 | $ int const N) 15 | ${ 16 | $ int const threadsPerBlock = 256; 17 | $ int blocksPerGrid = (N + threadsPerBlock - 1) / threadsPerBlock; 18 | $ TimesTwoKernel<<>>(A, B, N); 19 | $} 20 | 21 | 22 | @function result = timestwo(a) 23 | n = numel(a) 24 | # TimesTwo(gpu double[] a, gpu output double[n] result, int n); 25 | end 26 | -------------------------------------------------------------------------------- /testing/test_gpu_int32.mw: -------------------------------------------------------------------------------- 1 | $void __global__ TimesTwoKernel(int32_t *A, 2 | $ int32_t *B, 3 | $ int const N) 4 | ${ 5 | $ /* Calculate the global linear index, assuming a 1-d grid. */ 6 | $ int const i = blockDim.x * blockIdx.x + threadIdx.x; 7 | $ if (i < N) { 8 | $ B[i] = 2.0 * A[i]; 9 | $ } 10 | $} 11 | 12 | $void TimesTwo(int32_t *A, 13 | $ int32_t *B, 14 | $ int const N) 15 | ${ 16 | $ int const threadsPerBlock = 256; 17 | $ int blocksPerGrid = (N + threadsPerBlock - 1) / threadsPerBlock; 18 | $ TimesTwoKernel<<>>(A, B, N); 19 | $} 20 | 21 | 22 | @function result = timestwo_gpu_int32(a) 23 | n = numel(a) 24 | # TimesTwo(gpu int32_t[] a, gpu output int32_t[n] result, int n); 25 | end 26 | 27 | -------------------------------------------------------------------------------- /example/fem/src/quad2d.h: -------------------------------------------------------------------------------- 1 | /* 2 | * quad2d.h 3 | * Interface for four-node quad element shapes. 4 | * 5 | * Copyright (c) 2007 David Bindel 6 | * See the file COPYING for copying permissions 7 | */ 8 | #ifndef QUAD2D_H 9 | #define QUAD2D_H 10 | 11 | #include "feshapes.h" 12 | 13 | class Quad2d : public FEShapes { 14 | public: 15 | Quad2d() {} 16 | Quad2d(const double* x) { set_nodes(x); } 17 | virtual ~Quad2d(); 18 | 19 | void set_node(int nodenum, const double* x); 20 | void set_nodes(const double* x); 21 | 22 | void eval(const double *XX, double* xx, 23 | double* N, double* dN, 24 | double& J) const; 25 | 26 | int nshape() const { return 4; } 27 | 28 | private: 29 | double nodex[2*4]; 30 | void remap_gradients(double* FF, double* dN, double& J) const; 31 | }; 32 | 33 | #endif /* QUAD2D_H */ 34 | -------------------------------------------------------------------------------- /example/fem/src/gauss2by2.h: -------------------------------------------------------------------------------- 1 | /* 2 | * gauss2by2.h 3 | * 2-by-2 Gauss grid quadrature over [-1,1]^2. 4 | * 5 | * Copyright (c) 2007 David Bindel 6 | * See the file COPYING for copying permissions 7 | */ 8 | 9 | #ifndef GAUSS2BY2_H 10 | #define GAUSS2BY2_H 11 | 12 | #include "feshapes.h" 13 | #include "feintegrals.h" 14 | 15 | class Gauss4 : public VolumeQuadrature { 16 | public: 17 | Gauss4(FEShapes& quad) : VolumeQuadrature(quad, 2) { 18 | start(); 19 | } 20 | 21 | void start() { i = 0; eval(); } 22 | bool done() { return (i > 3); } 23 | void operator++() { if (++i <= 3) eval(); } 24 | double wt() { return X[3*i+2]*J; } 25 | 26 | private: 27 | static const double X[12]; 28 | int i; 29 | 30 | void eval() { quad.eval(X+3*i, xx(), N(), dN(), J); } 31 | }; 32 | 33 | #endif /* GAUSS2BY2_H */ 34 | -------------------------------------------------------------------------------- /example/fem/src/elastic2d.h: -------------------------------------------------------------------------------- 1 | /* 2 | * elastic2d.h 3 | * Element type for 2D elasticity 4 | * 5 | * Copyright (c) 2007 David Bindel 6 | * See the file COPYING for copying permissions 7 | */ 8 | 9 | #ifndef ELASTIC2D_H 10 | #define ELASTIC2D_H 11 | 12 | #include "etype.h" 13 | #include "mesh.h" 14 | #include "feshapes.h" 15 | 16 | 17 | class Elastic2D : public EType { 18 | public: 19 | Elastic2D(double E, double nu, const char* type = "plane strain"); 20 | 21 | void assign_ids(Mesh* mesh, int eltid); 22 | void assemble_f(Mesh* mesh, int eltid); 23 | void assemble_K(Mesh* mesh, int eltid, 24 | MatrixAssembler* K_assembler); 25 | 26 | private: 27 | double D[9]; 28 | int id[8]; 29 | void plane_strain(double E, double nu); 30 | void plane_stress(double E, double nu); 31 | void get_quad(FEShapes& quad, Mesh* mesh, int eltid); 32 | }; 33 | 34 | #endif /* ELASTIC2D_H */ 35 | -------------------------------------------------------------------------------- /testing/test_gpu_complex.mw: -------------------------------------------------------------------------------- 1 | $void __global__ TimesTwoKernel(cuDoubleComplex *A, 2 | $ cuDoubleComplex *B, 3 | $ int const N) 4 | ${ 5 | $ /* Calculate the global linear index, assuming a 1-d grid. */ 6 | $ int const i = blockDim.x * blockIdx.x + threadIdx.x; 7 | $ if (i < N) { 8 | $ /* B[i] = make_cuDoubleComplex(2.0,0.0) * A[i]; */ 9 | $ B[i] = cuCmul(make_cuDoubleComplex(2.0,0.0),A[i]); 10 | $ } 11 | $} 12 | 13 | $void TimesTwo(cuDoubleComplex *A, 14 | $ cuDoubleComplex *B, 15 | $ int const N) 16 | ${ 17 | $ int const threadsPerBlock = 256; 18 | $ int blocksPerGrid = (N + threadsPerBlock - 1) / threadsPerBlock; 19 | $ TimesTwoKernel<<>>(A, B, N); 20 | $} 21 | 22 | 23 | @function result = timestwo_complex(a) 24 | n = numel(a) 25 | # TimesTwo(gpu dcomplex[] a, gpu output dcomplex[n] result, int n); 26 | end 27 | -------------------------------------------------------------------------------- /src/stringify.c: -------------------------------------------------------------------------------- 1 | /* 2 | * stringify.c 3 | * Turns input from stdin into a C string definition written on 4 | * stdout. Adds quotes, newline characters, and backslashes as 5 | * needed. 6 | * 7 | * Copyright (c) 2007 David Bindel 8 | * See the file COPYING for copying permissions 9 | */ 10 | #include 11 | #include 12 | 13 | 14 | void stringify(const char* name) 15 | { 16 | char line[512]; 17 | char* p; 18 | 19 | printf("/*\n" 20 | " * Auto-generated by stringify\n" 21 | " */\n\n"); 22 | printf("const char* %s =", name); 23 | while (fgets(line, sizeof(line), stdin)) { 24 | printf("\n \""); 25 | for (p = line; *p; ++p) { 26 | if (*p == '"' || *p == '\\') 27 | putc('\\', stdout); 28 | if (*p != '\n' && *p != '\r') 29 | putc(*p, stdout); 30 | } 31 | printf("\\n\""); 32 | } 33 | printf(";\n\n"); 34 | } 35 | 36 | 37 | int main(int argc, char** argv) 38 | { 39 | if (argc != 2) { 40 | fprintf(stderr, "String name required\n"); 41 | exit(-1); 42 | } 43 | stringify(argv[1]); 44 | return 0; 45 | } 46 | -------------------------------------------------------------------------------- /example/fem/test_simple.m: -------------------------------------------------------------------------------- 1 | % test_mesh.m 2 | % Test MWrap interface to mesh data structure. 3 | % 4 | % Copyright (c) 2007 David Bindel 5 | % See the file COPYING for copying permissions 6 | 7 | init; 8 | 9 | mobj = Mesh_create(1, 1, 2); 10 | try 11 | 12 | % -- Set up a simple mesh 13 | i1 = Mesh_add_node(mobj, 0); 14 | i2 = Mesh_add_node(mobj, 1); 15 | i3 = Mesh_add_node(mobj, 2); 16 | i4 = Mesh_add_node(mobj, 3); 17 | s1 = Mesh_add_scalar1d(mobj, 1); 18 | e1 = Mesh_add_element(mobj, s1, [i1, i2]); 19 | e2 = Mesh_add_element(mobj, s1, [i2, i3]); 20 | e3 = Mesh_add_element(mobj, s1, [i3, i4]); 21 | Mesh_initialize(mobj); 22 | 23 | % -- Assign Dirichlet BC to first dof at node 1 24 | Mesh_set_bc(mobj, 1, 1, 1); 25 | 26 | fprintf('-- Mesh nodes and connectivities --\n'); 27 | x = Mesh_x(mobj) 28 | ix = Mesh_ix(mobj) 29 | 30 | fprintf('-- Mesh dof assignments --\n'); 31 | numid = Mesh_initialize(mobj) 32 | id = Mesh_id(mobj) 33 | 34 | fprintf('-- Assembled stiffness (standard three-point stencil) --\n'); 35 | K = Mesh_assemble_K(mobj); 36 | K = full(K) 37 | 38 | catch 39 | 40 | fprintf('Error: %s\n', lasterr); 41 | 42 | end 43 | Mesh_delete(mobj); 44 | -------------------------------------------------------------------------------- /example/fem/interface/elements.mw: -------------------------------------------------------------------------------- 1 | % elements.mw 2 | % MWrap bindings for element types. 3 | % 4 | % Copyright (c) 2007 David Bindel 5 | % See the file COPYING for copying permissions 6 | 7 | $[ 8 | #include "mesh.h" 9 | #include "scalar1d.h" 10 | #include "scalar2d.h" 11 | #include "elastic2d.h" 12 | $] 13 | 14 | # class Scalar1D : EType; 15 | # class Scalar2D : EType; 16 | # class Elastic2D : EType; 17 | 18 | 19 | @function etype = Mesh_add_scalar1d(mobj, k) 20 | % material = Mesh_add_scalar1d(mobj, k) 21 | % 22 | % Add a simple scalar element type to the mesh object. 23 | # Scalar1D* etype = new Scalar1D(double k); 24 | # mobj->Mesh.add_material(EType* etype); 25 | 26 | 27 | @function etype = Mesh_add_scalar2d(mobj, k) 28 | % material = Mesh_add_scalar2d(mobj, k) 29 | % 30 | % Add a simple scalar element type to the mesh object. 31 | # Scalar2D* etype = new Scalar2D(double k); 32 | # mobj->Mesh.add_material(EType* etype); 33 | 34 | 35 | @function etype = Mesh_add_elastic2d(mobj, E, nu, which) 36 | % material = Mesh_add_elastic2d(mobj, E, nu, which) 37 | % 38 | % Add a plane strain elastic element type to the mesh. 39 | # Elastic2D* etype = new Elastic2D(double E, double nu, cstring which); 40 | # mobj->Mesh.add_material(EType* etype); 41 | -------------------------------------------------------------------------------- /testing/test_char.m: -------------------------------------------------------------------------------- 1 | function test_char 2 | % pass-fail test of the char- args and arrays. 3 | % must do either make test_char_cpp or make test_char_c99 first. 4 | % based on test_single.m, Barnett & Gimbutas 7/5/20-7/20/20. 5 | 6 | tol = 2e-16; 7 | tols = 1e-7; 8 | %format long g % for debug 9 | 10 | 11 | %fprintf('scalar char routines...\n') % ------------------------------------- 12 | x = 1/3; ce = x+x; xs = single(x); 13 | 14 | try 15 | c = addchar(xs,xs); % should error 16 | catch ME 17 | assert(ME.message=='test_charmex: Invalid scalar argument, mxCHAR_CLASS expected') 18 | end 19 | 20 | a = '1'; b = '2'; ce = a+b; 21 | c = addchar(a,b); 22 | assert(norm(c-ce)ix(0,eltid); 17 | int n2 = mesh->ix(1,eltid); 18 | mesh->id(0,n1) = 1; 19 | mesh->id(0,n2) = 1; 20 | } 21 | 22 | 23 | void ME::assemble_f(Mesh* mesh, int eltid) 24 | { 25 | int n1 = mesh->ix(0,eltid); 26 | int n2 = mesh->ix(1,eltid); 27 | double L = mesh->x(0,n2) - mesh->x(0,n1); 28 | double kappa = k/L; 29 | double udiff = mesh->u(0,n2) - mesh->u(0,n1); 30 | mesh->f(0,n1) -= kappa*udiff; 31 | mesh->f(0,n2) += kappa*udiff; 32 | } 33 | 34 | 35 | void ME::assemble_K(Mesh* mesh, int eltid, 36 | MatrixAssembler* K_assembler) 37 | { 38 | int n1 = mesh->ix(0,eltid); 39 | int n2 = mesh->ix(1,eltid); 40 | double L = mesh->x(0,n2) - mesh->x(0,n1); 41 | double kappa = k/L; 42 | int i[2] = {mesh->id(0,n1), mesh->id(0,n2)}; 43 | double K_elt[4] = { kappa, -kappa, 44 | -kappa, kappa }; 45 | K_assembler->add_entry(i, i, K_elt, 2, 2); 46 | } 47 | -------------------------------------------------------------------------------- /example/eventq/eventq_plain.mw: -------------------------------------------------------------------------------- 1 | % eventq_plain.mw 2 | % Simple event queue for use in MATLAB event-driven simulations. 3 | % 4 | % Copyright (c) 2007 David Bindel 5 | % See the file COPYING for copying permissions 6 | 7 | $[ 8 | #include 9 | 10 | typedef std::pair Event; 11 | typedef std::priority_queue< Event, 12 | std::vector, 13 | std::greater > EventQueue; 14 | $] 15 | 16 | 17 | @function [q] = EventQ_new(); 18 | # EventQueue* q = new EventQueue(); 19 | 20 | 21 | @function EventQ_destroy(q); 22 | # delete(EventQueue* q); 23 | 24 | 25 | @function [e] = EventQ_empty(q) 26 | # int e = q->EventQueue.empty(); 27 | 28 | 29 | @function [id, t] = EventQ_pop(q) 30 | $ void pop_event(EventQueue* q, int& id, double& t) { 31 | $ t = q->top().first; 32 | $ id = q->top().second; 33 | $ q->pop(); 34 | $ } 35 | $ 36 | # pop_event(EventQueue* q, output int& id, output double& t); 37 | 38 | 39 | @function EventQ_push(q, id, t) 40 | $ void push_events(EventQueue* q, int* id, double* t, int m) 41 | $ { 42 | $ for (int i = 0; i < m; ++i) 43 | $ q->push(Event(t[i], id[i])); 44 | $ } 45 | $ 46 | m = length(id); 47 | # push_events(EventQueue* q, int[m] id, double[m] t, int m); 48 | -------------------------------------------------------------------------------- /example/fem/src/feintegrals.h: -------------------------------------------------------------------------------- 1 | /* 2 | * feintegrals.h 3 | * Interface for element quadrature rules. 4 | * 5 | * Copyright (c) 2007 David Bindel 6 | * See the file COPYING for copying permissions 7 | */ 8 | 9 | #ifndef FEINTEGRALS_H 10 | #define FEINTEGRALS_H 11 | 12 | #include "feshapes.h" 13 | 14 | #include 15 | using std::vector; 16 | 17 | class VolumeQuadrature { 18 | public: 19 | VolumeQuadrature(FEShapes& quad, int ndim) : 20 | quad(quad), nshape1(quad.nshape()), 21 | xx1(2), N1(quad.nshape()), dN1(ndim*quad.nshape()) {} 22 | 23 | virtual void start() = 0; 24 | virtual bool done() = 0; 25 | 26 | virtual void operator++() = 0; 27 | virtual double wt() = 0; 28 | 29 | int nshape() { return nshape1; } 30 | double* xx() { return &(xx1[0]); } 31 | double* N() { return &(N1[0]); } 32 | double* dN() { return &(dN1[0]); } 33 | double xx(int i) { return xx1[i]; } 34 | double N(int i) { return N1[i]; } 35 | double dN(int i, int j) { return dN1[i+j*nshape1]; } 36 | 37 | protected: 38 | FEShapes& quad; 39 | int nshape1; 40 | 41 | vector xx1; 42 | vector N1; 43 | vector dN1; 44 | double J; 45 | }; 46 | 47 | #endif /* FEINTEGRALS_H */ 48 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | mwrap -- MEX file generation for MATLAB and Octave 2 | Copyright (c) 2007-2008 David Bindel 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | You may distribute a work that contains part or all of the source code 15 | generated by mwrap under the terms of your choice. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | THE SOFTWARE. 24 | 25 | -------------------------------------------------------------------------------- /example/fem/test_assembler.m: -------------------------------------------------------------------------------- 1 | % test_assembler.m 2 | % Test MWrap interface to CSC matrix assembler. 3 | % 4 | % Copyright (c) 2007 David Bindel 5 | % See the file COPYING for copying permissions 6 | 7 | init; 8 | 9 | N = 1000; 10 | aobj = Assembler_create(N,N); 11 | try 12 | 13 | fprintf('\nRunning initial assembly loop\n'); 14 | tic; 15 | for j = 1:N 16 | idx = [j, j+1]; 17 | Ke = [1, -1; -1, 1]; 18 | Assembler_add(aobj, idx, idx, Ke); 19 | end 20 | toc; 21 | 22 | fprintf('Nonzeros in assembler before compression and form\n'); 23 | Assembler_stats(aobj); 24 | K = Assembler_get(aobj); 25 | 26 | fprintf('Nonzeros in assembler after compression and form\n'); 27 | Assembler_stats(aobj); 28 | 29 | fprintf('\nRe-running assembly loop\n'); 30 | Assembler_clear(aobj); 31 | tic; 32 | for j = 1:N 33 | idx = [j, j+1]; 34 | Ke = [1, -1; -1, 1]; 35 | Assembler_add(aobj, idx, idx, Ke); 36 | end 37 | toc; 38 | 39 | fprintf('Nonzeros in assembler before compression and form\n'); 40 | Assembler_stats(aobj); 41 | K = Assembler_get(aobj); 42 | 43 | fprintf('Nonzeros in assembler after compression and form\n'); 44 | Assembler_stats(aobj); 45 | 46 | fprintf('\nComparing the result matrices\n'); 47 | K2 = Assembler_get(aobj); 48 | fprintf('|K2-K1| = %g\n\n', norm(K-K2,1)); 49 | 50 | catch 51 | 52 | fprintf('Caught %s\n', lasterr); 53 | 54 | end 55 | Assembler_delete(aobj); 56 | -------------------------------------------------------------------------------- /example/eventq2/eventq2.mw: -------------------------------------------------------------------------------- 1 | % eventq_plain.mw 2 | % Simple event queue for use in MATLAB event-driven simulations. 3 | % 4 | % Copyright (c) 2007 David Bindel 5 | % See the file COPYING for copying permissions 6 | 7 | $[ 8 | #include 9 | #include 10 | 11 | typedef std::pair Event; 12 | typedef std::priority_queue< Event, 13 | std::vector, 14 | std::greater > EventQueue; 15 | $] 16 | 17 | 18 | // ---- 19 | @function [q] = EventQ_new(); 20 | # EventQueue* q = new EventQueue(); 21 | 22 | 23 | // ---- 24 | @function EventQ_destroy(q); 25 | 26 | while ~EventQ_empty(q) 27 | EventQ_pop(q) 28 | end 29 | # delete(EventQueue* q); 30 | 31 | 32 | // ---- 33 | @function [e] = EventQ_empty(q) 34 | # int e = q->EventQueue.empty(); 35 | 36 | 37 | // ---- 38 | @function [data, t] = EventQ_pop(q) 39 | $[ 40 | mxArray* pop_event(EventQueue* q, double& t) { 41 | t = q->top().first; 42 | mxArray* data = mxDuplicateArray(q->top().second); 43 | mxDestroyArray(q->top().second); 44 | q->pop(); 45 | return data; 46 | } 47 | $] 48 | # mxArray data = pop_event(EventQueue* q, output double& t); 49 | 50 | 51 | // ---- 52 | @function EventQ_push(q, data, t) 53 | $[ 54 | void push_event(EventQueue* q, const mxArray* a, double t) 55 | { 56 | mxArray* data = mxDuplicateArray(a); 57 | mexMakeArrayPersistent(data); 58 | q->push(Event(t, data)); 59 | } 60 | $] 61 | # push_event(EventQueue* q, mxArray data, double t); 62 | -------------------------------------------------------------------------------- /src/Makefile: -------------------------------------------------------------------------------- 1 | include ../make.inc 2 | 3 | 4 | # === Primary targets === 5 | 6 | ../mwrap: mwrap.o lex.yy.o mwrap-ast.o mwrap-typecheck.o \ 7 | mwrap-mgen.o mwrap-cgen.o mwrap-ast.h 8 | $(CXX) -o ../mwrap mwrap.o mwrap-ast.o \ 9 | mwrap-typecheck.o mwrap-mgen.o mwrap-cgen.o \ 10 | lex.yy.o 11 | 12 | mwrap.o: mwrap.cc lex.yy.c mwrap-ast.h 13 | $(CXX) -c mwrap.cc 14 | 15 | mwrap.cc mwrap.hh: mwrap.y 16 | $(BISON) -d -v mwrap.y -o mwrap.cc 17 | 18 | ifeq ($(shell bison --version 2>&1 | sed -n 's/^.*GNU Bison.* \([0-9]*\).*$$/\1/p'), 3) 19 | ERROR_VERBOSE = %define parse.error verbose 20 | else 21 | ERROR_VERBOSE = %error-verbose 22 | endif 23 | 24 | mwrap.y: mwrap.y.in 25 | sed -e 's/@ERROR_VERBOSE@/$(ERROR_VERBOSE)/' < mwrap.y.in > mwrap.y 26 | 27 | lex.yy.o: lex.yy.c mwrap.hh 28 | $(CC) -c lex.yy.c 29 | 30 | lex.yy.c: mwrap.l 31 | $(FLEX) mwrap.l 32 | 33 | mwrap-ast.o: mwrap-ast.cc mwrap-ast.h 34 | $(CXX) -c -g mwrap-ast.cc 35 | 36 | mwrap-typecheck.o: mwrap-typecheck.cc mwrap-ast.h 37 | $(CXX) -c -g mwrap-typecheck.cc 38 | 39 | mwrap-cgen.o: mwrap-cgen.cc mwrap-ast.h mwrap-support.h 40 | $(CXX) -c -g mwrap-cgen.cc 41 | 42 | mwrap-mgen.o: mwrap-mgen.cc mwrap-ast.h 43 | $(CXX) -c -g mwrap-mgen.cc 44 | 45 | mwrap-support.h: mwrap-support.c stringify 46 | ./stringify mex_header < mwrap-support.c > mwrap-support.h 47 | 48 | stringify: stringify.c 49 | $(CC) -o stringify stringify.c 50 | 51 | 52 | # === Clean-up targets === 53 | 54 | clean: 55 | rm -f mwrap.output 56 | rm -f *.o *~ 57 | rm -f stringify 58 | 59 | realclean: clean 60 | rm -f mwrap.y lex.yy.c mwrap.cc mwrap.hh mwrap-support.h mwrap.pdf 61 | 62 | -------------------------------------------------------------------------------- /example/eventq/eventq_handle.mw: -------------------------------------------------------------------------------- 1 | % eventq_handle.mw 2 | % Simple event queue for use in MATLAB event-driven simulations. 3 | % Uses the MATLAB 2008+ OO system for encapsulating the event queue. 4 | % 5 | % Copyright (c) 2007 David Bindel 6 | % See the file COPYING for copying permissions 7 | 8 | $ #include 9 | $ 10 | $ typedef std::pair Event; 11 | $ typedef std::priority_queue< Event, 12 | $ std::vector, 13 | $ std::greater > EventQueue; 14 | 15 | 16 | @ eventqh.m -------------------------------------------- 17 | 18 | classdef eventqh < handle 19 | 20 | properties 21 | mwptr 22 | end 23 | 24 | methods 25 | 26 | function [qobj] = eventqh() 27 | # EventQueue* q = new EventQueue(); 28 | qobj.mwptr = q; 29 | end 30 | 31 | function delete(q) 32 | #delete(EventQueue* q); 33 | end 34 | 35 | function e = empty(q) 36 | # int e = q->EventQueue.empty(); 37 | end 38 | 39 | function [id, t] = pop(q) 40 | $ void pop_event(EventQueue* q, int& id, double& t) { 41 | $ t = q->top().first; 42 | $ id = q->top().second; 43 | $ q->pop(); 44 | $ } 45 | # pop_event(EventQueue* q, output int& id, output double& t); 46 | end 47 | 48 | function push(q, id, t) 49 | $ void push_events(EventQueue* q, int* id, double* t, int m) 50 | $ { 51 | $ for (int i = 0; i < m; ++i) 52 | $ q->push(Event(t[i], id[i])); 53 | $ } 54 | m = length(id); 55 | # push_events(EventQueue* q, int[m] id, double[m] t, int m); 56 | end 57 | 58 | end 59 | end 60 | -------------------------------------------------------------------------------- /example/fem/src/quad2d.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * quad2d.h 3 | * Implementation for four-node quad element shapes. 4 | * 5 | * Copyright (c) 2007 David Bindel 6 | * See the file COPYING for copying permissions 7 | */ 8 | #include "quad2d.h" 9 | 10 | #define ME Quad2d 11 | 12 | 13 | ME::~ME() 14 | { 15 | } 16 | 17 | 18 | void ME::set_node(int nodenum, const double* x) 19 | { 20 | nodex[2*nodenum+0] = x[0]; 21 | nodex[2*nodenum+1] = x[1]; 22 | } 23 | 24 | 25 | void ME::set_nodes(const double* x) 26 | { 27 | for (int i = 0; i < 8; ++i) 28 | nodex[i] = x[i]; 29 | } 30 | 31 | 32 | void ME::eval(const double *XX, double* xx, 33 | double* N, double* dN, 34 | double& J) const 35 | { 36 | double X = XX[0]; 37 | double Y = XX[1]; 38 | double FF[4]; 39 | 40 | /* 41 | // Evaluate element functions 42 | 43 | input X, Y; 44 | input nodex(2,4); 45 | 46 | output N(4); 47 | output dN(4,2); 48 | output xx(2); 49 | output FF(2,2); 50 | 51 | N1x = (1-X)/2; N1y = (1-Y)/2; 52 | N2x = (1+X)/2; N2y = (1+Y)/2; 53 | 54 | N = [ N1x*N1y; N2x*N1y; N2x*N2y; N1x*N2y]; 55 | dN = [ -N1y, N1y, N2y, -N2y; 56 | -N1x, -N2x, N2x, N1x ]'/2; 57 | 58 | xx = nodex*N; 59 | FF = nodex*dN; 60 | */ 61 | remap_gradients(FF, dN, J); 62 | } 63 | 64 | 65 | void ME::remap_gradients(double* FF, double* dN, double& J) const 66 | { 67 | J = (FF[0]*FF[3]-FF[1]*FF[2]); 68 | double invF[4] = { FF[3]/J, -FF[1]/J, 69 | -FF[2]/J, FF[0]/J }; 70 | 71 | /* 72 | // Remap gradients 73 | 74 | inout dN(4,2); 75 | input invF(2,2); 76 | dN = dN*invF; 77 | */ 78 | } 79 | -------------------------------------------------------------------------------- /example/zlib/gzfile.mw: -------------------------------------------------------------------------------- 1 | % gzfile.mw 2 | % MWrap wrapper to the ZLib compression library. 3 | % 4 | % Copyright (c) 2007 David Bindel 5 | % See the file COPYING for copying permissions 6 | 7 | $#include 8 | 9 | 10 | // ---- 11 | @function [gzf] = gzopen(path, mode) 12 | % [gzf] = gzopen(path, mode) 13 | % 14 | % Open a zlib output file. 15 | 16 | # void* gzf = gzopen(cstring path, cstring mode); 17 | 18 | 19 | // ---- 20 | @function gzclose(gzf) 21 | % gzclose(gzf) 22 | % 23 | % Close a zlib output file. 24 | 25 | # gzclose(void* gzf); 26 | 27 | 28 | // ---- 29 | @function [A] = gzread(gzf) 30 | % [A] = gzread(gzf) 31 | % 32 | % Read a matrix from a zlib file. 33 | 34 | # int isize = sizeof(int 0); 35 | # int dsize = sizeof(double 0); 36 | nbytes = 2*isize; 37 | # gzread(void* gzf, output int[2] dims, int nbytes); 38 | m = dims(1); n = dims(2); nbytes = m*n*dsize; 39 | # gzread(void* gzf, output double[m,n] A, int nbytes); 40 | % gzwrite(gzf, A) 41 | % 42 | % Write a matrix to a zlib file. 43 | 44 | 45 | // ---- 46 | @function gzwrite(gzf, A) 47 | % [A] = gzwrite(gzf, A) 48 | % 49 | % Write a matrix from a zlib file. 50 | 51 | # int isize = sizeof(int 0); 52 | # int dsize = sizeof(double 0); 53 | nbytes = 2*isize; 54 | [m,n] = size(A); 55 | dims = [m,n]; 56 | # gzwrite(void* gzf, int[2] dims, int nbytes); 57 | m = dims(1); n = dims(2); nbytes = m*n*dsize; 58 | # gzwrite(void* gzf, double[m,n] A, int nbytes); 59 | 60 | 61 | // ---- 62 | @function gzsave(path, A) 63 | % gzsave(path, A) 64 | % 65 | % Save a matrix to a zlib file. 66 | 67 | gzf = gzopen(path, 'w+'); 68 | gzwrite(gzf, A) 69 | 70 | 71 | // ---- 72 | @function [A] = gzload(path) 73 | % [A] = gzload(path) 74 | % 75 | % Read a matrix from a zlib file. 76 | 77 | gzf = gzopen(path, 'r'); 78 | A = gzread(gzf); 79 | -------------------------------------------------------------------------------- /example/eventq/eventq_class.mw: -------------------------------------------------------------------------------- 1 | % eventq_class.mw 2 | % Simple event queue for use in MATLAB event-driven simulations. 3 | % Uses the MATLAB OO system for encapsulating the event queue. 4 | % 5 | % Copyright (c) 2007 David Bindel 6 | % See the file COPYING for copying permissions 7 | 8 | $ #include 9 | $ 10 | $ typedef std::pair Event; 11 | $ typedef std::priority_queue< Event, 12 | $ std::vector, 13 | $ std::greater > EventQueue; 14 | 15 | 16 | @ @eventq/eventq.m ------------------------------------- 17 | 18 | function [qobj] = eventq(); 19 | 20 | qobj = []; 21 | # EventQueue* q = new EventQueue(); 22 | qobj.q = q; 23 | qobj = class(qobj, 'eventq'); 24 | 25 | 26 | @ @eventq/destroy.m ------------------------------------- 27 | 28 | function destroy(qobj); 29 | 30 | q = qobj.q; 31 | # delete(EventQueue* q); 32 | 33 | 34 | @ @eventq/empty.m ------------------------------------- 35 | 36 | function [e] = empty(qobj) 37 | 38 | q = qobj.q; 39 | # int e = q->EventQueue.empty(); 40 | 41 | 42 | @ @eventq/pop.m ------------------------------------- 43 | 44 | function [id, t] = pop(qobj) 45 | 46 | $ void pop_event(EventQueue* q, int& id, double& t) { 47 | $ t = q->top().first; 48 | $ id = q->top().second; 49 | $ q->pop(); 50 | $ } 51 | $ 52 | q = qobj.q; 53 | # pop_event(EventQueue* q, output int& id, output double& t); 54 | 55 | 56 | @ @eventq/push.m ------------------------------------- 57 | 58 | function push(qobj, id, t) 59 | 60 | $ void push_events(EventQueue* q, int* id, double* t, int m) 61 | $ { 62 | $ for (int i = 0; i < m; ++i) 63 | $ q->push(Event(t[i], id[i])); 64 | $ } 65 | $ 66 | q = qobj.q; 67 | m = length(id); 68 | # push_events(EventQueue* q, int[m] id, double[m] t, int m); 69 | -------------------------------------------------------------------------------- /example/fem/test_patch.m: -------------------------------------------------------------------------------- 1 | % test_mesh3.m 2 | % Test MWrap interface to mesh data structure. 3 | % 4 | % Copyright (c) 2007 David Bindel 5 | % See the file COPYING for copying permissions 6 | 7 | init; 8 | 9 | mobj = Mesh_create(2, 2, 4); 10 | try 11 | fprintf('-- Four element elastic patch test --\n'); 12 | 13 | % Nodes: 14 | % 1 2 3 4 5 6 7 8 9 15 | x = [ 0.0, 4.0, 10.0, 0.0, 5.5, 10.0, 0.0, 4.2, 10.0; 16 | 0.0, 0.0, 0.0, 4.5, 5.5, 5.0, 10.0, 10.0, 10.0]; 17 | 18 | % Boundary codes and values 19 | bc =[ 1, 0, 0, 1, 0, 0, 1, 0, 0; 20 | 1, 0, 0, 0, 0, 0, 0, 0, 0]; 21 | bv =[ 0, 0, 2.5, 0, 0, 5.0, 0, 0, 2.5, 22 | 0, 0, 0, 0, 0, 0, 0, 0, 0]; 23 | 24 | % Elements: 25 | % 1 2 3 4 26 | ix = [ 1, 2, 4, 5 ; 27 | 2, 3, 5, 6 ; 28 | 5, 6, 8, 9 ; 29 | 4, 5, 7, 8 ]; 30 | 31 | % Set up problem mesh 32 | material = Mesh_add_elastic2d(mobj, 1000.0, 0.25, 'plane strain'); 33 | Mesh_load(mobj, material, x, ix); 34 | Mesh_initialize(mobj); 35 | 36 | % Set boundary conditions 37 | Mesh_set_bc(mobj, bc); 38 | Mesh_set_bv(mobj, bv); 39 | Mesh_assign_ids(mobj); 40 | 41 | % Assemble stiffness and force 42 | K = Mesh_assemble_K(mobj); 43 | F = Mesh_assemble_F(mobj); 44 | 45 | % Solve for the reduced displacement 46 | u = -K\F; 47 | 48 | % Patch test should recover linear fields -- check that it does 49 | uu = Mesh_u(mobj); 50 | resid = uu - (uu/x)*x; 51 | fprintf('Patch test residual: %g\n', norm(resid)); 52 | 53 | % Assemble residual and make sure it's zero 54 | Mesh_set_ur(mobj, u); 55 | RR = Mesh_assemble_F(mobj); 56 | fprintf('Reported residual force: %g\n', norm(RR)); 57 | 58 | catch 59 | 60 | fprintf('Error: %s\n', lasterr); 61 | 62 | end 63 | Mesh_delete(mobj); 64 | -------------------------------------------------------------------------------- /example/fem/src/scalar2d.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * scalar2d.cc 3 | * Element type for 2D Laplacian (4 node quad only). 4 | * 5 | * Copyright (c) 2007 David Bindel 6 | * See the file COPYING for copying permissions 7 | */ 8 | 9 | #include "etype.h" 10 | #include "mesh.h" 11 | #include "scalar2d.h" 12 | #include "quad2d.h" 13 | #include "gauss2by2.h" 14 | 15 | #define ME Scalar2D 16 | 17 | 18 | void ME::assign_ids(Mesh* mesh, int eltid) 19 | { 20 | for (int i = 0; i < 4; ++i) 21 | mesh->id(0, mesh->ix(i,eltid)) = 1; 22 | } 23 | 24 | 25 | void ME::assemble_f(Mesh* mesh, int eltid) 26 | { 27 | Quad2d quad; 28 | Gauss4 xi(quad); 29 | get_quad(quad, mesh, eltid); 30 | 31 | vector K(4*4); 32 | for (xi.start(); !xi.done(); ++xi) { 33 | 34 | // Compute grad u at the quadrature point 35 | double dudx[2] = {0, 0}; 36 | for (int j = 0; j < 4; ++j) { 37 | double uj = mesh->u(0,mesh->ix(j,eltid)); 38 | dudx[0] += xi.dN(j,0) * uj; 39 | dudx[1] += xi.dN(j,1) * uj; 40 | } 41 | 42 | // Contribute k * dot(grad N_i, grad u) * wt 43 | for (int i = 0; i < 4; ++i) 44 | mesh->f(0,mesh->ix(i,eltid)) += 45 | k * (xi.dN(i,0) * dudx[0] + 46 | xi.dN(i,1) * dudx[1]) * xi.wt(); 47 | } 48 | } 49 | 50 | 51 | void ME::assemble_K(Mesh* mesh, int eltid, 52 | MatrixAssembler* K_assembler) 53 | { 54 | Quad2d quad; 55 | Gauss4 xi(quad); 56 | get_quad(quad, mesh, eltid); 57 | 58 | vector K(4*4); 59 | for (xi.start(); !xi.done(); ++xi) 60 | for (int j = 0; j < 4; ++j) 61 | for (int i = 0; i < 4; ++i) 62 | K[4*j+i] += 63 | k * (xi.dN(i,0) * xi.dN(j,0) + 64 | xi.dN(i,1) * xi.dN(j,1)) * xi.wt(); 65 | 66 | K_assembler->add_entry(id, id, &(K[0]), 4, 4); 67 | } 68 | 69 | 70 | void ME::get_quad(FEShapes& quad, Mesh* mesh, int eltid) 71 | { 72 | for (int i = 0; i < 4; ++i) { 73 | int n = mesh->ix(i,eltid); 74 | quad.set_node(i, mesh->x(n)); 75 | id[i] = mesh->id(0,n); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /testing/test_single.mw: -------------------------------------------------------------------------------- 1 | % test double and single precision, scalars and arrays, in mwrap. 2 | % Barnett & Gimbutas 7/5/20-7/20/20. 3 | 4 | % make as in Makefile, 5 | % then pass-fail test in octave/matlab with: 6 | % test_single.m 7 | 8 | % the old non-pass-fail is here: 9 | % test_single_humanreadable.m 10 | 11 | 12 | % REAL====================================================== 13 | 14 | % scalar real......... 15 | 16 | $ void add(double a, double b, double *c) { *c = a + b; } 17 | @function c=add(a,b) 18 | # add(double a, double b, output double[1]c); 19 | 20 | $ void addf(float a, float b, float *c) { *c = a + b; } 21 | @function c=addf(a,b) 22 | # addf(float a, float b, output float[1]c); 23 | 24 | % array real........ 25 | 26 | $ void arradd(double *a, double *b, double *c, int n) 27 | $ { for (int i=0;idouble, as mwrap 0.33.3 designed for! 33 | 34 | try 35 | c = arradd(xf,xf) % should error 36 | catch ME 37 | ME.message 38 | disp('good') 39 | end 40 | 41 | try 42 | c = arraddf(x,x), class(c) % should error 43 | catch ME 44 | ME.message 45 | disp('good') 46 | end 47 | 48 | c = arraddf(xf,xf) % input as designed, should give single 49 | 50 | 51 | fprintf('\nscalar complex routines...\n') 52 | z = (1+2i)/3; zf = single(z); 53 | c = addz(z,z), class(c) 54 | 55 | try 56 | c = addz(zf,zf) % should error 57 | catch ME 58 | ME.message 59 | disp('good') 60 | end 61 | 62 | try 63 | c = addc(z,z), class(c) % should error 64 | catch ME 65 | ME.message 66 | disp('good') 67 | end 68 | 69 | c = addc(zf,zf) % input as designed, should give single 70 | 71 | fprintf('\narray complex routines...\n') 72 | z = z*ones(3,1); zf = zf*ones(3,1); 73 | 74 | try 75 | c = arraddz(z,z), class(c) % input as designed, double 76 | catch ME 77 | ME.message 78 | disp('****** bad') 79 | end 80 | 81 | try 82 | c = arraddz(zf,zf) % should error 83 | catch ME 84 | ME.message 85 | disp('good') 86 | end 87 | 88 | try 89 | c = arraddc(z,z), class(c) % should error 90 | catch ME 91 | ME.message 92 | disp('good') 93 | end 94 | 95 | try 96 | c = arraddc(zf,zf) % input as designed, should give single 97 | catch ME 98 | ME.message 99 | disp('****** bad') 100 | end 101 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | MWrap 2 | ===== 3 | 4 | MWrap is an interface generation system in the spirit of SWIG or matwrap. 5 | From a set of augmented MATLAB script files, MWrap will generate a MEX gateway to desired C/C++/Fortran function calls and MATLAB function files to access that gateway. 6 | It makes wrapping C/C++/Fortran from MATLAB almost pleasant! 7 | The details of converting to and from MATLAB's data structures, and of 8 | allocating and freeing temporary storage, are hidden from the user. It is also compatible with modern Octave via `mkoctfile --mex`. 9 | 10 | To compile, edit `make.inc` and then run `make`. The output will be a standalone executable (`mwrap`) in the main directory. 11 | 12 | It was created by David Bindel, who hosts his old version 13 | at https://www.cs.cornell.edu/~bindel/sw/mwrap 14 | 15 | 16 | Example usage 17 | ------------- 18 | 19 | David Bindel's user's guide (`mwrap.pdf`) describes MWrap in detail; you can also look at the example subdirectories and the testing subdirectory to get some idea of how MWrap is used. 20 | 21 | Alex Barnett also maintains a set of minimally complete tutorial examples of calling C/Fortran libraries (including OpenMP) from MATLAB/Octave, using MWrap, at https://github.com/ahbarnett/mwrapdemo 22 | 23 | 24 | Contributors and version history 25 | -------------------------------- 26 | 27 | MWrap was originally written by David Bindel, c. 2009. 28 | It was moved to github in c. 2015 in order to add new features, and is now maintained by Zydrunas Gimbutas, Alex Barnett, Libin Lu, Manas Rachh, and Rafael Laboissière. 29 | 30 | Version 0.33 (c. 2009) 31 | Author: David Bindel 32 | Initial revision, clone David's repository (c. 2015) 33 | 34 | Version 1.0 (c. 2020) 35 | Contributors: Zydrunas Gimbutas, Alex Barnett, Libin Lu. 36 | Add support for 64-bit Matlab and gcc-4.6 37 | Add support for gcc 7.3+ 38 | Add support for Matlab R2018a complex interleaved API 39 | Add support for C99 int32_t, int64_t, uint32_t, uint64_t 40 | Allow single precision Matlab inputs and outputs 41 | 42 | Version 1.1 (2022) 43 | Contributors: Manas Rachh, Zydrunas Gimbutas. 44 | Add support for gfortran -fno-underscoring flag 45 | 46 | Version 1.2 (2025) 47 | Contributors: Libin Lu, Rafael Laboissière, Zydrunas Gimbutas. 48 | Cope with error verbose directive in both versions 2 and 3 of Bison 49 | Add support for Matlab gpuArray 50 | Add support for char scalar 51 | 52 | Also see https://github.com/zgimbutas/mwrap/tags 53 | -------------------------------------------------------------------------------- /example/fem/interface/assembler.mw: -------------------------------------------------------------------------------- 1 | % assembler.mw 2 | % MWrap bindings for MatrixAssembler (CSC matrix assembly). 3 | % 4 | % Copyright (c) 2007 David Bindel 5 | % See the file COPYING for copying permissions 6 | 7 | $[ 8 | #include "assembler.h" 9 | #include 10 | #include 11 | 12 | mxArray* export_matrix(MatrixAssembler* matrix) 13 | { 14 | matrix->compress(); 15 | int m = matrix->get_m(); 16 | int n = matrix->get_n(); 17 | int nnz = matrix->csc_nnz(); 18 | mxArray* result = mxCreateSparse(m, n, nnz, mxREAL); 19 | std::copy(matrix->get_jc(), matrix->get_jc()+n+1, mxGetJc(result)); 20 | std::copy(matrix->get_ir(), matrix->get_ir()+nnz, mxGetIr(result)); 21 | std::copy(matrix->get_pr(), matrix->get_pr()+nnz, mxGetPr(result)); 22 | return result; 23 | } 24 | $] 25 | 26 | 27 | @function aobj = Assembler_create(m, n, nnz) 28 | % aobj = Assembler_create(m, n) 29 | % 30 | % Create an assembly object for m-by-n matrices. 31 | if nargin < 2, m = n; end 32 | if nargin < 3 33 | # MatrixAssembler* aobj = new MatrixAssembler(int m, int n); 34 | else 35 | # MatrixAssembler* aobj = new MatrixAssembler(int m, int n, int nnz); 36 | end 37 | 38 | 39 | @function Assembler_delete(aobj) 40 | % Assembler_delete(aobj) 41 | % 42 | % Delete a matrix assembler object 43 | # delete(MatrixAssembler* aobj); 44 | 45 | 46 | @function Assembler_add(aobj, ii, jj, Aelt) 47 | % Assembler_create(aobj, ii, jj, Aelt) 48 | % 49 | % Perform A(ii,jj) += Aelt. 50 | [m,n] = size(Aelt); 51 | ii = ii-1; 52 | jj = jj-1; 53 | # aobj->MatrixAssembler.add_entry(int[m] ii, int[n] jj, double[m,n] Aelt, 54 | # int m, int n); 55 | 56 | 57 | @function K = Assembler_get(aobj) 58 | % K = Assembler_get(aobj) 59 | % 60 | % Retrieve a sparse matrix from a matrix assembler. 61 | # mxArray K = export_matrix(MatrixAssembler* aobj); 62 | 63 | 64 | @function Assembler_clear(aobj) 65 | % Assembler_clear(aobj) 66 | % 67 | % Clear the matrix assembler in preparation for building a new matrix. 68 | # aobj->MatrixAssembler.wipe(); 69 | 70 | 71 | @function [structure_nnz, cached_nnz] = Assembler_stats(aobj) 72 | % [structure_nnz, cached_nnz] = Assembler_stats(aobj) 73 | % 74 | % Get statistics about the nonzeros in the assembler. 75 | # int structure_nnz = aobj->MatrixAssembler.csc_nnz(); 76 | # int cached_nnz = aobj->MatrixAssembler.cache_nnz(); 77 | if nargout == 0 78 | fprintf('NNZ in structure: %d\n', structure_nnz); 79 | fprintf('NNZ in cache: %d\n', cached_nnz); 80 | end 81 | 82 | -------------------------------------------------------------------------------- /src/mwrap-mgen.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * mwrap-mgen.cc 3 | * Generate MATLAB scripts from MWrap AST. 4 | * 5 | * Copyright (c) 2007 David Bindel 6 | * See the file COPYING for copying permissions 7 | */ 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include "mwrap-ast.h" 14 | 15 | 16 | /* -- Output MATLAB call code -- */ 17 | /* 18 | * Each call is translated to MATLAB code of the form 19 | * 20 | * mex_id_ = 'identifier from id_string'; 21 | * [result1, result2, ...] = mexfunc(mex_id_, in1, ..., dim1, dim2, ...); 22 | * 23 | * where dim1, dim2, ... are any explicitly provided array dimensions. 24 | */ 25 | 26 | 27 | int has_output_args(Var* v) 28 | { 29 | if (!v) 30 | return 0; 31 | if (v->iospec == 'o' || v->iospec == 'b') 32 | return 1; 33 | else 34 | return has_output_args(v->next); 35 | } 36 | 37 | 38 | void print_output_args(FILE* fp, Var* v, int& first) 39 | { 40 | if (!v) 41 | return; 42 | if (v->iospec == 'o' || v->iospec == 'b') { 43 | if (!first) 44 | fprintf(fp, ", "); 45 | fprintf(fp, "%s", v->name); 46 | first = 0; 47 | } 48 | print_output_args(fp, v->next, first); 49 | } 50 | 51 | 52 | void print_input_args(FILE* fp, Var* v) 53 | { 54 | if (!v) 55 | return; 56 | if (v->tinfo == VT_const) 57 | fprintf(fp, ", 0"); 58 | else if (v->iospec == 'i' || v->iospec == 'b') 59 | fprintf(fp, ", %s", v->name); 60 | print_input_args(fp, v->next); 61 | } 62 | 63 | 64 | void print_dimension_args(FILE* fp, Expr* e) 65 | { 66 | if (!e) 67 | return; 68 | fprintf(fp, ", %s", e->value); 69 | print_dimension_args(fp, e->next); 70 | } 71 | 72 | 73 | void print_dimension_args(FILE* fp, Var* v) 74 | { 75 | if (!v) 76 | return; 77 | if (v->qual) 78 | print_dimension_args(fp, v->qual->args); 79 | print_dimension_args(fp, v->next); 80 | } 81 | 82 | 83 | void print_matlab_call(FILE* fp, Func* f, const char* mexfunc) 84 | { 85 | fprintf(fp, "mex_id_ = '%s';\n", id_string(f).c_str()); 86 | if (f->ret || has_output_args(f->args)) { 87 | int first = 1; 88 | fprintf(fp, "["); 89 | print_output_args(fp, f->ret, first); 90 | print_output_args(fp, f->args, first); 91 | fprintf(fp, "] = "); 92 | } 93 | fprintf(fp, "%s(mex_id_", mexfunc); 94 | if (f->thisv) 95 | fprintf(fp, ", %s", f->thisv); 96 | print_input_args(fp, f->args); 97 | print_dimension_args(fp, f->ret); 98 | print_dimension_args(fp, f->args); 99 | fprintf(fp, ");\n"); 100 | } 101 | -------------------------------------------------------------------------------- /example/fem/src/mesh.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * mesh.cc 3 | * Finite element mesh implementation. 4 | * 5 | * Copyright (c) 2007 David Bindel 6 | * See the file COPYING for copying permissions 7 | */ 8 | #include "mesh.h" 9 | 10 | #define ME Mesh 11 | 12 | 13 | EType::~EType() 14 | { 15 | } 16 | 17 | 18 | ME::~ME() 19 | { 20 | for (vector::iterator i = materials_owned.begin(); 21 | i != materials_owned.end(); ++i) { 22 | delete(*i); 23 | } 24 | } 25 | 26 | 27 | int ME::add_node(double* x) 28 | { 29 | int id = numnp(); 30 | for (int i = 0; i < ndm_; ++i) 31 | X.push_back(x[i]); 32 | return id; 33 | } 34 | 35 | 36 | int ME::add_element(EType* etype, int* nodes, int nen) 37 | { 38 | int id = numelt(); 39 | int i = 0; 40 | for (; i < nen && i < maxnen_; ++i) IX.push_back(nodes[i]); 41 | for (; i < maxnen_; ++i) IX.push_back(-1); 42 | elements.push_back(etype); 43 | return id; 44 | } 45 | 46 | 47 | void ME::add_material(EType* material) 48 | { 49 | materials_owned.push_back(material); 50 | } 51 | 52 | 53 | void ME::set_ur(const double* ur) 54 | { 55 | for (int i = 0; i < ID.size(); ++i) { 56 | if (ID[i] >= 0) 57 | U[i] = ur[ID[i]]; 58 | if (BC[i]) 59 | U[i] = BV[i]; 60 | } 61 | } 62 | 63 | 64 | void ME::get_ur(double* ur) 65 | { 66 | for (int i = 0; i < ID.size(); ++i) 67 | if (ID[i] >= 0) 68 | ur[ID[i]] = U[i]; 69 | } 70 | 71 | 72 | void ME::get_fr(double* fr) 73 | { 74 | for (int i = 0; i < ID.size(); ++i) { 75 | if (ID[i] >= 0) 76 | fr[ID[i]] = R[i]; 77 | if (!BC[i]) 78 | fr[ID[i]] -= BV[i]; 79 | } 80 | } 81 | 82 | 83 | int ME::initialize() 84 | { 85 | ID.resize(maxndf_ * numnp()); 86 | R.resize (maxndf_ * numnp()); 87 | U.resize (maxndf_ * numnp()); 88 | BC.resize(maxndf_ * numnp()); 89 | BV.resize(maxndf_ * numnp()); 90 | return assign_ids(); 91 | } 92 | 93 | 94 | int ME::assign_ids() 95 | { 96 | numid_ = 0; 97 | int n = numelt(); 98 | 99 | for (int i = 0; i < ID.size(); ++i) 100 | ID[i] = 0; 101 | 102 | for (int i = 0; i < n; ++i) 103 | if (elements[i]) 104 | elements[i]->assign_ids(this, i); 105 | 106 | for (int i = 0; i < ID.size(); ++i) 107 | ID[i] = ( (ID[i] && !BC[i]) ? numid_++ : -1 ); 108 | 109 | return numid_; 110 | } 111 | 112 | 113 | void ME::assemble_F() 114 | { 115 | int n = numelt(); 116 | for (int i = 0; i < n; ++i) 117 | if (elements[i]) 118 | elements[i]->assemble_f(this, i); 119 | } 120 | 121 | 122 | void ME::assemble_K(MatrixAssembler* K_assembler) 123 | { 124 | int n = numelt(); 125 | for (int i = 0; i < n; ++i) 126 | if (elements[i]) 127 | elements[i]->assemble_K(this, i, K_assembler); 128 | } 129 | -------------------------------------------------------------------------------- /doc/mwrap.1: -------------------------------------------------------------------------------- 1 | .TH MWRAP 1 2012 "mwrap" "MWRAP manpage" 2 | .SH NAME 3 | mwrap - Octave/MATLAB mex generator 4 | .SH SYNOPSIS 5 | .SY mwrap 6 | .OP \-mex \fIoutputmex\fP 7 | .OP \-m \fIoutput.m\fP 8 | .OP \-c \fIoutputmex.c\fP 9 | .OP \-mb 10 | .OP \-list 11 | .OP \-catch 12 | .OP \-i8 13 | .OP \-c99complex 14 | .OP \-cppcomplex 15 | .OP \-gpu 16 | \fIinfile1\fP \fIinfile2\fP ... 17 | .br 18 | .SH DESCRIPTION 19 | .LP 20 | \fBmwrap\fP is an interface generation system in the spirit of SWIG or 21 | matwrap. From a set of augmented Octave/MATLAB script files, \fBmwrap\fP 22 | will generate a MEX gateway to desired C/C++ function calls and \.m function 23 | files to access that gateway. The details of converting to and from 24 | Octave's or MATLAB's data structures, and of allocating and freeing 25 | temporary storage, are hidden from the user. 26 | .SH OPTIONS 27 | .TP 28 | .B \-mex 29 | specifies the name of the MEX function that the generated functions will 30 | call. This name will generally be the same as the prefix for the C/C++ 31 | output file name. 32 | . 33 | .TP 34 | .B \-m 35 | specifies the name of the Octave/MATLAB script to be generated. 36 | . 37 | .TP 38 | .B \-c 39 | specifies the name of the C MEX file to be generated. The MEX file may 40 | contain stubs corresponding to several different generated files. 41 | . 42 | .TP 43 | .B \-mb 44 | redirect Octave/MATLAB function output to files named in the input. In this 45 | mode, the processor will change Octave/MATLAB function output files whenever 46 | it encounters a line beginning with @. If @ occurs alone on a line, the 47 | output will be turned off; if the line begins with @function, the line will 48 | be treated as the first line of a function, and the m-file name will be 49 | deduced from the function name; and otherwise, the characters after @ (up to 50 | the next set of white space) will be treated as a filename, and \fBmwrap\fP 51 | will try to write to that file. 52 | . 53 | .TP 54 | .B \-list 55 | print to the standard output the names of all files that would be generated 56 | from redirect output by the \-mb flag. 57 | . 58 | .TP 59 | .B \-catch 60 | surround library calls in try/catch blocks in order to intercept C++ 61 | exceptions. 62 | . 63 | .TP 64 | .B \-i8 65 | convert \fBint\fP, \fBlong\fP, \fBuint\fP, \fBulong\fP types to 66 | \fBint64_t\fP, \fBuint64_t\fP. This provides 67 | a convenient way to interface with \fB-fdefault-integer-8\fP and 68 | \fB-i8\fP flags used by Fortran compilers. 69 | . 70 | .TP 71 | .B \-c99complex 72 | use the C99 complex floating point types as the default \fBdcomplex\fP and 73 | \fBfcomplex\fP types. 74 | . 75 | .TP 76 | .B \-cppcomplex 77 | use the C++ complex floating point types as the default \fBdcomplex\fP and 78 | \fBfcomplex\fP types. 79 | . 80 | .TP 81 | .B \-gpu 82 | add support code for MATLAB gpuArray. 83 | 84 | .SH AUTHORS 85 | .LP 86 | \fBmwrap\fP is written by David Bindel and Zydrunas Gimbutas. This 87 | manual page was written by Nicolas Bourdaud. 88 | -------------------------------------------------------------------------------- /example/fem/src/assembler.h: -------------------------------------------------------------------------------- 1 | /* 2 | * assembler.h 3 | * Compressed sparse column matrix assembler interface. 4 | * 5 | * Copyright (c) 2007 David Bindel 6 | * See the file COPYING for copying permissions 7 | */ 8 | 9 | #ifndef ASSEMBLER_H 10 | #define ASSEMBLER_H 11 | 12 | #include 13 | using std::vector; 14 | 15 | /* 16 | * The MatrixAssembler class is responsible for assembling a finite element 17 | * matrix. In pure MATLAB, the assembly operation looks something like 18 | * 19 | * for i = 1:num_elements 20 | * [Ke, idx] = element_stiffness(i); 21 | * Ivalid = find(idx > 0 & idx < N); 22 | * idx = idx(Ivalid); 23 | * Ke = Ke(Ivalid,Ivalid); 24 | * K(idx,idx) = K(idx,idx) + Ke; 25 | * end 26 | * 27 | * The method add_entry is equivalent to most of the body of this loop -- 28 | * it removes out-of-range indices and accumulates the rest of the element 29 | * contribution. 30 | * 31 | * Elements in the matrix can be stored in one of two ways. First, 32 | * there are elements that go into the current compressed sparse 33 | * column matrix structure. Then there are elements that correspond 34 | * to indices that were not in the matrix the last time we built the 35 | * compressed sparse column structure. When it is time to assemble 36 | * the matrix, we use the compress method to take all these extra 37 | * elements and merge them into the compressed sparse column indexing 38 | * structure. This means that after K is assembled once, any we can 39 | * assemble other matrices with the same structure using a little less 40 | * time and memory. 41 | */ 42 | 43 | class MatrixAssembler { 44 | public: 45 | MatrixAssembler(int m, int n) : m(m), n(n), jc(n+1) {} 46 | MatrixAssembler(int m, int n, int coord_nnz) : 47 | m(m), n(n), jc(n+1), coords(coord_nnz) {} 48 | 49 | void add_entry(int i, int j, double Aij); 50 | void add_entry(const int* i, const int* j, double* Aij, 51 | int m_elt, int n_elt); 52 | 53 | void wipe(); 54 | void pack_cache(); 55 | void compress(); 56 | 57 | int get_m() { return m; } 58 | int get_n() { return n; } 59 | int* get_jc() { return &(jc[0]); } 60 | int* get_ir() { return &(ir[0]); } 61 | double* get_pr() { return &(pr[0]); } 62 | 63 | int cache_nnz() { return coords.size(); } 64 | int csc_nnz() { return pr.size(); } 65 | 66 | private: 67 | 68 | struct Coord { 69 | Coord() {} 70 | Coord(int i, int j, double Aij) : i(i), j(j), Aij(Aij) {} 71 | bool operator<(const Coord& coord) const { 72 | return ((j < coord.j) || (j == coord.j && i < coord.i)); 73 | } 74 | int i, j; 75 | double Aij; 76 | }; 77 | 78 | int m, n; 79 | 80 | // Things that fit in the compressed sparse representation 81 | vector jc; 82 | vector ir; 83 | vector pr; 84 | 85 | // Cache of entries that didn't fit in the compressed sparse form 86 | vector coords; 87 | }; 88 | 89 | #endif /* ASSEMBLER_H */ 90 | -------------------------------------------------------------------------------- /example/fem/src/assembler2.h: -------------------------------------------------------------------------------- 1 | /* 2 | * assembler.h 3 | * Compressed sparse column matrix assembler interface. 4 | * 5 | * Copyright (c) 2007 David Bindel 6 | * See the file COPYING for copying permissions 7 | */ 8 | 9 | #ifndef ASSEMBLER2_H 10 | #define ASSEMBLER2_H 11 | 12 | #include 13 | using std::vector; 14 | 15 | /* 16 | * The MatrixAssembler2 class is responsible for assembling a finite element 17 | * matrix. In pure MATLAB, the assembly operation looks something like 18 | * 19 | * for i = 1:num_elements 20 | * [Ke, idx] = element_stiffness(i); 21 | * Ivalid = find(idx > 0 & idx < N); 22 | * idx = idx(Ivalid); 23 | * Ke = Ke(Ivalid,Ivalid); 24 | * K(idx,idx) = K(idx,idx) + Ke; 25 | * end 26 | * 27 | * The method add_entry is equivalent to most of the body of this loop -- 28 | * it removes out-of-range indices and accumulates the rest of the element 29 | * contribution. 30 | * 31 | * Elements in the matrix can be stored in one of two ways. First, 32 | * there are elements that go into the current compressed sparse 33 | * column matrix structure. Then there are elements that correspond 34 | * to indices that were not in the matrix the last time we built the 35 | * compressed sparse column structure. When it is time to assemble 36 | * the matrix, we use the compress method to take all these extra 37 | * elements and merge them into the compressed sparse column indexing 38 | * structure. This means that after K is assembled once, we can 39 | * assemble other matrices with the same structure using a little less 40 | * time and memory. 41 | */ 42 | 43 | class MatrixAssembler2 { 44 | public: 45 | MatrixAssembler2(int m, int n) : m(m), n(n), jc(n+1) {} 46 | MatrixAssembler2(int m, int n, int coord_nnz) : 47 | m(m), n(n), jc(n+1), coords(coord_nnz) {} 48 | 49 | void add_entry(int i, int j, double Aij); 50 | void add_entry(const int* i, const int* j, double* Aij, 51 | int m_elt, int n_elt); 52 | 53 | void wipe(); 54 | void pack_cache(); 55 | void compress(); 56 | 57 | int get_m() { return m; } 58 | int get_n() { return n; } 59 | int* get_jc() { return &(jc[0]); } 60 | int* get_ir() { return &(ir[0]); } 61 | double* get_pr() { return &(pr[0]); } 62 | 63 | int cache_nnz() { return coords.size(); } 64 | int csc_nnz() { return pr.size(); } 65 | 66 | private: 67 | 68 | struct Coord { 69 | Coord() {} 70 | Coord(int i, int j, double Aij) : i(i), j(j), Aij(Aij) {} 71 | bool operator<(const Coord& coord) const { 72 | return ((j < coord.j) || (j == coord.j && i < coord.i)); 73 | } 74 | int i, j; 75 | double Aij; 76 | }; 77 | 78 | int m, n; 79 | 80 | // Things that fit in the compressed sparse representation 81 | vector jc; 82 | vector ir; 83 | vector pr; 84 | 85 | // Cache of entries that didn't fit in the compressed sparse form 86 | vector coords; 87 | }; 88 | 89 | #endif /* ASSEMBLER2_H */ 90 | -------------------------------------------------------------------------------- /NEWS: -------------------------------------------------------------------------------- 1 | Recent updates: 2 | 3 | Version 1.2 (Apr 10, 2025): 4 | Cope with error verbose directive in both versions 2 and 3 of Bison 5 | Added support for gpuArray 6 | Added support for char scalar 7 | 8 | Version 1.1 (Jun 7, 2022): 9 | Added support for gfortran -fno-underscoring flag 10 | 11 | Version 1.0 (Aug 4, 2020): 12 | Added support for 64-bit Matlab and gcc-4.6 13 | Added support for gcc 7.3+ 14 | Added support for Matlab R2018a complex interleaved API 15 | Added support for C99 int32_t, int64_t, uint32_t, uint64_t 16 | Allow single precision Matlab inputs and outputs 17 | 18 | Version 0.32 (Nov 5, 2008): 19 | Added support for new single-class style MATLAB objects; an example 20 | is in the manual, as well as in examples/eventq. 21 | 22 | Version 0.31 (Jun 19, 2008): 23 | Added line to license to clarify that code generated by MWrap may be 24 | redistributed under terms of the user's choice. 25 | 26 | Version 0.30 (Apr 29, 2008): 27 | Added more complete support for auto-converted objects, allowing them to 28 | be used as inout or output parameters and updating the documentation 29 | accordingly. Corrected bug in C call line checking feature (added in 0.28); 30 | corrected missing virtual destructor for Quad2d in FEM example. 31 | 32 | Version 0.29 (Apr 27, 2008): 33 | Reworked internal error handling logic. Added typedef mxArray support 34 | to allow automatic conversion of mxArrays to temporary objects on input. 35 | 36 | Version 0.28 (Mar 4, 2008): 37 | Added a check against ending a block of C call lines without finishing 38 | a statement (e.g. missing a semicolon on an isolated call line). 39 | Added support for C++ end-of-line comments inside C call lines. 40 | Added partial recovery on syntax errors. 41 | 42 | Version 0.27 (Feb 19, 2008): 43 | Added const arguments. 44 | 45 | Version 0.26 (Feb 18, 2008): 46 | Updated demos. 47 | 48 | Version 0.25 (Feb 8, 2008): 49 | Corrected code to add bounds checks on complex arrays. 50 | Added nonzero return codes on error. 51 | 52 | Version 0.24 (Feb 7, 2008): 53 | Added comment lines. 54 | 55 | Version 0.23 (Feb 6, 2008): 56 | Added logging support for profiling / coverage testing. 57 | 58 | Version 0.22 (Jan 29, 2008): 59 | Added @include support. 60 | 61 | Version 0.21 (Jan 7, 2008): 62 | Added support for string literal arguments. 63 | Added support for @function redirections. 64 | Corrected line number counting in presence of $[ $] code blocks. 65 | 66 | Version 0.20 (Sep 20, 2007): 67 | Added $[ $] delimiters for C code blocks. 68 | 69 | Version 0.19 (Sep 4, 2007): 70 | Added array references. 71 | 72 | Version 0.18 (August 15, 2007): 73 | Added interpretation of empty input array arguments as NULL. 74 | 75 | Version 0.17 (July 31, 2007): 76 | Added scoped names for access to static methods, namespaces. 77 | 78 | Version 0.16 (July 9, 2007): 79 | Added flags to set default complex support to C++ or C99 complex types 80 | 81 | Version 0.15 (July 5, 2007): 82 | Corrected complex support (needs setz macro) 83 | 84 | Version 0.14 (July 3, 2007): 85 | Added complex support 86 | 87 | Version 0.13 (June 30, 2007): 88 | Added FORTRAN bindings 89 | -------------------------------------------------------------------------------- /testing/test_single.m: -------------------------------------------------------------------------------- 1 | function test_single 2 | % pass-fail test of the single- and double-precision args and arrays. 3 | % must do either make test_single_cpp or make test_single_c99 first. 4 | % Barnett & Gimbutas. 7/20/20 5 | 6 | tol = 2e-16; 7 | tols = 1e-7; 8 | %format long g % for debug 9 | 10 | 11 | %fprintf('scalar real routines...\n') % ------------------------------------- 12 | x = 1/3; ce = x+x; xf = single(x); 13 | c = add(x,x); 14 | assert(abs(c-ce)tol) % test it's not doing double-prec! 32 | assert(class(c)=='single') 33 | 34 | 35 | %fprintf('\narray real routines...\n') % ------------------------------------ 36 | x = x*ones(3,1); xf = xf*ones(3,1); ce=x+x; 37 | c = arradd(x,x); 38 | assert(norm(c-ce)double, as mwrap 0.33.3 designed for! 40 | 41 | try 42 | c = arradd(xf,xf); % should error 43 | catch ME 44 | assert(ME.message=='test_singlemex: Invalid array argument, mxDOUBLE_CLASS expected'); 45 | end 46 | 47 | try 48 | c = arraddf(x,x); % should error 49 | catch ME 50 | assert(ME.message=='test_singlemex: Invalid array argument, mxSINGLE_CLASS expected'); 51 | end 52 | 53 | c = arraddf(xf,xf); % input as designed, should give single 54 | assert(norm(double(c)-ce)tol) % test it's not doing double-prec! 56 | assert(class(c)=='single') 57 | 58 | 59 | %fprintf('\nscalar complex routines...\n') % ------------------------------- 60 | z = (1+2i)/3; zf = single(z); ce = z+z; 61 | c = addz(z,z); 62 | assert(abs(c-ce)double, as mwrap 0.33.3 designed for! 64 | 65 | try 66 | c = addz(zf,zf); % should error 67 | catch ME 68 | assert(ME.message=='test_singlemex: Invalid scalar argument, mxDOUBLE_CLASS expected'); 69 | end 70 | 71 | try 72 | c = addc(z,z); % should error 73 | catch ME 74 | assert(ME.message=='test_singlemex: Invalid scalar argument, mxSINGLE_CLASS expected'); 75 | end 76 | 77 | c = addc(zf,zf); % input as designed, should give single 78 | assert(abs(double(c)-ce)tol) % test it's not doing double-prec! 80 | assert(class(c)=='single') 81 | 82 | 83 | % fprintf('\narray complex routines...\n') % -------------------------------- 84 | z = z*ones(3,1); zf = zf*ones(3,1); ce = z+z; 85 | c = arraddz(z,z); % input as designed, double 86 | assert(norm(c-ce)double, as mwrap 0.33.3 designed for! 88 | 89 | try 90 | c = arraddz(zf,zf); % should error 91 | catch ME 92 | assert(ME.message=='test_singlemex: Invalid array argument, mxDOUBLE_CLASS expected'); 93 | end 94 | 95 | try 96 | c = arraddc(z,z); % should error 97 | catch ME 98 | assert(ME.message=='test_singlemex: Invalid array argument, mxSINGLE_CLASS expected'); 99 | end 100 | 101 | c = arraddc(zf,zf); % input as designed, should give single 102 | assert(norm(double(c)-ce)tol) % test it's not doing double-prec! 104 | assert(class(c)=='single') 105 | -------------------------------------------------------------------------------- /example/fem/src/mesh.h: -------------------------------------------------------------------------------- 1 | /* 2 | * mesh.h 3 | * Finite element mesh implementation. 4 | * 5 | * Copyright (c) 2007 David Bindel 6 | * See the file COPYING for copying permissions 7 | */ 8 | 9 | #ifndef MESH_H 10 | #define MESH_H 11 | 12 | #include "assembler.h" 13 | #include "etype.h" 14 | 15 | #include 16 | using std::vector; 17 | 18 | class Mesh { 19 | public: 20 | Mesh(int ndm, int maxndf, int maxnen) : 21 | ndm_(ndm), maxndf_(maxndf), maxnen_(maxnen), numid_(0) {} 22 | ~Mesh(); 23 | 24 | int ndm() const { return ndm_; } 25 | int maxndf() const { return maxndf_; } 26 | int maxnen() const { return maxnen_; } 27 | int numelt() const { return elements.size(); } 28 | int numnp() const { return X.size() / ndm_; } 29 | int numid() const { return numid_; } 30 | 31 | double* x () { return &(X[0]); } 32 | int* ix() { return &(IX[0]); } 33 | int* id() { return &(ID[0]); } 34 | double* u () { return &(U[0]); } 35 | double* f () { return &(R[0]); } 36 | char* bc() { return &(BC[0]); } 37 | double* bv() { return &(BV[0]); } 38 | 39 | const double* x (int j) const { return &(X [j*ndm_]); } 40 | const int* ix(int j) const { return &(IX[j*maxnen_]); } 41 | const int* id(int j) const { return &(ID[j*maxndf_]); } 42 | const double* u (int j) const { return &(U [j*maxndf_]); } 43 | const double* f (int j) const { return &(R [j*maxndf_]); } 44 | double* f (int j) { return &(R [j*maxndf_]); } 45 | const char* bc(int j) const { return &(BC[j*maxndf_]); } 46 | const double* bv(int j) const { return &(BV[j*maxndf_]); } 47 | 48 | double x (int i, int j) const { return X [i+j*ndm_]; } 49 | int ix(int i, int j) const { return IX[i+j*maxnen_]; } 50 | int id(int i, int j) const { return ID[i+j*maxndf_]; } 51 | int& id(int i, int j) { return ID[i+j*maxndf_]; } 52 | double u (int i, int j) const { return U [i+j*maxndf_]; } 53 | double f (int i, int j) const { return R [i+j*maxndf_]; } 54 | double& f (int i, int j) { return R [i+j*maxndf_]; } 55 | char bc(int i, int j) const { return BC[i+j*maxndf_]; } 56 | char& bc(int i, int j) { return BC[i+j*maxndf_]; } 57 | double bv(int i, int j) const { return BV[i+j*maxndf_]; } 58 | double& bv(int i, int j) { return BV[i+j*maxndf_]; } 59 | 60 | void set_ur(const double* ur); 61 | void get_ur(double* ur); 62 | void get_fr(double* ur); 63 | 64 | int initialize(); 65 | int assign_ids(); 66 | 67 | void assemble_F(); 68 | void assemble_K(MatrixAssembler* K_assembler); 69 | 70 | int add_node(double* x); 71 | int add_element(EType* etype, int* nodes, int numnp); 72 | void add_material(EType* material); 73 | 74 | private: 75 | Mesh(const Mesh&); 76 | Mesh& operator=(const Mesh&); 77 | 78 | int ndm_; // Number of spatial dimensions 79 | int maxndf_; // Maximum degrees of freedom per node 80 | int maxnen_; // Maximum number of nodes per element 81 | int numid_; // Number of active degrees of freedom 82 | 83 | vector X; // Coordinate array ( ndm * numnp ) 84 | vector IX; // Element connectivity ( maxnen * numelt ) 85 | vector ID; // Identifier assignment ( maxndf * numnp ) 86 | vector R; // Full residual vector ( maxndf * numnp ) 87 | vector U; // Full solution ( maxndf * numnp ) 88 | vector BC; // Flag Dirichlet BCs ( maxndf * numnp ) 89 | vector BV; // Boundary values ( maxndf * numnp ) 90 | 91 | vector elements; // Material assignment (numelt) 92 | 93 | vector materials_owned; 94 | }; 95 | 96 | #endif /* MESH_H */ 97 | -------------------------------------------------------------------------------- /example/fem/src/assembler.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * assembler.cc 3 | * Compressed sparse column matrix assembler implementation. 4 | * 5 | * Copyright (c) 2007 David Bindel 6 | * See the file COPYING for copying permissions 7 | */ 8 | 9 | #include "assembler.h" 10 | #include 11 | #include 12 | 13 | #define ME MatrixAssembler 14 | 15 | using std::sort; 16 | using std::fill; 17 | 18 | 19 | /* 20 | * Add A(i,j) += Aij. If there's space in the existing compressed 21 | * sparse column data structure, add it there; otherwise, stash it in 22 | * the coords cache vector. 23 | */ 24 | void ME::add_entry(int i, int j, double Aij) 25 | { 26 | if (i < 0 || i >= m || j < 0 || j >= n) 27 | return; 28 | for (int ii = jc[j]; ii < jc[j+1]; ++ii) { 29 | if (ir[ii] == i) { 30 | pr[ii] += Aij; 31 | return; 32 | } 33 | } 34 | coords.push_back(Coord(i,j,Aij)); 35 | } 36 | 37 | 38 | /* 39 | * Add an element submatrix. 40 | */ 41 | void ME::add_entry(const int* i, const int* j, double* Aij, 42 | int m_elt, int n_elt) 43 | { 44 | for (int jj = 0; jj < n_elt; ++jj) 45 | for (int ii = 0; ii < m_elt; ++ii) 46 | add_entry(i[ii], j[jj], Aij[jj*m_elt+ii]); 47 | } 48 | 49 | 50 | /* 51 | * Wipe the input matrix. Note that the compressed sparse column index 52 | * structure remains intact, so we can re-assemble without doing too much 53 | * work. 54 | */ 55 | void ME::wipe() 56 | { 57 | coords.resize(0); 58 | fill(get_pr(), get_pr()+jc[n], 0); 59 | } 60 | 61 | 62 | /* 63 | * Sort the entries in the coords cache, and merge (by summing) contributions 64 | * to the same position. 65 | */ 66 | void ME::pack_cache() 67 | { 68 | if (coords.size() > 0) { 69 | sort(coords.begin(), coords.end()); 70 | int i_merge = 0; 71 | for (int i_coord = 1; i_coord < coords.size(); ++i_coord) { 72 | if (coords[i_merge] < coords[i_coord]) 73 | coords[++i_merge] = coords[i_coord]; 74 | else 75 | coords[i_merge].Aij += coords[i_coord].Aij; 76 | } 77 | coords.resize(i_merge+1); 78 | } 79 | } 80 | 81 | 82 | /* 83 | * Pack the coordinate cache, then merge sort the contents of the compressed 84 | * sparse column data structure with the contents of the entry cache. 85 | */ 86 | void ME::compress() 87 | { 88 | pack_cache(); 89 | 90 | ir.resize(ir.size() + coords.size()); 91 | pr.resize(pr.size() + coords.size()); 92 | 93 | int i_coord = coords.size()-1; // Next input coord to process 94 | int i_csc = jc[n]-1; // Next input CSC entry to process 95 | int i_merge = pr.size()-1; // Next output CSC entry to process 96 | 97 | jc[n] = pr.size(); 98 | for (int j = n; j > 0; --j) { 99 | 100 | // Merge column from cache with column from previous CSC 101 | while (i_coord >= 0 && coords[i_coord].j == j-1 && 102 | i_csc >= 0 && i_csc >= jc[j-1]) { 103 | if (coords[i_coord].i > ir[i_csc]) { 104 | ir[i_merge] = coords[i_coord].i; 105 | pr[i_merge] = coords[i_coord].Aij; 106 | --i_coord; 107 | } else { 108 | ir[i_merge] = ir[i_csc]; 109 | pr[i_merge] = pr[i_csc]; 110 | --i_csc; 111 | } 112 | --i_merge; 113 | } 114 | 115 | // Copy stragglers from coord list 116 | while (i_coord >= 0 && coords[i_coord].j == j-1) { 117 | ir[i_merge] = coords[i_coord].i; 118 | pr[i_merge] = coords[i_coord].Aij; 119 | --i_coord; 120 | --i_merge; 121 | } 122 | 123 | // Copy stragglers from CSC list 124 | while (i_csc >= 0 && i_csc >= jc[j-1]) { 125 | ir[i_merge] = ir[i_csc]; 126 | pr[i_merge] = pr[i_csc]; 127 | --i_csc; 128 | --i_merge; 129 | } 130 | 131 | // Update the column count 132 | jc[j-1] = i_merge+1; 133 | } 134 | 135 | coords.resize(0); 136 | } 137 | 138 | -------------------------------------------------------------------------------- /example/fem/src/assembler2.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * assembler.cc 3 | * Compressed sparse column matrix assembler implementation. 4 | * 5 | * Copyright (c) 2007 David Bindel 6 | * See the file COPYING for copying permissions 7 | */ 8 | 9 | #include "assembler.h" 10 | #include 11 | #include 12 | 13 | #define ME MatrixAssembler2 14 | 15 | using std::sort; 16 | using std::fill; 17 | 18 | 19 | /* 20 | * Add A(i,j) += Aij. If there's space in the existing compressed 21 | * sparse column data structure, add it there; otherwise, stash it in 22 | * the coords cache vector. 23 | */ 24 | void ME::add_entry(int i, int j, double Aij) 25 | { 26 | if (i < 0 || i >= m || j < 0 || j >= n) 27 | return; 28 | for (int ii = jc[j]; ii < jc[j+1]; ++ii) { 29 | if (ir[ii] == i) { 30 | pr[ii] += Aij; 31 | return; 32 | } 33 | } 34 | coords.push_back(Coord(i,j,Aij)); 35 | } 36 | 37 | 38 | /* 39 | * Add an element submatrix. 40 | */ 41 | void ME::add_entry(const int* i, const int* j, double* Aij, 42 | int m_elt, int n_elt) 43 | { 44 | for (int jj = 0; jj < n_elt; ++jj) 45 | for (int ii = 0; ii < m_elt; ++ii) 46 | add_entry(i[ii], j[jj], Aij[jj*m_elt+ii]); 47 | } 48 | 49 | 50 | /* 51 | * Wipe the input matrix. Note that the compressed sparse column index 52 | * structure remains intact, so we can re-assemble without doing too much 53 | * work. 54 | */ 55 | void ME::wipe() 56 | { 57 | coords.resize(0); 58 | fill(get_pr(), get_pr()+jc[n], 0); 59 | } 60 | 61 | 62 | /* 63 | * Sort the entries in the coords cache, and merge (by summing) contributions 64 | * to the same position. 65 | */ 66 | void ME::pack_cache() 67 | { 68 | if (coords.size() > 0) { 69 | sort(coords.begin(), coords.end()); 70 | int i_merge = 0; 71 | for (int i_coord = 1; i_coord < coords.size(); ++i_coord) { 72 | if (coords[i_merge] < coords[i_coord]) 73 | coords[++i_merge] = coords[i_coord]; 74 | else 75 | coords[i_merge].Aij += coords[i_coord].Aij; 76 | } 77 | coords.resize(i_merge+1); 78 | } 79 | } 80 | 81 | 82 | /* 83 | * Pack the coordinate cache, then merge sort the contents of the compressed 84 | * sparse column data structure with the contents of the entry cache. 85 | */ 86 | void ME::compress() 87 | { 88 | pack_cache(); 89 | 90 | ir.resize(ir.size() + coords.size()); 91 | pr.resize(pr.size() + coords.size()); 92 | 93 | int i_coord = coords.size()-1; // Next input coord to process 94 | int i_csc = jc[n]-1; // Next input CSC entry to process 95 | int i_merge = pr.size()-1; // Next output CSC entry to process 96 | 97 | jc[n] = pr.size(); 98 | for (int j = n; j > 0; --j) { 99 | 100 | // Merge column from cache with column from previous CSC 101 | while (i_coord >= 0 && coords[i_coord].j == j-1 && 102 | i_csc >= 0 && i_csc >= jc[j-1]) { 103 | if (coords[i_coord].i > ir[i_csc]) { 104 | ir[i_merge] = coords[i_coord].i; 105 | pr[i_merge] = coords[i_coord].Aij; 106 | --i_coord; 107 | } else { 108 | ir[i_merge] = ir[i_csc]; 109 | pr[i_merge] = pr[i_csc]; 110 | --i_csc; 111 | } 112 | --i_merge; 113 | } 114 | 115 | // Copy stragglers from coord list 116 | while (i_coord >= 0 && coords[i_coord].j == j-1) { 117 | ir[i_merge] = coords[i_coord].i; 118 | pr[i_merge] = coords[i_coord].Aij; 119 | --i_coord; 120 | --i_merge; 121 | } 122 | 123 | // Copy stragglers from CSC list 124 | while (i_csc >= 0 && i_csc >= jc[j-1]) { 125 | ir[i_merge] = ir[i_csc]; 126 | pr[i_merge] = pr[i_csc]; 127 | --i_csc; 128 | --i_merge; 129 | } 130 | 131 | // Update the column count 132 | jc[j-1] = i_merge+1; 133 | } 134 | 135 | coords.resize(0); 136 | } 137 | 138 | -------------------------------------------------------------------------------- /testing/Makefile: -------------------------------------------------------------------------------- 1 | include ../make.inc 2 | 3 | all: test_transfers test_cpp_complex $(TESTC99COMPLEX) test_syntax \ 4 | test_typecheck test_catch test_fortran1 test_fortran2 \ 5 | test_redirect test_include test_single_cpp test_char_cpp 6 | # run the tests... 7 | octave-cli --no-init-file --quiet test_all.m 8 | 9 | test_transfers: 10 | ../mwrap -mex test_transfersmex \ 11 | -c test_transfersmex.cc \ 12 | -m test_transfers.m test_transfers.mw 13 | $(MEX) test_transfersmex.cc 14 | 15 | test_cpp_complex: 16 | ../mwrap -cppcomplex \ 17 | -mex test_cpp_complexmex \ 18 | -c test_cpp_complexmex.cc \ 19 | -m test_cpp_complex.m test_cpp_complex.mw 20 | $(MEX) test_cpp_complexmex.cc 21 | 22 | test_c99_complex: 23 | ../mwrap -c99complex \ 24 | -mex test_c99_complexmex \ 25 | -c test_c99_complexmex.c \ 26 | -m test_c99_complex.m test_c99_complex.mw 27 | $(MEX) test_c99_complexmex.c 28 | 29 | # the following two are designed to create mwrap errors, and compared against 30 | # log files. For now, since they would break the make process, the minus signs 31 | # prevent them from being made. 32 | test_syntax: 33 | - ../mwrap -cppcomplex test_syntax.mw 2> test_syntax.log 34 | - diff test_syntax.log test_syntax.ref 35 | 36 | test_typecheck: 37 | - ../mwrap -cppcomplex test_typecheck.mw 2> test_typecheck.log 38 | diff test_typecheck.log test_typecheck.ref 39 | 40 | 41 | test_catch: 42 | ../mwrap -mex test_catchmex -catch \ 43 | -c test_catchmex.cc \ 44 | -m test_catch.m \ 45 | test_catch.mw 46 | $(MEX) test_catchmex.cc 47 | 48 | test_fortran1: 49 | ../mwrap -mex test_fortran1mex \ 50 | -c test_fortran1mex.cc \ 51 | -m test_fortran1.m \ 52 | test_fortran1.mw 53 | $(MEX) test_fortran1mex.cc 54 | 55 | test_fortran2: 56 | ../mwrap -mex test_fortran2mex \ 57 | -c test_fortran2mex.c \ 58 | -m test_fortran2.m \ 59 | test_fortran2.mw 60 | $(MEX) test_fortran2mex.c 61 | 62 | test_redirect: 63 | ../mwrap -mb test_redirect.mw 64 | 65 | test_include: 66 | ../mwrap -mex test_includemex\ 67 | -c test_includemex.cc \ 68 | -m test_include.m test_include.mw 69 | $(MEX) test_includemex.cc 70 | 71 | # these two are tested by test_char.m ... 72 | test_char_cpp: 73 | ../mwrap -cppcomplex -mex test_charmex \ 74 | -c test_charmex.cc \ 75 | -mb test_char.mw 76 | $(MEX) test_charmex.cc 77 | 78 | test_char_c99: 79 | ../mwrap -mex test_charmex \ 80 | -c test_charmex.c \ 81 | -mb test_char.mw 82 | $(MEX) test_charmex.c 83 | 84 | # these last two are tested by test_single.m ... 85 | test_single_cpp: 86 | ../mwrap -cppcomplex -mex test_singlemex \ 87 | -c test_singlemex.cc \ 88 | -mb test_single.mw 89 | $(MEX) test_singlemex.cc 90 | 91 | test_single_c99: 92 | ../mwrap -c99complex -mex test_singlemex \ 93 | -c test_singlemex.c \ 94 | -mb test_single.mw 95 | $(MEX) test_singlemex.c 96 | 97 | test_gpu: 98 | ../mwrap -gpu -list -cppcomplex -mb -mex test_gpu -c test_gpu.cu test_gpu.mw 99 | 100 | test_gpu_complex: 101 | ../mwrap -gpu -list -cppcomplex -mb -mex test_gpu_complex -c test_gpu_complex.cu test_gpu_complex.mw 102 | 103 | test_gpu_int32: 104 | ../mwrap -gpu -list -cppcomplex -mb -mex test_gpu_int32 -c test_gpu_int32.cu test_gpu_int32.mw 105 | 106 | test_cpu: 107 | ../mwrap -list -cppcomplex -mb -mex test_cpu -c test_cpu.cc test_cpu.mw 108 | 109 | test_cpu_int32: 110 | ../mwrap -list -cppcomplex -mb -mex test_cpu_int32 -c test_cpu_int32.cc test_cpu_int32.mw 111 | 112 | clean: 113 | rm -f *~ *.mex* *.o* test_typecheck.log test_syntax.log 114 | rm -f test_fortran1.m test_fortran2.m test_transfers.m test_catch.m 115 | rm -f test_fortran1mex.cc test_fortran2mex.c 116 | rm -f test_cpp_complex.m test_c99_complex.m 117 | rm -f test_transfersmex.cc test_catchmex.cc test_fortranmex.cc 118 | rm -f test_cpp_complexmex.cc test_c99_complexmex.c 119 | rm -f test_redirect.m test_redirect1.m 120 | rm -f test_singlemex.c test_singlemex.cc 121 | rm -f add.m addf.m addz.m addc.m 122 | rm -f arradd.m arraddf.m arraddz.m arraddc.m 123 | rm -f test_include.m test_includemex.cc 124 | rm -f test_charmex.c test_charmex.cc 125 | rm -f addchar.m arraddchar.m 126 | -------------------------------------------------------------------------------- /example/fem/src/elastic2d.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * elastic2d.cc 3 | * Element type for 2D elasticity (4 node quad only). 4 | * 5 | * Copyright (c) 2007 David Bindel 6 | * See the file COPYING for copying permissions 7 | */ 8 | 9 | #include "etype.h" 10 | #include "mesh.h" 11 | #include "elastic2d.h" 12 | #include "quad2d.h" 13 | #include "gauss2by2.h" 14 | #include 15 | 16 | #define ME Elastic2D 17 | 18 | 19 | ME::ME(double E, double nu, const char* type) 20 | { 21 | if (strcmp(type, "plane stress") == 0) 22 | plane_stress(E, nu); 23 | else 24 | plane_strain(E, nu); 25 | } 26 | 27 | 28 | void ME::plane_strain(double E, double nu) 29 | { 30 | /* 31 | input E, nu; 32 | output D(3,3); 33 | 34 | D = E/(1+nu)/(1-2*nu) * 35 | [ 1-nu, nu, 0; 36 | nu, 1-nu, 0; 37 | 0, 0, (1-2*nu)/2 ]; 38 | */ 39 | } 40 | 41 | 42 | void ME::plane_stress(double E, double nu) 43 | { 44 | /* 45 | input E, nu; 46 | output D(3,3); 47 | 48 | D = E/(1-nu*nu) * 49 | [ 1, nu, 0; 50 | nu, 1, 0; 51 | 0, 0, (1-nu)/2 ]; 52 | */ 53 | } 54 | 55 | 56 | void ME::assign_ids(Mesh* mesh, int eltid) 57 | { 58 | for (int i = 0; i < 4; ++i) { 59 | int ni = mesh->ix(i,eltid); 60 | mesh->id(0,ni) = 1; 61 | mesh->id(1,ni) = 1; 62 | } 63 | } 64 | 65 | 66 | void ME::assemble_f(Mesh* mesh, int eltid) 67 | { 68 | Quad2d quad; 69 | Gauss4 xi(quad); 70 | get_quad(quad, mesh, eltid); 71 | 72 | vector K(4*4); 73 | for (xi.start(); !xi.done(); ++xi) { 74 | 75 | double eps[3] = {0, 0, 0}; 76 | for (int j = 0; j < 4; ++j) { 77 | const double* u = mesh->u(mesh->ix(j,eltid)); 78 | double Nj_x = xi.dN(j,0); 79 | double Nj_y = xi.dN(j,1); 80 | 81 | /* 82 | // Contribute strain at quadrature point 83 | 84 | input Nj_x, Nj_y, D(3,3); 85 | inout eps(3); 86 | input u(2); 87 | 88 | Bj = [Nj_x, 0; 89 | 0, Nj_y; 90 | Nj_y, Nj_x]; 91 | 92 | eps += Bj*u; 93 | */ 94 | } 95 | 96 | for (int i = 0; i < 4; ++i) { 97 | double* f = mesh->f(mesh->ix(i,eltid)); 98 | double Ni_x = xi.dN(i,0); 99 | double Ni_y = xi.dN(i,1); 100 | double w = xi.wt(); 101 | 102 | /* 103 | // Contribute B_i'*D*B(u) * w 104 | 105 | input Ni_x, Ni_y, D(3,3), w; 106 | input eps(3); 107 | inout f(2); 108 | 109 | Bi = [Ni_x, 0; 110 | 0, Ni_y; 111 | Ni_y, Ni_x]; 112 | 113 | f += Bi'*D*eps*w; 114 | */ 115 | } 116 | 117 | } 118 | } 119 | 120 | 121 | void ME::assemble_K(Mesh* mesh, int eltid, 122 | MatrixAssembler* K_assembler) 123 | { 124 | Quad2d quad; 125 | Gauss4 xi(quad); 126 | get_quad(quad, mesh, eltid); 127 | 128 | vector K(8*8); 129 | for (xi.start(); !xi.done(); ++xi) { 130 | double w = xi.wt(); 131 | for (int j = 0; j < 4; ++j) { 132 | double Nj_x = xi.dN(j,0); 133 | double Nj_y = xi.dN(j,1); 134 | for (int i = 0; i < 4; ++i) { 135 | double Ni_x = xi.dN(i,0); 136 | double Ni_y = xi.dN(i,1); 137 | double* Knodal = &(K[16*j +2*i+ 0]); 138 | 139 | /* 140 | // B-matrix based displacement formulation 141 | // Isotropic plane strain constitutive tensor 142 | 143 | input D(3,3), w; 144 | input Ni_x, Ni_y, Nj_x, Nj_y; 145 | inout Knodal[8](2,2); 146 | 147 | Bi = [Ni_x, 0; 148 | 0, Ni_y; 149 | Ni_y, Ni_x]; 150 | 151 | Bj = [Nj_x, 0; 152 | 0, Nj_y; 153 | Nj_y, Nj_x]; 154 | 155 | Knodal += Bi'*D*Bj * w; 156 | */ 157 | } 158 | } 159 | } 160 | 161 | K_assembler->add_entry(id, id, &(K[0]), 8, 8); 162 | } 163 | 164 | 165 | void ME::get_quad(FEShapes& quad, Mesh* mesh, int eltid) 166 | { 167 | for (int i = 0; i < 4; ++i) { 168 | int n = mesh->ix(i,eltid); 169 | quad.set_node(i, mesh->x(n)); 170 | id[2*i+0] = mesh->id(0,n); 171 | id[2*i+1] = mesh->id(1,n); 172 | } 173 | } 174 | -------------------------------------------------------------------------------- /src/mwrap-ast.h: -------------------------------------------------------------------------------- 1 | /* 2 | * mwrap-ast.h 3 | * MWrap abstract syntax tree declarations. 4 | * 5 | * Copyright (c) 2007 David Bindel 6 | * See the file COPYING for copying permissions 7 | */ 8 | 9 | #ifndef MWRAP_AST_H 10 | #define MWRAP_AST_H 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | using std::string; 18 | using std::map; 19 | using std::set; 20 | 21 | enum { 22 | VT_unk, // Unknown 23 | VT_obj, // Object 24 | VT_array, // Numeric array (real) 25 | VT_carray, // Numeric array (single complex) 26 | VT_zarray, // Numeric array (double complex) 27 | VT_rarray, // Reference to numeric array 28 | VT_scalar, // Numeric scalar (real) 29 | VT_cscalar, // Numeric scalar (single complex) 30 | VT_zscalar, // Numeric scalar (double complex) 31 | VT_string, // Char string 32 | VT_mx, // mxArray 33 | VT_p_obj, // Pointer to object 34 | VT_p_scalar, // Pointer to scalar (real) 35 | VT_p_cscalar, // Pointer to scalar (single complex) 36 | VT_p_zscalar, // Pointer to scalar (double complex) 37 | VT_r_obj, // Reference to object 38 | VT_r_scalar, // Reference to scalar (real) 39 | VT_r_cscalar, // Reference to scalar (single complex) 40 | VT_r_zscalar, // Reference to scalar (double complex) 41 | VT_const, // Constant expression 42 | }; 43 | 44 | struct InheritsDecl { 45 | InheritsDecl(char* name, InheritsDecl* next) : 46 | name(name), next(next) {} 47 | 48 | char* name; // Name of inherited class 49 | InheritsDecl* next; 50 | }; 51 | 52 | struct Expr { 53 | Expr(char* value) : value(value), next(NULL), input_label(-1) {} 54 | 55 | int input_label; // Index of dim variable in input arg list 56 | char* value; // Expression to be evaluated to get dimension 57 | Expr* next; 58 | }; 59 | 60 | struct TypeQual { 61 | TypeQual(char qual, Expr* args) : 62 | qual(qual), args(args) {} 63 | 64 | char qual; // Pointer ('*'), ref ('&'), array ('a'), or nothing (0) 65 | Expr* args; // Array / cstring dimension list 66 | }; 67 | 68 | struct Var { 69 | Var(char devicespec, char iospec, char* basetype, TypeQual* qual, char* name) : 70 | devicespec(devicespec), iospec(iospec), basetype(basetype), qual(qual), tinfo(VT_unk), 71 | name(name), next(NULL), input_label(-1), output_label(-1) {} 72 | 73 | int input_label; // Index in input arg list 74 | int output_label; // Index in output arg list 75 | char iospec; // Indicate input ('i'), output ('o'), or both ('b') 76 | char devicespec; // Indicate cpu ('c'), gpu ('g') 77 | char* basetype; // Name of the base type 78 | TypeQual* qual; // Type qualifier (pointer, ref, etc) 79 | int tinfo; // General type identifier (see VT_* list above) 80 | char* name; // MATLAB text for variable name (or value) 81 | Var* next; 82 | }; 83 | 84 | struct Func { 85 | Func(char* thisv, char* classv, char* funcv, 86 | const string& fname, int line) : 87 | fname(fname), line(line), fort(false), id(-1), 88 | thisv(thisv), classv(classv), funcv(funcv), 89 | args(NULL), ret(NULL), next(NULL), same_next(NULL) {} 90 | 91 | string fname; // Name of file where this function was defined 92 | int line; // Number of the line where the function was defined 93 | bool fort; // Flag whether this is a FORTRAN function 94 | 95 | int id; // Identifier (used for numbering stub functions) 96 | char* thisv; // This var (only for methods) 97 | char* classv; // Class type (only for methods or 'new' calls) 98 | char* funcv; // Function or method name 99 | Var* args; // Arguments 100 | Var* ret; // Return variable 101 | 102 | Func* next; // Next in ordinary linked list 103 | Func* same_next; // Next in list of type-identical calls 104 | }; 105 | 106 | extern "C" char* mwrap_strdup(const char* s); 107 | 108 | extern map class_decls; 109 | void add_inherits(const char* childname, InheritsDecl* ilist); 110 | 111 | extern set scalar_decls; 112 | extern set cscalar_decls; 113 | extern set zscalar_decls; 114 | extern set mxarray_decls; 115 | void init_scalar_types(); 116 | char *promote_int(char* name); 117 | void add_scalar_type(const char* name); 118 | void add_cscalar_type(const char* name); 119 | void add_zscalar_type(const char* name); 120 | void add_mxarray_type(const char* name); 121 | bool is_scalar_type(const char* name); 122 | bool is_cscalar_type(const char* name); 123 | bool is_zscalar_type(const char* name); 124 | bool is_mxarray_type(const char* name); 125 | 126 | string id_string(Func* f); 127 | int typecheck(Func* func, int line); 128 | 129 | void print(FILE* fp, Func* func); 130 | void print_matlab_call(FILE* fp, Func* func, const char* mexfunc); 131 | void print_mex_init(FILE* fp); 132 | void print_mex_file(FILE* fp, Func* f); 133 | 134 | void mex_c99_complex(FILE* fp); 135 | void mex_cpp_complex(FILE* fp); 136 | 137 | void destroy(Func* func); 138 | void destroy(InheritsDecl* ilist); 139 | void destroy_inherits(); 140 | 141 | extern bool mw_use_gpu; 142 | extern bool mw_generate_catch; 143 | extern bool mw_use_c99_complex; 144 | extern bool mw_use_cpp_complex; 145 | extern int mw_promote_int; 146 | 147 | extern int mw_use_int32_t; 148 | extern int mw_use_int64_t; 149 | extern int mw_use_uint32_t; 150 | extern int mw_use_uint64_t; 151 | extern int mw_use_longlong; 152 | extern int mw_use_ulonglong; 153 | 154 | extern int mw_use_ulong; 155 | extern int mw_use_uint; 156 | extern int mw_use_ushort; 157 | extern int mw_use_uchar; 158 | 159 | #endif /* MWRAP_AST_H */ 160 | 161 | -------------------------------------------------------------------------------- /example/fem/src/quad2d1.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * quad2d.h 3 | * Implementation for four-node quad element shapes. 4 | * 5 | * Copyright (c) 2007 David Bindel 6 | * See the file COPYING for copying permissions 7 | */ 8 | #include "quad2d.h" 9 | 10 | #define ME Quad2d 11 | 12 | 13 | ME::~ME() 14 | { 15 | } 16 | 17 | 18 | void ME::set_node(int nodenum, const double* x) 19 | { 20 | nodex[2*nodenum+0] = x[0]; 21 | nodex[2*nodenum+1] = x[1]; 22 | } 23 | 24 | 25 | void ME::set_nodes(const double* x) 26 | { 27 | for (int i = 0; i < 8; ++i) 28 | nodex[i] = x[i]; 29 | } 30 | 31 | 32 | void ME::eval(const double *XX, double* xx, 33 | double* N, double* dN, 34 | double& J) const 35 | { 36 | double X = XX[0]; 37 | double Y = XX[1]; 38 | double FF[4]; 39 | 40 | /* 41 | // Evaluate element functions 42 | 43 | input X, Y; 44 | input nodex(2,4); 45 | 46 | output N(4); 47 | output dN(4,2); 48 | output xx(2); 49 | output FF(2,2); 50 | 51 | N1x = (1-X)/2; N1y = (1-Y)/2; 52 | N2x = (1+X)/2; N2y = (1+Y)/2; 53 | 54 | N = [ N1x*N1y; N2x*N1y; N2x*N2y; N1x*N2y]; 55 | dN = [ -N1y, N1y, N2y, -N2y; 56 | -N1x, -N2x, N2x, N1x ]'/2; 57 | 58 | xx = nodex*N; 59 | FF = nodex*dN; 60 | */ 61 | /* */ { 62 | double tmp1_ = X; 63 | double tmp2_ = Y; 64 | double tmp3_ = nodex[0*2+0]; 65 | double tmp4_ = nodex[0*2+1]; 66 | double tmp5_ = nodex[1*2+0]; 67 | double tmp6_ = nodex[1*2+1]; 68 | double tmp7_ = nodex[2*2+0]; 69 | double tmp8_ = nodex[2*2+1]; 70 | double tmp9_ = nodex[3*2+0]; 71 | double tmp10_ = nodex[3*2+1]; 72 | double tmp12_ = 1.0 - tmp1_; 73 | double tmp14_ = tmp12_ / 2.0; 74 | double tmp15_ = 1.0 - tmp2_; 75 | double tmp16_ = tmp15_ / 2.0; 76 | double tmp17_ = 1.0 + tmp1_; 77 | double tmp18_ = tmp17_ / 2.0; 78 | double tmp19_ = 1.0 + tmp2_; 79 | double tmp20_ = tmp19_ / 2.0; 80 | double tmp21_ = tmp14_ * tmp16_; 81 | double tmp22_ = tmp18_ * tmp16_; 82 | double tmp23_ = tmp18_ * tmp20_; 83 | double tmp24_ = tmp14_ * tmp20_; 84 | double tmp25_ = -tmp16_; 85 | double tmp26_ = -tmp20_; 86 | double tmp27_ = -tmp14_; 87 | double tmp28_ = -tmp18_; 88 | double tmp29_ = tmp25_ / 2.0; 89 | double tmp30_ = tmp16_ / 2.0; 90 | double tmp31_ = tmp20_ / 2.0; 91 | double tmp32_ = tmp26_ / 2.0; 92 | double tmp33_ = tmp27_ / 2.0; 93 | double tmp34_ = tmp28_ / 2.0; 94 | double tmp35_ = tmp18_ / 2.0; 95 | double tmp36_ = tmp14_ / 2.0; 96 | double tmp37_ = tmp3_ * tmp21_; 97 | double tmp38_ = tmp5_ * tmp22_; 98 | double tmp39_ = tmp37_ + tmp38_; 99 | double tmp40_ = tmp7_ * tmp23_; 100 | double tmp41_ = tmp39_ + tmp40_; 101 | double tmp42_ = tmp9_ * tmp24_; 102 | double tmp43_ = tmp41_ + tmp42_; 103 | double tmp44_ = tmp4_ * tmp21_; 104 | double tmp45_ = tmp6_ * tmp22_; 105 | double tmp46_ = tmp44_ + tmp45_; 106 | double tmp47_ = tmp8_ * tmp23_; 107 | double tmp48_ = tmp46_ + tmp47_; 108 | double tmp49_ = tmp10_ * tmp24_; 109 | double tmp50_ = tmp48_ + tmp49_; 110 | double tmp51_ = tmp3_ * tmp29_; 111 | double tmp52_ = tmp5_ * tmp30_; 112 | double tmp53_ = tmp51_ + tmp52_; 113 | double tmp54_ = tmp7_ * tmp31_; 114 | double tmp55_ = tmp53_ + tmp54_; 115 | double tmp56_ = tmp9_ * tmp32_; 116 | double tmp57_ = tmp55_ + tmp56_; 117 | double tmp58_ = tmp4_ * tmp29_; 118 | double tmp59_ = tmp6_ * tmp30_; 119 | double tmp60_ = tmp58_ + tmp59_; 120 | double tmp61_ = tmp8_ * tmp31_; 121 | double tmp62_ = tmp60_ + tmp61_; 122 | double tmp63_ = tmp10_ * tmp32_; 123 | double tmp64_ = tmp62_ + tmp63_; 124 | double tmp65_ = tmp3_ * tmp33_; 125 | double tmp66_ = tmp5_ * tmp34_; 126 | double tmp67_ = tmp65_ + tmp66_; 127 | double tmp68_ = tmp7_ * tmp35_; 128 | double tmp69_ = tmp67_ + tmp68_; 129 | double tmp70_ = tmp9_ * tmp36_; 130 | double tmp71_ = tmp69_ + tmp70_; 131 | double tmp72_ = tmp4_ * tmp33_; 132 | double tmp73_ = tmp6_ * tmp34_; 133 | double tmp74_ = tmp72_ + tmp73_; 134 | double tmp75_ = tmp8_ * tmp35_; 135 | double tmp76_ = tmp74_ + tmp75_; 136 | double tmp77_ = tmp10_ * tmp36_; 137 | double tmp78_ = tmp76_ + tmp77_; 138 | N[0*4+0] = tmp21_; 139 | N[0*4+1] = tmp22_; 140 | N[0*4+2] = tmp23_; 141 | N[0*4+3] = tmp24_; 142 | dN[0*4+0] = tmp29_; 143 | dN[0*4+1] = tmp30_; 144 | dN[0*4+2] = tmp31_; 145 | dN[0*4+3] = tmp32_; 146 | dN[1*4+0] = tmp33_; 147 | dN[1*4+1] = tmp34_; 148 | dN[1*4+2] = tmp35_; 149 | dN[1*4+3] = tmp36_; 150 | xx[0*2+0] = tmp43_; 151 | xx[0*2+1] = tmp50_; 152 | FF[0*2+0] = tmp57_; 153 | FF[0*2+1] = tmp64_; 154 | FF[1*2+0] = tmp71_; 155 | FF[1*2+1] = tmp78_; 156 | } /* */ 157 | remap_gradients(FF, dN, J); 158 | } 159 | 160 | 161 | void ME::remap_gradients(double* FF, double* dN, double& J) const 162 | { 163 | J = (FF[0]*FF[3]-FF[1]*FF[2]); 164 | double invF[4] = { FF[3]/J, -FF[1]/J, 165 | -FF[2]/J, FF[0]/J }; 166 | 167 | /* 168 | // Remap gradients 169 | 170 | inout dN(4,2); 171 | input invF(2,2); 172 | dN = dN*invF; 173 | */ 174 | /* */ { 175 | double tmp1_ = dN[0*4+0]; 176 | double tmp2_ = dN[0*4+1]; 177 | double tmp3_ = dN[0*4+2]; 178 | double tmp4_ = dN[0*4+3]; 179 | double tmp5_ = dN[1*4+0]; 180 | double tmp6_ = dN[1*4+1]; 181 | double tmp7_ = dN[1*4+2]; 182 | double tmp8_ = dN[1*4+3]; 183 | double tmp9_ = invF[0*2+0]; 184 | double tmp10_ = invF[0*2+1]; 185 | double tmp11_ = invF[1*2+0]; 186 | double tmp12_ = invF[1*2+1]; 187 | double tmp13_ = tmp1_ * tmp9_; 188 | double tmp14_ = tmp5_ * tmp10_; 189 | double tmp15_ = tmp13_ + tmp14_; 190 | double tmp16_ = tmp2_ * tmp9_; 191 | double tmp17_ = tmp6_ * tmp10_; 192 | double tmp18_ = tmp16_ + tmp17_; 193 | double tmp19_ = tmp3_ * tmp9_; 194 | double tmp20_ = tmp7_ * tmp10_; 195 | double tmp21_ = tmp19_ + tmp20_; 196 | double tmp22_ = tmp4_ * tmp9_; 197 | double tmp23_ = tmp8_ * tmp10_; 198 | double tmp24_ = tmp22_ + tmp23_; 199 | double tmp25_ = tmp1_ * tmp11_; 200 | double tmp26_ = tmp5_ * tmp12_; 201 | double tmp27_ = tmp25_ + tmp26_; 202 | double tmp28_ = tmp2_ * tmp11_; 203 | double tmp29_ = tmp6_ * tmp12_; 204 | double tmp30_ = tmp28_ + tmp29_; 205 | double tmp31_ = tmp3_ * tmp11_; 206 | double tmp32_ = tmp7_ * tmp12_; 207 | double tmp33_ = tmp31_ + tmp32_; 208 | double tmp34_ = tmp4_ * tmp11_; 209 | double tmp35_ = tmp8_ * tmp12_; 210 | double tmp36_ = tmp34_ + tmp35_; 211 | dN[0*4+0] = tmp15_; 212 | dN[0*4+1] = tmp18_; 213 | dN[0*4+2] = tmp21_; 214 | dN[0*4+3] = tmp24_; 215 | dN[1*4+0] = tmp27_; 216 | dN[1*4+1] = tmp30_; 217 | dN[1*4+2] = tmp33_; 218 | dN[1*4+3] = tmp36_; 219 | } /* */ 220 | } 221 | -------------------------------------------------------------------------------- /src/mwrap.l: -------------------------------------------------------------------------------- 1 | %{ 2 | /* 3 | * mwrap.l 4 | * Lexer for MWrap. 5 | * 6 | * Copyright (c) 2007 David Bindel 7 | * See the file COPYING for copying permissions 8 | */ 9 | 10 | #include "mwrap.hh" 11 | #include 12 | #include 13 | 14 | extern int listing_flag; // Output filenames from @ commands? 15 | extern int mbatching_flag; // Do we want to output on @ commands? 16 | extern int linenum; // Lexer line number 17 | extern FILE* outfp; // MATLAB output file 18 | extern FILE* outcfp; // C output file 19 | 20 | static int done_at_switch; // Set when @ redirection is done 21 | 22 | extern char* mwrap_strdup(char* s); 23 | 24 | static int is_name_char(char c) 25 | { 26 | return (isalnum(c) || c == '_'); 27 | } 28 | 29 | static char* fname_scan_line(char* s) 30 | { 31 | static char namebuf[256]; /* FIXME */ 32 | int name_start, name_end, i, j; 33 | 34 | /* Name ends at last alphanum before args */ 35 | name_end = 0; 36 | while (s[name_end] && s[name_end] != '(') 37 | ++name_end; 38 | while (name_end > 0 && !is_name_char(s[name_end])) 39 | --name_end; 40 | 41 | /* Back up to the start of the name */ 42 | name_start = name_end; 43 | while (s[name_start] > 0 && is_name_char(s[name_start])) 44 | --name_start; 45 | 46 | /* Copy the name into the buf and add .m */ 47 | for (i = name_start+1, j = 0; i <= name_end; ++i, ++j) 48 | namebuf[j] = s[i]; 49 | strcpy(namebuf+j, ".m"); 50 | return namebuf; 51 | } 52 | 53 | 54 | #define MAX_INCLUDE_DEPTH 10 55 | YY_BUFFER_STATE include_stack[MAX_INCLUDE_DEPTH]; 56 | int include_stack_line[MAX_INCLUDE_DEPTH]; 57 | int include_stack_ptr = 0; 58 | extern void set_include_name(const char* s); 59 | extern void get_include_name(); 60 | 61 | 62 | /* The lexer switches states when it sees a specially formatted comment 63 | * as the first non-blank mode in a line. In total, there are six states: 64 | * 65 | * INITIAL - start of line 66 | * TS - ordinary text line 67 | * AS - at line (redirection) 68 | * FS - @function line (function declaration + redirection) 69 | * SS - embedded C line 70 | * BS - block of embedded C 71 | * CS - C call line 72 | * COMMS - Comment line 73 | * 74 | * Transitions are as follows. 75 | * 76 | * "$[" : INITIAL -> BS 77 | * "$]" : BS -> INITIAL 78 | * "@" : INITIAL -> AS (batching mode only) 79 | * "@function" : INITIAL -> FS 80 | * "$" : INITIAL -> SS 81 | * "#" : INITIAL -> CS 82 | * non-blank : INITIAL -> TS 83 | * newline: (AS, SS, CS, TS) -> INITIAL 84 | */ 85 | 86 | %} 87 | 88 | %s CSTATE 89 | %s SSTATE 90 | %s BSTATE 91 | %s ASTATE 92 | %s FSTATE 93 | %s TSTATE 94 | %s COMMSTATE 95 | %x INCLSTATE 96 | 97 | %% 98 | "@function" { 99 | if (mbatching_flag && outfp) 100 | fclose(outfp); 101 | BEGIN FSTATE; 102 | return NON_C_LINE; 103 | } 104 | 105 | "@include" { BEGIN INCLSTATE; return NON_C_LINE; } 106 | 107 | "@" { 108 | if (mbatching_flag && outfp) 109 | fclose(outfp); 110 | done_at_switch = 0; 111 | BEGIN ASTATE; 112 | return NON_C_LINE; 113 | } 114 | 115 | "#" { BEGIN CSTATE; } 116 | \$\[[ \t\r]*\n { BEGIN BSTATE; ++linenum; return NON_C_LINE; } 117 | "$" { BEGIN SSTATE; return NON_C_LINE; } 118 | "//" { BEGIN COMMSTATE; return NON_C_LINE; } 119 | 120 | \n { if (outfp) fprintf(outfp, "%s", yytext); 121 | ++linenum; 122 | BEGIN 0; 123 | return NON_C_LINE; } 124 | [ \t] { if (outfp) fprintf(outfp, "%s", yytext); } 125 | . { if (outfp) fprintf(outfp, "%s", yytext); 126 | BEGIN TSTATE; 127 | return NON_C_LINE; } 128 | 129 | \n { ++linenum; BEGIN 0; } 130 | . ; 131 | 132 | <> { 133 | if (--include_stack_ptr < 0) { 134 | yyterminate(); 135 | } else { 136 | yy_delete_buffer(YY_CURRENT_BUFFER); 137 | yy_switch_to_buffer(include_stack[include_stack_ptr]); 138 | linenum = include_stack_line[include_stack_ptr]; 139 | get_include_name(); 140 | BEGIN INCLSTATE; 141 | } 142 | } 143 | 144 | [ \t\r]* ; 145 | [^ \t\r\n]+ { 146 | if (include_stack_ptr >= MAX_INCLUDE_DEPTH) { 147 | fprintf(stderr, "Error: Includes nested too deeply"); 148 | exit(-1); 149 | } 150 | set_include_name(yytext); 151 | include_stack_line[include_stack_ptr] = linenum; 152 | include_stack[include_stack_ptr++] = YY_CURRENT_BUFFER; 153 | yyin = fopen(yytext, "r"); 154 | if (!yyin) { 155 | fprintf(stderr, "Error: Could not read '%s'\n", yytext); 156 | exit(-1); 157 | } 158 | linenum = 1; 159 | yy_switch_to_buffer(yy_create_buffer(yyin, YY_BUF_SIZE)); 160 | BEGIN 0; 161 | } 162 | \n { ++linenum; BEGIN 0; } 163 | 164 | [^\n]+ { 165 | char* fname = fname_scan_line(yytext); 166 | if (mbatching_flag) { 167 | outfp = fopen(fname, "w+"); 168 | if (!outfp) { 169 | fprintf(stderr, "Error: Could not write %s\n", yytext); 170 | exit(-1); 171 | } 172 | } 173 | if (listing_flag) 174 | fprintf(stdout, "%s\n", fname); 175 | if (outfp) 176 | fprintf(outfp, "function%s\n", yytext); 177 | } 178 | \n { ++linenum; BEGIN 0; } 179 | 180 | [ \t\r]+ ; 181 | [^ \t\r\n]+ { if (mbatching_flag && !done_at_switch) { 182 | outfp = fopen(yytext, "w+"); 183 | if (!outfp) { 184 | fprintf(stderr, "Error: Could not write %s\n", 185 | yytext); 186 | exit(-1); 187 | } 188 | } 189 | if (listing_flag && !done_at_switch) 190 | fprintf(stdout, "%s\n", yytext); 191 | done_at_switch = 1; 192 | } 193 | \n { ++linenum; BEGIN 0; } 194 | 195 | \n { if (outfp) fprintf(outfp, "%s", yytext); ++ linenum; BEGIN 0; } 196 | . { if (outfp) fprintf(outfp, "%s", yytext); } 197 | 198 | \n { if (outcfp) fprintf(outcfp, "%s", yytext); ++linenum; BEGIN 0; } 199 | . { if (outcfp) fprintf(outcfp, "%s", yytext); } 200 | 201 | \$\][ \t\r]*\n { ++linenum; BEGIN 0; } 202 | \n { if (outcfp) fprintf(outcfp, "%s", yytext); ++linenum; } 203 | . { if (outcfp) fprintf(outcfp, "%s", yytext); } 204 | 205 | "new" { return NEW; } 206 | "FORTRAN" { return FORTRAN; } 207 | "input" { return INPUT; } 208 | "output" { return OUTPUT; } 209 | "inout" { return INOUT; } 210 | "class" { return CLASS; } 211 | "typedef" { return TYPEDEF; } 212 | "cpu" { return CPU; } 213 | "gpu" { return GPU; } 214 | 215 | ((::)?[_a-zA-Z][_a-zA-Z0-9]*)* { 216 | yylval.string = mwrap_strdup(yytext); 217 | return ID; 218 | } 219 | [0-9]+ { 220 | yylval.string = mwrap_strdup(yytext); 221 | return NUMBER; 222 | } 223 | \'[^'\n]*['\n] { 224 | yylval.string = mwrap_strdup(yytext); 225 | return STRING; 226 | } 227 | \/\/[^\n]* ; 228 | 229 | [ \t\r]+ ; 230 | \n { ++linenum; BEGIN 0; } 231 | . return yytext[0]; 232 | 233 | %% 234 | -------------------------------------------------------------------------------- /example/fem/interface/mesh.mw: -------------------------------------------------------------------------------- 1 | % mesh.mw 2 | % MWrap bindings for Mesh. 3 | % 4 | % Copyright (c) 2007 David Bindel 5 | % See the file COPYING for copying permissions 6 | 7 | $ #include "mesh.h" 8 | 9 | 10 | // ---- 11 | @function mobj = Mesh_create(ndm, maxndf, maxnen) 12 | % mobj = Mesh_create(ndm, maxndf, maxnen) 13 | % 14 | % Create a new mesh object. 15 | % ndm - Number of spatial dimensions 16 | % maxndf - Maximum number of dofs per node 17 | % maxnen - Maximum number of elements per node 18 | # Mesh* mobj = new Mesh(int ndm, int maxndf, int maxnen); 19 | 20 | 21 | // ---- 22 | @function Mesh_delete(mobj) 23 | % Mesh_delete(mobj) 24 | % 25 | % Delete an existing mesh object. 26 | # delete(Mesh* mobj); 27 | 28 | 29 | // ---- 30 | @function ndm = Mesh_ndm(mobj) 31 | % ndm = Mesh_ndm(mobj) 32 | % 33 | % Get the number of spatial dimensions for the mesh 34 | # int ndm = mobj->Mesh.ndm(); 35 | 36 | 37 | // ---- 38 | @function maxndf = Mesh_maxndf(mobj) 39 | % maxndf = Mesh_maxndf(mobj) 40 | % 41 | % Get the maximum number of nodal dofs for the mesh 42 | # int maxndf = mobj->Mesh.maxndf(); 43 | 44 | 45 | // ---- 46 | @function maxnen = Mesh_maxnen(mobj) 47 | % maxnen = Mesh_maxnen(mobj) 48 | % 49 | % Get the maximum number of nodes per element for the mesh 50 | # int maxnen = mobj->Mesh.maxnen(); 51 | 52 | 53 | // ---- 54 | @function numelt = Mesh_numelt(mobj) 55 | % numelt = Mesh_numelt(mobj) 56 | % 57 | % Get the number of elements in the mesh. 58 | # int numelt = mobj->Mesh.numelt(); 59 | 60 | 61 | // ---- 62 | @function numnp = Mesh_numnp(mobj) 63 | % numnp = Mesh_numnp(mobj) 64 | % 65 | % Get the number of nodes in the mesh 66 | # int numnp = mobj->Mesh.numnp(); 67 | 68 | 69 | // ---- 70 | @function numid = Mesh_numid(mobj) 71 | % numid = Mesh_numid(mobj) 72 | % 73 | % Get the number of active dofs in the mesh 74 | # int numid = mobj->Mesh.numid(); 75 | 76 | 77 | // ---- 78 | @function x = Mesh_x(mobj, i) 79 | % Mesh_x(mobj, i) 80 | % 81 | % Get the coordinates of mesh node i. If the node number is omitted, 82 | % get the coordinates for all nodes in the mesh. 83 | 84 | if nargin == 2 85 | i = i-1; 86 | # int ndm = mobj->Mesh.ndm(); 87 | # double[ndm] x = mobj->Mesh.x(int i); 88 | else 89 | # int numnp = mobj->Mesh.numnp(); 90 | # int ndm = mobj->Mesh.ndm(); 91 | # double[ndm,numnp] x = mobj->Mesh.x(); 92 | end 93 | 94 | 95 | // ---- 96 | @function ix = Mesh_ix(mobj, i) 97 | % Mesh_ix(mobj, i) 98 | % 99 | % Get the connectivity of element i. If the element number is omitted, 100 | % get the connectivity for all elements in the mesh. 101 | 102 | if nargin == 2 103 | i = i-1; 104 | # int maxnen = mobj->Mesh.maxndf(); 105 | # int[maxnen] ix = mobj->Mesh.ix(int i); 106 | else 107 | # int numelt = mobj->Mesh.numelt(); 108 | # int maxnen = mobj->Mesh.maxnen(); 109 | # int[maxnen,numelt] ix = mobj->Mesh.ix(); 110 | end 111 | ix = ix+1; 112 | 113 | 114 | // ---- 115 | @function id = Mesh_id(mobj, i) 116 | % Mesh_id(mobj, i) 117 | % 118 | % Get the degrees of freedom for element i. If the element number is omitted, 119 | % get the degrees of freedom for all elements in the mesh. 120 | 121 | if nargin == 2 122 | i = i - 1; 123 | # int maxndf = mobj->Mesh.maxndf(); 124 | # int[maxndf] id = mobj->Mesh.id(int i); 125 | else 126 | # int numnp = mobj->Mesh.numnp(); 127 | # int maxndf = mobj->Mesh.maxndf(); 128 | # int[maxndf,numnp] id = mobj->Mesh.id(); 129 | end 130 | id = id + 1; 131 | 132 | 133 | // ---- 134 | @function u = Mesh_u(mobj, i) 135 | % Mesh_u(mobj, i) 136 | % 137 | % Get the displacement of mesh node i. If the node number is omitted, 138 | % get the displacements for all nodes in the mesh. 139 | 140 | if nargin == 2 141 | i = i-1; 142 | # int maxndf = mobj->Mesh.maxndf(); 143 | # double[maxndf] u = mobj->Mesh.u(int i); 144 | else 145 | # int numnp = mobj->Mesh.numnp(); 146 | # int maxndf = mobj->Mesh.maxndf(); 147 | # double[maxndf,numnp] u = mobj->Mesh.u(); 148 | end 149 | 150 | 151 | // ---- 152 | @function f = Mesh_f(mobj, i) 153 | % Mesh_f(mobj, i) 154 | % 155 | % Get the forces for mesh node i. If the node number is omitted, 156 | % get the forces for all nodes in the mesh. 157 | 158 | if nargin == 2 159 | i = i-1; 160 | # int maxndf = mobj->Mesh.maxndf(); 161 | # double[maxndf] f = mobj->Mesh.f(int i); 162 | else 163 | # int numnp = mobj->Mesh.numnp(); 164 | # int maxndf = mobj->Mesh.maxndf(); 165 | # double[maxndf,numnp] f = mobj->Mesh.f(); 166 | end 167 | 168 | 169 | // ---- 170 | @function bc = Mesh_bc(mobj, i) 171 | % Mesh_bc(mobj, i) 172 | % 173 | % Get the boundary codes of mesh node i. If the node number is omitted, 174 | % get the boundary codes for all nodes in the mesh. 175 | 176 | if nargin == 2 177 | i = i-1; 178 | # int maxndf = mobj->Mesh.maxndf(); 179 | # char[maxndf] bc = mobj->Mesh.bc(int i); 180 | else 181 | # int numnp = mobj->Mesh.numnp(); 182 | # int maxndf = mobj->Mesh.maxndf(); 183 | # char[maxndf,numnp] bc = mobj->Mesh.bc(); 184 | end 185 | 186 | 187 | // ---- 188 | @function bv = Mesh_bv(mobj, i) 189 | % Mesh_bv(mobj, i) 190 | % 191 | % Get the boundary values of mesh node i. If the node number is omitted, 192 | % get the boundary values for all nodes in the mesh. 193 | 194 | if nargin == 2 195 | i = i-1; 196 | # int maxndf = mobj->Mesh.maxndf(); 197 | # double[maxndf] bv = mobj->Mesh.bv(int i); 198 | else 199 | # int numnp = mobj->Mesh.numnp(); 200 | # int maxndf = mobj->Mesh.maxndf(); 201 | # double[maxndf,numnp] bv = mobj->Mesh.bv(); 202 | end 203 | 204 | 205 | // ---- 206 | @function Mesh_set_ur(mobj, ur) 207 | % Mesh_set_ur(mobj, ur) 208 | % 209 | % Set reduced displacement vector 210 | 211 | numid = Mesh_numid(mobj); 212 | # mobj->Mesh.set_ur(input double[numid] ur); 213 | 214 | 215 | // ---- 216 | @function ur = Mesh_get_ur(mobj) 217 | % ur = Mesh_get_ur(mobj) 218 | % 219 | % Get reduced displacement vector 220 | 221 | numid = Mesh_numid(mobj); 222 | # mobj->Mesh.get_ur(output double[numid] ur); 223 | 224 | 225 | // ---- 226 | @function Mesh_set_bc(mobj, bc, i, j) 227 | % Mesh_set_bc(mobj, bc, i, j) 228 | % 229 | % Set the boundary codes of mesh node i. If the node number is omitted, 230 | % set the boundary codes for all nodes in the mesh. 231 | $[ 232 | void set_bc(Mesh* mesh, char bc, int i, int j) 233 | { 234 | mesh->bc(i,j) = bc; 235 | } 236 | 237 | void set_bc(Mesh* mesh, char* bc) 238 | { 239 | int numnp = mesh->numnp(); 240 | int maxndf = mesh->maxndf(); 241 | for (int j = 0; j < numnp; ++j) 242 | for (int i = 0; i < maxndf; ++i) 243 | mesh->bc(i,j) = bc[i+j*maxndf]; 244 | } 245 | $] 246 | if nargin == 4 247 | i = i-1; 248 | j = j-1; 249 | # int maxndf = mobj->Mesh.maxndf(); 250 | # set_bc(Mesh* mobj, char bc, int i, int j); 251 | else 252 | # int numnp = mobj->Mesh.numnp(); 253 | # int maxndf = mobj->Mesh.maxndf(); 254 | # set_bc(Mesh* mobj, char[maxndf,numnp] bc); 255 | end 256 | 257 | 258 | // ---- 259 | @function Mesh_set_bv(mobj, bv, i, j) 260 | % Mesh_set_bv(mobj, bv, i, j) 261 | % 262 | % Set the boundary codes of mesh node i. If the node number is omitted, 263 | % set the boundary codes for all nodes in the mesh. 264 | $[ 265 | void set_bv(Mesh* mesh, double bv, int i, int j) 266 | { 267 | mesh->bv(i,j) = bv; 268 | } 269 | 270 | void set_bv(Mesh* mesh, double* bv) 271 | { 272 | int numnp = mesh->numnp(); 273 | int maxndf = mesh->maxndf(); 274 | for (int j = 0; j < numnp; ++j) 275 | for (int i = 0; i < maxndf; ++i) 276 | mesh->bv(i,j) = bv[i+j*maxndf]; 277 | } 278 | $] 279 | if nargin == 4 280 | i = i-1; 281 | j = j-1; 282 | # int maxndf = mobj->Mesh.maxndf(); 283 | # set_bv(Mesh* mobj, double bv, int i, int j); 284 | else 285 | # int numnp = mobj->Mesh.numnp(); 286 | # int maxndf = mobj->Mesh.maxndf(); 287 | # set_bv(Mesh* mobj, double[maxndf,numnp] bv); 288 | end 289 | 290 | 291 | // ---- 292 | @function numid = Mesh_initialize(mobj) 293 | % numid = Mesh_initialize(mobj) 294 | % 295 | % Initialize the mesh object after completion of X/IX arrays. 296 | # int numid = mobj->Mesh.initialize(); 297 | 298 | 299 | // ---- 300 | @function numid = Mesh_assign_ids(mobj) 301 | % numid = Mesh_assign_ids(mobj) 302 | % 303 | % Assign identifiers to active degrees of freedom in the mesh. 304 | # int numid = mobj->Mesh.assign_ids(); 305 | 306 | 307 | // ---- 308 | @function F = Mesh_assemble_F(mobj) 309 | % F = Mesh_assemble_F(mobj) 310 | % 311 | % Assemble system residual force vector. 312 | 313 | numid = Mesh_numid(mobj); 314 | # mobj->Mesh.assemble_F(); 315 | # mobj->Mesh.get_fr(output double[numid] F); 316 | 317 | 318 | // ---- 319 | @function K = Mesh_assemble_K(mobj) 320 | % K = Mesh_assemble_K(mobj) 321 | % 322 | % Assemble system stiffness matrix. 323 | 324 | numid = Mesh_numid(mobj); 325 | Ka = Assembler_create(numid, numid); 326 | # mobj->Mesh.assemble_K(MatrixAssembler* Ka); 327 | K = Assembler_get(Ka); 328 | Assembler_delete(Ka); 329 | 330 | 331 | // ---- 332 | @function id = Mesh_add_node(mobj, x) 333 | % id = Mesh_add_node(mobj, x) 334 | % 335 | % Build a new node at position x and return the index. 336 | 337 | # int ndm = mobj->Mesh.ndm(); 338 | # int id = mobj->Mesh.add_node(double[ndm] x); 339 | id = id + 1; 340 | 341 | 342 | // ---- 343 | @function id = Mesh_add_element(mobj, etype, nodes) 344 | % id = Mesh_add_element(mobj, etype, nodes) 345 | % 346 | % Build a new element of type etype connected to the indicated nodes, 347 | % and return the index. 348 | 349 | numnp = length(nodes); 350 | nodes = nodes-1; 351 | # int id = mobj->Mesh.add_element(EType* etype, int[numnp] nodes, int numnp); 352 | id = id + 1; 353 | 354 | 355 | // ---- 356 | @function Mesh_load(mobj, etype, x, ix) 357 | % Mesh_load(mobj, material, x, ix) 358 | % 359 | % Add a new batch of elements 360 | % material - Material type 361 | % x - Coordinates of nodes in new elements 362 | % ix - Connectivity array for new elements 363 | 364 | # int ndm = mobj->Mesh.ndm(); 365 | ids = zeros(1,size(x,2)); 366 | for j = 1:size(x,2) 367 | xj = x(:,j); 368 | # int id = mobj->Mesh.add_node(double[ndm] xj); 369 | ids(j) = id; 370 | end 371 | 372 | numnp = size(ix,1); 373 | for j = 1:size(ix,2) 374 | ixj = ids(ix(:,j)); 375 | # int id = mobj->Mesh.add_element(EType* etype, int[numnp] ixj, int numnp); 376 | end 377 | -------------------------------------------------------------------------------- /src/mwrap-ast.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * mwrap-ast.cc 3 | * Recursive routines for AST printing, identifier construction, 4 | * and destruction. 5 | * 6 | * Copyright (c) 2007 David Bindel 7 | * See the file COPYING for copying permissions 8 | */ 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include "mwrap-ast.h" 15 | 16 | 17 | /* -- Add inheritance relationship -- */ 18 | /* 19 | * We represent inheritance relationships as a list of child classes 20 | * associated with each parent. This makes sense when we generate the 21 | * type casting routines, since we only allow casts to the parent 22 | * types. But it's the opposite of how inheritance relations are 23 | * specified syntactically. 24 | */ 25 | 26 | map class_decls; 27 | 28 | 29 | void add_inherits(const char* childname, InheritsDecl* ilist) 30 | { 31 | for (; ilist; ilist = ilist->next) { 32 | InheritsDecl*& children = class_decls[ilist->name]; 33 | children = new InheritsDecl(mwrap_strdup(childname), children); 34 | } 35 | } 36 | 37 | 38 | /* -- Add scalar type data -- */ 39 | /* 40 | * The names of the numeric scalar types are stored in the set scalar_decls. 41 | * We provide a basic list, but the user can specify more -- the only real 42 | * constraint is there has to be a meaningful typecast to/from a double. 43 | */ 44 | 45 | set scalar_decls; 46 | set cscalar_decls; 47 | set zscalar_decls; 48 | set mxarray_decls; 49 | 50 | 51 | void init_scalar_types() 52 | { 53 | const char* scalar_types[] = { 54 | "double", "float", 55 | "long", "int", "short", "char", 56 | "ulong", "uint", "ushort", "uchar", 57 | "int32_t", "int64_t", "uint32_t", "uint64_t", 58 | "bool", "size_t", "ptrdiff_t", NULL}; 59 | 60 | for (const char** s = scalar_types; *s; ++s) 61 | add_scalar_type(*s); 62 | } 63 | 64 | 65 | char *promote_int(char* name) 66 | { 67 | /* Detect C99 types: int32_t, int64_t, uint32_t, uint64_t */ 68 | if( strcmp(name,"int32_t") == 0 ) mw_use_int32_t = 1; 69 | if( strcmp(name,"int64_t") == 0 ) mw_use_int64_t = 1; 70 | if( strcmp(name,"uint32_t") == 0 ) mw_use_uint32_t = 1; 71 | if( strcmp(name,"uint64_t") == 0 ) mw_use_uint64_t = 1; 72 | 73 | if( strcmp(name,"ulong") == 0 ) mw_use_ulong = 1; 74 | if( strcmp(name,"uint") == 0 ) mw_use_uint = 1; 75 | if( strcmp(name,"ushort") == 0 ) mw_use_ushort = 1; 76 | if( strcmp(name,"uchar") == 0 ) mw_use_uchar = 1; 77 | 78 | /* Promote integers */ 79 | if( mw_promote_int == 1 ) 80 | { 81 | if( strcmp(name,"uint") == 0 ) mw_use_ulong = 1; 82 | if( strcmp(name,"int") == 0 ) return strdup("long"); 83 | if( strcmp(name,"uint") == 0 ) return strdup("ulong"); 84 | } 85 | if( mw_promote_int == 2 ) 86 | { 87 | if( strcmp(name,"uint") == 0 ) mw_use_ulong = 1; 88 | if( strcmp(name,"ulong") == 0 ) mw_use_ulong = 1; 89 | if( strcmp(name,"int") == 0 ) return strdup("long"); 90 | if( strcmp(name,"long") == 0 ) return strdup("long"); 91 | if( strcmp(name,"uint") == 0 ) return strdup("ulong"); 92 | if( strcmp(name,"ulong") == 0 ) return strdup("ulong"); 93 | } 94 | if( mw_promote_int == 3 ) 95 | { 96 | if( strcmp(name,"int") == 0 ) mw_use_int32_t = 1; 97 | if( strcmp(name,"long") == 0 ) mw_use_int64_t = 1; 98 | if( strcmp(name,"uint") == 0 ) mw_use_uint32_t = 1; 99 | if( strcmp(name,"ulong") == 0 ) mw_use_uint64_t = 1; 100 | if( strcmp(name,"int") == 0 ) return strdup("int32_t"); 101 | if( strcmp(name,"long") == 0 ) return strdup("int32_t"); 102 | if( strcmp(name,"uint") == 0 ) return strdup("uint64_t"); 103 | if( strcmp(name,"ulong") == 0 ) return strdup("uint64_t"); 104 | } 105 | if( mw_promote_int == 4 ) 106 | { 107 | if( strcmp(name,"int") == 0 ) mw_use_int64_t = 1; 108 | if( strcmp(name,"long") == 0 ) mw_use_int64_t = 1; 109 | if( strcmp(name,"uint") == 0 ) mw_use_uint64_t = 1; 110 | if( strcmp(name,"ulong") == 0 ) mw_use_uint64_t = 1; 111 | if( strcmp(name,"int") == 0 ) return strdup("int64_t"); 112 | if( strcmp(name,"long") == 0 ) return strdup("int64_t"); 113 | if( strcmp(name,"uint") == 0 ) return strdup("uint64_t"); 114 | if( strcmp(name,"ulong") == 0 ) return strdup("uint64_t"); 115 | } 116 | return name; 117 | } 118 | 119 | 120 | 121 | void add_scalar_type(const char* name) 122 | { 123 | scalar_decls.insert(name); 124 | } 125 | 126 | 127 | void add_cscalar_type(const char* name) 128 | { 129 | cscalar_decls.insert(name); 130 | } 131 | 132 | 133 | void add_zscalar_type(const char* name) 134 | { 135 | zscalar_decls.insert(name); 136 | } 137 | 138 | 139 | void add_mxarray_type(const char* name) 140 | { 141 | mxarray_decls.insert(name); 142 | } 143 | 144 | 145 | bool is_scalar_type(const char* name) 146 | { 147 | return (scalar_decls.find(name) != scalar_decls.end()); 148 | } 149 | 150 | 151 | bool is_cscalar_type(const char* name) 152 | { 153 | return (cscalar_decls.find(name) != cscalar_decls.end()); 154 | } 155 | 156 | 157 | bool is_zscalar_type(const char* name) 158 | { 159 | return (zscalar_decls.find(name) != zscalar_decls.end()); 160 | } 161 | 162 | 163 | bool is_mxarray_type(const char* name) 164 | { 165 | return (mxarray_decls.find(name) != mxarray_decls.end()); 166 | } 167 | 168 | 169 | /* -- Print the AST -- */ 170 | /* 171 | * Print a human-readable translation of the abstract syntax tree to 172 | * the output. This is only used for generating comprehensible comments 173 | * in the C code. 174 | */ 175 | 176 | 177 | void print(FILE* fp, Expr* e) 178 | { 179 | if (!e) 180 | return; 181 | fprintf(fp, "%s", e->value); 182 | if (e->next) { 183 | fprintf(fp, ", "); 184 | print(fp, e->next); 185 | } 186 | } 187 | 188 | 189 | void print(FILE* fp, TypeQual* q) 190 | { 191 | if (!q) 192 | return; 193 | if (q->qual == 'a') { 194 | fprintf(fp, "["); 195 | print(fp, q->args); 196 | fprintf(fp, "]"); 197 | } else 198 | fprintf(fp, "%c", q->qual); 199 | } 200 | 201 | void print_devicespec(FILE* fp, Var* v) 202 | { 203 | if (v->devicespec == 'g') 204 | fprintf(fp, "gpu "); 205 | } 206 | 207 | void print_iospec(FILE* fp, Var* v) 208 | { 209 | if (v->iospec == 'o') 210 | fprintf(fp, "output "); 211 | else if (v->iospec == 'b') 212 | fprintf(fp, "inout "); 213 | } 214 | 215 | 216 | void print_var(FILE* fp, Var* v) 217 | { 218 | fprintf(fp, "%s", v->basetype); 219 | print(fp, v->qual); 220 | fprintf(fp, " %s", v->name); 221 | } 222 | 223 | 224 | void print_args(FILE* fp, Var* v) 225 | { 226 | if (!v) 227 | return; 228 | print_devicespec(fp, v); 229 | print_iospec(fp, v); 230 | print_var(fp, v); 231 | if (v->next) { 232 | fprintf(fp, ", "); 233 | print_args(fp, v->next); 234 | } 235 | } 236 | 237 | 238 | void print(FILE* fp, Func* f) 239 | { 240 | if (!f) 241 | return; 242 | if (f->ret) { 243 | print_var(fp, f->ret); 244 | fprintf(fp, " = "); 245 | } 246 | if (f->thisv) 247 | fprintf(fp, "%s->%s.", f->thisv, f->classv); 248 | fprintf(fp, "%s(", f->funcv); 249 | print_args(fp, f->args); 250 | fprintf(fp, ");\n"); 251 | } 252 | 253 | 254 | /* -- ID string -- */ 255 | /* 256 | * The ID string is a compressed text representation of the AST for 257 | * a function. We replace all the variable names by the letter 'x' 258 | * so that when we have the same function call with different arguments, 259 | * we will generate the same signature. 260 | */ 261 | 262 | 263 | string id_string(Expr* e) 264 | { 265 | if (!e) 266 | return ""; 267 | return "x" + id_string(e->next); 268 | } 269 | 270 | 271 | string id_string(TypeQual* q) 272 | { 273 | if (!q) 274 | return ""; 275 | if (q->qual == 'a') 276 | return "[" + id_string(q->args) + "]"; 277 | else 278 | return (string() + q->qual); 279 | } 280 | 281 | 282 | string id_string(Var* v) 283 | { 284 | if (!v) 285 | return ""; 286 | 287 | string name; 288 | if (v->devicespec == 'c') 289 | name += "c "; 290 | else if (v->devicespec == 'g') 291 | name += "g "; 292 | 293 | if (v->iospec == 'i') 294 | name += "i "; 295 | else if (v->iospec == 'o') 296 | name += "o "; 297 | else 298 | name += "io "; 299 | name += promote_int(v->basetype); 300 | name += id_string(v->qual); 301 | if (v->tinfo == VT_const) { 302 | name += " "; 303 | name += v->name; 304 | } 305 | if (v->next) { 306 | name += ", "; 307 | name += id_string(v->next); 308 | } 309 | return name; 310 | } 311 | 312 | 313 | string id_string(Func* f) 314 | { 315 | if (!f) 316 | return ""; 317 | 318 | string name; 319 | if (f->ret) { 320 | name += id_string(f->ret); 321 | name += " = "; 322 | } 323 | if (f->thisv) { 324 | name += f->thisv; 325 | name += "->"; 326 | name += f->classv; 327 | name += "."; 328 | } 329 | name += f->funcv; 330 | name += "("; 331 | name += id_string(f->args); 332 | name += ")"; 333 | return name; 334 | } 335 | 336 | 337 | /* -- Destroy an AST -- */ 338 | 339 | 340 | void destroy(Expr* e) 341 | { 342 | if (!e) 343 | return; 344 | destroy(e->next); 345 | delete[] e->value; 346 | delete e; 347 | } 348 | 349 | 350 | void destroy(TypeQual* q) 351 | { 352 | if (!q) 353 | return; 354 | destroy(q->args); 355 | delete q; 356 | } 357 | 358 | 359 | void destroy(Var* v) 360 | { 361 | if (!v) 362 | return; 363 | destroy(v->next); 364 | destroy(v->qual); 365 | delete[] v->basetype; 366 | delete[] v->name; 367 | delete v; 368 | } 369 | 370 | 371 | void destroy(Func* f) 372 | { 373 | while (f) { 374 | Func* oldf = f; 375 | f = f->next; 376 | 377 | destroy(oldf->same_next); 378 | destroy(oldf->ret); 379 | if (oldf->thisv) 380 | delete[] oldf->thisv; 381 | if (oldf->classv) 382 | delete[] oldf->classv; 383 | delete[] oldf->funcv; 384 | destroy(oldf->args); 385 | delete oldf; 386 | } 387 | } 388 | 389 | 390 | void destroy(InheritsDecl* i) 391 | { 392 | if (!i) 393 | return; 394 | destroy(i->next); 395 | delete i; 396 | } 397 | 398 | 399 | void destroy_inherits() 400 | { 401 | map::iterator i = class_decls.begin(); 402 | for (; i != class_decls.end(); ++i) { 403 | destroy(i->second); 404 | i->second = NULL; 405 | } 406 | } 407 | -------------------------------------------------------------------------------- /src/mwrap.y.in: -------------------------------------------------------------------------------- 1 | %{ 2 | /* 3 | * mwrap.y 4 | * Parser for mwrap. 5 | * 6 | * Copyright (c) 2007 David Bindel 7 | * See the file COPYING for copying permissions 8 | */ 9 | 10 | #include 11 | #include 12 | #include 13 | #include "mwrap-ast.h" 14 | 15 | extern "C" { 16 | int yylex(); 17 | int yywrap(); 18 | int yyerror(const char* s); 19 | } 20 | 21 | using std::string; 22 | 23 | bool mw_use_gpu = 0; // Use GPU? 24 | bool mw_generate_catch = false; // Catch C++ exceptions? 25 | bool mw_use_cpp_complex = false; // Use C++ complex types? 26 | bool mw_use_c99_complex = false; // Use C99 complex types? 27 | int mw_promote_int = 0; // Convert integer types to mwSize? 28 | int mw_use_int32_t = 0; // Use C99 int32_t? 29 | int mw_use_int64_t = 0; // Use C99 int64_t? 30 | int mw_use_uint32_t = 0; // Use C99 uint32_t? 31 | int mw_use_uint64_t = 0; // Use C99 uint64_t? 32 | int mw_use_ulong = 0; // Use unsigned long? 33 | int mw_use_uint = 0; // Use unsigned int? 34 | int mw_use_ushort = 0; // Use unsigned short? 35 | int mw_use_uchar = 0; // Use unsigned char? 36 | int listing_flag = 0; // Output filenames from @ commands? 37 | int mbatching_flag = 0; // Output on @ commands? 38 | int linenum = 0; // Lexer line number 39 | FILE* outfp = 0; // MATLAB output file 40 | FILE* outcfp = 0; // C output file 41 | 42 | static int type_errs = 0; // Number of typecheck errors 43 | static int func_id = 0; // Assign stub numbers 44 | static Func* funcs = 0; // AST - linked list of functions 45 | static Func* lastfunc = 0; // Last link in funcs list 46 | static const char* mexfunc = "mexfunction"; // Name of mex function 47 | static string current_ifname; // Current input file name 48 | 49 | 50 | #define MAX_INCLUDE_DEPTH 10 51 | static string include_stack_names[MAX_INCLUDE_DEPTH]; 52 | extern int include_stack_ptr; 53 | 54 | extern "C" void set_include_name(const char* s) 55 | { 56 | include_stack_names[include_stack_ptr] = current_ifname; 57 | current_ifname = s; 58 | } 59 | 60 | extern "C" void get_include_name() 61 | { 62 | current_ifname = include_stack_names[include_stack_ptr].c_str(); 63 | } 64 | 65 | 66 | inline void add_func(Func* func) 67 | { 68 | static std::map func_lookup; 69 | if (!funcs) { 70 | funcs = func; 71 | lastfunc = func; 72 | return; 73 | } 74 | 75 | Func*& func_ptr = func_lookup[id_string(func)]; 76 | if (func_ptr) { 77 | func_ptr->same_next = func; 78 | } else { 79 | lastfunc->next = func; 80 | lastfunc = func; 81 | } 82 | func_ptr = func; 83 | } 84 | 85 | %} 86 | 87 | %union { 88 | char* string; 89 | struct Func* func; 90 | struct Var* var; 91 | struct TypeQual* qual; 92 | struct Expr* expr; 93 | struct InheritsDecl* inherits; 94 | char c; 95 | } 96 | 97 | %token NON_C_LINE 98 | %token NEW TYPEDEF CLASS FORTRAN 99 | %token ID 100 | %token NUMBER STRING 101 | %token INPUT OUTPUT INOUT 102 | %token CPU GPU 103 | 104 | %type func funcall 105 | %type var basevar args argsrest 106 | %type iospec 107 | %type devicespec 108 | %type quals aqual 109 | %type arrayspec exprs exprrest expr 110 | %type inheritslist inheritsrest 111 | 112 | @ERROR_VERBOSE@ 113 | 114 | %% 115 | statements: statement statements | ; 116 | 117 | statement: 118 | basevar '=' funcall { 119 | $3->ret = $1; 120 | $3->id = ++func_id; 121 | type_errs += typecheck($3, linenum); 122 | if (outfp) 123 | print_matlab_call(outfp, $3, mexfunc); 124 | add_func($3); 125 | } 126 | | funcall { 127 | $1->id = ++func_id; 128 | type_errs += typecheck($1, linenum); 129 | if (outfp) 130 | print_matlab_call(outfp, $1, mexfunc); 131 | add_func($1); 132 | } 133 | | tdef 134 | | classdef 135 | | NON_C_LINE 136 | | error ';' { yyerrok; } ; 137 | 138 | tdef: 139 | TYPEDEF ID ID ';' { 140 | if (strcmp($2, "numeric") == 0) { 141 | add_scalar_type($3); 142 | } else if (strcmp($2, "dcomplex") == 0) { 143 | add_zscalar_type($3); 144 | } else if (strcmp($2, "fcomplex") == 0) { 145 | add_cscalar_type($3); 146 | } else if (strcmp($2, "mxArray") == 0) { 147 | add_mxarray_type($3); 148 | } else { 149 | fprintf(stderr, "Unrecognized typespace: %s\n", $2); 150 | ++type_errs; 151 | } 152 | delete[] $2; 153 | delete[] $3; 154 | } ; 155 | 156 | classdef: 157 | CLASS ID ':' inheritslist ';' { 158 | add_inherits($2, $4); 159 | delete[] $2; 160 | destroy($4); 161 | } 162 | 163 | inheritslist: 164 | ID inheritsrest { $$ = new InheritsDecl($1, $2); } ; 165 | 166 | inheritsrest: 167 | ',' ID inheritsrest { $$ = new InheritsDecl($2, $3); } 168 | | { $$ = NULL; } ; 169 | 170 | funcall: func '(' args ')' ';' { $$ = $1; $$->args = $3; } ; 171 | 172 | args: 173 | var argsrest { $$ = $1; $$->next = $2; } 174 | | { $$ = NULL; } ; 175 | 176 | argsrest: 177 | ',' var argsrest {$$ = $2; $$->next = $3; } 178 | | { $$ = NULL; } ; 179 | 180 | basevar: ID ID { $$ = new Var('c', 'o', promote_int($1), NULL, $2); } 181 | basevar: ID quals ID { $$ = new Var('c', 'o', promote_int($1), $2, $3); } 182 | basevar: ID ID aqual { $$ = new Var('c', 'o', promote_int($1), $3, $2); } 183 | 184 | var: devicespec iospec ID ID { $$ = new Var($1, $2, promote_int($3), NULL, $4); } 185 | var: devicespec iospec ID quals ID { $$ = new Var($1, $2, promote_int($3), $4, $5); } 186 | var: devicespec iospec ID ID aqual { $$ = new Var($1, $2, promote_int($3), $5, $4); } 187 | 188 | var: devicespec iospec ID NUMBER { $$ = new Var($1, $2, promote_int($3), NULL, $4); } 189 | var: devicespec iospec ID quals NUMBER { $$ = new Var($1, $2, promote_int($3), $4, $5); } 190 | 191 | var: devicespec iospec ID STRING { $$ = new Var($1, $2, promote_int($3), NULL, $4); } 192 | var: devicespec iospec ID quals STRING { $$ = new Var($1, $2, promote_int($3), $4, $5); } 193 | 194 | devicespec: 195 | CPU { $$ = 'c'; } 196 | | GPU { $$ = 'g'; } 197 | | { $$ = 'c'; } ; 198 | 199 | iospec: 200 | INPUT { $$ = 'i'; } 201 | | OUTPUT { $$ = 'o'; } 202 | | INOUT { $$ = 'b'; } 203 | | { $$ = 'i'; } ; 204 | 205 | quals: 206 | '*' { $$ = new TypeQual('*', NULL); } 207 | | '&' { $$ = new TypeQual('&', NULL); } 208 | | aqual { $$ = $1; } ; 209 | 210 | aqual: 211 | arrayspec { $$ = new TypeQual('a', $1); } 212 | | arrayspec '&' { $$ = new TypeQual('r', $1); } ; 213 | 214 | arrayspec: '[' exprs ']' { $$ = $2; } ; 215 | 216 | exprs: 217 | expr exprrest { $$ = $1; $$->next = $2; } 218 | | { $$ = NULL; } 219 | 220 | exprrest: 221 | ',' expr exprrest { $$ = $2; $$->next = $3; } 222 | | { $$ = NULL; } 223 | 224 | expr: 225 | ID { $$ = new Expr($1); } 226 | | NUMBER { $$ = new Expr($1); } 227 | 228 | func: 229 | ID '-' '>' ID '.' ID { $$ = new Func($1, $4, $6, current_ifname, linenum); } 230 | | ID { $$ = new Func(NULL, NULL, $1, current_ifname, linenum); } 231 | | FORTRAN ID { $$ = new Func(NULL, NULL, $2, current_ifname, linenum); 232 | $$->fort = true; 233 | } 234 | | NEW ID { $$ = new Func(NULL, $2, mwrap_strdup("new"), 235 | current_ifname, linenum); 236 | } 237 | ; 238 | 239 | %% 240 | #include 241 | #include 242 | 243 | extern FILE* yyin; 244 | 245 | int yywrap() 246 | { 247 | return 1; 248 | } 249 | 250 | int yyerror(const char* s) 251 | { 252 | fprintf(stderr, "Parse error (%s:%d): %s\n", current_ifname.c_str(), 253 | linenum, s); 254 | return 0; 255 | } 256 | 257 | char* mwrap_strdup(const char* s) 258 | { 259 | char* result = new char[strlen(s)+1]; 260 | strcpy(result, s); 261 | return result; 262 | } 263 | 264 | const char* help_string = 265 | "mwrap 1.2 - MEX file generator for MATLAB and Octave\n" 266 | "\n" 267 | "Syntax:\n" 268 | " mwrap [-mex outputmex] [-m output.m] [-c outputmex.c] [-mb] [-list]\n" 269 | " [-catch] [-i8] [-c99complex] [-cppcomplex] [-gpu] infile1 infile2 ...\n" 270 | "\n" 271 | " -mex outputmex -- specify the MATLAB mex function name\n" 272 | " -m output.m -- generate the MATLAB stub called output.m\n" 273 | " -c outputmex.c -- generate the C file outputmex.c\n" 274 | " -mb -- generate .m files specified with @ redirections\n" 275 | " -list -- list files specified with @ redirections\n" 276 | " -catch -- generate C++ exception handling code\n" 277 | " -i8 -- convert int, long, uint, ulong to int64_t, uint64_t\n" 278 | " -c99complex -- add support code for C99 complex types\n" 279 | " -cppcomplex -- add support code for C++ complex types\n" 280 | " -gpu -- add support code for MATLAB gpuArray\n" 281 | "\n"; 282 | 283 | int main(int argc, char** argv) 284 | { 285 | int j; 286 | int err_flag = 0; 287 | init_scalar_types(); 288 | 289 | if (argc == 1) { 290 | fprintf(stderr, "%s", help_string); 291 | return 0; 292 | } else { 293 | for (j = 1; j < argc; ++j) { 294 | if (strcmp(argv[j], "-m") == 0 && j+1 < argc) 295 | outfp = fopen(argv[j+1], "w+"); 296 | if (strcmp(argv[j], "-c") == 0 && j+1 < argc) 297 | outcfp = fopen(argv[j+1], "w+"); 298 | if (strcmp(argv[j], "-mex") == 0 && j+1 < argc) 299 | mexfunc = argv[j+1]; 300 | if (strcmp(argv[j], "-mb") == 0) 301 | mbatching_flag = 1; 302 | if (strcmp(argv[j], "-list") == 0) 303 | listing_flag = 1; 304 | if (strcmp(argv[j], "-catch") == 0) 305 | mw_generate_catch = true; 306 | if (strcmp(argv[j], "-i8") == 0) 307 | mw_promote_int = 4; 308 | if (strcmp(argv[j], "-c99complex") == 0) 309 | mw_use_c99_complex = true; 310 | if (strcmp(argv[j], "-cppcomplex") == 0) 311 | mw_use_cpp_complex = true; 312 | if (strcmp(argv[j], "-gpu") == 0) 313 | mw_use_gpu = true; 314 | } 315 | 316 | if (mw_use_c99_complex || mw_use_cpp_complex) { 317 | add_zscalar_type("dcomplex"); 318 | add_cscalar_type("fcomplex"); 319 | } 320 | 321 | for (j = 1; j < argc; ++j) { 322 | if (strcmp(argv[j], "-m") == 0 || 323 | strcmp(argv[j], "-c") == 0 || 324 | strcmp(argv[j], "-mex") == 0) 325 | ++j; 326 | else if (strcmp(argv[j], "-mb") == 0 || 327 | strcmp(argv[j], "-list") == 0 || 328 | strcmp(argv[j], "-catch") == 0 || 329 | strcmp(argv[j], "-i8") == 0 || 330 | strcmp(argv[j], "-c99complex") == 0 || 331 | strcmp(argv[j], "-cppcomplex") == 0 || 332 | strcmp(argv[j], "-gpu") == 0); 333 | else { 334 | linenum = 1; 335 | type_errs = 0; 336 | yyin = fopen(argv[j], "r"); 337 | if (yyin) { 338 | current_ifname = argv[j]; 339 | if (outcfp) 340 | print_mex_init(outcfp); 341 | err_flag += yyparse(); 342 | fclose(yyin); 343 | } else { 344 | fprintf(stderr, "Could not read %s\n", argv[j]); 345 | } 346 | if (type_errs) 347 | fprintf(stderr, "%s: %d type errors detected\n", 348 | argv[j], type_errs); 349 | err_flag += type_errs; 350 | } 351 | } 352 | } 353 | if (!err_flag && outcfp) 354 | print_mex_file(outcfp, funcs); 355 | destroy(funcs); 356 | destroy_inherits(); 357 | if (outfp) 358 | fclose(outfp); 359 | if (outcfp) 360 | fclose(outcfp); 361 | return err_flag; 362 | } 363 | -------------------------------------------------------------------------------- /src/mwrap-typecheck.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * mwrap-typecheck.cc 3 | * Typecheck MWrap AST. 4 | * 5 | * Copyright (c) 2007 David Bindel 6 | * See the file COPYING for copying permissions 7 | */ 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include "mwrap-ast.h" 14 | 15 | 16 | /* -- Label input / output indices -- */ 17 | /* 18 | * To each argument, we assign an input label (index of the argument 19 | * in the prhs array) and an output label (the index in the plhs 20 | * array). The protocol is that we pass input and inout arguments in 21 | * first, and then tack on all the dimensioning arguments at the end. 22 | */ 23 | 24 | 25 | void label_dim_args(Expr* e, int& icount) 26 | { 27 | if (!e) 28 | return; 29 | e->input_label = icount++; 30 | label_dim_args(e->next, icount); 31 | } 32 | 33 | 34 | void label_dim_args(Var* v, int& icount) 35 | { 36 | if (!v) 37 | return; 38 | if (v->qual) 39 | label_dim_args(v->qual->args, icount); 40 | label_dim_args(v->next, icount); 41 | } 42 | 43 | 44 | void label_args(Var* v, int& icount, int& ocount) 45 | { 46 | if (!v) 47 | return; 48 | if (v->iospec == 'i' || v->iospec == 'b') 49 | v->input_label = icount++; 50 | if (v->iospec == 'o' || v->iospec == 'b') 51 | v->output_label = ocount++; 52 | label_args(v->next, icount, ocount); 53 | } 54 | 55 | 56 | void label_args(Func* f) 57 | { 58 | int icount = 0; 59 | int ocount = 0; 60 | if (f->thisv) 61 | icount = 1; 62 | label_args(f->ret, icount, ocount); 63 | label_args(f->args, icount, ocount); 64 | label_dim_args(f->ret, icount); 65 | label_dim_args(f->args, icount); 66 | } 67 | 68 | 69 | /* -- Fortran-ize arguments -- */ 70 | /* 71 | * For FORTRAN calls, we make the following type conversions and 72 | * checks on arguments: 73 | * 74 | * - All types of scalar arguments are converted to pointer-to-scalar. 75 | * - Object arguments are forbidden 76 | * - C string arguments generate a warning 77 | * 78 | * Only scalar return values are allowed from wrapped FORTRAN functions. 79 | */ 80 | 81 | 82 | int fortranize_args(Var* v, int line) 83 | { 84 | if (!v) 85 | return 0; 86 | int errcount = 0; 87 | if (v->tinfo == VT_obj || v->tinfo == VT_p_obj || v->tinfo == VT_r_obj) { 88 | fprintf(stderr, "Error (%d): ", line); 89 | fprintf(stderr, "Cannot pass object %s to FORTRAN\n", v->name); 90 | ++errcount; 91 | } else if (v->tinfo == VT_rarray) { 92 | fprintf(stderr, "Error (%d): ", line); 93 | fprintf(stderr, "Cannot pass pointer ref %s to FORTRAN\n", v->name); 94 | ++errcount; 95 | } else if (v->tinfo == VT_string) { 96 | fprintf(stderr, "Warning (%d): ", line); 97 | fprintf(stderr, "Danger passing C string %s to FORTRAN\n", v->name); 98 | } else if (v->tinfo == VT_scalar || v->tinfo == VT_r_scalar) { 99 | v->tinfo = VT_p_scalar; 100 | } else if (v->tinfo == VT_cscalar || v->tinfo == VT_r_cscalar) { 101 | v->tinfo = VT_p_cscalar; 102 | } else if (v->tinfo == VT_zscalar || v->tinfo == VT_r_zscalar) { 103 | v->tinfo = VT_p_zscalar; 104 | } 105 | return errcount + fortranize_args(v->next, line); 106 | } 107 | 108 | 109 | int fortranize_ret(Var* v, int line) 110 | { 111 | if (!v) 112 | return 0; 113 | if (v->tinfo == VT_cscalar || v->tinfo == VT_zscalar) { 114 | fprintf(stderr, "Warning (%d): ", line); 115 | fprintf(stderr, "Danger returning complex from FORTRAN\n"); 116 | } else if (v->tinfo != VT_scalar) { 117 | fprintf(stderr, "Error (%d): ", line); 118 | fprintf(stderr, "Can only return scalars from FORTRAN\n"); 119 | return 1; 120 | } 121 | return 0; 122 | } 123 | 124 | 125 | int fortranize_args(Func* f, int line) 126 | { 127 | if (!f->fort) 128 | return 0; 129 | return (fortranize_args(f->args, line) + 130 | fortranize_ret(f->ret, line)); 131 | } 132 | 133 | 134 | /* -- Type info assignment and checking -- */ 135 | /* 136 | * Strictly speaking, we're doing semantic checking here -- there are a 137 | * few things we check for that don't qualify as type errors. The 138 | * assumption is that any input to the C code generator has passed the 139 | * type checker. 140 | */ 141 | 142 | 143 | int assign_scalar_tinfo(Var* v, int line, 144 | int tags, int tagp, int tagr, int taga, 145 | int tagar) 146 | { 147 | // Numeric types 148 | if (!v->qual) { 149 | v->tinfo = tags; 150 | } else if (v->qual->qual == '*') { 151 | v->tinfo = tagp; 152 | } else if (v->qual->qual == '&') { 153 | v->tinfo = tagr; 154 | } else if (v->qual->qual == 'a') { 155 | v->tinfo = taga; 156 | if (v->qual->args && 157 | v->qual->args->next && 158 | v->qual->args->next->next) { 159 | fprintf(stderr, "Error (%d): ", line); 160 | fprintf(stderr, "Array %s should be 1D or 2D\n", v->name); 161 | return 1; 162 | } 163 | } else if (v->qual->qual == 'r') { 164 | v->tinfo = tagar; 165 | if (tagar == VT_unk) { 166 | fprintf(stderr, "Error (%d): ", line); 167 | fprintf(stderr, "Array ref %s must be to a real array\n", 168 | v->name); 169 | return 1; 170 | } 171 | if (v->qual->args && 172 | v->qual->args->next && 173 | v->qual->args->next->next) { 174 | fprintf(stderr, "Error (%d): ", line); 175 | fprintf(stderr, "Array %s should be 1D or 2D\n", v->name); 176 | return 1; 177 | } 178 | } else { 179 | assert(0); 180 | } 181 | 182 | return 0; 183 | } 184 | 185 | 186 | int assign_tinfo(Var* v, int line) 187 | { 188 | if (is_scalar_type(v->basetype)) { 189 | 190 | return assign_scalar_tinfo(v, line, VT_scalar, VT_p_scalar, 191 | VT_r_scalar, VT_array, VT_rarray); 192 | 193 | } else if (is_cscalar_type(v->basetype)) { 194 | 195 | return assign_scalar_tinfo(v, line, VT_cscalar, VT_p_cscalar, 196 | VT_r_cscalar, VT_carray, VT_unk); 197 | 198 | } else if (is_zscalar_type(v->basetype)) { 199 | 200 | return assign_scalar_tinfo(v, line, VT_zscalar, VT_p_zscalar, 201 | VT_r_zscalar, VT_zarray, VT_unk); 202 | 203 | } else if (strcmp(v->basetype, "const") == 0) { 204 | 205 | if (v->qual) { 206 | fprintf(stderr, "Error (%d): ", line); 207 | fprintf(stderr, "Constant %s cannot have modifiers\n", v->name); 208 | return 1; 209 | } 210 | v->tinfo = VT_const; 211 | if (v->name[0] == '\'') { 212 | char* p_out = v->name; 213 | char* p_in = v->name; 214 | for (; *p_in; ++p_in) { 215 | if (*p_in != '\'') 216 | *p_out++ = *p_in; 217 | } 218 | *p_out++ = 0; 219 | } 220 | 221 | } else if (strcmp(v->basetype, "cstring") == 0) { 222 | 223 | // String type 224 | if (v->qual && v->qual->qual != 'a') { 225 | fprintf(stderr, "Error (%d): ", line); 226 | fprintf(stderr, "String type %s cannot have modifiers\n", 227 | v->name); 228 | return 1; 229 | } 230 | if (v->qual && v->qual->args && v->qual->args->next) { 231 | fprintf(stderr, "Error (%d): ", line); 232 | fprintf(stderr, "Strings are one dimensional\n"); 233 | return 1; 234 | } 235 | v->tinfo = VT_string; 236 | 237 | } else if (strcmp(v->basetype, "mxArray") == 0) { 238 | 239 | // MATLAB intrinsic type 240 | if (v->qual) { 241 | fprintf(stderr, "Error (%d): ", line); 242 | fprintf(stderr, "mxArray %s cannot have modifiers\n", 243 | v->name); 244 | return 1; 245 | } 246 | v->tinfo = VT_mx; 247 | 248 | } else { 249 | 250 | // Object type 251 | if (!v->qual) 252 | v->tinfo = VT_obj; 253 | else if (v->qual->qual == '*') 254 | v->tinfo = VT_p_obj; 255 | else if (v->qual->qual == '&') 256 | v->tinfo = VT_r_obj; 257 | else if (v->qual->qual == 'a' || v->qual->qual == 'r') { 258 | fprintf(stderr, "Error (%d): ", line); 259 | fprintf(stderr, "%s cannot be an array of object %s\n", 260 | v->name, v->basetype); 261 | return 1; 262 | } else 263 | assert(0); 264 | 265 | } 266 | return 0; 267 | } 268 | 269 | 270 | int typecheck_return(Var* v, int line) 271 | { 272 | if (!v) 273 | return 0; 274 | 275 | int err = assign_tinfo(v, line); 276 | if ((v->tinfo == VT_array || 277 | v->tinfo == VT_carray || 278 | v->tinfo == VT_zarray) && 279 | !(v->qual && v->qual->args)) { 280 | fprintf(stderr, "Error (%d): ", line); 281 | fprintf(stderr, "Return array %s must have dims\n", v->name); 282 | ++err; 283 | } else if (v->tinfo == VT_const) { 284 | fprintf(stderr, "Error (%d): ", line); 285 | fprintf(stderr, "Cannot return constant\n"); 286 | ++err; 287 | } else if (v->tinfo == VT_rarray) { 288 | fprintf(stderr, "Error (%d): ", line); 289 | fprintf(stderr, "Ref to array %s looks just like array on return\n", 290 | v->name); 291 | ++err; 292 | } else if (v->tinfo == VT_string && v->qual) { 293 | fprintf(stderr, "Error (%d): ", line); 294 | fprintf(stderr, "Return string %s cannot have dims\n", v->name); 295 | ++err; 296 | } 297 | return err; 298 | } 299 | 300 | 301 | int typecheck_args(Var* v, int line) 302 | { 303 | if (!v) 304 | return 0; 305 | 306 | int err = assign_tinfo(v, line); 307 | if (v->iospec == 'i') 308 | return err + typecheck_args(v->next, line); 309 | 310 | if (isdigit(v->name[0])) { 311 | fprintf(stderr, "Error (%d): ", line); 312 | fprintf(stderr, "Number %s cannot be output\n", v->name); 313 | ++err; 314 | } 315 | 316 | if ((v->tinfo == VT_obj || v->tinfo == VT_p_obj || v->tinfo == VT_r_obj) && 317 | !is_mxarray_type(v->basetype)) { 318 | fprintf(stderr, "Error (%d): ", line); 319 | fprintf(stderr, "Object %s cannot be output\n", v->name); 320 | ++err; 321 | } else if ((v->tinfo == VT_array || 322 | v->tinfo == VT_carray || 323 | v->tinfo == VT_zarray || 324 | v->tinfo == VT_rarray) && 325 | v->iospec == 'o' && 326 | !(v->qual && v->qual->args)) { 327 | fprintf(stderr, "Error (%d): ", line); 328 | fprintf(stderr, "Output array %s must have dims\n", v->name); 329 | ++err; 330 | } else if (v->tinfo == VT_rarray && v->iospec != 'o') { 331 | fprintf(stderr, "Error (%d): ", line); 332 | fprintf(stderr, "Array ref %s *must* be output\n", v->name); 333 | ++err; 334 | } else if (v->tinfo == VT_scalar) { 335 | fprintf(stderr, "Error (%d): ", line); 336 | fprintf(stderr, "Scalar %s cannot be output\n", v->name); 337 | ++err; 338 | } else if (v->tinfo == VT_const) { 339 | fprintf(stderr, "Error (%d): ", line); 340 | fprintf(stderr, "Constant %s cannot be output\n", v->name); 341 | ++err; 342 | } else if (v->tinfo == VT_string && 343 | !(v->qual && v->qual->args)) { 344 | fprintf(stderr, "Error (%d): ", line); 345 | fprintf(stderr, "String %s cannot be output without size\n", v->name); 346 | ++err; 347 | } else if (v->tinfo == VT_mx && v->iospec == 'b') { 348 | fprintf(stderr, "Error (%d): ", line); 349 | fprintf(stderr, "mxArray %s cannot be used for inout\n", v->name); 350 | ++err; 351 | } 352 | return err + typecheck_args(v->next, line); 353 | } 354 | 355 | 356 | int typecheck(Func* f, int line) 357 | { 358 | label_args(f); 359 | return (typecheck_return(f->ret, line) + 360 | typecheck_args(f->args, line) + 361 | fortranize_args(f, line)); 362 | } 363 | 364 | -------------------------------------------------------------------------------- /example/fem/src/elastic2d1.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * elastic2d.cc 3 | * Element type for 2D elasticity (4 node quad only). 4 | * 5 | * Copyright (c) 2007 David Bindel 6 | * See the file COPYING for copying permissions 7 | */ 8 | 9 | #include "etype.h" 10 | #include "mesh.h" 11 | #include "elastic2d.h" 12 | #include "quad2d.h" 13 | #include "gauss2by2.h" 14 | #include 15 | 16 | #define ME Elastic2D 17 | 18 | 19 | ME::ME(double E, double nu, const char* type) 20 | { 21 | if (strcmp(type, "plane stress") == 0) 22 | plane_stress(E, nu); 23 | else 24 | plane_strain(E, nu); 25 | } 26 | 27 | 28 | void ME::plane_strain(double E, double nu) 29 | { 30 | /* 31 | input E, nu; 32 | output D(3,3); 33 | 34 | D = E/(1+nu)/(1-2*nu) * 35 | [ 1-nu, nu, 0; 36 | nu, 1-nu, 0; 37 | 0, 0, (1-2*nu)/2 ]; 38 | */ 39 | /* */ { 40 | double tmp1_ = E; 41 | double tmp2_ = nu; 42 | double tmp4_ = 1.0 + tmp2_; 43 | double tmp5_ = tmp1_ / tmp4_; 44 | double tmp7_ = 2.0 * tmp2_; 45 | double tmp8_ = 1.0 - tmp7_; 46 | double tmp9_ = tmp5_ / tmp8_; 47 | double tmp10_ = 1.0 - tmp2_; 48 | double tmp12_ = tmp8_ / 2.0; 49 | double tmp13_ = tmp9_ * tmp10_; 50 | double tmp14_ = tmp9_ * tmp2_; 51 | double tmp15_ = tmp9_ * tmp12_; 52 | D[0*3+0] = tmp13_; 53 | D[0*3+1] = tmp14_; 54 | D[0*3+2] = 0; 55 | D[1*3+0] = tmp14_; 56 | D[1*3+1] = tmp13_; 57 | D[1*3+2] = 0; 58 | D[2*3+0] = 0; 59 | D[2*3+1] = 0; 60 | D[2*3+2] = tmp15_; 61 | } /* */ 62 | } 63 | 64 | 65 | void ME::plane_stress(double E, double nu) 66 | { 67 | /* 68 | input E, nu; 69 | output D(3,3); 70 | 71 | D = E/(1-nu*nu) * 72 | [ 1, nu, 0; 73 | nu, 1, 0; 74 | 0, 0, (1-nu)/2 ]; 75 | */ 76 | /* */ { 77 | double tmp1_ = E; 78 | double tmp2_ = nu; 79 | double tmp4_ = tmp2_ * tmp2_; 80 | double tmp5_ = 1.0 - tmp4_; 81 | double tmp6_ = tmp1_ / tmp5_; 82 | double tmp8_ = 1.0 - tmp2_; 83 | double tmp10_ = tmp8_ / 2.0; 84 | double tmp11_ = tmp6_ * tmp2_; 85 | double tmp12_ = tmp6_ * tmp10_; 86 | D[0*3+0] = tmp6_; 87 | D[0*3+1] = tmp11_; 88 | D[0*3+2] = 0; 89 | D[1*3+0] = tmp11_; 90 | D[1*3+1] = tmp6_; 91 | D[1*3+2] = 0; 92 | D[2*3+0] = 0; 93 | D[2*3+1] = 0; 94 | D[2*3+2] = tmp12_; 95 | } /* */ 96 | } 97 | 98 | 99 | void ME::assign_ids(Mesh* mesh, int eltid) 100 | { 101 | for (int i = 0; i < 4; ++i) { 102 | int ni = mesh->ix(i,eltid); 103 | mesh->id(0,ni) = 1; 104 | mesh->id(1,ni) = 1; 105 | } 106 | } 107 | 108 | 109 | void ME::assemble_f(Mesh* mesh, int eltid) 110 | { 111 | Quad2d quad; 112 | Gauss4 xi(quad); 113 | get_quad(quad, mesh, eltid); 114 | 115 | vector K(4*4); 116 | for (xi.start(); !xi.done(); ++xi) { 117 | 118 | double eps[3] = {0, 0, 0}; 119 | for (int j = 0; j < 4; ++j) { 120 | const double* u = mesh->u(mesh->ix(j,eltid)); 121 | double Nj_x = xi.dN(j,0); 122 | double Nj_y = xi.dN(j,1); 123 | 124 | /* 125 | // Contribute strain at quadrature point 126 | 127 | input Nj_x, Nj_y, D(3,3); 128 | inout eps(3); 129 | input u(2); 130 | 131 | Bj = [Nj_x, 0; 132 | 0, Nj_y; 133 | Nj_y, Nj_x]; 134 | 135 | eps += Bj*u; 136 | */ 137 | /* */ { 138 | double tmp1_ = Nj_x; 139 | double tmp2_ = Nj_y; 140 | double tmp3_ = eps[0*3+0]; 141 | double tmp4_ = eps[0*3+1]; 142 | double tmp5_ = eps[0*3+2]; 143 | double tmp6_ = u[0*2+0]; 144 | double tmp7_ = u[0*2+1]; 145 | double tmp8_ = tmp1_ * tmp6_; 146 | double tmp9_ = tmp2_ * tmp7_; 147 | double tmp10_ = tmp2_ * tmp6_; 148 | double tmp11_ = tmp1_ * tmp7_; 149 | double tmp12_ = tmp10_ + tmp11_; 150 | double tmp13_ = tmp3_ + tmp8_; 151 | double tmp14_ = tmp4_ + tmp9_; 152 | double tmp15_ = tmp5_ + tmp12_; 153 | eps[0*3+0] = tmp13_; 154 | eps[0*3+1] = tmp14_; 155 | eps[0*3+2] = tmp15_; 156 | } /* */ 157 | } 158 | 159 | for (int i = 0; i < 4; ++i) { 160 | double* f = mesh->f(mesh->ix(i,eltid)); 161 | double Ni_x = xi.dN(i,0); 162 | double Ni_y = xi.dN(i,1); 163 | double w = xi.wt(); 164 | 165 | /* 166 | // Contribute B_i'*D*B(u) * w 167 | 168 | input Ni_x, Ni_y, D(3,3), w; 169 | input eps(3); 170 | inout f(2); 171 | 172 | Bi = [Ni_x, 0; 173 | 0, Ni_y; 174 | Ni_y, Ni_x]; 175 | 176 | f += Bi'*D*eps*w; 177 | */ 178 | /* */ { 179 | double tmp1_ = Ni_x; 180 | double tmp2_ = Ni_y; 181 | double tmp3_ = D[0*3+0]; 182 | double tmp4_ = D[0*3+1]; 183 | double tmp5_ = D[0*3+2]; 184 | double tmp6_ = D[1*3+0]; 185 | double tmp7_ = D[1*3+1]; 186 | double tmp8_ = D[1*3+2]; 187 | double tmp9_ = D[2*3+0]; 188 | double tmp10_ = D[2*3+1]; 189 | double tmp11_ = D[2*3+2]; 190 | double tmp12_ = w; 191 | double tmp13_ = eps[0*3+0]; 192 | double tmp14_ = eps[0*3+1]; 193 | double tmp15_ = eps[0*3+2]; 194 | double tmp16_ = f[0*2+0]; 195 | double tmp17_ = f[0*2+1]; 196 | double tmp18_ = tmp1_ * tmp3_; 197 | double tmp19_ = tmp2_ * tmp5_; 198 | double tmp20_ = tmp18_ + tmp19_; 199 | double tmp21_ = tmp2_ * tmp4_; 200 | double tmp22_ = tmp1_ * tmp5_; 201 | double tmp23_ = tmp21_ + tmp22_; 202 | double tmp24_ = tmp1_ * tmp6_; 203 | double tmp25_ = tmp2_ * tmp8_; 204 | double tmp26_ = tmp24_ + tmp25_; 205 | double tmp27_ = tmp2_ * tmp7_; 206 | double tmp28_ = tmp1_ * tmp8_; 207 | double tmp29_ = tmp27_ + tmp28_; 208 | double tmp30_ = tmp1_ * tmp9_; 209 | double tmp31_ = tmp2_ * tmp11_; 210 | double tmp32_ = tmp30_ + tmp31_; 211 | double tmp33_ = tmp2_ * tmp10_; 212 | double tmp34_ = tmp1_ * tmp11_; 213 | double tmp35_ = tmp33_ + tmp34_; 214 | double tmp36_ = tmp20_ * tmp13_; 215 | double tmp37_ = tmp26_ * tmp14_; 216 | double tmp38_ = tmp36_ + tmp37_; 217 | double tmp39_ = tmp32_ * tmp15_; 218 | double tmp40_ = tmp38_ + tmp39_; 219 | double tmp41_ = tmp23_ * tmp13_; 220 | double tmp42_ = tmp29_ * tmp14_; 221 | double tmp43_ = tmp41_ + tmp42_; 222 | double tmp44_ = tmp35_ * tmp15_; 223 | double tmp45_ = tmp43_ + tmp44_; 224 | double tmp46_ = tmp40_ * tmp12_; 225 | double tmp47_ = tmp45_ * tmp12_; 226 | double tmp48_ = tmp16_ + tmp46_; 227 | double tmp49_ = tmp17_ + tmp47_; 228 | f[0*2+0] = tmp48_; 229 | f[0*2+1] = tmp49_; 230 | } /* */ 231 | } 232 | 233 | } 234 | } 235 | 236 | 237 | void ME::assemble_K(Mesh* mesh, int eltid, 238 | MatrixAssembler* K_assembler) 239 | { 240 | Quad2d quad; 241 | Gauss4 xi(quad); 242 | get_quad(quad, mesh, eltid); 243 | 244 | vector K(8*8); 245 | for (xi.start(); !xi.done(); ++xi) { 246 | double w = xi.wt(); 247 | for (int j = 0; j < 4; ++j) { 248 | double Nj_x = xi.dN(j,0); 249 | double Nj_y = xi.dN(j,1); 250 | for (int i = 0; i < 4; ++i) { 251 | double Ni_x = xi.dN(i,0); 252 | double Ni_y = xi.dN(i,1); 253 | double* Knodal = &(K[16*j +2*i+ 0]); 254 | 255 | /* 256 | // B-matrix based displacement formulation 257 | // Isotropic plane strain constitutive tensor 258 | 259 | input D(3,3), w; 260 | input Ni_x, Ni_y, Nj_x, Nj_y; 261 | inout Knodal[8](2,2); 262 | 263 | Bi = [Ni_x, 0; 264 | 0, Ni_y; 265 | Ni_y, Ni_x]; 266 | 267 | Bj = [Nj_x, 0; 268 | 0, Nj_y; 269 | Nj_y, Nj_x]; 270 | 271 | Knodal += Bi'*D*Bj * w; 272 | */ 273 | /* */ { 274 | double tmp1_ = D[0*3+0]; 275 | double tmp2_ = D[0*3+1]; 276 | double tmp3_ = D[0*3+2]; 277 | double tmp4_ = D[1*3+0]; 278 | double tmp5_ = D[1*3+1]; 279 | double tmp6_ = D[1*3+2]; 280 | double tmp7_ = D[2*3+0]; 281 | double tmp8_ = D[2*3+1]; 282 | double tmp9_ = D[2*3+2]; 283 | double tmp10_ = w; 284 | double tmp11_ = Ni_x; 285 | double tmp12_ = Ni_y; 286 | double tmp13_ = Nj_x; 287 | double tmp14_ = Nj_y; 288 | double tmp15_ = Knodal[0*8+0]; 289 | double tmp16_ = Knodal[0*8+1]; 290 | double tmp17_ = Knodal[1*8+0]; 291 | double tmp18_ = Knodal[1*8+1]; 292 | double tmp19_ = tmp11_ * tmp1_; 293 | double tmp20_ = tmp12_ * tmp3_; 294 | double tmp21_ = tmp19_ + tmp20_; 295 | double tmp22_ = tmp12_ * tmp2_; 296 | double tmp23_ = tmp11_ * tmp3_; 297 | double tmp24_ = tmp22_ + tmp23_; 298 | double tmp25_ = tmp11_ * tmp4_; 299 | double tmp26_ = tmp12_ * tmp6_; 300 | double tmp27_ = tmp25_ + tmp26_; 301 | double tmp28_ = tmp12_ * tmp5_; 302 | double tmp29_ = tmp11_ * tmp6_; 303 | double tmp30_ = tmp28_ + tmp29_; 304 | double tmp31_ = tmp11_ * tmp7_; 305 | double tmp32_ = tmp12_ * tmp9_; 306 | double tmp33_ = tmp31_ + tmp32_; 307 | double tmp34_ = tmp12_ * tmp8_; 308 | double tmp35_ = tmp11_ * tmp9_; 309 | double tmp36_ = tmp34_ + tmp35_; 310 | double tmp37_ = tmp21_ * tmp13_; 311 | double tmp38_ = tmp33_ * tmp14_; 312 | double tmp39_ = tmp37_ + tmp38_; 313 | double tmp40_ = tmp24_ * tmp13_; 314 | double tmp41_ = tmp36_ * tmp14_; 315 | double tmp42_ = tmp40_ + tmp41_; 316 | double tmp43_ = tmp27_ * tmp14_; 317 | double tmp44_ = tmp33_ * tmp13_; 318 | double tmp45_ = tmp43_ + tmp44_; 319 | double tmp46_ = tmp30_ * tmp14_; 320 | double tmp47_ = tmp36_ * tmp13_; 321 | double tmp48_ = tmp46_ + tmp47_; 322 | double tmp49_ = tmp39_ * tmp10_; 323 | double tmp50_ = tmp42_ * tmp10_; 324 | double tmp51_ = tmp45_ * tmp10_; 325 | double tmp52_ = tmp48_ * tmp10_; 326 | double tmp53_ = tmp15_ + tmp49_; 327 | double tmp54_ = tmp16_ + tmp50_; 328 | double tmp55_ = tmp17_ + tmp51_; 329 | double tmp56_ = tmp18_ + tmp52_; 330 | Knodal[0*8+0] = tmp53_; 331 | Knodal[0*8+1] = tmp54_; 332 | Knodal[1*8+0] = tmp55_; 333 | Knodal[1*8+1] = tmp56_; 334 | } /* */ 335 | } 336 | } 337 | } 338 | 339 | K_assembler->add_entry(id, id, &(K[0]), 8, 8); 340 | } 341 | 342 | 343 | void ME::get_quad(FEShapes& quad, Mesh* mesh, int eltid) 344 | { 345 | for (int i = 0; i < 4; ++i) { 346 | int n = mesh->ix(i,eltid); 347 | quad.set_node(i, mesh->x(n)); 348 | id[2*i+0] = mesh->id(0,n); 349 | id[2*i+1] = mesh->id(1,n); 350 | } 351 | } 352 | -------------------------------------------------------------------------------- /testing/test_transfers.mw: -------------------------------------------------------------------------------- 1 | function test_transfers 2 | 3 | test_mult_inherit; 4 | test_scopes; 5 | test_literals; 6 | test_types; 7 | test_complex; 8 | test_nulls; 9 | test_method; 10 | test_returns; 11 | test_inputs; 12 | test_outputs; 13 | test_inouts; 14 | test_mx; 15 | test_const; 16 | test_struct; 17 | 18 | % ================================================================ 19 | $[ 20 | 21 | #include 22 | #include 23 | 24 | struct Pair { 25 | Pair(double x, double y) { xy[0] = x; xy[1] = y; } 26 | double xy[2]; 27 | double x() { return xy[0]; } 28 | double y() { return xy[1]; } 29 | }; 30 | 31 | struct BadPair { 32 | double x; 33 | }; 34 | 35 | struct DerivedPair : public Pair { 36 | DerivedPair() : Pair(7,11) {} 37 | }; 38 | 39 | #include 40 | typedef std::complex cmplx; 41 | #define real_cmplx(z) (z).real() 42 | #define imag_cmplx(z) (z).imag() 43 | #define setz_cmplx(zp, r, i) *zp = cmplx(r,i) 44 | 45 | typedef unsigned char uchar; 46 | typedef unsigned long ulong; 47 | 48 | $] 49 | % ================================================================ 50 | function test_mult_inherit 51 | $[ 52 | class Parent1 { 53 | public: 54 | Parent1(int data) : data1_(data) {} 55 | virtual ~Parent1() {} 56 | virtual int data1() { return data1_; } 57 | protected: 58 | int data1_; 59 | }; 60 | 61 | class Parent2 { 62 | public: 63 | Parent2(int data) : data2_(data) {} 64 | virtual ~Parent2() {} 65 | virtual int data2() { return data2_; } 66 | protected: 67 | int data2_; 68 | }; 69 | 70 | class Child : public Parent1, public Parent2 { 71 | public: 72 | Child() : Parent1(1), Parent2(2) {} 73 | virtual int data1() { return data1_ + 1; } 74 | virtual int data2() { return data2_ + 1; } 75 | int datas() { return data1_ + data2_; } 76 | }; 77 | 78 | $] 79 | 80 | # class Child : Parent1, Parent2; 81 | # Child* c = new Child(); 82 | # int d1 = c->Parent1.data1(); 83 | # int d2 = c->Parent2.data2(); 84 | # int dd = c->Child.datas(); 85 | 86 | tassert(d1 == 2, 'Multiple inheritance handling (1)'); 87 | tassert(d2 == 3, 'Multiple inheritance handling (2)'); 88 | tassert(dd == 3, 'Multiple inheritance handling (3)'); 89 | 90 | % ================================================================ 91 | function test_scopes; 92 | 93 | $ class OuterClass { 94 | $ public: 95 | $ static int static_method() { return 123; } 96 | $ }; 97 | # int x = OuterClass::static_method(); 98 | 99 | tassert(x == 123, 'Access to static class method'); 100 | 101 | % ================================================================ 102 | function test_literals; 103 | 104 | $ int literal_plus1(int x) { return x+1; } 105 | # int y = literal_plus1(int 7); 106 | # int l = strlen(cstring 'Test'); 107 | tassert(y == 8, 'Integer literals'); 108 | tassert(l == 4, 'String literals'); 109 | 110 | % ================================================================ 111 | function test_types; 112 | 113 | $ typedef unsigned char byte; 114 | $ void takes_double(double& x) {} 115 | $ void takes_float(float& x) {} 116 | $ void takes_long(long& x) {} 117 | $ void takes_int(int& x) {} 118 | $ void takes_char(char& x) {} 119 | $ void takes_ulong(unsigned long& x) {} 120 | $ void takes_uint(unsigned int& x) {} 121 | $ void takes_uchar(unsigned char& x) {} 122 | $ void takes_bool(bool& x) {} 123 | $ void takes_size_t(size_t& x) {} 124 | 125 | x = 0; xs = single(x); xc=char(42); 126 | # typedef numeric byte; 127 | # takes_double(double& x); 128 | # takes_float(float& xs); 129 | # takes_long(long& x); 130 | # takes_int(int& x); 131 | # takes_char(char& xc); 132 | # takes_ulong(ulong& x); 133 | # takes_uint(uint& x); 134 | # takes_uchar(uchar& x); 135 | # takes_uchar(byte& x); 136 | # takes_bool(bool& x); 137 | # takes_size_t(size_t& x); 138 | 139 | # class DerivedPair : Pair; 140 | # DerivedPair* dp = new DerivedPair(); 141 | # double x = dp->Pair.x(); 142 | tassert(x == 7, 'Type casting'); 143 | 144 | % ================================================================ 145 | function test_complex; 146 | 147 | $ cmplx zsum(cmplx* zarray, int n) { 148 | $ cmplx sum(0); 149 | $ for (int i = 0; i < n; ++i) sum += zarray[i]; 150 | $ return sum; 151 | $ } 152 | 153 | zarray = rand(10,1) + 1i*rand(10,1); 154 | n = length(zarray); 155 | # typedef dcomplex cmplx; 156 | # cmplx result = zsum(cmplx[] zarray, int n); 157 | tassert(abs(result-sum(zarray)) < 1e-10*norm(zarray), 'Complex support'); 158 | 159 | 160 | % ================================================================ 161 | function test_nulls; 162 | 163 | $ Pair* null_pair() { return NULL; } 164 | # Pair* p = null_pair(); 165 | tassert(p == 0, 'Null pointer return'); 166 | 167 | $ int is_null(Pair* p) { return !p; } 168 | # int flag = is_null(Pair* p); 169 | tassert(flag, 'Null pointer input'); 170 | 171 | $ char* null_string() { return NULL; } 172 | # cstring s = null_string(); 173 | tassert(s == 0, 'Null string return'); 174 | 175 | # char* c = null_string(); 176 | tassert(isempty(c), 'Null scalar pointer return'); 177 | 178 | nil = []; 179 | $ int is_null(double* data) { return !data; } 180 | # int flag = is_null(double[] nil); 181 | tassert(flag, 'Null array input'); 182 | 183 | # char[1] ca = null_string(); 184 | tassert(isempty(ca), 'Null array return'); 185 | 186 | $ void test_null_obj(Pair& p) { } 187 | try 188 | # test_null_obj(Pair p); 189 | tassert(0, 'Null argument dereference 1'); 190 | end 191 | try 192 | # test_null_obj(Pair& p); 193 | tassert(0, 'Null argument dereference 1'); 194 | end 195 | 196 | try 197 | # double x = p->Pair.x(); 198 | tassert(0, 'Invalid this test'); 199 | end 200 | 201 | # BadPair* bp = new BadPair(); 202 | try 203 | $ void test_bad_pair(Pair* p) { } 204 | # test_bad_pair(Pair* bp); 205 | tassert(0, 'Invalid pointer test'); 206 | end 207 | # delete(BadPair* bp); 208 | 209 | 210 | % ================================================================ 211 | function test_method; 212 | 213 | x = 1; 214 | y = 2; 215 | # Pair* p = new Pair(double x, double y); 216 | # double xx = p->Pair.x(); 217 | # double yy = p->Pair.y(); 218 | # delete(Pair* p); 219 | tassert(xx == 1, 'Method call'); 220 | tassert(yy == 2, 'Method call'); 221 | 222 | 223 | % ================================================================ 224 | function test_returns; 225 | 226 | $ Pair test_return_obj() { return Pair(1.5, 2.5); } 227 | # Pair p1 = test_return_obj(); 228 | tassert(sscanf(p1, 'Pair:%x') > 0, 'Return object'); 229 | 230 | $ double* test_return_array(Pair& p) { return p.xy; } 231 | # double[2] xy = test_return_array(Pair& p1); 232 | tassert(norm(xy-[1.5; 2.5]) == 0, 'Return array'); 233 | 234 | $ double* test_return_array2(Pair& p) { return p.xy; } 235 | # double xy[2] = test_return_array2(Pair& p1); 236 | tassert(norm(xy-[1.5; 2.5]) == 0, 'Return array'); 237 | 238 | $ double test_return_scalar(double* xy) { return xy[0] + xy[1]; } 239 | # double sum = test_return_scalar(double[] xy); 240 | tassert(sum == 4, 'Return scalar'); 241 | 242 | xy_z = [1+5i, 7+11i]; 243 | $ cmplx test_return_zscalar(cmplx* xy) { return xy[0] + xy[1]; } 244 | # cmplx sum1 = test_return_zscalar(cmplx[] xy); 245 | # cmplx sum2 = test_return_zscalar(cmplx[] xy_z); 246 | tassert(sum1 == 4, 'Return zscalar (reals)'); 247 | tassert(sum2 == 8+16i, 'Return zscalar (complexes)'); 248 | 249 | $ const char* test_return_string() { return "Hello, world!"; } 250 | # cstring s = test_return_string(); 251 | tassert(strcmp(s, 'Hello, world!'), 'Return string'); 252 | 253 | $ Pair* test_return_p_obj() { return new Pair(3, 5); } 254 | # Pair* p2 = test_return_p_obj(); 255 | # double[2] xy = test_return_array(Pair& p2); 256 | tassert(norm(xy - [3;5]) == 0, 'Return obj*'); 257 | 258 | a = 7; b = 11; 259 | $ int* test_return_p_scalar(int* a, int* b) { return (*a > *b) ? a : b; } 260 | # int* z1 = test_return_p_scalar(int* a, int* b); 261 | tassert(z1 == 11, 'Return scalar*'); 262 | 263 | a_z = 7 + 10i; b_z = 11 + 15i; 264 | $ cmplx* test_return_p_zscalar(cmplx* a, cmplx* b) { 265 | $ return (a->real() > b->real()) ? a : b; 266 | $ } 267 | # cmplx* z1 = test_return_p_zscalar(cmplx* a, cmplx* b); 268 | # cmplx* z2 = test_return_p_zscalar(cmplx* a_z, cmplx* b_z); 269 | tassert(z1 == 11, 'Return zscalar*'); 270 | tassert(z2 == 11 + 15i, 'Return zscalar*'); 271 | 272 | $ Pair& test_return_r_obj(Pair& p) { return p; } 273 | # Pair& p2c = test_return_r_obj(Pair& p2); 274 | tassert(strcmp(p2, p2c), 'Return obj&'); 275 | 276 | $ int& test_return_r_scalar(int& a, int& b) { return (a > b) ? a : b; } 277 | # int& z2 = test_return_r_scalar(int& a, int& b); 278 | tassert(z2 == 11, 'Return scalar&'); 279 | 280 | $ cmplx& test_return_r_zscalar(cmplx& a, cmplx& b) { 281 | $ return (a.real() > b.real()) ? a : b; 282 | $ } 283 | # cmplx& z2 = test_return_r_zscalar(cmplx& a, cmplx& b); 284 | # cmplx& z3 = test_return_r_zscalar(cmplx& a_z, cmplx& b_z); 285 | tassert(z2 == 11, 'Return zscalar&'); 286 | tassert(z3 == 11 + 15i, 'Return zscalar&'); 287 | 288 | # delete(Pair* p1); 289 | # delete(Pair* p2); 290 | 291 | 292 | % ================================================================ 293 | function test_inputs 294 | 295 | x = 101; y = 202; 296 | # Pair* p = new Pair(double x, double y); 297 | $ double test_input_obj(Pair p) { return p.xy[0] + p.xy[1]; } 298 | # double sum = test_input_obj(input Pair p); 299 | tassert(sum == 303, 'Input obj'); 300 | 301 | xy = [11, 22]; 302 | $ double test_input_array(double* xy) { return xy[0] + xy[1]; } 303 | # double sum = test_input_array(double[2] xy); 304 | tassert(sum == 33, 'Input array'); 305 | 306 | $ double test_input_array2(double* xy) { return xy[0] + xy[1]; } 307 | # double sum = test_input_array2(double xy[2]); 308 | tassert(sum == 33, 'Input array'); 309 | 310 | xy_z = [11 + 5i, 22 + 6i]; 311 | $ cmplx test_input_zarray(cmplx* xy) { return xy[0] + xy[1]; } 312 | # cmplx sum = test_input_zarray(cmplx[2] xy); 313 | # cmplx sum2 = test_input_zarray(cmplx[2] xy_z); 314 | tassert(sum == 33, 'Input zarray'); 315 | tassert(sum2 == 33 + 11i, 'Input zarray'); 316 | 317 | $ int test_input_scalar(int x) { return x+1; } 318 | # int xp1 = test_input_scalar(int x); 319 | tassert(xp1 == 102, 'Input scalar'); 320 | 321 | x_z = 101 + 99i; 322 | $ cmplx test_input_zscalar(cmplx x) { return x+1.0; } 323 | # cmplx xp1 = test_input_zscalar(cmplx x); 324 | # cmplx xp1z = test_input_zscalar(cmplx x_z); 325 | tassert(xp1 == 102, 'Input zscalar'); 326 | tassert(xp1z == 102 + 99i, 'Input zscalar'); 327 | 328 | msg = 'Hello, world!'; 329 | $ int test_input_string(char* s) { return strlen(s); } 330 | # int msglen = test_input_string(cstring msg); 331 | tassert(msglen == length(msg), 'Input string'); 332 | 333 | $ double test_input_p_obj(Pair* p) { return p->xy[0] + p->xy[1]; } 334 | # double sum2 = test_input_p_obj(Pair* p); 335 | tassert(sum2 == 303, 'Input obj*'); 336 | 337 | $ int test_input_p_scalar(int* x) { return *x+1; } 338 | # int xp1b = test_input_p_scalar(int* x); 339 | tassert(xp1b == 102, 'Input scalar*'); 340 | 341 | $ cmplx test_input_p_zscalar(cmplx* x) { return *x+1.0; } 342 | # cmplx xp1b = test_input_p_zscalar(cmplx* x); 343 | # cmplx xp1c = test_input_p_zscalar(cmplx* x_z); 344 | tassert(xp1b == 102, 'Input zscalar*'); 345 | tassert(xp1c == 102 + 99i, 'Input zscalar*'); 346 | 347 | $ double test_input_r_obj(Pair& p) { return p.xy[0] + p.xy[1]; } 348 | # double sum3 = test_input_r_obj(Pair& p); 349 | tassert(sum3 == 303, 'Input obj&'); 350 | 351 | $ int test_input_r_scalar(int& x) { return x+1; } 352 | # int xp1c = test_input_r_scalar(input int& x); 353 | tassert(xp1c == 102, 'Input scalar&'); 354 | 355 | $ cmplx test_input_r_zscalar(cmplx& x) { return x+1.0; } 356 | # cmplx xp1c = test_input_r_zscalar(input cmplx& x); 357 | # cmplx xp1d = test_input_r_zscalar(input cmplx& x_z); 358 | tassert(xp1c == 102, 'Input scalar&'); 359 | tassert(xp1d == 102 + 99i, 'Input scalar&'); 360 | 361 | # delete(input Pair* p); 362 | 363 | 364 | % ================================================================ 365 | function test_outputs 366 | 367 | $ void test_output_array(double* xy) { xy[0] = 1; xy[1] = 2; } 368 | # test_output_array(output double[2] xy); 369 | tassert(norm(xy-[1;2]) == 0, 'Output array'); 370 | 371 | $ void test_output_rarray(const double*& xy) { 372 | $ static double result[2] = {7, 11}; 373 | $ xy = result; 374 | $ } 375 | # test_output_rarray(output double[2]& xyr); 376 | tassert(norm(xyr-[7;11]) == 0, 'Output rarray'); 377 | 378 | $ void test_output_rarray2(const double*& xy) { xy = NULL; } 379 | # test_output_rarray2(output double[2]& xyr2); 380 | tassert(isempty(xyr2), 'Output rarray'); 381 | 382 | $ void test_output_zarray(cmplx* xy) { xy[0] = 1; xy[1] = 2; } 383 | $ void test_output_zarray2(cmplx* xy) { xy[0] = cmplx(1,3); xy[1] = 2; } 384 | # test_output_zarray(output cmplx[2] xy); 385 | # test_output_zarray2(output cmplx[2] xy_z); 386 | tassert(norm(xy-[1;2]) == 0, 'Output array'); 387 | tassert(norm(xy_z-[1+3i;2]) == 0, 'Output array'); 388 | 389 | fmt = '= %d'; i = 101; 390 | # sprintf(output cstring[128] buf, input cstring fmt, input int i); 391 | tassert(strcmp('= 101', buf), 'Output string'); 392 | 393 | $ void test_output_p_scalar(int* i) { *i = 202; } 394 | # test_output_p_scalar(output int* i2); 395 | tassert(i2 == 202, 'Output scalar*'); 396 | 397 | $ void test_output_p_zscalar(cmplx* z) { *z = cmplx(202,303); } 398 | # test_output_p_zscalar(output cmplx* z2); 399 | tassert(z2 == 202+303i, 'Output zscalar*'); 400 | 401 | $ void test_output_r_scalar(int& i) { i = 303; } 402 | # test_output_r_scalar(output int& i3); 403 | tassert(i3 == 303, 'Output scalar&'); 404 | 405 | $ void test_output_r_zscalar(cmplx& z) { z = cmplx(303,404); } 406 | # test_output_r_zscalar(output cmplx& z3); 407 | tassert(z3 == 303+404i, 'Output zscalar&'); 408 | 409 | 410 | % ================================================================ 411 | function test_inouts 412 | 413 | xy = [1, 2]; 414 | $ void test_inout_array(double* xy) { xy[0] += 1; xy[1] += 1; } 415 | # test_inout_array(inout double[] xy); 416 | tassert(norm(xy - [2,3]) == 0, 'Inout array'); 417 | 418 | s1 = 'foo'; 419 | s2 = 'bar'; 420 | # strcat(inout cstring[128] s1, input cstring s2); 421 | tassert(strcmp(s1, 'foobar'), 'Inout string'); 422 | 423 | i1 = 101; 424 | $ void test_inout_p_scalar(int* i) { *i += 202; } 425 | # test_inout_p_scalar(inout int* i1); 426 | tassert(i1 == 303, 'Inout scalar*'); 427 | 428 | i2 = 101; 429 | $ void test_inout_r_scalar(int& i) { i += 303; } 430 | # test_inout_r_scalar(inout int& i2); 431 | tassert(i2 == 404, 'Inout scalar&'); 432 | 433 | 434 | % ================================================================ 435 | function test_mx 436 | 437 | $ #include 438 | 439 | in1 = 42; 440 | $ double test_mx_input(const mxArray* x) { return *mxGetPr(x); } 441 | # double out1 = test_mx_input(input mxArray in1); 442 | tassert(out1 == 42, 'Input mx'); 443 | 444 | $ void test_mx_output(mxArray** x) 445 | $ { 446 | $ *x = mxCreateString("foobar"); 447 | $ } 448 | # test_mx_output(output mxArray out2); 449 | tassert(strcmp(out2, 'foobar'), 'Output mx'); 450 | 451 | $ mxArray* test_mx_return() 452 | $ { 453 | $ mxArray* m = mxCreateDoubleMatrix(1,1, mxREAL); 454 | $ *mxGetPr(m) = 42; 455 | $ return m; 456 | $ } 457 | # mxArray out3 = test_mx_return(); 458 | tassert(out3 == 42, 'Return mx'); 459 | 460 | 461 | % ================================================================ 462 | function test_const 463 | 464 | $ const int TEST_CONST = 42; 465 | $ int identity(int i) { return i; } 466 | # int result = identity(const TEST_CONST); 467 | tassert(result == 42, 'Constant transfer'); 468 | # int result2 = identity(const 'TEST_CONST'); 469 | tassert(result2 == 42, 'Constant transfer'); 470 | 471 | % ================================================================ 472 | function test_struct 473 | 474 | $[ 475 | 476 | struct my_struct_t { 477 | double x; 478 | double y; 479 | }; 480 | 481 | int my_struct_allocs = 0; 482 | 483 | int get_my_struct_allocs() 484 | { 485 | return my_struct_allocs; 486 | } 487 | 488 | my_struct_t* mxWrapGet_my_struct_t(const mxArray* a, const char** e) 489 | { 490 | // Note -- there really ought to be an error check here 491 | ++my_struct_allocs; 492 | my_struct_t* o = new my_struct_t; 493 | o->x = mxGetPr(a)[0]; 494 | o->y = mxGetPr(a)[1]; 495 | return o; 496 | } 497 | 498 | mxArray* mxWrapSet_my_struct_t(my_struct_t* o) 499 | { 500 | mxArray* a = mxCreateDoubleMatrix(2,1,mxREAL); 501 | mxGetPr(a)[0] = o->x; 502 | mxGetPr(a)[1] = o->y; 503 | return a; 504 | } 505 | 506 | my_struct_t* mxWrapAlloc_my_struct_t() 507 | { 508 | ++my_struct_allocs; 509 | return new my_struct_t; 510 | } 511 | 512 | void mxWrapFree_my_struct_t(my_struct_t* o) 513 | { 514 | --my_struct_allocs; 515 | delete o; 516 | } 517 | 518 | void unpack_struct(my_struct_t& o, double* xy) 519 | { 520 | xy[0] = o.x; 521 | xy[1] = o.y; 522 | } 523 | 524 | void pack_struct(my_struct_t& o, double* xy) 525 | { 526 | o.x = xy[0]; 527 | o.y = xy[1]; 528 | } 529 | 530 | void swap_struct(my_struct_t& o) 531 | { 532 | double tmp = o.x; 533 | o.x = o.y; 534 | o.y = tmp; 535 | } 536 | 537 | my_struct_t& rightmost(my_struct_t& p1, my_struct_t& p2) 538 | { 539 | return (p1.x >= p2.x) ? p1 : p2; 540 | } 541 | 542 | my_struct_t* add1(my_struct_t& o) 543 | { 544 | o.x += 1; 545 | o.y += 1; 546 | return &o; 547 | } 548 | 549 | $] 550 | 551 | # typedef mxArray my_struct_t; 552 | 553 | xy1 = [1, 2]; 554 | # unpack_struct(my_struct_t& xy1, output double xy2[2]); 555 | tassert(norm(xy2-[1;2]) == 0, 'Structure conversion on input'); 556 | 557 | # pack_struct(output my_struct_t xy3, double[] xy1); 558 | tassert(norm(xy3-[1;2]) == 0, 'Structure conversion on output'); 559 | 560 | xy4 = [3; 4]; 561 | # swap_struct(inout my_struct_t xy4); 562 | tassert(norm(xy4-[4; 3]) == 0, 'Structure on inout'); 563 | 564 | # my_struct_t& result = rightmost(my_struct_t& xy1, my_struct_t& xy4); 565 | tassert(norm(result-[4;3]) == 0, 'Structure on reference return'); 566 | 567 | # my_struct_t* xy5 = add1(my_struct_t& xy4); 568 | tassert(norm(xy5-[5;4]) == 0, 'Structure on pointer return'); 569 | 570 | # int alloc_count = get_my_struct_allocs(); 571 | tassert(alloc_count == 0, 'Balanced allocations in structure management'); 572 | 573 | % ================================================================ 574 | function tassert(pred, msg) 575 | 576 | if ~pred, fprintf('Failure: %s\n', msg); end 577 | 578 | --------------------------------------------------------------------------------