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 2025: Register Now

Registration is now open for SAS Innovate 2025 , our biggest and most exciting global event of the year! Join us in Orlando, FL, May 6-9.
Sign up by Dec. 31 to get the 2024 rate of just $495.
Register now!

Multiple Linear Regression in SAS

Learn how to run multiple linear regression models with and without interactions, presented by SAS user Alex Chaplin.

Find more tutorials on the SAS Users YouTube channel.

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