LP: postive reduced costs corresponding to positive variables? - optimization

I have the next LP problem
Maximize
1000 x1 + 500 x2 - 500 x5 - 250 x6
Subject To
c1: x1 + x2 - x3 - x4 = 0
c2: - x3 + x5 = 0
c3: - x4 + x6 = 0
With these Bounds
0 <= x1 <= 10
0 <= x2 <= 15
0 <= x5 <= 15
0 <= x6 <= 5
By solving this problem with Cplex dual algorithm I get an optimal solution of 6250. But checking the reduced costs of the variables I get the next results
Variable value reduced cost
1 10.0 500.0
1 0.0 -0.0
2 5.0 -0.0
3 5.0 -0.0
4 5.0 -0.0
5 5.0 250.0
Is it possible to have a positive reduced cost on a positive valued variable? Because the reduced cost value indicates how much the objective function coefficient on the corresponding variable must be improved before the value of the variable will be positive in the optimal solution, what does a positive reduced cost means on a postive valued variable?

Variable 1 is listed twice in the solution?
Note that you need to distinguish between nonbasic at lower bound and nonbasic at upper bound. The reduced cost indicates how much the objective can change when the corresponding bound changes by one unit.
Note also that most textbooks focus on the special case x >= 0 while practical solvers support both lower and upper bounds: L <= x <= U.

Related

Optimization between 2 dependent variables

I couldn't find a solution nowhere, so I'm asking here. Hope someone knows how to guide me thru.
So, I'm not quite sure if this is a optimization problem (if anyone know what kind of problem is this, let me know), but I need to find the quantity of clients that each attendant has to have so that each has the same amount of orders. I don't know if there is a function or a regression that could be made of this.
Column A has the clients name. Column B has the "difficulty" that each client is to assist - that is, "1" is normal difficulty, "2" is double the normal difficulty and so on - meaning that the orders of this clients will be multiplied by his difficulty. Column C has a spec that only attendant Y can assist. Column D has the quantity of orders that each client requested. And finally column E is the account attendant.
CLIENT
ATTENTION
SPEC
ORDERS
ATTENDANT
a1
3
0
6
y
a2
3
0
7
x
a3
1
0
1
y
a4
1
0
9
y
a5
2
0
6
y
a6
1
0
7
y
a7
3
0
2
y
a8
3
0
9
x
a9
3
0
9
y
a10
2
1
8
y
a11
2
0
8
x
a12
2
0
9
y
a13
1
1
2
y
a14
2
0
4
x
a15
3
0
10
y
a16
2
0
9
x
a17
2
0
8
y
a18
1
1
5
y
a19
3
0
8
x
a20
1
1
3
y
a21
2
0
10
x
a22
2
0
6
x
Summary tables:
ATTENDANT
TOTAL ORDERS
x
61
y
84
ATTENDANT
TOTAL CLIENTS
x
8
y
14
ATTENDANT
TOTAL ORDERS
x
61
y
84
y (spec 0)
66
y (spec 1)
18
Here is a linear program that solves this. Fun problem! This uses the pyomo environment and the separately installed glpk solver. Result: It's a tie! X and Y don't need to haggle! ;)
Code:
# client assignment
import csv
from collections import namedtuple
import pyomo.environ as pyo
data_file = 'data.csv'
Record = namedtuple('Record', ['attention', 'spec', 'orders'])
records = {}
with open(data_file, 'r') as src:
src.readline() # burn header row
reader = csv.reader(src, skipinitialspace=True)
for line in reader:
record = Record(int(line[1]), int(line[2]), int(line[3]))
records[line[0]] = record
#print(records)
# set up the ILP
m = pyo.ConcreteModel()
# SETS
m.C = pyo.Set(initialize=records.keys()) # the set of clients
m.A = pyo.Set(initialize=['X', 'Y']) # the set of attendants
# PARAMETERS
m.attention = pyo.Param(m.C, initialize={c: r.attention for (c, r) in records.items()})
m.y_required = pyo.Param(m.C, initialize={c: r.spec for (c, r) in records.items()})
m.orders = pyo.Param(m.C, initialize={c: r.orders for (c, r) in records.items()})
# VARIABLES
m.assign = pyo.Var(m.A, m.C, domain=pyo.Binary) # 1: assign attendant a to client c
m.work_delta = pyo.Var(domain=pyo.NonNegativeReals) # the abs(work difference)
# OBJECTIVE
# minimize the work delta...
m.obj = pyo.Objective(expr=m.work_delta)
# CONSTRAINTS
# each client must be serviced once and only once
def service(m, c):
return sum(m.assign[a, c] for a in m.A) == 1
m.C1 = pyo.Constraint(m.C, rule=service)
# y-specific customers must be serviced by attendant y, and optionally if not reqd.
def y_serves(m, c):
return m.assign['Y', c] >= m.y_required[c]
m.C2 = pyo.Constraint(m.C, rule=y_serves)
# some convenience expressions to capture work...
m.y_work = sum(m.attention[c] * m.orders[c] * m.assign['Y', c] for c in m.C)
m.x_work = sum(m.attention[c] * m.orders[c] * m.assign['X', c] for c in m.C)
# capture the ABS(y_work - x_work) with 2 constraints
m.C3a = pyo.Constraint(expr=m.work_delta >= m.y_work - m.x_work)
m.C3b = pyo.Constraint(expr=m.work_delta >= m.x_work - m.y_work)
# check the model
#m.pprint()
# SOLVE
solver = pyo.SolverFactory('glpk')
res = solver.solve(m)
# ensure the result is optimal
status = res.Solver()['Termination condition'].value
assert(status == 'optimal', f'error occurred, status: {status}. Check model!')
print(res)
print(f'x work: {pyo.value(m.x_work)} units')
print(f'y work: {pyo.value(m.y_work)} units')
# list assignments
for c in m.C:
for a in m.A:
if pyo.value(m.assign[a, c]):
print(f'Assign {a} to customer {c}')
Output:
Problem:
- Name: unknown
Lower bound: 0.0
Upper bound: 0.0
Number of objectives: 1
Number of constraints: 47
Number of variables: 46
Number of nonzeros: 157
Sense: minimize
Solver:
- Status: ok
Termination condition: optimal
Statistics:
Branch and bound:
Number of bounded subproblems: 53
Number of created subproblems: 53
Error rc: 0
Time: 0.008551836013793945
Solution:
- number of solutions: 0
number of solutions displayed: 0
x work: 158.0 units
y work: 158.0 units
Assign Y to customer a1
Assign Y to customer a2
Assign X to customer a3
Assign Y to customer a4
Assign Y to customer a5
Assign Y to customer a6
Assign Y to customer a7
Assign Y to customer a8
Assign X to customer a9
Assign Y to customer a10
Assign X to customer a11
Assign X to customer a12
Assign Y to customer a13
Assign X to customer a14
Assign X to customer a15
Assign X to customer a16
Assign X to customer a17
Assign Y to customer a18
Assign X to customer a19
Assign Y to customer a20
Assign Y to customer a21
Assign Y to customer a22
[Finished in 588ms]
In Excel Solver
Note: in the solver options, be sure to de-select "ignore integer constraints"
This seems to work OK. The green shaded areas are "locked" to Y and not in the solver's control.
I'm always suspicious of the solver in Excel, so check everything!

