简体   繁体   中英

Constraint on objective function in Python Gekko

Is there a way to constrain the objective function to be within a range in Python Gekko? I am working through the example optimization problem on the economics of a commercial fishery over a 10 year operation. The adjustable parameter is the production rate (harvest rate) of the fish. The objective function is the profit from the operation over the 10 year period. The optimization problem in mathematical terms is:

渔业经济优化

The solution and Python Gekko code are:

钓鱼优化结果

from gekko import GEKKO
import numpy as np
import matplotlib.pyplot as plt

# create GEKKO model
m = GEKKO()

# time points
n=501
m.time = np.linspace(0,10,n)

# constants
E = 1
c = 17.5
r = 0.71
k = 80.5
U_max = 20

# fishing rate
u = m.MV(value=1,lb=0,ub=1)
u.STATUS = 1
u.DCOST = 0

# fish population
x = m.Var(value=70)

# fish population balance
m.Equation(x.dt() == r*x*(1-x/k)-u*U_max)

# objective (profit)
J = m.Var(value=0)
# final objective
Jf = m.FV()
Jf.STATUS = 1
m.Connection(Jf,J,pos2='end')
m.Equation(J.dt() == (E-c/x)*u*U_max)
# maximize profit
m.Maximize(Jf)

# options
m.options.IMODE = 6  # optimal control
m.options.NODES = 3  # collocation nodes
m.options.SOLVER = 3 # solver (IPOPT)

# solve optimization problem
m.solve()

# print profit
print('Optimal Profit: ' + str(Jf.value[0]))

# plot results
plt.figure(1)
plt.subplot(2,1,1)
plt.plot(m.time,J.value,'r--',label='profit')
plt.plot(m.time[-1],Jf.value[0],'ro',markersize=10,\
         label='final profit = '+str(Jf.value[0]))
plt.plot(m.time,x.value,'b-',label='fish population')
plt.ylabel('Value')
plt.legend()
plt.subplot(2,1,2)
plt.plot(m.time,u.value,'k.-',label='fishing rate')
plt.ylabel('Rate')
plt.xlabel('Time (yr)')
plt.legend()
plt.show()

One of the observations I've had in chemical manufacturing is that optimization sometimes leads to non-intuitive solutions because the optimizer (IPOPT) is going to take the process to the absolute limit to achieve even a few dollars more of profitability. Is there a way to constrain the objective function (profit in this case) so that the business stays viable but the optimizer doesn't give a solution that is pushing the limits of the equipment (or the fish population in this case).

You can set a limit on the objective by adding an upper bound such as:

Jf = m.FV(ub=100)  # final objective

This sets an upper bound ub of 100 . Even though you can do this, there are a variety of reasons why you may not want to put a constraint on the objective. One is that this could lead to an infeasible solution if the optimizer cannot achieve that limit. Another is that you may still not achieve an "intuitive solution" or one that wouldn't push your equipment (such as fishing boats or your chemical manufacturing plant) to the limit in certain periods. As Tim mentioned in the comment, a better way is to put constraints on things that you can control such as fishing rate. A few parameters that you may find useful are the move suppression factor DCOST , maximum movement DMAX , and cost for fishing rate COST . Maybe it isn't reasonable to ramp up to full fishing rate in one year and then drop to 40% for 5+ years. There may also be costs associated with building up the fishing fleet that would be not be reflected in your current solution.

You can also set up the objective as a soft constraint between certain target values and then let other objectives such as maximize fish population be the driving force for decisions between the upper and lower profitability targets.

# objective (profit)
J = m.CV(value=0)
J.SPHI = 100; J.WSPHI = 1000
J.SPLO = 80;  J.WSPLO = 1000
m.options.CV_WGT_START = n-1 # start at n-1
J.STATUS = 1

m.Maximize(x) # maximize fish population

This gives a solution between profit limits of 80 to 100 but also maximizes the fish population.

钓鱼人口

from gekko import GEKKO
import numpy as np
import matplotlib.pyplot as plt

# create GEKKO model
m = GEKKO()

# time points
n=501
m.time = np.linspace(0,10,n)

# constants
E = 1
c = 17.5
r = 0.71
k = 80.5
U_max = 20

# fishing rate
u = m.MV(value=1,lb=0,ub=1)
u.STATUS = 1
u.DCOST = 0

# fish population
x = m.Var(value=70)

# fish population balance
m.Equation(x.dt() == r*x*(1-x/k)-u*U_max)

# objective (profit)
J = m.CV(value=0)
J.SPHI = 100; J.WSPHI = 1000
J.SPLO = 80;  J.WSPLO = 1000
m.options.CV_WGT_START = n-1 # start at n-1
J.STATUS = 1

m.Maximize(x) # maximize fish population

m.Equation(J.dt() == (E-c/x)*u*U_max)

# options
m.options.IMODE = 6  # optimal control
m.options.NODES = 3  # collocation nodes
m.options.SOLVER = 3 # solver (IPOPT)

# solve optimization problem
m.solve()

# print profit
print('Optimal Profit: ' + str(J.value[-1]))

# plot results
plt.figure(1)
plt.subplot(2,1,1)
plt.plot([0,10],[100,100],'k:',label='target profit range')
plt.plot([0,10],[80,80],'k:')
plt.plot(m.time,J.value,'r--',label='profit')
plt.plot(m.time[-1],J.value[-1],'ro',markersize=10,\
         label='final profit = '+str(J.value[-1]))
plt.plot(m.time,x.value,'b-',label='fish population')
plt.ylabel('Value')
plt.legend()
plt.subplot(2,1,2)
plt.plot(m.time,u.value,'k.-',label='fishing rate')
plt.ylabel('Rate')
plt.xlabel('Time (yr)')
plt.legend()
plt.show()

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM