예제 #1
0
    def generate(R, P, G, B):
        while R:
            h = normal(F[R.pop()], G | P)

            if h is not None:
                k, LM = h

                G0 = set(g for g in G if monomial_div(sdp_LM(F[g], u), LM))
                P0 = set(p for p in P if monomial_div(sdp_LM(F[p], u), LM))

                G, P, R = G - G0, P - P0 | set([k]), R | G0 | P0

                for i, j in set(B):
                    if i in G0 or j in G0:
                        del B[(i, j)]

        G |= P

        for i in G:
            for j in P:
                if i == j:
                    continue

                if i < j:
                   k = (i, j)
                else:
                   k = (j, i)

                if k not in B:
                    B[k] = monomial_lcm(sdp_LM(F[i], u), sdp_LM(F[j], u))

        G = set([ normal(F[g], G - set([g]))[0] for g in G ])

        return R, P, G, B
예제 #2
0
def critical_pair(f, g, ring):
    """
    Compute the critical pair corresponding to two labeled polynomials.

    A critical pair is a tuple (um, f, vm, g), where um and vm are
    terms such that um * f - vm * g is the S-polynomial of f and g (so,
    wlog assume um * f > vm * g).
    For performance sake, a critical pair is represented as a tuple
    (Sign(um * f), um, f, Sign(vm * g), vm, g), since um * f creates
    a new, relatively expensive object in memory, whereas Sign(um *
    f) and um are lightweight and f (in the tuple) is a reference to
    an already existing object in memory.
    """
    domain = ring.domain

    ltf = Polyn(f).LT
    ltg = Polyn(g).LT
    lt = (monomial_lcm(ltf[0], ltg[0]), domain.one)

    um = term_div(lt, ltf, domain)
    vm = term_div(lt, ltg, domain)

    # The full information is not needed (now), so only the product
    # with the leading term is considered:
    fr = lbp_mul_term(lbp(Sign(f), Polyn(f).leading_term, Num(f)), um)
    gr = lbp_mul_term(lbp(Sign(g), Polyn(g).leading_term, Num(g)), vm)

    # return in proper order, such that the S-polynomial is just
    # u_first * f_first - u_second * f_second:
    if lbp_cmp(fr, gr) == -1:
        return (Sign(gr), vm, g, Sign(fr), um, f)
    else:
        return (Sign(fr), um, f, Sign(gr), vm, g)
예제 #3
0
 def select(P):
     # normal selection strategy
     # select the pair with minimum LCM(LM(f), LM(g))
     pr = min(P,
              key=lambda pair:
              O(monomial_lcm(sdp_LM(f[pair[0]], u), sdp_LM(f[pair[1]], u))))
     return pr
예제 #4
0
    def generate(R, P, G, B):
        while R:
            h = normal(F[R.pop()], G | P)

            if h is not None:
                k, LM = h

                G0 = set(g for g in G if monomial_div(sdp_LM(F[g], u), LM))
                P0 = set(p for p in P if monomial_div(sdp_LM(F[p], u), LM))

                G, P, R = G - G0, P - P0 | set([k]), R | G0 | P0

                for i, j in set(B):
                    if i in G0 or j in G0:
                        del B[(i, j)]

        G |= P

        for i in G:
            for j in P:
                if i == j:
                    continue

                if i < j:
                    k = (i, j)
                else:
                    k = (j, i)

                if k not in B:
                    B[k] = monomial_lcm(sdp_LM(F[i], u), sdp_LM(F[j], u))

        G = set([normal(F[g], G - set([g]))[0] for g in G])

        return R, P, G, B
