Writing “scripts” in the AMPL command language
All examples use steelT.mod as the model file and the steelT.dat as the data file.
One pass of sensitivity analysis on avail[3] in the multi-period production problem (Section 4.2)
solve; display total_profit >steelT.sens; option display_1col 0; option omit_zero_rows 0; display Make >steelT.sens; display Sell >steelT.sens; option display_1col 20; option omit_zero_rows 1; display Inv >steelT.sens; let avail[3] := avail[3] + 5;
Same as steelT.sa1 but split into two scripts, using the commands command
solve; display total_profit >steelT.sens; commands steelT.sa1b; let avail[3] := avail[3] + 5;
option display_1col 0; option omit_zero_rows 0; display Make >steelT.sens; display Sell >steelT.sens; option display_1col 20; option omit_zero_rows 1; display Inv >steelT.sens;
Iterated sensitivity analysis, using contents of steelT.sa1a and steelT.sa1b within a for loop
model steelT.mod; data steelT.dat; for {1..4} { solve; display total_profit >steelT.sens; option display_1col 0; option omit_zero_rows 0; display Make >steelT.sens; display Sell >steelT.sens; option display_1col 20; option omit_zero_rows 1; display Inv >steelT.sens; let avail[3] := avail[3] + 5; }
. . . also building a table of results
model steelT.mod; data steelT.dat; set AVAIL3; param avail3_obj {AVAIL3}; param avail3_dual {AVAIL3}; let AVAIL3 := avail[3] .. avail[3] + 15 by 5; option solver_msg 0; for {a in AVAIL3} { let avail[3] := a; solve; let avail3_obj[a] := total_profit; let avail3_dual[a] := time[3].dual; } display avail3_obj, avail3_dual;
. . . also using repeat until, and building up an index set for the table
model steelT.mod; data steelT.dat; option solution_precision 10; option solver_msg 0; set AVAIL3 default {}; param avail3_obj {AVAIL3}; param avail3_dual {AVAIL3}; param avail3_step := 5; repeat { solve; let AVAIL3 := AVAIL3 union {avail[3]}; let avail3_obj[avail[3]] := total_profit; let avail3_dual[avail[3]] := time[3].dual; let avail[3] := avail[3] + avail3_step; } until time[3].dual = 0; display avail3_obj, avail3_dual;
. . . also using if to record only those parameter values at which the dual price changes
model steelT.mod; data steelT.dat; option solution_precision 10; option solver_msg 0; set AVAIL3 default {}; param avail3_obj {AVAIL3}; param avail3_dual {AVAIL3}; let avail[3] := 1; param avail3_step := 1; param previous_dual default Infinity; repeat while previous_dual > 0 { solve; if time[3].dual < previous_dual then { let AVAIL3 := AVAIL3 union {avail[3]}; let avail3_obj[avail[3]] := total_profit; let avail3_dual[avail[3]] := time[3].dual; let previous_dual := time[3].dual; } let avail[3] := avail[3] + avail3_step; } display avail3_obj, avail3_dual;
Binary search to find a breakpoint in the dual value
model steelT.mod; data steelT.dat; option solution_precision 10; option solver_msg 0; param avail3_lower default 22; param dual_lower; param avail3_upper default 23; param dual_upper; let avail[3] := avail3_lower; solve; let dual_lower := time[3].dual; let avail[3] := avail3_upper; solve; let dual_upper := time[3].dual; repeat { let avail[3] := (avail3_lower + avail3_upper) / 2; solve; if time[3].dual = dual_lower then let avail3_lower := avail[3]; else let avail3_upper := avail[3]; } until (avail3_upper - avail3_lower) / avail[3] < 0.0000001; printf "Dual value %11.6f for avail[3] < %9.6f\n", dual_lower, avail3_lower; printf "Dual value %11.6f for avail[3] > %9.6f\n", dual_upper, avail3_upper;
. . . also handling the case of more than one breakpoint in the initial interval
model steelT.mod; data steelT.dat; option solution_precision 10; option solver_msg 0; param avail3_lower default 0; param dual_lower; param avail3_upper default 70; param dual_upper; let avail[3] := avail3_lower; solve; let dual_lower := time[3].dual; let avail[3] := avail3_upper; solve; let dual_upper := time[3].dual; repeat { let avail[3] := (avail3_lower + avail3_upper) / 2; solve; if time[3].dual > dual_upper then { let avail3_lower := avail[3]; let dual_lower := time[3].dual; } else let avail3_upper := avail[3]; } until (avail3_upper - avail3_lower) / avail[3] < 0.0000001; printf "Dual value %11.6f for avail[3] < %9.6f\n", dual_lower, avail3_lower; printf "Dual value %11.6f for avail[3] > %9.6f\n", dual_upper, avail3_upper;
. . . also counting the extra breakpoints detected
model steelT.mod; data steelT.dat; option solution_precision 10; option solver_msg 0; param avail3_lower default 0; param dual_lower; param avail3_upper default 70; param dual_upper; param other_bkpts default 0; let avail[3] := avail3_lower; solve; let dual_lower := time[3].dual; let avail[3] := avail3_upper; solve; let dual_upper := time[3].dual; repeat { let avail[3] := (avail3_lower + avail3_upper) / 2; solve; if time[3].dual = dual_lower then let avail3_lower := avail[3]; else if time[3].dual = dual_upper then let avail3_upper := avail[3]; else { let other_bkpts := other_bkpts + 1; let avail3_lower := avail[3]; let dual_lower := time[3].dual; }; } until (avail3_upper - avail3_lower) / avail[3] < 0.0000001; printf "Dual value %11.6f for avail[3] < %9.6f\n", dual_lower, avail3_lower; printf "Dual value %11.6f for avail[3] > %9.6f\n", dual_upper, avail3_upper; if other_bkpts > 0 then printf "Additional breakpoints detected: %2d\n", other_bkpts; ;
Sensitivity analysis using break and continue
model steelT.mod; data steelT.dat; option solution_precision 10; option solver_msg 0; set AVAIL3 default {}; param avail3_obj {AVAIL3}; param avail3_dual {AVAIL3}; let avail[3] := 0; param previous_dual default Infinity; repeat { let avail[3] := avail[3] + 1; solve; if time[3].dual = previous_dual then continue; let AVAIL3 := AVAIL3 union {avail[3]}; let avail3_obj[avail[3]] := total_profit; let avail3_dual[avail[3]] := time[3].dual; if time[3].dual = 0 then break; let previous_dual := time[3].dual; } display avail3_obj, avail3_dual;
. . . also for each t, printing at the end of each pass
model steelT.mod; data steelT.dat; option solution_precision 10; option solver_msg 0; set AVAILt; param availt_obj {AVAILt}; param availt_dual {AVAILt}; param avail_orig; param previous_dual; for {t in 1..T} { let AVAILt := {}; reset data availt_obj; reset data availt_dual; let avail_orig := avail[t]; let avail[t] := 0; let previous_dual := Infinity; repeat { let avail[t] := avail[t] + 1; solve; if time[t].dual = previous_dual then continue; let AVAILt := AVAILt union {avail[t]}; let availt_obj[avail[t]] := total_profit; let availt_dual[avail[t]] := time[t].dual; if time[t].dual = 0 then break; let previous_dual := time[t].dual; } let avail[t] := avail_orig; display t, availt_obj, availt_dual; }
. . . also for each t, storing all values until the end
model steelT.mod; data steelT.dat; option solution_precision 10; option solver_msg 0; set AVAIL {1..T} default {}; param avail_obj {t in 1..T, AVAIL[t]}; param avail_dual {t in 1..T, AVAIL[t]}; param avail_orig; param previous_dual; for {t in 1..T} { let AVAIL[t] := {}; let avail_orig := avail[t]; let avail[t] := 0; let previous_dual := Infinity; repeat { let avail[t] := avail[t] + 1; solve; if time[t].dual = previous_dual then continue; let AVAIL[t] := AVAIL[t] union {avail[t]}; let avail_obj[t,avail[t]] := total_profit; let avail_dual[t,avail[t]] := time[t].dual; if time[t].dual = 0 then break; let previous_dual := time[t].dual; } let avail[t] := avail_orig; } display {t in 1..T}: {a in AVAIL[t]} (avail_obj[t,a], avail_dual[t,a]);
. . . also incorporating a break criterion requiring a named loop
model steelT.mod; data steelT.dat; option solution_precision 10; option solver_msg 0; set AVAIL3 default {}; param avail3_obj {AVAIL3}; param avail3_dual {AVAIL3}; let avail[3] := 0; param previous_dual default Infinity; repeat sens_loop { let avail[3] := avail[3] + 1; solve; if time[3].dual = previous_dual then continue; let AVAIL3 := AVAIL3 union {avail[3]}; let avail3_obj[avail[3]] := total_profit; let avail3_dual[avail[3]] := time[3].dual; for {t in 1..T} if time[t].dual < 2700 then break sens_loop; let previous_dual := time[3].dual; } display avail3_obj, avail3_dual;
Data-specific script for a formatted table
printf "\n%s%14s%17s\n", "SALES", "bands", "coils"; printf {t in 1..T}: "week %d%9d%7.1f%%%9d%7.1f%%\n", t, Sell["bands",t], 100*Sell["bands",t]/market["bands",t], Sell["coils",t], 100*Sell["coils",t]/market["coils",t];
General script for formatted table, using a for loop
printf "\nSALES"; printf {p in PROD}: "%14s ", p; printf "\n"; for {t in 1..T} { printf "week %d", t; for {p in PROD} { printf "%9d", Sell[p,t]; printf "%7.1f%%", 100 * Sell[p,t]/market[p,t]; } # printf {p in PROD}: # "%9d%7.1f%%", Sell[p,t], 100*Sell[p,t]/market[p,t]; printf "\n"; } printf "\n";
. . . also with if statement to suppress printing of 100%
printf "\nSALES"; printf {p in PROD}: "%14s ", p; printf "\n"; for {t in 1..T} { printf "week %d", t; for {p in PROD} { printf "%9d", Sell[p,t]; if Sell[p,t] < market[p,t] then printf "%7.1f%%", 100 * Sell[p,t]/market[p,t]; else printf " --- "; } printf "\n"; } printf "\n";