๐ 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
or10
), - 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
ensuresarr[0] > x + 1
.expr_2
encodesyยฒ < 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
- 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.