Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cover cp.abs() using the builtin #513

Merged
merged 13 commits into from
Oct 3, 2024
2 changes: 1 addition & 1 deletion cpmpy/expressions/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,4 @@
from .globalconstraints import alldifferent, allequal, circuit # Old, to be deprecated
from .globalfunctions import Maximum, Minimum, Abs, Element, Count, NValue, NValueExcept, Among
from .core import BoolVal
from .python_builtins import all, any, max, min, sum
from .python_builtins import all, any, max, min, sum, abs
27 changes: 24 additions & 3 deletions cpmpy/expressions/python_builtins.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,15 @@
max
min
sum
abs
"""
import builtins # to use the original Python-builtins

from .utils import is_false_cst, is_true_cst
from .variables import NDVarArray
from .utils import is_false_cst, is_true_cst, is_any_list
from .variables import NDVarArray, cpm_array
from .core import Expression, Operator
from .globalfunctions import Minimum, Maximum
from .globalfunctions import Minimum, Maximum, Abs
from ..exceptions import CPMpyException


# Overwriting all/any python built-ins
Expand Down Expand Up @@ -125,3 +127,22 @@ def sum(*iterable, **kwargs):

assert len(kwargs)==0, "sum over decision variables does not support keyword arguments"
return Operator("sum", iterable)


def abs(element):
"""
abs() overwrites the python built-in to support decision variables.

if the element given is not a CPMpy expression, the built-in is called
else an Absolute functional global constraint is constructed.
"""
if is_any_list(element): # compat: not allowed by builtins.abs(), but allowed by numpy.abs()
return cpm_array([abs(elem) for elem in element])

if isinstance(element, Expression):
Dimosts marked this conversation as resolved.
Show resolved Hide resolved
# create global
return Abs(element)

return builtins.abs(element)


47 changes: 47 additions & 0 deletions tests/test_builtins.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import unittest

import cpmpy as cp
from cpmpy.exceptions import CPMpyException

iv = cp.intvar(-8, 8, shape=5)


class TestBuiltin(unittest.TestCase):

def test_max(self):
constraints = [cp.max(iv) + 9 <= 8]
model = cp.Model(constraints)
self.assertTrue(model.solve())
self.assertTrue(cp.max(iv.value()) <= -1)

model = cp.Model(cp.max(iv).decompose_comparison('!=', 4))
self.assertTrue(model.solve())
self.assertNotEqual(str(cp.max(iv.value())), '4')

def test_min(self):
constraints = [cp.min(iv) + 9 == 8]
model = cp.Model(constraints)
self.assertTrue(model.solve())
self.assertEqual(str(cp.min(iv.value())), '-1')

model = cp.Model(cp.min(iv).decompose_comparison('==', 4))
self.assertTrue(model.solve())
self.assertEqual(str(cp.min(iv.value())), '4')

def test_abs(self):
constraints = [cp.abs(iv[0]) + 9 <= 8]
model = cp.Model(constraints)
self.assertFalse(model.solve())

#with list
constraints = [cp.abs(iv+2) <= 8, iv < 0]
model = cp.Model(constraints)
self.assertTrue(model.solve())

constraints = [cp.abs([iv[0], iv[2], iv[1], -8]) <= 8, iv < 0]
model = cp.Model(constraints)
self.assertTrue(model.solve())

model = cp.Model(cp.abs(iv[0]).decompose_comparison('!=', 4))
self.assertTrue(model.solve())
self.assertNotEqual(str(cp.abs(iv[0].value())), '4')
2 changes: 1 addition & 1 deletion tests/test_globalconstraints.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ def test_alldifferent_except_n(self):

# and some more
iv = cp.intvar(-8, 8, shape=3)
self.assertTrue(cp.Model([cp.AllDifferentExceptN(iv,2)]).solve())
self.assertTrue(cp.Model([cp.AllDifferentExceptN(iv,4)]).solve())
self.assertTrue(cp.AllDifferentExceptN(iv,4).value())
self.assertTrue(cp.Model([cp.AllDifferentExceptN(iv,7), iv == [7, 7, 1]]).solve())
self.assertTrue(cp.AllDifferentExceptN(iv,7).value())
Expand Down
Loading