Relational Constraints

๐ŸŽ“ Relational Constraints

We often want to write formulas โ€” sums, products, powers, or trigonometric functions โ€” to enforce them over variables, to find the right assignments. In Qaekwy, the building block for this is the Expression class. Expressions let you treat mathematical formulas as first-class constraints of your model: you can combine them, compare them, turn them into constraints, or even promote them to variables.


๐Ÿงฑ What Is an Expression?

An Expression is a symbolic mathematical formula built from:

  • Variables (integer or array variables),
  • Constants (like 3 or 10),
  • Mathematical / Boolean operators (+, -, *, /, &, |, etc.),
  • Expression functions (like sqr, sqrt, exp, sin, max, sum_of, โ€ฆ).

You can think of an Expression as a โ€œrecipeโ€ for computing a value that depends on the solverโ€™s decisions.

For example:

expr_1 = 2 * x + 3
expr_2 = power(y, 2) - 4
expr_3 = expr_1 - sum_of(arr)

Here:

  • expr_1 represents the formula 2ยทx + 3.
  • expr_2 represents the formula yยฒ โˆ’ 4.
  • expr_3 represents the formula (2ยทx + 3) โˆ’ โˆ‘ arr.

At solving time, whenever x and y are assigned, the solver knows what expr_1, expr_2, and expr_3 evaluate to.


๐Ÿงฎ Arithmetic with Expressions

Expressions are composable. You can add, subtract, multiply, or combine them in more complex ways:

result_expr = expr_1 + expr_2
result_expr = expr_1 * 2 - expr_2

Conceptually, this works like symbolic algebra: Qaekwy tracks the operations to build a structured formula tree.


๐Ÿ”Ž Relational Expressions: Turning Formulas into Constraints

On their own, expressions are just formulas. To constrain them, you must compare them. This is done using Pythonโ€™s comparison operators:

bool_expr = expr_1 >= expr_2
bool_expr = expr_1 == 0

Each comparison produces a relational expression (a Boolean formula). To actually enforce it in the model, you wrap it into a RelationalExpression constraint:

constraint = RelationalExpression(expr_1 >= expr_2)
my_model.add_constraint(constraint)

This way, expr_1 โ‰ฅ expr_2 becomes a logical rule that the solver must respect during search.


๐Ÿ“š Expression Functions

Qaekwy provides a collection of mathematical functions that operate on expressions. They extend the expressiveness of your models beyond simple linear formulas.

Aggregation

  • maximum(expr_array) โ†’ maximum of an array of expressions.
  • minimum(expr_array) โ†’ minimum of an array of expressions.
  • sum_of(expr_array) โ†’ sum of an array of expressions.

Arithmetic transformations

  • absolute(expr) โ†’ |expr|.
  • sqr(expr) โ†’ exprยฒ.
  • power(expr, val) โ†’ expr^val.
  • nroot(expr, val) โ†’ val-th root of expr.
  • sqrt(expr) โ†’ โˆšexpr.

Trigonometry

  • sin(expr), cos(expr), tan(expr) โ†’ trigonometric functions.
  • asin(expr), acos(expr), atan(expr) โ†’ inverse trigonometric functions.

Exponential & logarithm

  • exp(expr) โ†’ e^expr.
  • log(expr) โ†’ ln(expr).

These allow you to model highly nonlinear phenomena โ€” growth, oscillations, angles, penalties โ€” directly in your CSP or optimization problem.


๐ŸŽจ Example 1: Nonlinear Constraints with Expressions

from qaekwy.model.constraint.relational import RelationalExpression
from qaekwy.model.function import sqr, exp, power
from qaekwy.model.modeller import Modeller
from qaekwy.model.variable.integer import IntegerVariable, IntegerVariableArray

# Create variables
x = IntegerVariable("x", domain_low=0, domain_high=100)
y = IntegerVariable("y", domain_low=0, domain_high=100)
z = IntegerVariable("z", domain_low=0, domain_high=100)
arr = IntegerVariableArray("arr", length=3, domain_low=0, domain_high=100)

# Expressions
expr_1 = arr[0] > x + 1
expr_2 = sqr(y) < arr[1] * z
expr_3 = exp(arr[2]) + power(z, 3) >= arr[0] + arr[1]

# Build the model
my_model = Modeller()
my_model.add_variable(x)
my_model.add_variable(y)
my_model.add_variable(z)
my_model.add_variable(arr)

# Add constraints
my_model.add_constraint(RelationalExpression(expr_1))
my_model.add_constraint(RelationalExpression(expr_2))
my_model.add_constraint(RelationalExpression(expr_3))

Here:

  • expr_1 ensures arr[0] > x + 1.
  • expr_2 encodes yยฒ < arr[1]ยทz.
  • expr_3 mixes exponential and polynomial terms.

These would be extremely difficult to encode by hand without expressions.


๐ŸŽฏ Example 2: Expressions as Variables (Objectives)

Expressions can also be turned into variables via IntegerExpressionVariable. This is useful when:

  • You want to monitor a complex formula,
  • Or you want to optimize it (maximize/minimize).
from qaekwy.model.variable.integer import IntegerVariable, IntegerExpressionVariable
from qaekwy.model.constraint.relational import RelationalExpression
from qaekwy.model.specific import SpecificMaximum
from qaekwy.model.function import power
from qaekwy.model.modeller import Modeller

# Variables
x = IntegerVariable("x", 0, 100)
y = IntegerVariable("y", 0, 100)
z = IntegerVariable("z", 0, 100)

# Complex nonlinear expression
nonlinear_expr = (power(x, 2) + power(y, 3)) * z + x * y - 10

# Promote it to a variable
objective_variable = IntegerExpressionVariable(
    var_name="objective_variable",
    expression=nonlinear_expr
)

# Constraint & objective
nonlinear_constraint = RelationalExpression(objective_variable < 100)
maximum_nonlinear = SpecificMaximum(objective_variable)

# Build model
my_model = Modeller()
my_model.add_variable(x)
my_model.add_variable(y)
my_model.add_variable(z)
my_model.add_variable(objective_variable)
my_model.add_constraint(nonlinear_constraint)
my_model.add_objective(maximum_nonlinear)

Here:

  • The nonlinear expression becomes a variable that the solver tracks.
  • We add a constraint (objective_variable < 100).
  • We set an objective: maximize objective_variable.

โšก Why Expressions Are Powerful

  1. Conciseness: Instead of building dozens of primitive constraints, you can write natural mathematical formulas.
  2. Flexibility: Expressions let you describe nonlinear, trigonometric, or exponential relationships.
  3. Reusability: An expression can be used in multiple constraints or as an optimization objective.
  4. Integration: Expressions play well with reification, branching, and global constraints.

๐Ÿ“Œ Takeaway

  • In Qaekwy, Expressions are symbolic formulas that extend the modeling language.
  • They can be combined arithmetically, compared relationally, and transformed with a wide range of functions.
  • Relational expressions turn formulas into constraints.
  • Expression variables let you optimize formulas directly.
  • Together, they make complex constraint models natural to write and efficient to solve.
  • important: Expressions must contain variables of the same type (e.g., all integer). Mixing types (integer with float) is not supported.