def canonize_and_add_monomials(self, monomials, lower_bound=None): inadmissibles = KeyOrderedDict() def push_inadmissible(inad): inadmissibles.toggle(RevlexBasisMonomial(*inad), 1) for mon in monomials: if mon.admissible(): self._add_admissible_monomial(mon) else: push_inadmissible(mon) while inadmissibles: mon, _ = inadmissibles.remove_max() if lower_bound is not None and leading_integer_upper_bound(mon) < lower_bound[0]: continue for rep in _adem_relation(mon): if rep.admissible(): if lower_bound is None or rep >= lower_bound: self._add_admissible_monomial(rep) else: push_inadmissible(rep)
def __init__(self, monomials, lower_bound=None): self._admissibles = KeyOrderedDict() self.canonize_and_add_monomials(monomials, lower_bound=lower_bound)
class AdmissibleTerm(object): def __init__(self, monomials, lower_bound=None): self._admissibles = KeyOrderedDict() self.canonize_and_add_monomials(monomials, lower_bound=lower_bound) def __str__(self): s = ' + '.join(map(str, self._admissibles)) return s if s else '0' def _add_admissible_monomial(self, monomial): self._admissibles.toggle(LexBasisMonomial(*monomial), 1) def __len__(self): return len(self._admissibles) def __iter__(self): return iter(self._admissibles) def __eq__(self, other): return self._admissibles == other._admissibles def __bool__(self): return bool(self._admissibles) is_zero = __bool__ def leading_term(self): if self._admissibles: k, _ = self._admissibles.peek_max() return k else: raise IndexError('Attempt to examine leading term in zero expression') # this obviously leaves room for improvement def canonize_and_add_monomials(self, monomials, lower_bound=None): inadmissibles = KeyOrderedDict() def push_inadmissible(inad): inadmissibles.toggle(RevlexBasisMonomial(*inad), 1) for mon in monomials: if mon.admissible(): self._add_admissible_monomial(mon) else: push_inadmissible(mon) while inadmissibles: mon, _ = inadmissibles.remove_max() if lower_bound is not None and leading_integer_upper_bound(mon) < lower_bound[0]: continue for rep in _adem_relation(mon): if rep.admissible(): if lower_bound is None or rep >= lower_bound: self._add_admissible_monomial(rep) else: push_inadmissible(rep) def differential(self, lower_bound=None): seq = chain.from_iterable(map(_differential, iter(self))) return AdmissibleTerm(seq, lower_bound=lower_bound) def __add__(self, other): new_at = AdmissibleTerm([]) new_at._admissibles = self._admissibles.sym_diff(other._admissibles) return new_at def __iadd__(self, other): self._admissibles = self._admissibles.sym_diff(other._admissibles) return self def __mul__(self, other): terms = (x * y for x, y in product(self, other)) return AdmissibleTerm(terms) def copy(self): new_at = AdmissibleTerm([]) new_at._admissibles = self._admissibles.copy() return new_at