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

@RobPratt

 

At previous thread, OPT model is provided to find the best Treatment/Method for BLOC/DT.

Let the solution have improvement for as many as BLOC/DT, the goal is to maximize the total score [improvement=_tmin_x[treatment/method] is less than _tmin_orig for each BLOC/DT. Score=1 if improvement; -5 if none improvement]. This is Stage I. 

 

Now the second stage is to maximize the total sum of the differences between _tmin_x

and _tmin_orig ONLY from the top solutions from Stage I. THAT MEANs an additional constrain

on the TOTAL SCORE from Stage I >= A THESHOLD.

 

%let optds=mm_out_x6_x;
data have;
   set &optds.;
   rename _tmin=method1 _tmin_ew=method2 _tmin_wt_r=method3 _tmin_wt_r2=method4;
run;

title "OPT on &optds.";
proc optmodel;
   /* read input data */
   set METHODS = 1..4;
   set <str,num,num> DATE_BLOCK_TREATMENT;
   num _tmin_orig {DATE_BLOCK_TREATMENT};
   num outcome {DATE_BLOCK_TREATMENT, METHODS};
   read data have into DATE_BLOCK_TREATMENT=[dt bloc condi_id] _tmin_orig
      {m in METHODS} <outcome[dt,bloc,condi_id,m]=col('method'||m)>;
   set TREATMENTS = setof {<d,b,t> in DATE_BLOCK_TREATMENT} t;
   set DATE_BLOCK = setof {<d,b,t> in DATE_BLOCK_TREATMENT} <d,b>;

  /* define optimization model */
   var SelectTreatment {TREATMENTS} binary;
   var SelectMethod {METHODS} binary;
   var SelectTreatmentMethod {TREATMENTS, METHODS} binary;
   var IsGood {DATE_BLOCK} binary;
   /* if IsGood[d,b] = 1 then Score[d,b] = 1 else Score[d,b] = -5 */
   impvar Score {<d,b> in DATE_BLOCK} = 1 * IsGood[d,b] - 5 * (1 - IsGood[d,b]);
   max TotalScore = sum {<d,b> in DATE_BLOCK} Score[d,b];
   con CardinalityTreatment:
      sum {t in TREATMENTS} SelectTreatment[t] = 2;
   con CardinalityMethod:
      sum {m in METHODS} SelectMethod[m] = 1;
   /* SelectTreatmentMethod[t,m] <= SelectTreatment[t] * SelectMethod[m] */
   con Linearize1 {t in TREATMENTS, m in METHODS}:
      SelectTreatmentMethod[t,m] <= SelectTreatment[t];
   con Linearize2 {t in TREATMENTS, m in METHODS}:
      SelectTreatmentMethod[t,m] <= SelectMethod[m];
   con AtLeastOneGood {<d,b> in DATE_BLOCK}:
      IsGood[d,b] <= sum {<(d),(b),t> in DATE_BLOCK_TREATMENT, 
			m in METHODS: outcome[d,b,t,m] < _tmin_orig[d,b,t]} SelectTreatmentMethod[t,m];

   /* call MILP solver , TOP one only*/
   solve;
   create data want_method from [method] SelectMethod;
   create data want_treatment from [treatment] SelectTreatment;
   create data want_dt_bloc from [dt bloc] IsGood Score;
   create data want_x_dtbloc from [d b]=DATE_BLOCK;
   create data want_trtmt from [t]=TREATMENTS;

quit;

  I tried some variation, below or alike. But it complains.

 /* IT WAS  
   impvar Score {<d,b> in DATE_BLOCK} = 1 * IsGood[d,b] - 5 * (1 - IsGood[d,b]);
   max TotalScore = sum {<d,b> in DATE_BLOCK} Score[d,b];*/
   var Score {<d,b> in DATE_BLOCK} = 1 * IsGood[d,b] - 5 * (1 - IsGood[d,b]);
   var TotalScore = sum {<d,b> in DATE_BLOCK} Score[d,b];
   impvar difx{<d,b> in DATE_BLOCK} = outcome[d,b]* IsGood[d,b]-_time_orig[b];
   max TotalDif =sum {<d,b> in DATE_BLOCK} difx[d,b];


con MinScore TotalScore >=4;

Please keep # of selection of Treatment and Method BOTH=2. THanks, 

 

con CardinalityTreatment:
      sum {t in TREATMENTS} SelectTreatment[t] = 2;
   con CardinalityMethod:
      sum {m in METHODS} SelectMethod[m] = 2;

THanks, 

 

1 ACCEPTED SOLUTION

Accepted Solutions
RobPratt
SAS Super FREQ

TotalScore.sol is the value of TotalScore from the most recent solver call.  You can alternatively use a manually specified threshold.  The following code changes yield the same objective values as in your Excel file:

   con CardinalityMethod:
      sum {m in METHODS} SelectMethod[m] = 1;

   /* primary objective */
   solve;

