Initializing help system before first use

Using multi-objective solving


Type: Goal Programming
Rating: 3 (intermediate)
Description: lexgoalprog.mos: lexicographic goal programming for solving a small production planning example
  • configuration of multiple objectives via 'objconfig' constructors in list form
  • list combining 'mpvar' and 'linctr' types
  • detailed status check via XPRS_SOLVESTATUS and XPRS_SOLSTATUS
markowitzmo.mos: Markowitz portfolio optimization, multi-objective quadratic programming example
  • list combining 'nlctr' and 'linctr' types
  • display of the optimal frontier as SVG graph
multiobjknapsack.mos: Knapsack problem with two objectives
  • configuration of multiple objectives in array structure using priorities
  • multi-objective logging settings
File(s): lexgoalprog.mos, markowitzmo.mos, multiobjknapsack.mos


lexgoalprog.mos
(!*******************************************************
   Mosel Example Problems
   ======================

   file lexgoalprog.mos
   ````````````````````
   An example of lexicographic goal programming using the 
   Xpress multi-objective functionality

   Problem description:
   A company produces two electrical products, A and B. Both require
   two stages of production: wiring and assembly. 
   The production plan must meet several goals:
   1. A profit of $200
   2. A contractual requirement of 40 units of product B
   3. To fully utilize the available wiring department hours
   4. To avoid overtime in the assembly department

   (c) 2022 Fair Isaac Corporation
       author: S. Heipcke, June 2022
  *******************************************************!)
model "lexGP" 
 uses "mmxprs"

 public declarations
  ! Decision variables for the number of products to make of each type
   produceA,produceB: mpvar
  ! Deviational variables:
  ! There is a penalty for both under- and over-utilizing each department
   surfeit_wiring, deficit_wiring: mpvar
   surfeit_assembly, deficit_assembly: mpvar
  ! There is no penalty for surfeit in profit or in production of product B, 
  ! only for deficits
   deficit_profit, deficit_productB: mpvar
   Goals: list of linctr or mpvar    ! or also:  list of any
 end-declarations

 produceA is_integer; produceB is_integer

 ! **** Production constraints:
 ! Meet or exceed profit goal of $200
 ! Profit for products A and B are $7 and $6 respectively
 Profit:= 7 * produceA + 6 * produceB 
 Profit + deficit_profit >= 200
 ! Meet or exceed production goal for product B
 produceB + deficit_productB >= 40
 ! Utilize wiring department:
 ! Products A and B require 2 and 3 hours of wiring, 120 hours are available
 2 * produceA + 3 * produceB - surfeit_wiring + deficit_wiring = 120
 ! Utilize assembly department:
 ! Products A and B require 6 and 5 hours of assembly, 300 hours are available
 6 * produceA + 5 * produceB - surfeit_assembly + deficit_assembly = 300

 ! Objective configuration
 Goals:=[deficit_profit, deficit_productB, surfeit_wiring + deficit_wiring,
         surfeit_assembly + deficit_assembly]
(!  Cfg:= [objconfig("priority=4 abstol=0 reltol=0"),
         objconfig("priority=3 abstol=0 reltol=0"),
         objconfig("priority=2 abstol=0 reltol=0"),
         objconfig("priority=1 abstol=0 reltol=0")] !)
 ! Same as:
 forall(i in 1..4) Cfg+=[objconfig(5-i,1,0,0)]

 ! Uncomment this line to try out the effect of inversing priority order:
 ! forall(i in 1..4) Cfg(i).priority:=i
 
! setparam("XPRS_VERBOSE", true)

 ! Minimize deviations, in priority order
 minimize(Goals,Cfg)

 ! **** Solution reporting
 declarations
   SolStat,SolvStat: array(integer) of string    ! Status messages
 end-declarations

 SolvStat:: ([XPRS_SOLVESTATUS_UNSTARTED, XPRS_SOLVESTATUS_STOPPED, 
   XPRS_SOLVESTATUS_FAILED, XPRS_SOLVESTATUS_COMPLETED])  
  ["The solve has not been started.", "Optimization has been interrupted.",
   "Optimization has run into a nonrecoverable problem and failed.",
   "Search completed."] 

 SolStat:: ([XPRS_SOLSTATUS_NOTFOUND, XPRS_SOLSTATUS_OPTIMAL, 
   XPRS_SOLSTATUS_FEASIBLE, XPRS_SOLSTATUS_INFEASIBLE, XPRS_SOLSTATUS_UNBOUNDED])
  ["No solution available.", "An optimal solution has been found.",
   "A solution that is not proven optimal is found.",
   "No solution exists.", "The problem is unbounded, if feasible."]

 writeln("Problem solve status: ", SolvStat(getparam("XPRS_SOLVESTATUS")), 
         " Solution status: ", SolStat(getparam("XPRS_SOLSTATUS")), 
         " Objectives solved: ", getparam("XPRS_SOLVEDOBJS"))
 if getparam("XPRS_SOLVESTATUS")=XPRS_SOLVESTATUS_COMPLETED and
    getparam("XPRS_SOLSTATUS")=XPRS_SOLSTATUS_OPTIMAL and
    getparam("XPRS_SOLVEDOBJS")=4 then
   writeln('Production plan:')
   writeln('Product A: ', produceA.sol, ' units')
   writeln('Product B: ', produceB.sol, ' units')
   writeln('Profit: $', Profit.sol)

   if deficit_profit.sol > 0: 
     writeln('Profit goal missed by $', deficit_profit.sol)
   if deficit_profit.sol > 0:
     writeln('Profit goal missed by $', deficit_profit.sol)
   if deficit_productB.sol > 0:
     writeln('Contractual goal for product B missed by ', deficit_productB.sol, ' units')
   if surfeit_wiring.sol > 0:
     writeln('Unused wiring department hours: ', surfeit_wiring.sol)
   if deficit_wiring.sol > 0:
     writeln('Wiring department overtime: ', deficit_wiring.sol)
   if surfeit_assembly.sol > 0:
     writeln('Unused assembly department hours: ', surfeit_assembly.sol)
   if deficit_assembly.sol > 0:
     writeln('Assembly department overtime: ', deficit_assembly.sol)
 else
   writeln('Problem could not be solved')
 end-if
