Hello,
I am modifying the Sched_tasks example to make it applicable to optimize several tasks across scattered units with different durations.
Here is my .mod file:
using CP;
int NbHouses = ...; // Number of units
range HousesRange = 1..NbHouses;
int NoTasks = ...; // Number of tasks
range TasksRange = 1..NoTasks;
{string} WorkerNames = ...; // List of workers' names
string TaskNames[TasksRange] = ...; // List of task names as an array of strings
{string} ActivityNames = {}; // List of task names as a set of strings
// Use the data from TaskNames to create the ActivityNames
execute {
for (var i in TasksRange) {
ActivityNames.add(TaskNames[i]);
}
}
// Create a tuple containing id and name of tasks
tuple ListOfTask {
int id;
string TaskName;
};
{ListOfTask} tasksAsTuples = {<i, TaskNames[i]> | i in TasksRange};
execute {
writeln("tasksAsTuples: ", tasksAsTuples);
}
int Duration[HousesRange][TasksRange] = ...; // Duration for each task in each house as a matrix
// Data for workers
tuple ResourceDat {
key int id;
string type;
string name;
};
{ResourceDat} resources = ...;
// Create a list of the resource types
{string} resourceTypes = {r.type | r in resources};
// Data for task & worker requirements (Which crew to complete a task and how many required)
tuple Requirement {
string task;
string resource;
int quantity;
};
{Requirement} requirements = ...;
// Create a tuple with data of list of tasks & requirements for each one & available crews
tuple Allocation {
ListOfTask dmd;
Requirement req;
ResourceDat resource;
};
{Allocation} allocs =
{<tn, m, r> | tn in tasksAsTuples, m in requirements, r in resources :
tn.TaskName == m.task && r.type == m.resource};
// Relationships among tasks
tuple Precedence {
string pre;
string post;
string type;
int delay;
};
// Import the relationships from the .dat file
{Precedence} Precedences = ...;
int ReleaseDate[HousesRange] = ...;
int DueDate[HousesRange] = ...;
float Weight[HousesRange] = ...;
// Define the matrix to import the values
int transitionTimes[HousesRange][HousesRange] = ...;
// Transition time across the units
tuple triplet {
int loc1;
int loc2;
int value;
};
// Create a set of tuples from the traveling matrix
{triplet} transitionAsTuples = {<i, j, transitionTimes[i][j]> | i in HousesRange, j in HousesRange};
// Create the house interval variables
dvar interval houses[h in HousesRange] in ReleaseDate[h]..(maxint div 2)-1;
// Create the task interval variables
dvar interval itvs[h in HousesRange][t in TasksRange] size Duration[h][t];
// Create the allocation interval variables
dvar interval tiallocs[allocs] optional;
// Create the sequence variables
dvar sequence workers[r in resources] in all(a in allocs: a.resource == r) tiallocs[a];
int levels[rt in resourceTypes] = sum(r in resources : r.type == rt) 1;
cumulFunction cumuls[rt in resourceTypes] =
sum(rc in requirements, tn in tasksAsTuples, h in HousesRange, t in TasksRange : rc.resource == rt && tn.TaskName == rc.task) pulse(itvs[h][t], rc.quantity);
// Declare the mapping from task names to task indices
int taskIndex[ActivityNames];
// Populate the mapping
execute {
for (var i in TasksRange) {
taskIndex[TaskNames[i]] = i;
}
}
// Define the objective Functions:
// The total duration
dexpr float TotalDuration = max(h in HousesRange, t in TasksRange) endOf(itvs[h][t]);
// Determine the earliest start time among all houses
dexpr float firstStartTime = min(h in HousesRange) startOf(houses[h]);
// Objective Function:
minimize TotalDuration;
subject to {
// Ensure the first task in the first house starts at day 0
firstStartTime == 0;
// Add the precedence constraints
forall(h in HousesRange)
forall(p in Precedences)
if (p.type == "FS") endBeforeStart(itvs[h][taskIndex[p.pre]], itvs[h][taskIndex[p.post]], p.delay);
else if (p.type == "SS") startAtStart(itvs[h][taskIndex[p.pre]], itvs[h][taskIndex[p.post]], p.delay);
else if (p.type == "FF") endAtEnd(itvs[h][taskIndex[p.pre]], itvs[h][taskIndex[p.post]], p.delay);
else if (p.type == "SF") startBeforeEnd(itvs[h][taskIndex[p.pre]], itvs[h][taskIndex[p.post]], p.delay);
// Add the house span constraints
forall(h in HousesRange)
span(houses[h], all(t in TasksRange) itvs[h][t]);
// Add the no overlap constraints
forall(r in resources) {
noOverlap(workers[r], transitionAsTuples);
}
// Ensure resource levels are not exceeded
forall(r in resourceTypes : levels[r] > 10) {
cumuls[r] <= levels[r];
}
}
// Set solver parameters
execute {
cp.param.FailLimit = 10000;
cp.param.TimeLimit = 300;
cp.param.TimeMode = "CPUTime";
cp.param.SearchType = "auto";
writeln("Solver parameters set.");
}
Here is my .dat file
NbHouses = 3;
NoTasks = 10;
WorkerNames = {"Crew1-1", "Crew1-2","Crew2", "Crew3-1", "Crew3-2","Crew3-3","Crew4", "Crew5", "Crew6", "Crew7", "Crew8", "Crew9", "Crew10" };
resources = {
<1, MasonaryLayer, "Crew1-1" >,
<2, MasonaryLayer, "Crew1-2" >,
<3, Carpenter, "Crew2" >,
<4, Plumber, "Crew3-1" >,
<5, Plumber, "Crew3-2" >,
<6, Plumber, "Crew3-3" >,
<7, CeilingWorker, "Crew4" >,
<8, RoofWorker, "Crew5" >,
<9, Painter, "Crew6" >,
<10, WindowInstaller, "Crew7" >,
<11, FacadeWorker, "Crew8" >,
<12, GardenWorker, "Crew9" >,
<13, Mover, "Crew10" >
};
TaskNames = [
"masonry",
"carpentry",
"plumbing",
"ceiling",
"roofing",
"painting",
"windows",
"facade",
"garden",
"moving"
];
// Each row represents a building (unit) with duration of tasks in the same order as in TaskNames list
Duration = [[35, 30, 25, 20, 25, 15, 20, 15, 20, 15],
[10, 15, 10, 15, 10, 5, 10, 5, 10, 5],
[5, 10, 5, 10, 5, 15, 20, 15, 20, 15]];
requirements = {
<masonry, MasonaryLayer, 1>,
<carpentry, Carpenter, 1>,
<plumbing, Plumber, 1>,
<ceiling, CeilingWorker, 1>,
<roofing, RoofWorker, 1>,
<painting, Painter, 1>,
<windows, WindowInstaller, 1>,
<facade, FacadeWorker, 1>,
<garden, GardenWorker, 1>,
<moving, Mover, 1>
};
// transitionTimes to be entered as a fraction of day (e.g., 2 hrs = 0.25 day)
transitionTimes = [[0, 2, 1],
[2, 0, 1],
[1, 1, 0]
];
ReleaseDate = [ 0, 0, 0];
DueDate = [120, 212, 304];
Weight = [100.0, 100.0, 100.0];
// Format <"Predecessor", "Successor", "Relation type", Lag time>,
// FS = Finish to Start; SS = Start to Start; FF = Finish to Finish; SF = Start to Finish
// Lag = + Lag time ; Lead = - Lag time
Precedences = {
<"masonry", "carpentry", "SS", 2>,
<"masonry", "plumbing", "FS", -2>,
<"masonry", "ceiling", "FS", 0>,
<"carpentry", "roofing", "FS", 0>,
<"ceiling", "painting", "FS", 0>,
<"roofing", "windows", "FF", 0>,
<"roofing", "facade", "FS", 0>,
<"plumbing", "facade", "FS", 0>,
<"roofing", "garden", "FS", 0>,
<"plumbing", "garden", "SF", 0>,
<"windows", "moving", "FS", 0>,
<"facade", "moving", "FS", 0>,
<"garden", "moving", "FS", 0>,
<"painting", "moving", "FS", 0>
};
I have issues with lines highlighted in Bold (in the .mod file):
1- Create the sequence variable for the workers
2- cumulFunction for the resources consumption.
Also, I need to calculate the idle time for each worker and the total idle time
Any help would be much appreciated,
Regards,
------------------------------
Fam Saeed
------------------------------