Hello MathOverflow community,
EDIT: Fixed some typos and added some clarifications regarding what is an input.
EDIT No1: Fixed some typos and added some clarifications regarding what is an input.
EDIT No2: Substituting the sum of the squares of the diagonal elements for the trace indeed made this a linear problem which I was then able to solve using the simplex's "Big M" method. Works like a charm, even on Excel! My VBA code:
Public Const MAXVALUE As Double = 1.79769313486231E+308 'Arbitrary large value
Public Const EPSILON As Double = 0.0001 'Tolerance parameter for the Simplex method
Public Const BIGM As Double = 100# 'Big M constant for the Simplex method
Public Function Simplex(odds As Range) As Variant
'///////////////////////////////////////////////////////////////////////
'/// :function: Simplex
'/// :scope: Public
'/// :description: For odds.Cells.Count > 10, there can be instability issues.
'/// :return: Wrapper (data validation) for the Simplex_ function.
'/// :odds: An array of long-term odds (Range).
'///////////////////////////////////////////////////////////////////////
Dim n As Long
n = odds.Cells.Count
With WorksheetFunction
If .Count(odds) <> n Then
Simplex = CVErr(xlErrNum)
ElseIf .CountIf(odds, ">1") > 0 Then
Simplex = CVErr(xlErrValue)
ElseIf .CountIf(odds, "<0") > 0 Then
Simplex = CVErr(xlErrValue)
ElseIf Abs(.Sum(odds) - 1) > EPSILON Then
Simplex = CVErr(xlErrValue)
Else
Simplex = Simplex_(odds)
End If
End With
End Function
Private Function Simplex_(pi As Range) As Double()
'///////////////////////////////////////////////////////////////////////
'/// :function: Simplex_
'/// :scope: Public
'/// :description: Implements the "Big M" variant of the Simplex method.
'/// :return: The lowest trace probability matrix having stationary distribution Odds.
'/// :pi: An array of long-term odds.
'///////////////////////////////////////////////////////////////////////
Dim StopFlag As Boolean
Dim output() As Double
Dim MinRatio As Double
Dim MaxCost As Double
Dim factor As Double
Dim Ratio As Double
Dim Pivot As Double
Dim x() As Variant
Dim Row As Long
Dim Col As Long
Dim n As Long
Dim i As Long
Dim j As Long
Dim k As Long
n = pi.Cells.Count
'As we're looking for a matrix, the number of unknowns is n^2 + others for the constraints
ReDim x(0 To 2 * n + 1, 0 To n * n + 2 * n + 2) As Variant
ReDim output(1 To n, 1 To n) As Double
x(0, 0) = "BASIS"
x(0, 1) = "Z"
For i = 1 To n * n
Row = 1 + (i - 1) \ n
Col = 1 + (i - 1) Mod n
x(0, i + 1) = "p" & Row & Col
Next
For i = 1 To n
Col = 1 + (i - 1) Mod n
x(0, i + n * n + 1) = "c.r" & Col
x(0, i + n * n + n + 1) = "c.pi" & Col
x(i, 0) = "c.r" & Col
x(i + n, 0) = "c.pi" & Col
Next
x(0, n * n + 2 * n + 2) = "RHS" 'Right-hand side
x(2 * n + 1, 0) = "COST"
For i = 1 To n
For j = 1 To n * n
Row = 1 + (j - 1) \ n
x(i, j + 1) = IIf(Row = i, 1, 0)
Next
x(i, n * n + 2 * n + 2) = 1
For j = 1 To n * n
Row = 1 + (j - 1) \ n
Col = 1 + (j - 1) Mod n
x(i + n, j + 1) = IIf(Col = i, pi(Row).Value, 0)
Next
x(i + n, n * n + 2 * n + 2) = pi(i).Value
Next
For i = 1 To n * n
Row = 1 + (i - 1) \ n
Col = 1 + (i - 1) Mod n
x(2 * n + 1, i + 1) = IIf(Row = Col, -1, 0)
Next
For i = 1 To 2 * n
For j = i + 1 To 2 * n
x(i, n * n + 1 + j) = 0
x(j, n * n + 1 + i) = 0
Next
x(i, 1) = 0
x(i, n * n + 1 + i) = 1
x(2 * n + 1, n * n + 1 + i) = -BIGM
Next
x(2 * n + 1, 1) = 1
x(2 * n + 1, n * n + 2 * n + 2) = 0
For k = 1 To 2 * n
Col = n * n + 1 + k
MinRatio = MAXVALUE
For i = 1 To 2 * n
If x(i, Col) > 0 Then
Ratio = x(i, n * n + 2 * n + 2) / x(i, Col)
If Ratio < MinRatio Then
MinRatio = Ratio
Row = i
End If
End If
Next
Pivot = x(Row, Col)
For i = 1 To 2 * n + 1
If i <> Row Then
factor = -x(i, Col) / Pivot
For j = 1 To n * n + 2 * n + 2
x(i, j) = x(i, j) + factor * x(Row, j)
Next
End If
Next
For j = 1 To n * n + 2 * n + 2
x(Row, j) = x(Row, j) / Pivot
Next
Next
Do
MaxCost = -MAXVALUE
For i = 1 To n * n
If x(2 * n + 1, i + 1) > MaxCost Then
MaxCost = x(2 * n + 1, i + 1)
Col = i + 1
End If
Next
If MaxCost <= 0 Then
Exit Do
Else
MinRatio = MAXVALUE
For i = 1 To 2 * n
If x(i, Col) > 0 Then
Ratio = x(i, n * n + 2 * n + 2) / x(i, Col)
If Ratio < MinRatio Then
MinRatio = Ratio
Row = i
End If
End If
Next
Pivot = x(Row, Col)
For i = 1 To 2 * n + 1
If i <> Row Then
factor = -x(i, Col) / Pivot
For j = 1 To n * n + 2 * n + 2
x(i, j) = x(i, j) + factor * x(Row, j)
Next
End If
Next
For j = 1 To n * n + 2 * n + 2
x(Row, j) = x(Row, j) / Pivot
Next
x(Row, 0) = x(0, Col)
End If
Loop
For i = 1 To n * n
Row = 1 + (i - 1) \ n
Col = 1 + (i - 1) Mod n
For j = 1 To 2 * n
If x(j, 0) = "p" & Row & Col Then
output(Row, Col) = x(j, n * n + 2 * n + 2)
Exit For
End If
Next
Next
Simplex_ = output
End Function