# $ sage -sh # $ pip install tabulate from tabulate import tabulate # P = (2, 4) # ord_P(y - 2x) = 2 # from Washington example 11.4 page 345 K. = GF(11)[] Px, Py = K(2), K(4) assert (3*Px^2 + 4) / (2*Py) == 2 basis = [(x - Px), (y - Py), 1] # Return components for basis def decomp(f, basis): comps = [] r = f for b in basis: a, r = r.quo_rem(b) comps.append(a) assert r == 0 return comps def comp(comps, basis): return sum(a*b for a, b in zip(comps, basis)) original_f = y - 2*x assert comp(decomp(original_f, basis), basis) == original_f # P = (a, b) # y² = x³ + Ax + B # (y - b)(y + b) = (x - a)³ + C(3,2)a(x - a)² + (3a² + A)(x - a) # # sage: ((x - a)^3 + binomial(3,2)*a*(x - a)^2 + (3*a^2 + A)*(x - a)).expand() # -a^3 + x^3 - A*a + A*x # But since (a, b) ∈ E(K) => b² = a³ + Aa + B # => B = b² - (a³ + Aa) # # So at every step we replace the component for (y - Py) # with the reduction to the component for (x - Px) EC_A = 4 EC_B = 0 EC = y^2 - x^3 - EC_A*x - EC_B # so we can replace (y - Py) with this b0, b1, b2 = basis Ef = b0^2 + binomial(3,2)*Px*b0^1 + (3*Px^2 + EC_A) Eg = (y + Py) assert EC == b1*Eg - b0*Ef # f / g # Technically we don't need g but we keep track of it anyway def apply_reduction(f, g, basis): #a1 = f[1] #f[1] = 0 b0, b1, _ = basis # b1 == b0 * f / g # so we can replace c b1 with (cf/g) b0 # a2 = 0 assert f[2] == 0 # note that # b1 = (f/g) b0 # so # x = a0 b0 + a1 b1 + 0 b2 # = (a0 + a1 f/g) b0 # let a0 = p/q # x = (pg + a1 f) # ----------- b0 # qg f[0] = f[0]*Eg + f[1]*Ef f[1] = 0 g[0] *= Eg k = 1 table = [] table.append(("", "f", "g", "k")) def log(step_name, f, g, k): table.append((step_name, str(f), str(g), k)) f = decomp(original_f, basis) g = [1] log("start", f, g, k) # Reduce apply_reduction(f, g, basis) log("reduce", f, g, k) f = f[0] # Decompose f = decomp(f, basis) log("decomp", f, g, k) assert comp(f, basis) == (x - 2)^2 - 5*(x - 2) - 2*(y - 4) assert f[2] == 0 k += 1 # Reduce apply_reduction(f, g, basis) log("reduce", f, g, k) f = f[0] # Decompose f = decomp(f, basis) log("decomp", f, g, k) # Program terminates because remainder is nonzero assert f[2] != 0 print(f"basis = {basis}") print(tabulate(table)) print(f"k = {k}") # Test final value is correct S = K.quotient(y^2 - x^3 - 4*x).fraction_field() f0, f1, f2 = f f = f0*b0 + f1*b1 + f2*b2 g = g[0] fprime = b0^k * f/g assert fprime == S(original_f) # to convert fprime back again: # f, g = fprime.numerator().lift(), fprime.denominator().lift() # to get the parent ring use: # f.parent() # to move up the hierarchy # S.ring().cover_ring() assert g(Px, Py) != 0 assert f(Px, Py) != 0 assert b0(Px, Py) == 0