Writing piecewise constraints in GAMS - gams-math

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;

Related

consecutive days constraint in linear programming

For a work shift optimization problem, I've defined a binary variable in PuLP as follows:
pulp.LpVariable.dicts('VAR', (range(D), range(N), range(T)), 0, 1, 'Binary')
where
D = # days in each schedule we create (=28, or 4 weeks)
N = # of workers
T = types of work shift (=6)
For the 5th and 6th type of work shift (with index 4 and 5), I need to add a constraint that any worker who works these shifts must do so for seven consecutive days... and not any seven days but the seven days starting from Monday (aka a full week). I've tried defining the constraint as follows, but I'm getting an infeasible solution when I add this constraint and try to solve the problem (it worked before without it)
I know this constraint (along with the others from before) should theoretically be feasible because we manually schedule work shifts with the same set of constraints. Is there anything wrong with the way I've coded the constraint?
## looping over each worker
for j in range(N):
## looping for every Monday in the 28 days
for i in range(0,D,7):
c = None
## accessing only the 5th and 6th work shift type
for k in range(4,T):
c+=var[i][j][k]+var[i+1][j][k]+var[i+2][j][k]+var[i+3][j][k]+var[i+4][j][k]+var[i+5][j][k]+var[i+6][j][k]
problem+= c==7
If I understand correctly then your constraint requires that each worker is required to work the 4th and 5th shift in every week. This is because of c == 7, i.e. 7 of the binaries in c must be set to 1. This does not allow any worker to work in shift 0 through 3, right?
You need to change the constraint so that c == 7 is only enforced if the worker works any shift in that range. A very simple way to do that would be something like
v = list()
for k in range(4,T):
v.extend([var[i][j][k], var[i+1][j][k], var[i+2][j][k], var[i+3][j][k], var[i+4][j][k], var[i+5][j][k], var[i+6][j][k]])
c = sum(v)
problem += c <= 7 # we can pick at most 7 variables from v
for x in v:
problem += 7 * x <= c # if any variable in v is picked, then we must pick 7 of them
This is by no means the best way to model that (indicator variables would be much better), but it should give you an idea what to do.
Just to offer an alternative approach, assuming (as I read it) that for any given week a worker can either work some combination of shifts in [0:3] across the seven days, or one of the shifts [4:5] every day: we can do this by defining a new binary variable Y[w][n][t] which is 1 if in week w worker n does a restricted shift t, 0 otherwise. Then we can relate this variable to our existing variable X by adding constraints so that the values X can take depend on the values of Y.
# Define the sets of shifts
non_restricted_shifts = [0,1,2,3]
restricted_shifts = [4,5]
# Define a binary variable Y, 1 if for week w worker n works restricted shift t
Y = LpVariable.dicts('Y', (range(round(D/7)), range(N), restricted_shifts), cat=LpBinary)
# If sum(Y[week][n][:]) = 1, the total number of non-restricted shifts for that week and n must be 0
for week in range(round(D/7)):
for n in range(N):
prob += lpSum(X[d][n][t] for d in range(week*7, week*7 + 7) for t in non_restricted_shifts) <= 1000*(1-lpSum(Y[week][n][t] for t in restricted_shifts))
# If worker n has 7 restricted shift t in week w, then Y[week][n][t] == 1, otherwise it is 0
for week in range(round(D/7)):
for n in range(N):
for t in restricted_shifts:
prob += lpSum(X[d][n][t] for d in range(week*7, week*7+7)) <= 7*(Y[week][n][t])
prob += lpSum(X[d][n][t] for d in range(week*7, week*7+7)) >= Y[week][n][t]*7
Some example output (D=14, N=2, T=6):
/ M T W T F S S / M T W T F S S / M T W T F S S / M T W T F S S
WORKER 0
Shifts: / 2 3 1 3 3 2 2 / 1 0 2 3 2 2 0 / 3 1 2 2 3 1 1 / 2 3 0 3 3 0 3
WORKER 1
Shifts: / 3 1 2 3 1 1 2 / 3 3 2 3 3 3 3 / 4 4 4 4 4 4 4 / 1 3 2 2 3 2 1
WORKER 2
Shifts: / 1 2 3 1 3 1 1 / 3 3 2 2 3 2 3 / 3 2 3 0 3 1 0 / 4 4 4 4 4 4 4
WORKER 3
Shifts: / 2 2 3 2 1 2 3 / 5 5 5 5 5 5 5 / 3 1 3 1 0 3 1 / 2 2 2 2 3 0 3
WORKER 4
Shifts: / 5 5 5 5 5 5 5 / 3 3 1 0 2 3 3 / 0 3 3 3 3 0 2 / 3 3 3 2 3 2 3

