Multicriteria Decision Making¶
Goal programming is a variation of linear programming considering more than one objective (goals) in the objective function. Goal programming solutions do not always achieve all goals and they are not optimal; they achieve the best or most satisfactory solution possible.
Goal Constraint Requirements:
All goal constraints are equalities that include deviational variables \(d^-\) and \(d^+\)
A negative deviational variable, \(d^-\), is the amount by which a goal level is under-achieved
A positive deviational variable, \(d^+\), is the amount by which a goal level is exceeded
At least one or both deviational variables in a goal constraint must equal zero
The objective function seeks to minimize the deviation from the respective goals in the order of the goal priorities.
Goal programming example:¶
Solve the following problem:
!pip install gurobipy
# Import gurobi library
from gurobipy import * # This command imports the Gurobi functions and classes.
import numpy as np
m = Model('multiobj')
# Add Variables
x = m.addVars(range(2), name='x', lb=0, vtype = GRB.INTEGER)
dm = m.addVars(range(3), name='dm', lb=0, vtype = GRB.INTEGER)
dp = m.addVars(range(3), name='dp', lb=0, vtype = GRB.INTEGER)
#totSlack = m.addVar(name='totSlack')
m.update()
# Add Constraints
c1 = m.addConstr(1 *x[0] + 2*x[1] + 1*dm[0] - 1*dp[0] == 40)
c2 = m.addConstr(40*x[0] + 50*x[1] + 1*dm[1] - 1*dp[1] == 1600)
c3 = m.addConstr(4 *x[0] + 3*x[1] + 1*dm[2] - 1*dp[2] == 120)
# Add Objective Function
m.ModelSense = GRB.MINIMIZE
m.setObjectiveN(dm[0], index=0, priority=3)
m.setObjectiveN(dm[1], index=1, priority=2)
m.setObjectiveN(dp[2], index=2, priority=1)
m.setObjectiveN(dp[0], index=3, priority=0)
# Optimize Model
m.optimize()
# Output formatted solution
for v in m.getVars():
print(v.varName, v.x)
#print('Obj :', m.objVal)
Collecting gurobipy
Downloading gurobipy-9.5.0-cp37-cp37m-manylinux2014_x86_64.whl (11.5 MB)
|████████████████████████████████| 11.5 MB 12.7 MB/s
?25hInstalling collected packages: gurobipy
Successfully installed gurobipy-9.5.0
Restricted license - for non-production use only - expires 2023-10-25
Gurobi Optimizer version 9.5.0 build v9.5.0rc5 (linux64)
Thread count: 1 physical cores, 2 logical processors, using up to 2 threads
Optimize a model with 3 rows, 8 columns and 12 nonzeros
Model fingerprint: 0xedfe4e5b
Variable types: 0 continuous, 8 integer (0 binary)
Coefficient statistics:
Matrix range [1e+00, 5e+01]
Objective range [1e+00, 1e+00]
Bounds range [0e+00, 0e+00]
RHS range [4e+01, 2e+03]
---------------------------------------------------------------------------
Multi-objectives: starting optimization with 4 objectives ...
---------------------------------------------------------------------------
Multi-objectives: applying initial presolve ...
---------------------------------------------------------------------------
Presolve time: 0.00s
Presolved: 3 rows and 8 columns
---------------------------------------------------------------------------
Multi-objectives: optimize objective 1 () ...
---------------------------------------------------------------------------
Presolve removed 3 rows and 8 columns
Presolve time: 0.00s
Presolve: All rows and columns removed
Explored 0 nodes (0 simplex iterations) in 0.07 seconds (0.00 work units)
Thread count was 1 (of 2 available processors)
Solution count 1: 0
Optimal solution found (tolerance 1.00e-04)
Best objective 0.000000000000e+00, best bound 0.000000000000e+00, gap 0.0000%
---------------------------------------------------------------------------
Multi-objectives: optimize objective 2 () ...
---------------------------------------------------------------------------
Loaded user MIP start with objective 0
Explored 0 nodes (0 simplex iterations) in 0.11 seconds (0.00 work units)
Thread count was 1 (of 2 available processors)
Solution count 1: 0
Optimal solution found (tolerance 1.00e-04)
Best objective 0.000000000000e+00, best bound 0.000000000000e+00, gap 0.0000%
---------------------------------------------------------------------------
Multi-objectives: optimize objective 3 () ...
---------------------------------------------------------------------------
Loaded user MIP start with objective 40
Presolve removed 5 rows and 8 columns
Presolve time: 0.00s
Presolve: All rows and columns removed
Explored 0 nodes (0 simplex iterations) in 0.14 seconds (0.00 work units)
Thread count was 1 (of 2 available processors)
Solution count 2: 0 40
Optimal solution found (tolerance 1.00e-04)
Best objective 0.000000000000e+00, best bound 0.000000000000e+00, gap 0.0000%
---------------------------------------------------------------------------
Multi-objectives: optimize objective 4 () ...
---------------------------------------------------------------------------
Loaded user MIP start with objective 24
Presolve removed 4 rows and 6 columns
Presolve time: 0.00s
Presolved: 2 rows, 2 columns, 4 nonzeros
Variable types: 0 continuous, 2 integer (0 binary)
Root relaxation: objective 1.500000e+01, 0 iterations, 0.00 seconds (0.00 work units)
Nodes | Current Node | Objective Bounds | Work
Expl Unexpl | Obj Depth IntInf | Incumbent BestBd Gap | It/Node Time
* 0 0 0 15.0000000 15.00000 0.00% - 0s
Explored 1 nodes (0 simplex iterations) in 0.18 seconds (0.00 work units)
Thread count was 2 (of 2 available processors)
Solution count 2: 15 24
Optimal solution found (tolerance 1.00e-04)
Best objective 1.500000000000e+01, best bound 1.500000000000e+01, gap 0.0000%
---------------------------------------------------------------------------
Multi-objectives: solved in 0.24 seconds (0.00 work units), solution count 3
x[0] 15.0
x[1] 20.0
dm[0] 0.0
dm[1] 0.0
dm[2] 0.0
dp[0] 15.0
dp[1] 0.0
dp[2] 0.0
Altered goal programming example:¶
Solve the following problem:
from gurobipy import *
m = Model('multiobj')
# Add Variables
x = m.addVars(range(2), name='x', lb=0, vtype = GRB.INTEGER)
dm = m.addVars(range(6), name='dm', lb=0, vtype = GRB.INTEGER)
dp = m.addVars(range(4), name='dp', lb=0, vtype = GRB.INTEGER)
#totSlack = m.addVar(name='totSlack')
m.update()
# Add Constraints
c1 = m.addConstr(1 *x[0] + 2 *x[1] + 1*dm[0] - 1*dp[0] == 40)
c2 = m.addConstr(40*x[0] + 50*x[1] + 1*dm[1] - 1*dp[1] == 1600)
c3 = m.addConstr(4 *x[0] + 3 *x[1] + 1*dm[2] - 1*dp[2] == 120)
c4 = m.addConstr( 1*dp[0] + 1*dm[3] - 1*dp[3] == 10)
c5 = m.addConstr(1 *x[0] + 1*dm[4] == 30)
c6 = m.addConstr( 1 *x[1] + 1*dm[5] == 20)
# Add Objective Function
m.ModelSense = GRB.MINIMIZE
m.setObjectiveN(dm[0], index=0, priority=4)
m.setObjectiveN(dm[1], index=1, priority=3)
m.setObjectiveN(dp[2], index=2, priority=2)
m.setObjectiveN(dp[3], index=3, priority=1)
m.setObjectiveN(4*dm[4]+5*dm[5], index=4, priority=0)
# Optimize Model
m.optimize()
# Output formatted solution
for v in m.getVars():
print(v.varName, v.x)
#print('Obj :', m.objVal)
Gurobi Optimizer version 9.5.0 build v9.5.0rc5 (linux64)
Thread count: 1 physical cores, 2 logical processors, using up to 2 threads
Optimize a model with 6 rows, 12 columns and 19 nonzeros
Model fingerprint: 0x2a5ffb2a
Variable types: 0 continuous, 12 integer (0 binary)
Coefficient statistics:
Matrix range [1e+00, 5e+01]
Objective range [1e+00, 5e+00]
Bounds range [0e+00, 0e+00]
RHS range [1e+01, 2e+03]
---------------------------------------------------------------------------
Multi-objectives: starting optimization with 5 objectives ...
---------------------------------------------------------------------------
Multi-objectives: applying initial presolve ...
---------------------------------------------------------------------------
Presolve removed 2 rows and 2 columns
Presolve time: 0.00s
Presolved: 4 rows and 10 columns
---------------------------------------------------------------------------
Multi-objectives: optimize objective 1 () ...
---------------------------------------------------------------------------
Presolve removed 4 rows and 10 columns
Presolve time: 0.00s
Presolve: All rows and columns removed
Explored 0 nodes (0 simplex iterations) in 0.05 seconds (0.00 work units)
Thread count was 1 (of 2 available processors)
Solution count 1: 0
Optimal solution found (tolerance 1.00e-04)
Best objective 0.000000000000e+00, best bound 0.000000000000e+00, gap 0.0000%
---------------------------------------------------------------------------
Multi-objectives: optimize objective 2 () ...
---------------------------------------------------------------------------
Loaded user MIP start with objective 0
Explored 0 nodes (0 simplex iterations) in 0.07 seconds (0.00 work units)
Thread count was 1 (of 2 available processors)
Solution count 1: 0
Optimal solution found (tolerance 1.00e-04)
Best objective 0.000000000000e+00, best bound 0.000000000000e+00, gap 0.0000%
---------------------------------------------------------------------------
Multi-objectives: optimize objective 3 () ...
---------------------------------------------------------------------------
Loaded user MIP start with objective 60
Presolve removed 6 rows and 10 columns
Presolve time: 0.00s
Presolve: All rows and columns removed
Explored 0 nodes (0 simplex iterations) in 0.10 seconds (0.00 work units)
Thread count was 1 (of 2 available processors)
Solution count 2: 0 60
Optimal solution found (tolerance 1.00e-04)
Best objective 0.000000000000e+00, best bound 0.000000000000e+00, gap 0.0000%
---------------------------------------------------------------------------
Multi-objectives: optimize objective 4 () ...
---------------------------------------------------------------------------
Loaded user MIP start with objective 5
Presolve removed 7 rows and 10 columns
Presolve time: 0.00s
Presolve: All rows and columns removed
Explored 0 nodes (0 simplex iterations) in 0.13 seconds (0.00 work units)
Thread count was 1 (of 2 available processors)
Solution count 1: 5
Optimal solution found (tolerance 1.00e-04)
Best objective 5.000000000000e+00, best bound 5.000000000000e+00, gap 0.0000%
---------------------------------------------------------------------------
Multi-objectives: optimize objective 5 () ...
---------------------------------------------------------------------------
Loaded user MIP start with objective 60
Presolve removed 8 rows and 10 columns
Presolve time: 0.00s
Presolve: All rows and columns removed
Explored 0 nodes (0 simplex iterations) in 0.16 seconds (0.00 work units)
Thread count was 1 (of 2 available processors)
Solution count 1: 60
Optimal solution found (tolerance 1.00e-04)
Best objective 6.000000000000e+01, best bound 6.000000000000e+01, gap 0.0000%
---------------------------------------------------------------------------
Multi-objectives: solved in 0.18 seconds (0.00 work units), solution count 2
x[0] 15.0
x[1] 20.0
dm[0] 0.0
dm[1] 0.0
dm[2] 0.0
dm[3] 0.0
dm[4] 15.0
dm[5] 0.0
dp[0] 15.0
dp[1] 0.0
dp[2] 0.0
dp[3] 5.0
Problem Example: C9Q8¶
Solve the following goal programming model:
from gurobipy import *
m = Model('C9Q8')
# Add Variables
x = m.addVars(range(2), name='x', lb=0, vtype = GRB.INTEGER)
dm = m.addVars(range(3), name='dm', lb=0, vtype = GRB.INTEGER)
dp = m.addVars(range(3), name='dp', lb=0, vtype = GRB.INTEGER)
#totSlack = m.addVar(name='totSlack')
m.update()
# Add Constraints
c1 = m.addConstr(1*x[0] + 1*x[1] + 1*dm[0] - 1*dp[0] == 800)
c2 = m.addConstr(5*x[0] + 1*dm[1] - 1*dp[1] == 2500)
c3 = m.addConstr( 3*x[1] + 1*dm[2] - 1*dp[2] == 1400)
# Add Objective Function
m.ModelSense = GRB.MINIMIZE
m.setObjectiveN(dm[0]+dp[0], index=0, priority=3)
m.setObjectiveN(dm[1], index=1, priority=2)
m.setObjectiveN(dm[2], index=2, priority=1)
m.setObjectiveN(3*dp[1]+5*dp[2], index=3, priority=0)
# Optimize Model
m.optimize()
# Output formatted solution
for v in m.getVars():
print(v.varName, v.x)
#print('Obj :', m.objVal)
Gurobi Optimizer version 9.5.0 build v9.5.0rc5 (linux64)
Thread count: 1 physical cores, 2 logical processors, using up to 2 threads
Optimize a model with 3 rows, 8 columns and 10 nonzeros
Model fingerprint: 0xa4b28e54
Variable types: 0 continuous, 8 integer (0 binary)
Coefficient statistics:
Matrix range [1e+00, 5e+00]
Objective range [1e+00, 5e+00]
Bounds range [0e+00, 0e+00]
RHS range [8e+02, 2e+03]
---------------------------------------------------------------------------
Multi-objectives: starting optimization with 4 objectives ...
---------------------------------------------------------------------------
Multi-objectives: applying initial presolve ...
---------------------------------------------------------------------------
Presolve time: 0.00s
Presolved: 3 rows and 8 columns
---------------------------------------------------------------------------
Multi-objectives: optimize objective 1 () ...
---------------------------------------------------------------------------
Presolve removed 3 rows and 8 columns
Presolve time: 0.00s
Presolve: All rows and columns removed
Explored 0 nodes (0 simplex iterations) in 0.04 seconds (0.00 work units)
Thread count was 1 (of 2 available processors)
Solution count 1: 0
Optimal solution found (tolerance 1.00e-04)
Best objective 0.000000000000e+00, best bound 0.000000000000e+00, gap 0.0000%
---------------------------------------------------------------------------
Multi-objectives: optimize objective 2 () ...
---------------------------------------------------------------------------
Loaded user MIP start with objective 0
Explored 0 nodes (0 simplex iterations) in 0.06 seconds (0.00 work units)
Thread count was 1 (of 2 available processors)
Solution count 1: 0
Optimal solution found (tolerance 1.00e-04)
Best objective 0.000000000000e+00, best bound 0.000000000000e+00, gap 0.0000%
---------------------------------------------------------------------------
Multi-objectives: optimize objective 3 () ...
---------------------------------------------------------------------------
Loaded user MIP start with objective 1400
Presolve removed 5 rows and 8 columns
Presolve time: 0.00s
Presolve: All rows and columns removed
Explored 0 nodes (0 simplex iterations) in 0.09 seconds (0.00 work units)
Thread count was 1 (of 2 available processors)
Solution count 2: 500 1400
Optimal solution found (tolerance 1.00e-04)
Best objective 5.000000000000e+02, best bound 5.000000000000e+02, gap 0.0000%
---------------------------------------------------------------------------
Multi-objectives: optimize objective 4 () ...
---------------------------------------------------------------------------
Loaded user MIP start with objective 0
Explored 0 nodes (0 simplex iterations) in 0.10 seconds (0.00 work units)
Thread count was 1 (of 2 available processors)
Solution count 1: 0
Optimal solution found (tolerance 1.00e-04)
Best objective 0.000000000000e+00, best bound 0.000000000000e+00, gap 0.0000%
---------------------------------------------------------------------------
Multi-objectives: solved in 0.12 seconds (0.00 work units), solution count 2
x[0] 500.0
x[1] 300.0
dm[0] 0.0
dm[1] 0.0
dm[2] 500.0
dp[0] 0.0
dp[1] 0.0
dp[2] 0.0
Problem Example: C9Q10¶
Solve the following goal programming model:
from gurobipy import *
m = Model('C9Q10')
# Add Variables
x = m.addVars(range(2), name='x', lb=0, vtype = GRB.INTEGER)
dm = m.addVars(range(4), name='dm', lb=0, vtype = GRB.INTEGER)
dp = m.addVars(range(4), name='dp', lb=0, vtype = GRB.INTEGER)
#totSlack = m.addVar(name='totSlack')
m.update()
# Add Constraints
c1 = m.addConstr(8*x[0] + 6*x[1] + 1*dm[0] - 1*dp[0] == 480)
c2 = m.addConstr(1*x[0] + 1*dm[1] - 1*dp[1] == 40)
c3 = m.addConstr( 1*x[1] + 1*dm[2] - 1*dp[2] == 50)
c4 = m.addConstr( 1*dp[0] + 1*dm[3] - 1*dp[3] == 20)
# Add Objective Function
m.ModelSense = GRB.MINIMIZE
m.setObjectiveN(dm[0], index=0, priority=2)
m.setObjectiveN(5*dm[1]+2*dm[2], index=1, priority=1)
m.setObjectiveN(dp[3], index=2, priority=0)
# Optimize Model
m.optimize()
# Output formatted solution
for v in m.getVars():
print(v.varName, v.x)
#print('Obj :', m.objVal)
Gurobi Optimizer version 9.5.0 build v9.5.0rc5 (linux64)
Thread count: 1 physical cores, 2 logical processors, using up to 2 threads
Optimize a model with 4 rows, 10 columns and 13 nonzeros
Model fingerprint: 0x30f2088f
Variable types: 0 continuous, 10 integer (0 binary)
Coefficient statistics:
Matrix range [1e+00, 8e+00]
Objective range [1e+00, 5e+00]
Bounds range [0e+00, 0e+00]
RHS range [2e+01, 5e+02]
---------------------------------------------------------------------------
Multi-objectives: starting optimization with 3 objectives ...
---------------------------------------------------------------------------
Multi-objectives: applying initial presolve ...
---------------------------------------------------------------------------
Presolve time: 0.00s
Presolved: 4 rows and 10 columns
---------------------------------------------------------------------------
Multi-objectives: optimize objective 1 () ...
---------------------------------------------------------------------------
Presolve removed 4 rows and 10 columns
Presolve time: 0.00s
Presolve: All rows and columns removed
Explored 0 nodes (0 simplex iterations) in 0.05 seconds (0.00 work units)
Thread count was 1 (of 2 available processors)
Solution count 1: 0
Optimal solution found (tolerance 1.00e-04)
Best objective 0.000000000000e+00, best bound 0.000000000000e+00, gap 0.0000%
---------------------------------------------------------------------------
Multi-objectives: optimize objective 2 () ...
---------------------------------------------------------------------------
Loaded user MIP start with objective 100
Presolve removed 5 rows and 10 columns
Presolve time: 0.00s
Presolve: All rows and columns removed
Explored 0 nodes (0 simplex iterations) in 0.08 seconds (0.00 work units)
Thread count was 1 (of 2 available processors)
Solution count 2: 0 100
Optimal solution found (tolerance 1.00e-04)
Best objective 0.000000000000e+00, best bound 0.000000000000e+00, gap 0.0000%
---------------------------------------------------------------------------
Multi-objectives: optimize objective 3 () ...
---------------------------------------------------------------------------
Loaded user MIP start with objective 120
Presolve removed 6 rows and 10 columns
Presolve time: 0.00s
Presolve: All rows and columns removed
Explored 0 nodes (0 simplex iterations) in 0.10 seconds (0.00 work units)
Thread count was 1 (of 2 available processors)
Solution count 1: 120
Optimal solution found (tolerance 1.00e-04)
Best objective 1.200000000000e+02, best bound 1.200000000000e+02, gap 0.0000%
---------------------------------------------------------------------------
Multi-objectives: solved in 0.11 seconds (0.00 work units), solution count 2
x[0] 40.0
x[1] 50.0
dm[0] 0.0
dm[1] -0.0
dm[2] -0.0
dm[3] 0.0
dp[0] 140.0
dp[1] 0.0
dp[2] 0.0
dp[3] 120.0