Exemplo n.º 1
0
    def test__get_wmon_lst_1m4(self):

        if not self.mathematica_is_installed():
            print(
                'test__get_wmon_lst is not tested, since mathematica is not installed'
            )
            return

        g_lst = ring('u0,u1,u2,u3,u4')
        w_lst = [(0, 1), (0, 1), (1, -3), (1, -2), (1, -2)]

        out = SERing.get_wmon_lst(g_lst, w_lst, 1, -4)
        print(out)
        assert out == []
Exemplo n.º 2
0
    def test__get_wmon_lst_2m4(self):

        if not self.mathematica_is_installed():
            print(
                'test__get_wmon_lst is not tested, since mathematica is not installed'
            )
            return

        g_lst = ring('u0,u1,u2,u3,u4')
        w_lst = [(0, 1), (0, 1), (1, -3), (1, -2), (1, -2)]

        chk = ring(
            '[u3^2,u3*u4,u4^2,u0*u2*u3,u0*u2*u4,u1*u2*u3,u1*u2*u4,u0^2*u2^2,u0*u1*u2^2,u1^2*u2^2]'
        )
        out = SERing.get_wmon_lst(g_lst, w_lst, 2, -4)
        print(out)
        assert out == sorted(chk)
Exemplo n.º 3
0
def usecase_B5():
    '''
    We compute the projective isomorphism between two 
    conic bundles that are parametrized by the 
    birational maps 
    
    ff: P2 ---> X     and    gg: P1xP1 ---> Y
     
    Further explanation of this example can be found 
    in the accompanying arxiv article on projective
    isomorphisms between rational surfaces.
    '''

    # we construct linear series associated to ff in order to determine
    # the generators of the graded coordinate ring of conic bundle X

    # basepoints in chart x0!=0;
    p1 = (0, 0)
    p2 = (0, 1)
    p3 = (1, 0)

    # 0f+p = e0-e1
    PolyRing.reset_base_field()
    bp_tree = BasePointTree()
    bp_tree.add('z', p1, 1)
    f0p1 = SERing.conv(LinearSeries.get([1], bp_tree).pol_lst)
    SETools.p('f0p1 =', len(f0p1), f0p1)

    # 1f-3p = e0+e1-e2-e3
    bp_tree = BasePointTree()
    bp_tree.add('z', p2, 1)
    bp_tree.add('z', p3, 1)
    f1m3 = SERing.conv(LinearSeries.get([1], bp_tree).pol_lst)
    SETools.p('f1m3 =', len(f1m3), f1m3)

    # 1f-2p = 2e0-e2-e3
    bp_tree = BasePointTree()
    bp_tree.add('z', p2, 1)
    bp_tree.add('z', p3, 1)
    f1m2 = SERing.conv(LinearSeries.get([2], bp_tree).pol_lst)
    SETools.p('f1m2 =', len(f1m2), f1m2)

    # 1f-1p = 3e0-e1-e2-e3
    bp_tree = BasePointTree()
    bp_tree.add('z', p1, 1)
    bp_tree.add('z', p2, 1)
    bp_tree.add('z', p3, 1)
    f1m1 = SERing.conv(LinearSeries.get([3], bp_tree).pol_lst)
    SETools.p('f1m1 =', len(f1m1), f1m1)

    # 1f-0p = 4e0-2e1-e2-e3
    bp_tree = BasePointTree()
    bp_tree.add('z', p1, 2)
    bp_tree.add('z', p2, 1)
    bp_tree.add('z', p3, 1)
    f1m0 = SERing.conv(LinearSeries.get([4], bp_tree).pol_lst)
    SETools.p('f1m0 =', len(f1m0), f1m0)

    # 2f-4p = 4e0-2e2-2e3
    bp_tree = BasePointTree()
    bp_tree.add('z', p2, 2)
    bp_tree.add('z', p3, 2)
    f2m4 = SERing.conv(LinearSeries.get([4], bp_tree).pol_lst)
    SETools.p('f2m4 =', len(f2m4), f2m4)

    # by inspection we recover the generators of graded ring of ff
    U = ring('x1'), ring('x2'), ring('x1+x2-x0'), ring('x1*x2'), ring(
        '(x1+x2-x0)^2')

    # compute bidegree (2,d) in order to find a relation between the generators
    u = u0, u1, u2, u3, u4 = ring('u0,u1,u2,u3,u4')
    SETools.p(
        'Compare number of monomials of given bi-weight with dimension predicted by the Riemann-Roch formula...'
    )
    for d in reversed([-i for i in range(8)]):
        w_lst = [(0, 1), (0, 1), (1, -3), (1, -2), (1, -2)]
        SETools.p('\tweight=', (2, d), ',\t#monomials=',
                  len(SERing.get_wmon_lst(u, w_lst, 2, d)), ',\tRR=',
                  29 + 5 * d)

    # template for generators of coordinate ring for weight (2,-1) and (1,0)
    T2m4 = ring(
        '[u3^2,u3*u4,u4^2,u0*u2*u3,u0*u2*u4,u1*u2*u3,u1*u2*u4,u0^2*u2^2,u0*u1*u2^2,u1^2*u2^2]'
    )
    T1m0 = ring(
        '[u1^2*u4,u1^2*u3,u1^3*u2,u0*u1*u4,u0*u1*u3,u0*u1^2*u2,u0^2*u4,u0^2*u3,u0^2*u1*u2,u0^3*u2]'
    )
    SETools.p('T2m4 =', T2m4)
    SETools.p('T1m0 =', T1m0)

    # find linear relation for f2m4
    a = a0, a1, a2, a3, a4, a5, a6, a7, a8, a9 = [
        elt.subs({u[i]: U[i]
                  for i in range(5)}) for elt in T2m4
    ]  # @UnusedVariable
    mata = sage_matrix(sage_QQ, SERing.get_matrix_P2(a))
    kera = mata.transpose().right_kernel().matrix()
    SETools.p('kera =', kera)
    assert kera * sage_vector(a) == sage_vector([0])
    assert a1 - a8 == 0

    # construct map gg from ff
    # sage_Permutations(10).random_element().to_matrix().rows()
    ff = f1m0
    matp = [(0, 0, 0, 0, 1, 0, 0, 0, 0, 0), (0, 0, 0, 0, 0, 0, 0, 1, 0, 0),
            (0, 0, 0, 1, 0, 0, 0, 0, 0, 0), (0, 0, 0, 0, 0, 0, 0, 0, 0, 1),
            (0, 0, 0, 0, 0, 0, 1, 0, 0, 0), (0, 0, 0, 0, 0, 1, 0, 0, 0, 0),
            (0, 0, 0, 0, 0, 0, 0, 0, 1, 0), (0, 0, 1, 0, 0, 0, 0, 0, 0, 0),
            (0, 1, 0, 0, 0, 0, 0, 0, 0, 0), (1, 0, 0, 0, 0, 0, 0, 0, 0, 0)]
    matp = sage_matrix(matp)
    x0, x1, x2, y0, y1, y2, y3 = ring(
        'x0,x1,x2,y0,y1,y2,y3')  # P2(x0:x1:x2) and P1xP1(y0:y1;y2:y3)
    gg = [comp.subs({x0: y1 * y3, x1: y0 * y2, x2: y1 * y2}) for comp in ff]
    gg = list(matp * sage_vector(gg))
    gcd_gg = sage_gcd(gg)
    gg = [comp / gcd_gg for comp in gg]
    SETools.p('gcd_gg =', gcd_gg)
    SETools.p('ff     =', len(ff), ff)
    SETools.p('gg     =', len(gg), gg)

    # we construct linear series associated to gg in order to determine
    # the generators of the graded coordinate ring of conic bundle Y

    # determine and set basepoint tree
    ls = LinearSeries(SERing.conv(gg), PolyRing('x,y,v,w'))
    bp_tree = ls.get_bp_tree()
    SETools.p('bp_tree(gg) =', bp_tree)
    tree_211 = BasePointTree(['xv', 'xw', 'yv', 'yw'])
    tree_211.add('xw', (0, 0), 2).add('t', (1, 0), 1)
    tree_211.add('yv', (0, 1), 1)

    # 1g+0q = 4l0+2l1-2e1-e2-e3
    g1m0 = SERing.conv(LinearSeries.get([4, 2], tree_211).pol_lst)
    SETools.p('g1m0 =', len(g1m0), g1m0)

    # 1g-3q = (l0+l1-e1-e2-e3) + (b-e1)
    g1m3 = SERing.conv(LinearSeries.get([1, 2], tree_211).pol_lst)
    SETools.p('g1m3 =', len(g1m3), g1m3)

    # 1g-2q = 2l0+2l1-2e1-e2-e3
    g1m2 = SERing.conv(LinearSeries.get([2, 2], tree_211).pol_lst)
    SETools.p('g1m2 =', len(g1m2), g1m2)

    # 1g-1q = 3l0+2l1-2e1-e2-e3
    g1m1 = SERing.conv(LinearSeries.get([3, 2], tree_211).pol_lst)
    SETools.p('g1m1 =', len(g1m1), g1m1)

    # 2g-4q = 4l0+4l1-4e1-2e2-2e3
    tree_422 = BasePointTree(['xv', 'xw', 'yv', 'yw'])
    tree_422.add('xw', (0, 0), 4).add('t', (1, 0), 2)
    tree_422.add('yv', (0, 1), 2)
    g2m4 = SERing.conv(LinearSeries.get([4, 4], tree_422).pol_lst)
    SETools.p('g2m4 =', len(g2m4), g2m4)

    # by inspection we recover the generators of graded ring of gg
    V = ring('y0'), ring('y1'), ring('y0*y2^2+y1*y2^2-y1*y2*y3'), ring(
        'y0*y1*y2^2'), ring('y0^2*y2^2+y1^2*y2^2-y1^2*y3^2')

    # find linear relation for g2m4
    b = b0, b1, b2, b3, b4, b5, b6, b7, b8, b9 = [
        elt.subs({u[i]: V[i]
                  for i in range(5)}) for elt in T2m4
    ]  # @UnusedVariable
    matb = sage_matrix(sage_QQ, SERing.get_matrix_P1xP1(b))
    kerb = matb.transpose().right_kernel().matrix()
    SETools.p('kerb =', kerb)
    assert kerb * sage_vector(b) == sage_vector([0])
    assert 2 * b0 + b1 - 2 * b3 - 2 * b5 + b8 == 0

    # compute inverse of G
    G = [elt.subs({u[i]: V[i] for i in range(5)}) for elt in T1m0]
    z = ring('z0,z1,z2,z3,z4,z5,z6,z7,z8,z9')
    t = ring('t')
    ide = [G[i] * z[0] - z[i] * G[0] for i in range(10)] + [t * G[0] - 1]
    I01 = sage_ideal(ide).elimination_ideal([t, y2, y3]).gens()
    I23 = sage_ideal(ide).elimination_ideal([t, y0, y1]).gens()
    I01 = [elt for elt in I01
           if elt.degree(y0) == 1 and elt.degree(y1) == 1][0]
    I23 = [elt for elt in I23
           if elt.degree(y2) == 1 and elt.degree(y3) == 1][0]
    Q0 = I01.coefficient(y1)
    Q1 = -I01.coefficient(y0)
    Q2 = I23.coefficient(y3)
    Q3 = -I23.coefficient(y2)
    Q = [Q0, Q1, Q2, Q3]
    SETools.p('Q =', Q)  # [-z9, -z8, -z8, -z6 - 2*z7 + z8 + z9]

    # check the inverse
    QoG = [q.subs({z[i]: G[i] for i in range(10)}) for q in Q]
    gcd01 = sage_gcd(QoG[0], QoG[1])
    gcd23 = sage_gcd(QoG[2], QoG[3])
    QoG = [QoG[0] / gcd01, QoG[1] / gcd01, QoG[2] / gcd23, QoG[3] / gcd23]
    SETools.p('QoG =', QoG)
    assert QoG == [y0, y1, y2, y3]

    # compose F with projective isomorphism P
    c = c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12 = [
        ring('c' + str(i)) for i in range(13)
    ]
    dctZ = {u[i]: z[i] for i in range(5)}
    dctP = {
        z[0]: c0 * u0 + c1 * u1,
        z[1]: c2 * u0 + c3 * u1,
        z[2]: c4 * u2,
        z[3]: c5 * u3 + c6 * u4 + c7 * u0 * u2 + c8 * u1 * u2,
        z[4]: c9 * u3 + c10 * u4 + c11 * u0 * u2 + c12 * u1 * u2
    }
    PoF = [comp.subs(dctZ).subs(dctP) for comp in T1m0]
    PoF = [comp.subs({u[i]: U[i] for i in range(5)}) for comp in PoF]
    PoF = [comp / sage_gcd(PoF) for comp in PoF]
    SETools.p('PoF =', len(PoF), PoF)

    # compose PoF with Q
    QoPoF = [comp.subs({z[i]: PoF[i] for i in range(10)}) for comp in Q]
    gcd01 = sage_gcd(QoPoF[0], QoPoF[1])
    gcd23 = sage_gcd(QoPoF[2], QoPoF[3])
    QoPoF = [
        QoPoF[0] / gcd01, QoPoF[1] / gcd01, QoPoF[2] / gcd23, QoPoF[3] / gcd23
    ]
    SETools.p('QoPoF =', len(QoPoF), QoPoF)

    # create a list of equations for the ci
    b = T2m4
    rel_g4m2 = 2 * b[0] + b[1] - 2 * b[3] - 2 * b[5] + b[8]
    SETools.p('rel_g4m2 =', rel_g4m2)
    rel_g4m2 = rel_g4m2.subs(dctZ).subs(dctP).subs(
        {u[i]: U[i]
         for i in range(5)})
    SETools.p('rel_g4m2 =', rel_g4m2)
    rel_lst = []
    x = ring('[x0,x1,x2]')
    for exp in sage_Compositions(4 + 3, length=3):
        rel_lst += [rel_g4m2.coefficient({x[i]: exp[i] - 1 for i in range(3)})]
    SETools.p('rel_lst =', len(rel_lst), rel_lst)
    t = ring('t')
    rel_lst += [(c0 * c3 - c1 * c2) * c4 * (c5 * c10 - c9 * c6) * t - 1]

    # solve for ci and put the solutions in dictionary form
    prime_lst = sage_ideal(rel_lst).elimination_ideal(
        t).primary_decomposition()
    SETools.p('prime_lst =', len(prime_lst))
    for gen_lst in [prime.gens() for prime in prime_lst]:
        sol_dct = sage_solve([sage_SR(gen) for gen in gen_lst],
                             [sage_SR(elt) for elt in c],
                             solution_dict=True)
        assert len(sol_dct) == 1
        SETools.p('\t gen_lst =', gen_lst)
        SETools.p('\t sol_dct =', sol_dct[0])
    prime_lst2 = []
    prime_lst2 += [prime_lst[0].gens() + [c0 - 1, c4 - 1]]
    prime_lst2 += [prime_lst[1].gens() + [c1 - 1, c4 - 1]]
    prime_lst2 += [prime_lst[2].gens() + [c1 - 1, c4 - 1]]
    prime_lst2 += [prime_lst[3].gens() + [c0 - 1, c4 - 1]]
    SETools.p('Added equations to prime_lst to simplify solutions:')
    for gen_lst in prime_lst2:
        sol_dct = sage_solve([sage_SR(gen) for gen in gen_lst],
                             [sage_SR(elt) for elt in c],
                             solution_dict=True)
        assert len(sol_dct) == 1
        SETools.p('\t gen_lst =', gen_lst)
        SETools.p('\t sol_dct =', sol_dct[0])
    r0, r1 = ring('r0,r1')
    sol0 = {
        c0: 1,
        c1: 0,
        c2: 0,
        c3: -r0 * r1,
        c4: 1,
        c5: 0,
        c6: r0,
        c7: 0,
        c8: 0,
        c9: r1,
        c10: -2 * r0,
        c11: 2,
        c12: -2 * r0 * r1
    }
    sol1 = {
        c0: 0,
        c1: 1,
        c2: -r0 * r1,
        c3: 0,
        c4: 1,
        c5: 0,
        c6: r0,
        c7: 0,
        c8: 0,
        c9: r1,
        c10: -2 * r0,
        c11: -2 * r0 * r1,
        c12: 2
    }
    sol2 = {
        c0: 0,
        c1: 1,
        c2: -r0 * r1,
        c3: 0,
        c4: 1,
        c5: r0,
        c6: 0,
        c7: 0,
        c8: 0,
        c9: -2 * r0,
        c10: r1,
        c11: -2 * r0 * r1,
        c12: 2
    }
    sol3 = {
        c0: 1,
        c1: 0,
        c2: 0,
        c3: -r0 * r1,
        c4: 1,
        c5: r0,
        c6: 0,
        c7: 0,
        c8: 0,
        c9: -2 * r0,
        c10: r1,
        c11: 2,
        c12: -2 * r0 * r1
    }
    sol_lst = [sol0, sol1, sol2, sol3]
    SETools.p('Simplified solutions by hand:')
    for sol in sol_lst:
        SETools.p('\t', sol)

    #  compose compatible reparametrizations with gg
    y = ring('[y0,y1,y2,y3]')
    gr_lst = []
    SETools.p('Computing (gg o r) for each sol in sol_lst...')
    for sol in sol_lst:
        gr = [
            comp.subs({y[i]: QoPoF[i]
                       for i in range(4)}).subs(sol) for comp in gg
        ]
        SETools.p('\t gr =', gr)
        gcd_gr = sage_gcd(gr)
        SETools.p('\t\t gcd_gr    =', gcd_gr)
        gr_lst += [[comp / gcd_gr for comp in gr]]
        SETools.p('\t\t gr/gcd_gr =', gr_lst[-1])
    SETools.p('gr_lst =', len(gr_lst))
    for gr in gr_lst:
        SETools.p('\t gr =', gr)

    # get coefficient matrix of ff and its kernel
    mff = SERing.get_matrix_P2(ff)
    kff = mff.right_kernel_matrix().T
    SETools.p('mff =', mff.dimensions(), list(mff))
    SETools.p('kff =', kff.dimensions(), list(kff))
    assert (mff * kff).is_zero()

    # get implicit equations for image of gg
    z = ring('z0,z1,z2,z3,z4,z5,z6,z7,z8,z9')
    y = ring('y0,y1,y2,y3')
    igg = SERing.R.ideal([z[i] - gg[i] for i in range(10)
                          ]).elimination_ideal([y[i] for i in range(4)])
    SETools.p('igg =', list(igg.gens()))

    # Compute isomorphisms for each gr
    SETools.p('Compute projective isomorphism for each gr in gr_lst:')
    for gr in gr_lst:

        mgr = SERing.get_matrix_P2(gr)
        mgk = mgr * kff
        assert mgk.is_zero()  # because the surfaces in P^9 are linearly normal

        Ef = sage_matrix(sage_QQ, mff.rows() + kff.T.rows())
        Egr = sage_matrix(mgr.rows() + kff.T.rows())
        UpI = Egr * Ef.inverse()
        assert (UpI.submatrix(10, 10) - sage_identity_matrix(5)).is_zero()
        U = UpI.submatrix(0, 0, 10, 10)
        SETools.p('\tU =', U.dimensions(), list(U))

        # check if the answer is correct by substituting into the equations of Y
        Uff = list(U * sage_vector(ff))
        iggs = igg.subs({z[i]: Uff[i] for i in range(10)})
        assert iggs.is_zero()
