or-tools module in python adds custom syntax where functions can take arbitrary expressions as arguments (something like below), which is evaluated not instantaneously but solved as a constraint later
model.Add(x + 2 * y -1 >= z)
When I print the type of the argument from my function, it shows
<class 'ortools.sat.python.cp_model.BoundedLinearExpression'>
A simple way is to pass the expression as a string, but it feels better. I wish to understand how this is achieved. Is this a way to create custom syntax in python? Does it require updating the parser or something like that?
Here is the simple program
from ortools.sat.python import cp_model
def foo(expr):
print(expr, type(expr))
def main():
model = cp_model.CpModel()
var_upper_bound = max(50, 45, 37)
x = model.NewIntVar(0, var_upper_bound, 'x')
y = model.NewIntVar(0, var_upper_bound, 'y')
z = model.NewIntVar(0, var_upper_bound, 'z')
a = 0
b = 0
c = 0
model.Add(2*x + 7*y + 3*z == 50)
solver = cp_model.CpSolver()
status = solver.Solve(model)
if status == cp_model.OPTIMAL:
print('x value: ', solver.Value(x))
print('y value: ', solver.Value(y))
print('z value: ', solver.Value(z))
foo(2*x + 7*y + 3*z == 50)
foo(2*a + 7*b + 3*c == 50)
if __name__ == '__main__':
main()
x, y, z are special variables (instances of some class) and the expression with x, y, z is stored as expression
a, b, c are simple integers and the expression is evaluated immediately and the result is stored as a bool
-
I see the OR source code but I don't know how to make an example to reproduce what you are seeing when you "print the type of the argument". Please can you edit the question to show a short code snippet that will produce the output shown in your question?TMBailey– TMBailey2021年09月12日 07:34:42 +00:00Commented Sep 12, 2021 at 7:34
-
Note that BoundedLinearExpression have an str method, but not a repr one. So str(x + 2 *y - 1 >= z) should be be pretty-printed.Laurent Perron– Laurent Perron2021年09月12日 11:33:02 +00:00Commented Sep 12, 2021 at 11:33
2 Answers 2
They override the python operators.
References:
- https://docs.python.org/3/reference/datamodel.html#emulating-numeric-types
- https://github.com/google/or-tools/blob/b37d9c786b69128f3505f15beca09e89bf078a89/ortools/sat/python/cp_model.py#L212-L233
def __mul__(self, arg):
if isinstance(arg, numbers.Integral):
if arg == 1:
return self
elif arg == 0:
return 0
cp_model_helper.AssertIsInt64(arg)
return _ProductCst(self, arg)
else:
raise TypeError('Not an integer linear expression: ' + str(arg))
Comments
The or-tools module defines its own classes for model variables, and within the class definitions the module defines methods for applying operators to those classes.
As a trivial example we can define our own class along with a method for '+'.
# New class will normally not support math operators.
class Blah(object):
def __init__(self, context):
self.context = context
def __add__(self, value):
# Support '+' operator with class Blah.
return self.context.format(value)
x = Blah("Chocolate with {} is the result.")
# '*' operator is not supported.
x * 2
# Traceback (most recent call last):
#
# File "<ipython-input-26-80b83cb135a7>", line 1, in <module>
# x * 2
#
# TypeError: unsupported operand type(s) for *: 'Blah' and 'int'
# '+' operator is implemented for class Blah.
x + 3
# 'Chocolate with 3 is the result.'