예제 #5
0
def sdp_lcm(f, g, u, O, K):
    """
    Computes LCM of two polynomials in `K[X]`.

    The LCM is computed as the unique generater of the intersection
    of the two ideals generated by `f` and `g`. The approach is to
    compute a Groebner basis with respect to lexicographic ordering
    of `t*f` and `(1 - t)*g`, where `t` is an unrelated variable and
    then filtering out the solution that doesn't contain `t`.

    References
    ==========

    1. [Cox97]_

    """
    from sympy.polys.groebnertools import sdp_groebner

    if not f or not g:
        return []

    if sdp_term_p(f) and sdp_term_p(g):
        monom = monomial_lcm(sdp_LM(f, u), sdp_LM(g, u))

        fc, gc = sdp_LC(f, K), sdp_LC(g, K)

        if K.has_Field:
            coeff = K.one
        else:
            coeff = K.lcm(fc, gc)

        return [(monom, coeff)]

    if not K.has_Field:
        lcm = K.one
    else:
        fc, f = sdp_primitive(f, K)
        gc, g = sdp_primitive(g, K)

        lcm = K.lcm(fc, gc)

    f_terms = tuple( ((1,) + m,  c) for m, c in f )
    g_terms = tuple( ((0,) + m,  c) for m, c in g ) \
            + tuple( ((1,) + m, -c) for m, c in g )

    F = sdp_sort(f_terms, lex)
    G = sdp_sort(g_terms, lex)

    basis = sdp_groebner([F, G], u, lex, K)

    H = [ h for h in basis if sdp_indep_p(h, 0, u) ]

    if K.is_one(lcm):
        h = [ (m[1:], c)     for m, c in H[0] ]
    else:
        h = [ (m[1:], c * lcm) for m, c in H[0] ]

    return sdp_sort(h, O)
예제 #6
0
def sdp_lcm(f, g, u, O, K):
    """
    Computes LCM of two polynomials in `K[X]`.

    The LCM is computed as the unique generater of the intersection
    of the two ideals generated by `f` and `g`. The approach is to
    compute a Groebner basis with respect to lexicographic ordering
    of `t*f` and `(1 - t)*g`, where `t` is an unrelated variable and
    then filtering out the solution that doesn't contain `t`.

    References
    ==========

    1. [Cox97]_

    """
    from sympy.polys.groebnertools import sdp_groebner

    if not f or not g:
        return []

    if sdp_term_p(f) and sdp_term_p(g):
        monom = monomial_lcm(sdp_LM(f, u), sdp_LM(g, u))

        fc, gc = sdp_LC(f, K), sdp_LC(g, K)

        if K.has_Field:
            coeff = K.one
        else:
            coeff = K.lcm(fc, gc)

        return [(monom, coeff)]

    if not K.has_Field:
        lcm = K.one
    else:
        fc, f = sdp_primitive(f, K)
        gc, g = sdp_primitive(g, K)

        lcm = K.lcm(fc, gc)

    f_terms = tuple(((1, ) + m, c) for m, c in f)
    g_terms = tuple( ((0,) + m,  c) for m, c in g ) \
            + tuple( ((1,) + m, -c) for m, c in g )

    F = sdp_sort(f_terms, lex)
    G = sdp_sort(g_terms, lex)

    basis = sdp_groebner([F, G], u, lex, K)

    H = [h for h in basis if sdp_indep_p(h, 0, u)]

    if K.is_one(lcm):
        h = [(m[1:], c) for m, c in H[0]]
    else:
        h = [(m[1:], c * lcm) for m, c in H[0]]

    return sdp_sort(h, O)
예제 #7
0
def groebner_lcm(f, g):
    """
    Computes LCM of two polynomials using Groebner bases.

    The LCM is computed as the unique generater of the intersection
    of the two ideals generated by `f` and `g`. The approach is to
    compute a Groebner basis with respect to lexicographic ordering
    of `t*f` and `(1 - t)*g`, where `t` is an unrelated variable and
    then filtering out the solution that doesn't contain `t`.

    References
    ==========

    1. [Cox97]_

    """
    assert f.ring == g.ring

    ring = f.ring
    domain = ring.domain

    if not f or not g:
        return ring.zero

    if len(f) <= 1 and len(g) <= 1:
        monom = monomial_lcm(f.LM, g.LM)
        coeff = domain.lcm(f.LC, g.LC)
        return ring.term_new(monom, coeff)

    fc, f = f.primitive()
    gc, g = g.primitive()

    lcm = domain.lcm(fc, gc)

    f_terms = [ ((1,) + monom, coeff) for monom, coeff in f.terms() ]
    g_terms = [ ((0,) + monom, coeff) for monom, coeff in g.terms() ] \
            + [ ((1,) + monom,-coeff) for monom, coeff in g.terms() ]

    t = Dummy("t")
    t_ring = ring.clone(symbols=(t,) + ring.symbols, order=lex)

    F = t_ring.from_terms(f_terms)
    G = t_ring.from_terms(g_terms)

    basis = groebner([F, G], t_ring)

    def is_independent(h, j):
        return all(not monom[j] for monom in h.monoms())

    H = [ h for h in basis if is_independent(h, 0) ]

    h_terms = [ (monom[1:], coeff*lcm) for monom, coeff in H[0].terms() ]
    h = ring.from_terms(h_terms)

    return h
