| |||||||||||||||
| |||||||||||||||
|
Outer approximation for quadratic facility location: solving different problem types in sequence Description A quadratic facility location problem is formulated and solved as an MIQP problem (quadfacloc.mos) and via an outer approximation algorithm that iterates over MIP and QP subproblems (quadfaclocoa.mos). Difficulty rating: 4 (medium-difficult)
Source Files By clicking on a file name, a preview is opened at the bottom of this page.
quadfaclocoa.mos
(!*********************************************************************
Mosel NL examples
=================
file quadfaclocoa.mos
`````````````````````
Quadratic Facility Location model
Model of a quadratic facility location problem solved
by outer approximation (main problem: MIP, subproblem: QP).
The goal is to assign facilities to customers to minimize cost.
Original AMPL model by Sven Leyffer, see
https://www.researchgate.net/publication/2827082_Solving_Mixed_Integer_Nonlinear_Programs_by_Outer_Approximation
(c) 2018 Fair Isaac Corporation
author: Z.Csizmadia, Sven Leyffer, Aug. 2018, rev. Apr.2021
*********************************************************************!)
model QuadFacLocOA
uses "mmxprs", "mmnl", "mmsystem"
parameters
ILIM = 100
end-parameters
forward procedure printsol
declarations
Iter: integer
end-declarations
declarations
I = 1..5 ! Set of facilities
J = 1..10 ! Set of customers
FacX,FacY: array(I) of real ! X/Y coordinates of facility location
CustX,CustY: array(J) of real ! X/Y coordinates of customer location
C: array(I) of real ! Fixed cost of opening facility at location
Q: array(I,J) of real ! Quadr. cost of meeting demand j from facility i
UBD,LBD: real ! Upper/lower bound on solution
end-declarations
! **** Generate random data:
! **** Cost coefficients and coordinates of all facility + customer locations
setrandseed(42)
SCALE:=100
forall(i in I) do
C(i) := SCALE*100*random
FacX(i) := SCALE*random
FacY(i) := SCALE*random
end-do
forall(j in J) do
CustX(j) := SCALE*random
CustY(j) := SCALE*random
end-do
forall(i in I, j in J) ! Formula used by Lee to create instances
Q(i,j) := 50 * sqrt( (FacX(i) - CustX(j))*(FacX(i) - CustX(j)) +
(FacY(i) - CustY(j))*(FacY(i) - CustY(j)))
! **** Optimization model formulation ****
declarations
eta: mpvar ! Linearization of quad. objective terms
x: array(I,J) of mpvar ! Percentage of customer j served by facility j
z: array(I) of mpvar ! =1, iff facility i built
LastPoint: array(I) of real ! Latest discrete solution values from main
LastMain: real ! Latest obj solution value for main problem
LastX: array(I,J) of real ! Latest 'x' solution values from subproblem
LastSub: real ! Latest obj solution value for subproblem
end-declarations
! **** Main problem (MIP)
declarations
MainProb: mpproblem
end-declarations
with MainProb do
declarations
LinCost: linctr
end-declarations
eta is_free
! Linearized objective function
LinCost:= sum(i in I) C(i)*z(i)
! After the initial iteration, the objective is changed to this form:
! LinCost:= sum(i in I) C(i)*z(i) + eta
! Variable upper bound (only serve customers from open facilities)
forall(i in I, j in J) x(i,j) <= z(i)
! Meet all customers' demands
forall(j in J) sum(i in I) x(i,j) = 1
forall(i in I) z(i) is_binary
! setparam("xprs_verbose",true)
end-do
! **** Submodel (continuous QP)
declarations
SubNLP: mpproblem
end-declarations
with SubNLP do
declarations
QuadCost: nlctr
Fixings: array(I) of linctr
end-declarations
! Quadratic objective function
QuadCost:= sum(i in I) C(i)*z(i) + sum(i in I, j in J) Q(i,j)*x(i,j)^2;
! Variable upper bound (only serve customers from open facilities)
forall(i in I, j in J) x(i,j) <= z(i)
! Meet all customers' demands
forall(j in J) sum(i in I) x(i,j) = 1
! setparam("xprs_verbose",true)
end-do
! **** Outer approximation algorithm
UBD := 1E20; LBD := -1E20
Iter:= 0; starttime:=gettime
while (LBD < UBD-(SCALE*1E-2) and Iter <= ILIM) do
Iter += 1
with MainProb do
minimize(LinCost)
! writeprob('MainProb_'+Iter,'l')
if getprobstat<>XPRS_OPT then break; end-if
forall(i in I) LastPoint(i) := getsol(z(i))
LastMain := getobjval
end-do
with SubNLP do
forall(i in I) Fixings(i):= z(i) = LastPoint(i) ! Fix discrete variables
minimize(QuadCost)
! writeprob('SubNLP_'+Iter,'l')
forall(i in I, j in J) LastX(i,j) := getsol(x(i,j))
LastSub := getobjval
end-do
with MainProb do
! After the first iteration add the linearization term to the objective
if Iter=1 then LinCost+= eta; end-if
! Linearization of quadratic part
eta >=
sum(i in I, j in J) Q(i,j)*LastX(i,j)^2 + ! Objective value
sum(i in I, j in J) 2*Q(i,j)*LastX(i,j)*(x(i,j) - LastX(i,j)) ! Gradient
end-do
UBD := minlist( UBD, LastSub )
LBD := LastMain
writeln(gettime-starttime, "sec Iter = ", Iter, ": LBD = ", LBD, " UBD = ", UBD)
! Uncomment this line to display intermediate solutions in detail:
! printsol
end-do
if Iter > ILIM then writeln("Iteration limit reached"); end-if
printsol
! **** Display the solution ****
procedure printsol
write("Open Customer locations\nfacility")
forall(j in J) write(formattext("%6d",j))
forall(i in I | LastPoint(i)>0) do
write("\n ", textfmt(i,-8))
forall(j in J) write(formattext("%5.1f%%",LastX(i,j).sol*100))
end-do
writeln
end-procedure
end-model
| |||||||||||||||
| © Copyright 2025 Fair Isaac Corporation. |