Skip to content

Commit

Permalink
minor fix: globalconstraint.py and python_buildins.py (#337)
Browse files Browse the repository at this point in the history
* removal of redundant code (first evaluation is never used)

* Use of numpy formalism to express the decomposition

* uniform naming within class

* minor changes (PEP 8 compliance, typo, spaces,...)

* minor modifications: add few spaces

* Revert "Use of numpy formalism to express the decomposition"

This reverts commit fe6cdcf.

---------

Co-authored-by: wout4 <wout.vanroose@gmail.com>
  • Loading branch information
363734 and Wout4 authored Sep 8, 2023
1 parent 914153a commit 0b6d7c5
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 15 deletions.
33 changes: 20 additions & 13 deletions cpmpy/expressions/globalconstraints.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ def my_circuit_decomp(self):
from .utils import flatlist, all_pairs, argval, is_num, eval_comparison, is_any_list, is_boolexpr, get_bounds
from .globalfunctions import * # XXX make this file backwards compatible


# Base class GlobalConstraint
class GlobalConstraint(Expression):
"""
Expand All @@ -142,20 +143,22 @@ def decompose(self):
Defining constraints (totally) define new auxiliary variables needed for the decomposition,
they can always be enforced top-level.
"""
raise NotImplementedError("Decomposition for",self,"not available")
raise NotImplementedError("Decomposition for", self, "not available")

def get_bounds(self):
"""
Returns the bounds of a Boolean global constraint.
Numerical global constraints should reimplement this.
"""
return (0,1)
return 0, 1


# Global Constraints (with Boolean return type)
def alldifferent(args):
warnings.warn("Deprecated, use AllDifferent(v1,v2,...,vn) instead, will be removed in stable version", DeprecationWarning)
return AllDifferent(*args) # unfold list as individual arguments


class AllDifferent(GlobalConstraint):
"""All arguments have a different (distinct) value
"""
Expand All @@ -170,6 +173,7 @@ def decompose(self):
def value(self):
return len(set(a.value() for a in self.args)) == len(self.args)


class AllDifferentExcept0(GlobalConstraint):
"""
All nonzero arguments have a distinct value
Expand All @@ -189,6 +193,8 @@ def value(self):
def allequal(args):
warnings.warn("Deprecated, use AllEqual(v1,v2,...,vn) instead, will be removed in stable version", DeprecationWarning)
return AllEqual(*args) # unfold list as individual arguments


class AllEqual(GlobalConstraint):
"""All arguments have the same value
"""
Expand All @@ -208,6 +214,8 @@ def value(self):
def circuit(args):
warnings.warn("Deprecated, use Circuit(v1,v2,...,vn) instead, will be removed in stable version", DeprecationWarning)
return Circuit(*args) # unfold list as individual arguments


class Circuit(GlobalConstraint):
"""The sequence of variables form a circuit, where x[i] = j means that j is the successor of i.
"""
Expand Down Expand Up @@ -240,14 +248,13 @@ def decompose(self):

return constraining, defining


def value(self):
pathlen = 0
idx = 0
visited = set()
arr = [argval(a) for a in self.args]
while(idx not in visited):
if idx == None:
while idx not in visited:
if idx is None:
return False
if not (0 <= idx < len(arr)):
break
Expand Down Expand Up @@ -284,6 +291,7 @@ def value(self):
rev = [argval(a) for a in self.args[1]]
return all(rev[x] == i for i, x in enumerate(fwd))


class Table(GlobalConstraint):
"""The values of the variables in 'array' correspond to a row in 'table'
"""
Expand All @@ -301,9 +309,9 @@ def value(self):
return arrval in tab



# syntax of the form 'if b then x == 9 else x == 0' is not supported
# a little helper:
# syntax of the form 'if b then x == 9 else x == 0' is not supported (no override possible)
# same semantic as CPLEX IfThenElse constraint
# https://www.ibm.com/docs/en/icos/12.9.0?topic=methods-ifthenelse-method
class IfThenElse(GlobalConstraint):
def __init__(self, condition, if_true, if_false):
if not is_boolexpr(condition) or not is_boolexpr(if_true) or not is_boolexpr(if_false):
Expand All @@ -312,7 +320,6 @@ def __init__(self, condition, if_true, if_false):

def value(self):
condition, if_true, if_false = self.args
condition_val = argval(condition)
if argval(condition):
return argval(if_true)
else:
Expand All @@ -327,7 +334,7 @@ def __repr__(self):
return "If {} Then {} Else {}".format(condition, if_true, if_false)



class InDomain(GlobalConstraint):
"""
The "InDomain" constraint, defining non-interval domains for an expression
Expand Down Expand Up @@ -438,7 +445,7 @@ def __init__(self, start, duration, end, demand, capacity):
if any(is_boolexpr(arg) for arg in flatargs):
raise TypeError("All input lists should contain only arithmetic arguments for Cumulative constraints: {}".format(flatargs))

super(Cumulative, self).__init__("cumulative",[start, duration, end, demand, capacity])
super(Cumulative, self).__init__("cumulative", [start, duration, end, demand, capacity])

def decompose(self):
"""
Expand Down Expand Up @@ -478,15 +485,15 @@ def value(self):
return None

# start, dur, end are np arrays
start, dur, end, demand, cap = argvals
start, dur, end, demand, capacity = argvals
# start and end seperated by duration
if not (start + dur == end).all():
return False

# demand doesn't exceed capacity
lb, ub = min(start), max(end)
for t in range(lb, ub+1):
if cap < sum(demand * ((start <= t) & (t < end))):
if capacity < sum(demand * ((start <= t) & (t < end))):
return False

return True
Expand Down
9 changes: 7 additions & 2 deletions cpmpy/expressions/python_builtins.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
from .core import Expression, Operator
from .globalfunctions import Minimum, Maximum


# Overwriting all/any python built-ins
# all: listwise 'and'
def all(iterable):
Expand All @@ -42,7 +43,7 @@ def all(iterable):
elif is_true_cst(elem):
pass
elif isinstance(elem, Expression) and elem.is_bool():
collect.append( elem )
collect.append(elem)
else:
raise Exception("Non-Boolean argument '{}' to 'all'".format(elem))
if len(collect) == 1:
Expand All @@ -51,6 +52,7 @@ def all(iterable):
return Operator("and", collect)
return True


# any: listwise 'or'
def any(iterable):
"""
Expand All @@ -66,7 +68,7 @@ def any(iterable):
elif is_false_cst(elem):
pass
elif isinstance(elem, Expression) and elem.is_bool():
collect.append( elem )
collect.append(elem)
else:
raise Exception("Non-Boolean argument '{}' to 'all'".format(elem))
if len(collect) == 1:
Expand All @@ -75,6 +77,7 @@ def any(iterable):
return Operator("or", collect)
return False


def max(iterable):
"""
max() overwrites python built-in,
Expand All @@ -84,6 +87,7 @@ def max(iterable):
return np.max(iterable)
return Maximum(iterable)


def min(iterable):
"""
min() overwrites python built-in,
Expand All @@ -93,6 +97,7 @@ def min(iterable):
return np.min(iterable)
return Minimum(iterable)


def sum(iterable):
"""
sum() overwrites python built-in,
Expand Down

0 comments on commit 0b6d7c5

Please sign in to comment.