How do I do it to just get a integer solution in AMPL? - ampl

We make phones. We have selling price, production cost, profit.
The goal is to maximize profits.
The following components are required to assemble each phone.
Maximum quantity of components .
Orders (so many phones were ordered from us, we sold them) :
Here is my mod file:
set PHONE;
set COMPONENTS;
param price {PHONE} >= 0;
param cost {PHONE} >= 0;
param maxComponents {COMPONENTS} >= 0;
param ordered {PHONE} >= 0;
param matrix {COMPONENTS, PHONE}; #The amount of components needed to make a particular phone.
var x {PHONE} >= 0; # Number of manufactured telephones.
maximize profit: sum {i in PHONE} ( ordered[i] * price[i] - x[i] * cost[i] );
subject to min_manufacture {i in PHONE}:
x[i] >= ordered[i]; # We must produce a minimum of what is ordered
subject to component {i in COMPONENTS}:
sum {j in PHONE} matrix[i,j] * x[j] <= maxComponents[i]; # The number of components used must not exceed the maximum.
subject to min_quantity {i in COMPONENTS, l in PHONE}:
sum {j in PHONE} matrix[i,j] * x[j] >= matrix[i,l]; # Minimum quantity used per component if we manufacture at least one telephone. For example, a triple phone requires at least 2 of the five components.
and dat file:
set PHONE := 1 2 3 4 5;
set COMPONENTS:= 1 2 3 4 5 6 7;
param price :=
1 450
2 120
3 500
4 390
5 100;
param cost :=
1 370
2 90
3 400
4 320
5 70;
param maxComponents :=
1 28
2 20
3 8
4 30
5 47
6 27
7 15;
param ordered :=
1 3
2 5
3 5
4 0
5 10;
param matrix: 1 2 3 4 5 :=
1 1 1 0 0 0
2 1 1 0 0 0
3 1 0 0 0 0
4 1 0 1 1 0
5 0 0 2 1 1
6 0 0 2 1 0
7 0 0 1 1 0;
The problem is that if, for example, the maximum amount of sixth components is three, the maximum amount of seventh components is two , then 1.5 is produced from the triple phone which cannot be . And quantity used of the fourth, fifth, sixth, seventh components for the triple phone 1,5 3 3 1,5 which also cannot be.
How do I do it to just get a integer solution?
Because if I write to the variable x that it's an integer, I get zero for everything.
My run file:
model phone.mod;
data phone.dat;
option presolve 0;
option solver cplex;
solve;
display profit, x;
display {i in COMPONENTS, j in PHONE} matrix[i,j] * x[j];

You need to declare the relevant variables as integer, like so:
var x {PHONE} >= 0 integer;
Some solvers are not able to deal with integer constraints and may ignore that constraint (with a warning message) but CPLEX should be fine.

Related

Writing piecewise constraints in GAMS

