gurobi objective function: cost coefficients dependent on sum of solution variables

1,301 views
Skip to first unread message

Monique Bakker

unread,
Sep 5, 2016, 12:22:14 AM9/5/16
to Gurobi Optimization
Hi,
I am trying to solve a model (python) where the coefficients in the linear objective function depend on the sum of certain solution variables.
All variables are binary.

I get the error 'Divisor must be a constant'.
Is there a way around this? 

Thanks. Code:

from gurobipy import *
import math
import numpy
import openpyxl



# physicians
physicians = ['DrA', 'DrB']

# halfdays in planspan
planspan = ['MoAM', 'MoPM', 'TuAM', 'TuPM', 'WeAM', 'WePM', 'ThAM', 'ThPM', 'FrAM', 'FrPM']

# activities
activities = ['Admin1', 'Frac2', 'Spec3', 'Fleb4', 'Latr5', 'Endo6', 'Surg7', 'Surg8',
     'Noth9', 'Annl10']

# Model
m = Model("motest1")

# Assignment variables: x[j,a,t] ==1 if physician j is assigned to activity a
# on half day t.
# Just as in workforce1.py, since an assignment model always produces integer solutions, we use
# continuous variables and solve as an LP.

x = []
n = 1
for j in physicians:
    for t in planspan:
        for a in activities:
            x.append(m.addVar(vtype=GRB.BINARY, name="x%d%s_%s_%s" % (n,j,t,a)))
            n = n+1
m.update()

# Add constraints to ensure that EXACTLY one of the activities is assigned
# note that sum(x[0:9]) does not include the 9th item labeled x10 
m.addConstr(sum(x[0:10]) == 1)
m.addConstr(sum(x[10:20]) == 1)
m.addConstr(sum(x[20:30]) == 1)
m.addConstr(sum(x[30:40]) == 1)
m.addConstr(sum(x[40:50]) == 1)
m.addConstr(sum(x[50:60]) == 1)
m.addConstr(sum(x[60:70]) == 1)
m.addConstr(sum(x[70:80]) == 1)
m.addConstr(sum(x[80:90]) == 1)
m.addConstr(sum(x[90:100]) == 1)

# j=2
m.addConstr(sum(x[101:110]) == 1)
m.addConstr(sum(x[110:120]) == 1)
m.addConstr(sum(x[120:130]) == 1)
m.addConstr(sum(x[130:140]) == 1)
m.addConstr(sum(x[140:150]) == 1)
m.addConstr(sum(x[150:160]) == 1)
m.addConstr(sum(x[160:170]) == 1)
m.addConstr(sum(x[170:180]) == 1)
m.addConstr(sum(x[180:190]) == 1)
m.addConstr(sum(x[190:200]) == 1)

M = array([[ 2.        ,  2.        ],
       [ 0.83333333,  1.16666667],
       [ 2.16666667,  2.        ],
       [ 0.        ,  0.        ],
       [ 0.5       ,  0.16666667],
       [ 0.5       ,  0.83333333],
       [ 1.5       ,  1.16666667],
       [ 0.83333333,  1.33333333],
       [ 1.66666667,  1.33333333],
       [ 0.2       ,  0.2       ]])

C = array([[ 0.69230769,  0.69230769],
       [ 0.72137137,  0.63005549],
       [-0.67160603,  0.60671454],
       [ 0.        ,  0.        ],
       [ 0.06355356, -0.31430663],
       [ 0.76585138,  1.32377788],
       [-0.43737702, -0.64233165],
       [ 1.79534889,  0.61685841],
       [ 0.        ,  0.        ],
       [ 0.        ,  0.        ]])

obj = LinExpr()
for j in range(len(physicians)):
    for a in range(len(activities)-2): # activity 2-8 (index starts at 0)
        if j == 0:        
            rng = x[a:100:10]  # this sum is the number of instances of each activity 
        elif j == 1:
            rng = x[a+100:200:10]
        d = sum(rng)
        if d >= 0:
            for i in range(len(rng)):
                obj += 1/d * (d - M[a][j] + C[a][j])  * rng[i]  
        elif d == 0:
            for i in range(len(rng)):
                obj += (d - M[a][j] + C[a][j]) * rng[i] 

Eric Berger

unread,
Sep 5, 2016, 3:32:33 AM9/5/16
to gur...@googlegroups.com
Is there a typo? Should
m.addConstr(sum(x[101:110]) == 1)
be 
m.addConstr(sum(x[100:110]) == 1)

i.e. 100 instead of 101 ?



--

---
You received this message because you are subscribed to the Google Groups "Gurobi Optimization" group.
To unsubscribe from this group and stop receiving emails from it, send an email to gurobi+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Sonja Mars

unread,
Sep 6, 2016, 3:01:34 AM9/6/16
to gur...@googlegroups.com
Hi,

The problem is this line:
> obj += 1/d * (d - M[a][j] + C[a][j]) * rng[i]
And especially this term: 1/d. d is a linear expression, it is a sum of variables that is generated here:

> if j == 0:
> rng = x[a:100:10] # this sum is the number of instances of each activity
> elif j == 1:
> rng = x[a+100:200:10]
> d = sum(rng)

When I ran your code d looked like this:

<gurobi.LinExpr: x1DrA_MoAM_Admin1 + x11DrA_MoPM_Admin1 + x21DrA_TuAM_Admin1 + x31DrA_TuPM_Admin1 + x41DrA_WeAM_Admin1 + x51DrA_WePM_Admin1 + x61DrA_ThAM_Admin1 + x71DrA_ThPM_Admin1 + x81DrA_FrAM_Admin1 + x91DrA_FrPM_Admin1>

With "Divisor must be a constant" Gurobi is telling you that you cannot have something like 1/(c^T*x) where x is a vector of variable in your objective. This is nonlinear. You will have to reformulate your model to be linear or quadratic otherwise Gurobi cannot solve it.

Best regards,
Sonja

-----------------------------------------------------------------
Dr. Sonja Mars
Gurobi Optimization



Reply all
Reply to author
Forward
0 new messages