Esempio n. 1
0
def vectorSpaceBasis(GB):
    '''
    parameters
    ----------
    GB: list
        Polynomials that make up a Groebner basis for the ideal.

    Returns
    -------
    basis : list
        tuples representing the monomials in the vector space basis
    var_to_pos_dict : dictionary
        maps each variable to its position in the vector space basis
    '''
    LT_G = [f.lead_term for f in GB]
    possibleVarDegrees = [range(max(tup)) for tup in zip(*LT_G)]
    possibleMonomials = itertools.product(*possibleVarDegrees)
    basis = []
    var_to_pos_dict = {}
    for mon in possibleMonomials:
        divisible = False
        for LT in LT_G:
            if divides(LT, mon):
                divisible = True
                break
        if not divisible:
            basis.append(mon)
            if (sum(mon) == 1) or (sum(mon) == 0):
                var_to_pos_dict[mon] = basis.index(mon)

    return basis, var_to_pos_dict
Esempio n. 2
0
def reduce_poly(poly, divisors, basisSet, permitted_round_error=1e-10):
    '''
    Divides a polynomial by a set of divisor polynomials using the standard
    multivariate division algorithm and returns the remainder
    parameters
    ----------
    poly : polynomial object
        the polynomial to be divided by the Groebner basis
    divisors : list of polynomial objects
        polynomials to divide poly by
    basisSet : set of tuples
        The monomials that make up a basis for the vector space
    returns
    -------
    polynomial object
        the remainder of poly / divisors
    '''
    remainder_shape = np.maximum.reduce([p.shape for p in divisors])
    remainder = np.zeros(remainder_shape)

    for term in zip(*np.where(poly.coeff != 0)):
        if term in basisSet:
            remainder[term] += poly.coeff[term]
            poly.coeff[term] = 0
    poly.__init__(poly.coeff, clean_zeros=False)

    # while poly is not the zero polynomial
    while np.any(poly.coeff):
        divisible = False
        # Go through polynomials in set of divisors
        for divisor in divisors:
            # If the LT of the divisor divides the LT of poly
            if divides(divisor.lead_term, poly.lead_term):
                # Get the quotient LT(poly)/LT(divisor)
                LT_quotient = np.subtract(poly.lead_term, divisor.lead_term)

                poly_to_subtract_coeff = divisor.mon_mult(LT_quotient,
                                                          returnType='Matrix')
                # Match sizes of poly_to_subtract and poly so
                # poly_to_subtract.coeff can be subtracted from poly.coeff
                poly_coeff, poly_to_subtract_coeff = match_size(
                    poly.coeff, poly_to_subtract_coeff)
                new_coeff = poly_coeff - \
                    (poly.lead_coeff/poly_to_subtract_coeff[tuple(divisor.lead_term+LT_quotient)])*poly_to_subtract_coeff

                new_coeff[np.where(
                    np.abs(new_coeff) < permitted_round_error)] = 0

                for term in zip(*np.where(new_coeff != 0)):
                    if term in basisSet:
                        remainder[term] += new_coeff[term]
                        new_coeff[term] = 0

                poly.__init__(new_coeff, clean_zeros=False)
                divisible = True
                break
    return remainder
Esempio n. 3
0
def get_good_rows(matrix, matrix_terms):
    '''
    Gets the rows in a matrix whose leading monomial is not divisible by the leading monomial of any other row.

    Parameters
    ----------
    matrix : (M,N) ndarray
        Input matrix.
    matrix_terms : array-like
        The column labels for matrix in order. Contains Term objects.

    Returns
    -------
    keys : list
        Rows indicies satisfying the divisibility condition.

    Notes
    -----
    This function could probably be improved, but for now it is good enough.
    '''
    rowLMs = dict()
    already_looked_at = set()
    #Finds the leading terms of each row.
    for i, j in zip(*np.where(matrix != 0)):
        if i in already_looked_at:
            continue
        else:
            already_looked_at.add(i)
            rowLMs[i] = matrix_terms[j]
    keys = list(rowLMs.keys())
    keys = keys[::-1]
    spot = 0
    #Uses a sieve to find which of the rows to keep.
    while spot != len(keys):
        term1 = rowLMs[keys[spot]]
        toRemove = list()
        for i in range(spot + 1, len(keys)):
            term2 = rowLMs[keys[i]]
            if divides(term1, term2):
                toRemove.append(keys[i])
        for i in toRemove:
            keys.remove(i)
        spot += 1
    return keys