I'm trying to solve the network problem below in GAMS Cplex. I have a piecewise constraint that depend on the node situations (whether a node is an origin (o) node, in between node, and destination (d) node).
How do I write these piecewise constraints? Or is there any way to write this 'manually' for the equation 1 to 5?
In the program below, I've written:
eq1 represents node 1 as an origin node,
eq2 eq3 eq4 represents node 2,3, and 4 as in between nodes,
eq5 represents node 5 as a destination node.
Set
i nodes /1,2,3,4,5/;
Alias(i,j);
Set
arc(i,j) arcs from node i to j
/1 .2
2 .1
1 .3
3 .1
1 .4
4 .1
2 .3
3 .2
2 .5
5 .2
3 .5
5 .3
4 .5
5 .4/;
Table c(i,j) population exposed from node i to node j
1 2 3 4 5
1 0 105000 90000 65000 0
2 105000 0 100000 0 85000
3 90000 100000 0 0 80000
4 65000 0 0 0 55000
5 0 85000 80000 55000 0
;
Table l(i,j) distance from node i to node j
1 2 3 4 5
1 0 5 8 10 0
2 5 0 2 0 7
3 8 2 0 0 11
4 10 0 0 0 8
5 0 7 11 8 0
Binary Variables
x(i,j)
y(i,j);
Positive Variables
v(i,j)
lambda(i,j);
Free Variables
w(i) node i
w(j) node j
z optimization solution;
Scalar
R very large number;
R = 10000000000000000;
Equations
sol optimization solution
eq1(i,j) constraint 1
eq2(i,j) constraint 2
eq3(i,j) constraint 3
eq4(i,j) constraint 4
eq5(i,j) constraint 5
eq6(i,j) constraint 6
eq7(i,j) constraint 7
eq8(i,j) constraint 8
eq9(i,j) constraint 9;
sol.. z =e= sum(arc(i,j),c(arc)*x(arc));
eq1(i,j).. x(1,2) - x(2,1) + x(1,3) - x(3,1) + x(1,4) - x(4,1) =e= 1;
eq2(i,j).. - x(1,2) + x(2,1) + x(2,3) - x(3,2) + x(2,5) - x(5,2) =e= 0;
eq3(i,j).. - x(1,3) + x(3,1) - x(2,3) + x(3,2) + x(3,5) - x(5,3) =e= 0;
eq4(i,j).. - x(1,4) + x(4,1) + x(4,5) - x(5,4) =e= 0;
eq5(i,j).. - x(2,5) + x(5,2) - x(3,5) + x(5,3) - x(4,5) + x(5,4) =e= -1;
eq6(i,j).. - y(i,j) + x(i,j) =l= 0;
eq7(i,j).. l(i,j) - w(i) + w(j) - v(i,j) + lambda(i,j) =e= 0;
eq8(i,j).. v(i,j) - R * (1 - x(i,j)) =l= 0;
eq9(i,j).. lambda(i,j) - R * (1 - (y(i,j) - x(i,j))) =l= 0;
Model contohTMB /all/;
Solve contohTMB using MIP Minimizing z;
Display "Solution values:"
Display
x.l, z.l;

how I can initialize a parameter in AMPL when it is defined on multiple sets?

Suppose I have
param m; #number of modes
param n; #number of individual
param a; #number of alternatives
param f; #number of household
set M, default{1..m}; #set of modes
set N, default{1..n}; #set of individuals
set A, default{1..a}; #set of alternatives
set F, default{1..f}; #set of family
set E, within F cross N
How I can initialize param X{E,M,A} ?
Suppose
a:=2 , m:=3 , n:= 4 f:=2;
and set E is defined:
set E:= 1 1 1 2 2 3 2 4 ;
You can declare the parameter just as you suggested:
param X{E,M,A};
Now, if you want to provide a default value (which I assume is what you are asking), you can do it in the usual way:
param X{E,M,A} default 0;
Then provide some non-default values in the .dat file, e.g.,:
param: X :=
1 1 1 2 5
2 3 2 1 6;
Note that AMPL doesn't fill the default values into the parameter until you call solve. From the AMPL book, p. 120:
The expression that gives the default value of a parameter is evaluated only when the parameter’s value is first needed, such as when an objective or constraint that uses the parameter is processed by a solve command.
So if you type display X; after you have issued the model and data commands but before you have issued the solve command, you'll only get the non-default values, e.g.:
X :=
1 1 1 2 5
2 3 2 1 6
;
But if you use display X; after you call solve, you'll get the full list:
X [1,*,*,1] (tr)
: 1 2 :=
1 0 0
2 0 0
3 0 0
[1,*,*,2] (tr)
: 1 2 :=
1 5 0
2 0 0
3 0 0
[2,*,*,1] (tr)
: 3 4 :=
1 0 0
2 6 0
3 0 0
[2,*,*,2] (tr)
: 3 4 :=
1 0 0
2 0 0
3 0 0
;
For completeness, here are the .mod and .dat files I used for this answer:
.mod:
param m; #number of modes
param n; #number of individual
param a; #number of alternatives
param f; #number of household
set M, default{1..m}; #set of modes
set N, default{1..n}; #set of individuals
set A, default{1..a}; #set of alternatives
set F, default{1..f}; #set of family
set E, within F cross N;
param X{E,M,A} default 0;
var myVar{E,M,A} >= 0;
minimize Obj: sum {(i,j) in E, mm in M, aa in A} X[i,j,mm,aa] * myVar[i,j,mm,aa];
.dat:
param a:=2;
param m:=3;
param n:= 4;
param f:=2;
set E:= 1 1 1 2 2 3 2 4 ;
param: X :=
1 1 1 2 5
2 3 2 1 6;