예제 #8
0
def sdp_spoly(p1, p2, u, O, K):
    """
    Compute LCM(LM(p1), LM(p2))/LM(p1)*p1 - LCM(LM(p1), LM(p2))/LM(p2)*p2
    """
    LM1 = sdp_LM(p1, u)
    LM2 = sdp_LM(p2, u)
    LCM12 = monomial_lcm(LM1, LM2)
    m1 = monomial_div(LCM12, LM1)
    m2 = monomial_div(LCM12, LM2)
    s1 = sdp_mul_term(p1, (m1, K.one), u, O, K)
    s2 = sdp_mul_term(p2, (m2, K.one), u, O, K)
    s = sdp_sub(s1, s2, u, O, K)
    return s
예제 #9
0
def sdp_spoly(p1, p2, u, O, K):
    """
    Compute LCM(LM(p1), LM(p2))/LM(p1)*p1 - LCM(LM(p1), LM(p2))/LM(p2)*p2
    """
    LM1 = sdp_LM(p1, u)
    LM2 = sdp_LM(p2, u)
    LCM12 = monomial_lcm(LM1, LM2)
    m1 = monomial_div(LCM12, LM1)
    m2 = monomial_div(LCM12, LM2)
    s1 = sdp_mul_term(p1, (m1, K.one), u, O, K)
    s2 = sdp_mul_term(p2, (m2, K.one), u, O, K)
    s = sdp_sub(s1, s2, u, O, K)
    return s
예제 #10
0
def sdm_spoly(f, g, O, K, phantom=None):
    """
    Compute the generalized s-polynomial of ``f`` and ``g``.

    The ground field is assumed to be ``K``, and monomials ordered according to
    ``O``.

    This is invalid if either of ``f`` or ``g`` is zero.

    If the leading terms of `f` and `g` involve different basis elements of
    `F`, their s-poly is defined to be zero. Otherwise it is a certain linear
    combination of `f` and `g` in which the leading terms cancel.
    See [SCA, defn 2.3.6] for details.

    If ``phantom`` is not ``None``, it should be a pair of module elements on
    which to perform the same operation(s) as on ``f`` and ``g``. The in this
    case both results are returned.

    Examples
    ========

    >>> from sympy.polys.distributedmodules import sdm_spoly
    >>> from sympy.polys import QQ, lex
    >>> f = [((2, 1, 1), QQ(1)), ((1, 0, 1), QQ(1))]
    >>> g = [((2, 3, 0), QQ(1))]
    >>> h = [((1, 2, 3), QQ(1))]
    >>> sdm_spoly(f, h, lex, QQ)
    []
    >>> sdm_spoly(f, g, lex, QQ)
    [((1, 2, 1), 1/1)]
    """
    if not f or not g:
        return sdm_zero()
    LM1 = sdm_LM(f)
    LM2 = sdm_LM(g)
    if LM1[0] != LM2[0]:
        return sdm_zero()
    LM1 = LM1[1:]
    LM2 = LM2[1:]
    lcm = monomial_lcm(LM1, LM2)
    m1 = monomial_div(lcm, LM1)
    m2 = monomial_div(lcm, LM2)
    c = K.quo(-sdm_LC(f, K), sdm_LC(g, K))
    r1 = sdm_add(sdm_mul_term(f, (m1, K.one), O, K),
                 sdm_mul_term(g, (m2, c), O, K), O, K)
    if phantom is None:
        return r1
    r2 = sdm_add(sdm_mul_term(phantom[0], (m1, K.one), O, K),
                 sdm_mul_term(phantom[1], (m2, c), O, K), O, K)
    return r1, r2
