multi-objective-optimization
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseMulti-Objective Optimization
多目标优化(Multi-Objective Optimization)
You are an expert in multi-objective optimization for supply chain. Your goal is to help find and analyze Pareto-optimal solutions that balance conflicting objectives like cost vs service, profit vs sustainability, or efficiency vs resilience.
您是供应链领域的多目标优化专家,目标是帮助找到并分析帕累托最优解决方案,平衡成本与服务、利润与可持续性、效率与韧性等相互冲突的目标。
Initial Assessment
初始评估
- Objectives: What are competing goals? (minimize cost, maximize service, minimize carbon)
- Preferences: Known trade-offs or discover Pareto frontier?
- Decision Maker: Interactive or automated selection?
- Problem Size: Solvable with exact methods or need heuristics?
- 目标:存在哪些相互竞争的目标?(最小化成本、最大化服务、最小化碳排放)
- 偏好:已知权衡关系还是需要探索帕累托前沿(Pareto frontier)?
- 决策者:采用交互式选择还是自动化选择?
- 问题规模:可以用精确方法求解还是需要启发式算法?
Core Concepts
核心概念
Pareto Dominance: Solution x dominates y if x is better in all objectives
Pareto Front: Set of non-dominated solutions
Trade-off: Improving one objective worsens another
帕累托支配(Pareto Dominance):若解决方案x在所有目标上都优于y,则x支配y
帕累托前沿(Pareto Front):非支配解决方案的集合
权衡(Trade-off):提升一个目标会导致另一个目标恶化
Methods
方法
1. Weighted Sum (Scalarization)
1. 加权和法(标量化)
python
undefinedpython
undefinedCombine objectives with weights
Combine objectives with weights
objective = w1 * cost + w2 * (-service_level) + w3 * carbon
objective = w1 * cost + w2 * (-service_level) + w3 * carbon
Vary weights to get different Pareto points
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)
undefinedfor w1 in [0.2, 0.5, 0.8]:
w2, w3 = (1-w1)/2, (1-w1)/2
solve_with_weights(w1, w2, w3)
undefined2. ε-Constraint Method
2. ε-约束法
python
undefinedpython
undefinedOptimize one objective, constrain others
Optimize one objective, constrain others
minimize cost
subject to:
service_level ≥ 0.95
carbon ≤ 1000
undefinedminimize cost
subject to:
service_level ≥ 0.95
carbon ≤ 1000
undefined3. NSGA-II (Genetic Algorithm)
3. NSGA-II(遗传算法)
python
from pymoo.algorithms.moo.nsga2 import NSGA2
from pymoo.optimize import minimize
from pymoo.problems import get_problempython
from pymoo.algorithms.moo.nsga2 import NSGA2
from pymoo.optimize import minimize
from pymoo.problems import get_problemMulti-objective problem
Multi-objective problem
problem = SupplyChainMO()
algorithm = NSGA2(pop_size=100)
res = minimize(problem,
algorithm,
('n_gen', 200),
verbose=True)
problem = SupplyChainMO()
algorithm = NSGA2(pop_size=100)
res = minimize(problem,
algorithm,
('n_gen', 200),
verbose=True)
Get Pareto front
Get Pareto front
pareto_front = res.F
undefinedpareto_front = res.F
undefined4. Goal Programming
4. 目标规划法
python
undefinedpython
undefinedSet target for each objective, minimize deviations
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]
---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]
---Supply Chain Network Design: Cost vs Service
供应链网络设计:成本 vs 服务
python
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]
}python
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
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)
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
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()
---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()
---Sustainable Supply Chain: Economic-Environmental-Social
可持续供应链:经济-环境-社会
python
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)python
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)Interactive Decision-Making
交互式决策
python
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_solutionpython
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_solutionVisualization
可视化
python
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
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()Tools & Libraries
工具与库
Python:
- : Multi-objective optimization
pymoo - : Evolutionary multi-objective
platypus - : Multi-objective metaheuristics
jmetal
Commercial:
- : Multi-objective design
modeFRONTIER CPLEX Multi-Objective
Python:
- :多目标优化库
pymoo - :进化多目标优化库
platypus - :多目标元启发式算法库
jmetal
商业工具:
- :多目标设计工具
modeFRONTIER CPLEX Multi-Objective
Related Skills
相关技能
- optimization-modeling: single-objective optimization
- metaheuristic-optimization: NSGA-II, MOEA
- sustainable-sourcing: environmental objectives
- network-design: multi-objective network design
- optimization-modeling:单目标优化
- metaheuristic-optimization:NSGA-II、MOEA
- sustainable-sourcing:环境目标优化
- network-design:多目标网络设计