예제 #1
0
def _random_poly(_type, dim):
    '''
    Generates a random polynomial that has the form
    c_1x_1 + c_2x_2 + ... + c_nx_n where n = dim and each c_i is a randomly
    chosen integer between 0 and 1000.

    Parameters
    ----------
    _type : string
        Type of Polynomial to generate. "MultiCheb" or "MultiPower".
    dim : int
        Degree of polynomial to generate (?).

    Returns
    -------
    Polynomial
        Randomly generated Polynomial.
    '''
    _vars = get_var_list(dim)

    random_poly_shape = [2 for i in range(dim)]

    random_poly_coeff = np.zeros(tuple(random_poly_shape), dtype=int)
    for var in _vars:
        random_poly_coeff[var] = np.random.randint(1000)

    if _type == 'MultiCheb':
        return MultiCheb(random_poly_coeff), _vars
    else:
        return MultiPower(random_poly_coeff), _vars
def makeBasisDict(matrix, matrix_terms, VB, power):
    '''Calculates and returns the basisDict.

    This is a dictionary of the terms on the diagonal of the reduced TVB matrix to the terms in the Vector Basis.
    It is used to create the multiplication matrix in root_finder.

    Parameters
    --------
    matrix: numpy array
        The reduced TVB matrix.
    matrix_terms : numpy array
        The terms in the matrix. The i'th row is the term represented by the i'th column of the matrix.
    VB : numpy array
        Each row is a term in the vector basis.
    power : bool
        If True, the initial polynomials were MultiPower. If False, they were MultiCheb.

    Returns
    -----------
    basisDict : dict
        Maps terms on the diagonal of the reduced TVB matrix (tuples) to numpy arrays that represent the
        terms reduction into the Vector Basis.
    '''
    basisDict = {}

    VBSet = set()
    for i in VB:
        VBSet.add(tuple(i))

    if power: #We don't actually need most of the rows, so we only get the ones we need.
        neededSpots = set()
        for term, mon in itertools.product(VB,get_var_list(VB.shape[1])):
            if tuple(term+mon) not in VBSet:
                neededSpots.add(tuple(term+mon))

    spots = list()
    for dim in range(VB.shape[1]):
        spots.append(VB.T[dim])

    for i in range(matrix.shape[0]):
        term = tuple(matrix_terms[i])
        if power and term not in neededSpots:
            continue
        basisDict[term] = matrix[i][matrix.shape[0]:]

    return basisDict
예제 #3
0
def makeBasisDict(matrix, matrix_terms, VB):
    '''Calculates and returns the basisDict.

    This is a dictionary of the terms on the diagonal of the reduced Macaulay matrix to the terms in the Vector Basis.
    It is used to create the multiplication matrix in root_finder.

    Parameters
    --------
    matrix: numpy array
        The reduced Macaulay matrix.
    matrix_terms : numpy array
        The terms in the matrix. The i'th row is the term represented by the i'th column of the matrix.
    VB : numpy array
        Each row is a term in the vector basis.

    Returns
    -----------
    basisDict : dict
        Maps terms on the diagonal of the reduced Macaulay matrix (tuples) to numpy arrays of the shape remainder_shape
        that represent the terms reduction into the Vector Basis.
    '''
    basisDict = {}
    VBSet = set()
    for i in VB:
        VBSet.add(tuple(i))

    #We don't actually need most of the rows, so we only get the ones we need.
    neededSpots = set()
    for term, mon in itertools.product(VB, get_var_list(VB.shape[1])):
        if tuple(term - mon) not in VBSet:
            neededSpots.add(tuple(term - mon))

    for i in range(matrix.shape[0]):
        term = tuple(matrix_terms[i])
        if term not in neededSpots:
            continue
        basisDict[term] = matrix[i][matrix.shape[0]:]
    return basisDict