Esempio n. 4
0
def calc_r(m, polys):
    '''Calculates an r polynomial that has a leading monomial m.

    Parameters
    ----------
    m : array-like
        The leading monomial that the r polynomial should have.
    polys : array-like
        Contains polynomial objects from which to create the r polynomial.

    Returns
    -------
    Polynomial or None
        If no polynomial divides m, returns None. Otherwise, returns
        the r polynomial with leading monomial m.

    Notes
    -----
    The r polynomial corresponding to m is defined as follows:

        Find a polynomial p such that the leading monomial of p divides m.
        Then the r polynomial is

        .. math::
            r = \frac{m}_{LT(p)} * p

    The reason we use r polynomials is because now any polynomial with
    m as a term will be linearly reduced by r.

    '''
    for poly in polys:
        LT_p = list(poly.lead_term)
        if len(LT_p) == len(m) and utils.divides(LT_p, m):
            quotient = utils.quotient(m, LT_p)
            if not LT_p == m:  #Make sure c isn't all 0
                return poly.mon_mult(quotient)
    return None
Esempio n. 5
0
def sort_reducible_polys(old_polys, new_polys):
    '''Finds which polynomials are reducible.
    The polynomials that are reducible aren't used in phi and r calculations, they are just added
    to the matrix. They are also removed from the poly list they are in, as whatever they are reduced
    down to will be pulled out of the matrix at the end.

    A polynomial is considered reducible if the leading term of another polynomial divides it's leading term.
    In the case of multiple polynomials having the same leading term, one is considered non-reducible and the
    rest are reducible.

    Parameters
    ----------
    old_polys : list
        The polynomails that have already gone through the reduction before.
    new_polys : list
        The polynomials that have not gone through the reduction before.

    Returns
    -------
    old_polys : list
        The old_polys that are not reducible.
    new_polys : list
        The new_polys that are not reducible.
    matrix_polys : list
        The polynomials that are being put in the matrix. Any polynomial that is reducible is put in the matrix,
        and if it is reducible because some other polynomials lead term divides it's lead term than the other
        polynomial is multiplied by th monomial needed to give it the same lead term, and that is put in the matrix.
    '''
    matrix_polys = list()

    old = old_polys
    new = new_polys
    polys = old + new

    polys = utils.sorted_polys_monomial(polys)

    old_polys = list()
    new_polys = list()

    lms = defaultdict(list)
    for p in polys:
        lms[p.lead_term].append(p)

    # This list will contain one polynomial for each leading term,
    # so all the leading terms will be unique
    polys_with_unique_lm = list()

    for i in lms:
        # If there are multiple polynomials with the same leading term
        # we add just one of them to polys_with_unique_lm and add the
        # rest to the matrix for reduction.
        if len(lms[i]) > 1:
            polys_with_unique_lm.append(lms[i][0])
            lms[i].remove(lms[i][0])
            for p in lms[i]:
                matrix_polys.append(p)
        else:
            polys_with_unique_lm.append(lms[i][0])

    divides_out = list()

    # Checks if anything in old_polys or new_polys can divide each other
    # Example: if f1 divides f2, then f2 and  LT(f2)/LT(f1) * f1 are
    # added to the matrix
    for i, j in itertools.permutations(polys_with_unique_lm, 2):
        if i in divides_out:
            continue
        if utils.divides(j.lead_term, i.lead_term):  # j divides into i
            divides_out.append(i)
            matrix_polys.append(i)
            matrix_polys.append(
                j.mon_mult(
                    tuple(a - b for a, b in zip(i.lead_term, j.lead_term))))

    # Now add everything that couldn't be divided out to the matrix,
    # and put them back in either self.old_polys or self.new_polys,
    # whichever they belonged to before.
    #
    # This means that the ones that got divided out are essentially
    # removed from the list they belonged to, so they won't be
    # used for phi or r calculations.
    for i in polys_with_unique_lm:
        if i not in divides_out:
            matrix_polys.append(i)
            if i in old:
                old_polys.append(i)
            elif i in new:
                new_polys.append(i)
            else:
                raise ValueError("Where did this poly come from?")
    return old_polys, new_polys, matrix_polys