How do I do it to just get a integer solution in 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.

Time complexity of nested for loop inside while loop

If there is a nested for loop inside while loop like this:
while(condition)
for(i=0; i<size; i++)
the size in the for loop is increasing every time the for loop is being executed, starting at 1,2,...,n-1
and the while loop runs n-1 times.
That means that the time complexity is O(n^3)?
If by every time the for loop is being executed you mean every time the while(condition) triggers a new run of the for loop, then the time complexity is .
That is, if you increment a counter inside the inner for loop, it will be incremented = n choose 2 times. But because constant factors and lower order terms are omitted in big O notation, we can just write .
For illustration, consider this Python 2.7 implementation (I converted the outer while loop + size increment into a for loop):
n = 10
counter = 0
for size in range(1, n):
for i in range(0, size):
counter += 1
print i,
print
print
print "counter =", counter
print "n choose 2 =", (n * (n - 1)) / 2
Output:
0
0 1
0 1 2
0 1 2 3
0 1 2 3 4
0 1 2 3 4 5
0 1 2 3 4 5 6
0 1 2 3 4 5 6 7
0 1 2 3 4 5 6 7 8
counter = 45
n choose 2 = 45
Try running it with different values of n to see that the formula holds true.

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

Formula for Buy 3 get 1 Free

I'm trying to write PL/SQL to get how much you pay if you purchase a certain amount of items. If you purchase 3 items, you get 1 free.
Therefore, for every 4th item purchased one of them is free. That means I pay for 3 items if 4 items are "purchased." If 10 items are attained then 8 should be paid for, 2 are free.
p-b v_p
*** ***
1 1 = 1
2 2 = 2
3 3 = 3
4 3(1) = 3
5 3(1) + 1 = 4
6 3(1) + 2 = 5
7 3(1) + 3 = 6
8 3(1) + 3(1) = 6
9 3(1) + 3(1) + 1 = 7
10 3(1) + 3(1) + 2 = 8
11 3(1) + 3(1) + 3 = 9
12 3(1) + 3(1) + 3(1) = 9
I've got
trunc(p-b / 3 * 2.4);
but my values are inconsistent.
Sometimes it works with
trunc(p-b / 3 * 2.25);
Am I doing the formula incorrectly? I'm supposed to be using trunc or mod.
To calculate the amount of Payed/Free stuff:
DECLARE
nAmount NUMBER := '10';
nPay NUMBER;
nFree NUMBER;
BEGIN
nPay := nAmount - TRUNC(nAmount / 4);
nFree := TRUNC(nAmount / 4);
DBMS_OUTPUT.PUT_LINE('Pay: ' || nPay);
DBMS_OUTPUT.PUT_LINE('Free: ' || nFree);
END;
/
I would use trunc and modulo
SELECT p-b, (trunc(p-b /4)) * 3 + mod(p-b, 4)
FROM your_table
demo
We can use the below formula to attain the result.
Assume n = p-b
n - ( n - mod( n, 4 ) ) / 4
Eg:
SELECT n, n - (n - mod(n,4))/4 result
FROM (SELECT LEVEL n
FROM DUAL
CONNECT BY LEVEL <= 12)
in simple way the result is:
p-b - trunc(p-b / 4);