예제 #11
0
def spoly(p1, p2):
    """
    Compute LCM(LM(p1), LM(p2))/LM(p1)*p1 - LCM(LM(p1), LM(p2))/LM(p2)*p2
    This is the S-poly provided p1 and p2 are monic
    """
    LM1 = p1.LM
    LM2 = p2.LM
    LCM12 = monomial_lcm(LM1, LM2)
    m1 = monomial_div(LCM12, LM1)
    m2 = monomial_div(LCM12, LM2)
    s1 = p1.mul_monom(m1)
    s2 = p2.mul_monom(m2)
    s = s1 - s2
    return s
예제 #12
0
def sdm_monomial_lcm(A, B):
    """
    Return the "least common multiple" of ``A`` and ``B``.

    IF `A = M e_j` and `B = N e_j`, where `M` and `N` are polynomial monomials,
    this returns `\lcm(M, N) e_j`. Note that ``A`` and ``B`` involve distinct
    monomials.

    Otherwise the result is undefined.

    >>> from sympy.polys.distributedmodules import sdm_monomial_lcm
    >>> sdm_monomial_lcm((1, 2, 3), (1, 0, 5))
    (1, 2, 5)
    """
    return (A[0],) + monomial_lcm(A[1:], B[1:])
예제 #13
0
def S_poly(tp1, tp2):
    """expv1,p1 = tp1 with expv1 = p1.leading_expv(), p1 monic; 
    similarly for tp2.
    Compute LCM(LM(p1),LM(p2))/LM(p1)*p1 - LCM(LM(p1),LM(p2))/LM(p2)*p2
    Throw LPolyOverflowError if bits_exp is too small for the result.
    """
    expv1, p1 = tp1
    expv2, p2 = tp2
    lp = p1.lp
    lcm12 = monomial_lcm(expv1, expv2)
    m1 = monomial_div(lcm12, expv1)
    m2 = monomial_div(lcm12, expv2)
    # TODO oprimize
    res = Poly(lp)
    res.iadd_m_mul_q(p1, (m1, 1))
    res.iadd_m_mul_q(p2, (m2, -1))
    return res
예제 #14
0
 def prune(P, S, h):
     """
     Prune the pair-set by applying the chain criterion
     [SCA, remark 2.5.11].
     """
     remove = set()
     for (a, b, c) in permutations(S, 3):
         A = sdm_LM(a)
         B = sdm_LM(b)
         C = sdm_LM(c)
         if len(set([A[0], B[0], C[0]])) != 1 or not h in [a, b, c]:
             continue
         if monomial_divides(B[1:], monomial_lcm(A[1:], C[1:])):
             remove.add((tuple(a), tuple(c)))
     return [(f, g) for (f, g) in P if (h not in [f, g]) or \
                 ((tuple(f), tuple(g)) not in remove and \
                  (tuple(g), tuple(f)) not in remove)]
예제 #15
0
파일: lgroebner.py 프로젝트: pernici/sympy
def S_poly(tp1, tp2):
    """expv1,p1 = tp1 with expv1 = p1.leading_expv(), p1 monic; 
    similarly for tp2.
    Compute LCM(LM(p1),LM(p2))/LM(p1)*p1 - LCM(LM(p1),LM(p2))/LM(p2)*p2
    Throw LPolyOverflowError if bits_exp is too small for the result.
    """
    expv1, p1 = tp1
    expv2, p2 = tp2
    lp = p1.lp
    lcm12 = monomial_lcm(expv1, expv2)
    m1 = monomial_div(lcm12, expv1)
    m2 = monomial_div(lcm12, expv2)
    # TODO oprimize
    res = Poly(lp)
    res.iadd_m_mul_q(p1, (m1, 1))
    res.iadd_m_mul_q(p2, (m2, -1))
    return res