Minimum Network Flow in GAMS

I am trying to solve below network problem in GAMS Cplex. I am unable to get the desired output as the GAMS is giving the arcs which doesnt exist as output. Could you please help me in correcting this.
Program:
Set
i supply nodes /1,2,3,4/;
Alias(i,j);
Set
arc(i,j) arcs from node i to j
/1 .2
2 .3
3 .4
1 .4
2 .4/;
Parameter b(i) number of units available or required at node i
/ 1 5
2 2
3 -4
4 -3/ ;
Table c(i,j) cost of shipping from node i to node j
1 2 3 4
1 0 3 0 1
2 0 0 6 5
3 0 0 0 0
4 0 0 2 0 ;
Positive variables
x(i,j) number of units shipped along arc from i to j;
Variable z;
Equations obj, cons(i);
obj.. z =E= sum(arc(i,j),c(arc)*x(arc));
cons(i).. sum(j,x(i,j)) - sum(j,x(j,i)) =E= b(i);
I think you need to use the set "arc" in your constraints "cons" like this:
cons(i).. sum(arc(i,j),x(i,j)) - sum(arc(j,i),x(j,i)) =E= b(i);
Hope that helps,
Lutz

SAS Proc Optmodel Constraint Syntax

I have an optimization exercise I am trying to work through and am stuck again on the syntax. Below is my attempt, and I'd really like a thorough explanation of the syntax in addition to the solution code. I think it's the specific index piece that I am having trouble with.
The problem:
I have an item that I wish to sell out of within ten weeks. I have a historical trend and wish to alter that trend by lowering price. I want maximum margin dollars. The below works, but I wish to add two constraints and can't sort out the syntax. I have spaces for these two constraints in the code, with my brief explanation of what I think they may look like. Here is a more detailed explanation of what I need each constraint to do.
inv_cap=There is only so much inventory available at each location. I wish to sell it all. For location 1 it is 800, location 2 it is 1200. The sum of the column FRC_UNITS should equal this amount, but cannot exceed it.
price_down_or_same=The price cannot bounce around, so it needs to always be less than or more than the previous week. So, price(i)<=price(i-1) where i=week.
Here is my attempt. Thank you in advance for assistance.
*read in data;
data opt_test_mkdown_raw;
input
ITM_NBR
ITM_DES_TXT $
LCT_NBR
WEEK
LY_UNITS
ELAST
COST
PRICE
TOTAL_INV;
cards;
1 stuff 1 1 300 1.2 6 10 800
1 stuff 1 2 150 1.2 6 10 800
1 stuff 1 3 100 1.2 6 10 800
1 stuff 1 4 60 1.2 6 10 800
1 stuff 1 5 40 1.2 6 10 800
1 stuff 1 6 20 1.2 6 10 800
1 stuff 1 7 10 1.2 6 10 800
1 stuff 1 8 10 1.2 6 10 800
1 stuff 1 9 5 1.2 6 10 800
1 stuff 1 10 1 1.2 6 10 800
1 stuff 2 1 400 1.1 6 9 1200
1 stuff 2 2 200 1.1 6 9 1200
1 stuff 2 3 100 1.1 6 9 1200
1 stuff 2 4 100 1.1 6 9 1200
1 stuff 2 5 100 1.1 6 9 1200
1 stuff 2 6 50 1.1 6 9 1200
1 stuff 2 7 20 1.1 6 9 1200
1 stuff 2 8 20 1.1 6 9 1200
1 stuff 2 9 5 1.1 6 9 1200
1 stuff 2 10 3 1.1 6 9 1200
;
run;
data opt_test_mkdown_raw;
set opt_test_mkdown_raw;
ITM_LCT_WK=cats(ITM_NBR, LCT_NBR, WEEK);
ITM_LCT=cats(ITM_NBR, LCT_NBR);
run;
proc optmodel;
*set variables and inputs;
set<string> ITM_LCT_WK;
number ITM_NBR{ITM_LCT_WK};
string ITM_DES_TXT{ITM_LCT_WK};
string ITM_LCT{ITM_LCT_WK};
number LCT_NBR{ITM_LCT_WK};
number WEEK{ITM_LCT_WK};
number LY_UNITS{ITM_LCT_WK};
number ELAST{ITM_LCT_WK};
number COST{ITM_LCT_WK};
number PRICE{ITM_LCT_WK};
number TOTAL_INV{ITM_LCT_WK};
*read data into procedure;
read data opt_test_mkdown_raw into
ITM_LCT_WK=[ITM_LCT_WK]
ITM_NBR
ITM_DES_TXT
ITM_LCT
LCT_NBR
WEEK
LY_UNITS
ELAST
COST
PRICE
TOTAL_INV;
var NEW_PRICE{i in ITM_LCT_WK};
impvar FRC_UNITS{i in ITM_LCT_WK}=(1-(NEW_PRICE[i]-PRICE[i])*ELAST[i]/PRICE[i])*LY_UNITS[i];
con ceiling_price {i in ITM_LCT_WK}: NEW_PRICE[i]<=PRICE[i];
/*con inv_cap {j in ITM_LCT}: sum{i in ITM_LCT_WK}=I want this to be 800 for location 1 and 1200 for location 2;*/
con supply_last {i in ITM_LCT_WK}: FRC_UNITS[i]>=LY_UNITS[i];
/*con price_down_or_same {j in ITM_LCT} : NEW_PRICE[week]<=NEW_PRICE[week-1];*/
*state function to optimize;
max margin=sum{i in ITM_LCT_WK}
(NEW_PRICE[i]-COST[i])*(1-(NEW_PRICE[i]-PRICE[i])*ELAST[i]/PRICE[i])*LY_UNITS[i];
/*expand;*/
solve;
*write output dataset;
create data results_MKD_maxmargin
from
[ITM_LCT_WK]={ITM_LCT_WK}
ITM_NBR
ITM_DES_TXT
LCT_NBR
WEEK
LY_UNITS
FRC_UNITS
ELAST
COST
PRICE
NEW_PRICE
TOTAL_INV;
*write results to window;
print
/*NEW_PRICE */
margin;
quit;
The main difficulty is that in your application, decisions are indexed by (Item,Location) pairs and Weeks, but in your code you have merged (Item,Location,Week) triplets. I rather like that use of the data step, but the result in this example is that your code is unable to refer to specific weeks and to specific pairs.
The fix that changes your code the least is to add these relationships by using defined sets and inputs that OPTMODEL can compute for you. Then you will know which triplets refer to each combination of (Item,Location) pair and week:
/* This code creates a set version of the Item x Location pairs
that you already have as strings */
set ITM_LCTS = setof{ilw in ITM_LCT_WK} itm_lct[ilw];
/* For each Item x Location pair, define a set of which
Item x Location x Week entries refer to that Item x Location */
set ILWperIL{il in ITM_LCTS} = {ilw in ITM_LCT_WK: itm_lct[ilw] = il};
With this relationship you can add the other two constraints.
I left your code as is, but applied to the new code a convention I find useful, especially when there are similar names like itm_lct and ITM_LCTS:
sets as all caps;
input parameters start with lowercase;
output (vars, impvars, and constraints) start with Uppercase */
Here is the new OPTMODEL code:
proc optmodel;
*set variables and inputs;
set<string> ITM_LCT_WK;
number ITM_NBR{ITM_LCT_WK};
string ITM_DES_TXT{ITM_LCT_WK};
string ITM_LCT{ITM_LCT_WK};
number LCT_NBR{ITM_LCT_WK};
number WEEK{ITM_LCT_WK};
number LY_UNITS{ITM_LCT_WK};
number ELAST{ITM_LCT_WK};
number COST{ITM_LCT_WK};
number PRICE{ITM_LCT_WK};
number TOTAL_INV{ITM_LCT_WK};
*read data into procedure;
read data opt_test_mkdown_raw into
ITM_LCT_WK=[ITM_LCT_WK]
ITM_NBR
ITM_DES_TXT
ITM_LCT
LCT_NBR
WEEK
LY_UNITS
ELAST
COST
PRICE
TOTAL_INV;
var NEW_PRICE{i in ITM_LCT_WK} <= price[i];
impvar FRC_UNITS{i in ITM_LCT_WK} =
(1-(NEW_PRICE[i]-PRICE[i])*ELAST[i]/PRICE[i]) * LY_UNITS[i];
* Moved to bound
con ceiling_price {i in ITM_LCT_WK}: NEW_PRICE[i] <= PRICE[i];
con supply_last{i in ITM_LCT_WK}: FRC_UNITS[i] >= LY_UNITS[i];
/* This code creates a set version of the Item x Location pairs
that you already have as strings */
set ITM_LCTS = setof{ilw in ITM_LCT_WK} itm_lct[ilw];
/* For each Item x Location pair, define a set of which
Item x Location x Week entries refer to that Item x Location */
set ILWperIL{il in ITM_LCTS} = {ilw in ITM_LCT_WK: itm_lct[ilw] = il};
/* I assume that for each item and location
the inventory is the same for all weeks for convenience,
i.e., that is not a coincidence */
num inventory{il in ITM_LCTS} = max{ilw in ILWperIL[il]} total_inv[ilw];
con inv_cap {il in ITM_LCTS}:
sum{ilw in ILWperIL[il]} Frc_Units[ilw] = inventory[il];
num lastWeek = max{ilw in ITM_LCT_WK} week[ilw];
/* Concatenating indexes is not the prettiest, but gets the job done here*/
con Price_down_or_same {il in ITM_LCTS, w in 2 .. lastWeek}:
New_Price[il || w] <= New_Price[il || w - 1];*/
*state function to optimize;
max margin=sum{i in ITM_LCT_WK}
(NEW_PRICE[i]-COST[i])*(1-(NEW_PRICE[i]-PRICE[i])*ELAST[i]/PRICE[i])*LY_UNITS[i];
expand;
solve;
*write output dataset;
create data results_MKD_maxmargin
from
[ITM_LCT_WK]={ITM_LCT_WK}
ITM_NBR
ITM_DES_TXT
LCT_NBR
WEEK
LY_UNITS
FRC_UNITS
ELAST
COST
PRICE
NEW_PRICE
TOTAL_INV;
*write results to window;
print
NEW_PRICE FRC_UNITS
margin
;
quit;

