Operations Research topics: SAS/OR,
SAS Optimization, and SAS Simulation Studio

Resource Constraints using Proc CLP

Reply
New Contributor
Posts: 2

Resource Constraints using Proc CLP

I need some advice.   I am using 14.2

 

I have a scheduling problem which is solved using Proc CLP.  It utilises the ACTDATA,  RESDATA data sets.  I need to add a number of constraints to when resources are available as described below.

 Scenario 1

Resource A is not available on day  2 and therefore Resource A cannot be assigned  to any activity that is scheduled over that period.

Scenario 2.

The resources assigned for use on Activity A must also be assigned to Activity B.  Using the data below, if the resource VANCOVER is assigned to Activity AA2, then resource VANCOVER must also be assigned to activity AB2.

 

ACTIVITY DATA

ACTIVITY             SUCCESSOR        DURATION          RESOURCE          QTY

AA1                        AA3                        12                           CANADA              1

AA2                        AA3                        20                           UK                        1

AA3                        AB2                        30                           CANADA              1

AA4                        AB3                        30                           CANADA              1

AB2                        AB3                        20                           CANADA              1

AB3                                                      10                           UK                        1

 

RESOURCE DATA

RESOURCE          CAPACITY            POOL                     SUBQTY

LONDON              1                              UK                          1

EDINBURGH         1                              UK                          1

VANCOVER          1                              CANADA                1

CALGARY             1                              CANADA                1

 

How can I add these constraints to the problem using Proc CLP or should the model be reworked  using Proc OPTMODEL.

SAS Employee
Posts: 7

Re: Resource Constraints using Proc CLP

Hi!

 

The first scenario can be addressed by introducing an activity "X" with the sole purpose of using up resource "LONDON" on day 2:

 

proc clp schedtime=schedtime schedres=schedres;
activity X = (dur=1 SGE=2 FLE=3);
RESOURCE (LONDON);
REQUIRES X = (LONDON);
run;

 

This scenario can also be handled by proc. CPM, using resource calendars, activity calendars, or the resource input data set to specify the resource level.

 

The second scenario is what we have called a "REQUIRESSAME" constraint. Adding this constraint to CLP is a requirement that is under review for implementation in a future release.

 

Thanks!

Lindsey

 

 

SAS Employee
Posts: 448

Re: Resource Constraints using Proc CLP

[ Edited ]

Here is one way to solve this problem by using the MILP solver in PROC OPTMODEL:

data ACTIVITYDATA;
   input _ACTIVITY_ $ _SUCCESSOR_ $ _DURATION_ _RESOURCE_ $ _QTY_;
   if _ACTIVITY_ = 'CALGVACA' then do;
      _ALIGNTYPE_ = 'seq';
      _ALIGNDATE_ = 2;
   end;
   datalines;
AA1 AA3 12 CANADA 1
AA2 AA3 20 UK 1
AA3 AB2 30 CANADA 1
AA4 AB3 30 CANADA 1
AB2 AB3 20 CANADA 1
AB3 . 10 UK 1
CALGVACA . 1 CALGARY 1 
;

data RESOURCEDATA;
   input _RESOURCE_ $ _CAPACITY_ _POOL_ $ _SUBQTY_;
   datalines;
LONDON 1 UK 1
EDINBURGH 1 UK 1
VANCOVER 1 CANADA 1
CALGARY 1 CANADA 1
;

