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,
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
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
I see a few issues here:
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;
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.
Stage II, below.
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
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.
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,
Please open a new question for that.
Dive into keynotes, announcements and breakthroughs on demand.
Explore Now →