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

基于外部代码的Python约束优化:避免重复调用外部代码问题

解决Scipy优化中目标函数与约束函数重复调用外部代码的性能问题

核心思路是对相同输入x的计算结果y进行缓存,避免重复调用耗时的external_code。以下是两种可行的重构方案:

方案一:基于类的缓存实现

通过类的实例变量保存最近一次计算的x和y,让目标函数与约束函数共享缓存状态,结构清晰易维护:

import numpy as np
from scipy.optimize import minimize, Bounds

def external_code(x):
    # 替换为你的实际外部代码逻辑
    y = np.zeros(6)
    y[0] = x[0]**2 + x[1]**2 + x[2]**2
    y[1] = x[0] + x[1]
    y[2] = x[2]
    y[3] = x[0]
    y[4] = x[1]
    y[5] = x[2]
    return y

class OptimizationWrapper:
    def __init__(self):
        self.last_x = None  # 缓存最近一次的输入x
        self.last_y = None  # 缓存对应x的输出y

    def _get_y(self, x):
        # 检查输入是否与缓存一致,仅在不一致时调用external_code
        if self.last_x is None or not np.allclose(x, self.last_x, atol=1e-8):
            self.last_x = x.copy()  # 存副本避免原数组修改导致缓存失效
            self.last_y = external_code(x)
        return self.last_y

    def objective(self, x):
        y = self._get_y(x)
        return y[0]

    def constraint(self, x):
        y = self._get_y(x)
        return np.array([
            5.0 - y[1],
            1.0 - y[2],
            1.0 - (y[3] + y[4] + y[5])
        ])

# 初始化包装器并执行优化
wrapper = OptimizationWrapper()
bounds = Bounds([0.0, -np.inf, 0.0], [10.0, 10.0, 2.0])
x0 = np.array([1.0, 0.0, 1.0])

res = minimize(
    wrapper.objective,
    x0,
    method='SLSQP',
    bounds=bounds,
    constraints={'fun': wrapper.constraint, 'type': 'ineq'}
)

print(res)

方案二:闭包缓存实现

利用闭包特性共享缓存变量,无需定义类,代码更简洁:

import numpy as np
from scipy.optimize import minimize, Bounds

def external_code(x):
    # 替换为你的实际外部代码逻辑
    y = np.zeros(6)
    y[0] = x[0]**2 + x[1]**2 + x[2]**2
    y[1] = x[0] + x[1]
    y[2] = x[2]
    y[3] = x[0]
    y[4] = x[1]
    y[5] = x[2]
    return y

def create_optimization_functions():
    last_x = None
    last_y = None

    def objective(x):
        nonlocal last_x, last_y
        if last_x is None or not np.allclose(x, last_x, atol=1e-8):
            last_x = x.copy()
            last_y = external_code(x)
        return last_y[0]

    def constraint(x):
        nonlocal last_x, last_y
        if last_x is None or not np.allclose(x, last_x, atol=1e-8):
            last_x = x.copy()
            last_y = external_code(x)
        return np.array([
            5.0 - last_y[1],
            1.0 - last_y[2],
            1.0 - (last_y[3] + last_y[4] + last_y[5])
        ])

    return objective, constraint

# 创建共享缓存的目标函数与约束函数
objective, constraint = create_optimization_functions()
bounds = Bounds([0.0, -np.inf, 0.0], [10.0, 10.0, 2.0])
x0 = np.array([1.0, 0.0, 1.0])

res = minimize(
    objective,
    x0,
    method='SLSQP',
    bounds=bounds,
    constraints={'fun': constraint, 'type': 'ineq'}
)

print(res)

关键注意事项

  • 使用np.allclose而非直接比较浮点数,避免因优化器传入的微小数值差异导致不必要的重复计算。
  • 缓存的x需保存副本(x.copy()),防止原数组被修改后缓存失效。
  • 该方案仅适用于确定性的external_code(相同输入对应相同输出),若外部代码含随机逻辑则不适用。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 11:57:12