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

Nonlinear objective with integer decision variables

Description
The examples describe problems with a nonlinear objective function and some integer decision variables.
  1. A craftsman wants to optimise its revenue based on the size of the produced wooden boxes (boxes02.mos)
  2. Dealers sell apples at a market at the same price and the game is to find the quantity sold and the associated price (pricechange.mos).


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





pricechange_graph.mos

(!*********************************************************************
   Mosel NL examples
   =================
   file pricechange_graph.mos
   ``````````````````````````
   Five dealers in adjacent stalls at a market were selling apples
   of identical quality, so they had to keep their prices equal. At the
   end of the day every dealer had sold a different number of apples, 
   yet all had taken in the same total.
   How much did they charge and how much did they take in, assuming
   that all prices were integer values?  
   Note: The problem is possible only if the price was changed during
   the course of the day. We minimize the number of price changes.

   Based on AMPL model pchange.mod by M.J.Chlond
   Reference: M. Kraitchik, Mathematical Recreations (p. 33-35), Dover

   - Graphical representation of results -   

   (c) 2013 Fair Issac Corporation
       author: S. Heipcke, Mar. 2013, rev. Dec. 2017
*********************************************************************!)
  
model "pricechange"
 uses "mmxnlp", "mmsystem", "mmsvg"

 parameters
   NP = 4                               ! Maximum number of price changes
   MAXPRICE = 10                        ! Highest permissible price
 end-parameters  

 forward procedure print_sol
 forward procedure draw_sol(title: text, offset: real, iter: integer)

 declarations
  DEALERS: set of string                ! Dealers
  PRICES = 1..NP                        ! Prices
  NSOLD: array(DEALERS) of real         ! Total number sold by each dealer
  sell: array(DEALERS,PRICES) of mpvar  ! Number sold by dealer i at price j
  price: array(PRICES) of mpvar	        ! Price j (i.e. first and second prices)
  pchange: array(PRICES) of mpvar       ! 1 iff price j and j+1 are different
  totalrev: mpvar                       ! Total revenu per dealer
 end-declarations

 NSOLD:: (["Mr.Brown","Mrs.White","Mr.Black","Mr.Grey","Ms.Violet"])[10, 25, 30, 15, 35]
   !  More difficult: [10, 25, 30, 12, 35]
   !  Easy: [10, 25, 30, 15, 35]
 finalize(DEALERS)

 forall(i in DEALERS,p in PRICES) do
  sell(i,p)<=NSOLD(i)
  sell(i,p) is_integer
 end-do

 forall(p in PRICES) do
  price(p)>=1
  price(p)<=MAXPRICE
  price(p) is_integer
  pchange(p) is_binary
 end-do

! Quantities sold
 forall(i in DEALERS) NSOLD(i) = sum(p in PRICES) sell(i,p)

! All dealers take in the same
 forall(i in DEALERS)
  sum(p in PRICES) (price(p)*sell(i,p)) = totalrev

! Direction of price changes (symmetry breaking)
 price(2) >= price(1)+1

! Counter the number of price changes
 forall(p in PRICES | p>1) price(p) >= price(p-1)+pchange(p)
 forall(p in PRICES | p>1) price(p)-price(p-1) <= MAXPRICE*pchange(p)

! Solve the problem
 setparam("xnlp_verbose",true) 

! Obj 1: Minimize total span of prices
 MaxDiff:= price(NP)-price(1)

! Obj2 : Minimize number of price changes
 TotalChanges:= sum(p in PRICES | p>1) pchange(p)

! Scale the size of the displayed graph
 svgsetgraphscale(5)

! Solve the problem for the different objectives
 minimize(MaxDiff)
 print_sol
 draw_sol("Obj 1 (rev="+totalrev.sol+")", 0, 1)

 minimize(TotalChanges)
 print_sol
 draw_sol("Obj 2 (rev="+totalrev.sol+")", 0.2, 2)

