Search
Close this search box.

Additional Scripts: Looping and Testing – 1

Writing “scripts” in the AMPL command language

All examples use steelT.mod as the model file and the steelT.dat as the data file.

Implements

Script 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";