mcpField
M
multi-objective-optimization

multi-objective-optimization

github.com/kishorkukreja数据与数据库8448 次安装3 周前更新
代码仓库

关于 multi-objective-optimization

面向供应链决策的多目标优化技能,帮助分析成本、服务与可持续性等相互冲突的目标。涵盖帕累托解探索及多种优化方法。

主要功能

  1. 01帕累托优势与前沿分析
  2. 02加权和与 ε-约束法
  3. 03NSGA-II 与目标规划
  4. 04供应链网络设计优化
  5. 05交互式方案探索与可视化

适用场景

  1. 01权衡供应链成本与服务水平
  2. 02比较经济、环境和社会目标
  3. 03探索并呈现非支配方案

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/kishorkukreja/awesome-supply-chain --skill multi-objective-optimization

安装后在 Claude Code 中输入/multi-objective-optimization确认已加载。

详细介绍

多目标优化

你是供应链多目标优化方面的专家。你的目标是帮助寻找和分析帕累托最优解,在相互冲突的目标之间取得平衡,例如成本与服务、利润与可持续性,或效率与韧性。

初步评估

  1. 目标:有哪些相互竞争的目标?(降低成本、提高服务水平、减少碳排放)
  2. 偏好:是否已知权衡关系,还是需要发现帕累托前沿?
  3. 决策者:采用交互式还是自动化选择?
  4. 问题规模:能否用精确方法求解,还是需要启发式方法?

核心概念

帕累托支配: 如果解 x 在所有目标上都优于 y,则 x 支配 y

帕累托前沿: 由非支配解组成的集合

权衡: 改善一个目标会使另一个目标变差


方法

1. 加权和法(标量化)
# Combine objectives with weights
objective = w1 * cost + w2 * (-service_level) + w3 * carbon

# Vary weights to get different Pareto points
for w1 in [0.2, 0.5, 0.8]:
    w2, w3 = (1-w1)/2, (1-w1)/2
    solve_with_weights(w1, w2, w3)
2. ε 约束法
# Optimize one objective, constrain others
minimize cost
subject to:
    service_level ≥ 0.95
    carbon ≤ 1000
3. NSGA-II(遗传算法)
from pymoo.algorithms.moo.nsga2 import NSGA2
from pymoo.optimize import minimize
from pymoo.problems import get_problem

# Multi-objective problem
problem = SupplyChainMO()

algorithm = NSGA2(pop_size=100)

res = minimize(problem,
               algorithm,
               ('n_gen', 200),
               verbose=True)

# Get Pareto front
pareto_front = res.F
4. 目标规划
# Set target for each objective, minimize deviations
targets = {'cost': 100000, 'service': 0.98, 'carbon': 500}

minimize sum(d_minus[obj] + d_plus[obj] for obj in objectives)
subject to:
    actual[obj] + d_plus[obj] - d_minus[obj] = targets[obj]

供应链网络设计:成本与服务

from pulp import *
import numpy as np
import matplotlib.pyplot as plt

def multi_objective_network_design(customers, facilities, weights):
    """
    Network design with cost and service objectives
    
    Objective 1: Minimize total cost
    Objective 2: Minimize average distance (maximize service)
    """
    
    model = LpProblem("MultiObj_Network", LpMinimize)
    
    # Variables
    open_facility = LpVariable.dicts("Open", facilities, cat='Binary')
    flow = LpVariable.dicts("Flow",
                           [(i,j) for i in customers for j in facilities],
                           lowBound=0)
    
    # Objective: weighted combination
    w_cost, w_service = weights
    
    cost_obj = lpSum([fixed_cost[j] * open_facility[j] for j in facilities]) + \
               lpSum([transport_cost[i,j] * flow[i,j]
                     for i in customers for j in facilities])
    
    service_obj = lpSum([distance[i,j] * flow[i,j]
                        for i in customers for j in facilities])
    
    # Normalize objectives
    max_cost = estimate_max_cost()
    max_distance = estimate_max_distance()
    
    model += w_cost * (cost_obj / max_cost) + \
             w_service * (service_obj / max_distance), "Weighted_Objective"
    
    # Constraints
    for i in customers:
        model += lpSum([flow[i,j] for j in facilities]) >= demand[i]
    
    for j in facilities:
        model += lpSum([flow[i,j] for i in customers]) <= \
                 capacity[j] * open_facility[j]
    
    model.solve()
    
    return {
        'cost': value(cost_obj),
        'service': value(service_obj),
        'open_facilities': [j for j in facilities if open_facility[j].varValue > 0.5]
    }