예제 #16
0
 def prune(P, S, h):
     """
     Prune the pair-set by applying the chain criterion
     [SCA, remark 2.5.11].
     """
     remove = set()
     retain = set()
     for (a, b, c) in permutations(S, 3):
         A = sdm_LM(a)
         B = sdm_LM(b)
         C = sdm_LM(c)
         if len(set([A[0], B[0], C[0]])) != 1 or not h in [a, b, c] or \
            any(tuple(x) in retain for x in [a, b, c]):
             continue
         if monomial_divides(B[1:], monomial_lcm(A[1:], C[1:])):
             remove.add((tuple(a), tuple(c)))
             retain.update([tuple(b), tuple(c), tuple(a)])
     return [(f, g) for (f, g) in P if (h not in [f, g]) or \
                 ((tuple(f), tuple(g)) not in remove and \
                  (tuple(g), tuple(f)) not in remove)]
예제 #17
0
def sdm_spoly(f, g, O, K):
    """
    Compute the generalized s-polynomial of ``f`` and ``g``.

    The ground field is assumed to be ``K``, and monomials ordered according to
    ``O``.

    This is invalid if either of ``f`` or ``g`` is zero.

    If the leading terms of `f` and `g` involve different basis elements of
    `F`, their s-poly is defined to be zero. Otherwise it is a certain linear
    combination of `f` and `g` in which the leading terms cancel.
    See [SCA, defn 2.3.6] for details.

    Examples
    ========

    >>> from sympy.polys.distributedmodules import sdm_spoly
    >>> from sympy.polys import QQ, lex
    >>> f = [((2, 1, 1), QQ(1)), ((1, 0, 1), QQ(1))]
    >>> g = [((2, 3, 0), QQ(1))]
    >>> h = [((1, 2, 3), QQ(1))]
    >>> sdm_spoly(f, h, lex, QQ)
    []
    >>> sdm_spoly(f, g, lex, QQ)
    [((1, 2, 1), 1/1)]
    """
    if not f or not g:
        return sdm_zero()
    LM1 = sdm_LM(f)
    LM2 = sdm_LM(g)
    if LM1[0] != LM2[0]:
        return sdm_zero()
    LM1 = LM1[1:]
    LM2 = LM2[1:]
    lcm = monomial_lcm(LM1, LM2)
    return sdm_add(
        sdm_mul_term(f, (monomial_div(lcm, LM1), K.one), O, K),
        sdm_mul_term(
            g, (monomial_div(lcm, LM2), K.quo(-sdm_LC(f, K), sdm_LC(g, K))), O,
            K), O, K)
예제 #18
0
def sdm_spoly(f, g, O, K):
    """
    Compute the generalized s-polynomial of ``f`` and ``g``.

    The ground field is assumed to be ``K``, and monomials ordered according to
    ``O``.

    This is invalid if either of ``f`` or ``g`` is zero.

    If the leading terms of `f` and `g` involve different basis elements of
    `F`, their s-poly is defined to be zero. Otherwise it is a certain linear
    combination of `f` and `g` in which the leading terms cancel.
    See [SCA, defn 2.3.6] for details.

    Examples
    ========

    >>> from sympy.polys.distributedmodules import sdm_spoly
    >>> from sympy.polys import QQ, lex
    >>> f = [((2, 1, 1), QQ(1)), ((1, 0, 1), QQ(1))]
    >>> g = [((2, 3, 0), QQ(1))]
    >>> h = [((1, 2, 3), QQ(1))]
    >>> sdm_spoly(f, h, lex, QQ)
    []
    >>> sdm_spoly(f, g, lex, QQ)
    [((1, 2, 1), 1/1)]
    """
    if not f or not g:
        return sdm_zero()
    LM1 = sdm_LM(f)
    LM2 = sdm_LM(g)
    if LM1[0] != LM2[0]:
        return sdm_zero()
    LM1 = LM1[1:]
    LM2 = LM2[1:]
    lcm = monomial_lcm(LM1, LM2)
    return sdm_add(sdm_mul_term(f, (monomial_div(lcm, LM1), K.one), O, K),
                   sdm_mul_term(g, (monomial_div(lcm, LM2),
                                    K.quo(-sdm_LC(f, K), sdm_LC(g, K))), O, K),
                   O, K)
예제 #19
0
def test_monomial_lcm():
    assert monomial_lcm((3,4,1), (1,2,0)) == (3,4,1)
