How to add new constraints in the scheduling problem at CPLEX? - scheduling

I am a beginner at CPLEX and I am struggling to add more constraints in my project. The script works well when I have multiple origin and destination, and just one product
I would like to do it with more products demand in each destination, and I do not know how to write the Constraints.
{string} Forest = {"A","B","C","D","E"};
{string} Destination = {"D1" , "D2"};
{string} Products = {"Pinus","Eucalyptus"};
float Demand [Destination][Products]= [[3,1],[4,5]];
float Distance [Forest][Destination]=[[21,52],[42,12],[25,15],[52,31],[9,42]];
float Stock [Forest][Products]= [[0.94,0],[0,8.62],[0,1.21],[2.6,0],[8.77,0]];`
//Decision Variables
dvar float+ Delivered [Forest][Destination];
//Função Objetivo
minimize
sum (u in Forest, c in Destination) Distance[u][c] * Delivered[u][c];
//Constraints
subject to {
forall (u in Forest)
sum (c in Destination)
Delivered[u][c] <= Stock [u];
forall (c in Destination)
sum (u in Forest)
Delivered[u][c] >= Demand[c];
}
I have cross-posted this question.

You shave to also expand your decision variable by Products (like you did for Demand and Stock) so that you can know how much of each product is delivered.
Then you can replicate each constraint for each product by adding a "forall (p in Products)".
dvar float+ Delivered [Forest][Destination][Products];
forall (p in Products)
forall (u in Forest)
sum (c in Destination)
Delivered[u][c][p] <= Stock[u][p];

you could try something like
{string} Forest = {"A","B","C","D","E"};
{string} Destination = {"D1" , "D2"};
{string} Products = {"Pinus","Eucalyptus"};
float Demand [Destination][Products]= [[3,1],[4,5]];
float Distance [Forest][Destination]=[[21,52],[42,12],[25,15],[52,31],[9,42]];
float Stock [Forest][Products]= [[0.94,0],[0,8.62],[0,1.21],[2.6,0],[8.77,0]];
//Decision Variables
dvar float+ Delivered [Products][Forest][Destination];
//Função Objetivo
minimize sum (p in Products,u in Forest, c in Destination) Distance[u][c] * Delivered[p][u][c];
//Constraints
subject to {
forall (u in Forest,p in Products) sum (c in Destination) Delivered[p][u][c] <= Stock [u][p];
forall (p in Products,c in Destination) sum (u in Forest) Delivered[p][u][c] >= Demand[c][p];
}

Related

How to get all solutions in CPLEX to a MIP

UPDATE: Now I get the count of solutions, but when I try to get them out, it just gives me identical schedules. I have added the code suggested by Alex below. As an example, it gives me that there is 4 different solutions, but when I write the X matrices they are identical. Can anyone help me with this? I want the four different solutions.
I am making a schedule for a Single round robin tournament.
It is modelled as a MIP in CPLEX and in my solution pool there is at the moment four solutions with the same optimal objective value.
I want to get each of these four solutions, so they can be printed and examined indivudally. Is that possible?
// Create Parameters:
{string} G1 = ...; // Set of teams in first group
{string} G2 = ...; // Set of teams in second group
{string} Teams = G1 union G2;
tuple Match {string team1; string team2;}
{Match} Matches_G1 = {<t1,t2>| ordered t1,t2 in G1};
{Match} Matches_G2 = {<t1,t2>| ordered t1,t2 in G2};
{Match} MD1 = ...;
{Match} MD2 = ...;
{Match} MD3 = ...;
{Match} M = Matches_G1 union Matches_G2; //All matches for the two groups
{Match} matchForTeam[t in Teams] = {m| m in M : m.team1 == t || m.team2 == t}; //List of all teams
{string} S =...; //Set of stadiums
{string} T = ...; //Set of kick off times
{string} D = ...; //Set of kick off days
int K[D][S][T] = ...; //Predetermined schedule between stadium and kickoff time
float VT[M][T] = ...; //Value of match if played on Matchday M at Time T according to TV distribution
// Decision Variables:
dvar int X[M][S][T] in 0..1; // if match M is played at time T
dvar int Dist; //Object function for distribution
//////////// OBJECTIVE FUNCTION ///////////////
maximize
Dist;
//////////// CONSTRAINTS ///////////////
subject to{
Dist == sum(m in M, s in S, t in T) (VT[m][t])*X[m][s][t];
//A match can only be played one time
forall(m in M)
sum(s in S, t in T) X[m][s][t] == 1;
//Simultaneous Kickoff on matchday 3
sum(s in S)X[<"A1", "A4">][s]["22.00"] == sum(s in S)X[<"A2", "A3">][s]["22.00"];
//only one match on possible kick off times at matchday 1
forall(t in T : t != "18.00")
sum(s in S, m in MD1) X[m][s][t]==1;
//only one match on possible kick off times at matchday 2
forall(t in T : t != "18.00")
sum(s in S, m in MD2) X[m][s][t]==1;
//two matches per possible kick off times at matchday 3
forall(t in T : t in {"18.00", "22.00"})
sum(s in S, m in MD3) X[m][s][t]==2;
//One match per stadium on matchday 1
forall(s in S)
sum(m in MD1, t in T: t != "18.00") X[m][s][t] == 1;
//One match per stadium on matchday 2
forall(s in S)
sum(m in MD2, t in T: t != "18.00") X[m][s][t] == 1;
//one match per stadium on matchday 3
forall(s in S)
sum(m in MD3, t in T: t in {"18.00", "22.00"}) X[m][s][t] == 1;
//Each team can play at most two matches per stadium
forall(i in Teams, s in S)
sum(t in T, m in matchForTeam[i]) X[m][s][t] <= 2;
//Each team can play at most two matches per kickoff time
forall(i in Teams, t in T)
sum(s in S, m in matchForTeam[i]) X[m][s][t] <= 2;
forall(s in S, t in T, m in MD1)
X[m][s][t] <= K["1"][s][t];
forall(s in S, t in T, m in MD2)
X[m][s][t] <= K["2"][s][t];
forall(s in S, t in T, m in MD3)
X[m][s][t] <= K["3"][s][t];
}
execute{
writeln("schedule: ", X);
var cd = new IloOplOutputFile("resbi2.txt");
for(var m in M)
for(var s in S)
for(var t in T)
cd.writeln(thisOplModel.X[m][s][t]);
cd.close();
}
main{
cplex.solnpoolintensity=4;
cplex.solnpoolagap=0;
thisOplModel.generate();
cplex.solve();
if (cplex.populate()) {
var nsolns = cplex.solnPoolNsolns;
writeln("number of solutions: ", nsolns);
writeln("average object value: ", cplex.getSolnPoolMeanObjValue());
writeln();
for (var s=0; s<nsolns; s++) {
thisOplModel.setPoolSolution(s);
var cd = new IloOplOutputFile("resAB" +s+".txt");
cd.writeln(thisOplModel.X);
cd.close();
thisOplModel.postProcess();
}
}
}
yes in scripting you can loop into all solutions from a solution pool.
See https://github.com/AlexFleischerParis/zooopl/blob/master/zooseveral.mod
int nbKids=300;
float costBus40=500;
float costBus30=400;
dvar int+ nbBus40;
dvar int+ nbBus30;
//minimize
//costBus40*nbBus40 +nbBus30*costBus30;
subject to
{
40*nbBus40+nbBus30*30>=nbKids;
}
execute
{
writeln("nbBus40 = ",nbBus40," and nbBus30 = ",nbBus30," and the cost is ",costBus40*nbBus40 +nbBus30*costBus30);
}
main {
cplex.solnpoolintensity=4;
thisOplModel.generate();
cplex.solve();
if (cplex.populate()) {
var nsolns = cplex.solnPoolNsolns;
writeln("Number of solutions found = ",nsolns);
writeln();
for (var s=0; s<nsolns; s++) {
thisOplModel.setPoolSolution(s);
thisOplModel.postProcess();
}
}
}

Why my work in ILOG CPLEX have no solution?

i'm working on a production mix problem in ILOG CPLEX. But there are some problems that occur. My work is about sawmill production mix (production planning for lumber products that transform from log). I tried to solve my problem using 2 file .dat, one using dummy data and one using real data.
Data processing with dummy data show the solution, but when i'm using real data, result show no solution. So i've tried to change each of my dummy data with my real data (one by one to see what data that caused the problem). And it turned out the data are "LumberRecFac" and "DemandMaks". Then, i tried to change that two data with a several random numbers. And it shows that the maximum data for "LumberRecFac" is 0.5 and the maximum data for "DemandMaks" is 10.9.
Is there something that i missed/wrong in my .mod and .dat? Because i have to run my ILOG CPLEX .mod using my real data.
Here my .mod
//product mix
//i= (RST)
//d,l (Log)
//p (Cutting_Pattern)
int i=...;
int d=...;
int l=...;
int p=...;
range RST= 1..i; //Lumber Product(Raw Sawn Timber)
range Diameter_Log=1..d; //Diameter Log
range Panjang_Log=1..l; //Length log
range Cutting_Pattern=1..p; //Cutting Pattern
//set tuple
tuple DMdl{ //diameter and length
int d;
int l;
}
tuple DMdlp{ //diameter, length, and cutting pattern
int d;
int l;
int p;
}
tuple Cdpi{ //conversion factor (from log to lumber products)
int d;
int p;
int i;
}
//set
setof (DMdl) Log={<d,l> | d in Diameter_Log, l in Panjang_Log};
setof (DMdlp) Log_LCR={<d,l,p> | d in Diameter_Log, l in Panjang_Log, p in Cutting_Pattern};
setof (Cdpi) KonversiLog_LCR={<d,p,i> | d in Diameter_Log, p in Cutting_Pattern, i in RST};
//import data
int HargaJual[RST]=...; //Selling price of RST
int BiayaLogBaru[Log]=...; //Cost of new log
int BiayaLogLama[Log]=...; //Cost of old log
int BiayaProduksiLog=...; //Production cost
int BiayaSetup=...; //Setup cost
float LumberRecFac[KonversiLog_LCR]=...; //Conversion Factor (Lumber Recovery Ratio)
float DemandMaks[RST]=...; //Demand
int BM=...; //Big Constant (Big M)
int Tmax=...; //Max Production Time
int ProcessTime[Cutting_Pattern]=...; //Process time for one log
float SetupTime[Cutting_Pattern]=...; //Setup time
float TotalLogLamaSimpan[Log]=...; //Quantity of old log
//decision variable
dvar float+ Pi[RST]; //Quantity of lumber products
dvar float+ VF[RST]; //Quantity of selling lumber products
dvar boolean CPp[Cutting_Pattern];
dvar float TotalLogBaruBeli[Log]; //Quantity of new lod that have to buy
dvar float+ LogProduksi[Log_LCR]; //Total quantity of log to produce
dvar float+ LogBaruDipakai[Log]; //Total quantity of new log that processed
dvar float+ LogLamaDipakai[Log]; //Total quantity of old log that processed
dvar float+ TotalLogSimpan[Log]; //Total inventor of new log
//objective function
dexpr float sales=sum(i in RST) VF[i]*HargaJual[i];
dexpr float purchased=sum(d in Diameter_Log, l in Panjang_Log) (TotalLogBaruBeli[<d,l>]*BiayaLogBaru[<d,l>])+(LogLamaDipakai[<d,l>]*BiayaLogLama[<d,l>]);
dexpr float production=sum(d in Diameter_Log, l in Panjang_Log) LogProduksi[<d,l,p>]*BiayaProduksiLog;
dexpr float setup=sum(p in Cutting_Pattern) BiayaSetup*CPp[p];
maximize sales-(purchased+production+setup);
//constraint
subject to{
//constraint 1 : raw material inventory
forall (d in Diameter_Log, l in Panjang_Log)
TotalLogBaruBeli[<d,l>]==LogBaruDipakai[<d,l>]+TotalLogSimpan[<d,l>];
forall (d in Diameter_Log, l in Panjang_Log)
TotalLogLamaSimpan[<d,l>]>=LogLamaDipakai[<d,l>];
//constraint 2 : log processing
forall (l in Panjang_Log, i in RST)
sum(d in Diameter_Log, p in Cutting_Pattern) LogProduksi[<d,l,p>]*LumberRecFac[<d,p,i>]==Pi[i];
forall (d in Diameter_Log, l in Panjang_Log)
sum(p in Cutting_Pattern )LogProduksi[<d,l,p>]==LogLamaDipakai[<d,l>]+LogBaruDipakai[<d,l>];
forall (p in Cutting_Pattern)
sum(d in Diameter_Log, l in Panjang_Log) LogProduksi[<d,l,p>]<=BM*CPp[p];
forall (p in Cutting_Pattern)
sum(d in Diameter_Log, l in Panjang_Log) (LogProduksi[<d,l,p>]*ProcessTime[p])+(SetupTime[p]*CPp[p])<=Tmax;
//constraint 3 : production management and demand satisfaction
forall (i in RST)
Pi[i]>=VF[i];
forall (i in RST)
VF[i]==DemandMaks[i];
}
Here my dummy data
i = 3;
d = 2;
l = 2;
p = 1;
HargaJual= [1500 1400 1600];
BiayaLogLama=[100 250
200 400];
BiayaLogBaru=[150 250
300 450];
BiayaProduksiLog= 400;
BiayaSetup= 5;
LumberRecFac= [0.5 0.5 0.5
0.5 0.5 0.5];
DemandMaks= [9.8 10.9 10.8];
BM= 10000;
Tmax= 48;
ProcessTime= [1];
SetupTime= [0.1];
TotalLogLamaSimpan=[2 1
1 2];
Here my real data
i = 10;
d = 2;
l = 5;
p = 1;
HargaJual= [3114984
43347890
22956482
7775850
15380010
16984110
8703344
3500008
3288741
2525224
];
BiayaLogLama=[2328042 2834346 3035619 3044953 3199186
4446927 4872151 4924974 6006590 6637329];
BiayaLogBaru=[2360389 3291645 3212665 3231400 3453636
4456572 4884165 5057298 6261820 6733965];
BiayaProduksiLog= 17435453;
BiayaSetup= 5;
LumberRecFac= [0.0127 0.0145 0.0982 0.1353 0.4127 0.0001 0.2800 0.0107 0.1348 0.0166
0.6842 0.2105 0.0643 0.2359 0.4730 0.0497 0.3728 0.0187 0.2393 0.0434];
DemandMaks= [188.110
75.259
121.711
253.759
1206.444
5.248
180.735
0
164.510
0];
BM= 1000000;
Tmax= 480;
ProcessTime= [1];
SetupTime= [0.1];
TotalLogLamaSimpan=[0.030 2.770
3.776 5.530
2.993 3.880
1.678 2.970
1.588 0.140];
your model is not feasible. If you label your constraints then CPLEX will give you some relaxation and conflicts that will help you understand why.
For instance:
forall (d in Diameter_Log, l in Panjang_Log)
ct1:TotalLogLamaSimpan[<d,l>]>=LogLamaDipakai[<d,l>];
//constraint 2 : log processing
forall (l in Panjang_Log, i in RST)
ct2:sum(d in Diameter_Log, p in Cutting_Pattern) LogProduksi[<d,l,p>]*LumberRecFac[<d,p,i>]==Pi[i];
will display a conflict with ct2 and if you remove that then you get a feasible solution

CPLEX dvar as condition

I have this problem while trying to find a solution for a resource constraint scheduling problem. Whenever I put dvar as a condition in a forall loop or if condition I have the error that states "Decision variable (or expression) "S" not allowed".
range activity = 1..16;
dvar float+ S[activity];
dvar float+ rd[jobs];
forall (i in activity)
forall (t in T:S[i]<=t<=S[i]+D[i]) //boolean b
b[i][t]==1;
forall (t in T)
forall (k in R)
sum (i in activity)b[i][t]*V[i][k]<=Rk[k];//human resources constraint
forall (j in jobs)
forall (t in T:rd[j]<=t<=S[maxact[j]])//boolean y
y[j][t]==1;
This is a very common mistake. The code you are writing is building the model for cplex. The cplex variables in your (dvars, like your S) usually do not have a value until the model has been solved, so you cannot use their value during the model building process. You need to restructure your problem and you will probably need to use additional bool or int variables or indicator constraints inside your model.
This will work:
range activity = 1..16;
dvar float+ S[activity];
range jobs=1..3;
range T=1..3;
range R=1..4;
dvar boolean b[activity][T];
dvar boolean y[jobs][T];
int D[activity];
int Rk[R]; int V[activity][R]; int maxact[j in jobs]=1;
dvar float+ rd[jobs];
subject to {
forall (i in activity)
forall (t in T) //boolean b
((S[i]<=t) &&(t<=S[i]+D[i])) => (b[i][t]==1);
forall (t in T) forall (k in R)
sum (i in activity)b[i][t]*V[i][k]<=Rk[k];//human resources constraint
forall (j in jobs) forall (t in T)//boolean y
((rd[j]<=t) &&
(t<=S[maxact[j]])) => (y[j][t]==1);
}

Step Independent Smoothing

I often smooth values by blending percentages and inverse percentages with the below:
current_value = (current_value * 0.95f) + (goal_value * 0.05f)
I'm running into a situation where I would like to perform this action n times, and n is a floating point value.
What would be the proper way of performing the above, say 12.5 times for example?
One way of doing this would be to handle the integer amount, and then approximate the remaining amount. For example (I assume valid inputs, you would want to check for those):
void Smooth(float& current, float goal, float times, float factor){
// Handle the integer steps;
int numberIterations = (int)times;
for (int i = 0; i < numberIterations; ++i){
current = (factor * current) + (goal * (1 - factor));
}
// Aproximate the rest of the step
float remainingIteration = times - numberIterations;
float adjusted_factor = factor + ((1 - factor) * (1 - remainingIteration));
current = (adjusted_factor * current) + (goal * (1 - adjusted_factor));
}
Running for the following values I get:
current=1 goal=2 factor=0.95
12.0 times - 1.45964
12.5 times - 1.47315
13.0 times - 1.48666
I appreciate the help! I have been trying several things related to compound interest, and I believe I may have solved this with the following. My ultimate goal in mind (which was actually unstated here) was to actually do this with very little iterative processing. powf() may be the most time consuming piece here.
float blend_n(float c, float g, float f, float n)
{
if (g != 0.0f)
return c + ((g - c) / g) * (g - g * powf(1.0f - f, n));
else
return c * powf(1.0 - f, n);
}
It's late here, and my redbull is wearing off so there may be some parts that could be factored out.
Usage would be setting c to the return value of blend_n ...
Thanks again!
[EDIT]
I should explain here that c is the (current) value, g is the (goal) value, f is the (factor), and n is the (number of steps)
[/EDIT]
[EDIT2]
An exception has to be made for goal values of 0, as it will result in a NaN (Not a Number) ... Change done to the code above
[/EDIT2]

Incremental entropy computation

Let std::vector<int> counts be a vector of positive integers and let N:=counts[0]+...+counts[counts.length()-1] be the the sum of vector components. Setting pi:=counts[i]/N, I compute the entropy using the classic formula H=p0*log2(p0)+...+pn*log2(pn).
The counts vector is changing --- counts are incremented --- and every 200 changes I recompute the entropy. After a quick google and stackoverflow search I couldn't find any method for incremental entropy computation. So the question: Is there an incremental method, like the ones for variance, for entropy computation?
EDIT: Motivation for this question was usage of such formulas for incremental information gain estimation in VFDT-like learners.
Resolved: See this mathoverflow post.
I derived update formulas and algorithms for entropy and Gini index and made the note available on arXiv. (The working version of the note is available here.) Also see this mathoverflow answer.
For the sake of convenience I am including simple Python code, demonstrating the derived formulas:
from math import log
from random import randint
# maps x to -x*log2(x) for x>0, and to 0 otherwise
h = lambda p: -p*log(p, 2) if p > 0 else 0
# update entropy if new example x comes in
def update(H, S, x):
new_S = S+x
return 1.0*H*S/new_S+h(1.0*x/new_S)+h(1.0*S/new_S)
# entropy of union of two samples with entropies H1 and H2
def update(H1, S1, H2, S2):
S = S1+S2
return 1.0*H1*S1/S+h(1.0*S1/S)+1.0*H2*S2/S+h(1.0*S2/S)
# compute entropy(L) using only `update' function
def test(L):
S = 0.0 # sum of the sample elements
H = 0.0 # sample entropy
for x in L:
H = update(H, S, x)
S = S+x
return H
# compute entropy using the classic equation
def entropy(L):
n = 1.0*sum(L)
return sum([h(x/n) for x in L])
# entry point
if __name__ == "__main__":
L = [randint(1,100) for k in range(100)]
M = [randint(100,1000) for k in range(100)]
L_ent = entropy(L)
L_sum = sum(L)
M_ent = entropy(M)
M_sum = sum(M)
T = L+M
print("Full = ", entropy(T))
print("Update = ", update(L_ent, L_sum, M_ent, M_sum))
You could re-compute the entropy by re-computing the counts and using some simple mathematical identity to simplify the entropy formula
K = count.size();
N = count[0] + ... + count[K - 1];
H = count[0]/N * log2(count[0]/N) + ... + count[K - 1]/N * log2(count[K - 1]/N)
= F * h
h = (count[0] * log2(count[0]) + ... + count[K - 1] * log2(count[K - 1]))
F = -1/(N * log2(N))
which holds because of log2(a / b) == log2(a) - log2(b)
Now given an old vector count of observations so far and another vector of new 200 observations called batch, you can do in C++11
void update_H(double& H, std::vector<int>& count, int& N, std::vector<int> const& batch)
{
N += batch.size();
auto F = -1/(N * log2(N));
for (auto b: batch)
++count[b];
H = F * std::accumulate(count.begin(), count.end(), 0.0, [](int elem) {
return elem * log2(elem);
});
}
Here I assume that you have encoded your observations as int. If you have some kind of symbol, you would need a symbol table std::map<Symbol, int>, and do a lookup for each symbol in batch before you update the count.
This seems the quickest way of writing some code for a general update. If you know that in every batch only few counts actually change, you can do as #migdal does and keep track of the changing counts, subtract their old contribution to the entropy and add the new contribution.