Search code examples
pythonsyntaxor-toolscp-sat

python creating custom syntax


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


Solution

  • They override the python operators.

    References:

        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))