# Generate Pareto frontier
pareto_solutions = []
for w_cost in np.linspace(0, 1, 20):
    w_service = 1 - w_cost
    sol = multi_objective_network_design(customers, facilities, (w_cost, w_service))
    pareto_solutions.append(sol)

# Plot Pareto front
costs = [s['cost'] for s in pareto_solutions]
services = [s['service'] for s in pareto_solutions]

plt.figure(figsize=(10, 6))
plt.plot(costs, services, 'o-', linewidth=2, markersize=8)
plt.xlabel('Total Cost ($)')
plt.ylabel('Average Distance (Service)')
plt.title('Pareto Frontier: Cost vs Service Trade-off')
plt.grid(True, alpha=0.3)
plt.show()

可持续供应链:经济、环境与社会

class TripleBottomLineOptimization:
    """
    Optimize Economic, Environmental, and Social objectives
    """
    
    def __init__(self, network_data):
        self.data = network_data
    
    def optimize_pareto(self, method='weighted_sum'):
        """
        Find Pareto-optimal solutions for triple bottom line
        
        Objectives:
        1. Economic: Minimize cost
        2. Environmental: Minimize carbon emissions
        3. Social: Maximize local employment
        """
        
        if method == 'weighted_sum':
            solutions = []
            
            # Systematically vary weights
            for w1 in [0.2, 0.4, 0.6, 0.8]:
                for w2 in [0.2, 0.4, 0.6, 0.8]:
                    w3 = max(0, 1 - w1 - w2)
                    if w1 + w2 + w3 > 0.99:  # Valid weight combination
                        sol = self.solve_weighted(w1, w2, w3)
                        solutions.append(sol)
            
            # Filter non-dominated solutions
            pareto_front = self.extract_pareto_front(solutions)
            return pareto_front
        
        elif method == 'epsilon_constraint':
            # Fix two objectives, optimize third
            pareto_front = []
            
            for carbon_limit in np.linspace(min_carbon, max_carbon, 10):
                for employment_target in np.linspace(min_emp, max_emp, 10):
                    sol = self.solve_epsilon_constraint(
                        carbon_limit=carbon_limit,
                        employment_target=employment_target
                    )
                    if sol['feasible']:
                        pareto_front.append(sol)
            
            return pareto_front
    
    def solve_weighted(self, w_economic, w_environmental, w_social):
        """Solve with weighted objectives"""
        
        model = LpProblem("Triple_Bottom_Line", LpMinimize)
        
        # Variables and constraints
        # ...
        
        # Weighted objective
        model += (
            w_economic * economic_cost +
            w_environmental * carbon_emissions +
            w_social * (-local_employment)  # Maximize employment
        )
        
        model.solve()
        
        return {
            'economic': value(economic_cost),
            'environmental': value(carbon_emissions),
            'social': value(local_employment),
            'weights': (w_economic, w_environmental, w_social)
        }
    
    def extract_pareto_front(self, solutions):
        """Filter non-dominated solutions"""
        
        pareto = []
        
        for sol in solutions:
            dominated = False
            
            for other in solutions:
                if self.dominates(other, sol):
                    dominated = True
                    break
            
            if not dominated:
                pareto.append(sol)
        
        return pareto
    
    def dominates(self, sol1, sol2):
        """Check if sol1 Pareto-dominates sol2"""
        
        # sol1 dominates if better in all objectives
        better_economic = sol1['economic'] <= sol2['economic']
        better_environmental = sol1['environmental'] <= sol2['environmental']
        better_social = sol1['social'] >= sol2['social']  # Maximize
        
        at_least_one_strictly_better = (
            sol1['economic'] < sol2['economic'] or
            sol1['environmental'] < sol2['environmental'] or
            sol1['social'] > sol2['social']
        )
        
        return (better_economic and better_environmental and better_social and
                at_least_one_strictly_better)

