BookmarkSubscribeRSS Feed
☑ This topic is solved. Need further help from the community? Please sign in and ask a new question.
Fibo1123
Calcite | Level 5

Hello. I recently posted a request for assistance in giving preference to certain resources/variables when optimizing.

 

Proc Optmodel MILP Scheduling: Pausing resource reallocation and giving preference to allocation 

 

@RobPratt  `s solution was very informative, particularly this bit that illustrates how to create sets within sets:

 

con DesiredConstraint1 {<PROD_ID, slot, day> in PROD_SLOT_DAY, <(PROD_ID), slot2, day2> in PROD_SLOT_DAY: dayToNum[day2] in dayToNum[day]+1..dayToNum[day]+N}:

 

 

I have another issue with set manipulation(?). I am using MILP to maximize revenue based on the allocation of product IDs to a set of time slots over a set of days.

 

var PROD_ASSIGN{PROD_SLOT_DAY}
a tuple of <string PROD_ID, num SLOT, string DAY>

 

I would like constrain allocation of the primary variable PROD_ID based on a secondary numeric feature, call it "FTR", such that:

  1. PROD_IDs with identical FTR cannot be scheduled in back-to-back SLOTs within a given DAY.
  2. PROD_IDs with identical FTR cannot be scheduled in the same SLOT on consecutive DAYs.

 

So, for example, let PROD_ID={...,"ABC", "DEF"...}, slot={...9,10,...}, and day={...,"Wednesday", "Thursday",...}. Assume that both ABC and DEF both have identical FTR=10.

 

  • Constraint 1 above would prevent the allocation of combinations {ABC,ABC}, {DEF,DEF}, and {ABC,DEF} to both SLOT=9 and SLOT=10 on Wednesday.
  • Constraint 2 above would prevent the allocation of combinations {ABC,ABC}, {DEF,DEF}, and {ABC,DEF} to SLOT=9 on both Wednesday and Thursday.

 

I have used the following code in a separate constraint to prevent a given PROD_ID from being assigned to more than 2 consecutive slots (indexed by "start" here):

PROD_ASSIGN[prod_id, start, day] + PROD_ASSIGN[prod_id, start+1, day] + PROD_ASSIGN[prod_id, start+2, day] <= 2

I am just constraining the number of times a given PROD_ID can appear in set of consecutive slots.
This is rather straight-forward sum as PROD_ID is a component of the PROD_ASSIGN optimization variable.

 

In my example this time though, I would like to constrain the number of times that a secondary feature, which is not a component of PROD_ASSIGN, appears vertically (i.e. in consecutive slots within a given day) and horizontally (i.e. in a given slot across consecutive days).

 

Any suggestions of how I can do this? 


In the attached "Build Input Data" code, I have created a data set called SECOND_FTR_PRODS that contains a numeric FTR code for each of the corresponding PROD_IDs. My sample optimization code is included in "Optimize Schedule". I am not married to the idea of a numeric FTR. If string is more convenient/easy-to-solve, I can convert numeric values to string as needed.

1 ACCEPTED SOLUTION

Accepted Solutions
RobPratt
SAS Super FREQ
   con Constraint1 {<PROD_ID, slot, day> in PROD_SLOT_DAY, <PROD_ID2, slot2, (day)> in PROD_SLOT_DAY: FTR[PROD_ID] = FTR[PROD_ID2] and slot2 = slot+1}:
      PROD_ASSIGN[PROD_ID, slot, day] + PROD_ASSIGN[PROD_ID2, slot2, day] <= 1;

   con Constraint2 {<PROD_ID, slot, day> in PROD_SLOT_DAY, <PROD_ID2, (slot), day2> in PROD_SLOT_DAY: FTR[PROD_ID] = FTR[PROD_ID2] and dayToNum[day2] = dayToNum[day]+1}:
      PROD_ASSIGN[PROD_ID, slot, day] + PROD_ASSIGN[PROD_ID2, slot, day2] <= 1;

View solution in original post

3 REPLIES 3
RobPratt
SAS Super FREQ
   con Constraint1 {<PROD_ID, slot, day> in PROD_SLOT_DAY, <PROD_ID2, slot2, (day)> in PROD_SLOT_DAY: FTR[PROD_ID] = FTR[PROD_ID2] and slot2 = slot+1}:
      PROD_ASSIGN[PROD_ID, slot, day] + PROD_ASSIGN[PROD_ID2, slot2, day] <= 1;

   con Constraint2 {<PROD_ID, slot, day> in PROD_SLOT_DAY, <PROD_ID2, (slot), day2> in PROD_SLOT_DAY: FTR[PROD_ID] = FTR[PROD_ID2] and dayToNum[day2] = dayToNum[day]+1}:
      PROD_ASSIGN[PROD_ID, slot, day] + PROD_ASSIGN[PROD_ID2, slot, day2] <= 1;
Fibo1123
Calcite | Level 5

@RobPratt Thank you for your reply. 

 

Based on your previous solution, I assume your current solution would also need a lookup array like this:

/*Note: I converted input numeric FTR to string FTR_c: strip(put(FTR, best3.)) */
set <string> FTR_chars;
read data SECOND_FTR_PRODS into FTR_chars = [FTR_c];

num FTR {FTR_chars}; num ftr_cnt init 0; for {d in FTR_chars} do; ftr_cnt = ftr_cnt + 1; FTR[d] = ftr_cnt; end;
print FTR;

Fibo1123_1-1720168082799.png

 

This however generates an error, ERROR: The array subscript 'FTR[AAA]' is invalid at line 185 column 103. , when this code is called as 'AAA' is a PROD_ID value:

FTR[PROD_ID] = FTR[PROD_ID2]

This equality takes the string PROD_ID as input rather than the FTR_c values that were used to create the FTR array.

 

I could recreate the array using PROD_ID rather than FTR_C like:

num FTR {PROD_IDs}; /*PROD_IDs = set of string PROD_ID values defined in the attached SAS code*/
num ftr_cnt init 0;
for {d in PROD_IDs} do;
     ftr_cnt = ftr_cnt + 1;
     FTR[d] = ftr_cnt;
end;
print FTR;

but this just assigns an integer to each PROD_ID value. It doesn't incorporate the FTR/FTR_c values from the SECOND_FTR_PRODS table, which is what I am trying to accomplish this time.

Fibo1123_0-1720168046718.png

 

I think I need some kind of lookup array/matrix/? that takes PROD_ID as an input and outputs the corresponding FTR/FTR_c value. 

Any thoughts on how I might create that?

RobPratt
SAS Super FREQ

For the code I suggested, the following suffices:

   num FTR {PROD_IDs};
   read data SECOND_FTR_PRODS into [PROD_ID] FTR;

sas-innovate-white.png

Missed SAS Innovate in Orlando?

Catch the best of SAS Innovate 2025 — anytime, anywhere. Stream powerful keynotes, real-world demos, and game-changing insights from the world’s leading data and AI minds.

 

Register now

Discussion stats
  • 3 replies
  • 1735 views
  • 0 likes
  • 2 in conversation