/*   con MinScore: TotalScore >= TotalScore.sol;*/
   con MinScore: TotalScore >= -5;

   impvar difx {<d,b> in DATE_BLOCK} = 
      sum {<(d),(b),t> in DATE_BLOCK_TREATMENT, m in METHODS} max(_tmin_orig[d,b,t] - outcome[d,b,t,m], 0) * SelectTreatmentMethod[t,m];
   max TotalDif = sum {<d,b> in DATE_BLOCK} difx[d,b];

   /* secondary objective */
   solve with milp / primalin;
   put TotalScore= TotalDif=;

The PUT statement shows the resulting objective values:

TotalScore=-3 TotalDif=13365

View solution in original post

8 REPLIES 8
hellohere
Pyrite | Level 9

Here is possibility that a huge improvement [_tmin_orig - _tmin_x/Treatment/Method] for just one or two BLOC/DT, but no improvement for the BLOC/DT leftover. That does not stand for a good

treatment/method. 

 

So this is a two-stage approach. 1) find the candidates which has improvement for as many as

BLOC/DT 2) the top solutions from 1) as good candidates, to find the best one(s) with the 

highest improvement. 

 

The goal function for Stage II can be to 1) Maximize the sum of the diffs between _tmin_orig and _tmin_x.

2) with customized penalty function, such as AVG(_tmin_orig-_tmin_x)/Stdev(_tmin_orig-_tmin_x)

 

Thanks alot

RobPratt
SAS Super FREQ

I see a few issues here:

  1. You cannot have = expression in a VAR statement.  You should keep the original impvar Score and max TotalScore declarations.
  2. The outcome parameter requires four arguments, not two: outcome[d,b,t,m], not outcome[d,b].
  3. You have not defined _time_orig[b].  Is this maybe supposed to be _tmin_orig[d,b,t]?
  4. Your MinScore declaration is missing a colon, and the right-hand side should depend on the previous objective function value.  Correct syntax is: con MinScore: TotalScore >= TotalScore.sol;

I'm not quite sure what you want the secondary objective to be, but here's an outline of the two stages:

   /* primary objective */
   solve;

   con MinScore: TotalScore >= TotalScore.sol;

   impvar difx {<d,b> in DATE_BLOCK} = sum {<(d),(b),t> in DATE_BLOCK_TREATMENT, m in METHODS} (_tmin_orig[d,b,t] - outcome[d,b,t,m]) * SelectTreatmentMethod[t,m];
   max TotalDif = sum {<d,b> in DATE_BLOCK} difx[d,b];

   /* secondary objective */
   solve with milp / primalin;

 

hellohere
Pyrite | Level 9

Thanks. It runs through. Let me take a while to digest. 

 

Attached is EXCEL/SOLVER, with all color-coded.  The Stage II has an additional constrain on the 

TotalScore from Stage I. 

 

 con MinScore: TotalScore >= TotalScore.sol;

TotalScore.sol is the TotalScore from each solution from the primary objective? If yes, 

then I bet this might be it. 

Anyway to set TotalScore.sol a specific value as THE THRESHOLD?!

Say the primary objective solutions: the highest TotalScore is 3 and most tops are

around -5 to 3; a judgement is made to set THE THRESHOLD=-5, the secondary objective

is to MAXIMIZE the sum of DIFX[_tmin_orig - _tmin_x/TREATMENT&METHOD] {{only if

_tmin_orig > _tmin_x, Otherwise 0; WELL OTHER PENALTY FUNCTIONS CAN BE APPLIED LATER ON}}. 

 

Stage I, below. 

SOLVER_Stage_1.jpg

 

Stage II, below. 

SOLVER_Stage_2.jpg

 

 

RobPratt
SAS Super FREQ

TotalScore.sol is the value of TotalScore from the most recent solver call.  You can alternatively use a manually specified threshold.  The following code changes yield the same objective values as in your Excel file:

   con CardinalityMethod:
      sum {m in METHODS} SelectMethod[m] = 1;

   /* primary objective */
   solve;

/*   con MinScore: TotalScore >= TotalScore.sol;*/
   con MinScore: TotalScore >= -5;

   impvar difx {<d,b> in DATE_BLOCK} = 
      sum {<(d),(b),t> in DATE_BLOCK_TREATMENT, m in METHODS} max(_tmin_orig[d,b,t] - outcome[d,b,t,m], 0) * SelectTreatmentMethod[t,m];
   max TotalDif = sum {<d,b> in DATE_BLOCK} difx[d,b];

   /* secondary objective */
   solve with milp / primalin;
   put TotalScore= TotalDif=;

The PUT statement shows the resulting objective values:

TotalScore=-3 TotalDif=13365

hellohere
Pyrite | Level 9

I am totally new to SAS/OPT, including the syntax. 

 

Inside EXCEL/SOLVER, the final solution for Stage II with TotalScor=-3. It was 3. 

hellohere
Pyrite | Level 9

@RobPratt

 

How to code-up a penalty function on the difference between _tmin_orig and _tmin_x?!

 

If _tmin_orig<=_tmin_x, score=-10

else if _tmin_orig>_tmin_x+60, score=2

else if _tmin_orig>_tmin_x+36, score=4

else if _tmin_orig>_tmin_x+24, score=8

else if _tmin_orig>_tmin_x+12, score=6

else if _tmin_orig>_tmin_x+6, score=2

else if _tmin_orig>_tmin_x+0, score=1

 

Thanks,