! Obj3 + 4 : Minimize + maximize total revenue per dealer
 minimize(totalrev)
 print_sol
 draw_sol("Obj 3 (rev="+totalrev.sol+")", 0.4, 3)

 maximize(totalrev)
 print_sol
 draw_sol("Obj 4 (rev="+totalrev.sol+")", 0.6, 4)

 svgsave("pricechange.svg")
 svgwaitclose("Close browser window to terminate model execution.", 1)

!**************** Solution printing ****************
 procedure print_sol
  nlstat:=getparam("XNLP_STATUS")
  if nlstat<>XNLP_STATUS_LOCALLY_OPTIMAL and nlstat<>XNLP_STATUS_OPTIMAL then
   writeln("No solution found.")
  else   
   writeln("Number of price changes: ", TotalChanges.sol)
   writeln("Amplitude of prices: ", MaxDiff.sol)
   writeln("Total revenue per dealer: ", totalrev.sol)
   writeln("Quantities sold: ")
   writeln(" "*(21+round(TotalChanges.sol)), "Quantity at prices")
   write("Dealer      TotalQty")
   forall(p in PRICES | p=1 or pchange(p).sol>0) 
     write(strfmt(price(p).sol,5),"/kg")
   writeln("\n", "-"*(22+(round(TotalChanges.sol)+1)*8))
   forall(i in DEALERS) do
    write(strfmt(i,-9), strfmt(NSOLD(i),9), "  ")
    forall(p in PRICES | p=1 or pchange(p).sol>0)
     write(strfmt(sum(q in PRICES | price(q).sol=price(p).sol) 
      round(sell(i,q).sol),8))
    writeln
   end-do   
   writeln("-"*(22+(round(TotalChanges.sol)+1)*8))
  end-if
 end-procedure

!**************** Graphical representation of results ****************

 procedure draw_sol(title: text, offset: real, iter: integer)
  nlstat:=getparam("XNLP_STATUS")
  if nlstat=XNLP_STATUS_LOCALLY_OPTIMAL or nlstat=XNLP_STATUS_OPTIMAL then
   SCALE:=10
   svgsetgraphviewbox(0,-4,SCALE*(DEALERS.size+2),MAXPRICE*min(i in DEALERS) NSOLD(i)+10)
   svgsetgraphlabels("","Total sales prices per dealer")

 ! Draw the total revenue
   svgaddgroup("plotr"+iter, title, svgcolor(200,25,25))
   svgaddline(0, totalrev.sol, SCALE*(DEALERS.size+1), totalrev.sol)
   svgaddtext(SCALE*(DEALERS.size+1)+1, totalrev.sol-1, "Iteration "+iter)
 
 ! Draw a bar chart with the quantity sold per price for every dealer
   if iter=1 then
     forall(p in 1..MAXPRICE) do  
       svgaddgroup("P"+p, string(p)+"$/kg", svgcolor(25*p,100-5*p,250-25*p))
       writeln( svgcolor(25*p,100-5*p,250-25*p))
       svgsetstyle(SVG_FILL,SVG_CURRENT)
     end-do
     svgaddgroup("D", "Dealers", SVG_BLACK)
     svgsetstyle(SVG_FONTSIZE,"xx-small")
     forall(i in DEALERS, ct as counter)
       svgaddtext(SCALE*(ct-0.4+offset), -2, i)
     ct:=0
   end-if

   forall(i in DEALERS, ct as counter) do
     totd:=0
     forall(p in PRICES | p=1 or pchange(p).sol>0) do
       totq:=sum(q in PRICES | price(q).sol=price(p).sol) round(sell(i,q).sol*price(p).sol)
       if totq>0 then
         pv:=round(price(p).sol)
      	 svgaddrectangle("P"+pv, SCALE*(ct-0.4+offset), totd, SCALE*(0.15), totq)
      	 totd+=totq
       end-if	
     end-do
   end-do

   svgrefresh
  end-if

 end-procedure

end-model

Back to examples browserPrevious exampleNext example