def __init__(self, L, O, V): super(BorderBasis, self).__init__(L, L.as_polys(V)) self.O = O self.dO = L.border(O) self.V = V self._quotient_basis = [L.monom(o) for o in O] self.Q = BorderBasedUniverse(L.ring, O)
class BorderBasis(Basis): """ A border basis. """ def __init__(self, L, O, V): super(BorderBasis, self).__init__(L, L.as_polys(V)) self.O = O self.dO = L.border(O) self.V = V self._quotient_basis = [L.monom(o) for o in O] self.Q = BorderBasedUniverse(L.ring, O) def find_basis_nearest_lt(self, t): """ Find the basis element with the nearest leading term """ # Find the index closest to t closest, dist = None, maxint for t_ in self.dO: d = tuple_diff(t, t_) if any(idx < 0 for idx in d): continue dist_ = sum(d) if dist_ < dist: closest, dist = t_, dist_ assert closest is not None return self._generators[self.dO.index(closest)] def find_basis_with_lt(self, t): """ Find the basis element with leading term """ idx = self.dO.index(t) return self._generators[idx] @property def quotient_basis(self): return self._quotient_basis def mod(self, f): """ Compute the mod """ while True: if f.LM in self.O: return f else: # Find the nearest element on the border, and eliminate b = self.find_basis_nearest_lt(f.LM) f -= f.LC/b.LC * self.L.monom(tuple_diff(f.LM, b.LM)) * b def formal_multiplication_matrices(self): """ With border bases, we know that the formal multiplication matrices essentially only invoke terms on the border, so we can compute this super efficiently. """ d = len(self.Q) Vs = [np.zeros((d,d)) for _ in xrange(self.L.nsymbols)] for i, V in enumerate(Vs): for j, b in enumerate(self.O): t = tuple_incr(b, i) if t in self.O: V[j, self.Q.index(t)] = 1 else: b_ = self.find_basis_with_lt(t) for t, c in b_.terms()[1:]: V[j, self.Q.index(t)] = -c return Vs