Search code examples
matlabdelphidelphi-7dynamic-arrays

How to MOVE or COPY multidimensional dynamic arrays to matlab`s arrays


If I use non-dynamic arrays, all works

    pmxArray = mxArray^;
    perA_ptr: pmxArray;
    perA: array[1..3,1..4] of double;

    perA_ptr := mxCreateDoubleMatrix(4,3,mxREAL);
    Move(perA, mxGetPr(perA_ptr)^, 4*3*sizeof(double));
    ......
    _mlflinprog1(1,perX_ptr,perF_ptr,perA_ptr,perB_ptr,perLB_ptr);

it's WORKS.

but i need to use dynamic arrays. And i have a problem

perA: array of array of Double;
SetLength(perA,4,3);
perA_ptr := mxCreateDoubleMatrix(4,3,mxREAL);
Move(perA, mxGetPr(perA_ptr)^, 12*sizeof(double));

doesnt work, only trash in array;

Move(perA[0,0], mxGetPr(perA_ptr)^, 4*sizeof(double)); - WORKS for first row, but i need to copy all array's data, IDK how to do that in delphi.

That's arrays I need for matlab c shared library.


Solution

  • Your static array is stored in one contiguous block. A two dimensional dynamic array is ragged. In C terms you have double**. Although a Delphi array has extra book keeping, that's how you need to think of it.

    So when you do

    SetLength(perA, 4, 3);
    

    you have an array perA of length 4, each of whose elements is another array. Each inner array is of length 3. The 3 elements of each inner array are stored contiguously, but these arrays are not contiguous. Therefore you'll need to copy the rows one at a time.

    Exactly how you implement this depends on whether your Delphi matrix is stored row-major or col-major. If the former then it's simplest to populate a matrix and then transpose it. The code for both variants might look like this:

    type
      TDoubleMatrix = array of array of Double;
    
    function CreateDoubleMatrixColMajor(nRow, nCol: Integer): TDoubleMatrix;
    begin
      SetLength(Result, nCol, nRow);
    end;
    
    function CreatemxArrayFromColMajor(const M: TDoubleMatrix): PmxArray;
    var
      col: Integer;
      nRow, nCol: Integer;
      values: PDouble;
    begin
      nCol := Length(M);
      Assert(nCol > 0);
      nRow := Length(M[0]);
      Assert(nRow > 0);
    
      result := mxCreateDoubleMatrix(nRow, nCol, mxREAL);
      values := mxGetData(result);
      for col := 0 to nCol - 1 do
      begin
        Assert(Length(M[col]) = nRow);
        Move(M[col], values^, nRow * SizeOf(Double));
        inc(values, nRow);
      end;
    end;
    
    function CreateDoubleMatrixRowMajor(nRow, nCol: Integer): TDoubleMatrix;
    begin
      SetLength(Result, nRow, nCol);
    end;
    
    function CreatemxArrayFromRowMajor(const M: TDoubleMatrix): PmxArray;
    var
      row: Integer;
      nRow, nCol: Integer;
      tmp: PmxArray;
      values: PDouble;
    begin
      nRow := Length(M);
      Assert(nRow > 0);
      nCol := Length(M[0]);
      Assert(nCol > 0);
    
      tmp := mxCreateDoubleMatrix(nCol, nRow, mxREAL);
      values := mxGetData(tmp);
      for row := 0 to nRow - 1 do
      begin
        Assert(Length(M[row]) = nCol);
        Move(M[row], values^, nCol * SizeOf(Double));
        inc(values, nCol);
      end;
      mexCallMATLAB(1, @result, 1, @tmp, 'transpose');
      mxDestroyArray(tmp);
    end;
    

    I've not even compiled any of this code. All my Matlab programming is done in C. But I think that the above should have the ideas that you need.