end-model  


markowitzmo.mos
(!*******************************************************
   Mosel Example Problems
   ======================

   file markowitzmo.mos
   ````````````````````
    Markowitz portfolio optimization
    A multi-objective quadratic programming example
    -- Display of the optimal frontier as SVG graph --

    In Markowitz portfolio optimization there are two objectives: 
    to maximize reward while minimizing risk (i.e. variance). 
    This example plots several points on the optimal frontier using 
    a blended multi-objective approach, and shows that a point
    computed using a lexicographic approach also lies on this frontier.

   (c) 2022 Fair Isaac Corporation
       author: S. Heipcke, June 2022
  *******************************************************!)
model "markowitzmo (SVG)"
 uses "mmxnlp", "mmsvg"

 declarations
  STOCKS = 1..5                      ! Set of 5 stocks
  RET: array(STOCKS) of real         ! Historical mean return on investment 
  COV: array(STOCKS,STOCKS) of real  ! Historical covariances of the stocks
  x: array(STOCKS) of mpvar          ! Percentage of capital to invest in stocks
  Goals: list of linctr or nlctr     ! Objective functions
  ObjCfg: list of objconfig          ! Configuration of objectives 
 end-declarations

 RET::[0.31, 0.87, 0.31, 0.66, 0.24]
 COV::[0.32,  0.70,  0.19,  0.52,  0.16,
       0.70,  4.35, -0.48, -0.06, -0.03,
       0.19, -0.48,  0.98,  1.10,  0.10,
       0.52, -0.6,   1.10,  2.48,  0.37,
       0.16, -0.3,   0.10,  0.37,  0.31]

! Constraints:
! Must invest 100% of capital
 sum(i in STOCKS) x(i) = 1

! Objectives:
! Total expected return
 Return:= sum(i in STOCKS) RET(i)*x(i)
 Variance:= sum(i,j in STOCKS) x(i)*x(j)*COV(i,j)
! List of objectives
 Goals:=[Return, Variance]

! setparam("XPRS_VERBOSE", true)

! Vary the objective weights to explore the optimal frontier
 declarations
   POINTS: range
   SOLMEAN: array(POINTS) of real
   SOLVAR: array(POINTS) of real
 end-declarations
 SCALEX:=10

 forall(p in 0..20, w=p/20.0+if(p=0,0.0001,if(p=20,-0.0001,0))) do
  ! Negative weight to minimize variance
  ! maximize(Goals,[objconfig(0,w),objconfig(0,w-1)])
 ! Same as:
   maximize(Goals,[objconfig("weight",w),objconfig("weight",w-1)])
   if getprobstat=XPRS_OPT then
     SOLMEAN(p):=Return.sol
     SOLVAR(p):=Variance.sol
     writeln("Solution for w=", w, ": ", SOLMEAN(p), " / ", SOLVAR(p))
   else
     writeln("No solution for w=", w)
   end-if
 end-do

! Now we will maximize profit alone, and then minimize variance while not
! sacrificing more than 10% of the maximum profit
 ObjCfg:=[objconfig("priority=1 weight=1 reltol=0.1"), 
          objconfig("priority=0 weight=-1")]
! Same as:
! ObjCfg:=[objconfig(1,1,0.001,0.1), objconfig(0,-1)]
! or:
! ObjCfg:=[objconfig(1,1,0.001,0.1), objconfig("weight",-1)]
!)
 maximize(Goals,ObjCfg)
 m0:=Return.sol
 v0:=Variance.sol
 writeln("Solution for config=", ObjCfg, ":\n", strfmt("",20), m0, " / ", v0)