Proc Optmodel SAS Maintaining Defined Separation within Group

I am relatively new to proc optmodel and have been struggling with syntax/structure. I was able to get help once before and am stuck again.
Here is my dataset:
data have;
input NAME $ TEAM $ LEAD GRADE XXX MIN MAX YYY RATE;
cards;
HAL A 1 1 50 45 55 100 1.1
SAL A 0 2 55 0 9999 200 1
KIM A 0 3 70 0 9999 50 1.4
JIM B 1 2 100 90 110 300 .95
GIO B 0 3 120 0 9999 50 1
CAL B 0 4 130 0 9999 20 .9
TOM C 1 1 2 1 5 20 .7
SUE C 0 3 5 0 9999 10 .5
VAL D 1 7 20 15 25 100 .6
WHO D 0 4 10 0 9999 10 .9
;
run;
Here are the specifics:
1. Only the "team lead" has any meaningful constraints.
2. However, the other members of the team will be adjusted accordingly. The value of XXX will be ten percent lower or higher relative to the difference in grade from the team lead. So, if HAL's NEW_XXX is 50 (stays same), then SAL will be 10% higher than HAL's (2 is 1 unit greater than 1) which is 55. KIM's NEW_XXX is 60, since this is twenty percent higher than HAL (3 is 2 units greater than 1. SImilarly, WHO's NEW_XXX will be 30% lower than VAL's.
Does that make sense?
Below is what I have so far, which is the skeleton from a similar project.
proc optmodel;
*set variables and inputs;
set<string>NAME;
string TEAM{NAME};
number LEAD{NAME};
number GRADE{NAME};
number XXX{NAME};
number MIN{NAME};
number MAX{NAME};
number YYY{NAME};
number RATE{NAME};
set TEAMS = setof{i in NAME} TEAM[i];
set NAMEperTEAM{gi in TEAMS} = {i in NAME: TEAM[i] = gi};
var NEW_XXX{i in NAME}>=MIN[i]<=MAX[i];
*read data into procedure;
read data have into
NAME=[NAME]
TEAM
LEAD
GRADE
XXX
MIN
MAX
YYY
RATE;
*state function to optimize;
max metric=sum{gi in TEAMS}
sum{i in NAMEperTEAM[gi]}
(NEW_XXX[i])*(1-(NEW_XXX[i]-XXX[i])*RATE[i]/XXX[i])*YYY[i];
expand;
solve;
*write output dataset;
create data results
from [NAME]={NAME}
TEAM
LEAD
GRADE
XXX
NEW_XXX
MIN
MAX
RATE
YYY;
*write results to window;
print NEW_XXX metric;
quit;
If I understand this correctly, you need set the non-team leads NEW_XXX variable in an equality constraint. That leaves only the team lead NEW_XXX variables free for the optimization.
Let me know if this is what you are trying to accomplish.
Here's how I did it:
proc optmodel;
*set variables and inputs;
set<string> NAME;
string TEAM{NAME};
number LEAD{NAME};
number GRADE{NAME};
number XXX{NAME};
number MIN{NAME};
number MAX{NAME};
number YYY{NAME};
number RATE{NAME};
*read data into procedure;
read data have into
NAME=[NAME]
TEAM
LEAD
GRADE
XXX
MIN
MAX
YYY
RATE;
set TEAMS = setof{i in NAME} TEAM[i];
set NAMEperTEAM{gi in TEAMS} = {i in NAME: TEAM[i] = gi};
/*Helper array that gives me the team leader for each team*/
str LEADS{TEAMS};
for {i in NAME: LEAD[i] = 1} do;
LEADS[TEAM[i]] = i;
end;
var NEW_XXX{i in NAME} init XXX[i] >=MIN[i]<=MAX[i];
*state function to optimize;
max metric=sum{gi in TEAMS}(
sum{i in NAMEperTEAM[gi]} (
(NEW_XXX[i])*(1-(NEW_XXX[i]-XXX[i])*RATE[i]/XXX[i])*YYY[i]
)
);
/*Constrain the non-lead members*/
con NonLeads{i in NAME: LEAD[i] = 0}: NEW_XXX[i] = (1 + (GRADE[i] - GRADE[LEADS[TEAM[i]]]) * 0.1) * NEW_XXX[LEADS[TEAM[i]]] ;
expand;
solve;
*write output dataset;
create data results
from [NAME]={NAME}
TEAM
LEAD
GRADE
XXX
NEW_XXX
MIN
MAX
RATE
YYY;
*write results to window;
print new_xxx metric;
quit;