FICO
FICO Xpress Optimization Examples Repository
FICO Optimization Community FICO Xpress Optimization Home
Back to examples browserPrevious exampleNext example

Successive linear programming (SLP) model for a financial planning problem

Description
  • modifying constraint coefficients
  • while statement
  • basis in- and output and problem reloading
  • setting/accessing optimiser parameters
  • procedure
Further explanation of this example: 'Mosel User Guide', Section 12.1 Recursion


Source Files
By clicking on a file name, a preview is opened at the bottom of this page.
recurse.mos[download]
fin_nl.mos[download]





recurse.mos

(!*******************************************************
  * Mosel Example Problems                              *
  * ======================                              *
  *                                                     *
  * file recurse.mos                                    *
  * ````````````````                                    *
  * Example for the use of the Mosel language           *
  * (Financial application of Recursion, that is        *
  *  Non-linear programming)                            *  
  *                                                     *
  *  The problem is to solve                            *
  *     net(t) = Payments(t)  - interest(t)             *
  *     balance(t) = balance(t-1) - net(t)              *
  *     interest(t) = (92/365) * balance(t) *           *
  *                                   interest_rate     *
  *  where                                              *
  *     balance(0) = 0                                  *
  *     balance(T) = 0                                  *
  *     for interest_rate                               *
  *                                                     *
  *  The problem is that we have the T products:        *
  *     balance(t) * interest_rate                      *
  *  which cannot be modelled just by LP.               *
  *                                                     *
  * (c) 2008 Fair Isaac Corporation                     *
  *     author: S. Heipcke, 2001, rev. Jun. 2022        *
  *******************************************************!)

model Fin_nlp                       ! Start a new model

uses "mmxprs"                       ! Load the optimizer library

forward procedure solverec          ! Declare a procedure defined later

declarations
 T=6                                ! Time horizon
 RT=1..T                            ! Range of time periods
 P,R,V: array(RT) of real           ! Payments
 B: array(RT) of real               ! An INITIAL GUESS as to balances b(t)
 X: real                            ! An INITIAL GUESS as to interest rate x

 interest: array(RT) of mpvar       ! Interest
 net: array(RT) of mpvar            ! Net
 balance: array(RT) of mpvar        ! Balance
 x: mpvar                           ! Interest rate
 dx: mpvar                          ! Change to x
 eplus, eminus: array(RT) of mpvar       ! + and - deviations
end-declarations

 X:= 0.00
 B:: [1, 1, 1, 1, 1, 1]
 P:: [-1000, 0, 0, 0, 0, 0]
 R:: [206.6, 206.6, 206.6, 206.6, 206.6, 0]
 V:: [-2.95, 0, 0, 0, 0, 0]

                                    ! net = payments - interest
 forall(t in RT) Net(t):=  net(t) = (P(t)+R(t)+V(t)) - interest(t)

                                    ! Money balance across periods
 forall(t in RT) Bal(t):= balance(t) = if(t>1, balance(t-1), 0) - net(t)

!       interest = (92/365)*( balance * interest_rate)
! i.e.  interest(t) = (92/365)*( balance(t-1)  * x )
!       interest(t) = (92/365)*( balance(t-1)  * ( X + dx ) )
!       interest(t) = (92/365)*( balance(t-1)*X + (B(t-1)+db(t-1))*dx )
!       interest(t) = (92/365)*( balance(t-1)*X + B(t-1)*dx )   (approx)
!       Use penalty variables (eplus and eminus) to ensure feasibility:
 forall(t in 2..T) 
  Interest(t):= 
   -(365/92)*interest(t) + X*balance(t-1) + B(t-1)*dx + eplus(t) - eminus(t) = 0
                          
 Def:= X + dx = x                    ! Define the interest rate: x = X + dx
                                     
 Feas:= sum(t in RT) (eplus(t)+eminus(t))  ! Objective: get feasible

 interest(1) = 0                     ! Initial interest is zero
 forall (t in RT) net(t) is_free
 forall (t in 1..T-1) balance(t) is_free
 balance(T) = 0                      ! Final balance is zero
 dx is_free

 minimize(Feas)                      ! Solve the LP-problem

 solverec                            ! Recursion loop
 
                                     ! Print the solution
 writeln("\nThe interest rate is ", x.sol)
 write(strfmt("t",5), strfmt(" ",4))
 forall(t in RT) write(strfmt(t,5), strfmt(" ",3))
 write("\nBalances ")
 setparam("realfmt", "%8.2f")
 forall(t in RT)  write(balance(t).sol)
 write("\nInterest ")
 forall(t in RT)  write(interest(t).sol)
 writeln

 
!************************************************************************
!  Recursion loop: we recurse on X and the b(t)'s.
!    The 'B(t-1)' in rows interest(t) get the prior value of b(t-1)
!    The 'X' in rows interest(t) get the prior value of x
!    The 'X' in row def gets the prior value of x
!    We say we have converged when the change in dx is less than 1.0E-6
!************************************************************************
procedure solverec

 declarations
  TOLERANCE=0.000001                  ! Convergence tolerance
  variation: real                     ! Variation of x
  BC: array(RT) of real
  bas: basis
 end-declarations

  setparam("zerotol", TOLERANCE)      ! Set Mosel comparison tolerance
  variation:=1.0
  ct:=0

  while(variation>0) do
    savebasis(bas)                    ! Save the current basis
    ct+=1
    forall(t in 2..T) 
      BC(t-1):= balance(t-1).sol      ! Get solution values for balance(t)'s
    XC:= x.sol                        ! and x
    write("Round ", ct, " x:", x.sol, " (variation:", variation,"), ")
    writeln("Simplex iterations: ", getparam("XPRS_SIMPLEXITER"))

    forall(t in 2..T) do              ! Update coefficients
      Interest(t)+= (BC(t-1)-B(t-1))*dx
      B(t-1):=BC(t-1)
      Interest(t)+= (XC-X)*balance(t-1)
    end-do
    Def+= XC-X  
    X:=XC
    oldxval:=XC                       ! Store solution value of x

    loadprob(Feas)                    ! Reload the problem into the optimizer
    loadbasis(bas)                    ! Reload previous basis
    minimize(Feas)                    ! Re-solve the LP-problem

    variation:= abs(x.sol-oldxval)    ! Change in dx
  end-do
 
end-procedure 

end-model


Back to examples browserPrevious exampleNext example