Public Class AlglibTest

  ''' <summary>
  '''     Standard mean-variance portfolio optimisation:  A quadratic problem.
  '''     Minimise: -aWeight' aExpReturn + .5 aWeight' matCov aWeight
  '''     Input the linear term as the negative of the expected returns
  ''' </summary>
  Public Sub TestNoBudget()

    Dim matCov(,) As Double 'The quadratic term
    Dim aNegativeExpReturn() As Double 'The linear term (the negative of expected returns)
    Dim aBoundLower(), aBoundUpper() As Double
    Dim aStartingWeight(), aOptimalWeight() As Double
    Dim TerminationType As Integer

    matCov = New Double(,) _
      {{0.142, 0.056, 0.061}, _
      {0.056, 0.181, 0.031}, _
      {0.061, 0.031, 0.08}}
    aNegativeExpReturn = New Double() {-0.1, -0.1, -0.1}
    aBoundLower = New Double() {0, 0, 0}
    aBoundUpper = New Double() {Double.PositiveInfinity, Double.PositiveInfinity, Double.PositiveInfinity}
    aStartingWeight = New Double() {1 / 3, 1 / 3, 1 / 3}

    aOptimalWeight = GetOptWeight(matCov, aNegativeExpReturn, aBoundLower, aBoundUpper, aStartingWeight, TerminationType)

  End Sub


  ''' <summary>
  '''   As above, but including a constraint that the weights add to 1.
  '''   This is done using a Lagrangian multiplier
  '''   augmented into the input vector and matrix.
  ''' </summary>
  Public Sub TestWithBudgetConstraint()

    Dim matCov(,) As Double
    Dim aNegativeExpReturn() As Double
    Dim aBoundLower(), aBoundUpper() As Double
    Dim aStartingWeight(), aOptimalWeight() As Double
    Dim TerminationType As Integer

    matCov = New Double(,) _
      {{0.142, 0.056, 0.061, 1}, _
      {0.056, 0.181, 0.031, 1}, _
      {0.061, 0.031, 0.08, 1}, _
      {1, 1, 1, 0}}
    aNegativeExpReturn = New Double() {-0.1, -0.1, -0.1, -1}
    aBoundLower = New Double() {0, 0, 0, Double.NegativeInfinity}
    aBoundUpper = New Double() {Double.PositiveInfinity, Double.PositiveInfinity, Double.PositiveInfinity, Double.PositiveInfinity}
    aStartingWeight = New Double() {0.25, 0.25, 0.25, 0.25}

    aOptimalWeight = GetOptWeight(matCov, aNegativeExpReturn, aBoundLower, aBoundUpper, aStartingWeight, TerminationType)

    TerminationType = TerminationType

  End Sub


  ''' <summary>
  '''     Using Alglib's quadratic program minimiser
  ''' </summary>
  Public Function GetOptWeight _
    (ByVal matCov(,) As Double, ByVal aNegativeExpReturn() As Double, _
    ByVal aBoundLower() As Double, ByVal aBoundUpper() As Double, _
    ByVal aStartingWeight() As Double, _
    ByRef TerminationType As Integer) _
    As Double()

    Try

      Dim AlglibState As minqpstate = New XAlglib.minqpstate()
      Dim AlglibReport As minqpreport = New XAlglib.minqpreport()
      Dim aOptWeight() As Double
      Dim NumDimensions As Integer

      NumDimensions = aNegativeExpReturn.GetLength(0)

      'Set-up the problem and solve for this RA and Starting weights
      XAlglib.minqpcreate(NumDimensions, AlglibState)
      XAlglib.minqpsetquadraticterm(AlglibState, matCov)
      XAlglib.minqpsetlinearterm(AlglibState, aNegativeExpReturn)
      XAlglib.minqpsetstartingpoint(AlglibState, aStartingWeight)
      XAlglib.minqpsetbc(AlglibState, aBoundLower, aBoundUpper)
      XAlglib.minqpoptimize(AlglibState)
      XAlglib.minqpresults(AlglibState, aOptWeight, AlglibReport)

      TerminationType = AlglibReport.terminationtype

      'Return optimal weights
      Return aOptWeight

    Catch ex As System.Exception
      Dim mEx As New ExceptionIMapsControl(GetCurrentMethod, ex)
      Throw mEx

    End Try

  End Function


End Class