! Plot the optimal frontier and mark the individual point that we calculated
 svgaddgroup("GrS", "Variance vs mean return", 'grey')
 svgsetstyle(SVG_STROKEWIDTH, 0.25)
 svgaddgroup("GrM", "Max profit, then variance", 'darkred')

 forall(p in POINTS) svgaddpoint("GrS", SOLMEAN(p)*SCALEX, SOLVAR(p))
 svgaddline("GrS", sum(p in POINTS) [SOLMEAN(p)*SCALEX, SOLVAR(p)])

 svgaddpoint("GrM", m0*SCALEX,v0)
 svgaddtext("GrS",0.5,8, 'Return on investment vs variance')
 svgsetstyle(svggetlastobj, SVG_COLOR, SVG_BLACK)
 svgsetstyle(svggetlastobj, SVG_FONTSIZE, "5px")
 svgsetgraphscale(10)
 svgsetgraphviewbox(0,0,9,9)
 svgsetgraphpointsize(0.5)
 svgsetgraphlabels('Expected return', 'Variance')

! Optionally save graphic to file
 svgsave("markowitz.svg")

! Display the graph and wait for window to be closed by the user 
 svgrefresh
 svgwaitclose("Close browser window to terminate model execution.", 1)
end-model

multiobjknapsack.mos
(!*******************************************************
   Mosel Example Problems
   ======================

   file multiobjknapsack.mos
   `````````````````````````
   Multi-objective knapsack example

   (c) 2022 Fair Isaac Corporation
       author: S. Heipcke, June 2022
  *******************************************************!)
model "multiobjknapsack"
 uses "random", "mmxprs"
 
 parameters
   N = 15            ! Number of items
   NOBJ = 2          ! Number of goals
   MAXW = 10         ! Maximum weight that can be carried
 end-parameters

 declarations
   R=1..N                              ! Set of items
   WEIGHT: array(R) of real            ! Weight per item
   OBJS = 1..NOBJ                      ! Set of objectives
   VALUE: array(OBJS,R) of real        ! Value of items for each objective
   take: array(R) of mpvar             ! Whether to select an item
   TotValue: array(OBJS) of linctr     ! Objective functions (goals)
   ObjCfg: array(OBJS) of objconfig    ! Configuration of objectives
 end-declarations

! Generate random weights and two random value metrics
 setmtrandseed(123)
 forall(i in R) WEIGHT(i):= mtrand_int(1, 4)
 forall(o in OBJS, i in R) VALUE(o,i):= mtrand_int(1, 6)

! Decision variables for each item
 forall(i in R) take(i) is_binary

! Total weight cannot exceed maximum weight
 WLimit:= sum(i in R) WEIGHT(i)*take(i) <= MAXW

! Define the objectives
 forall(o in OBJS) TotValue(o):= sum(i in R) VALUE(o,i)*take(i)
! Configuration of multiple objectives: 
! * Distinct priority values: solved as pre-emptive multi-obj problem where
!   a higher value indicates higher priority, that is, to be treated earlier 
! * Equal priority values: solved as Archimedian multi-obj problem
 ObjCfg(1).priority:=2
 ObjCfg(2).priority:=1

! Solve the problem
 setparam("XPRS_VERBOSE", true)         ! Enable solver logging
 setparam("XPRS_MULTIOBJLOG", 1)        ! Configure multi-objective logging: 
                                        ! 0=none, 1=summary, 2=detailed
 maximise(TotValue,ObjCfg)

! Solution reporting
! if getprobstat=XPRS_OPT and getparam("XPRS_SOLVEDOBJS")=NOBJ then
 if getparam("XPRS_SOLVESTATUS")=XPRS_SOLVESTATUS_COMPLETED and
    getparam("XPRS_SOLSTATUS")=XPRS_SOLSTATUS_OPTIMAL then
   writeln('Problem was solved to optimality.')
   write('Items selected:')
   forall(i in R | take(i).sol=1) write(i, ' ')
   writeln("\nTotal weight:", WLimit.act)
   writeln('First objective:', TotValue(1).sol)
   writeln('Second objective:', TotValue(2).act)
 elif getprobstat=XPRS_INF and getparam("XPRS_SOLVEDOBJS")=1 then
   writeln('Failed to solve first objective.')
 else
   writeln('Solved first objective but failed to solve second objective.')
 end-if

end-model

© 2001-2025 Fair Isaac Corporation. All rights reserved. This documentation is the property of Fair Isaac Corporation (“FICO”). Receipt or possession of this documentation does not convey rights to disclose, reproduce, make derivative works, use, or allow others to use it except solely for internal evaluation purposes to determine whether to purchase a license to the software described in this documentation, or as otherwise set forth in a written software license agreement between you and FICO (or a FICO affiliate). Use of this documentation and the software described in it must conform strictly to the foregoing permitted uses, and no other use is permitted.