Quantcast
Channel: Yet Another Math Programming Consultant
Viewing all articles
Browse latest Browse all 809

Transportation model with some non-existing links

$
0
0

I am again looking at simple models based on the transportation model:

Dense Transportation Model
\[\begin{align}\min&\sum_{i,j}\color{darkblue}c_{i,j}\cdot\color{darkred}x_{i,j}\\ & \sum_j \color{darkred}x_{i,j} \le \color{darkblue}a_i && \forall i \\& \sum_i \color{darkred}x_{i,j} \ge \color{darkblue}b_j && \forall j \\ & \color{darkred}x_{i,j} \ge 0 \end{align}\]


This is a good time to discuss what happens when some links can not be used. When a significant number of links cannot be used, the underlying bipartite graph is called sparse. Let's discuss some of the approaches often used to handle this.

  • Use a dense formulation with a large cost coefficient \(\color{darkblue}c_{i,j}=99999\) if the link \(i\rightarrow j\) should not be used. This is my least favorite approach. We need to invent a large penalty cost (should we use 99999 or 999999 or something even more extreme?). This may make the problem poorly scaled.
  • Use a dense formulation, but fix \(\color{darkblue}x_{i,j}=0\) for the non-existing links. The solver will remove these fixed variables in the presolve phase before starting to iterate.
    • In GAMS we can add to this model.holdfixed=1;. This will remove all fixed variables from the model even before passing on the model to the solver.
  • Use a sparse formulation, where don't even generate the non-existing links. I.e. only generate \(\color{darkblue}x_{i,j}\) for existing links. This is my favorite approach. It is the most work, but it is also the most explicit. 

When creating a larger dense problem, we stress the system at different points:
  • During model generation
  • The solver receives a larger model
  • Hopefully, it can presolve things away
  • The solver has to re-insert solution values during postsolve
  • The modeling system receives a larger solution
Should we really worry about this, or should we pick the simplest approach? One way to weigh these things is to look at the performance. Warning: this is an extremely simple and easy-to-solve LP, and the situation may be dramatically different for a complex, difficult MIP model. 

I set up the following scenario: 
  • 500 supply nodes
  • 500 demand nodes
  • 80% of the arcs are removed

 The results are:

 

----    132 PARAMETER results  performance comparison

c x.fx holdfixed sparse

Variables 250001.000250001.00049667.00049667.000
Equations 1001.0001001.0001001.0001001.000
Nonzero elem. 750001.000549667.000148999.000148999.000
Modelstat Optimal Optimal Optimal Optimal
Objective 12015.21812015.21812015.21812015.218
Generation time 0.2420.3010.1580.096
Solver time 0.4680.3310.1070.112
Iterations 967.0001351.0001351.0001351.000


Unexpectedly the first method needs the fewest iterations. The models holdfixed and sparse are almost identical (which makes sense) and are the winners. In general, however, timings are just quite good for this model.


Appendix: GAMS Model


$onText


  
Three different ways to implement a sparse bipartite graph (transportation problem).

  
1. Dense with large cost on non-existsing links
  
2. Dense with fixing x.fx(i,j)=0 when link (i,j) does not exist
  
2a. Id with model.holdfixed.
  
3. Don't even generate the variables x(i,j) when i->j is missing. (my preferred way)


$offtext

set
   i
'supply nodes'/sup1*sup500/
   j
'demand nodes'/dem1*dem500/
   link(i,j) 
'allowed links'
;

alias(i,ii),(j,jj);

* sparse network
* increase fraction if infeasible
link(i,j) = uniform(0,1)<0.2;

scalar totsupdem 'total supply and demand'/10000/;

parameter
   capacity(i)
   demand(j)
;
* we try to generate a balanced transportation problem
* where sum(demand) = sum(supply) = 10000
capacity(i) = uniform(0,1);
capacity(i) = totsupdem*capacity(i)/
sum(ii,capacity(ii));

demand(j) = uniform(0,1);
demand(j) = totsupdem*demand(j)/
sum(jj,demand(jj));

parameter c(i,j) 'unit transportation cost';
c(i,j) = 1e6;
c(link) = uniform(1,10);

*-------------------------------------------------------------------------------
* reporting macro
*-------------------------------------------------------------------------------

acronym Optimal;

parameter results(*,*) 'performance comparison';
$macro collect(m,id) \
     results(
'Variables',id) = m.numvar; \
     results(
'Equations',id) = m.numequ; \
     results(
'Nonzero elem.',id) = m.numnz; \
     results(
'Modelstat',id) = m.modelstat; \
     results(
'Modelstat',id)$(m.modelstat=1) = Optimal; \
     results(
'Objective',id) = m.objval; \
     results(
'Generation time',id) = m.etSolve-m.etSolver; \
     results(
'Solver time',id) = m.etSolver; \
     results(
'Iterations',id) = m.iterusd;




*-------------------------------------------------------------------------------
*
* (1) c(i,j)=99999 for links that don't exist
*
*-------------------------------------------------------------------------------

variable z 'total cost';
positivevariable x(i,j) 'shipment from i->j';

equations
    objective
    eDemand(j)  
'meet demand'
    eCapacity(i)
"don't exceed capacity"
;

objective..     z =e=
sum((i,j), c(i,j)*x(i,j));
eDemand(j)..   
sum(i, x(i,j)) =e= demand(j);
eCapacity(i).. 
sum(j, x(i,j)) =e= capacity(i);

model m1 /all/;
* no printing to listing file
m1.solprint = %solprint.Silent%;
solve m1 minimizing z using lp;

collect(m1,
'c')

*-------------------------------------------------------------------------------
*
* (2) x.fx(i,j)=0 if link does not exist
*
*-------------------------------------------------------------------------------

x.fx(i,j)$(
not link(i,j)) = 0;
c(i,j)$(
not link(i,j))= 0;
option bratio=1;
solve m1 minimizing z using lp;

collect(m1,
'x.fx')


*-------------------------------------------------------------------------------
*
* (2a)holdfixed
*
*-------------------------------------------------------------------------------

m1.holdfixed=1;
solve m1 minimizing z using lp;

collect(m1,
'holdfixed')

*-------------------------------------------------------------------------------
*
* (3) sparse
*
*-------------------------------------------------------------------------------

equations
    objective2
    eDemand2(j)  
'meet demand'
    eCapacity2(i)
"don't exceed capacity"
;

objective2..     z =e=
sum(link, c(link)*x(link));
eDemand2(j)..   
sum(link(i,j), x(link)) =e= demand(j);
eCapacity2(i).. 
sum(link(i,j), x(link)) =e= capacity(i);

model m2 /all-m1/;
m2.solprint = %solprint.Silent%;
solve m2 minimizing z using lp;

collect(m2,
'sparse')

display results;


Viewing all articles
Browse latest Browse all 809

Trending Articles