Fortran MEX using Cell arrays - crashing Matlab..
    6 Ansichten (letzte 30 Tage)
  
       Ältere Kommentare anzeigen
    
Hi, I am trying to learn how to use cell arrays in Mex functions. I've written a simple test function below, which should take a cell array of doubles, then simply square each element. So from Matlab if...
A = {[1 2 3] ; [1 2 3]}
.. then B = mexGateway(A)
should give B = {[1 4 9];[1 4 9]}.
But, it just crashes Matlab. From the debugger, the crash happens when it tries to call compute. What have I missed here, and how should this be changed to make it work? Cheers, Arwel
#include "fintrf.h"
C-------------------------------------------------------------------------------
C     Test program that inputs cell array of double arrays, squares each element
C     then outputs the results in a new cell array
C--------------------------------------------------------------------------------
        subroutine mexFunction(nlhs, plhs, nrhs, prhs)
C     Declarations
      implicit none
C     Mex function arguments      
      mwPointer plhs(*), prhs(*), dat
      integer nlhs, nrhs 
C     Function Declarations      
      mwPointer mxCreateCellMatrix
      mwPointer mxGetCell
      mwPointer mxSetCell
      mwPointer mxGetData
      mwPointer mxGetPr
      mwPointer mxGetNumberOfElements
      mwSize i, m
C     Pointers Arrays and vars
      mwPointer numberOfCells
      mwPointer outputArray
      mwPointer inputArray
      mwPointer thisCell
      mwPointer calcOutpArray
      mwPointer size
C     input checking to be added..      
C     Get the size of the input array..
      inputArray = prhs(1)
      numberOfCells = mxGetNumberOfElements(inputArray)
C     Output cell array will have the same dimensions
      outputArray = mxCreateCellMatrix(numberOfCells,1)
c     Loop over all the elements in the input array and call comp...     
        do 10 i=1,numberOfCells
            thisCell = mxGetCell(inputArray,i)
            size = mxGetNumberOfElements(thisCell)
            call compute(%VAL(calcOutpArray),%VAL(thisCell),%VAL(size)) 
            call mxSetCell(outputArray,i,calcOutpArray)
  10    continue
        plhs(1) = outputArray
        return
        end 
C   -----------------------------------------------------------
      subroutine compute(outArray,inArray,l)
        real*8 outArray(l,1), inArray(l,1)
        real*8 n
        do 20 n=1,l
          outArray(n,1) = inArray(n,1)*inArray(n,1)
  20    continue
        return
        end
0 Kommentare
Antworten (4)
  dpb
      
      
 am 20 Jul. 2016
        Subroutine compute is Fortran, don't need (and can't use) %VAL on the arguments; they'll be handled just like any other Fortran argument.
call compute(calcOutpArray,thisCell,size)
0 Kommentare
  James Tursa
      
      
 am 20 Jul. 2016
        
      Bearbeitet: James Tursa
      
      
 am 21 Jul. 2016
  
      You are not creating any output cells, so you are writing to garbage address locations which will eventually result in a MATLAB crash. I.e., in this line
            call compute(%VAL(calcOutpArray),%VAL(thisCell),%VAL(size))
calcOutpArray hasn't been set to anything prior to this call. Plus you aren't even passing the correct thing anyway as dpb has pointed out. This section of code should look something like this:
        mwSize m, n
        integer*4 :: ComplexFlag = 0
        mwPointer pr_out, pr_in
           :
      m = numberOfCells
      n = 1
      outputArray = mxCreateCellMatrix(m,n)  ! <-- Always pass variables for sizes, not literal constants
           :
        do i=1,numberOfCells
            thisCell = mxGetCell(inputArray,i)    ! <-- This is an (mxArray *)
            m = mxGetNumberOfElements(thisCell)
            n = 1
            calcOutpArray = mxCreateDoubleMatrix(m,n,ComplexFlag)  ! <-- This is an (mxArray *)
            pr_in = mxGetPr(thisCell)             ! <-- This is a (double *)
            pr_out = mxGetPr(calcOutpArray)       ! <-- This is a (double *)
            call compute(%VAL(pr_out),%VAL(pr_in),m)   ! <-- Pass value of (double *) to compute
            call mxSetCell(outputArray,i,calcOutpArray)
        enddo
            :
            :
      subroutine compute(outArray,inArray,l)
        mwSize l
        real*8 outArray(l,1), inArray(l,1)
        mwSize n
The %VAL( ) constructs work in the above code because the subroutine compute has an implicit interface. If it had an explicit interface you would need to do something else.
And, Fortran is an array based language, like MATLAB. So these lines of code:
        do 20 n=1,l
          outArray(n,1) = inArray(n,1)*inArray(n,1)
  20    continue
Can be reduced to this one statement, since * is element-wise multiply in Fortran:
          outArray = inArray*inArray
CAUTION: This all assumes that the input argument is EXACTLY as expected. If not, you will probably get a crash. E.g., if one of the cell elements of the input variable is not set, it will physically contain a NULL address (0 in Fortran). So for that iteration you would have thisCell = 0, and subsequent lines that use thisCell will probably crash MATLAB. To make your code robust against this, you need to check that thisCell is not 0, and if you pass that then check to see that it is double class and not sparse etc etc. So you need to put in lots of checks like this to make sure your code doesn't crash MATLAB for unexpected inputs.
0 Kommentare
  Arwel
 am 20 Jul. 2016
        
      Bearbeitet: Arwel
 am 20 Jul. 2016
  
      1 Kommentar
  James Tursa
      
      
 am 20 Jul. 2016
				You already have that correct:
        plhs(1) = outputArray
Siehe auch
Kategorien
				Mehr zu Write C Functions Callable from MATLAB (MEX Files) finden Sie in Help Center und File Exchange
			
	Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!


