Ваша точная формулировка имеет O (N ^ 2) ненулей, так что вы застряли с O (N ^ 2) алгоритмом для ее построения. Вы можете избежать повторного создания выражения с помощью этого более процедурного цикла.
import gurobipy as grb
import numpy as np
np.random.seed(10)
N = 5000
x = np.random.randint(10, high=2*N, size=N)
obj = -np.random.randint(10, high=2*N, size=N)
model = gb.Model("ACC")
# more interesting objective
amp_i_vars = model.addVars(N, vtype=grb.GRB.BINARY, name='ai', obj=obj)
model.update()
cum = grb.LinExpr()
for i, ai in amp_i_vars.items():
cum += ai
model.addConstr(cum <= x[i])
model.optimize()
Однако вы можете сформулировать эквивалентную модель с O (n) ненулевыми значениями, добавив параллельный список переменных, представляющих совокупную сумму, и используя повторение
cum [i] = cum [i - 1] + x [i] . Это также приведет к модели, которая решает гораздо быстрее.
import gurobipy as grb
import numpy as np
N = 5000
np.random.seed(10)
x = np.random.randint(10, high=2*N, size=N)
obj = -np.random.randint(10, high=2*N, size=N)
model = gb.Model("ACC")
# more interesting objective function
amp_i_vars = model.addVars(N, vtype=grb.GRB.BINARY, name='ai', obj=obj)
# since cum_vars are variables, use simple upper bound
cum_vars = model.addVars(N, vtype=grb.GRB.CONTINUOUS, name='cum', ub=x)
prev_cum = 0
for i, (ai, cum) in enumerate(zip(amp_i_vars.values(), cum_vars.values())):
model.addConstr(cum == prev_cum + ai, name="sum_constr." + str(i))
prev_cum = cum
model.optimize()
Для N = 5000 это решает за 0,5 секунды против 16 секунд для плотной модели.