def Intension(node): checkType(node, Node) ctr = ECtr(ConstraintIntension(node)) if ctr.blank_basic_attributes(): ctr.copy_basic_attributes_of(node) node.mark_as_used() return ctr
def add_condition(self, operator, right_operand): if isinstance(right_operand, (int, Variable)): return ECtr(self.constraint.set_condition(operator, right_operand)) # TODO : which kind of right operand is authorized? just a partial sum? assert isinstance(self.constraint, ConstraintSum) pc = PartialConstraint.combine_partial_objects( self, TypeNode.SUB, right_operand) # the 'complex' right operand is moved to the left return ECtr(pc.constraint.set_condition(operator, 0))
def AllDifferent(term, *others, excepting=None, matrix=None): terms = flatten(term, others) if matrix is not None: assert excepting is None, "excepting values are currently not supported for AllDifferentMatrix" matrix = [flatten(row) for row in terms] assert all(len(row) == len(matrix[0]) for row in matrix), "The matrix id badly formed" assert all(checkType(l, [Variable]) for l in matrix) return ECtr(ConstraintAllDifferentMatrix(matrix)) excepting = list(excepting) if isinstance(excepting, (tuple, set)) else [excepting] if isinstance(excepting, int) else excepting checkType(terms, ([Variable, Node])) checkType(excepting, ([int], type(None))) return ECtr(ConstraintAllDifferent(terms, excepting))
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 Extension(*, scope, table, positive=True): scope = flatten(scope) checkType(scope, [Variable]) assert isinstance(table, list) if any(isinstance(v, ConditionValue) for t in table for v in t): # if smart table table = sorted(list(to_ordinary_table(table, [x.dom for x in scope], keep_any=True))) checkType(table, [str, int, float]) checkType(positive, bool) assert isinstance(table, list) and len(table) > 0, "A table must be a non-empty list of tuples or integers (or symbols)" assert isinstance(table[0], (tuple, int, str)), "Elements of tables are tuples or integers (or symbols)" #print(table) assert isinstance(table[0], (int, str)) or len(scope) == len(table[0]), ( "The length of each tuple must be the same as the arity." + "Maybe a problem with slicing: you must for example write x[i:i+3,0] instead of x[i:i+3][0]") # TODO: this ckecking don't pass on Waterbucket.py, but the xml file is the same that the java version ! # if options.checker: # if not hasattr(Extension, "checked_tables"): # Extension.checked_tables = set() # if id(table) not in checked_tables: # for t in table: # for i, v in enumerate(t): # if v not in variables[i].dom: # raise ValueError( # "Problem: Constraint extension : a value of table is not represented in a domain of a variable : " + str(domainElement)) # checked_tables.add(id(table)) return ECtr(ConstraintExtension(scope, table, positive))
def Channel(list1, list2=None, *, start_index1=0, start_index2=0): list1 = flatten(list1) checkType(list1, [Variable]) if list2: list2 = flatten(list2) checkType(list2, [Variable]) checkType(start_index1, int) checkType(start_index2, int) assert start_index2 == 0 or list2 is not None, "start_index2 is defined while list2 is not specified" return ECtr(ConstraintChannel(list1, start_index1, list2, start_index2))
def _ordered(term, others, operator, lengths): terms = flatten(term, others) checkType(terms, [Variable]) checkType(operator, TypeOrderedOperator) checkType(lengths, ([int, Variable], type(None))) if lengths is not None: if len(terms) == len(lengths): lengths = lengths[:-1] # we assume that the last value is useless assert len(terms) == len(lengths) + 1 return ECtr(ConstraintOrdered(terms, operator, lengths))
def Clause(term, *others, phases=None): literals = flatten(term, others) phases = [False] * len(literals) if phases is None else flatten(phases) assert len(literals) == len(phases) checkType(literals, ([Variable, NotVariable])) checkType(phases, [bool]) for i, literal in enumerate(literals): if isinstance(literal, NotVariable): literals[i] = literal.variable phases[i] = True return ECtr(ConstraintClause(literals, phases))
def AllDifferentList(lists, *others, excepting=None): if isinstance(lists, types.GeneratorType): lists = [l for l in lists] elif len(others) > 0: lists = list((lists,) + others) lists = [flatten(l) for l in lists] assert all(checkType(l, [Variable]) for l in lists) excepting = list(excepting) if isinstance(excepting, (tuple, set)) else excepting checkType(excepting, ([int], type(None))) assert all(len(l) == len(lists[0]) for l in lists) and (excepting is None or len(excepting) == len(list[0])) return ECtr(ConstraintAllDifferentList(lists, excepting))
def __eq__(self, other): other = self._simplify_with_auxiliary_variables(other) if isinstance( self.constraint, (ConstraintElement, ConstraintElementMatrix)) and isinstance( other, (int, Variable)): if isinstance(self.constraint, ConstraintElement): arg = self.constraint.arguments[TypeCtrArg.LIST] arg.content = flatten( arg.content ) # we need to flatten now because it has not been done before return ECtr(self.constraint.set_value( other)) # only value must be replaced for these constraints return self.add_condition(TypeConditionOperator.EQ, other)
def Cardinality(term, *others, occurrences, closed=False): terms = flatten(term, others) checkType(terms, [Variable]) assert isinstance(occurrences, dict) values = list(occurrences.keys()) assert all(isinstance(value, (int, Variable)) for value in values) occurs = list(occurrences.values()) checkType(closed, (bool, type(None))) for i, occ in enumerate(occurs): if isinstance(occ, range): occurs[i] = str(min(occ)) + ".." + str(max(occ)) if isinstance(occ, list): flat = flatten(occ) if all([isinstance(e, int) for e in flat]) and flat == list(range(min(flat), max(flat) + 1)): flat = str(min(flat)) + ".." + str(max(flat)) occurs[i] = flat return ECtr(ConstraintCardinality(terms, values, occurs, closed))
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 recognizing_instantiations(entities): def _elements_for_building_instantiation(trees): t1, t2 = [], [] for tree in trees: pair = tree.var_val_if_binary_type(TypeNode.EQ) if pair is None: return None t1.append(pair[0]) t2.append(pair[1]) return t1, t2 for i, e in enumerate(entities): # since a group, we can test only the first constraint (to see if it is a group of intension constraints) if isinstance(e, EGroup) and isinstance(e.entities[0].constraint, ConstraintIntension): elements = _elements_for_building_instantiation( c.constraint.arguments[TypeCtrArg.FUNCTION].content for c in e.entities) if elements: entities[i] = ECtr( ConstraintInstantiation( elements[0], elements[1])).copy_basic_attributes_of(e) elif isinstance(e, (ESlide, EToGather, EBlock, EToSatisfy)): recognizing_instantiations(e.entities)
def Regular(*, scope, automaton): scope = flatten(scope) checkType(scope, [Variable]) checkType(automaton, Automaton) return ECtr(ConstraintRegular(scope, automaton))
def Mdd(*, scope, mdd): scope = flatten(scope) checkType(scope, [Variable]) checkType(mdd, MDD) return ECtr(ConstraintMdd(scope, mdd.transitions))
def AllEqual(term, *others): terms = flatten(term, others) checkType(terms, ([Variable], [Node])) return ECtr(ConstraintAllEqual(terms))
def Circuit(term, *others, start_index=0, size=None): terms = flatten(term, others) checkType(terms, [Variable]) checkType(start_index, int) checkType(size, (int, type(None))) return ECtr(ConstraintCircuit(terms, start_index, size))
def NoOverlap(*, origins, lengths, zero_ignored=False): checkType(origins, [Variable]) checkType(lengths, ([Variable], [int])) return ECtr(ConstraintNoOverlap(origins, lengths, zero_ignored))
def _wrapping_by_complete_or_partial_constraint(ctr): condition = ctr.arguments[TypeCtrArg.CONDITION].content return ECtr(ctr) if condition is not None else PartialConstraint(ctr)