The function works as an "asset class allocation" engine (with constraints in the Param range) and simulates a portfolio model on each row of the array. I attempt to publish the array onto the worksheet with four methods, each of them fails.
Those Params are configured in M3:O6 as {Min 5, Max 100, Step 5} for each asset weight in assets A,B,C,D.
The function fails to paste the 2D array into Excel. There are 970 permutations, so array is 970x5. Is this a size issue? Code works fine up to PrintArray AllocArray, ActiveWorkbook.Worksheets("Test").[A1]
Sub PrintArray(Data As Variant, Cl As Range)
Cl.Resize(UBound(Data, 1), UBound(Data, 2)) = Data
End Sub
Function ConfigureArrayFolly()
Dim Param() As Variant
Param = Range("M3:O6")
Dim AMin, AMax, AStep, BMin, BMax, BStep, CMin, CMax, CStep, DMin, DMax, DStep As Double
AMin = Param(1, 1): AMax = Param(1, 2): AStep = Param(1, 3)
BMin = Param(2, 1): BMax = Param(2, 2): BStep = Param(2, 3)
CMin = Param(3, 1): CMax = Param(3, 2): CStep = Param(3, 3)
DMin = Param(4, 1): DMax = Param(4, 2): DStep = Param(4, 3)
Dim nSim As Double: nSim = (1 + (AMax - AMin) / AStep) * (1 + (BMax - BMin) / BStep) * (1 + (CMax - CMin) / CStep) * (1 + (DMax - DMin) / DStep)
Dim nAsset As Double: nAsset = 4 ' Count {A, B, ... , F}
'Debug.Print nSim
Dim AllocArray() As Variant
ReDim AllocArray(1 To 970, 0 To nAsset)
Dim Sim As Integer: Sim = 1
Dim A As Double
Dim B As Integer
Dim C As Integer
Dim D As Integer
For A = AMin To AMax Step AStep
For B = BMin To BMax Step BStep
'If (A + B) > 100 Then GoTo endB
For C = CMin To CMax Step CStep
'If (A + B + C) > 100 Then GoTo endC
For D = DMin To DMax Step DStep
' nAsset is the count of set {a1, a2 ... an}
' AllocArray(1, 2, 3) = (Sim, a1, a2)
'Constraints
If (A + B + C + D) <> 100 Then GoTo endD
Debug.Print Sim; A; B; C; D
AllocArray(Sim, 0) = Sim
AllocArray(Sim, 1) = A
AllocArray(Sim, 2) = B
AllocArray(Sim, 3) = C
AllocArray(Sim, 4) = D
Sim = Sim + 1
' Debug.Print "Sim "; Sim; AllocArray(1, 1)
endD:
Next D
endC:
Next C
endB:
Next B
Next A
' Print to sheet - Method One (fails)
Dim NumRows As Long: Dim NumCols As Long
NumRows = UBound(AllocArray, 1) - LBound(AllocArray, 1) + 1
NumCols = UBound(AllocArray, 2) - LBound(AllocArray, 2) + 1
Set Destination = Range("D20").Resize(NumRows, NumCols).Value = AllocArray
' Print to sheet - Method Two (fails)
'Sheets("Test").Range("D20").Value = AllocArray(1, 1)
'Print to sheet - Method Three (fails)
PrintArray AllocArray, ActiveWorkbook.Worksheets("Test").[D20]
'Print to sheet - Method Four (fails)
Range("D20:H989").Value = AllocArray
Sheets("Test").Range("D20").Resize(Sim, NumCols).Value = AllocArray
'Range(D20:G6002) = AllocArray
ConfigureArrayFolly = nSim
End Function
Your array has different lower bounds for each dimension.
You need to adjust for that by adding 1 to UBound(Data,2) :
Sub PrintArray(Data As Variant, Cl As Range)
Cl.Resize(UBound(Data, 1), UBound(Data, 2) + 1) = Data
End Sub
A few pointers.
You are correct in using Range("D20").Resize(NumRows, NumCols).Value = AllocArray syntax.
AllocArray needs to be sized with ReDim AllocArray(1 to NumRows, 1 to NumCols)
It is correctly defined as Dim AllocArray() as Variant
The contents need to be either a Double or a String. You are mixing integers and doubles and I think Excel has a hard time with this (I may be wrong). Set A, B, C and D as Double
Dim nAsset As Integer: nAsset = 5 ' Count {A, B, ... , F} this is an integer, why was it defined as a Double?
Use 32-bit integers for counting. Dim Sim As Long: Sim = 1. The max. value for an Integer is 32767 so you may be overflowing. This may apply to other Integer types in your code too.
You already know how big the array is, you don't need the UBound() and LBound() calls.
Related
It appears that I'm not the only one to struggle with this, but I can't find an good answer, so I try my chance here!
I would like to find a 3rd degree polynomial line of best fit, given two sets of data stored in arrays. Basically, it looks like that
Dim X(0 to 9) as Integer
Dim Y(0 to 9) as Integer
for k = 0 to 9
X(k) = 'something
Y(k) = 'something else
Next
So far I've worked out how to solve my issue with a 1st degree polynomial Y = aX + b :
a = Application.WorksheetFunction.LinEst(Y, X, True, False)(1)
b = Application.WorksheetFunction.LinEst(Y, X, True, False)(2)
I also found that if my values X and Y are written into a Sheet, I can find a higher polynomial with this :
'x-axis values are entered in X column, y-values in Y column
Z = Application.Evaluate("=linest(Y1:Y10,X1:X10^{1,2,3})")
'The answer is in Z such that Y = Z(1)*Y^3+Z(2)*Y^2+Z(3)*Y+Z(4)
Assuming my arrays are already sorted, how can I use linest with arrays and not values entered into cells?
If you want the OLS best fit coefficients (i.e. linear regression) and not interpolation, then you can do it like this for a second order polynomial:
Sub test()
Dim X(0 To 9, 0 To 1) As Integer
Dim Y(0 To 9, 0 To 0) As Integer
i = 0
For n = 0 To 9
X(n, 0) = i
X(n, 1) = i * i
Y(n, 0) = i * i + 3 * i - 7
i = i + 1
Next
B = WorksheetFunction.LinEst(Y, X)
B2 = B(1)
B1 = B(2)
B0 = B(3)
End Sub
This correctly returns -7 for B0, 3 for B1 and 1 for B2. This is pretty much the same as this answer: https://stackoverflow.com/a/27137957/1011724
You can make it more general, say a k-order polynomial like this:
Function f(X) As Integer ' This function is replaced by your data
f = -2 * WorksheetFunction.Power(X, 3) + 3 * X - 7
End Function
Sub test2()
Order = 3
ReDim X(0 To 9, 0 To Order - 1)
Dim Y(0 To 9, 0 To 0) As Integer
'Note i is only to generate dummy data
i = 1
For n = 0 To 9 'Replace 9 with the length of your data
X(n, 0) = i 'This line is replaced by your actual data
' Create the higher order features:
For k = 1 To Order
X(n, k-1) = Application.WorksheetFunction.Power(i, k)
Next
Y(n, 0) = f(i) 'This line is replaced by your actual data
i = i + 1
Next
B = WorksheetFunction.LinEst(Y, X)
End Sub
I've found another way to work with polynomial regression with arrays. The code is in this link. https://rosettacode.org/wiki/Polynomial_regression. Because the code in the website was not working due to incorrect array, I made a minor correction. It works now.
Function polynomial_regression(y As Variant, x As Variant, degree As Integer) As Variant
Dim a() As Double
ReDim a(1 To UBound(x), 1 To degree)
For i = 1 To UBound(x)
For j = 1 To degree
a(i, j) = x(i) ^ j
Next j
Next i
polynomial_regression = WorksheetFunction.LinEst(WorksheetFunction.Transpose(y), a, True, True)
End Function
I added a function to the above to use range variables as inputs to work as an equivalent to the Excel function linest()
Public Function RangeToArray(ByRef myRange As Variant) As Variant
Dim individualCell As Range
Dim i As Integer
ReDim myArray(1 To myRange.Count)
i = 1
For Each individualCell In myRange
myArray(i) = individualCell.Value
i = i + 1
Next
RangeToArray = myArray
End Function
Function PolyFit(yRange As Variant, xRange As Variant, degree As Integer) As Variant
Dim xAry() As Variant
Dim yAry() As Variant
Dim a() As Double
xAry() = RangeToArray(xRange)
yAry() = RangeToArray(yRange)
ReDim a(1 To (UBound(xAry)), 1 To (degree))
For i = 1 To (UBound(xAry))
For j = 1 To (degree)
a(i, j) = xAry(i) ^ (j)
Next j
Next i
PolyFit = WorksheetFunction.LinEst(WorksheetFunction.Transpose(yAry), a, True, False)
End Function
I have the following code, which based on the logic it should work.
I want it to be (4,3,2,1), but at the end of the loop I get t=(4,3,3,4)
Sub try()
Dim t As Variant
t = Array(1, 2, 3, 4)
a = UBound(t)
For k = 0 To a
t(k) = t(a - k)
Next k
End Sub
Any ideas?
You have to use a temporary variable to store the stuff before you make the switch else it will be overwritten.
Is this what you are trying?
Sub try()
Dim t As Variant, tmp As Variant
Dim a As Long, b As Long, i As Long
t = Array(1, 2, 3, 4)
a = UBound(t): b = LBound(t)
For i = 0 To ((a - b) \ 2)
tmp = t(i)
t(i) = t(a)
t(a) = tmp
a = a - 1
Next i
For i = 0 To UBound(t)
Debug.Print t(i)
Next i
End Sub
When you do t(k) = t(a - k) you assign t(a-k) to t(k), but then the value stored in t(k) is lost. You need to temporarily store that in another variable (variable x in the following example), then you can swap the values between t(k) and t(a - k) like this:
Sub try()
Dim t As Variant
Dim x As Variant
Dim b As Integer
t = Array(1, 2, 3, 4)
a = UBound(t)
b = (a - 1) / 2
For k = 0 To b
x = t(k)
t(k) = t(a - k)
t(a - k) = x
Next k
End Sub
Notice that you only need to iterate a number of times that is half of your array size (rounded down) otherwise you'd swap back values again and would end up with the same starting array.
If don't want to delete the original array you can
create a copy of the array in reverse creation.
See 1D and 2D array subs:
Option Base 1
Sub CopyArrayinReverseColumns1D()
Dim OriginalArr As Variant
Dim newarr As Variant
Dim a As Long
Dim i As Long
OriginalArr = Array(1, 2, 3, 4)
newarr = Array(0, 0, 0, 0)
a = UBound(OriginalArr)
For i = 1 To a
newarr(i) = OriginalArr(a - i + 1)
Debug.Print newarr(i)
Next
End Sub
Sub CopyArrayinReverseColumns2D()
Dim OriginalArr(2, 4) As Variant
Dim newarr(2, 4) As Variant
Dim a As Long
Dim b As Long
Dim i As Long
Dim n As Long
OriginalArr(1, 1) = 65
OriginalArr(1, 2) = 70
OriginalArr(1, 3) = 75
OriginalArr(1, 4) = 80
OriginalArr(2, 1) = 85
OriginalArr(2, 2) = 90
OriginalArr(2, 3) = 95
OriginalArr(2, 4) = 100
a = UBound(OriginalArr, 1)
b = UBound(OriginalArr, 2)
For i = 1 To a
For n = 1 To b
newarr(i, n) = OriginalArr(a - i + 1, n)
Debug.Print newarr(i, n)
Next
Next
End Sub
Building a portfolio asset allocator, for assets A, B, C, D, and want to expand it to n assets. With four assets, can run four nested loops. The issue is to create n nested loops, and then apply the constraint, detailed below, and the middle nest, which allocates an array to the current asset distribution. The constraint is (A + B + C + ... + n) <> 100 i.e. 100% allocation across all assets.
The asset step sizes are arbitrary (5 or 1) but there are minimum and maximum bounds on each n assets.
The asset sum to 100 constraint knocks out many of the iterations.
What is interesting in this question, is the AllocArray requires the position of each {A, B, C, ... , nAsset} i.e. the location of each nested loop. I think this makes an exciting puzzle.
Below is nAssets = 4 i.e. {A,B,C,D}:
MinMaxStepParam = Range("A1:C4")
Min Max Step
A 5 100 5
B 5 100 5
C 5 100 5
D 5 100 5
Dim Sim As Long: Sim = 1
Dim AllocArray() As Variant
ReDim AllocArray(1 To nSim, 1 To nAsset + 1)
Dim A As Double
Dim B As Double
Dim C As Double
Dim D As Double
For A = AMin To AMax Step AStep
For B = BMin To BMax Step BStep
'If (A + B) > 100 Then GoTo endB ' not required as middle nest bound catches all
For C = CMin To CMax Step CStep
'If (A + B + C) > 100 Then GoTo endC ' ditto
For D = DMin To DMax Step DStep
'Constraints
If (A + B + C + D) <> 100 Then GoTo endD
Debug.Print Sim; A; B; C; D
AllocArray(Sim, 1) = Sim
AllocArray(Sim, 2) = A
AllocArray(Sim, 3) = B
AllocArray(Sim, 4) = C
AllocArray(Sim, 5) = D
Sim = Sim + 1
endD:
Next D
endC:
Next C
endB:
Next B
Next A
PrintArray AllocArray, ActiveWorkbook.Worksheets("Output").[A1]
Sub PrintArray(Data As Variant, Cl As Range)
Cl.Resize(UBound(Data, 1), UBound(Data, 2)) = Data
End Sub
I have produced this as a dynamic loop, but there is an error. Can VBA handle using Array locations for the Min, Max and Step of a loop? Is there an alternative?
Sub ConfigureArrayDylan()
Dim Param() As Variant: Param = Range("M3:O6") ' a 4x3 with...Min Max Step... {5 100 5; 5 100 5; 5 100 5; 5 100 5}.
Dim nAsset As Long: nAsset = UBound(Param) ' Count {A, B, ... , D } = 4
Debug.Print nAsset
Dim Asset As Double
Dim Value As Double
Dim Sim As Long: Sim = 1
Dim nSim As Long: nSim = 1
Dim nSimStep As Long
For i = 1 To nAsset Step 1
nSimStep = (1 + (Param(i, 2) - Param(i, 1)) / Param(i, 3)) '(1 + (AMax - AMin) / AStep) *
Debug.Print i; nSimStep
nSim = nSim * nSimStep
Next i
Debug.Print nSim
Dim AllocArray() As Variant
ReDim AllocArray(1 To nSim, 1 To nAsset + 1)
For Asset = 1 To nAssets Step 1
For Value = Param(Asset, 1) To Param(Asset, 2) Step Param(Asset, 3)
Debug.Print Value; ' FAILURE HERE
AllocArray(Sim, Asset) = Value
Sim = Sim + 1
Next Value
Next Asset
Debug.Print Sim;
PrintArray AllocArray, ActiveWorkbook.Worksheets("Test").[L18]
'Range("D30").Resize(NumRows, NumCols).Value = AllocArray
End Sub
I am trying to do some array math in Excel which requires me to reverse a number of 1-dimensional ranges a good amount of times, so I want to write a function for it, rather than create reverses in the spreadsheet.
I have written a reverse() function in VBA but it returns #VALUE! errors in the spreadsheet. This happens no matter array size, nor whether inputting a same size array function or enclosing with a summary function like SUM(). I verified that the reversing logic works as a Sub. This leads me to believe the issue is with passing/returning the range/array but I don't understand what is wrong.
Function reverse(x As Range) As Variant()
' Array formula that reverses a one-dimensional array (1 row, x columns)
Dim oldArray() As Variant, newArray() As Variant
Dim rows As Long: i = x.rows.Count
Dim cols As Long: i = x.Columns.Count
ReDim oldArray(1 To rows, 1 To cols), newArray(1 To rows, 1 To cols)
oldArray = x.Value
newArray = oldArray
For i = 1 To cols / 2 Step 1
newArray(1, i) = oldArray(1, cols - i + 1)
newArray(1, cols - i + 1) = oldArray(1, i)
Next
reverse = newArray
End Function
Keep in mind, I may extend it to reverse 2 dimensional arrays, but that's the trivial part. My question is just trying to ensure the function works on a (1, N) range.
Thanks!
Find below code....
Function reverse(x As Range) As Variant()
' Array formula that reverses a one-dimensional array (1 row, x columns)
Dim oldArray() As Variant, newArray() As Variant
Dim rows As Long
rows = x.rows.Count
Dim cols As Long
cols = x.Columns.Count
ReDim oldArray(1 To rows, 1 To cols), newArray(1 To rows, 1 To cols)
oldArray = x.Value
newArray = oldArray
For i = 1 To cols / 2 Step 1
newArray(1, i) = oldArray(1, cols - i + 1)
newArray(1, cols - i + 1) = oldArray(1, i)
Next
reverse = newArray
End Function
The following code is more versatile, it use optional arguments to determine if rows, columns or both (or none) should be reversed. By default it will reverse columns.
Function ReverseRange(Source As Range, Optional ReverseRows As Boolean = False, Optional ReverseColumns As Boolean = True) As Variant()
Dim SourceArray() As Variant
Dim DestArray() As Variant
SourceArray = Source.value
Dim nRows As Long, nColumns As Long
nRows = UBound(SourceArray, 1)
nColumns = UBound(SourceArray, 2)
ReDim DestArray(1 To nRows, 1 To nColumns)
Dim r As Long, r2 As Long, c As Long, c2 As Long
For r = 1 To nRows
r2 = IIf(ReverseRows, nRows - r + 1, r)
For c = 1 To nColumns
c2 = IIf(ReverseColumns, nColumns - c + 1, c)
DestArray(r2, c2) = SourceArray(r, c)
Next c
Next r
ReverseRange = DestArray
End Function
Note that there is no verification on the range validity.
This will reverse the columns in the range no matter the row count.
Function reverse(Source As Range) As Variant()
Dim Data, RevData
Dim x As Long, y As Long, y1 As Long
Data = Source.Value
ReDim RevData(1 to UBound(Data, 1),1 to UBound(Data, 2))
For x = 1 To UBound(Data, 1)
y1 = UBound(Data, 2)
For y = 1 To UBound(Data, 2)
RevData(x, y1) = Data(x, y)
y1 = y1 - 1
Next
Next
reverse = RevData
End Function
I am working on a simulation with time to event data that requires some "memory" of when an event started in order to apply a Weibull function at that time. This requires a large matrix of values and I am interested a VBA solution to avoid large conditional and array calculations on the worksheet. The current solution is to create a matrix containing the data and to multiply that by a matrix containing the diagonal of interest and then sum the product to obtain the diagonal alone. The matrix is 1800x1800 on the sheet.
The code below appears to fault during the matrix multiplication and gives a "run time error '9' subscript of of range" message. I have found that 'array_2' -despite being specified as array_2(1,1) -shows as having a lower bound of 1 and upper bound of 2 (see block of code near the bottom for proof).
Any help as to why this is occurring would be much appreciated.
Todd
Sub sum_diag_float()
Dim a, b, q, i, j, x, y, lb, ub, sum As Double
Dim array_1(), array_2(), upright_arr(), array_product() As Variant
ReDim array_1(0 To 9, 0 To 9) As Variant
'create data
For a = 0 To 9
For b = 0 To 9
array_1(a, b) = WorksheetFunction.RandBetween(0, 10)
Next b
Next a
Range("A1:J10").Value = array_1
For q = 1 To 1
ReDim array_2(q, q) As Variant
array_2 = Range(Cells(1, 1), Cells(q + 1, q + 1)).Value
Range(Cells(1, 12), Cells(2, 13)).Value = array_2 'check array specification
'build binary matrix (0/1) from lower left to upper right
ReDim upright_arr(q, q) As Variant
For i = LBound(upright_arr, 1) To UBound(upright_arr, 1)
For j = LBound(upright_arr, 2) To UBound(upright_arr, 2)
If UBound(upright_arr, 2) = i + j Then
upright_arr(i, j) = 1
Else
upright_arr(i, j) = 0
End If
Next j
Next i
Range(Cells(4, 12), Cells(5, 13)).Value = upright_arr 'check matrix specification
'multiply data by the matrix
ReDim array_product(q, q) As Variant
For x = LBound(upright_arr, 1) To UBound(upright_arr, 1)
For y = LBound(upright_arr, 2) To UBound(upright_arr, 2)
array_product(x, y) = upright_arr(x, y) * array_2(x, y)
Next y
Next x
Range(Cells(7, 12), Cells(8, 13)).Value = array_product 'matrix multiplication result
sum = WorksheetFunction.sum(array_product)
Range("N9").Value = sum 'sum of matrix
lb = LBound(array_2, 1) 'proof of array dimension misspecification
Range("L11").Value = lb
ub = UBound(array_2, 1)
Range("L12").Value = ub
lb = LBound(array_2, 2)
Range("L14").Value = lb
ub = UBound(array_2, 2)
Range("L15").Value = ub
Next q
End Sub
The edited code following the first suggestions retains a runtime error '13' :
Sub sum_diag_float()
Dim a As Byte, b As Byte
Dim q As Double, i As Double, j As Double, x As Double, y As Double
Dim lb As Double, ub As Double, sum As Double
Dim array_1() As Double, array_2() As Double, upright_arr() As Double, array_product() As Double
ReDim array_1(0 To 9, 0 To 9) As Double
'create data
For a = 0 To 9
For b = 0 To 9
array_1(a, b) = WorksheetFunction.RandBetween(0, 10)
Next b
Next a
Range("A1:J10").Value = array_1
For q = 1 To 2
ReDim array_2(q, q) As Double
array_2 = Range(Cells(1, 1), Cells(q + 1, q + 1)).Value 'put cells in array
Range(Cells(1, 12), Cells(1 + q, 12 + q)).Value = array_2 'check array
'build binary matrix (0/1) from lower left to upper right
ReDim upright_arr(LBound(array_2, 1) To UBound(array_2, 1), LBound(array_2, 2) _
To UBound(array_2, 2)) As Double
For i = LBound(array_2, 1) To UBound(array_2, 1)
For j = LBound(array_2, 2) To UBound(array_2, 2)
If UBound(upright_arr, 2) = i + j - 1 Then
upright_arr(i, j) = 1
Else
upright_arr(i, j) = 0
End If
Next j
Next i
Range(Cells(5, 12), Cells(5 + q, 12 + q)).Value = upright_arr
'multiply data by the matrix
ReDim array_product(LBound(array_2, 1) To UBound(array_2, 1), LBound(array_2, 2) _
To UBound(array_2, 2)) As Double
For x = LBound(array_2, 1) To UBound(array_2, 1)
For y = LBound(array_2, 2) To UBound(array_2, 2)
array_product(x, y) = upright_arr(x, y) * array_2(x, y)
Next y
Next x
Range(Cells(9, 12), Cells(9 + q, 12 + q)).Value = array_product
sum = WorksheetFunction.sum(array_product)
Range("O12").Value = sum 'sum of matrix
Next q
End Sub
After correcting the above issues, the array multiplication step bugs to a run-time error '13' when used in the following code. I believe some variable is not being erased when called twice via the first sub. In reading various documentation, I do not beleive that I should have to provide any of the values to the call to 'sum_diag_float,' but this may be the problem. Ultimately, the sub 'call_txp_surv' will be called within other loops to create the desired simulation data, thus the need for the sub to work without bugs despite the number of times it is called. I am noting that a call_txp_surv with q = 1000 (s = 1000) does not generate an error, but at q = 1800 and s= 1800 the run-time '13' occurs. The code now contains the implemented cell counts which are different from previous code (much larger and thus no simulated data). Variables/counters have been renamed to avoid conflict with others. Any thoughts as to why this macro won't scale-up would be appreciated.
Sub call_txp_surv()
Dim lvad_clvad As Byte
For lvad_clvad = 1 To 2
If lvad_clvad = 1 Then
Worksheets("LVAD>TXP>death").Activate
Else
Worksheets("cLVAD>TXP>death").Activate
End If
Call sum_diag_float
Next lvad_clvad
End Sub
Sub sum_diag_float()
Application.Calculation = xlManual
Application.ScreenUpdating = False
Dim a As Byte, b As Byte
Dim m As Long, n As Long, q As Long, x As Long, y As Long
Dim array_1() As Double, array_2() As Variant, upright_arr() As Variant, array_product() As Variant
'cycle living calculation
For q = 1 To 1800
'put cells into array
array_2 = Range(Cells(3, 20), Cells(3 + q, 20 + q)).Value
'build binary matrix (0/1) from lower left to upper right
ReDim upright_arr(LBound(array_2, 1) To UBound(array_2, 1), LBound(array_2, 2) To UBound(array_2, 2)) As Variant
For m = LBound(array_2, 1) To UBound(array_2, 1)
For n = LBound(array_2, 2) To UBound(array_2, 2)
If UBound(upright_arr, 2) = m + n - 1 Then
upright_arr(m, n) = 1
Else
upright_arr(m, n) = 0
End If
Next n
Next m
'multiply data by the matrix
ReDim array_product(LBound(array_2, 1) To UBound(array_2, 1), LBound(array_2, 2) To UBound(array_2, 2)) As Variant
For x = LBound(array_2, 1) To UBound(array_2, 1)
For y = LBound(array_2, 2) To UBound(array_2, 2)
array_product(x, y) = upright_arr(x, y) * array_2(x, y)
Next y
Next x
'Range(Cells(9, 12), Cells(9 + q, 12 + q)).Value = array_product 'matrix multiplication result
sum = WorksheetFunction.sum(array_product)
Cells(4 + q, 1821).Value = sum 'sum of matrix
Next q
'cycle deaths
Dim c As Long, d As Long, s As Long, t As Long, u As Double, diff As Double
s = 1801
'subtract
For c = 1 To s
For d = 1 To (s - c)
diff = Cells(2 + d, 19 + c).Value - Cells(3 + d, 19 + c).Value
Cells(4 + d + (c - 1), 1823 + c).Value = diff
Next d
Next c
'sum
For t = 1 To (s - 1)
u = WorksheetFunction.sum(Range(Cells(4 + t, t + 1823), Cells(4 + t, t + 1824)))
Cells(4 + t, 1822).Value = u
Next t
Application.Calculation = xlAutomatic
Application.ScreenUpdating = True
End Sub
Your code line:
ReDim array_2(q, q) As Variant
dimensions array_2 as (0 to 1, 0 to 1)
But then your next line:
array_2 = Range(Cells(1, 1), Cells(q + 1, q + 1)).Value
actually redimensions array_2 to (1 to 2, 1 to 2) (two rows and two columns) (Dimension 1 for the rows; Dimension 2 for the columns).
This is what happens when you set an array equal to a range of cells.
If you want to retain the 0 to 1 dimensions, you would have to loop through the cells and assign them specifically.
See Arrays and Ranges in VBA by Chip Pearson
As an aside, your line:
Dim a, b, q, i, j, x, y, lb, ub, sum As Double
declares all of the variables, except for sum , as Variants. Given your code, I wonder if they should be declared as Long.
EDIT: With regard to your edited code, I don't understand why you did what you did.
In the link I posted above to Chip Pearson's website, it clearly shows that, when you are setting an array equal to a range, the array should be declared as type Variant; you have declared it as Double (twice!), therefore the Type Mismatch error. Again, if you MUST have the array as type Double, then you will have to loop through and assign the values one by one.
For reasons I wrote above, the ReDim array_2 line adds overhead without accomplishing anything and should be removed.
Why do you declare your counters as being of type Double instead of type Long?
The working and tested code for my question is below. Thanks to Ron for assisting.
Sub sum_diag_float()
Dim a As Byte, b As Byte
Dim q As Long, i As Long, j As Long, x As Long, y As Long
Dim array_1() As Double, array_2() As Variant, upright_arr() As Double, array_product() As Double
ReDim array_1(0 To 9, 0 To 9) As Double
'create data
For a = 0 To 9
For b = 0 To 9
array_1(a, b) = WorksheetFunction.RandBetween(0, 10)
Next b
Next a
Range("A1:J10").Value = array_1
For q = 1 To 2
array_2 = Range(Cells(1, 1), Cells(q + 1, q + 1)).Value 'put cells in array
Range(Cells(1, 12), Cells(1 + q, 12 + q)).Value = array_2 'check array specification
'build binary matrix (0/1) from lower left to upper right
ReDim upright_arr(LBound(array_2, 1) To UBound(array_2, 1), LBound(array_2, 2) To UBound(array_2, 2)) As Double
For i = LBound(array_2, 1) To UBound(array_2, 1)
For j = LBound(array_2, 2) To UBound(array_2, 2)
If UBound(upright_arr, 2) = i + j - 1 Then
upright_arr(i, j) = 1
Else
upright_arr(i, j) = 0
End If
Next j
Next i
Range(Cells(5, 12), Cells(5 + q, 12 + q)).Value = upright_arr 'check matrix specification
'multiply data by the matrix
ReDim array_product(LBound(array_2, 1) To UBound(array_2, 1), LBound(array_2, 2) To UBound(array_2, 2)) As Double
For x = LBound(array_2, 1) To UBound(array_2, 1)
For y = LBound(array_2, 2) To UBound(array_2, 2)
array_product(x, y) = upright_arr(x, y) * array_2(x, y)
Next y
Next x
Range(Cells(9, 12), Cells(9 + q, 12 + q)).Value = array_product 'matrix multiplication result
sum = WorksheetFunction.sum(array_product)
Range("O12").Value = sum 'sum of matrix
Next q
End Sub