BookmarkSubscribeRSS Feed
🔒 This topic is solved and locked. Need further help from the community? Please sign in and ask a new question.
SASAlex101
Obsidian | Level 7

I have code in proc optmodel that outputs a solution to a minimization problem. The solution matrix is a binary matrix which represents a column choice of restaurants szone value that best matches the ID's (first column s 1,2,3...) szone value. The following SAS code is where I am now. 

 

 

data WORK.RestaurantsBySzone;
Infile datalines delimiter="#";
length Restaurant $100.;
input Restaurant $ szone;
datalines;
McDonalds#1
Subway#1
Tim Hortons#1
Starbucks#1
KFC#2
Wendys#2
Taco Bell#2
Pizza Hut#2
Ruby Tuesday#3
Whataburger#3
Burger King#3
IHOP#3
;
run;
data WORK.OPEN_F1_FINAL;
Infile datalines delimiter='#';
input
S
szone
Var1
Var2
Var3
;
datalines;
1#3#2#2#3
2#1#2#3#3
3#2#2#1#1
4#2#3#1#3
5#3#1#1#2
6#1#3#1#3
7#2#3#1#1
8#3#3#3#1
9#1#3#2#2
10#2#1#2#2
11#2#3#2#6
12#2#2#2#2
13#2#2#2#1
14#1#2#1#3
15#1#1#2#3
16#3#2#2#1
17#3#1#1#3
18#1#1#3#1
19#1#3#2#3
20#1#3#1#3
;
Run;

data WORK.CoorespondingRestaurants;
Length	
Var1	$100.
Var2	$100.
Var3	$100.;
Infile datalines delimiter='#';
input
S
szone
Var1 $
Var2 $
Var3 $
;
datalines;
1#3#Pizza Hut#KFC#Ruby Tuesday
2#1#Pizza Hut#IHOP#Whataburger
3#2#Taco Bell#McDonalds#Subway
4#2#Burger King#McDonalds#Ruby Tuesday
5#3#Starbucks#Tim Hortons#Taco Bell
6#1#Whataburger#Subway#Burger King
7#2#Burger King#Subway#Tim Hortons
8#3#IHOP#Whataburger#Starbucks
9#1#IHOP#Pizza Hut#KFC
10#2#Starbucks#Pizza Hut#KFC
11#2#IHOP#Wendys#
12#2#Pizza Hut#Wendys#Taco Bell
13#2#Taco Bell#KFC#Tim Hortons
14#1#Pizza Hut#Subway#Ruby Tuesday
15#1#Starbucks#Taco Bell#Burger King
16#3#Pizza Hut#KFC#Starbucks
17#3#Starbucks#Subway#Whataburger
18#1#McDonalds#Burger King#Starbucks
19#1#Whataburger#Wendys#Burger King
20#1#Whataburger#Subway#IHOP
;
Run;
PROC SQL;
   CREATE TABLE WORK.CoorespondingRestaurants AS 
   SELECT t1.S, 
          t1.szone, 
          t1.Var1, 
          t1.Var2, 
          t1.Var3
      FROM WORK.COORESPONDINGRESTAURANTS t1;
QUIT;

proc optmodel;
ods output PrintTable#4=F1_Solution;
set SSET;
set JSET = 1..3;
num a {SSET, JSET};
num szone {SSET};

read data OPEN_F1_FINAL into SSET=[s] {j in JSET} <a[s,j] = col('Var'||(j))> szone;

var X {SSET, JSET} binary;
var Abs {SSET};

min Objective = (sum {s in SSET} Abs[s]) / (sum {s in SSET} szone[s]);

constraint OnceChoice {s in SSET}: sum {j in JSET} X[s,j] = 1;
constraint AbsCon1 {s in SSET}: Abs[s] >= sum {j in JSET} a[s,j]*X[s,j] - szone[s];
constraint AbsCon2 {s in SSET}: Abs[s] >= -sum {j in JSET} a[s,j]*X[s,j] + szone[s];

solve;

print a szone;
print Objective;
print X;

quit;

 

the solution matrix: 

 

SASAlex101_4-1629866980883.png

 

can be translated to: for S = 1 the best matched restaurant is 'Ruby Tuesday', and so forth for the other rows which can be determined by pairing the corresponding column with a 1 to the COORESPONDINGRESTAURANTS table. 

 

The subproblem is that I want to apply a limitation to how many of each restaurant can be chosen during the optimization. i.e I don't want the optimizer to choose McDonalds or KFC more often than another restaurant of the same szone based on the rule that

an szone 1 restaurant can only be chosen at most once in the solution

an szone 2 restaurant can only be chosen 2 times in the solution

an szone 3 restaurant can only be chosed at most 2 times in the solution.

 

There are 3 szones and 4 restaurants in each szone as shown in the table RESTAURANTBYSZONE. 

 

in excel, I would count using countifs or something the number of time a restaurant has been chosen and compare that to my szone rules:

 szonenumof choices in solutioncomment
