I solve the supply chain optimisation problem with building factories and warehouses. First, I wrote a project using standard CPLEX tools:
.mod:
int l = ...;
int n = ...;
int t = ...;
int m = ...;
range j = 1..m;
range i = 1..n;
range h = 1..l;
range e = 1..t;
int D[j] = ...;
int K[i] = ...;
int S[h] = ...;
int W[e] = ...;
float F[i] = ...;
float f[e] = ...;
float c1[h][i] = ...;
float c2[i][e] = ...;
float c3[e][j] = ...;
dvar boolean y1[i];
dvar boolean y2[e];
dvar int+ x1[e][j];
dvar int+ x2[i][e];
dvar int+ x3[h][i];
minimize
sum(I in i) (F[I] * y1[I]) +
sum(E in e) (f[E] * y2[E]) +
sum(H in h, I in i) (c1[H][I] * x3[H][I]) +
sum(I in i, E in e) (c2[I][E] * x2[I][E]) +
sum(E in e, J in j) (c3[E][J] * x1[E][J]);
subject to {
forall(H in h)
sum(I in i) x3[H][I] <= S[H];
forall(I in i)
sum(H in h) (x3[H][I]) - sum(E in e) (x2[I][E]) >= 0;
forall(I in i)
sum(E in e) x2[I][E] <= K[I] * y1[I];
forall(E in e)
sum(I in i) (x2[I][E]) - sum(J in j) (x1[E][J]) >= 0;
forall(E in e)
sum(J in j) x1[E][J] <= W[E] * y2[E];
forall(J in j)
sum(E in e) x1[E][J] == D[J];
}
.dat:
l = 3; //number of suppliers
n = 4; //number of potential factory locations
t = 5; //number of potential warehouse locations
m = 7; //number of markets or demand points
SheetConnection sheet("Task.xlsx");
D from SheetRead(sheet, "PWL!b26:h26"); //annual demand from customer
K from SheetRead(sheet, "PWL!h12:h15"); //potential capacity of factory at site
S from SheetRead(sheet, "PWL!f4:f6"); //supply capacity at supplier
W from SheetRead(sheet, "PWL!j21:j25"); //potential warehouse capacity at site
F from SheetRead(sheet, "PWL!g12:g15"); //fixed cost of locating a plant at site
f from SheetRead(sheet, "PWL!i21:i25"); //fixed cost of locating a warehouse at site
c1 from SheetRead(sheet, "PWL!b4:e6"); //cost of shipping one unit from supply source to factory
c2 from SheetRead(sheet, "PWL!b12:f15"); //cost of producing and shipping one unit from factory to warehouse
c3 from SheetRead(sheet, "PWL!b21:h25"); // cost of shipping one unit from warehouse to customer
x3 to SheetWrite(sheet, "PWL!m4:p6"); //quantity shipped from warehouse to market
x2 to SheetWrite(sheet, "PWL!m12:q15"); //quantity shipped from factory to warehouse
x1 to SheetWrite(sheet, "PWL!m21:s25"); //quantity shipped from supplier to factory at site
y1 to SheetWrite(sheet, "PWL!r12:r15"); //1 if factory is located at site i, 0 otherwise
y2 to SheetWrite(sheet, "PWL!t21:t25"); //1 if warehouse is located at site e, 0 otherwise
Then I was faced with the task of properly converting this code to CP, given its peculiarities, and I wrote the following:
.dat:
nSuppliers = 3;
nFactories = 4;
nWarehouses = 5;
nMarkets = 7;
suppliers = {
<0, 350>,
<1, 290>,
<2, 310>
};
factories = {
<0, 350, 450000>,
<1, 280, 500000>,
<2, 400, 450000>,
<3, 300, 450000>
};
warehouses = {
<0, 350, 30000>,
<1, 350, 40000>,
<2, 350, 35000>,
<3, 350, 20000>,
<4, 350, 35000>
};
markets = {
<0, 150>,
<1, 150>,
<2, 100>,
<3, 100>,
<4, 100>,
<5, 150>,
<6, 100>
};
c1 = [
[1.9, 1.9, 1.8, 1.9],
[2.0, 2.0, 1.9, 1.8],
[1.8, 2.0, 1.9, 2.0]
];
c2 = [
[6.1, 7.8, 7.9, 7.9, 7.8],
[7.7, 7.1, 6.9, 7.8, 7.7],
[6.7, 6.0, 7.1, 6.9, 6.7],
[7.0, 6.0, 6.5, 7.6, 6.6]
];
c3 = [
[4.5, 5.0, 4.6, 5.5, 4.8, 4.1, 4.9],
[4.8, 4.6, 4.9, 5.7, 5.7, 5.9, 4.0],
[5.2, 5.1, 5.1, 4.2, 4.7, 4.0, 5.0],
[5.2, 5.9, 4.3, 5.9, 5.7, 4.1, 4.7],
[4.9, 5.3, 4.1, 4.5, 4.7, 5.6, 4.0]
];
.mod:
using CP;
int nSuppliers = ...;
int nFactories = ...;
int nWarehouses = ...;
int nMarkets = ...;
execute {
cp.param.timelimit = 30;
}
tuple Supplier {
int id;
int capacity;
};
tuple Factory {
int id;
int capacity;
float cost;
};
tuple Warehouse {
int id;
int capacity;
float cost;
};
tuple Market {
int id;
int demand;
};
{Supplier} suppliers = ...;
{Factory} factories = ...;
{Warehouse} warehouses = ...;
{Market} markets = ...;
float c1[suppliers][factories] = ...;
float c2[factories][warehouses] = ...;
float c3[warehouses][markets] = ...;
dvar boolean y1[factories];
dvar boolean y2[warehouses];
dvar interval transportSF[suppliers][factories];
dvar interval transportFW[factories][warehouses];
dvar interval transportWM[warehouses][markets];
dvar sequence seqSF[s in suppliers] in (all(f in factories) transportSF[s][f]);
dvar sequence seqFW[f in factories] in (all(w in warehouses) transportFW[f][w]);
dvar sequence seqWM[w in warehouses] in (all(m in markets) transportWM[w][m]);
minimize
sum(f in factories) (f.cost * y1[f]) +
sum(w in warehouses) (w.cost * y2[w]) +
sum(s in suppliers, f in factories) (c1[s][f] * sizeOf(transportSF[s][f])) +
sum(f in factories, w in warehouses) (c2[f][w] * sizeOf(transportFW[f][w])) +
sum(w in warehouses, m in markets) (c3[w][m] * sizeOf(transportWM[w][m]));
subject to {
forall(s in suppliers)
sum(f in factories) sizeOf(transportSF[s][f]) <= s.capacity;
forall(f in factories)
sum(w in warehouses) sizeOf(transportFW[f][w]) <= f.capacity * y1[f];
forall(f in factories)
sum(s in suppliers) sizeOf(transportSF[s][f]) == sum(w in warehouses) sizeOf(transportFW[f][w]);
forall(w in warehouses)
sum(m in markets) sizeOf(transportWM[w][m]) <= w.capacity * y2[w];
forall(w in warehouses)
sum(f in factories) sizeOf(transportFW[f][w]) == sum(m in markets) sizeOf(transportWM[w][m]);
forall(m in markets)
sum(w in warehouses) sizeOf(transportWM[w][m]) == m.demand;
forall(s in suppliers)
noOverlap(seqSF[s]);
forall(f in factories)
noOverlap(seqFW[f]);
forall(w in warehouses)
noOverlap(seqWM[w]);
}
Excuse me, I don’t know much about CP, but how correct does this implementation look? Is it normal that the CP results take longer and the CPLEX and CP results are different?
New contributor
Даниил Бадин is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.