Exemplo n.º 4
0
def usecase_B4():
    '''
    We compute the projective automorphism of the 
    rational normal scrolls that is parametrized 
    the birational map f: P2 ---> X.
     
    Further explanation of this example can be found 
    in the accompanying arxiv article on projective
    isomorphisms between rational surfaces.
    '''

    # e0-e1
    p1 = (0, 0)
    p2 = (1, 0)
    p3 = (0, 1)
    PolyRing.reset_base_field()
    bpt = BasePointTree()
    bpt.add('z', p1, 1)
    f0p1 = SERing.conv(LinearSeries.get([1], bpt).pol_lst)
    SETools.p('f0p1 =', len(f0p1), f0p1)

    # e0-e2-e3
    bpt = BasePointTree()
    bpt.add('z', p2, 1)
    bpt.add('z', p3, 1)
    f1m2 = SERing.conv(LinearSeries.get([1], bpt).pol_lst)
    SETools.p('f1m2 =', len(f1m2), f1m2)

    # 2e0-e1-e2-e3
    bpt = BasePointTree()
    bpt.add('z', p1, 1)
    bpt.add('z', p2, 1)
    bpt.add('z', p3, 1)
    f1m1 = SERing.conv(LinearSeries.get([2], bpt).pol_lst)
    SETools.p('f1m1 =', len(f1m1), f1m1)

    # 3e0-2e1-e2-e3
    bpt = BasePointTree()
    bpt.add('z', p1, 2)
    bpt.add('z', p2, 1)
    bpt.add('z', p3, 1)
    f1m0 = SERing.conv(LinearSeries.get([3], bpt).pol_lst)
    SETools.p('f1m0 =', len(f1m0), f1m0)

    # set generators for the graded coordinate ring of f
    U = [ring('x1'), ring('x2'), ring('x1+x2-x0'), ring('x1*x2')]
    u = ring('u0,u1,u2,u3')

    # obtain monomials of weight (1,0)
    w_lst = [(0, 1), (0, 1), (1, -2), (1, -1)]
    M1m0 = SERing.get_wmon_lst(u, w_lst, 1, 0)
    SETools.p('M1m0 =', len(M1m0), M1m0)

    # compose F with projective isomorphism P
    z = [ring('z' + str(i)) for i in range(6)]
    c = [ring('c' + str(i)) for i in range(8)]
    dctZ = {u[i]: z[i] for i in range(4)}
    dctP = {
        z[0]: c[0] * u[0] + c[1] * u[1],
        z[1]: c[2] * u[0] + c[3] * u[1],
        z[2]: c[4] * u[2],
        z[3]: c[5] * u[3] + c[6] * u[0] * u[2] + c[7] * u[1] * u[2]
    }
    PoF = [comp.subs(dctZ).subs(dctP) for comp in M1m0]
    SETools.p('PoF wrt u =', len(PoF), PoF)
    PoF = [comp.subs({u[i]: U[i] for i in range(4)}) for comp in PoF]
    PoF = [comp / sage_gcd(PoF) for comp in PoF]
    SETools.p('PoF =', len(PoF), PoF)

    # recover matrix for automorphism P
    F = [comp.subs({u[i]: U[i] for i in range(4)}) for comp in M1m0]
    M = []
    for pol in [comp.subs(dctZ).subs(dctP) for comp in M1m0]:
        row = []
        for mon in M1m0:
            row += [pol.coefficient(mon)]
        M += [row]
    M = sage_matrix(M)
    SETools.p('M =', M.dimensions(), '\n' + str(M))
    MF = list(M * sage_vector(F))
    assert MF == PoF

    # compute the inverse Q of F
    t = ring('t')
    x = ring('x0,x1,x2')
    ide = [F[i] * z[0] - z[i] * F[0] for i in range(5)] + [t * F[0] - 1]
    I1 = sage_ideal(ide).elimination_ideal([t, x[2]]).gens()
    I2 = sage_ideal(ide).elimination_ideal([t, x[1]]).gens()
    I1 = [
        elt for elt in I1 if elt.degree(x[0]) == 1 and elt.degree(x[1]) == 1
    ][0]
    I2 = [
        elt for elt in I2 if elt.degree(x[0]) == 1 and elt.degree(x[2]) == 1
    ][0]
    Q0 = I1.coefficient(x[1])
    Q1 = -I1.coefficient(x[0])
    Q2 = I2.coefficient(x[0])
    Q = [Q0, Q1, Q2]
    SETools.p('Q =', Q)
    QoF = [comp.subs({z[i]: F[i] for i in range(5)}) for comp in Q]
    QoF = [comp / sage_gcd(QoF) for comp in QoF]
    assert QoF == [x[0], x[1], x[2]]

    # compute the composition
    QoPoF = [comp.subs({z[i]: PoF[i] for i in range(5)}) for comp in Q]
    QoPoF = [comp / sage_gcd(QoPoF) for comp in QoPoF]
    SETools.p('QoPoF =', len(QoPoF), QoPoF)

    # from the compatible reparametrizations QoPoF we compute the
    # projective automorphisms U of X.
    f = f1m0
    gr = [comp.subs({x[i]: QoPoF[i] for i in range(3)}) for comp in f]
    gcd_gr = sage_gcd(gr)

    gr = [comp / gcd_gr for comp in gr]
    Mf = SERing.get_matrix_P2(f)
    Mgr = SERing.get_matrix_P2(gr)
    Kf = Mf.right_kernel_matrix().T
    SETools.p('f   =', len(f), f)
    SETools.p('gr  =', len(gr), gr)
    SETools.p('\t gcd_gr  =', gcd_gr)
    SETools.p('Mf  =', Mf.dimensions(), list(Mf))
    SETools.p('Mgr =', Mgr.dimensions(), list(Mgr))
    SETools.p('Kf  =', Kf.dimensions(), list(Kf))

    assert (Mf * Kf).is_zero()
    assert (Mgr * Kf).is_zero()

    Ef = sage_matrix(sage_QQ, list(Mf) + list(Kf.T))
    Egr = sage_matrix(list(Mgr) + list(Kf.T))
    UpI = Egr * ~Ef
    assert (UpI.submatrix(5, 5) - sage_identity_matrix(5)).is_zero()
    U = UpI.submatrix(0, 0, 5, 5)
    SETools.p('UpI =', UpI.dimensions(), list(UpI))
    SETools.p('U   =', U.dimensions(), list(U), '\n' + str(U))

    # verify whether U*f is a parametrization for X for all (c0,...,c7)
    Uf = list(U * sage_vector(f))
    SETools.p('Uf  =', len(Uf), Uf)
    eqX = sage_ideal([z[i] - f[i]
                      for i in range(5)]).elimination_ideal([x[0], x[1],
                                                             x[2]]).gens()
    eqXs = [eq.subs({z[i]: Uf[i] for i in range(5)}) for eq in eqX]
    SETools.p('eqX =', len(eqX), eqX)
    SETools.p('eqXs=', len(eqXs), eqXs)
    assert eqXs == [0, 0, 0]