I have managed to get an Excel UDF working with a dll compiled from the c++ version of rnatrixinverse, but I suspect the code is rather clumsy. I'd be greatful for any comments on how it might be made more elegant.
Here is the VBA code:
Code:
Declare Function vbrmatinv Lib "d:\Users\Doug\Documents\Visual Studio 2010\Projects\Alglib2\Release\Alglib2.dll" _
(ByRef A2 As Double, ByVal M As Long) As Long
Function RMatInvdll(a As Variant) As Variant
Dim N As Long, M As Long, N2 As Long, Pivots() As Long
Dim A2() As Double, i As Long, J As Long, K As Long, Rtn As Long
If TypeName(a) = "Range" Then a = a.Value2
M = UBound(a)
N = UBound(a, 2)
' Copy 2D base 1 variant array to 1D base 0 double array
ReDim A2(0 To M * N - 1)
For i = 1 To M
For J = 1 To N
A2((i - 1) * M + J - 1) = a(i, J)
Next J
Next i
Rtn = vbrmatinv(A2(0), M)
' Copy 1D base 0 array to 2D base 1 array
For i = 1 To M
For J = 1 To N
a(i, J) = A2((i - 1) * M + J - 1)
Next J
Next i
' Assign array to function return value
RMatInvdll = a
End Function
And the c++
Code:
// vbmat.cpp -- Interface for VBA matrix functions.
#include "vbmat.h"
int vbrmatinv(double* av, int n)
{
int i,j,info;
matinvreport rep;
ap::real_2d_array a2;
a2.setcontent(0, n-1, 0, n-1, av);
rmatrixinverse(a2, n, info, rep);
for( i = 0; i < n; i++){
for (j=0;j<n;j++) {
av[i*n+j] = a2(i,j);
}
}
return 0 ;
}
At the VBA end the variant arrays need to be converted to a base 0 double array anyway, and the only way to do that is by looping through each element, so there is probably not much that can be done there.
I had a lot of trouble getting setcontent() to work, but I don't know why. What I ended up with is what I thought I was doing in the first place (but obviously something must be different, because now it is working :)).
For returning the array back to VBA, is it necessary to convert it to a 1D array, and if so is there a better way to do it?