Linear constraints for nonlinear variable relationship

Assume a mathematical optimization problem with two positive continuous variables:
0 <= x <= 1
0 <= y <= 1000
I am seeking of an efficient way to express in form of linear constraints (possibly with the use of binary/integer variables and big M) the following nonlinear relationship, so the problem can be solved with milp solvers:
when 0 <= y < 200 then x = 0
when y = 200 then 0 <= x <= 1
when 200 < y <= 1000 then x = 1
The numbers 200 and 1000 are indicative.
Are there any direct suggestions or papers/books addressing similar problems?
I think this will work...
Here's how I think of this. You have 3 states that you need to be aware of, which are the 3 partitions on the domain of y. So, 2 binary variables can capture these 3 states. In order to keep things linear, you will need to work with non-strict inequalities. So define:
y_lb ∈ {0, 1} and let y_lb = 1 if y >= 200
y_ub ∈ {0, 1} and let y_ub = 1 if y <= 1000
so now we have our partitions set up in terms of a truth table for y_lb and y_ub:
y y<200 200<=y<=1000 y>1000
y_lb 0 | 1 | 1
y_ub 1 | 1 | 0
Now we can easily link that truth table to constrain x:
x ∈ Reals
x <= y_lb
x >= 1 - y_ub

Cannot get the right result when iterating and applying a conditional statement in a DataFrame's column

