SrdTLT
SrdTLT

Reputation: 123

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.

Upvotes: 1

Views: 1612

Answers (1)

David Heffernan
David Heffernan

Reputation: 613461

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.

Upvotes: 3

Related Questions