I have an 3×3 matrix “mat” and a vector “vec” (3×1) of real numbers I want to matrix multiply (in the linear algebra sense) in a VBA function like so: t(vec)matvec to produce a 1×1 real number I can use in an equation.
I do not want to interact with a worksheet in the function. The values in the matrix and vector are eiter hard-coded or calculated from within the function. There should be a simple way to transpose then do a couple matrix multiplications like in MATLAB or R. Here is where I am so far:
Public Function QuickMaths() Dim vec As Variant Dim mat As Variant mat = Array(Array(1,1+1,3), _ Array(2^2,5,6), _ Array(7,8,9)) vec = Array(2*5,11,12) QuickMaths = Application.WorksheetFunction.MMult(Application.WorksheetFunction.MMult(Application.WorksheetFunction.Transpose(vec), mat), vec) End Function
I get #VALUE from this in a worksheet when I run it. I would expect the output to be a 1×1 matrix, but I don’t know if Excel VBA would consider that a scalar that can be output into a sheet as a single value (e.g. Double).
Please send help.
It would have been good if you had provided expected output (the specific scalar you’re expecting at the end).
Based on what I gather from your code and question, I’m going to assume you’re trying to perform two steps. The first being:
The second being:
(It’s been a while since I’ve done any matrix multiplication, so if you think I’ve misunderstood, let me know.)
Your first array (
mat) is an array of arrays (not a two dimensional array), which I don’t think
MMULT handles (https://support.office.com/en-us/article/mmult-function-40593ed7-a3cd-4b6b-b9a3-e4ad3c7245eb). So you might need to replace:
mat = Array(Array(1, 1 + 1, 3), _ Array(2 ^ 2, 5, 6), _ Array(7, 8, 9))
ReDim mat(0 To 2, 0 To 2) mat(0, 0) = 1 mat(0, 1) = 2 mat(0, 2) = 3 mat(1, 0) = 4 mat(1, 1) = 5 mat(1, 2) = 6 mat(2, 0) = 7 mat(2, 1) = 8 mat(2, 2) = 9
That said, manually assigning each array element can be impractical, so maybe make a small function to do it for you (see
FlattenAnArrayOfArrays function in code below).
From what I’ve read online in the last 30 minutes, matrix multiplication is not commutative and also requires that the number of columns in your first matrix match the number of rows in the second matrix. (You may already know all of this, but just mentioning it anyway.)
Based on the above, your code might look something like:
Option Explicit Public Function QuickMaths() As Variant ' This function returns a value of type Variant. ' Could return a Long/Double/numeric type; scalar should be at QuickMaths(1,1) ' But MMULT can return non-numeric values, so you risk ' getting a type mismatch error if the matrix multiplication ' is not successful (for whatever reason). ' Maybe this shouldn't be this function's concern -- or maybe it should. Dim mat As Variant mat = Array(Array(1, 1 + 1, 3), _ Array(2 ^ 2, 5, 6), _ Array(7, 8, 9)) mat = FlattenAnArrayOfArrays(mat) Dim vec As Variant vec = Array(2 * 5, 11, 12) Dim resultantMatrix As Variant resultantMatrix = Application.MMult(vec, mat) ' Number of columns in "vec" must match number of rows in "mat" resultantMatrix = Application.MMult(vec, Application.Transpose(resultantMatrix)) QuickMaths = resultantMatrix End Function Private Function FlattenAnArrayOfArrays(ByRef arrayOfArrays As Variant) As Variant() ' Given an array of arrays, returns a two-dimensional array. ' This function is very basic and has no error handling implemented. Dim firstArray() As Variant firstArray = arrayOfArrays(LBound(arrayOfArrays)) ' Columns inferred from first array in "arrayOfArrays" Dim outputArray() As Variant ReDim outputArray(LBound(arrayOfArrays) To UBound(arrayOfArrays), LBound(firstArray) To UBound(firstArray)) Dim rowIndex As Long For rowIndex = LBound(outputArray, 1) To UBound(outputArray, 1) Dim columnIndex As Long For columnIndex = LBound(outputArray, 2) To UBound(outputArray, 2) outputArray(rowIndex, columnIndex) = arrayOfArrays(rowIndex)(columnIndex) Next columnIndex Next rowIndex FlattenAnArrayOfArrays = outputArray End Function
- The return value of the
QuickMathsfunction is a 1×1 matrix, but you can assign it to a cell’s value.
- Similarly, if you call the
QuickMathsfunction from a worksheet cell, the cell will display the return value (without any issues or need for an array formula).