| name | multi-objective-optimization |
| description | When the user wants to optimize multiple conflicting objectives, find Pareto-optimal solutions, or balance trade-offs between cost, service, quality, and sustainability. Also use when the user mentions "multi-objective," "Pareto optimization," "NSGA-II," "trade-off analysis," "scalarization," "weighted objectives," "goal programming," or "multiple criteria optimization." For single objective, see optimization-modeling. |
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?
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
Methods
1. Weighted Sum (Scalarization)
objective = w1 * cost + w2 * (-service_level) + w3 * carbon
for w1 in [0.2, 0.5, 0.8]:
w2, w3 = (1-w1)/2, (1-w1)/2
solve_with_weights(w1, w2, w3)
2. ε-Constraint Method
minimize cost
subject to:
service_level ≥ 0.95
carbon ≤ 1000
3. NSGA-II (Genetic Algorithm)
from pymoo.algorithms.moo.nsga2 import NSGA2
from pymoo.optimize import minimize
from pymoo.problems import get_problem
problem = SupplyChainMO()
algorithm = NSGA2(pop_size=100)
res = minimize(problem,
algorithm,
('n_gen', 200),
verbose=True)
pareto_front = res.F
4. Goal Programming
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
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)
open_facility = LpVariable.dicts("Open", facilities, cat='Binary')
flow = LpVariable.dicts("Flow",
[(i,j) for i in customers for j in facilities],
lowBound=0)
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])
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"
for i in customers:
model += lpSum([flow[i,j] for j in facilities]) >= demand[i]
j facilities:
model += lpSum([flow[i,j] i customers]) <= \
capacity[j] * open_facility[j]
model.solve()
{
: value(cost_obj),
: value(service_obj),
: [j j facilities open_facility[j].varValue > ]
}
pareto_solutions = []
w_cost np.linspace(, , ):
w_service = - w_cost
sol = multi_objective_network_design(customers, facilities, (w_cost, w_service))
pareto_solutions.append(sol)
costs = [s[] s pareto_solutions]
services = [s[] s pareto_solutions]
plt.figure(figsize=(, ))
plt.plot(costs, services, , linewidth=, markersize=)
plt.xlabel()
plt.ylabel()
plt.title()
plt.grid(, alpha=)
plt.show()
Sustainable Supply Chain: Economic-Environmental-Social
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 = []
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:
sol = self.solve_weighted(w1, w2, w3)
solutions.append(sol)
pareto_front = self.extract_pareto_front(solutions)
return pareto_front
elif method == 'epsilon_constraint':
pareto_front = []
carbon_limit np.linspace(min_carbon, max_carbon, ):
employment_target np.linspace(min_emp, max_emp, ):
sol = .solve_epsilon_constraint(
carbon_limit=carbon_limit,
employment_target=employment_target
)
sol[]:
pareto_front.append(sol)
pareto_front
():
model = LpProblem(, LpMinimize)
model += (
w_economic * economic_cost +
w_environmental * carbon_emissions +
w_social * (-local_employment)
)
model.solve()
{
: value(economic_cost),
: value(carbon_emissions),
: value(local_employment),
: (w_economic, w_environmental, w_social)
}
():
pareto = []
sol solutions:
dominated =
other solutions:
.dominates(other, sol):
dominated =
dominated:
pareto.append(sol)
pareto
():
better_economic = sol1[] <= sol2[]
better_environmental = sol1[] <= sol2[]
better_social = sol1[] >= sol2[]
at_least_one_strictly_better = (
sol1[] < sol2[]
sol1[] < sol2[]
sol1[] > sol2[]
)
(better_economic better_environmental better_social
at_least_one_strictly_better)
Interactive Decision-Making
def interactive_pareto_exploration(problem, decision_maker):
"""
Interactive method: present solutions, get feedback, refine
"""
pareto_front = problem.generate_initial_pareto_front()
iteration = 0
max_iterations = 10
while iteration < max_iterations:
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']}")
preferred_region = decision_maker.get_preference(pareto_front)
if decision_maker.is_satisfied():
break
new_solutions = problem.explore_region(preferred_region, n_solutions=10)
pareto_front.extend(new_solutions)
pareto_front = filter_non_dominated(pareto_front)
iteration += 1
best_solution = decision_maker.select_final_solution(pareto_front)
return best_solution
Visualization
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((df))
plt.figure(figsize=(, ))
parallel_coordinates(df, , colormap=)
plt.title()
plt.ylabel()
plt.legend(loc=)
plt.grid(, alpha=)
plt.show()
Tools & Libraries
Python:
pymoo: Multi-objective optimization
platypus: Evolutionary multi-objective
jmetal: Multi-objective metaheuristics
Commercial:
modeFRONTIER: Multi-objective design
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