交互式决策

def interactive_pareto_exploration(problem, decision_maker):
    """
    Interactive method: present solutions, get feedback, refine
    """
    
    # Generate initial Pareto front
    pareto_front = problem.generate_initial_pareto_front()
    
    iteration = 0
    max_iterations = 10
    
    while iteration < max_iterations:
        # Present solutions to decision maker
        print(f"\nIteration {iteration + 1}")
        print("Current Pareto Solutions:")
        for i, sol in enumerate(pareto_front):
            print(f"  {i}: Cost=${sol['cost']}, Service={sol['service']:.2%}, Carbon={sol['carbon']}")
        
        # Get feedback
        preferred_region = decision_maker.get_preference(pareto_front)
        
        if decision_maker.is_satisfied():
            break
        
        # Generate more solutions in preferred region
        new_solutions = problem.explore_region(preferred_region, n_solutions=10)
        pareto_front.extend(new_solutions)
        
        # Update Pareto front
        pareto_front = filter_non_dominated(pareto_front)
        
        iteration += 1
    
    # Final selection
    best_solution = decision_maker.select_final_solution(pareto_front)
    return best_solution

可视化

def visualize_3d_pareto_front(solutions):
    """
    Visualize 3-objective Pareto front
    """
    
    from mpl_toolkits.mplot3d import Axes3D
    
    fig = plt.figure(figsize=(12, 10))
    ax = fig.add_subplot(111, projection='3d')
    
    costs = [s['cost'] for s in solutions]
    services = [s['service'] for s in solutions]
    carbons = [s['carbon'] for s in solutions]
    
    scatter = ax.scatter(costs, services, carbons,
                        c=carbons, cmap='RdYlGn_r',
                        s=100, alpha=0.6, edgecolors='black')
    
    ax.set_xlabel('Cost ($)', fontsize=12)
    ax.set_ylabel('Service Level', fontsize=12)
    ax.set_zlabel('Carbon Emissions (tons)', fontsize=12)
    ax.set_title('3D Pareto Frontier', fontsize=14, fontweight='bold')
    
    plt.colorbar(scatter, label='Carbon Emissions')
    plt.show()

def visualize_parallel_coordinates(pareto_front):
    """
    Parallel coordinates plot for many objectives
    """
    
    from pandas.plotting import parallel_coordinates
    import pandas as pd
    
    df = pd.DataFrame(pareto_front)
    df['Solution'] = range(len(df))
    
    plt.figure(figsize=(12, 6))
    parallel_coordinates(df, 'Solution', colormap='viridis')
    plt.title('Pareto Solutions - Parallel Coordinates')
    plt.ylabel('Normalized Objective Value')
    plt.legend(loc='upper right')
    plt.grid(True, alpha=0.3)
    plt.show()

工具与库

Python:

  • pymoo:多目标优化
  • platypus:进化式多目标优化
  • jmetal:多目标元启发式方法

商业软件:

  • modeFRONTIER:多目标设计
  • CPLEX Multi-Objective

相关技能

  • optimization-modeling:单目标优化
  • metaheuristic-optimization:NSGA-II、MOEA
  • sustainable-sourcing:环境目标
  • network-design:多目标网络设计

评论

支持 Markdown