예제 #20
0
 def lcm_divides(ip):
     # LCM(LM(h), LM(p)) divides LCM(LM(h), LM(g))
     m = monomial_lcm(mh, sdp_LM(f[ip], u))
     return monomial_div(LCMhg, m)
예제 #21
0
 def select(P):
     # normal selection strategy
     # select the pair with minimum LCM(LM(f), LM(g))
     pr = min(P, key=lambda pair: O(monomial_lcm(sdp_LM(f[pair[0]], u), sdp_LM(f[pair[1]], u))))
     return pr
예제 #22
0
 def lcm_divides(ip):
     # LCM(LM(h), LM(p)) divides LCM(LM(h), LM(g))
     m = monomial_lcm(mh, sdp_LM(f[ip], u))
     return monomial_div(LCMhg, m)
예제 #23
0
    def update(G, B, ih):
        # update G using the set of critical pairs B and h
        # [BW] page 230
        h = f[ih]
        mh = sdp_LM(h, u)

        # filter new pairs (h, g), g in G
        C = G.copy()
        D = set()

        while C:
            # select a pair (h, g) by popping an element from C
            ig = C.pop()
            g = f[ig]
            mg = sdp_LM(g, u)
            LCMhg = monomial_lcm(mh, mg)

            def lcm_divides(ip):
                # LCM(LM(h), LM(p)) divides LCM(LM(h), LM(g))
                m = monomial_lcm(mh, sdp_LM(f[ip], u))
                return monomial_div(LCMhg, m)

            # HT(h) and HT(g) disjoint: mh*mg == LCMhg
            if monomial_mul(mh, mg) == LCMhg or (
                not any(lcm_divides(ipx) for ipx in C) and not any(lcm_divides(pr[1]) for pr in D)
            ):
                D.add((ih, ig))

        E = set()

        while D:
            # select h, g from D (h the same as above)
            ih, ig = D.pop()
            mg = sdp_LM(f[ig], u)
            LCMhg = monomial_lcm(mh, mg)

            if not monomial_mul(mh, mg) == LCMhg:
                E.add((ih, ig))

        # filter old pairs
        B_new = set()

        while B:
            # select g1, g2 from B (-> CP)
            ig1, ig2 = B.pop()
            mg1 = sdp_LM(f[ig1], u)
            mg2 = sdp_LM(f[ig2], u)
            LCM12 = monomial_lcm(mg1, mg2)

            # if HT(h) does not divide lcm(HT(g1), HT(g2))
            if not monomial_div(LCM12, mh) or monomial_lcm(mg1, mh) == LCM12 or monomial_lcm(mg2, mh) == LCM12:
                B_new.add((ig1, ig2))

        B_new |= E

        # filter polynomials
        G_new = set()

        while G:
            ig = G.pop()
            mg = sdp_LM(f[ig], u)

            if not monomial_div(mg, mh):
                G_new.add(ig)

        G_new.add(ih)

        return G_new, B_new
