Goal Programming Example¶
Overview¶
This example demonstrates LumiX’s built-in goal programming support, which allows automatic conversion of hard constraints into soft constraints (goals) that can be violated with penalties.
Goal programming enables multi-objective optimization by prioritizing multiple conflicting goals and minimizing deviations from target values.
Problem Description¶
A company produces products with multiple conflicting objectives:
Goals (soft constraints that can be violated):
Meet minimum production targets (Priority 1 - highest)
Limit overtime hours (Priority 2 - medium)
Achieve target profit (Priority 3 - lowest)
Hard Constraints (must be satisfied):
Total hours ≤ capacity + overtime
Challenge: Traditional LP requires choosing one objective. Goal programming allows pursuing multiple goals simultaneously with priorities.
Mathematical Formulation¶
Traditional LP (Single Objective):
Goal Programming (Multiple Goals):
Subject to (relaxed constraints):
where:
\(d_g^+\) = positive deviation (exceeding target)
\(d_g^-\) = negative deviation (falling short of target)
\(w_p\) = priority weight (e.g., \(10^6, 10^5, 10^4\))
\(G_p\) = goals at priority level \(p\)
Goal Types¶
Minimize Excess (LE Constraints)¶
For expr ≤ rhs goals, minimize \(d^+\) (exceeding is bad):
model.add_constraint(
LXConstraint("overtime_limit")
.expression(overtime_expr)
.le()
.rhs(40)
.as_goal(priority=2, weight=1.0)
)
Minimize Shortfall (GE Constraints)¶
For expr ≥ rhs goals, minimize \(d^-\) (falling short is bad):
model.add_constraint(
LXConstraint("production_target")
.expression(production_expr)
.ge()
.rhs(100)
.as_goal(priority=1, weight=1.0)
)
Minimize Both Deviations (EQ Constraints)¶
For expr = rhs goals, minimize both \(d^+\) and \(d^-\):
model.add_constraint(
LXConstraint("profit_target")
.expression(profit_expr)
.eq()
.rhs(1800)
.as_goal(priority=3, weight=1.0)
)
Key Features¶
Automatic Goal Relaxation¶
Mark constraints as goals:
Product A : 100.00 units (Target: 100.00)
Product B : 80.00 units (Target: 80.00)
...
Goal Satisfaction:
Production Goal Product A: [SATISFIED]
Under-production: 0.00
Over-production: 0.00
Key Points:
.as_goal(priority, weight)marks constraint as softPriority determines importance (1 = highest)
Weight allows fine-tuning within priority level
Automatic Deviation Variables¶
LumiX automatically creates deviation variables:
# For each goal, LumiX creates:
# - goal_name_pos_dev (d⁺)
# - goal_name_neg_dev (d⁻)
# Original: production >= 100
# Relaxed: production + d⁻ - d⁺ = 100
Weighted vs Sequential Mode¶
Weighted Mode (default - single solve):
model.set_goal_mode("weighted")
# Priorities converted to exponential weights:
# P1: 10^6, P2: 10^5, P3: 10^4
Sequential Mode (multiple solves - true preemptive):
model.set_goal_mode("sequential")
# Solve priorities lexicographically:
# 1. Minimize P1 deviations
# 2. Fix P1, minimize P2 deviations
# 3. Fix P2, minimize P3 deviations
Solution Analysis¶
Check goal satisfaction:
LXConstraint(f"production_goal_{product.id}")
.expression(prod_expr)
.ge()
.rhs(product.target_production)
.as_goal(priority=1, weight=1.0) # Highest priority
)
# Goal 2: Limit overtime (Priority 2, medium)
# overtime <= MAX_OVERTIME
overtime_expr = LXLinearExpression().add_term(overtime, coeff=1.0)
model.add_constraint(
LXConstraint("overtime_goal")
.expression(overtime_expr)
.le()
.rhs(MAX_OVERTIME)
.as_goal(priority=2, weight=1.0) # Medium priority
)
Running the Example¶
Prerequisites:
pip install lumix
pip install ortools # or cplex, gurobi
Run:
cd examples/11_goal_programming
python 01_basic_goal_programming.py
Expected Output:
======================================================================
Basic Goal Programming Example
======================================================================
Model Summary:
Variables: 2 families + deviation variables
Constraints: 1 hard + 7 goals
Mode: weighted
======================================================================
Solution
======================================================================
Status: optimal
Objective: 1234.56 (weighted deviations)
----------------------------------------------------------------------
Production Plan:
----------------------------------------------------------------------
Product A : 105.00 units (Target: 100.00)
Product B : 95.00 units (Target: 80.00)
Overtime : 45.00 hours (Target: <=50.00)
Total Profit : $1,750.00 (Target: $1,800.00)
----------------------------------------------------------------------
Goal Satisfaction:
----------------------------------------------------------------------
Production Goal Product A: ✓ Satisfied
Under-production: 0.00
Over-production: 5.00
Production Goal Product B: ✓ Satisfied
Under-production: 0.00
Over-production: 15.00
Overtime Goal: ✓ Satisfied
Under limit: 0.00
Over limit: 0.00
Profit Goal: ✗ Not Satisfied
Under target: $50.00
Over target: $0.00
Complete Code Walkthrough¶
Step 1: Define Variables¶
variables. The workflow includes:
1. Building a production planning model with hard and soft constraints
2. Marking constraints as goals with priorities and weights
3. Automatically preparing goal programming (creates deviation variables)
4. Solving with weighted goal programming (single optimization)
5. Analyzing goal satisfaction and deviations
The example uses a simple production planning problem with three goals:
- Priority 1 (highest): Meet production targets
- Priority 2 (medium): Limit overtime hours
- Priority 3 (lowest): Achieve target profit
Returns:
None. Results are printed to console including:
- Model summary with variables and constraints
- Optimal solution with production quantities
- Goal satisfaction status for each goal
Step 2: Add Hard Constraints¶
$ python 01_basic_goal_programming.py
Or import and run programmatically::
>>> from examples.goal_programming.basic_goal_programming import main
>>> main()
Expected output::
Step 3: Add Goal Constraints¶
====================================================================
Model Summary:
...
Production Plan:
Product A : 100.00 units (Target: 100.00)
Product B : 80.00 units (Target: 80.00)
...
Goal Satisfaction:
Production Goal Product A: [SATISFIED]
Under-production: 0.00
Over-production: 0.00
...
Notes:
Goal Programming concepts demonstrated:
- Hard constraints: Must be satisfied (e.g., capacity limits)
- Soft constraints (goals): Can be violated with penalty
- Deviation variables: neg (under) and pos (over) deviation
- Priorities: Higher priority goals are more important
- Weights: Relative importance within same priority level
The .as_goal() method marks a constraint as a goal:
- .as_goal(priority=1, weight=1.0): Highest priority
- Higher priorities dominate lower priorities in weighted mode
- Within same priority, weights determine relative importance
Weighted mode converts priorities to exponentially different weights:
- Priority 1: weight * 10^6
- Priority 2: weight * 10^5
- Priority 3: weight * 10^4
This ensures higher priorities are always satisfied first before
considering lower priority goals.
The .prepare_goal_programming() method automatically:
- Creates deviation variables (neg, pos) for each goal
Step 4: Configure Goal Mode¶
- Maintains the original model structure
"""
print("=" * 70)
print("Basic Goal Programming Example")
Step 5: Solve and Analyze Goals¶
.continuous()
.bounds(lower=0)
.indexed_by(lambda p: p.id)
.from_data(PRODUCTS)
)
# Scalar variable needs a data source - use single element
overtime = (
LXVariable[int, float]("overtime")
Learning Objectives¶
After completing this example, you should understand:
Multi-Objective Optimization: Pursuing multiple goals simultaneously
Soft Constraints: Converting hard constraints to goals
Deviation Variables: How d⁺ and d⁻ represent violations
Priority Levels: Hierarchical goal importance
Weighted Formulation: Single-solve approximation of priorities
Goal Satisfaction: Analyzing which goals were achieved
Common Patterns¶
Pattern 1: Basic Goal Constraint¶
model.add_constraint(
LXConstraint("goal_name")
.expression(expr)
.ge() # or .le(), .eq()
.rhs(target_value)
.as_goal(priority=1, weight=1.0)
)
Pattern 2: Multiple Priorities¶
# Priority 1 (highest - must achieve if possible)
model.add_constraint(...).as_goal(priority=1, weight=1.0)
# Priority 2 (second - achieve after P1)
model.add_constraint(...).as_goal(priority=2, weight=1.0)
# Priority 3 (lowest - nice to have)
model.add_constraint(...).as_goal(priority=3, weight=1.0)
Pattern 3: Custom Objective (Priority 0)¶
# Use priority 0 to incorporate custom objective
model.add_constraint(
LXConstraint("maximize_profit")
.expression(profit_expr)
.ge()
.rhs(0)
.as_goal(priority=0, weight=1.0)
)
Pattern 4: Indexed Goals¶
# Goals for each entity
for entity in ENTITIES:
expr = LXLinearExpression().add_term(...)
model.add_constraint(
LXConstraint(f"goal_{entity.id}")
.expression(expr)
.ge()
.rhs(entity.target)
.as_goal(priority=1, weight=entity.importance)
)
Priority Weighting¶
Weighted Mode Calculation¶
# Automatic weight calculation
priority_weight = 10 ** (6 - priority)
combined_weight = priority_weight * goal_weight
# Examples:
# P1, w=1.0: 10^6 × 1.0 = 1,000,000
# P2, w=0.5: 10^5 × 0.5 = 50,000
# P3, w=2.0: 10^4 × 2.0 = 20,000
This ensures higher priorities dominate in the objective function.
Custom Weights Within Priority¶
# Different weights within same priority
model.add_constraint(...).as_goal(priority=1, weight=2.0) # More important
model.add_constraint(...).as_goal(priority=1, weight=1.0) # Less important
model.add_constraint(...).as_goal(priority=1, weight=0.5) # Least important
Goal Satisfaction Analysis¶
Check Individual Goals¶
# Check if goal satisfied
satisfied = solution.is_goal_satisfied("goal_name", tolerance=1e-6)
# Get deviation values
deviations = solution.get_goal_deviations("goal_name")
pos_dev = deviations["pos"] # Over-achievement
neg_dev = deviations["neg"] # Under-achievement
Indexed Goals¶
for entity in ENTITIES:
goal_name = f"goal_{entity.id}"
deviations = solution.get_goal_deviations(goal_name)
# Deviations are dictionaries for indexed goals
neg_dev_dict = deviations["neg"]
pos_dev_dict = deviations["pos"]
print(f"{entity.name}:")
print(f" Shortfall: {neg_dev_dict.get(entity.id, 0):.2f}")
print(f" Excess: {pos_dev_dict.get(entity.id, 0):.2f}")
Use Cases¶
Business Applications¶
Production Planning: Balance profit, costs, quality goals
Resource Allocation: Satisfy competing departmental needs
Project Portfolio: Optimize across budget, risk, strategic fit
Staff Scheduling: Balance coverage, costs, preferences
Supply Chain: Optimize service level, cost, inventory goals
When to Use Goal Programming¶
Use goal programming when:
Multiple conflicting objectives exist
Trade-offs between goals are acceptable
Priorities can be assigned to objectives
Some constraints can be relaxed with penalty
Don’t use when:
Single objective is clear
All constraints are hard (must be satisfied)
Equal importance for all objectives
Extending the Example¶
Try These Modifications¶
More Priorities: Add 4th and 5th priority levels
Sequential Mode: Enable true preemptive GP (when available)
Dynamic Weights: Adjust weights based on context
Conditional Goals: Goals that activate under conditions
Interactive: Allow user to set priorities dynamically
Next Steps¶
After mastering this example:
Example 09 (Sensitivity Analysis): Understanding constraint values
Example 08 (Scenario Analysis): Testing goal achievement under scenarios
Advanced GP: Multi-priority weighted formulations
See Also¶
Related Examples:
Production Planning Example - Base model for goal programming
Scenario Analysis Example - Testing goals under different scenarios
Sensitivity Analysis Example - Understanding trade-offs
API Reference:
lumix.solution.LXSolution
References:
Charnes & Cooper (1961). “Management Models and Industrial Applications of Linear Programming”
Ignizio (1976). “Goal Programming and Extensions”
Romero (1991). “Handbook of Critical Issues in Goal Programming”
Files in This Example¶
01_basic_goal_programming.py- Basic goal programming demonstration02_multi_priority_weighted.py- Advanced multi-priority exampleREADME.md- Detailed documentation and usage guide