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

Scipy Optimize Minimize(SLSQP)中目标与约束计算共享优化问询

Awesome question—this is exactly the kind of redundant computation that’s ripe for optimization, and you can absolutely cut your runtime nearly in half by sharing the core logic between your objective and constraint functions. Here’s how to do it effectively:

Solution Overview

The key problem is that your objective and constraint functions are running identical core logic to generate the result set, then splitting off different parts for their final calculations. We need to refactor this so the shared logic runs once per optimization iteration, not twice.

Step 1: Extract Shared Computation into a Reusable Function

First, pull out all the code that processes the input variables x and generates the full result set into a standalone function. This function will take x as input and return the complete set of results both your objective and constraint need.

import numpy as np

def compute_shared_results(x):
    # Your existing core logic here: process x, generate the full result set
    # Example placeholder logic:
    intermediate = x ** 2 + np.sin(x)
    full_result_set = {
        'target_data': intermediate[:3],  # Data used for objective
        'constraint_data': intermediate[3:]  # Data used for constraints
    }
    return full_result_set

Step 2: Choose a Caching/State Management Strategy

Now we need to ensure this shared function only runs once per x value, even if both the objective and constraint functions call it. There are two reliable approaches for this:

Option 1: Use a Cache with lru_cache

We can use Python's functools.lru_cache to cache the results of compute_shared_results for each unique x value. Since NumPy arrays aren't hashable (required for caching), we'll convert x to a tuple before passing it to the cached function.

from functools import lru_cache

# Wrap the shared function with caching
@lru_cache(maxsize=None)
def cached_shared_results(x_tuple):
    x = np.array(x_tuple)
    return compute_shared_results(x)

# Update objective function to use the cached results
def objective(x):
    results = cached_shared_results(tuple(x))
    # Calculate target value using results['target_data']
    return np.sum(results['target_data'])

# Update constraint function to reuse the same cached results
def constraint(x):
    results = cached_shared_results(tuple(x))
    # Calculate constraint values using results['constraint_data']
    return np.mean(results['constraint_data']) - 5.0  # Example constraint

This works because when the objective function runs first for a given x, it populates the cache. When the constraint function runs next with the same x, it pulls the precomputed results from the cache instead of re-running the core logic.

Option 2: Use a Class to Track State

If you prefer avoiding cache hashing (e.g., for very high-dimensional x), you can wrap everything in a class to track the last computed x and its corresponding results. This ensures we only re-run the shared logic when x changes.

class Optimizer:
    def __init__(self):
        self.last_x = None
        self.shared_results = None

    def _compute_shared(self, x):
        # Only re-run if x has changed since last call
        if self.last_x is None or not np.array_equal(x, self.last_x):
            self.shared_results = compute_shared_results(x)
            self.last_x = x.copy()
        return self.shared_results

    def objective(self, x):
        results = self._compute_shared(x)
        return np.sum(results['target_data'])

    def constraint(self, x):
        results = self._compute_shared(x)
        return np.mean(results['constraint_data']) - 5.0

# Usage
opt = Optimizer()
result = scipy.optimize.minimize(
    opt.objective,
    x0=np.array([1.0, 2.0, 3.0, 4.0]),  # Example initial guess
    method='SLSQP',
    constraints={'type': 'eq', 'fun': opt.constraint}
)

Why the args Parameter Isn't the Right Fit

You mentioned passing results via the constraint's args parameter, but this won't work for your use case. The args parameter is for fixed, static values that don't change between optimization iterations. Since your result set depends on the dynamic input x (which changes every iteration), you can't precompute it and pass it via args—the value would be stale after the first iteration.

Final Result

Either of the above approaches will ensure your core logic runs only once per iteration, cutting your total runtime from ~300 seconds (600*(0.25+0.25)) to ~150 seconds. This is exactly the near-halving you're aiming for!

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.08 18:33:15