0

I am working on RCPSP and want to apply Preemption to it.
I have divided the duration of every task into equal parts. Now after doing that I am unable to apply Precedence constraints to each of individual unit duration of a task.

using CP;

int NbTasks = ...;
int NbRsrcs = ...;
range RsrcIds = 1..NbRsrcs;  

int Capacity[r in RsrcIds] = ...;    

tuple Task {                        
  key int id;
  int     pt;
  int     dmds[RsrcIds];
  {int}   succs;            
  {int}   pred;
}
{Task} Tasks=...;


tuple sub_task { 
  Task task; 
  int p_no;
 }

 {sub_task} sub_activities = {<t,i > | t in Tasks, i in 1..t.pt  };  
 dvar interval itvs[t in Tasks]  size t.pt;
 dvar interval a[p in sub_activities] size 1;
 cumulFunction rsrcUsage[r in RsrcIds] = 
   sum (p in sub_activities: p.task.dmds[r]>0) pulse(a[p], p.task.dmds[r]);
 minimize max(t in Tasks) endOf(itvs[t]);

subject to {
  forall (r in RsrcIds)
  rsrcUsage[r] <= Capacity[r];
  forall (t1 in Tasks, t2id in t1.succs)
    endBeforeStart(itvs[t1], itvs[<t2id>]);
}     

execute {
  for (var p in sub_activities) {
    writeln("subactivity of " + p.task.id + " - " + p.p_no + " starts at " + a[p].start + " Ends at " + a[p].end);  
  } 
}

Thanks in Advance.

Xavier Nodet
  • 5,033
  • 2
  • 37
  • 48

2 Answers2

0

First, you should add some constraints that says that each task represented by interval itvs[t] spans the set of individual activities a[<t,i>], something like: span(itvs[t], all(i in 1..t.pt) a[<t,i>])

And then, say that the individual activities of a given task t form a chain, with constraints like: endBeforeStart(a[<t,i-1>],[<t,i>])

But note that for this preemptive version of the problem, you will loose one of the major interest of CP Optimizer which is the fact it avoids the enumeration of time. Here, if tasks are fully preemptive, you have to divide each task of duration D into D individual activities. If you know you have some constraints on the preemption of tasks (for instance that each individual activity has a minimal duration larger than the time unit), this can be exploited in the model to create less sub-activities.

  • Noted and Thank you very much Sir for your help. – Rahul Ghate Feb 15 '19 at 15:32
  • To reduce the sub activities I have defined two integer variables smin and smax which are the minimum and maximum duration of sub-activities. tuple subtask has been declared as {sub_task} sub_activities = { | t in Tasks, i in 1..t.pt div t.smin }; and decision variable is defined as dvar interval a[p in sub_activities] optional size p.task.smin..p.task.smax; and some constarints are added to above code. the code is keeps on running and doesn't provide solution. Can you please let me know what all modifications and constraints to add. – Rahul Ghate Mar 05 '19 at 06:26
  • Could you attach the full model? – Philippe Laborie Mar 07 '19 at 16:02
  • tuple Task { key int id; int pt; int dmds[RsrcIds]; {int} succs; int smin; int smax; } {Task} Tasks=...; tuple sub_task{ Task task; int p_no;} {sub_task} sub_activities = { | t in Tasks, i in 1..t.pt div t.smin }; dvar interval itvs[t in Tasks] size t.pt; dvar interval a[p in sub_activities] optional size p.task.smin..p.task.smax; cumulFunction rsrcUsage[r in RsrcIds]=sum (p in sub_activities: p.task.dmds[r]>0) pulse(a[p], p.task.dmds[r]); minimize max(p in sub_activities) endOf(a[p]); – Rahul Ghate Mar 11 '19 at 11:08
  • subject to { forall (r in RsrcIds) rsrcUsage[r] <= Capacity[r]; forall (t1 in Tasks, t2id in t1.succs) endBeforeStart(itvs[t1], itvs[]); forall(t in Tasks, i in 1..t.pt) span(itvs[t], all(i in 1..t.pt) a[]); forall(p in sub_activities){ forall(s in sub_activities: s.task==p.task && s.p_no==p.p_no+1){ endBeforeStart(a[p],a[s]); presenceOf(a[s])=> presenceOf(a[p]); execute { for (var p in sub_activities){ writeln("subactivity of " + p.task.id + " - " + p.p_no + " starts at " + a[p].start + " Ends at " + a[p].end); } } – Rahul Ghate Mar 11 '19 at 11:11
0

I think that your model is missing an important constraint that says that the sum of the durations of the different parts of a task is equal to the task processing time. Something like:

forall (t in Tasks) {
  sum(p in sub_activities: p.task==t) lengthOf(a[p]) == t.pt;
}

Also, given that the integer division will round the result down, you may miss some sub-activities, so I would rather use something like:

{sub_task} sub_activities = {<t,i > | t in Tasks, i in 1..1+(t.pt div t.smin )}; 

Furthermore, the size of the spanning tasks cannot be t.pt but will be larger if preemption is allowed, so it should be something like:

dvar interval itvs[t in Tasks] size t.pt..H; // H being a large number

Finally (but this is only to speed-up the resolution a little bit), you can reformulate the makespan expression in the objective using the task spanning intervals rather than the parts (this will involve less variables):

minimize max(t in Tasks) endOf(itvs[t]);

Also, if you have max duration on the parts, you need to prevent two consecutive parts to be contiguous (otherwise, I suppose it would be considered as the same part), so the chain of interval variables for the parts should have a minimal delay of 1:

forall(p in sub_activities){ 
  forall(s in sub_activities: s.task==p.task && s.p_no==p.p_no+1){ 
    endBeforeStart(a[p],a[s],1); 
    presenceOf(a[s])=> presenceOf(a[p]); 
  }
}
  • Sir in this model the sub-activities are getting divided into unit duration and if give a minimal delay of 1 (forall(p in sub_activities){ forall(s in sub_activities: s.task==p.task && s.p_no==p.p_no+1){ endBeforeStart(a[p],a[s],1); presenceOf(a[s])=> presenceOf(a[p]); } }) it creates gap which is undesirable. we require the activities to be divided only when their is resource constraint otherwise it should be kept as a whole activity. how can we do it? – Rahul Ghate Mar 14 '19 at 17:21