예제 #24
0
def sdm_groebner(G, NF, O, K):
    """
    Compute a minimal standard basis of ``G`` with respect to order ``O``.

    The algorithm uses a normal form ``NF``, for example ``sdm_nf_mora``.
    The ground field is assumed to be ``K``, and monomials ordered according
    to ``O``.

    Let `N` denote the submodule generated by elements of `G`. A standard
    basis for `N` is a subset `S` of `N`, such that `in(S) = in(N)`, where for
    any subset `X` of `F`, `in(X)` denotes the submodule generated by the
    initial forms of elements of `X`. [SCA, defn 2.3.2]

    A standard basis is called minimal if no subset of it is a standard basis.

    One may show that standard bases are always generating sets.

    Minimal standard bases are not unique. This algorithm computes a
    deterministic result, depending on the particular order of `G`.

    See [SCA, algorithm 2.3.8, and remark 1.6.3].
    """
    # First compute a standard basis
    S = [f for f in G if f]
    P = list(combinations(S, 2))

    def prune(P, S, h):
        """
        Prune the pair-set by applying the chain criterion
        [SCA, remark 2.5.11].
        """
        remove = set()
        retain = set()
        for (a, b, c) in permutations(S, 3):
            A = sdm_LM(a)
            B = sdm_LM(b)
            C = sdm_LM(c)
            if len(set([A[0], B[0], C[0]])) != 1 or not h in [a, b, c] or \
               any(tuple(x) in retain for x in [a, b, c]):
                continue
            if monomial_divides(B[1:], monomial_lcm(A[1:], C[1:])):
                remove.add((tuple(a), tuple(c)))
                retain.update([tuple(b), tuple(c), tuple(a)])
        return [(f, g) for (f, g) in P if (h not in [f, g]) or \
                    ((tuple(f), tuple(g)) not in remove and \
                     (tuple(g), tuple(f)) not in remove)]

    while P:
        # TODO better data structures!!!
        #print len(P), len(S)
        # Use the "normal selection strategy"
        lcms = [(i, sdm_LM(f)[:1] + monomial_lcm(sdm_LM(f)[1:], sdm_LM(g)[1:])) for \
                i, (f, g) in enumerate(P)]
        i = min(lcms, key=lambda x: O(x[1]))[0]
        f, g = P.pop(i)
        h = NF(sdm_spoly(f, g, O, K), S, O, K)
        if h:
            S.append(h)
            P.extend((h, f) for f in S if sdm_LM(h)[0] == sdm_LM(f)[0])
            P = prune(P, S, h)

    # Now interreduce it. (TODO again, better data structures)
    S = set(tuple(f) for f in S)
    for a, b in permutations(S, 2):
        A = sdm_LM(list(a))
        B = sdm_LM(list(b))
        if sdm_monomial_divides(A, B) and b in S and a in S:
            S.remove(b)

    return sorted((list(f) for f in S),
                  key=lambda f: O(sdm_LM(f)),
                  reverse=True)
예제 #25
0
    def update(G, B, ih):
        # update G using the set of critical pairs B and h
        # [BW] page 230
        h = f[ih]
        mh = sdp_LM(h, u)

        # filter new pairs (h, g), g in G
        C = G.copy()
        D = set()

        while C:
            # select a pair (h, g) by popping an element from C
            ig = C.pop()
            g = f[ig]
            mg = sdp_LM(g, u)
            LCMhg = monomial_lcm(mh, mg)

            def lcm_divides(ip):
                # LCM(LM(h), LM(p)) divides LCM(LM(h), LM(g))
                m = monomial_lcm(mh, sdp_LM(f[ip], u))
                return monomial_div(LCMhg, m)

            # HT(h) and HT(g) disjoint: mh*mg == LCMhg
            if monomial_mul(mh, mg) == LCMhg or (not any(
                    lcm_divides(ipx)
                    for ipx in C) and not any(lcm_divides(pr[1]) for pr in D)):
                D.add((ih, ig))

        E = set()

        while D:
            # select h, g from D (h the same as above)
            ih, ig = D.pop()
            mg = sdp_LM(f[ig], u)
            LCMhg = monomial_lcm(mh, mg)

            if not monomial_mul(mh, mg) == LCMhg:
                E.add((ih, ig))

        # filter old pairs
        B_new = set()

        while B:
            # select g1, g2 from B (-> CP)
            ig1, ig2 = B.pop()
            mg1 = sdp_LM(f[ig1], u)
            mg2 = sdp_LM(f[ig2], u)
            LCM12 = monomial_lcm(mg1, mg2)

            # if HT(h) does not divide lcm(HT(g1), HT(g2))
            if not monomial_div(LCM12, mh) or \
                monomial_lcm(mg1, mh) == LCM12 or \
                monomial_lcm(mg2, mh) == LCM12:
                B_new.add((ig1, ig2))

        B_new |= E

        # filter polynomials
        G_new = set()

        while G:
            ig = G.pop()
            mg = sdp_LM(f[ig], u)

            if not monomial_div(mg, mh):
                G_new.add(ig)

        G_new.add(ih)

        return G_new, B_new
예제 #26
0
 def lcm_divides(ip):
     # LCM(LM(h), LM(p)) divides LCM(LM(h), LM(g))
     m = monomial_lcm(mh, f[ip].LM)
     return monomial_div(LCMhg, m)
