Originally posted by: Dmartinc
Hi all,
I am having some issues trying to model a certain situation in a crew scheduling problem, which tries to represent the changes from a given initial roster to a new recovery roster, minimizing the changing costs. Therefore, I am using an IloIntArray Tasks_initial(env, NTasks), which keeps the initial roster, being -1 not assigned employee, 0 employee 1 assigned, and so on until MEmployees, and a decision variable IloIntVarArray Tasks(env, NTasks, 1, MEmployees). In order to illustrate the logic of the recovery, here there is an example:
Tasks_initial
-1,-1, 2,-1,-1, 5,-1,-1 Tasks
2, 3, 6, 7, 8, 5, 1, 0 So, if Tasks_initial[j] != Tasks[j], there is a change that should be counted, otherwise Tasks remains assigned to the same employee as in the initial roster. Therefore, I am trying to use an IloIfThen command within the objective function, which gives an error: error C2665: 'IloIfThen::IloIfThen' : none of the 4 overloads could convert all the argument types.
How could it be modeled this situation?
//Objective function IloNumArray c2(env, MEmployees*NTasks);
for (i=0; i<MEmployees; ++i)
for (j=0; j<NTasks; ++j) c2[i*NTasks+j] = c[i][j]; IloExpr Obj_Func_1(env);
for (j = 0; j < NTasks; j++)
{ Obj_Func_1 += IloIfThen(env, Tasks[j]!=Tasks_initial[j] && Tasks_initial[j]!=-1 , c2[Tasks[j]*NTasks+j]+c2[Tasks_initial[j]*NTasks+j]) ;
} IloObjective obj1 = IloMinimize(env, Obj_Func_1); Obj_Func_1.end();
Another issue that I am encountering in my model is that I get this message error (not enough memory) when I am building the following constraint:
//Minimum experience level over certain group of tasks IloNumArray exp2(env, MEmployees*NTasks);
for (i=0; i<MEmployees; ++i)
for (j=0; j<NTasks; ++j) exp2[i*NTasks+j] = exp[i][j];
for(k=0;k<KProjects;++k)
{ IloExpr Experience(env);
for(j=0; j< NTasks; ++j)
{ Experience += Projects[k][j]*exp2[Tasks[j]*NTasks+j];
} model.add(Experience >= Min_experience[k]); Experience.end();
} cout <<
" *Project experiences - checked"<<endl;
Is there a bug or something? Because my model works properly for small instances, this happens when the number of tasks and projects to schedule reach 200 and 40 respectively.
Please find my whole model and the dataset of instance where I encounter the error. I really appreciate if someone could answer my questions. Thanks in advance.
David
#include <ilcp/cp.h> using namespace std; ILOSTLBEGIN typedef IloArray<IloNumArray> NumMatrix;
//Coeffiecients matrix typedef IloArray<IloBoolArray> BoolMatrix;
//Boolean coefficients matrix typedef IloArray<IloIntVarArray> VarMatrix;
//Integer Decision variable matrix typedef IloArray<IloBoolVarArray> BoolVarMatrix;
//Boolean Decision variable matrix
int main(int,
const
char * [])
{ IloEnv env;
try
{ IloModel model(env); IloInt i, j, t, f, g, k; IloInt MEmployees, NTasks, KProjects; IloInt p, alpha = 0, beta = 1, constraint_required = 0; IloInt min_rest = 14, Rest_number=0; IloIntVar b; ifstream file(
"Normal Instances/Inst_50_10_(0.5-0.2-0.5-0.5)_14.csv"); file >> t; file.get(); cout <<
"Time:" << t << endl; file >> NTasks; file.get(); cout <<
"Number of tasks:" << NTasks << endl; file >> KProjects; file.get(); cout <<
"Number of Projects:" << KProjects << endl; file >> MEmployees; file.get(); cout <<
"Number of Employees:" << MEmployees << endl; p=t/7; IloNumArray T(env, p+1);
for(g=1; g<=p;g++)
{ T[g] = T[g-1] + 7;
}
for(j=1; j<p-1; j++)
{
if(T[j]<t-min_rest+1)
{ Rest_number = Rest_number + 1;
}
}
//Decision variables domain IloIntVarArray Tasks(env, NTasks, 0, MEmployees-1);
//Tasks decision
for(j=0; j<NTasks;++j)
{ stringstream nn; nn <<
"Task(" << j+1 <<
")"; Tasks[j].setName(nn.str().c_str());
} BoolVarMatrix y(env, MEmployees);
//Decision variable related to change y[i][j] of Size MEmployees x NTasks
for(i = 0; i < MEmployees; i++)
{ y[i] = IloBoolVarArray(env, NTasks);
for(j=0; j<NTasks;++j)
{ stringstream nn; nn <<
"y(" << i+1 <<
" " <<j+1 <<
")"; y[i][j].setName(nn.str().c_str());
}
} IloIntVarArray o(env, MEmployees-1, 0, t/2);
//o[i] Overpaid decision variables
for(j=0; j<MEmployees-1;++j)
{ stringstream nn; nn <<
"o(" << j+1 <<
")"; o[j].setName(nn.str().c_str());
} IloIntVarArray u(env, MEmployees-1, 0, t/8);
//u[i] Underpaid decision variables
for(j=0; j<MEmployees-1;++j)
{ stringstream nn; nn <<
"u(" << j+1 <<
")"; u[j].setName(nn.str().c_str());
}
//Coefficients BoolMatrix x(env, MEmployees);
//eligebility matrix e[i][j] of Size MEmployees x NTasks
for(i = 0; i < MEmployees; i++)
{ x[i] = IloBoolArray(env, NTasks);
} BoolMatrix e(env, MEmployees);
//eligebility matrix e[i][j] of Size MEmployees x NTasks
for(i = 0; i < MEmployees; i++)
{ e[i] = IloBoolArray(env, NTasks);
} NumMatrix c(env, MEmployees);
//c[i][j]Cost coefficients
for(i = 0; i < MEmployees; i++)
{ c[i] = IloNumArray(env, NTasks);
} IloNumArray s(env,NTasks);
//s[i] start time of task i IloNumArray d(env,NTasks);
//d[i] duration time of task i BoolMatrix Projects(env,KProjects);
//Projects in which is required an evaluation of the experience of Employee i in task j
for(i = 0; i < KProjects; i++)
{ Projects[i] = IloBoolArray(env, NTasks);
} NumMatrix exp(env, MEmployees);
//e[i][j] Experience of Employee i in task j
for(i = 0; i < MEmployees; i++)
{ exp[i] = IloNumArray(env, NTasks);
} IloNumArray Min_experience(env,KProjects);
//Min Experience required for project k IloNumArray G(env, MEmployees-1);
//g[i] Employees i with guaranteed days in his/her contract IloNumArray W_bar(env, MEmployees-1);
//W_bar[i] Expected work time for employee i IloNumArray nu(env,MEmployees-1);
//Underpaid rate IloNumArray phi(env, MEmployees-1);
//Overpaid rate IloNumArray omega(env, MEmployees-1);
//Overpaid rate IloBoolArray C(env, NTasks+Rest_number);
//Set of overlapping and sequencing constraints
//-----------------------------------------------Initilization--------------------------------------------------
for (j=0;j<NTasks;j++)
{ file >> s[j]; file.get();
}
//cout << "Tasks start time:" << s << endl;
for (j=0;j<NTasks;j++)
{ file >> d[j]; file.get();
}
//cout << "Tasks duration:" << d << endl;
for (i=0;i<MEmployees;i++)
{
for(
int j=0;j<NTasks;j++)
{ file >> e[i][j]; file.get();
}
}
//cout << "Employees´ Eligibility:" << e << endl << endl;
for (i=0;i<MEmployees;i++)
{
for(
int j=0;j<NTasks;j++)
{ file >> x[i][j]; file.get();
}
}
//cout << "Previous Roster:" << endl<< x << endl << endl;
for (i=0;i<MEmployees;i++)
{
for(
int j=0;j<NTasks;j++)
{ file >> c[i][j]; file.get();
}
}
//cout << "Scheduling costs:" << c << endl << endl;
for (j=0;j<MEmployees-1;j++)
{ file >> nu[j]; file.get();
}
//cout << "Underpaid rate:" << endl<< nu << endl;
for (j=0;j<MEmployees-1;j++)
{ file >> phi[j]; file.get();
}
//cout << "Overpaid rate:" << endl<< phi << endl <<endl;
for (j=0;j<MEmployees-1;j++)
{ file >> omega[j]; file.get();
}
//cout << "Current excess:" << endl<< omega << endl <<endl;
for (j=0;j<MEmployees-1;j++)
{ file >> G[j]; file.get();
}
//cout << "Guaranteed days:" << endl<< G << endl;
for (j=0;j<MEmployees-1;j++)
{ file >> W_bar[j]; file.get();
}
//cout << "Expected work time:" << endl<< W_bar << endl;
for (j=0;j<KProjects;j++)
{
for(k=0;k<NTasks;k++)
{ file >> Projects[j][k]; file.get();
}
}
//cout << "Projects:" << Projects << endl;
for (i=0;i<MEmployees;i++)
{
for(
int j=0;j<NTasks;j++)
{ file >> exp[i][j]; file.get();
}
}
//cout << "Experience matrix:" << exp << endl << endl;
for (j=0;j<KProjects;j++)
{ file >> Min_experience[j]; file.get();
} cout <<
"Minimum experience:" << Min_experience << endl <<endl; IloIntArray Tasks_initial(env, NTasks);
for(j=0; j<NTasks; j++)
{ Tasks_initial[j]= -1;
}
for(j=0; j<NTasks; j++)
{
for(i = 0; i < MEmployees; i++)
{
if(x[i][j]==1)
{ Tasks_initial[j]=i;
}
}
}
/* ------------------------------------------------------MODEL------------------------------------------------------------. */
//Elegibility IloNumArray e2(env, MEmployees*NTasks);
for (i=0; i<MEmployees; ++i)
for (j=0; j<NTasks; ++j) e2[i*NTasks+j] = e[i][j]; IloExpr expr(env);
for(j=0; j< NTasks; ++j)
{ expr = e2[Tasks[j]*NTasks+j]; model.add(expr==1); expr.end();
} cout <<
" *Eligibility - checked"<<endl;
//Minimum experience level over certain group of tasks IloNumArray exp2(env, MEmployees*NTasks);
for (i=0; i<MEmployees; ++i)
for (j=0; j<NTasks; ++j) exp2[i*NTasks+j] = exp[i][j];
for(k=0;k<KProjects;++k)
{ IloExpr Experience(env);
for(j=0; j< NTasks; ++j)
{ Experience += Projects[k][j]*exp2[Tasks[j]*NTasks+j];
} model.add(Experience >= Min_experience[k]); Experience.end();
} cout <<
" *Project experiences - checked"<<endl;
//Emplpoyees cannot be assigned to overlaping tasks IloInt Sum=0;
while(alpha < p)
//Algorithm to produce constraints preventing employees being allocated overlapping tasks
{
for(j=0; j<NTasks;j++)
{
if(T[alpha]==s[j]+d[j])
{
if(constraint_required == 1)
{ IloIntVarArray Overlapped_Tasks(env, Sum); g=0;
for(i = 0; i < NTasks; i++)
{
if((C[i]==1)&&(g<Sum))
{ Overlapped_Tasks[g]=Tasks[i]; g++;
}
} model.add(IloAllDiff(env, Overlapped_Tasks)); beta = beta + 1; constraint_required = 0; Sum=0;
} C[j]=0;
}
}
for(j=0; j<NTasks;j++)
{
if(T[alpha]==s[j])
{ constraint_required = 1; C[j]=1;
}
}
//cout <<" Constraint set("<< beta <<"):"<< C << endl <<endl;;
for(j=0; j<NTasks;j++)
{
if(C[j]==1) Sum++;
} alpha = alpha + 1;
} cout <<
" *Overlapped tasks - checked"<<endl;
//Employees cannot be assigned to sequence tasks alpha=0; beta=1; constraint_required = 0; Sum=0;
for(i=0; i<NTasks; i++)
{ C[i]=0;
}
while(alpha < p-1)
//Algorithm to produce constraints preventing employees being allocated sequencing tasks
{
for(j=0; j<NTasks;j++)
{
if(T[alpha]==s[j]+d[j])
{
if(constraint_required == 1)
{ IloIntVarArray Sequenced_Tasks(env, Sum); g=0;
for(i = 0; i < NTasks; i++)
{
if((C[i]==1)&&(g<Sum))
{ Sequenced_Tasks[g]=Tasks[i]; g++;
}
} model.add(IloAllDiff(env, Sequenced_Tasks)); beta = beta + 1; constraint_required = 0; Sum=0;
} C[j]=0;
for(i=0; i<NTasks;i++)
{
if(T[alpha]==s[i])
{ C[i]=0;
}
if(T[alpha+1]==s[i])
{ C[i]=0;
}
}
}
}
for(i=0; i<NTasks-1;i++)
{
if(T[alpha+1]==s[i]+d[i])
{
for(j=0; j<NTasks;j++)
{
for(g=0; g<NTasks;g++)
{
if((T[alpha+1]==s[i]+d[i])&&(T[alpha+1]==s[j])&&(T[alpha+2]==s[g]))
{ constraint_required = 1; C[j]=1;
//s[] C[i]=1;
//s[]+d[] C[g]=1;
//s[] before 14 days
}
}
if(T[alpha+1]==t-7)
{
if((T[alpha+1]==s[i]+d[i])&&(T[alpha+1]==s[j]))
{ constraint_required = 1; C[j]=1;
//s[] C[i]=1;
//s[]+d[]
}
}
}
}
}
for(j=0; j<NTasks;j++)
{
if(C[j]==1) Sum++;
}
//cout <<" Constraint set("<< beta <<"):"<< C << endl <<endl; alpha = alpha + 1;
} cout <<
" *Sequenced tasks - checked"<<endl; IloBoolVarArray Tasks2(env, MEmployees*NTasks);
for(j=0; j<NTasks; j++)
{ model.add(Tasks2[Tasks[j]*NTasks+j]==1);
} BoolVarMatrix Tasks3(env, MEmployees);
//Tasks matrix z[i][j] of Size MEmployees x NTasks
for(i = 0; i < MEmployees; i++)
{ Tasks3[i] = IloBoolVarArray(env, NTasks);
}
for (i=0; i<MEmployees; ++i)
for (j=0; j<NTasks; ++j) Tasks3[i][j]=Tasks2[i*NTasks+j];
//Calculation of any undertime payments
for(i=0; i<MEmployees-1; i++)
{ IloExpr Sum(env);
for(j=0; j<NTasks; j++)
{ Sum += d[j]*Tasks2[i*NTasks+j];
}
if(G[i]!=0)
{ model.add(u[i]>= G[i]-(W_bar[i]+ Sum)); Sum.end();
}
}
//Calculation of any overtime payments
for(i=0; i<MEmployees-1; i++)
{ IloExpr Sum(env);
for(j=0; j<NTasks; j++)
{ Sum += d[j]*Tasks2[i*NTasks+j];
}
if(G[i]!=0)
{ model.add(o[i]>= (W_bar[i]+ Sum)-G[i]); Sum.end();
}
}
for(i=0;i<MEmployees;i++)
{
for(j=0; j<NTasks; j++)
{
if(x[i][j] == 1)
{ model.add(Tasks2[i*NTasks+j]==x[i][j]-y[i][j]);
}
else
{ model.add(Tasks2[i*NTasks+j]==x[i][j]+y[i][j]);
}
}
}
//Objective function IloNumArray c2(env, MEmployees*NTasks);
for (i=0; i<MEmployees; ++i)
for (j=0; j<NTasks; ++j) c2[i*NTasks+j] = c[i][j]; IloExpr Obj_Func_1(env);
for (j = 0; j < NTasks; j++)
{ Obj_Func_1 += IloIfThen(env, Tasks[j]!=Tasks_initial[j] && Tasks_initial[j]!=-1 , c2[Tasks[j]*NTasks+j]+c2[Tasks_initial[j]*NTasks+j]) ;
} IloExpr Obj_Func_2(env);
for (i = 0; i < MEmployees-1; i++)
{
if(G[i]!=0) Obj_Func_2 += ((nu[i]*u[i]) + (phi[i]*o[i]));
} IloObjective obj1 = IloMinimize(env, Obj_Func_1); IloObjective obj2 = IloMinimize(env, Obj_Func_1+Obj_Func_2); Obj_Func_1.end(); Obj_Func_2.end(); cout <<
" *Objective function - checked"<<endl;
/* ---------------------------------------EXTRACTING THE MODEL AND SOLVING-----------------------------------------. */
//Call to Ilog Optimizer IloCP cp(model);
//EXTRACT cp.extract(model);
//PROPAGATION cp.propagate();
//Parameters settings
//cp.setParameter(IloCP::LogVerbosity, IloCP::Quiet); //Avoid Log
//cp.setParameter(IloCP::PropagationLog, IloCP::Verbose); //Propagation log
//cp.setParameter(IloCP::CountInferenceLevel, IloCP::Extended); //Extended info on search cp.setParameter(IloCP::OptimalityTolerance, 10); cp.setParameter(IloCP::RelativeOptimalityTolerance, 0.1);
//Sets optimality tolerance cp.setParameter(IloCP::BranchLimit, 500000);
//Limit number of search branches
//cp.setParameter(IloCP::DynamicProbing, 1); cp.setParameter(IloCP::RestartFailLimit,100);
//cp.setParameter(IloCP::TimeLimit, 300); cp.setParameter(IloCP::TemporalRelaxation, 1); cp.setParameter(IloCP::AllDiffInferenceLevel, 4);
//STRATEGY SEARCH
//cp.setParameter(IloCP::SearchType, IloCP::MultiPoint); //Multi-point search strategy -> Heuristic-Concentrates on finding good solutions
//cp.setParameter(IloCP::MultiPointNumberOfSearchPoints, 2);
//cp.setParameter(IloCP::RestartGrowthFactor ,10); //Restart search strategy -> Heuristic-It can prove optimality
//cp.setParameter(IloCP::SearchType, IloCP::DepthFirst); //Depth first search strategy -> Exact method model.add(obj1);
/*cp.solve(); // Store solution IloSolution sol1(env); for ( i=0; i<MEmployees; ++i) { for ( j=0; j<NTasks; ++j) { // For illustration purpose, we only save start values sol1.setValue(y[i][j], cp.getValue(y[i][j])); } } // Change objective model.remove(obj2); //model.add(Obj_Func_2 <= cp.getValue(Obj_Func_2)); // f1 should not worsen model.add(obj1); // Minimize f2 using sol1 as starting point cp.setStartingPoint(sol1);*/
if (cp.solve(IloSearchPhase(env,Tasks)))
{ cp.out() << std::endl <<
"- Solution:" << endl << endl;
/*env.out() << " - Changes in previous schedule: " << endl; for(i = 0; i < MEmployees-1; i++) { env.out() << " Employee(" << i+1 << "): \t"; for(j = 0; j < NTasks; j++) { env.out() << cp.getValue(y[i][j]); } env.out() << endl; } env.out() << " Agency: \t"; for(j = 0; j < NTasks; j++) { env.out() <<cp.getValue(y[MEmployees-1][j]) ; } env.out() << endl;*/ env.out() << endl <<
" - New Schedule: " << endl;
/*for(i = 0; i < MEmployees-1; i++) { env.out() << " Employee(" << i+1 << "): \t"; for(j = 0; j < NTasks; j++) { env.out() <<cp.getValue(e[i][j]*Tasks3[i][j]) ; } env.out() << endl; } env.out() << " Agency: \t"; for(j = 0; j < NTasks; j++) { env.out() <<cp.getValue(e[MEmployees-1][j]*Tasks3[MEmployees-1][j]) ; } env.out() << endl;*/
for(i=0; i<NTasks ; i++)
{
if(cp.getValue(Tasks[i])<MEmployees-1) cp.out() <<
" Task("<<i+1<<
") -> Employee(" << cp.getValue(Tasks[i])+1 <<
")"<< endl;
else cp.out() <<
" Task("<<i+1<<
") -> Agency"<<endl;
}
/*env.out() << endl <<" - Over-utilisation: " << endl; for(i = 0; i < 1; i++) { env.out() << " Days(Cost): "; for(j = 0; j < MEmployees-1; j++) { if(G[j]!=0) { env.out() << cp.getValue(o[j]); env.out() <<"(" <<ceil(cp.getValue(o[j]*phi[j]))<<")" <<"\t"; } } env.out() << endl << endl; } env.out() <<" - Under-utilisation: " << endl; for(i = 0; i < 1; i++) { env.out() << " Days(Cost): "; for(j = 0; j < MEmployees-1; j++) { if(G[j]!=0) { env.out() << cp.getValue(u[j]); env.out() <<"(" <<ceil(cp.getValue(u[j]*nu[j]))<<")" <<"\t"; } } env.out() << endl << endl; }*/ env.out() <<
" Minimal Cost = " << cp.getObjValue() <<
"\t"; env.out() <<
"Elapsed time = " << env.getTime() << endl<<endl; cp.out() <<
"Is it optimal ? = " << cp.getStatus() << endl << endl;
}
else
{ cp.out() <<
"No solution found. " << std::endl;
}
}
catch (IloException& ex)
{ env.out() <<
"Error: " << ex << std::endl;
} env.end();
return 0;
}
#CPOptimizer#DecisionOptimization