Constraints Module
The constraints module provides comprehensive constraint definition capabilities for optimization problems. It includes linear constraints, goal programming constraints, special non-linear constraints, and mathematical expressions.
Constraint Classes
Linear Constraints
- class constraints.OXConstraint(id: ~uuid.UUID = <factory>, class_name: str = '', expression: ~constraints.OXpression.OXpression = <factory>, relational_operator: ~constraints.OXConstraint.RelationalOperators = RelationalOperators.EQUAL, rhs: float | int = 0, name: str = '', active_scenario: str = 'Default', scenarios: dict[str, dict[str, ~typing.Any]] = <factory>)[source]
Bases:
OXObjectA constraint in an optimization problem with scenario support.
A constraint represents a relationship between an expression and a value, such as “2x + 3y <= 10”. This class supports multiple scenarios, allowing different constraint parameters (RHS values, names, operators) to be defined for different optimization scenarios.
The scenario system enables sensitivity analysis and what-if modeling by maintaining multiple constraint configurations within the same constraint object.
- expression
The left-hand side of the constraint.
- Type:
- relational_operator
The operator (>, >=, =, <, <=).
- Type:
- scenarios
Dictionary mapping scenario names to dictionaries of attribute values for that scenario.
Examples
Basic constraint creation:
>>> from constraints.OXpression import OXpression >>> expr = OXpression(variables=[x.id, y.id], weights=[2, 3]) >>> constraint = OXConstraint( ... expression=expr, ... relational_operator=RelationalOperators.LESS_THAN_EQUAL, ... rhs=10, ... name="Capacity constraint" ... )
Scenario-based constraint management:
>>> # Create constraint with base values >>> constraint = OXConstraint( ... expression=expr, ... relational_operator=RelationalOperators.LESS_THAN_EQUAL, ... rhs=100, ... name="Production capacity" ... ) >>> >>> # Create scenarios with different RHS values >>> constraint.create_scenario("High_Capacity", rhs=150, name="High capacity scenario") >>> constraint.create_scenario("Low_Capacity", rhs=80, name="Reduced capacity scenario") >>> >>> # Switch between scenarios >>> print(constraint.rhs) # 100 (Default scenario) >>> >>> constraint.active_scenario = "High_Capacity" >>> print(constraint.rhs) # 150 >>> print(constraint.name) # "High capacity scenario" >>> >>> constraint.active_scenario = "Low_Capacity" >>> print(constraint.rhs) # 80
- expression: OXpression
- relational_operator: RelationalOperators = '='
- __getattribute__(item)[source]
Custom attribute access that checks the active scenario first.
When an attribute is accessed, this method first checks if it exists in the active scenario, and if not, falls back to the object’s own attribute. This enables transparent scenario switching for constraint parameters.
- Parameters:
item (str) – The name of the attribute to access.
- Returns:
- The value of the attribute in the active scenario, or the
object’s own attribute if not found in the active scenario.
- Return type:
Any
Examples
>>> constraint = OXConstraint(rhs=100) >>> constraint.create_scenario("High_RHS", rhs=150) >>> print(constraint.rhs) # 100 (Default) >>> constraint.active_scenario = "High_RHS" >>> print(constraint.rhs) # 150 (from scenario)
- create_scenario(scenario_name: str, **kwargs)[source]
Create a new scenario with the specified constraint attribute values.
If the “Default” scenario doesn’t exist yet, it is created first, capturing the constraint’s current attribute values. This enables systematic scenario-based analysis while preserving the original constraint configuration.
- Parameters:
scenario_name (str) – The name of the new scenario.
**kwargs – Constraint attribute-value pairs for the new scenario. Common attributes include: - rhs (float | int): Right-hand side value - name (str): Constraint name for this scenario - relational_operator (RelationalOperators): Constraint operator
- Raises:
OXception – If an attribute in kwargs doesn’t exist in the constraint object.
Examples
Creating RHS scenarios for sensitivity analysis:
>>> constraint = OXConstraint( ... expression=expr, ... relational_operator=RelationalOperators.LESS_THAN_EQUAL, ... rhs=100, ... name="Base capacity" ... ) >>> >>> # Create scenarios with different RHS values >>> constraint.create_scenario("High_Demand", rhs=150, name="Peak capacity") >>> constraint.create_scenario("Low_Demand", rhs=75, name="Reduced capacity") >>> constraint.create_scenario("Critical", rhs=200, name="Emergency capacity") >>> >>> # Switch scenarios and access values >>> constraint.active_scenario = "High_Demand" >>> print(f"RHS: {constraint.rhs}, Name: {constraint.name}") >>> # Output: RHS: 150, Name: Peak capacity
Creating operator scenarios for constraint type analysis:
>>> constraint.create_scenario("Equality", ... relational_operator=RelationalOperators.EQUAL, ... name="Exact capacity requirement" ... ) >>> constraint.create_scenario("Lower_Bound", ... relational_operator=RelationalOperators.GREATER_THAN_EQUAL, ... name="Minimum capacity requirement" ... )
- reverse()[source]
Reverse the relational operator of the constraint.
This method changes the relational operator to its opposite: - GREATER_THAN becomes LESS_THAN - GREATER_THAN_EQUAL becomes LESS_THAN_EQUAL - EQUAL remains EQUAL - LESS_THAN becomes GREATER_THAN - LESS_THAN_EQUAL becomes GREATER_THAN_EQUAL
- Returns:
A new constraint with the reversed operator.
- Return type:
- property rhs_numerator
Get the numerator of the right-hand side as a fraction.
- Returns:
The numerator of the right-hand side.
- Return type:
- property rhs_denominator
Get the denominator of the right-hand side as a fraction.
- Returns:
The denominator of the right-hand side.
- Return type:
- to_goal(upper_bound: int | float | Fraction = 100) OXGoalConstraint[source]
Convert this constraint to a goal constraint for goal programming.
The conversion sets the relational operator to EQUAL and sets the desired deviation variables based on the original operator.
- Returns:
A new goal constraint based on this constraint.
- Return type:
See also
- __init__(id: ~uuid.UUID = <factory>, class_name: str = '', expression: ~constraints.OXpression.OXpression = <factory>, relational_operator: ~constraints.OXConstraint.RelationalOperators = RelationalOperators.EQUAL, rhs: float | int = 0, name: str = '', active_scenario: str = 'Default', scenarios: dict[str, dict[str, ~typing.Any]] = <factory>) None
- class constraints.OXGoalConstraint(id: ~uuid.UUID = <factory>, class_name: str = '', expression: ~constraints.OXpression.OXpression = <factory>, relational_operator: ~constraints.OXConstraint.RelationalOperators = RelationalOperators.EQUAL, rhs: float | int = 0, name: str = '', active_scenario: str = 'Default', scenarios: dict[str, dict[str, ~typing.Any]] = <factory>, positive_deviation_variable: ~variables.OXDeviationVar.OXDeviationVar = <factory>, negative_deviation_variable: ~variables.OXDeviationVar.OXDeviationVar = <factory>)[source]
Bases:
OXConstraintA goal constraint for goal programming.
A goal constraint extends a regular constraint by adding deviation variables that measure how much the constraint is violated. In goal programming, the objective is typically to minimize undesired deviations.
- positive_deviation_variable
The variable representing positive deviation from the goal.
- Type:
- negative_deviation_variable
The variable representing negative deviation from the goal.
- Type:
Examples
>>> goal = constraint.to_goal() >>> print(goal.positive_deviation_variable.desired) False >>> print(goal.negative_deviation_variable.desired) True
- positive_deviation_variable: OXDeviationVar
- negative_deviation_variable: OXDeviationVar
- property desired_variables: list[OXDeviationVar]
Get the list of desired deviation variables.
- Returns:
A list of deviation variables marked as desired.
- Return type:
- property undesired_variables: list[OXDeviationVar]
Get the list of undesired deviation variables.
- Returns:
A list of deviation variables not marked as desired.
- Return type:
- __init__(id: ~uuid.UUID = <factory>, class_name: str = '', expression: ~constraints.OXpression.OXpression = <factory>, relational_operator: ~constraints.OXConstraint.RelationalOperators = RelationalOperators.EQUAL, rhs: float | int = 0, name: str = '', active_scenario: str = 'Default', scenarios: dict[str, dict[str, ~typing.Any]] = <factory>, positive_deviation_variable: ~variables.OXDeviationVar.OXDeviationVar = <factory>, negative_deviation_variable: ~variables.OXDeviationVar.OXDeviationVar = <factory>) None
Constraint Collections
- class constraints.OXConstraintSet(id: ~uuid.UUID = <factory>, class_name: str = '', objects: list[~base.OXObject.OXObject] = <factory>)[source]
Bases:
OXObjectPotA specialized container for managing OXConstraint objects.
OXConstraintSet extends OXObjectPot to provide a type-safe container specifically designed for managing collections of OXConstraint objects. It ensures that only OXConstraint instances can be added or removed from the set, and provides specialized query functionality for finding constraints based on their metadata.
This class is particularly useful for organizing constraints in optimization problems by category, type, or other metadata attributes stored in the constraint’s related_data dictionary.
- Inherits all attributes from OXObjectPot
- - objects
List of constraint objects in the set
- Type:
list[OXObject]
- - id
Unique identifier for the constraint set
- Type:
- - name
Human-readable name for the constraint set
- Type:
- query(**kwargs)
Find constraints by metadata attributes
- Raises:
OXception – When attempting to add/remove non-OXConstraint objects
Examples
>>> # Create a constraint set for capacity constraints >>> capacity_set = OXConstraintSet(name="Capacity Constraints") >>> >>> # Add constraints with metadata >>> for i, constraint in enumerate(capacity_constraints): ... constraint.related_data["category"] = "capacity" ... constraint.related_data["priority"] = "high" ... capacity_set.add_object(constraint) >>> >>> # Query by metadata >>> high_priority = capacity_set.query(priority="high") >>> capacity_constraints = capacity_set.query(category="capacity") >>> >>> # Check set size >>> print(f"Total constraints: {len(capacity_set)}") >>> >>> # Iterate through constraints >>> for constraint in capacity_set: ... print(f"Constraint: {constraint.name}")
- add_object(obj: OXObject)[source]
Add an OXConstraint object to the constraint set.
This method provides type-safe addition of constraint objects to the set. Only OXConstraint instances are allowed to be added to maintain the integrity of the constraint set.
- Parameters:
obj (OXObject) – The constraint object to add. Must be an instance of OXConstraint.
- Raises:
OXception – If the object is not an instance of OXConstraint.
Examples
>>> constraint_set = OXConstraintSet() >>> constraint = OXConstraint(...) >>> constraint_set.add_object(constraint) >>> print(len(constraint_set)) # 1
- remove_object(obj: OXObject)[source]
Remove an OXConstraint object from the constraint set.
This method provides type-safe removal of constraint objects from the set. Only OXConstraint instances are allowed to be removed to maintain the integrity of the constraint set.
- Parameters:
obj (OXObject) – The constraint object to remove. Must be an instance of OXConstraint.
- Raises:
OXception – If the object is not an instance of OXConstraint.
Examples
>>> constraint_set = OXConstraintSet() >>> constraint = OXConstraint(...) >>> constraint_set.add_object(constraint) >>> constraint_set.remove_object(constraint) >>> print(len(constraint_set)) # 0
Mathematical Expressions
- class constraints.OXpression(id: ~uuid.UUID = <factory>, class_name: str = '', variables: list[~uuid.UUID] = <factory>, weights: list[float | int | ~fractions.Fraction] = <factory>)[source]
Bases:
OXObjectMathematical expression representing linear combinations of optimization variables.
OXpression is a fundamental component of the OptiX optimization framework that represents linear mathematical expressions in the form: c₁x₁ + c₂x₂ + … + cₙxₙ, where cᵢ are coefficients (weights) and xᵢ are decision variables.
This class is designed to handle expressions used in both constraint definitions and objective functions within optimization problems. It provides precise arithmetic handling through fraction-based calculations to avoid floating-point precision errors that can occur in mathematical optimization.
The class maintains variable references using UUIDs rather than direct object references, enabling serialization, persistence, and cross-system compatibility. This design pattern supports distributed optimization scenarios and model persistence.
- Key Features:
UUID-based variable referencing for serialization safety
Automatic conversion between floating-point and integer coefficient representations
Fraction-based arithmetic for mathematical precision
Iterator support for easy traversal of variable-coefficient pairs
Integration with OptiX constraint and objective function systems
Support for multiple numeric types (int, float, Fraction, Decimal)
- variables
Ordered list of variable UUIDs that participate in this expression. The order corresponds to the order of coefficients in the weights list.
- Type:
list[UUID]
- weights
Ordered list of coefficients (weights) for each variable. Supports mixed numeric types with automatic conversion.
- Type Parameters:
The class inherits from OXObject, providing UUID-based identity and serialization capabilities.
Example
Basic usage of OXpression for creating mathematical expressions:
from uuid import UUID from constraints import OXpression from variables import OXVariable # Create some optimization variables x = OXVariable(name="production_x", lower_bound=0, upper_bound=100) y = OXVariable(name="production_y", lower_bound=0, upper_bound=50) z = OXVariable(name="production_z", lower_bound=0) # Create expression: 2.5x + 1.75y + 3z (production cost function) cost_expr = OXpression( variables=[x.id, y.id, z.id], weights=[2.5, 1.75, 3.0] ) # Access expression properties print(f"Variables in expression: {cost_expr.number_of_variables}") # 3 print(f"Integer weights: {cost_expr.integer_weights}") # [10, 7, 12] print(f"Common denominator: {cost_expr.integer_denominator}") # 4 # Iterate through variable-coefficient pairs for var_uuid, coefficient in cost_expr: print(f"Variable {var_uuid}: coefficient = {coefficient}") # Example with mixed coefficient types mixed_expr = OXpression( variables=[x.id, y.id], weights=[Fraction(1, 3), 0.75] # Mixed Fraction and float )
Note
Variables are referenced by UUID to support serialization and persistence
The weights list must have the same length as the variables list
Automatic fraction conversion ensures mathematical precision for optimization solvers
The class supports empty expressions (no variables/weights) for initialization
All weight types are converted to fractions internally for consistent arithmetic
Warning
Ensure that the variables and weights lists maintain corresponding order and equal length. Mismatched lengths will result in undefined behavior during iteration and calculations.
See also
OXVariable: Decision variables used in expressions OXConstraint: Constraints that use OXpression for left-hand sides calculate_fraction: Internal function for precise fraction conversion get_integer_numerator_and_denominators: Utility for solver-compatible representations
- property number_of_variables: int
Get the total count of variables participating in this mathematical expression.
This property provides a convenient way to determine the dimensionality of the linear expression, which is useful for validation, debugging, and solver setup. The count represents the number of decision variables that have non-zero coefficients in this expression.
- Returns:
- The total number of variables in the expression. Returns 0 for empty
expressions (expressions with no variables or coefficients).
- Return type:
Note
The count is based on the length of the variables list
Empty expressions return 0, which is valid for initialization scenarios
The count should match the length of the weights list for consistency
Example
# Create expression with three variables expr = OXpression( variables=[var1_id, var2_id, var3_id], weights=[1.0, 2.5, 0.75] ) print(expr.number_of_variables) # Output: 3 # Empty expression empty_expr = OXpression() print(empty_expr.number_of_variables) # Output: 0
- property integer_weights: list[int]
Convert expression coefficients to integer representations with common denominator.
This property transforms all variable coefficients from their original numeric types (float, int, Fraction, Decimal) into integer values by finding a common denominator and scaling appropriately. This conversion is essential for optimization solvers that require integer coefficients while maintaining mathematical precision.
The conversion process: 1. Converts each weight to its exact fractional representation 2. Finds the least common multiple (LCM) of all denominators 3. Scales all numerators to use the common denominator 4. Returns the scaled integer numerators
- Returns:
- Integer representations of all coefficients, scaled by the common
denominator. The order corresponds to the variables list order. Returns empty list if no weights are present.
- Return type:
Note
Maintains exact mathematical precision through fraction arithmetic
The integer values represent numerators when using the common denominator
Use integer_denominator property to get the corresponding denominator
Essential for solvers like CPLEX or Gurobi that prefer integer coefficients
Example
# Expression with decimal coefficients expr = OXpression( variables=[x_id, y_id, z_id], weights=[0.5, 1.25, 2.0] ) print(expr.integer_weights) # [2, 5, 8] print(expr.integer_denominator) # 4 # Verification: 2/4 = 0.5, 5/4 = 1.25, 8/4 = 2.0
See also
integer_denominator: Get the common denominator for these integer weights get_integer_numerator_and_denominators: The underlying conversion function
- property integer_denominator: int
Get the common denominator used for integer weight representation.
This property returns the least common multiple (LCM) of all denominators in the fractional representations of the expression coefficients. When combined with the integer_weights property, it allows for exact reconstruction of the original coefficient values while providing integer representations suitable for optimization solvers.
The denominator represents the scaling factor applied to convert floating-point or fractional coefficients into integers. This approach maintains mathematical precision and avoids floating-point arithmetic errors in optimization calculations.
- Returns:
- The common denominator for all coefficients in the expression.
Returns 1 if all weights are integers, or the LCM of all fractional denominators if floating-point weights are present. Returns 1 for empty expressions.
- Return type:
Note
Always returns a positive integer value
The LCM approach ensures the smallest possible common denominator
Combined with integer_weights, provides exact coefficient representation
Essential for maintaining precision in constraint and objective definitions
Example
# Expression with fractional coefficients expr = OXpression( variables=[x_id, y_id, z_id], weights=[0.5, 0.25, 1.75] # 1/2, 1/4, 7/4 ) print(expr.integer_denominator) # 4 (LCM of 2, 4, 4) print(expr.integer_weights) # [2, 1, 7] # Verification: 2/4 = 0.5, 1/4 = 0.25, 7/4 = 1.75 # Expression with integer coefficients int_expr = OXpression( variables=[x_id, y_id], weights=[2, 3] ) print(int_expr.integer_denominator) # 1
See also
integer_weights: Get the integer numerators for these coefficients get_integer_numerator_and_denominators: The underlying conversion function
- __iter__()[source]
Enable iteration over variable-coefficient pairs in the mathematical expression.
This method implements the iterator protocol, allowing the OXpression object to be used in for-loops and other iteration contexts. It yields tuples of (variable_uuid, coefficient) pairs, maintaining the order defined in the variables and weights lists.
The iterator is particularly useful for: - Traversing expression terms for solver setup - Debugging and validation of expression contents - Serialization and persistence operations - Constructing string representations of expressions
- Yields:
tuple[UUID, float | int | Fraction] –
- Each iteration yields a tuple containing:
UUID: The unique identifier of the variable
float | int | Fraction: The coefficient (weight) for that variable
Note
Iteration order matches the order of variables and weights lists
Empty expressions will not yield any items
The yielded coefficients maintain their original numeric types
Supports standard Python iteration protocols (for loops, list comprehension, etc.)
Example
from uuid import uuid4 from fractions import Fraction # Create expression with mixed coefficient types expr = OXpression( variables=[uuid4(), uuid4(), uuid4()], weights=[2.5, 3, Fraction(1, 2)] ) # Iterate over variable-coefficient pairs for var_uuid, coefficient in expr: print(f"Variable {var_uuid}: coefficient = {coefficient}") # Use in list comprehension terms = [(str(var_id)[:8], coef) for var_id, coef in expr] print(f"Expression terms: {terms}") # Convert to dictionary expr_dict = dict(expr) # Count terms term_count = len(list(expr))
- Raises:
ValueError – If variables and weights lists have different lengths (this would indicate a malformed expression)
- constraints.get_integer_numerator_and_denominators(numbers: list[float | int]) tuple[int, list[int]][source]
Convert a list of floating-point or integer weights to integer representations.
This function takes a collection of numeric values (which may include floating-point numbers and integers) and converts them to exact integer representations by finding a common denominator. This is essential for optimization solvers that require integer coefficients while maintaining mathematical precision.
The function works by: 1. Converting each number to its fractional representation using calculate_fraction() 2. Finding the least common multiple (LCM) of all denominators 3. Scaling all numerators by appropriate factors to use the common denominator 4. Returning both the common denominator and the scaled integer numerators
- Parameters:
numbers (list[float | int]) – A list of numeric values to convert to integer representations. Can contain floating-point numbers, integers, or a mix of both types.
- Returns:
- A tuple containing:
int: The common denominator for all converted values
- list[int]: List of integer numerators corresponding to each input number
when expressed with the common denominator
- Return type:
- Raises:
ValueError – If the input list is empty or contains non-numeric values.
ZeroDivisionError – If any input number results in a zero denominator.
Note
All calculations maintain exact precision through Fraction arithmetic
The LCM approach ensures the smallest possible common denominator
Integer inputs are handled efficiently as Fraction(value, 1)
Useful for preparing coefficients for linear programming solvers
Example
# Convert mixed numeric types numbers = [0.5, 1.5, 2, 0.25] denominator, numerators = get_integer_numerator_and_denominators(numbers) print(f"Common denominator: {denominator}") # 4 print(f"Integer numerators: {numerators}") # [2, 6, 8, 1] # Verify the conversion for i, num in enumerate(numbers): converted = numerators[i] / denominator print(f"{num} = {numerators[i]}/{denominator} = {converted}") # Example with simple fractions simple_fractions = [0.5, 1.5, 2.0] denom, nums = get_integer_numerator_and_denominators(simple_fractions) # Returns: (2, [1, 3, 4]) representing [1/2, 3/2, 4/2]
See also
calculate_fraction: Used internally to convert individual numbers to fractions math.lcm: Used to find the least common multiple of denominators
Special Constraints
- class constraints.OXSpecialConstraint(id: ~uuid.UUID = <factory>, class_name: str = '')[source]
Bases:
OXObjectBase class for special constraints in optimization problems.
Special constraints are non-linear constraints that cannot be expressed as simple linear relationships. They require special handling by solvers and often involve complex relationships between variables.
This class serves as a base for all special constraint types including multiplicative, division, modulo, summation, and conditional constraints.
- class constraints.OXNonLinearEqualityConstraint(id: ~uuid.UUID = <factory>, class_name: str = '', output_variable: ~uuid.UUID = <factory>)[source]
Bases:
OXSpecialConstraintBase class for non-linear equality constraints.
Non-linear equality constraints represent relationships that cannot be expressed as linear combinations of variables. They typically have the form f(x1, x2, …, xn) = output_variable, where f is a non-linear function.
- output_variable
The UUID of the variable that stores the result of the non-linear operation.
- Type:
UUID
Examples
This is a base class and should not be instantiated directly. Use specific subclasses like OXMultiplicativeEqualityConstraint.
- class constraints.OXMultiplicativeEqualityConstraint(id: ~uuid.UUID = <factory>, class_name: str = '', output_variable: ~uuid.UUID = <factory>, input_variables: list[~uuid.UUID] = <factory>)[source]
Bases:
OXNonLinearEqualityConstraintA constraint representing multiplication of variables.
This constraint enforces that the output variable equals the product of all input variables: output_variable = input_variable_1 * input_variable_2 * … * input_variable_n
- output_variable
The UUID of the variable that stores the product. Inherited from OXNonLinearEqualityConstraint.
- Type:
UUID
Examples
>>> # Create a constraint: z = x * y >>> constraint = OXMultiplicativeEqualityConstraint( ... input_variables=[x.id, y.id], ... output_variable=z.id ... )
Note
This constraint is typically handled by constraint programming solvers that support non-linear operations.
- class constraints.OXDivisionEqualityConstraint(id: ~uuid.UUID = <factory>, class_name: str = '', output_variable: ~uuid.UUID = <factory>, input_variable: ~uuid.UUID = <factory>, denominator: int = 1)[source]
Bases:
OXNonLinearEqualityConstraintA constraint representing integer division of a variable.
This constraint enforces that the output variable equals the integer division of the input variable by the denominator: output_variable = input_variable // denominator
- input_variable
The UUID of the variable to divide.
- Type:
UUID
- output_variable
The UUID of the variable that stores the quotient. Inherited from OXNonLinearEqualityConstraint.
- Type:
UUID
Examples
>>> # Create a constraint: z = x // 3 >>> constraint = OXDivisionEqualityConstraint( ... input_variable=x.id, ... denominator=3, ... output_variable=z.id ... )
Note
This constraint performs integer division (floor division), not floating-point division.
- class constraints.OXModuloEqualityConstraint(id: ~uuid.UUID = <factory>, class_name: str = '', output_variable: ~uuid.UUID = <factory>, input_variable: ~uuid.UUID = <factory>, denominator: int = 1)[source]
Bases:
OXNonLinearEqualityConstraintA constraint representing modulo operation on a variable.
This constraint enforces that the output variable equals the remainder of the input variable divided by the denominator: output_variable = input_variable % denominator
- input_variable
The UUID of the variable to apply modulo to.
- Type:
UUID
- output_variable
The UUID of the variable that stores the remainder. Inherited from OXNonLinearEqualityConstraint.
- Type:
UUID
Examples
>>> # Create a constraint: z = x % 5 >>> constraint = OXModuloEqualityConstraint( ... input_variable=x.id, ... denominator=5, ... output_variable=z.id ... )
Note
The result is always non-negative and less than the denominator.
- class constraints.OXSummationEqualityConstraint(id: ~uuid.UUID = <factory>, class_name: str = '', input_variables: list[~uuid.UUID] = <factory>, output_variable: ~uuid.UUID = <factory>)[source]
Bases:
OXSpecialConstraintA constraint representing summation of variables.
This constraint enforces that the output variable equals the sum of all input variables: output_variable = input_variable_1 + input_variable_2 + … + input_variable_n
- output_variable
The UUID of the variable that stores the sum.
- Type:
UUID
Examples
>>> # Create a constraint: z = x + y + w >>> constraint = OXSummationEqualityConstraint( ... input_variables=[x.id, y.id, w.id], ... output_variable=z.id ... )
Note
While this could be expressed as a linear constraint, it’s included as a special constraint for consistency and solver optimization.
- class constraints.OXConditionalConstraint(id: ~uuid.UUID = <factory>, class_name: str = '', indicator_variable: ~uuid.UUID = <factory>, input_constraint: ~uuid.UUID = <factory>, constraint_if_true: ~uuid.UUID = <factory>, constraint_if_false: ~uuid.UUID = <factory>)[source]
Bases:
OXSpecialConstraintA constraint representing conditional logic.
This constraint enforces different constraints based on the value of an indicator variable. If the indicator variable is true, constraint_if_true is enforced; otherwise, constraint_if_false is enforced.
- indicator_variable
The UUID of the boolean variable that determines which constraint to enforce.
- Type:
UUID
- input_constraint
The UUID of the base constraint to evaluate.
- Type:
UUID
- constraint_if_true
The UUID of the constraint to enforce if the indicator variable is true.
- Type:
UUID
- constraint_if_false
The UUID of the constraint to enforce if the indicator variable is false.
- Type:
UUID
Examples
>>> # Create a conditional constraint: if flag then x >= 5 else x <= 3 >>> constraint = OXConditionalConstraint( ... indicator_variable=flag.id, ... input_constraint=base_constraint.id, ... constraint_if_true=upper_bound_constraint.id, ... constraint_if_false=lower_bound_constraint.id ... )
Note
This constraint is used for modeling logical implications and conditional relationships in optimization problems.
Enumerations
- class constraints.RelationalOperators(*values)[source]
Enumeration of relational operators for constraints.
These operators define the relationship between the left-hand side (expression) and right-hand side (rhs) of a constraint.
Available operators:
GREATER_THAN- Greater than (>)GREATER_THAN_EQUAL- Greater than or equal (>=)EQUAL- Equal (=)LESS_THAN- Less than (<)LESS_THAN_EQUAL- Less than or equal (<=)
- GREATER_THAN = '>'
- GREATER_THAN_EQUAL = '>='
- EQUAL = '='
- LESS_THAN = '<'
- LESS_THAN_EQUAL = '<='
Examples
Basic Linear Constraints
from constraints import OXConstraint, OXpression, RelationalOperators
from variables import OXVariable
# Create variables
x = OXVariable(name="x", lower_bound=0, upper_bound=100)
y = OXVariable(name="y", lower_bound=0, upper_bound=100)
# Create expression: 2x + 3y
expr = OXpression(variables=[x.id, y.id], weights=[2, 3])
# Create constraint: 2x + 3y <= 500
constraint = OXConstraint(
expression=expr,
relational_operator=RelationalOperators.LESS_THAN_EQUAL,
rhs=500,
name="Resource capacity constraint"
)
print(f"Constraint: {constraint}")
Goal Programming Constraints
from constraints import OXConstraint, RelationalOperators
# Create a regular constraint
constraint = OXConstraint(
expression=expr,
relational_operator=RelationalOperators.LESS_THAN_EQUAL,
rhs=100,
name="Production target"
)
# Convert to goal constraint
goal_constraint = constraint.to_goal()
# Check deviation variables
print(f"Positive deviation desired: {goal_constraint.positive_deviation_variable.desired}")
print(f"Negative deviation desired: {goal_constraint.negative_deviation_variable.desired}")
Constraint Sets
from constraints import OXConstraintSet, OXConstraint
# Create constraint set
constraint_set = OXConstraintSet(name="Production Constraints")
# Add constraints to the set
for i, constraint in enumerate(production_constraints):
# Add metadata for querying
constraint.related_data["category"] = "production"
constraint.related_data["priority"] = "high" if i < 3 else "medium"
constraint_set.add_object(constraint)
print(f"Total constraints: {len(constraint_set)}")
# Query constraints by metadata
high_priority = constraint_set.query(priority="high")
production_constraints = constraint_set.query(category="production")
Mathematical Expressions
from constraints import OXpression
from variables import OXVariable
# Create variables
x = OXVariable(name="x", lower_bound=0)
y = OXVariable(name="y", lower_bound=0)
z = OXVariable(name="z", lower_bound=0)
# Create expression: 2.5x + 1.5y + 3z
expr = OXpression(
variables=[x.id, y.id, z.id],
weights=[2.5, 1.5, 3]
)
# Access variable coefficients
for var_id, weight in zip(expr.variables, expr.weights):
print(f"Variable {var_id}: coefficient {weight}")
# Convert to integer coefficients
int_weights, denominator = expr.get_integer_weights()
print(f"Integer weights: {int_weights}, common denominator: {denominator}")
Special Constraints
from constraints import OXMultiplicativeEqualityConstraint, OXDivisionEqualityConstraint
from variables import OXVariable
# Create variables for multiplication
x = OXVariable(name="x", lower_bound=0, upper_bound=50)
y = OXVariable(name="y", lower_bound=0, upper_bound=50)
product = OXVariable(name="product", lower_bound=0, upper_bound=2500)
# Multiplication constraint: x * y = product
mult_constraint = OXMultiplicativeEqualityConstraint(
left_variable_id=x.id,
right_variable_id=y.id,
result_variable_id=product.id,
name="Product calculation"
)
# Division constraint: x / y = quotient (integer division)
quotient = OXVariable(name="quotient", lower_bound=0, upper_bound=100)
div_constraint = OXDivisionEqualityConstraint(
left_variable_id=x.id,
right_variable_id=y.id,
result_variable_id=quotient.id,
name="Division calculation"
)
Conditional Constraints
from constraints import OXConditionalConstraint
from variables import OXVariable
# Create binary variables
condition = OXVariable(name="use_machine", lower_bound=0, upper_bound=1, variable_type="binary")
production = OXVariable(name="production", lower_bound=0, upper_bound=100)
cost = OXVariable(name="cost", lower_bound=0, upper_bound=1000)
# Conditional constraint: if use_machine then production >= 10
conditional = OXConditionalConstraint(
condition_variable_id=condition.id,
implication_variable_id=production.id,
threshold_value=10,
name="Minimum production when machine is used"
)
Constraint Validation
def validate_constraint_satisfaction(constraint, variable_values):
"""Check if a constraint is satisfied by given variable values."""
# Calculate left-hand side value
lhs_value = 0
for var_id, weight in zip(constraint.expression.variables, constraint.expression.weights):
lhs_value += weight * variable_values.get(var_id, 0)
# Check constraint satisfaction
tolerance = 1e-6
if constraint.relational_operator == RelationalOperators.LESS_THAN_EQUAL:
return lhs_value <= constraint.rhs + tolerance
elif constraint.relational_operator == RelationalOperators.GREATER_THAN_EQUAL:
return lhs_value >= constraint.rhs - tolerance
elif constraint.relational_operator == RelationalOperators.EQUAL:
return abs(lhs_value - constraint.rhs) <= tolerance
elif constraint.relational_operator == RelationalOperators.LESS_THAN:
return lhs_value < constraint.rhs + tolerance
elif constraint.relational_operator == RelationalOperators.GREATER_THAN:
return lhs_value > constraint.rhs - tolerance
return False
# Usage
is_satisfied = validate_constraint_satisfaction(constraint, solution_values)
print(f"Constraint satisfied: {is_satisfied}")
Precise Arithmetic with Fractions
from constraints import OXpression, get_integer_numerator_and_denominators
# Create expression with decimal coefficients
expr = OXpression(
variables=[x.id, y.id, z.id],
weights=[0.333, 0.667, 1.5] # These will be converted to fractions
)
# Convert to integer representation for solver compatibility
int_weights, common_denom = get_integer_numerator_and_denominators(expr.weights)
print(f"Integer weights: {int_weights}")
print(f"Common denominator: {common_denom}")
# Access fraction properties
for i, weight in enumerate(expr.weights):
frac_weight = expr.get_fraction_weight(i)
print(f"Weight {i}: {frac_weight.numerator}/{frac_weight.denominator}")
See Also
Problem Module - Problem classes that use constraints
Variables Module - Variable definitions and management
Solvers Module - Solver implementations that handle constraints
../user_guide/constraints - Advanced constraint modeling guide