proc optmodel;
   set <str,str> ACTIVITY_SUCCESSOR;
   read data ACTIVITYDATA into ACTIVITY_SUCCESSOR=[_ACTIVITY_ _SUCCESSOR_];
   set ACTIVITIES = (union {<i,j> in ACTIVITY_SUCCESSOR} {i,j}) diff {''};
   num duration {ACTIVITIES} init 0;
   str resource {ACTIVITIES};
   num quantity {ACTIVITIES} init 1;
   str aligntype {ACTIVITIES};
   num aligndate {ACTIVITIES};
   read data ACTIVITYDATA into [_ACTIVITY_]
      duration=_DURATION_ resource=_RESOURCE_ quantity=_QTY_ aligntype=_ALIGNTYPE_ aligndate=_ALIGNDATE_;

   num maxperiod = sum {a in ACTIVITIES} duration[a] - 1;
   set PERIODS = 0..maxperiod;
   set ACTIVITIES_PERIODS = {a in ACTIVITIES, p in PERIODS: p+duration[a]-1 in PERIODS};
   var IsStart {ACTIVITIES_PERIODS} binary;
   con StartOnce {a in ACTIVITIES}:
      sum {<(a),p> in ACTIVITIES_PERIODS} IsStart[a,p] = 1;
   impvar Start {a in ACTIVITIES} = sum {<(a),p> in ACTIVITIES_PERIODS} p * IsStart[a,p];
   impvar Finish {a in ACTIVITIES} = Start[a] + duration[a];
   con Precedence {<a,s> in ACTIVITY_SUCCESSOR: s ne ''}:
      Finish[a] <= Start[s];

   con Alignment {a in ACTIVITIES: aligntype[a] = 'seq'}:
      Start[a] = aligndate[a];

   var MaxFinish integer >= max {a in ACTIVITIES} duration[a];
   min Makespan = MaxFinish;
   con MaxFinishCon {a in ACTIVITIES}:
      MaxFinish >= Finish[a];

   set <str,str> RESOURCE_POOL;
   num subquantity {RESOURCE_POOL} init 1;
   read data RESOURCEDATA into RESOURCE_POOL=[_RESOURCE_ _POOL_] subquantity=_SUBQTY_;
   set <str> RESOURCES;
   num capacity {RESOURCES};
   read data RESOURCEDATA into RESOURCES=[_RESOURCE_] capacity=_CAPACITY_;
   RESOURCE_POOL = RESOURCE_POOL union setof {r in RESOURCES} <r,r>;
   print subquantity;

   set RESOURCES_ACTIVITIES = {r in RESOURCES, a in ACTIVITIES: <r,resource[a]> in RESOURCE_POOL};
   var IsRes {RESOURCES_ACTIVITIES} binary;
   con OneResourcePerActivity {a in ACTIVITIES}:
      sum {<r,resource[a]> in RESOURCE_POOL} IsRes[r,a] = 1;
   var IsResPeriod {RESOURCES_ACTIVITIES, PERIODS} binary;
   con IsResPeriodImpliesIsRes {<r,a> in RESOURCES_ACTIVITIES, p in PERIODS}:
      IsResPeriod[r,a,p] <= IsRes[r,a];
   con IsStartImpliesResource {<a,p> in ACTIVITIES_PERIODS, p2 in p..p+duration[a]-1}:
      quantity[a] * IsStart[a,p] <= sum {<r,resource[a]> in RESOURCE_POOL} subquantity[r,resource[a]] * IsResPeriod[r,a,p2];
   con ResourceCapacity {r in RESOURCES, p in PERIODS}:
      sum {<(r),a> in RESOURCES_ACTIVITIES} IsResPeriod[r,a,p] <= capacity[r];

   solve;
   print {<a,p> in ACTIVITIES_PERIODS: IsStart[a,p].sol > 0.5} IsStart;
   print {<r,a> in RESOURCES_ACTIVITIES: IsRes[r,a].sol > 0.5} IsRes;
   print {<r,a> in RESOURCES_ACTIVITIES, p in PERIODS: IsResPeriod[r,a,p].sol > 0.5} IsResPeriod;

   create data schedtime from [activity] start finish;
   str assigned_resource {ACTIVITIES};
   for {a in ACTIVITIES} do;
      for {<r,(a)> in RESOURCES_ACTIVITIES: IsRes[r,a].sol > 0.5} do;
         assigned_resource[a] = r;
         leave;
      end;
   end;
   create data schedres from [activity] resource=assigned_resource qty=quantity;
quit;

proc gantt data=schedtime;
   chart / as=start af=finish;
   id activity;
run;
Ask a Question
Discussion stats
  • 2 replies
  • 312 views
  • 0 likes
  • 3 in conversation