I have a dataframe frame in which I need to iterate through one of the columns and apply certain conditional statements for using one or the other set of equations.
I've written the code below. However, I'm not getting the right result. In the code, the input_data variable is checked for positive values, but the condition is not met when encountering a negative value and always applies the equations for the case of positive values.
thanks in advance for any advice on this
import pandas as pd
x=[-1,1]
y=[2,3]
df=pd.DataFrame({'x':x, 'y':y})
print(df)
x y
0 -1 2
1 1 3
input_data=df['x']
for i in range(len(input_data)):
if input_data[i]>0:
df['z']=input_data[i]+1
df['z2']=df['z']+1
df['z3']=1
else:
df['z']=input_data[i]-1
df['z2']=df['z']-1
df['z3']=0
print(df)
x y z z2 z3
0 -1 2 2 3 1
1 1 3 2 3 1
In pandas, loops are generally implemented with apply():
df[['z','z2','z3']] = df.apply(
lambda row: [row.x+1, row.x+2, 1] if row.x > 0 else [row.x-1, row.x-2, 0],
result_type='expand',
axis=1)
# x y z z2 z3
# 0 -1 2 -2.0 -3.0 0.0
# 1 1 3 2.0 3.0 1.0
Or you can use the vectorized np.where():
df['z'] = np.where(df.x > 0, df.x + 1, df.x - 1)
df['z2'] = np.where(df.x > 0, df.z + 1, df.z - 1)
df['z3'] = df.x.gt(0).astype(int)
# x y z z2 z3
# 0 -1 2 -2 -3 0
# 1 1 3 2 3 1
As for the for loop implementation, the issue was due to the assignment statements.
For example df['z3'] = 1 sets the the whole z3 column to 1 (not just any particular row of z3 but the whole column). Similarly df['z3'] = 0 sets the whole column to 0. This applies to all those assignment statements.
So then because the last x value is positive, the final iteration sets all the z columns to the positive result.

Guidance needed | Optimization challenge. Would love to get some inputs 🙏🏻

I need some guidance on how to approach for this problem. I've simplified a real life example and if you can help me crack this by giving me some guidance, it'll be awesome.
I've been looking at public optimization algorithms here (https://www.cvxpy.org/) but I'm a noob and I'm not able to figure out which algorithm would help me (or if I really need it).
Problem:
x1 to x4 are items with certain properties (a,b,c,y,z)
I have certain needs:
Parameter My Needs
a 150
b 800
c 80
My goal is get all optimal coefficient sets for x1 to x4 (can be
fractions) so as to get as much of a, b and c as possible to satisfy
needs from the smallest possible y.
These conditions must always be met:
1)Individual values of z should stay within threshold (between maximum and minimum for x1, x2, x3 and x4)
2)And Total y should be maintained within limits (y <=1000 & y>=2000)
To illustrate an example:
x1
Each x1 has the following properties
a 20 Minimum z 10 Maximum z 50
b 200
c 0
y 300
z 20
x2
Each x2 has the following properties
a 30 Minimum z 60 Maximum z 160
b 5
c 20
y 50
z 40
x3
Each x3 has the following properties
a 20 Minimum z 100 Maximum z 200
b 200
c 15
y 200
z 40
x4
Each x4 has the following properties
a 5 Minimum z 100 Maximum z 300
b 30
c 20
y 500
z 200
One possible arrangement can be (not the optimal solution as I'm trying to keep y as low as possible but above 1000 but to illustrate output)
2x1+2x2+1x3+0.5x4
In this instance:
Coeff x1 2
Coeff x2 2
Coeff x3 3
Coeff x4 0.5
This set of coefficients yields
Optimal?
total y 1550 Yes
total a 162.5 Yes
total b 1025 Yes
total c 95 Yes
z of x1 40 Yes
z of x2 80 Yes
z of x3 120 Yes
z of x4 100 Yes
Lowest y? No
Can anyone help me out?
Thanks!

Modelling an efficiency drop of machine after certain hours of work

I am building linear programming model of machines manufacturing some parts in AMPL using CPLEX solver.
My problem is how to model 10% efficiency step drop of machine after 100 hours of work. I know that proper approach in my case is to use binary variable. Unfortunately I have no idea how to manage this.
Could you show an example how to model described above behavior in linear programming?
EDIT: attaching current AMPL code
Data:
data;
param M := 3; # machines count
param N := 5; # parts count
param efficiency: # efficiency [pc / h]
1 2 3 4 5 :=
1 0.85 1.30 0.65 1.50 0.40
2 0.65 0.80 0.55 1.50 0.70
3 1.20 0.95 0.35 1.70 0.40;
param R := 1 45 # machines costs [usd / h]
2 35
3 40;
param C := 1 60 # minimal manufactured counts of particulat parts
2 60
3 60
4 120
5 120;
Model:
model;
param M; # machines count
param N; # parts count
param efficiency {1..M, 1..N}; # efficiency [pc / h]
param R {1..M}; # machines costs [usd / h]
param C {1..N}; # minimal manufactured counts of particulat parts
var t {1..M, 1..N}; # time[machine,part]
var d {n in 1..N} = sum {m in 1..M} t[m,n] * efficiency[m,n];
minimize cost: sum {m in 1..M, n in 1..N} R[m] * t[m,n];
subject to c1 {n in 1..N}:
d[n] >= C[n];
subject to t1 {m in 1..M}:
sum {n in 1..N} t[m,n] <= 180; # machine time must be less than 180
subject to t2 {m in 1..M, n in 1..N}:
t[m,n] >= 0; # times must non-negative