def __init__(self, scope, table, positive=True): super().__init__(TypeCtr.EXTENSION) assert is_1d_list(scope, Variable) assert len(table) == 0 or ( len(scope) == 1 and (is_1d_list(table, int) or is_1d_list(table, str))) or ( len(scope) > 1 and len(scope) == len(table[0])) self.arg(TypeCtrArg.LIST, scope, content_ordered=True) self.arg(TypeCtrArg.SUPPORTS if positive else TypeCtrArg.CONFLICTS, ConstraintExtension.caching(table), content_compressible=False)
def _lex(term, others, operator, matrix): if len(others) == 0: assert is_matrix(term, Variable) lists = [flatten(l) for l in term] else: assert is_1d_list(term, Variable) and all(is_1d_list(l, Variable) for l in others) lists = [flatten(term)] + [flatten(l) for l in others] assert is_matrix(lists, Variable) # new check because some null cells (variables) may have been discarded assert all(len(l) == len(lists[0]) for l in lists) checkType(lists, [Variable]) checkType(operator, TypeOrderedOperator) return ECtr(ConstraintLexMatrix(lists, operator)) if matrix else ECtr(ConstraintLex(lists, operator))
def _inside_outside(v, op): v = v if len(v) > 1 else v[0] if isinstance(v, range): return ConditionInterval(op, v.start, v.stop - 1) if isinstance(v, set): return ConditionSet(op, v) assert is_1d_list(v, int) or is_1d_tuple(v, int) return ConditionSet(op, set(v))
def convert_to_namedtuples(obj): if not hasattr(convert_to_namedtuples, "cnt"): convert_to_namedtuples.cnt = 0 if isinstance(obj, list): if is_1d_list(obj, int): return ListInt(obj) if is_1d_list(obj, Variable): return ListVar(obj) if is_1d_list(obj, dict): nt = namedtuple("nt" + str(convert_to_namedtuples.cnt), obj[0].keys()) convert_to_namedtuples.cnt += 1 return [nt(*(convert_to_namedtuples(v) for (k, v) in d.items())) for d in obj] t = [convert_to_namedtuples(v) for v in obj] return ListInt(t) if isinstance(t[0], ListInt) else ListVar(t) if isinstance(t[0], ListVar) else t if isinstance(obj, dict): nt = namedtuple("nt" + str(convert_to_namedtuples.cnt), obj.keys()) convert_to_namedtuples.cnt += 1 return nt(*(convert_to_namedtuples(v) for (k, v) in obj.items())) return obj
def _tuple_contains(self, other): if not OpOverrider.activated: return self.__contains__(other) if is_containing(other, Variable) and len(self) > 0 and isinstance(self[0], (tuple, int)): queue_in.append((list(self), other)) return True if isinstance(other, int) and (is_1d_list(self, Variable) or is_1d_tuple(self, Variable)): # member/element constraint queue_in.append((self, other)) return True return self.__contains__(other)
def _list_contains(self, other): # for being able to use 'in' when expressing extension constraints if not OpOverrider.activated: return self.__contains__(other) if isinstance(other, types.GeneratorType): other = list(other) if is_containing(other, Variable) and len(self) > 0 and isinstance(self[0], (list, tuple, int)): queue_in.append((self, other)) return True if is_containing(other, Variable) and len(self) == 0: return other in set(self) error_if(is_containing(other, Variable), "It seems that you should use a set and not a list, as in x in {...}." + " Your arguments are " + str(other) + " " + str(self)) if isinstance(other, int) and (is_1d_list(self, Variable) or is_1d_tuple(self, Variable)): # member/element constraint queue_in.append((self, other)) return True return self.__contains__(other)
def caching(table): if len(table) == 0: return None arity = 1 if is_1d_list(table, (int, str)) else len(table[0]) h = hash(tuple(table)) if h not in ConstraintExtension.cache: if arity > 1: table.sort() ConstraintExtension.cache[h] = table_to_string( table, parallel=os.name != 'nt') elif isinstance(table[0], int): ConstraintExtension.cache[h] = integers_to_string(table) else: ConstraintExtension.cache[h] = " ".join(v for v in sorted(table)) return ConstraintExtension.cache[h]
def _bool_interpretation_for_in(left_operand, right_operand, bool_value): assert type(bool_value) is bool if isinstance(left_operand, Variable) and isinstance(right_operand, (tuple, list, set, frozenset, range)) and len(right_operand) == 0: return None if isinstance(left_operand, (Variable, int, str)) and isinstance(right_operand, (set, frozenset, range)): # it is a unary constraint of the form x in/not in set/range ctr = Intension(Node.build(TypeNode.IN, left_operand, right_operand) if bool_value else Node.build(TypeNode.NOTIN, left_operand, right_operand)) elif isinstance(left_operand, PartialConstraint): # it is a partial form of constraint (sum, count, maximum, ...) ctr = ECtr(left_operand.constraint.set_condition(TypeConditionOperator.IN if bool_value else TypeConditionOperator.NOTIN, right_operand)) elif isinstance(right_operand, Automaton): # it is a regular constraint ctr = Regular(scope=left_operand, automaton=right_operand) elif isinstance(right_operand, MDD): # it is a MDD constraint ctr = Mdd(scope=left_operand, mdd=right_operand) elif isinstance(left_operand, int) and (is_1d_list(right_operand, Variable) or is_1d_tuple(right_operand, Variable)): ctr = Count(right_operand, value=left_operand, condition=(TypeConditionOperator.GE, 1)) # atLeast1 TODO to be replaced by a member/element constraint ? else: # It is a table constraint if not hasattr(left_operand, '__iter__'): left_operand = [left_operand] if not bool_value and len(right_operand) == 0: return None # TODO what to do if the table is empty and bool_value is true? an error message ? ctr = Extension(scope=list(left_operand), table=right_operand, positive=bool_value) return ctr
def __contains__(self, other): if isinstance(other, int) and (is_1d_list(self, Variable) or is_1d_tuple(self, Variable)): # member constraint queue_in.append((self, other)) return True return list.__contains__(self, other)