Problem Types
OptiX supports three main types of optimization problems with increasing complexity: Constraint Satisfaction Problems (CSP), Linear Programming (LP), and Goal Programming (GP). This guide explains when and how to use each type.
Constraint Satisfaction Problems (CSP)
CSPs focus on finding any solution that satisfies all constraints without optimizing any particular objective. They are the foundation for more complex problem types.
When to Use CSP
Finding feasible solutions to complex constraint systems
Scheduling problems where any valid schedule is acceptable
Configuration problems with multiple requirements
Preprocessing to check problem feasibility
Key Characteristics
Variables: Decision variables with bounds and types
Constraints: Linear and special constraints that must be satisfied
No Objective: Focus on feasibility, not optimality
Solution: Any point that satisfies all constraints
from problem import OXCSPProblem
from constraints import RelationalOperators
# Create CSP for employee scheduling
csp = OXCSPProblem()
# Variables: work assignments (binary)
days = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri']
shifts = ['Morning', 'Evening']
employees = ['Alice', 'Bob', 'Carol']
for employee in employees:
for day in days:
for shift in shifts:
csp.create_decision_variable(
var_name=f"{employee}_{day}_{shift}",
description=f"{employee} works {shift} on {day}",
lower_bound=0,
upper_bound=1,
variable_type="binary"
)
# Constraint: Each shift must be covered
for day in days:
for shift in shifts:
shift_vars = [
var.id for var in csp.variables
if f"{day}_{shift}" in var.name
]
csp.create_constraint(
variables=shift_vars,
weights=[1] * len(shift_vars),
operator=RelationalOperators.GREATER_THAN_EQUAL,
value=1,
description=f"Cover {shift} shift on {day}"
)
# Constraint: No employee works both shifts same day
for employee in employees:
for day in days:
morning_var = next(v for v in csp.variables if f"{employee}_{day}_Morning" in v.name)
evening_var = next(v for v in csp.variables if f"{employee}_{day}_Evening" in v.name)
csp.create_constraint(
variables=[morning_var.id, evening_var.id],
weights=[1, 1],
operator=RelationalOperators.LESS_THAN_EQUAL,
value=1,
description=f"{employee} works at most one shift on {day}"
)
Linear Programming (LP)
Linear Programming extends CSP by adding an objective function to optimize. LP problems seek to maximize or minimize a linear objective subject to linear constraints.
When to Use LP
Resource allocation with clear optimization goals
Production planning to maximize profit or minimize cost
Transportation problems minimizing shipping costs
Portfolio optimization with linear objectives
Key Characteristics
Variables: Continuous, integer, or binary decision variables
Constraints: Linear equality and inequality constraints
Objective: Single linear objective function (minimize or maximize)
Solution: Optimal point that maximizes/minimizes the objective
Mathematical Form
Where: - \(x_i\) are decision variables - \(c_i\) are objective coefficients - \(a_{ji}\) are constraint coefficients - \(b_j\) are constraint bounds
from problem import OXLPProblem, ObjectiveType
from constraints import RelationalOperators
# Create LP for production planning
lp = OXLPProblem()
# Products to manufacture
products = [
{'name': 'Product_A', 'profit': 50, 'labor': 2, 'material': 1},
{'name': 'Product_B', 'profit': 40, 'labor': 3, 'material': 2},
{'name': 'Product_C', 'profit': 60, 'labor': 1, 'material': 3}
]
# Create production variables
for product in products:
lp.create_decision_variable(
var_name=f"production_{product['name']}",
description=f"Units of {product['name']} to produce",
lower_bound=0,
upper_bound=1000,
variable_type="continuous"
)
# Resource constraints
# Labor constraint: total labor <= 1000 hours
labor_vars = [var.id for var in lp.variables]
labor_weights = [product['labor'] for product in products]
lp.create_constraint(
variables=labor_vars,
weights=labor_weights,
operator=RelationalOperators.LESS_THAN_EQUAL,
value=1000,
description="Labor hours constraint"
)
# Material constraint: total material <= 800 units
material_weights = [product['material'] for product in products]
lp.create_constraint(
variables=labor_vars, # Same variables
weights=material_weights,
operator=RelationalOperators.LESS_THAN_EQUAL,
value=800,
description="Material constraint"
)
# Objective: maximize total profit
profit_weights = [product['profit'] for product in products]
lp.create_objective_function(
variables=labor_vars,
weights=profit_weights,
objective_type=ObjectiveType.MAXIMIZE
)
# Solve the problem
from solvers import solve
status, solution = solve(lp, 'ORTools')
Goal Programming (GP)
Goal Programming handles multiple, often conflicting objectives by formulating them as goals with associated deviation variables and priorities.
When to Use GP
Multi-criteria decision making
Problems with conflicting objectives
Situations where trade-offs are necessary
When exact goal achievement is less important than minimizing deviations
Key Characteristics
Variables: Decision variables plus deviation variables
Constraints: Regular constraints plus goal constraints
Objectives: Multiple goals with priorities or weights
Solution: Minimize weighted deviations from goals
Mathematical Form
Where: - \(d_i^+, d_i^-\) are positive and negative deviation variables - \(w_i^+, w_i^-\) are weights for deviations - \(g_i\) are goal targets
from problem import OXGPProblem
from constraints import RelationalOperators
# Create GP for workforce planning
gp = OXGPProblem()
# Decision variables: number of employees to hire
departments = ['Engineering', 'Sales', 'Support']
for dept in departments:
gp.create_decision_variable(
var_name=f"hire_{dept}",
description=f"Employees to hire in {dept}",
lower_bound=0,
upper_bound=50,
variable_type="integer"
)
# Goal constraints with priorities
goals = [
{
'description': 'Total workforce target of 100 employees',
'variables': [var.id for var in gp.variables],
'weights': [1, 1, 1],
'target': 100,
'priority': 1
},
{
'description': 'Engineering should be 40% of workforce',
'variables': [gp.variables[0].id], # Engineering
'weights': [1],
'target': 40,
'priority': 2
},
{
'description': 'Balance between Sales and Support',
'variables': [gp.variables[1].id, gp.variables[2].id], # Sales, Support
'weights': [1, -1],
'target': 0, # Equal hiring
'priority': 3
}
]
# Add goal constraints
for goal in goals:
gp.create_goal_constraint(
variables=goal['variables'],
weights=goal['weights'],
target_value=goal['target'],
description=goal['description']
)
# Additional regular constraints
# Budget constraint: hiring costs <= $500,000
hiring_costs = [80000, 60000, 50000] # Cost per hire by department
gp.create_constraint(
variables=[var.id for var in gp.variables],
weights=hiring_costs,
operator=RelationalOperators.LESS_THAN_EQUAL,
value=500000,
description="Budget constraint"
)
Problem Type Comparison
| Aspect | CSP | LP | GP |
|---|---|---|---|
| Primary Goal | Find feasible solution | Optimize single objective | Balance multiple objectives |
| Objective Function | None | Single linear objective | Multiple goals with priorities |
| Solution Type | Any feasible point | Optimal point | Best compromise point |
| Complexity | Low | Medium | High |
| Use Cases | Scheduling, Configuration | Resource allocation, Planning | Multi-criteria decisions |
Advanced Problem Features
Special Constraints
All problem types support special constraints for non-linear operations:
from problem import SpecialConstraintType
# Multiplication constraint: production * price = revenue
problem.create_special_constraint(
constraint_type=SpecialConstraintType.MULTIPLICATION,
left_variable_id=production_var.id,
right_variable_id=price_var.id,
result_variable_id=revenue_var.id
)
# Conditional constraint: if condition then action
problem.create_special_constraint(
constraint_type=SpecialConstraintType.CONDITIONAL,
left_variable_id=condition_var.id,
right_variable_id=action_var.id,
result_variable_id=result_var.id
)
Database Integration
Create variables and constraints from data objects:
from data import OXData, OXDatabase
# Create data structure
facilities = OXDatabase([
OXData(name="Plant_A", capacity=500, cost=1000),
OXData(name="Plant_B", capacity=300, cost=800)
])
customers = OXDatabase([
OXData(name="Customer_1", demand=200, location="NY"),
OXData(name="Customer_2", demand=150, location="CA")
])
# Create variables from Cartesian product
problem.create_variables_from_database_objects(
database_objects=[facilities, customers],
variable_name_template="ship_{0}_{1}",
variable_description_template="Shipment from {0} to {1}",
lower_bound=0,
upper_bound=1000
)
Problem Selection Guide
Choosing the Right Problem Type
Choose CSP When:
- Any feasible solution is acceptable
- Checking if constraints can be satisfied
- Constraint complexity is the main challenge
- No clear optimization criterion exists
Choose LP When:
- Clear single objective exists
- Linear relationships dominate
- Optimal solution is required
- Resource allocation is the focus
Choose GP When:
- Multiple conflicting objectives
- Trade-offs are necessary
- Stakeholder preferences vary
- Compromise solutions are acceptable
Migration Between Problem Types
You can easily migrate between problem types as requirements evolve:
# Start with CSP to check feasibility
csp = OXCSPProblem()
# ... add variables and constraints
# Convert to LP when objective becomes clear
lp = OXLPProblem()
# Copy variables and constraints from CSP
for variable in csp.variables:
lp.add_variable(variable)
for constraint in csp.constraints:
lp.add_constraint(constraint)
# Add objective function
lp.create_objective_function(variables, weights, ObjectiveType.MAXIMIZE)
# Evolve to GP when multiple objectives emerge
gp = OXGPProblem()
# Copy from LP and add goal constraints
Best Practices
Problem Modeling
Start Simple: Begin with CSP to ensure feasibility
Add Gradually: Introduce objectives and goals incrementally
Validate Early: Check constraints before adding complexity
Use Data: Leverage database integration for complex scenarios
Performance Tips
Variable Bounds: Tighten bounds to reduce search space
Constraint Order: Place restrictive constraints first
Problem Size: Monitor variable and constraint counts
Solver Selection: Choose appropriate solver for problem type
Common Pitfalls
Infeasible Problems: Over-constraining the solution space
Unbounded Objectives: Missing constraints on decision variables
Numerical Issues: Very large or very small coefficients
Goal Conflicts: Incompatible goals in GP problems
Tip
Development Workflow: Start with CSP to validate your constraint model, then add objectives to create LP, and finally introduce multiple goals for GP.
See Also
Quick Start Guide - Get started with your first problem
constraints - Advanced constraint modeling
Examples - Real-world problem examples
Problem Module - Complete API reference