You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Python GEKKO求解优化问题时遇负自由度及目标值异常

优化问题求解:负自由度与目标值异常问题

我正在求解一个优化问题,编写了对应的Python GEKKO代码。代码可运行,但出现**负自由度(negative degrees of freedom)**问题,且得到的目标值为负数,与预期的正值不符,恳请提供解决建议。

代码

# Import package
from gekko import GEKKO
import numpy as np

# Define parameters
P_CO = 600                      # $/tonCO
beta_CO2 = 1                    # no unit
P_CO2 = 60                      # $/tonCO2eq
E_ref = 3.1022616               # tonCO2eq/tonCO
E_dir = -1.600570692            # tonCO2eq/tonCO
E_indir_others = 0.3339226804   # tonCO2eq/tonCO
E_indir_elec_cons = 18.46607256 # GJ/tonCO
C1_CAPEX = 285695               # no unit
C2_CAPEX = 188.42               # no unit
C1_FOX = 82282                  # no unit
C2_FOX = 24.094                 # no unit
C1_ROX = 4471.5                 # no unit
C2_ROX = 96.034                 # no unit
C1_UOX = 1983.7                 # no unit
C2_UOX = 249.79                 # no unit
r = 0.08                        # discount rate
N = 10                          # number of scenarios
T = 30                          # total time period
GWP_init = 0.338723235          # 2020 Electricity GWP in EU 27 countries
theta_max = 1600000             # Max capacity

# Function to make GWP_EU matrix (TxN matrix)
def Electricity_GWP(GWP_init, n_years, num_episodes):

    GWP_mean = 0.36258224*np.exp(-0.16395611*np.arange(1, n_years+2)) + 0.03091272
    GWP_mean = GWP_mean.reshape(-1,1)
    GWP_Yearly = np.tile(GWP_mean, num_episodes) 

    noise = np.zeros((n_years+1, num_episodes))
    stdev2050 = GWP_mean[-1] * 0.25 
    stdev = np.arange(0, stdev2050 * (1 + 1/n_years), stdev2050/n_years)

    for i in range(n_years+1):
        noise[i,:] = np.random.normal(0, stdev[i], num_episodes) 

    GWP_forecast = GWP_Yearly + noise 

    return GWP_forecast

GWP_EU = Electricity_GWP(GWP_init, T, N) # (T+1)*N matrix
GWP_EU = GWP_EU[1:,:] # T*N matrix

print(np.shape(GWP_EU))

# Build Gekko model
m = GEKKO(remote=False)
theta = m.Array(m.Var, N, lb=0, ub=theta_max)
demand = np.ones((T,1))
demand[0] = 8031887.589
for k in range(1,11):
    demand[k] = demand[k-1] * 1.026 
for k in range(11,21):
    demand[k] = demand[k-1] * 1.016
for k in range(21,T):
    demand[k] = demand[k-1] * 1.011 
demand = 0.12 * demand
demand = np.tile(demand, N) # T*N matrix

print(np.shape(demand))

obj = m.sum([m.sum([((1/(1+r))**(t+1))*((P_CO*m.min3(demand[t,s], theta[s])) \
            + (beta_CO2*P_CO2*m.min3(demand[t,s], theta[s])*(E_ref-E_dir-E_indir_others-E_indir_elec_cons*GWP_EU[t,s])) \
            - (C1_CAPEX+C2_CAPEX*theta[s]+C1_FOX+C2_FOX*theta[s])-(C1_ROX+C2_ROX*m.min3(demand[t,s], theta[s])+C1_UOX+C2_UOX*m.min3(demand[t,s], theta[s]))) for t in range(T)]) for s in range(N)])
m.Maximize(obj/N)
m.solve() 

输出信息

(30, 10)
(30, 10)
 ----------------------------------------------------------------
 APMonitor, Version 1.0.0
 APMonitor Optimization Suite
 ----------------------------------------------------------------
 
 
 --------- APM Model Size ------------
 Each time step contains
   Objects      :  11
   Constants    :  0
   Variables    :  5121
   Intermediates:  0
   Connections  :  321
   Equations    :  3901
   Residuals    :  3901
 
 Number of state variables:    5121
 Number of total equations: -  3911
 Number of slack variables: -  2400
 ---------------------------------------
 Degrees of freedom       :    -1190
 
 * Warning: DOF <= 0
 ----------------------------------------------
 Steady State Optimization with APOPT Solver
 ----------------------------------------------
Iter:     1 I:  0 Tm:     18.61 NLPi:    5 Dpth:    0 Lvs:    0 Obj: -1.87E+09 Gap:  0.00E+00
 Successful solution
 
 ---------------------------------------------------
 Solver         :  APOPT (v1.0)
 Solution time  :  18.619200000000003 sec
 Objective      :  -1.8677021320161405E+9
 Successful solution
 ---------------------------------------------------

问题原因及解决建议

1. 负自由度问题原因与修复

负自由度说明约束方程数远超决策变量数,模型被过度约束。核心问题是m.min3()函数会自动生成大量辅助变量和约束:

  • 你仅定义了N=10个决策变量theta[s],但每个m.min3(demand[t,s], theta[s])会生成至少3个约束,结合T=30、N=10的规模,总约束数直接爆炸,导致DOF为负。

修复方法:
显式定义产量变量并添加约束替代m.min3(),减少不必要的辅助变量:

# 显式定义产量变量x[t,s]
x = m.Array(m.Var, (T,N), lb=0)
# 添加产量约束:产量不超过需求,也不超过产能
for t in range(T):
    for s in range(N):
        m.Equation(x[t,s] <= demand[t,s])
        m.Equation(x[t,s] <= theta[s])

2. 目标值为负的原因与修复

目标值为负大概率是成本项的计算逻辑错误:

  • 当前代码中每个时间步都重复扣除CAPEX和FOX,相当于把初始投资和年固定成本重复计算了30次,直接放大了成本规模;
  • C1_ROX、C1_UOX如果是年度固定成本,不应该和产量绑定重复扣除。

修复方法:
拆分目标函数的盈利、固定成本、可变成本项,明确成本的计算周期:

obj = 0
for s in range(N):
    # CAPEX是初始投资,仅在第0年扣除一次
    capex = C1_CAPEX + C2_CAPEX*theta[s]
    # 年固定运营成本(FOX、C1_ROX、C1_UOX)
    annual_fixed_cost = (C1_FOX + C2_FOX*theta[s]) + (C1_ROX + C1_UOX)
    for t in range(T):
        discount = (1/(1+r))**(t+1)
        # 销售收入
        revenue = P_CO * x[t,s]
        # 碳收益(确认减排量计算逻辑正确)
        carbon_benefit = beta_CO2 * P_CO2 * x[t,s] * (E_ref - E_dir - E_indir_others - E_indir_elec_cons*GWP_EU[t,s])
        # 可变运营成本
        var_cost = (C2_ROX + C2_UOX) * x[t,s]
        
        # 单时间步净收益
        net = revenue + carbon_benefit - var_cost - annual_fixed_cost
        # 第0年额外扣除初始投资
        if t == 0:
            obj += discount * (net - capex)
        else:
            obj += discount * net
m.Maximize(obj/N)

3. 额外建议

  • 先测试小规模模型:比如设置T=1、N=1,验证目标值是否为正,再逐步扩展到全规模;
  • 打印中间变量:比如输出单个场景下的盈利、成本项,核对每部分的符号和数值是否符合预期。

内容的提问来源于stack exchange,提问作者Feel

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.15 23:31:06