Initializing help system before first use

Purchase - Formulating piecewise linear functions


Type: Purchasing with price breaks
Rating: 3 (intermediate)
Description: Using the 'pwlin' construct for formulating continuous piecewise linear cost functions, showing 3 variants
  • list of breakpoint coordinates
  • list of slopes with list X-values of slope changes
  • list of linear segments (using 'pws')
File(s): purchase_pwl.mos, purchase_pwl_graph.mos
Data file(s): purchase.dat

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

   file purchase_pwl.mos
   `````````````````````
   TYPE:         Purchasing with price breaks
   DIFFICULTY:   3
   FEATURES:     MIP problem, using 'pwlin' for piecewise linear function
   DESCRIPTION:  There are three suppliers of a good, and they have quoted 
                 various prices for various quantities of product. We want 
                 to buy at least total cost, yet not buy too much from any 
                 one supplier. Each supplier offers decreasing prices for
                 increased lot size, in the form of incremental discounts.
                 We wish to buy 600 items in total.     
   FURTHER INFO: `Applications of optimization with Xpress-MP teaching 
                 material', Section 2.4 `SOS-2: Purchasing with price breaks';
                 `Applications of optimization with Xpress-MP', 
                 Section 3.4.5 `Special Ordered Sets of type 2'

   (c) 2020 Fair Isaac Corporation
       author: S. Heipcke, July 2020
*******************************************************!)

model "Purchase pwl"
 uses "mmxnlp"

 declarations
  NB = 3
  BREAK1 = 1..NB                     ! Price breaks
  BREAK0 = 0..NB                     ! Price breaks including 0
  SUPPL = 1..3                       ! Suppliers
 
  COST: array(SUPPL,BREAK1) of real  ! Unit cost
  B: array(SUPPL,BREAK0) of real    ! Breakpoints (quantities at which unit 
                                     ! cost changes)
  CB: array(SUPPL,BREAK0) of real   ! Total cost at break points
  MAXPERC: array(SUPPL) of real      ! Maximum percentages for each supplier
  REQ: real                          ! Total quantity required

  buy: array(SUPPL) of mpvar         ! Quantity to purchase from supplier s
  pay: array(SUPPL) of mpvar         ! Cost incurred from supplier s
 end-declarations

 initializations from 'purchase.dat'
  COST B MAXPERC REQ
 end-initializations

! Calculate total cost at breakpoints
 forall(s in SUPPL) do
  CB(s,0):= 0
  forall(b in BREAK1) CB(s,b):= CB(s,b-1) + COST(s,b)*(B(s,b)-B(s,b-1))
 end-do

! Objective: sum of costs*weights
 MinCost:= sum(s in SUPPL) pay(s)

! Define relation between bought quantities and price paid per supplier
 forall(s in SUPPL) 
 ! Formulation of pwlin via breakpoint coordinates 
   pay(s) = pwlin(buy(s), union(b in BREAK0) [B(s,b),CB(s,b)]) 
 ! Formulation of pwlin via slopes
!   pay(s) = pwlin(buy(s), union(b in 1..(NB-1)) [B(s,b)], union(b in BREAK1) [COST(s,b)])
 ! Formulation of pwlin via segments 
!   pay(s) = pwlin(union(b in 0..(NB-1)) [pws(B(s,b),CB(s,b)+COST(s,b+1)*(buy(s)-B(s,b)))]) 

! The minimum quantity that must be bought
 Demand:= sum(s in SUPPL) buy(s) >= REQ

! No more than the maximum percentage from each supplier
 forall(s in SUPPL) buy(s) <= MAXPERC(s)*REQ/100.0

 minimize(MinCost)              ! Solve the MIP-problem

 writeln("Minimum total cost: ", getobjval)
 forall(s in SUPPL) writeln(" buy(",s,"): ", getsol(buy(s)), " cost: ", pay(s).sol)

end-model

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

   file purchase_pwl_graph.mos
   ```````````````````````````
   TYPE:         Purchasing with price breaks
   DIFFICULTY:   3
   FEATURES:     MIP problem, using 'pwlin' for piecewise linear function,
                 graphical representation of data
   DESCRIPTION:  There are three suppliers of a good, and they have quoted 
                 various prices for various quantities of product. We want 
                 to buy at least total cost, yet not buy too much from any 
                 one supplier. Each supplier offers decreasing prices for
                 increased lot size, in the form of incremental discounts.
                 We wish to buy 600 items in total.     
   FURTHER INFO: `Applications of optimization with Xpress-MP teaching 
                 material', Section 2.4 `SOS-2: Purchasing with price breaks';
                 `Applications of optimization with Xpress-MP', 
                 Section 3.4.5 `Special Ordered Sets of type 2'

   (c) 2020 Fair Isaac Corporation
       author: S. Heipcke, July 2020
*******************************************************!)

model "Purchase pwl graph"
 uses "mmxnlp", "mmsvg"

 declarations
  NB = 3
  BREAK1 = 1..NB                     ! Price breaks
  BREAK0 = 0..NB                     ! Price breaks including 0
  SUPPL = 1..3                       ! Suppliers
 
  COST: array(SUPPL,BREAK1) of real  ! Unit cost
  B: array(SUPPL,BREAK0) of real    ! Breakpoints (quantities at which unit 
                                     ! cost changes)
  CB: array(SUPPL,BREAK0) of real   ! Total cost at break points
  MAXPERC: array(SUPPL) of real      ! Maximum percentages for each supplier
  REQ: real                          ! Total quantity required

  buy: array(SUPPL) of mpvar         ! Quantity to purchase from supplier s
  pay: array(SUPPL) of mpvar         ! Cost incurred from supplier s
 end-declarations

 initializations from 'purchase.dat'
  COST B MAXPERC REQ
 end-initializations

! **** Graphical representation of data ****

! Calculate total cost at breakpoints
 forall(s in SUPPL) do
  CB(s,0):= 0
  forall(b in BREAK1) CB(s,b):= CB(s,b-1) + COST(s,b)*(B(s,b)-B(s,b-1))
 end-do

 FACT:=100
 svgsetgraphviewbox(0, 0, max(s in SUPPL) B(s,NB), 2*FACT*max(s in SUPPL,b in BREAK1) COST(s,b)+1)
 svgsetgraphlabels("Units","Cost per unit")
 svgsetgraphstyle(SVG_STROKEWIDTH,5)
 forall(s in SUPPL) do
  svgaddgroup("SG"+s, "Supplier "+s)
  ! Unit cost graph per supplier
  svgaddline(union(b in BREAK1) [B(s,b-1), FACT*COST(s,b), B(s,b), FACT*COST(s,b)]) 
  ! Total cost scaled to fit into unit cost graph 
!  svgaddline(union(b in BREAK1) [B(s,b-1), CB(s,b-1)/5, B(s,b), CB(s,b)/5])
 end-do

! Objective: sum of costs*weights
 MinCost:= sum(s in SUPPL) pay(s)

! Define relation between bought quantities and price paid per supplier
 forall(s in SUPPL) 
 ! Formulation of pwlin via breakpoint coordinates 
!   pay(s) = pwlin(buy(s), union(b in BREAK0) [B(s,b),CB(s,b)]) 
 ! Formulation of pwlin via slopes
!   pay(s) = pwlin(buy(s), union(b in 1..(NB-1)) [B(s,b)], union(b in BREAK1) [COST(s,b)])
 ! Formulation of pwlin via segments 
   pay(s) = pwlin(union(b in 0..(NB-1)) [pws(B(s,b),CB(s,b)+COST(s,b+1)*(buy(s)-B(s,b)))]) 

! The minimum quantity that must be bought
 Demand:= sum(s in SUPPL) buy(s) >= REQ

! No more than the maximum percentage from each supplier
 forall(s in SUPPL) buy(s) <= MAXPERC(s)*REQ/100.0

 minimize(MinCost)              ! Solve the MIP-problem

 writeln("Minimum total cost: ", getobjval)
 forall(s in SUPPL) writeln(" buy(",s,"): ", getsol(buy(s)), " cost: ", pay(s).sol)

 svgsave("purchase.svg")
 svgrefresh
 svgwaitclose("Close browser window to terminate model execution.", 1)
end-model

© 2001-2023 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.