예제 #27
0
def test_monomial_lcm():
    assert monomial_lcm((3, 4, 1), (1, 2, 0)) == (3, 4, 1)
예제 #28
0
 def select(P):
     # normal selection strategy
     # select the pair with minimum LCM(LM(f), LM(g))
     pr = min(P, key=lambda pair: order(monomial_lcm(f[pair[0]].LM, f[pair[1]].LM)))
     return pr
예제 #29
0
 def select(P):
     # normal selection strategy
     # select the pair with minimum LCM(LM(f), LM(g))
     pr = minkey(P, key=lambda (i, j): O(monomial_lcm(sdp_LM(f[i], u), sdp_LM(f[j], u))))
     return pr
예제 #30
0
 def select(P):
     # select the pair with minimum LCM(LM(f), LM(g))
     pr = min(P, key=lambda (i, j): O(monomial_lcm(sdp_LM(f[i], u), sdp_LM(f[j], u))))
     return pr
예제 #31
0
def sdm_groebner(G, NF, O, K):
    """
    Compute a minimal standard basis of ``G`` with respect to order ``O``.

    The algorithm uses a normal form ``NF``, for example ``sdm_nf_mora``.
    The ground field is assumed to be ``K``, and monomials ordered according
    to ``O``.

    Let `N` denote the submodule generated by elements of `G`. A standard
    basis for `N` is a subset `S` of `N`, such that `in(S) = in(N)`, where for
    any subset `X` of `F`, `in(X)` denotes the submodule generated by the
    initial forms of elements of `X`. [SCA, defn 2.3.2]

    A standard basis is called minimal if no subset of it is a standard basis.

    One may show that standard bases are always generating sets.

    Minimal standard bases are not unique. This algorithm computes a
    deterministic result, depending on the particular order of `G`.

    See [SCA, algorithm 2.3.8, and remark 1.6.3].
    """
    # First compute a standard basis
    S = [f for f in G if f]
    P = list(combinations(S, 2))

    def prune(P, S, h):
        """
        Prune the pair-set by applying the chain criterion
        [SCA, remark 2.5.11].
        """
        remove = set()
        retain = set()
        for (a, b, c) in permutations(S, 3):
            A = sdm_LM(a)
            B = sdm_LM(b)
            C = sdm_LM(c)
            if len(set([A[0], B[0], C[0]])) != 1 or not h in [a, b, c] or \
               any(tuple(x) in retain for x in [a, b, c]):
                continue
            if monomial_divides(B[1:], monomial_lcm(A[1:], C[1:])):
                remove.add((tuple(a), tuple(c)))
                retain.update([tuple(b), tuple(c), tuple(a)])
        return [(f, g) for (f, g) in P if (h not in [f, g]) or \
                    ((tuple(f), tuple(g)) not in remove and \
                     (tuple(g), tuple(f)) not in remove)]

    while P:
        # TODO better data structures!!!
        #print len(P), len(S)
        # Use the "normal selection strategy"
        lcms = [(i, sdm_LM(f)[:1] + monomial_lcm(sdm_LM(f)[1:], sdm_LM(g)[1:])) for \
                i, (f, g) in enumerate(P)]
        i = min(lcms, key=lambda x: O(x[1]))[0]
        f, g = P.pop(i)
        h = NF(sdm_spoly(f, g, O, K), S, O, K)
        if h:
            S.append(h)
            P.extend((h, f) for f in S if sdm_LM(h)[0] == sdm_LM(f)[0])
            P = prune(P, S, h)

    # Now interreduce it. (TODO again, better data structures)
    S = set(tuple(f) for f in S)
    for a, b in permutations(S, 2):
        A = sdm_LM(list(a))
        B = sdm_LM(list(b))
        if sdm_monomial_divides(A, B) and b in S and a in S:
            S.remove(b)

    return sorted((list(f) for f in S), key=lambda f: O(sdm_LM(f)),
                  reverse=True)
예제 #32
0
 def select(P):
     # select the pair with minimum LCM(LM(f), LM(g))
     pr = min(P,
              key=lambda
              (i, j): O(monomial_lcm(sdp_LM(f[i], u), sdp_LM(f[j], u))))
     return pr