def integral_basis_of_unramified_subfield(self, precision=5): r""" Return an (approximate) integral basis of the maximal unramified subfield. INPUT: - ``precison`` -- a positive integer OUTPUT: A list `\alpha=(\alpha_0,\ldots,\alpha_{m-1})` of elements of `K_0` which approximate (with precision `p^N` an integral basis of the maximal unramified subfield. """ if not hasattr(self, "_integral_basis_of_unramified_subfield") or precision > 5: m = self.inertia_degree() if m == 1: return [QQ.one()] p = self.p() fb = GF(p**m, 'zeta').polynomial() f = fb.change_ring(self.number_field()) fx = f.derivative() vK = self.valuation() k = vK.residue_field() zetab = fb.change_ring(k).roots()[0][0] assert fb(zetab) == 0 zeta = vK.lift(zetab) while vK(f(zeta)) <= precision: zeta = zeta - f(zeta)/fx(zeta) zeta = self.reduce(zeta, precision +1) # now zeta is an approximate generator of the maximal unramified subfield self._integral_basis_of_unramified_subfield = [self.reduce(zeta**i, precision +1) for i in range(m)] return self._integral_basis_of_unramified_subfield
def handle_term(n, den_tuple): r""" Entry point for reduction of generalized multiple zeta values into standard multiple zeta values. EXAMPLES:: sage: from surface_dynamics.misc.generalized_multiple_zeta_values import handle_term, is_convergent sage: M = Multizetas(QQ) sage: V1 = FreeModule(ZZ, 1) sage: v = V1((1,)); v.set_immutable() sage: dt = ((v,3),) sage: assert is_convergent(1, dt) and handle_term(1, dt) == M((3,)) sage: V2 = FreeModule(ZZ, 2) sage: va = V2((1,0)); va.set_immutable() sage: vb = V2((0,1)); vb.set_immutable() sage: vc = V2((1,1)); vc.set_immutable() sage: dt = ((va,2), (vc,3)) sage: assert is_convergent(2, dt) and handle_term(2, dt) == M((2,3)) sage: dt1 = ((va,2),(vb,3)) sage: dt2 = ((va,3),(vb,2)) sage: assert is_convergent(2,dt1) and is_convergent(2,dt2) and handle_term(2, ((va,2), (vb,3))) == handle_term(2, ((va,3), (vb,2))) == M((2,)) * M((3,)) sage: V3 = FreeModule(ZZ, 3) sage: va = V3((1,0,0)); va.set_immutable() sage: vb = V3((0,1,0)); vb.set_immutable() sage: vc = V3((0,0,1)); vc.set_immutable() sage: vd = V3((1,1,0)); vd.set_immutable() sage: ve = V3((1,0,1)); ve.set_immutable() sage: vf = V3((0,1,1)); vf.set_immutable() sage: vg = V3((1,1,1)); vg.set_immutable() sage: assert handle_term(3, ((va,2), (vd,3), (vg,4))) == M((2,3,4)) sage: assert handle_term(3, ((va,2), (vb,3), (vc,4))) == handle_term(3, ((va,3), (vb,2), (vc,4))) == M((2,)) * M((3,)) * M((4,)) sage: assert handle_term(3, ((va,1), (vc,2), (vd,3))) == handle_term(3, ((va,1), (vb,2), (ve,3))) == handle_term(3, ((va,2), (vb,1), (vf,3))) == M((2,)) * M((1,3)) """ if n == 1: M = Multizetas(QQ) ans = M.zero() for v, p in den_tuple: # sum (v[0]x)^p ans += QQ.one() / v[0]**p * M((p, )) return ans elif n == 2: dat = to_Z2(den_tuple) if dat is None: raise NotImplementedError("generalized mzv {}".format(den_tuple)) return Z2(*dat) elif n == 3: dat = to_Z3(den_tuple) if dat is None: raise NotImplementedError("generalized mzv {}".format(den_tuple)) return Z3(*dat) return _handle_term(den_tuple, n)
def kill_relation(n, den_tuple, i, relation): r""" Make calls to `apply_relation` until we get rid of term EXAMPLES:: sage: from surface_dynamics.misc.generalized_multiple_zeta_values import kill_relation sage: V = FreeModule(ZZ, 2) sage: va = V((1,0)); va.set_immutable() sage: vb = V((0,1)); vb.set_immutable() sage: vc = V((1,1)); vc.set_immutable() sage: den_tuple = ((va,2),(vb,3),(vc,4)) sage: kill_relation(2, den_tuple, 2, [1,1,0]) [(1, (((0, 1), 3), ((1, 1), 6))), (2, (((0, 1), 2), ((1, 1), 7))), (1, (((1, 0), 2), ((1, 1), 7))), (3, (((0, 1), 1), ((1, 1), 8))), (3, (((1, 0), 1), ((1, 1), 8)))] """ assert len(relation) == len(den_tuple) assert 0 <= i < len(den_tuple) assert sum(relation[j] * den_tuple[j][0] for j in range(len(den_tuple))) == den_tuple[i][0] D = {den_tuple: QQ.one()} todo = [den_tuple] while todo: den_tuple = todo.pop(0) coeff1 = D.pop(den_tuple) for coeff, new_den_tuple in apply_relation(n, den_tuple, i, relation): coeff *= coeff1 if new_den_tuple in D: D[new_den_tuple] += coeff elif any(not new_den_tuple[j][1] for j in range(len(den_tuple))): new_den_tuple = tuple(x for x in new_den_tuple if x[1]) if new_den_tuple not in D: D[new_den_tuple] = coeff else: D[new_den_tuple] += coeff else: todo.append(new_den_tuple) D[new_den_tuple] = coeff return [(coeff, new_den_tuple) for new_den_tuple, coeff in D.items()]