๐ 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 3or10),
- 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_1represents the formula 2ยทx + 3.
- expr_2represents the formula yยฒ โ 4.
- expr_3represents 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_1ensures- arr[0] > x + 1.
- expr_2encodes- yยฒ < arr[1]ยทz.
- expr_3mixes 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
- Conciseness: Instead of building dozens of primitive constraints, you can write natural mathematical formulas.
- Flexibility: Expressions let you describe nonlinear, trigonometric, or exponential relationships.
- Reusability: An expression can be used in multiple constraints or as an optimization objective.
- 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.