예제 #4
0
def roots(polys, method='Groebner'):
    '''
    Finds the roots of the given list of polynomials.

    Parameters
    ----------
    polys : list of polynomial objects
        Polynomials to find the common roots of.
    method : string
        The root finding method to be used. Can be either 'Groebner',
        'Macaulay', or 'TVB'.
    returns
    -------
    list of numpy arrays
        the common roots of the polynomials
    '''
    polys = match_poly_dimensions(polys)

    # Determine polynomial type
    poly_type = is_power(polys, return_string=True)

    if method == 'TVB' or method == 'new_TVB':
        try:
            m_f, var_dict = TVBMultMatrix(polys, poly_type, method)
        except TVBError as e:
            if str(
                    e
            ) == "Doesn't have all x^n's on diagonal. Do linear transformation":
                raise e
                ''' #Optionally have it do F4 instead in thise case.
                warnings.warn("TVB method failed. Trying F4 instead. \
                    Error message from TVB is - {}".format(e), InstabilityWarning)
                method = 'Groebner'
                GB, m_f, var_dict = groebnerMultMatrix(polys, poly_type, method)
                '''
            elif str(e) == 'Polys are non-zero dimensional':
                return -1
            else:
                raise e
    else:
        GB, m_f, var_dict = groebnerMultMatrix(polys, poly_type, method)

    # both TVBMultMatrix and groebnerMultMatrix will return m_f as
    # -1 if the ideal is not zero dimensional or if there are no roots
    if type(m_f) == int:
        return -1

    # Get list of indexes of single variables and store vars that were not
    # in the vector space basis.
    dim = max(f.dim for f in polys)
    var_list = get_var_list(dim)
    var_indexes = [-1] * dim
    vars_not_in_basis = {}
    for i in range(len(var_list)):
        var = var_list[i]  # x_i
        if var in var_dict:
            var_indexes[i] = var_dict[var]
        else:
            # maps the position in the root to its variable
            vars_not_in_basis[i] = var

    vnib = False
    if len(vars_not_in_basis) != 0:
        if method == 'TVB':
            print("This isn't working yet...")
            return -1
        vnib = True

    # Get left eigenvectors

    e = np.linalg.eig(m_f.T)
    eig = e[1]
    num_vectors = eig.shape[1]

    eig_vectors = [eig[:, i] for i in range(num_vectors)]  # columns of eig
    roots = []
    for v in eig_vectors:
        if v[var_dict[tuple(0 for i in range(dim))]] == 0:
            continue
        root = np.zeros(dim, dtype=complex)
        # This will always work because var_indexes and root have the
        # same length - dim - and var_indexes has the variables in the
        # order they should be in the root
        for i in range(dim):
            x_i_pos = var_indexes[i]
            if x_i_pos != -1:
                root[i] = v[x_i_pos] / v[var_dict[tuple(0
                                                        for i in range(dim))]]
        if vnib:
            # Go through the indexes of variables not in the basis in
            # decreasing order. It must be done in decreasing order for the
            # roots to be calculated correctly, since the vars with lower
            # indexes depend on the ones with higher indexes
            for pos in list(vars_not_in_basis.keys())[::-1]:
                GB_poly = _get_poly_with_LT(vars_not_in_basis[pos], GB)
                var_value = GB_poly(root) * -1
                root[pos] = var_value
        roots.append(root)
        #roots.append(newton_polish(polys,root))
    return roots
예제 #5
0
def bounding_parallelepiped(linear):
    """
    A helper function for projecting polynomials. It accepts a linear
    polynomial and return vectors describing an (n-1)-dimensional parallelepiped
    that covers the intersection between the linear polynomial (it's variety)
    and the n-dimensional hypercube.

    Note: The parallelepiped can be described using just one vertex, and (n-1)
    vectors, each of dimension n.

    Second Note: This first attempt is very simple, and can be greatly improved
    by creating a parallelepiped that much more closely surrounds the points.
    Currently, it just makes a rectangle.

    Parameters
    ----------
        linear : numpy array
            The coefficients of the linear function.

    Returns
    -------
        p0 : numpy array
            One vertex of the parallelepiped.
        edges : numpy array
            Array of vectors describing the edges of the parallelepiped, from p0.
    """

    dim = linear.ndim
    coord = np.ones((dim-1,2))
    coord[:,0] = -1
    const = linear[tuple([0]*dim)]
    coeff = np.zeros(dim)
    # flatten the linear coefficients
    for i,idx in enumerate(get_var_list(dim)):
        coeff[i] = linear[idx]

    # get the intersection points with the hypercube edges
    lower = -np.ones(dim)
    upper = np.ones(dim)
    vert = []
    for i in range(dim):
        for pt in product(*coord):
            val = -const
            skipped = 0
            for j,c in enumerate(coeff):
                if i==j:
                    skipped = 1
                    continue
                val -= c*pt[j-skipped]
            one_point = list(pt)
            if not np.isclose(coeff[i], 0):
                one_point.insert(i,val/coeff[i])
            one_point = np.array(one_point)
            if np.all(lower <= one_point) and np.all(one_point <= upper):
                vert.append(one_point)

    # what to do if no intersections
    if len(vert) == 0:
        p0 = -const/np.dot(coeff, coeff)*coeff
        Q, R = np.linalg.qr(np.column_stack([coeff, np.eye(dim)[:,:dim-1]]))
        edges = Q[:,1:]
        return p0, edges
        # raise Exception("What do I do!?")

    # do the thing
    vert = np.unique(np.array(vert), axis=0)
    v0 = vert[0]
    vert_shift = vert - v0
    Q, vert_flat, _ = qr(vert_shift.T, pivoting=True)
    vert_flat = vert_flat[:-1] # remove flattened dimension
    min_vals = np.min(vert_flat, axis=1)
    max_vals = np.max(vert_flat, axis=1)

    p0 = Q[:,:-1].dot(min_vals) + v0
    edges = Q[:,:-1].dot(np.diag(max_vals-min_vals))
    return p0, edges