McDonalds12WRONG - too many
Subway13WRONG - too many
Tim Hortons10OK
Starbucks11OK
KFC22OK
Wendys22OK
Taco Bell24WRONG - too many
Pizza Hut22OK
Ruby Tuesday31OK
Whataburger31OK
Burger King31OK
IHOP31OK

 

on lines 2 and 3 above) Perhaps the optimizer could have chosen Tim Hortons instead of Subway when it had the choice of szone 1's. How does this correspond to a subproblem in my current proc optmodel?

 

Thanks so much! 

 

 

1 ACCEPTED SOLUTION

Accepted Solutions
RobPratt
SAS Super FREQ

Sorry for the false start, which I have now deleted.

 

You can omit the PROC SQL call, which doesn't change anything.

 

Add this DATA step:

data szoneData;
   input szone szoneLimit;
   datalines;
1 1
2 2
3 2
;

 Then add these OPTMODEL statements before the solver call:

   set <str> RESTAURANTS;
   num szone_r {RESTAURANTS};
   read data RestaurantsBySzone into RESTAURANTS=[Restaurant] szone_r=szone;

   str restaurant_sj {SSET, JSET};
   read data CoorespondingRestaurants into [s] {j in JSET} <restaurant_sj[s,j] = col('Var'||(j))>;

   set SZONES;
   num szoneLimit {SZONES};
   read data szoneData into SZONES=[szone] szoneLimit;

   con SzoneCon {r in RESTAURANTS}:
      sum {s in SSET, j in JSET: restaurant_sj[s,j] = r} X[s,j] <= szoneLimit[szone_r[r]];

After the solve, you can verify that the new constraint is satisfied by adding this statement:

   print SzoneCon.body SzoneCon.ub;

On my machine, the results are:

[1] SzoneCon.BODY SzoneCon.UB
Burger King 2 2
IHOP 2 2
KFC 2 2
McDonalds 1 1
Pizza Hut 2 2
Ruby Tuesday 2 2
Starbucks 1 1
Subway 1 1
Taco Bell 2 2
Tim Hortons 1 1
Wendys 2 2
Whataburger 2 2

View solution in original post

3 REPLIES 3
SASAlex101
Obsidian | Level 7

so, I may be misunderstanding how this works.

 

The values in the soluion Matrix X[s,j] are just the binary matrix of values which correspond to the szone choice in matrix a? It appears that this solution assumes that the columns in X correspond to szones? when the columns in X are just representative of the variable order in a. So I was trying to figure out how summing X[s,j] is counting the distinct restaurant choices as demonstrated in the excel counting method as shown in the pic below. 

SASAlex101_0-1629904992232.png

I think I can visualize how the szonelimit[szone[s]] is working. Seems to be a lookup based on the limit matrix we defined earlier. 

 

thanks Rob

RobPratt
SAS Super FREQ

Sorry for the false start, which I have now deleted.

 

You can omit the PROC SQL call, which doesn't change anything.

 

Add this DATA step:

data szoneData;
   input szone szoneLimit;
   datalines;
1 1
2 2
3 2
;

 Then add these OPTMODEL statements before the solver call:

   set <str> RESTAURANTS;
   num szone_r {RESTAURANTS};
   read data RestaurantsBySzone into RESTAURANTS=[Restaurant] szone_r=szone;

   str restaurant_sj {SSET, JSET};
   read data CoorespondingRestaurants into [s] {j in JSET} <restaurant_sj[s,j] = col('Var'||(j))>;

   set SZONES;
   num szoneLimit {SZONES};
   read data szoneData into SZONES=[szone] szoneLimit;

   con SzoneCon {r in RESTAURANTS}:
      sum {s in SSET, j in JSET: restaurant_sj[s,j] = r} X[s,j] <= szoneLimit[szone_r[r]];

After the solve, you can verify that the new constraint is satisfied by adding this statement:

   print SzoneCon.body SzoneCon.ub;

On my machine, the results are:

[1] SzoneCon.BODY SzoneCon.UB
Burger King 2 2
IHOP 2 2
KFC 2 2
McDonalds 1 1
Pizza Hut 2 2
Ruby Tuesday 2 2
Starbucks 1 1
Subway 1 1
Taco Bell 2 2
Tim Hortons 1 1
Wendys 2 2
Whataburger 2 2
SASAlex101
Obsidian | Level 7

ok I see. the call for 
sum {s in SSET, j in JSET: restaurant_sj[s,j] = r} X[s,j]

is equivalent to the COUNTIFS like in excel - taking the choice of Szone as indicated by X. 

 

elegant solution. The problem becomes more fickle if I play with the limit per szone in the szonedata; but, this definitely answers the question. 

 

Thanks Rob! 

sas-innovate-2024.png

Available on demand!

Missed SAS Innovate Las Vegas? Watch all the action for free! View the keynotes, general sessions and 22 breakouts on demand.

 

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
  • 397 views
  • 0 likes
  • 2 in conversation