Gurddy is a lightweight Python package designed to model and solve Constraint Satisfaction Problems (CSP), Linear Programming (LP), and Minimax optimization problems with ease. Built for researchers, engineers, and optimization enthusiasts, Gurddy provides a unified interface to define variables, constraints, and objectives—then leverages powerful solvers under the hood to deliver optimal or feasible solutions.
import gurddy
# Solve a simple logic puzzle: 3 people, pets, and house colors
model = gurddy.Model("LogicPuzzle", "CSP")
# Variables: people, pets, colors (positions 1-3)
alice = model.addVar("alice", domain=[1, 2, 3])
bob = model.addVar("bob", domain=[1, 2, 3])
carol = model.addVar("carol", domain=[1, 2, 3])
cat = model.addVar("cat", domain=[1, 2, 3])
dog = model.addVar("dog", domain=[1, 2, 3])
fish = model.addVar("fish", domain=[1, 2, 3])
red = model.addVar("red", domain=[1, 2, 3])
blue = model.addVar("blue", domain=[1, 2, 3])
green = model.addVar("green", domain=[1, 2, 3])
# All different constraints
model.addConstraint(gurddy.AllDifferentConstraint([alice, bob, carol]))
model.addConstraint(gurddy.AllDifferentConstraint([cat, dog, fish]))
model.addConstraint(gurddy.AllDifferentConstraint([red, blue, green]))
# Logic constraints
def same_position(a, b):
return a == b
model.addConstraint(gurddy.FunctionConstraint(same_position, (alice, cat))) # Alice has cat
model.addConstraint(gurddy.FunctionConstraint(same_position, (bob, red))) # Bob in red house
model.addConstraint(gurddy.FunctionConstraint(same_position, (cat, green))) # Cat owner in green house
model.addConstraint(gurddy.FunctionConstraint(same_position, (carol, fish))) # Carol has fish
# Solve
solution = model.solve()
print("Alice has Cat in Green house")
print("Bob has Dog in Red house")
print("Carol has Fish in Blue house")import gurddy
# Solve 4-Queens problem
model = gurddy.Model("4-Queens", "CSP")
# Create variables (one per row, value = column)
queens = [model.addVar(f"q{i}", domain=[0,1,2,3]) for i in range(4)]
# All queens in different columns
model.addConstraint(gurddy.AllDifferentConstraint(queens))
# No two queens on same diagonal
for i in range(4):
for j in range(i + 1, 4):
row_diff = j - i
diagonal_constraint = lambda c1, c2, rd=row_diff: abs(c1 - c2) != rd
model.addConstraint(gurddy.FunctionConstraint(diagonal_constraint, (queens[i], queens[j])))
# Solve and print solution
solution = model.solve()
if solution:
for row in range(4):
line = ['Q' if solution[f'q{row}'] == col else '.' for col in range(4)]
print(' '.join(line))Output:
. Q . .
. . . Q
Q . . .
. . Q .
from gurddy.solver.minimax_solver import MinimaxSolver
# Solve Rock-Paper-Scissors game
payoff_matrix = [
[0, -1, 1], # Rock vs [Rock, Paper, Scissors]
[1, 0, -1], # Paper vs [Rock, Paper, Scissors]
[-1, 1, 0] # Scissors vs [Rock, Paper, Scissors]
]
solver = MinimaxSolver(None)
result = solver.solve_game_matrix(payoff_matrix, player="row")
print(f"Optimal strategy: Rock={result['strategy'][0]:.2f}, "
f"Paper={result['strategy'][1]:.2f}, Scissors={result['strategy'][2]:.2f}")
print(f"Game value: {result['value']:.2f}")Output:
Optimal strategy: Rock=0.33, Paper=0.33, Scissors=0.33
Game value: 0.00
import gurddy
# Solve chicken-rabbit problem (鸡兔同笼)
model = gurddy.Model("ChickenRabbit", "LP")
chickens = model.addVar("chickens", low_bound=0, cat='Integer')
rabbits = model.addVar("rabbits", low_bound=0, cat='Integer')
# 35 heads, 94 legs
model.addConstraint(chickens + rabbits == 35) # heads constraint
model.addConstraint(chickens * 2 + rabbits * 4 == 94) # legs constraint
model.setObjective(chickens + rabbits, sense='Minimize')
solution = model.solve()
print(f"Chickens: {solution['chickens']}, Rabbits: {solution['rabbits']}")
# Output: Chickens: 23, Rabbits: 12Features
- 🧩 CSP Support: Define discrete variables, domains, and logical constraints.
- 📈 LP Support: Formulate linear objectives and inequality/equality constraints.
- 🎮 Minimax Support: Solve game theory problems and robust optimization under uncertainty.
- 🔬 SciPy Integration: Advanced nonlinear optimization, statistical modeling, and signal processing.
- 🔌 Extensible Solver Backend: Integrates with industry-standard solvers (e.g., Gurobi, CBC, or GLPK via compatible interfaces).
- 📦 Simple API: Intuitive syntax for rapid prototyping and experimentation.
- 🧪 Type-Hinted & Tested: Robust codebase with unit tests and clear documentation.
- Complete 9×9 Sudoku puzzle solver
- Demonstrates AllDifferent constraints
- Shows mask-based optimizations for small integer domains
- Run:
python examples/optimized_csp.py
- Place N queens on N×N chessboard without conflicts
- Demonstrates custom function constraints for diagonal checks
- Supports any board size (4×4, 8×8, etc.)
- Run:
python examples/n_queens.py
- Einstein's Zebra Puzzle: Complete 5-house logic puzzle solver
- Simple Logic Puzzles: 3-person pet/house assignments
- Advanced CSP Techniques: Function constraints, mask optimization
- Automatic Solver Selection: Uses optimized algorithms for best performance
- Run:
python examples/logic_puzzles.py
- Color graph vertices with minimum colors
- Includes sample graphs: Triangle, Square, Petersen, Wheel
- Finds chromatic number automatically
- Run:
python examples/graph_coloring.py
- Color geographical maps (Australia, USA, Europe)
- Demonstrates the Four Color Theorem
- Real-world adjacency relationships
- Run:
python examples/map_coloring.py
- Course Scheduling: University course timetabling
- Meeting Scheduling: Conference room allocation
- Resource Scheduling: Task-resource-time assignment
- Complex temporal and resource constraints
- Run:
python examples/scheduling.py
- Simple LP problem demonstration
- Shows PuLP integration
- Run:
python examples/optimized_lp.py
- Nonlinear Portfolio Optimization: Quadratic risk models with Sharpe ratio maximization
- Statistical Parameter Estimation: Constrained maximum likelihood estimation
- Signal Processing: FIR filter design with frequency response optimization
- Hybrid CSP-SciPy: Discrete facility location with continuous capacity optimization
- Numerical Integration: Distribution parameter fitting with quantile matching
- Run:
python examples/scipy_optimization.py
- Zero-Sum Games: Rock-Paper-Scissors, Matching Pennies, Battle of Sexes
- Portfolio Optimization: Minimize maximum loss across market scenarios
- Production Planning: Maximize minimum profit under demand uncertainty
- Security Games: Optimal resource allocation against adversaries
- Advertising Competition: Strategic budget allocation
- Mixed Strategy Equilibria: Find optimal randomized strategies
- Robust Decision Making: Handle worst-case scenarios
- Run:
python examples/minimax.py
# Navigate to examples directory
cd examples
# Run CSP examples
python n_queens.py
python graph_coloring.py
python map_coloring.py
python scheduling.py
python logic_puzzles.py
python optimized_csp.py
# Run LP examples
python optimized_lp.py
# Run Minimax examples
python minimax.py
# Run SciPy integration examples
python scipy_optimization.py8-Queens Solution:
+---+---+---+---+---+---+---+---+
| Q | | | | | | | |
+---+---+---+---+---+---+---+---+
| | | | | Q | | | |
+---+---+---+---+---+---+---+---+
...
Queen positions: (0,0), (1,4), (2,7), (3,5), (4,2), (5,6), (6,1), (7,3)
Triangle: Complete graph K3 (triangle)
Trying with 3 colors...
Chromatic number: 3
Vertex 0: Red
Vertex 1: Blue
Vertex 2: Green
Simple Logic Puzzle Solution:
Position 1: Alice has Cat in Green house
Position 2: Bob has Dog in Red house
Position 3: Carol has Fish in Blue house
Einstein's Zebra Puzzle Solution:
House 1: Norwegian - Green - Coffee - Snails - OldGold
House 2: Japanese - Blue - Water - Fox - Parliaments
House 3: English - Red - Milk - Horse - Chesterfields
House 4: Spanish - White - OrangeJuice - Dog - LuckyStrike
House 5: Ukrainian - Yellow - Tea - Zebra - Kools
ANSWERS:
Who owns the zebra? Ukrainian (House 5)
Who drinks water? Japanese (House 2)
Rock-Paper-Scissors Game:
Row Player (Maximizer) Strategy:
Rock: 0.3333
Paper: 0.3333
Scissors: 0.3333
Game Value: 0.0000
✓ Optimal strategy: Play each move with equal probability (1/3)
✓ Game value is 0 (fair game)
Robust Portfolio Optimization:
Optimal Allocation (minimize maximum loss):
Stock A: $12.28
Stock B: $0.00
Bond C: $87.72
Total: $100.00
Worst-case loss: $1.93
✓ Minimax strategy balances risk across all scenarios
- 🔬 Nonlinear Optimization: Advanced portfolio optimization with quadratic risk models
- 📊 Statistical Modeling: Constrained parameter estimation and distribution fitting
- 🎛️ Signal Processing: FIR filter design and frequency response optimization
- 🔄 Hybrid Approaches: Combine discrete CSP decisions with continuous SciPy optimization
- 🧮 Numerical Integration: Optimization objectives involving numerical integration
- ⚡ Seamless Integration: All SciPy functionality accessible through
import gurddyonly - 🎯 Unified API: No need to import scipy, numpy, or other dependencies directly
- 🎮 Game Theory Support: Solve zero-sum games and find Nash equilibria
- 🛡️ Robust Optimization: Minimize maximum loss or maximize minimum gain
- 📊 Mixed Strategies: Compute optimal probability distributions for competitive scenarios
- 💼 Real-World Applications: Portfolio optimization, security games, competitive strategy
- 🔧 Flexible API: Support for game matrices, scenario-based decisions, and custom constraints
- ⚡ Efficient Solving: Linear programming based implementation using PuLP
- ✅ Fixed CSP Solver: Resolved constraint propagation issues in tuple-based solver
- 🚀 Mask Optimization: Automatic detection and use of optimized algorithms for small integer domains
- 🧩 Complete Zebra Puzzle: Successfully solves Einstein's famous 5-house logic puzzle
- 📈 Performance Boost: Up to 10x faster solving for problems with domains 1-32
- 🔧 Robust Constraints: Improved handling of equality and adjacency constraints
- Automatic Solver Selection: Chooses optimal algorithm based on problem characteristics
- Enhanced Debugging: Better error messages and constraint conflict detection
- Flexible Domain Support: Works with both 0-based and 1-based integer domains
- Memory Efficient: Reduced memory usage through bit-mask operations
- Sudoku, N-Queens, Logic puzzles
- Key Techniques: AllDifferent constraints, custom functions
- Files:
optimized_csp.py,n_queens.py,logic_puzzles.py
- Graph coloring, map coloring
- Key Techniques: Binary constraints, chromatic number finding
- Files:
graph_coloring.py,map_coloring.py
- Course scheduling, resource allocation
- Key Techniques: Time-resource encoding, complex constraints
- Files:
scheduling.py
- Linear programming, mixed-integer programming
- Key Techniques: Objective optimization, constraint relaxation
- Files:
optimized_lp.py
- Zero-sum games, mixed strategies, Nash equilibria
- Portfolio optimization, worst-case planning
- Key Techniques: Minimax, maximin, robust optimization
- Files:
minimax.py
- Nonlinear portfolio optimization, statistical estimation
- Signal processing, hybrid discrete-continuous problems
- Key Techniques: SciPy integration, numerical optimization
- Files:
scipy_optimization.py
- 二十四点游戏 (24-point game), 鸡兔同笼 (chicken-rabbit problem)
- 数独 (Sudoku), N皇后 (N-Queens), 背包问题 (knapsack problem)
- Key Techniques: CSP modeling, linear programming, combinatorial optimization
- Files:
classic_problems.py
optimized_csp.py- Learn basic CSP concepts with Sudokun_queens.py- Understand custom constraintsgraph_coloring.py- Explore graph problems
map_coloring.py- Real-world constraint modelingscheduling.py- Multi-constraint problemsoptimized_lp.py- Introduction to LP
minimax.py- Game theory and robust optimizationlogic_puzzles.py- Complex CSP with advanced techniquesscipy_optimization.py- Nonlinear optimization and SciPy integration
classic_problems.py- 经典数学问题:二十四点、鸡兔同笼、数独等
# Custom constraint function
def my_constraint(val1, val2):
return val1 + val2 <= 10
# Add to model
model.addConstraint(FunctionConstraint(my_constraint, (var1, var2)))# For small integer domains (1-32), force mask optimization
solver = gurddy.CSPSolver(model)
solver.force_mask = True
solution = solver.solve()
# Automatic optimization (recommended)
# The solver automatically detects optimal algorithms
solution = model.solve()# Different domain types
model.addVar('binary_var', domain=[0, 1]) # Binary
model.addVar('small_int', domain=[1,2,3,4,5]) # Small integers
model.addVar('large_range', domain=list(range(100))) # Large rangeInstall the package from PyPI:
pip install gurddyFor LP/MIP examples you also need PuLP (the LP backend used by the built-in LPSolver):
pip install pulpFor SciPy integration examples you also need SciPy:
pip install scipyOr install with optional dependencies:
pip install gurddy[scipy] # Includes SciPyNote: Once installed, all SciPy functionality is accessible through import gurddy only - no need to import scipy directly!
If you publish optional extras you may use something like pip install gurddy[lp] if configured; otherwise install pulp separately as shown above.
After installing from PyPI you can import the public API from the gurddy package. The library exposes a small Model/Variable/Constraint API used by both CSP and LP solvers.
- Model: container for variables, constraints, and objective. Use
Model(...)and thenaddVar,addConstraint,setObjectiveor callsolve()which will dispatch to the appropriate solver based onproblem_type. - Variable: create with
Model.addVar(name, low_bound=None, up_bound=None, cat='Continuous', domain=None); for CSP usedomain(tuple of ints), for LP use numeric bounds and category ('Continuous', 'Integer', 'Binary'). - Expression: arithmetic expressions are created implicitly by operations on
Variableobjects or explicitly viaExpression(variable_or_value). - Constraint types:
LinearConstraint,AllDifferentConstraint,FunctionConstraint.
Gurddy can solve a wide variety of Constraint Satisfaction Problems. Here are some examples:
from gurddy.model import Model
from gurddy.constraint import AllDifferentConstraint
# Build CSP model
model = Model('simple_csp', problem_type='CSP')
# Add discrete variables with domains (1..9)
model.addVar('A1', domain=[1,2,3,4,5,6,7,8,9])
model.addVar('A2', domain=[1,2,3,4,5,6,7,8,9])
# Add AllDifferent constraint across a group
model.addConstraint(AllDifferentConstraint([model.variables['A1'], model.variables['A2']]))
# Solve (uses internal CSPSolver)
solution = model.solve()
print(solution) # dict of variable name -> assigned int, or None if unsatisfiablefrom gurddy.model import Model
from gurddy.constraint import AllDifferentConstraint, FunctionConstraint
def solve_n_queens(n=8):
model = Model(f"{n}-Queens", "CSP")
# Variables: one for each row, value represents column position
queens = {}
for row in range(n):
var_name = f"queen_row_{row}"
queens[var_name] = model.addVar(var_name, domain=list(range(n)))
# All queens in different columns
model.addConstraint(AllDifferentConstraint(list(queens.values())))
# No two queens on same diagonal
def not_on_same_diagonal(col1, col2, row_diff):
return abs(col1 - col2) != row_diff
queen_vars = list(queens.values())
for i in range(n):
for j in range(i + 1, n):
row_diff = j - i
constraint_func = lambda c1, c2, rd=row_diff: not_on_same_diagonal(c1, c2, rd)
model.addConstraint(FunctionConstraint(constraint_func, (queen_vars[i], queen_vars[j])))
return model.solve()
# Solve 8-Queens
solution = solve_n_queens(8)def solve_graph_coloring(edges, num_vertices, max_colors=4):
model = Model("GraphColoring", "CSP")
# Variables: one for each vertex
vertices = {}
for v in range(num_vertices):
vertices[f"vertex_{v}"] = model.addVar(f"vertex_{v}", domain=list(range(max_colors)))
# Adjacent vertices must have different colors
def different_colors(color1, color2):
return color1 != color2
for v1, v2 in edges:
var1 = vertices[f"vertex_{v1}"]
var2 = vertices[f"vertex_{v2}"]
model.addConstraint(FunctionConstraint(different_colors, (var1, var2)))
return model.solve()
# Example: Color a triangle graph
edges = [(0, 1), (1, 2), (2, 0)]
solution = solve_graph_coloring(edges, 3, 3)Gurddy's Minimax solver handles game theory and robust optimization problems:
- Zero-Sum Games: Two-player games where one player's gain equals the other's loss
- Mixed Strategy Equilibria: Find optimal randomized strategies using linear programming
- Minimax Decision Problems: Minimize maximum loss across uncertain scenarios
- Maximin Decision Problems: Maximize minimum gain under worst-case conditions
- Robust Optimization: Make decisions that perform well in all scenarios
- Game Theory: Rock-Paper-Scissors, Matching Pennies, Battle of Sexes
- Portfolio Optimization: Asset allocation minimizing worst-case loss
- Production Planning: Robust production under demand uncertainty
- Security Games: Resource allocation for defense against adversaries
- Competitive Strategy: Advertising budgets, pricing strategies
- Risk Management: Worst-case scenario planning
- Linear Programming Based: Uses PuLP for efficient solving
- Mixed Strategies: Computes optimal probability distributions
- Game Value Computation: Determines equilibrium payoffs
- Scenario Analysis: Handles multiple uncertain scenarios
- Budget Constraints: Supports resource allocation constraints
Gurddy's CSP solver can handle a wide variety of constraint satisfaction problems:
- AllDifferentConstraint: Global constraint ensuring all variables take distinct values
- FunctionConstraint: Custom binary constraints defined by Python functions
- LinearConstraint: Equality and inequality constraints (var == value, var <= value, etc.)
- Combinatorial Puzzles: Sudoku, N-Queens, Logic puzzles
- Graph Problems: Graph coloring, map coloring
- Scheduling: Resource allocation, time slot assignment
- Assignment Problems: Matching, allocation with constraints
- Mask-based AC-3: Optimized arc consistency for small integer domains (1-32)
- AllDifferent Propagation: Uses maximum matching algorithms for global constraints
- Smart Variable Ordering: Minimum Remaining Values (MRV) heuristic
- Value Ordering: Least Constraining Value (LCV) heuristic
- Automatic Optimization: CSPSolver automatically detects when to use mask optimizations
- Precomputed Support Masks: Cached constraint support for faster propagation
- Bit-level Operations: Memory-efficient domain representation and manipulation
- Intelligent Backtracking: Enhanced constraint propagation during search
- Backtracking with Inference: AC-3 constraint propagation during search
- Multiple Constraint Types: Mix different constraint types in the same problem
- Extensible: Easy to add custom constraint types and heuristics
The LP solver wraps PuLP. A basic LP/MIP example:
from gurddy.model import Model
# Build an LP model
m = Model('demo', problem_type='LP')
# addVar(name, low_bound=None, up_bound=None, cat='Continuous')
x = m.addVar('x', low_bound=0, cat='Continuous')
y = m.addVar('y', low_bound=0, cat='Integer')
# Objective: maximize 3*x + 5*y
m.setObjective(x * 3 + y * 5, sense='Maximize')
# Add linear constraints (using Expression objects implicitly via Variable operations)
m.addConstraint((x * 2 + y * 1) <= 10)
# Solve (uses LPSolver which wraps PuLP)
sol = m.solve()
print(sol) # dict var name -> numeric value or NoneThe Minimax solver handles game theory and robust optimization problems:
from gurddy.solver.minimax_solver import MinimaxSolver
# Rock-Paper-Scissors payoff matrix
payoff_matrix = [
[0, -1, 1], # Rock vs [Rock, Paper, Scissors]
[1, 0, -1], # Paper vs [Rock, Paper, Scissors]
[-1, 1, 0] # Scissors vs [Rock, Paper, Scissors]
]
solver = MinimaxSolver(None)
# Find optimal mixed strategy for row player
result = solver.solve_game_matrix(payoff_matrix, player="row")
print(f"Optimal strategy: {result['strategy']}") # [0.333, 0.333, 0.333]
print(f"Game value: {result['value']}") # 0.0 (fair game)from gurddy.solver.minimax_solver import MinimaxSolver
# Portfolio optimization: minimize maximum loss across scenarios
scenarios = [
{"StockA": -0.2, "StockB": -0.1, "BondC": 0.05}, # Bull market
{"StockA": 0.3, "StockB": 0.2, "BondC": -0.02}, # Bear market
{"StockA": 0.05, "StockB": 0.03, "BondC": -0.01} # Stable market
]
solver = MinimaxSolver(None)
result = solver.solve_minimax_decision(scenarios, ["StockA", "StockB", "BondC"])
print(f"Optimal allocation: {result['decision']}")
print(f"Worst-case loss: {result['max_loss']}")# Production planning: maximize minimum profit
scenarios = [
{"ProductX": -50, "ProductY": -40}, # High demand (negative for maximin)
{"ProductX": -30, "ProductY": -35}, # Medium demand
{"ProductX": -20, "ProductY": -25} # Low demand
]
solver = MinimaxSolver(None)
result = solver.solve_maximin_decision(scenarios, ["ProductX", "ProductY"])
print(f"Optimal production: {result['decision']}")
print(f"Guaranteed minimum profit: {result['min_gain']}")Gurddy comes with comprehensive examples demonstrating various problem types:
examples/optimized_csp.py- Complete Sudoku solver with optimizationsexamples/n_queens.py- N-Queens problem for any board sizeexamples/graph_coloring.py- Graph coloring with various test graphsexamples/map_coloring.py- Map coloring (Australia, USA, Europe)examples/scheduling.py- Course and meeting scheduling problemsexamples/logic_puzzles.py- Logic puzzles including Einstein's Zebra puzzle
examples/optimized_lp.py- LP relaxation vs MIP, timings, sensitivity analysis
examples/minimax.py- Game theory, robust optimization, security games
examples/scipy_optimization.py- Nonlinear optimization, statistical modeling, signal processing
examples/classic_problems.py- 二十四点游戏, 鸡兔同笼, 数独, N皇后, 背包问题examples/simple_classic_problems.py- 简化版二十四点和鸡兔同笼问题
# CSP Examples
python examples/n_queens.py # N-Queens problem
python examples/graph_coloring.py # Graph coloring
python examples/map_coloring.py # Map coloring
python examples/scheduling.py # Scheduling problems
python examples/logic_puzzles.py # Logic puzzles
python examples/optimized_csp.py # Sudoku solver
# LP Examples
python examples/optimized_lp.py # Production planning
# Minimax Examples
python examples/minimax.py # Game theory & robust optimization
# SciPy Integration Examples
python examples/scipy_optimization.py # Nonlinear optimization & SciPy integration
# Classic Problems Examples
python examples/classic_problems.py # 经典数学问题合集# Complete 9x9 Sudoku with given clues
model = Model("Sudoku", "CSP")
# Create 81 variables for 9x9 grid
vars_dict = {}
for row in range(1, 10):
for col in range(1, 10):
var_name = f"cell_{row}_{col}"
vars_dict[var_name] = model.addVar(var_name, domain=[1,2,3,4,5,6,7,8,9])
# Add AllDifferent constraints for rows, columns, and 3x3 boxes
# ... (see examples/optimized_csp.py for complete implementation)# The famous logic puzzle: 5 houses, 5 attributes each
# Who owns the zebra and who drinks water?
model = gurddy.Model("ZebraPuzzle", "CSP")
# Variables for each attribute (colors, nationalities, drinks, pets, cigarettes)
# Each assigned to houses 1-5 (optimized for mask-based solving)
houses = list(range(1, 6))
colors = ['Red', 'Green', 'White', 'Yellow', 'Blue']
nationalities = ['English', 'Spanish', 'Ukrainian', 'Norwegian', 'Japanese']
# ... create variables for each attribute
# AllDifferent constraints ensure each attribute appears exactly once
model.addConstraint(gurddy.AllDifferentConstraint(color_vars))
model.addConstraint(gurddy.AllDifferentConstraint(nationality_vars))
# ... add constraints for all attributes
# Logic constraints from the puzzle clues
def same_house(house1, house2):
return house1 == house2
# "The English person lives in the red house"
model.addConstraint(gurddy.FunctionConstraint(
same_house, (english_var, red_var)
))
# Force mask optimization for best performance
solver = gurddy.CSPSolver(model)
solver.force_mask = True
solution = solver.solve()
# Result: Ukrainian owns the zebra, Japanese drinks water# Schedule university courses avoiding conflicts
model = Model("CourseScheduling", "CSP")
courses = ['Math101', 'Physics101', 'Chemistry101', 'Biology101', 'English101']
time_slots = list(range(20)) # 5 days × 4 slots
# Variables and constraints for scheduling
# ... (see examples/scheduling.py for complete implementation)- CSP Optimizations: The CSP solver includes precomputed support masks, mask-based AC-3, and AllDifferent matching propagation for enhanced performance on small integer domains.
- LP Backend: Uses PuLP by default. Can be extended to support other solvers (ORTOOLS, Gurobi) by modifying
src/gurddy/solver/lp_solver.py. - Extensibility: Easy to add new constraint types by inheriting from the
Constraintbase class. - Memory Efficiency: Mask-based operations reduce memory usage for problems with small domains.
Run unit tests with pytest:
python -m pytestPRs welcome. If you add a new solver backend, please include configuration and a small example demonstrating usage.
This section lists the most commonly used classes and functions with signatures and short descriptions.
Model
-
Model(name: str = "Model", problem_type: str = "LP")
- Container for variables, constraints, objective and solver selection.
- Attributes: variables: Dict[str, Variable], constraints: List[Constraint], objective: Optional[Expression], sense: str
-
addVar(name: str, low_bound: Optional[float] = None, up_bound: Optional[float] = None, cat: str = 'Continuous', domain: Optional[list] = None) -> Variable
- Create and register a Variable. For CSP use
domain(list/tuple of ints). For LP use numeric bounds andcat.
- Create and register a Variable. For CSP use
-
addVars(names: List[str], **kwargs) -> Dict[str, Variable]
- Convenience to create multiple variables with the same kwargs.
-
addConstraint(constraint: Constraint, name: Optional[str] = None) -> None
- Register a Constraint object (LinearConstraint, AllDifferentConstraint, FunctionConstraint).
-
setObjective(expr: Expression, sense: str = "Maximize") -> None
- Set the objective expression and sense for LP problems.
-
solve() -> Optional[Dict[str, Union[int, float]]]
- Dispatch to the appropriate solver (CSPSolver or LPSolver) and return a mapping from variable name to value, or None if unsatisfiable/no optimal found.
Variable
- Variable(name: str, low_bound: Optional[float] = None, up_bound: Optional[float] = None,
cat: str = 'Continuous', domain: Optional[list] = None)
- Represents a decision variable. For CSP set
domain(discrete values). For LP set numeric bounds andcatin {'Continuous','Integer','Binary'}. - Supports arithmetic operator overloads to build
Expressionobjects (e.g.,x * 3 + y).
- Represents a decision variable. For CSP set
Expression
- Expression(term: Union[Variable, int, float, Expression])
- Arithmetic expression type used to build linear objectives and constraints.
- Operators: +, -, *, / with scalars; comparisons (==, <=, >=, <, >) produce
LinearConstraintinstances.
Constraint types
-
LinearConstraint(expr: Expression, sense: str)
- General linear constraint wrapper (sense in {'<=','>=','==', '!='}).
-
AllDifferentConstraint(vars: List[Variable])
- Global constraint enforcing all variables in the list take pairwise distinct values (used primarily for CSPs).
-
FunctionConstraint(func: Callable[[int,int], bool], vars: Tuple[Variable, ...])
- Custom binary (or n-ary) constraint defined by a Python callable.
Solvers
-
class CSPSolver
- CSPSolver(model: Model)
- Attributes: mask_threshold: int (domain size under which mask optimization is used), force_mask: bool
- Methods: solve() -> Optional[Dict[str, int]] (returns assignment mapping or None)
-
class LPSolver
- LPSolver(model: Model)
- Methods: solve() -> Optional[Dict[str, float]] (returns variable values mapping or None). Uses PuLP by default; requires
pulpinstalled.
-
class MinimaxSolver ✨ NEW
- MinimaxSolver(model: Model)
- Methods:
- solve_game_matrix(payoff_matrix: List[List[float]], player: str) -> Dict (solves zero-sum games)
- solve_minimax_decision(scenarios: List[Dict], variables: List[str]) -> Dict (minimize maximum loss)
- solve_maximin_decision(scenarios: List[Dict], variables: List[str]) -> Dict (maximize minimum gain)
- solve() -> Optional[Dict[str, float]] (generic model-based solving)
SciPy Integration
Gurddy seamlessly integrates SciPy functionality through a unified API. No need to import scipy directly!
Key Features:
- Hybrid Optimization: Combine discrete CSP decisions with continuous SciPy optimization
- Nonlinear Portfolio Optimization: Maximize Sharpe ratio with quadratic risk models
- Statistical Modeling: Constrained parameter estimation and distribution fitting
- Signal Processing: FIR filter design and frequency response optimization
- Numerical Integration: Advanced optimization with numerical integration
Simple Usage Examples:
import gurddy # Only import needed!
import numpy as np
# Portfolio optimization
returns = np.array([0.12, 0.15, 0.10])
cov_matrix = np.array([[0.04, 0.01, 0.02], [0.01, 0.05, 0.01], [0.02, 0.01, 0.03]])
result = gurddy.optimize_portfolio(returns, cov_matrix)
# Distribution fitting
data = np.random.gamma(2.0, 1.5, size=100)
result = gurddy.fit_distribution(data, distribution='gamma')
# Filter design
result = gurddy.design_filter(num_taps=21, cutoff_freq=100, sampling_freq=1000)
# Nonlinear optimization
result = gurddy.solve_nonlinear(lambda x: (x[0]-1)**2 + (x[1]-2)**2, x0=[0, 0])Hybrid CSP-SciPy Pattern:
import gurddy
# Step 1: Discrete decisions with CSP
model = gurddy.Model("Facility", "CSP")
facilities = [model.addVar(f"f_{i}", domain=[0, 1]) for i in range(3)]
model.addConstraint(gurddy.FunctionConstraint(lambda *f: sum(f) <= 2, facilities))
discrete_solution = model.solve()
# Step 2: Continuous optimization with SciPy integration
def continuous_objective(x_continuous, discrete_solution):
return sum(x_continuous[i] * discrete_solution[f"f_{i}"] for i in range(len(x_continuous)))
solver = gurddy.ScipySolver()
result = solver.solve_hybrid_problem(model, continuous_objective, ["cap_0", "cap_1", "cap_2"])Notes
- The API intentionally keeps model construction separate from solver execution. Use
Model.solve()for convenience or instantiate solver classes directly for advanced control (e.g., changeCSPSolver.force_mask). - For more examples see
examples/optimized_csp.py,examples/optimized_lp.py,examples/minimax.py.