How to enforce specific elements in a vector to be in an optimization solution in Gekko

27 Views Asked by At

I'm trying to generate an optimal combination of p records in a vector of length n while simultaneously ensuring (constraining) that specific elements in the vector are included in the solution set p (based on a binary value for now)

I have the equation "simu_total_volume" below that does work for ensuring the solution set never exceeds p records, but I am unable to figure out how to modify this equation to ensure that specific elements i in the vector are included in the solution set (even if non-optimal). x7 is the binary vector that selects which elements are included based on p.

"Labor Day" is a vector of 0s except for one element that is equal to 1 (this corresponds to element I want to include in the solution set). I can enforce this vector to sum to 1 per the below, but am unsure how to integrate it into "simu_total_volume" so that the solution conforms to it.

Apologies for not including all relevant information for reproducibility, but the full solution is very large.

simu_total_volume = [m.Intermediate((
(m.max2(0,base_volume[i]*(m.exp(total_vol_fedi[i])-1)) * x3[i] +
m.max2(0,base_volume[i]*(m.exp(total_vol_feao[i])-1)) * x4[i] +
m.max2(0,base_volume[i]*(m.exp(total_vol_diso[i])-1)) * x5[i] +
m.max2(0,base_volume[i]*(m.exp(total_vol_tpro[i])-1)) * x6[i]) + base_volume[i]) * x7[i]) for i in range(n)]

labor_day = [m.Intermediate(x8[i] * el_cppg['holiday_labor_day_flag'].values[i]) for i in range(n)]

#Require labor day to be in output
m.Equation(sum(labor_day) == 1)

#Limit max output
m.Equation(sum(x7)<=p)

m.Maximize(m.sum(simu_total_volume))

m.options.SOLVER=1

try:
    m.solve(disp = True)
except:
    continue
1

There are 1 best solutions below

0
John Hedengren On BEST ANSWER

There are multiple ways to constrain particular elements within an array. Here is a complete example that optimizes the elements of X to minimize the total cost. Each element X can be [0,1] and two can be selected with sum(X)==2.

from gekko import GEKKO
m = GEKKO(remote=False)
X = m.Array(m.Var,7,lb=0,ub=1,integer=True)
c = [1.2,0.95,1.3,1.0,0.8,1.25,1.4]
m.Equation(sum(X)==2)
m.Minimize(sum([X[i]*c[i] for i in range(7)]))
m.options.SOLVER=1
m.solve()
print(f'X: {X}')

The solver picks the two lowest that correspond to c elements of 0.95 and 0.8:

c = [1.2,0.95,1.3,1.0,0.8,1.25,1.4]
X: [[0.0] [1.0] [0.0] [0.0] [1.0] [0.0] [0.0]]

Here are a few ways to constrain the solution such as enforcing that the last element is always selected:

Add an equation

m.Equation(X[-1]==1)

Set the upper and lower bounds to the specified solution

X[-1].lower=1
X[-1].upper=1

Use the m.fix() function

m.fix(X[-1],1)

Add an objective as a soft constraint

Use this method if adding a hard constraint gives an infeasible solution. This will encourage the selection of a preferred option, but won't enforce it if the equations aren't satisfied.

m.Minimize(100*(X[-1]-1)**2)

Results

All of these methods return the correct solution that selects the last element (not optimal) and the least costly element.

X: [[0.0] [0.0] [0.0] [0.0] [1.0] [0.0] [1.0]]