def create_matrix(matrix_polys, matrix_terms=None): ''' Builds a Macaulay matrix. If there is only one term in the matrix it won't work. Parameters ---------- matrix_polys : list. Contains numpy arrays that hold the polynomials to be put in the matrix. matrix_terms : ndarray The terms that will exist in the matrix. Not sorted yet. Defaults to None, in which case it will be found in the function. Returns ------- matrix : ndarray The Macaulay matrix. ''' bigShape = np.maximum.reduce([p.coeff.shape for p in matrix_polys]) if matrix_terms is None: #Finds the matrix terms. non_zeroSet = set() for poly in matrix_polys: for term in zip(*np.where(poly.coeff != 0)): non_zeroSet.add(term) matrix_terms = np.array(non_zeroSet.pop()) for term in non_zeroSet: matrix_terms = np.vstack((matrix_terms, term)) matrix_terms = sort_matrix_terms(matrix_terms) #Get the slices needed to pull the matrix_terms from the coeff matrix. matrix_term_indexes = list() for i in range(len(bigShape)): matrix_term_indexes.append(matrix_terms.T[i]) #Adds the poly_coeffs to flat_polys, using added_zeros to make sure every term is in there. added_zeros = np.zeros(bigShape) flat_polys = list() for poly in matrix_polys: coeff = poly.coeff slices = slice_top(coeff) added_zeros[slices] = coeff flat_polys.append(added_zeros[matrix_term_indexes]) added_zeros[slices] = np.zeros_like(coeff) #Make the matrix matrix = np.vstack(flat_polys[::-1]) #Sorts the rows of the matrix so it is close to upper triangular. matrix = utils.row_swap_matrix(matrix) return matrix, matrix_terms
def create_matrix(poly_coeffs, degree, dim): ''' Builds a Telen Van Barel matrix. Parameters ---------- poly_coeffs : list. Contains numpy arrays that hold the coefficients of the polynomials to be put in the matrix. degree : int The degree of the TVB Matrix dim : int The dimension of the polynomials going into the matrix. Returns ------- matrix : 2D numpy array The Telen Van Barel matrix. matrix_terms : numpy array The ith row is the term represented by the ith column of the matrix. cuts : tuple When the matrix is reduced it is split into 3 parts with restricted pivoting. These numbers indicate where those cuts happen. ''' bigShape = [degree+1]*dim matrix_terms, cuts = sorted_matrix_terms(degree, dim) #Get the slices needed to pull the matrix_terms from the coeff matrix. matrix_term_indexes = list() for row in matrix_terms.T: matrix_term_indexes.append(row) #Adds the poly_coeffs to flat_polys, using added_zeros to make sure every term is in there. added_zeros = np.zeros(bigShape) flat_polys = list() for coeff in poly_coeffs: slices = slice_top(coeff) added_zeros[slices] = coeff flat_polys.append(added_zeros[matrix_term_indexes]) added_zeros[slices] = np.zeros_like(coeff) coeff = 0 poly_coeffs = 0 #Make the matrix. Reshape is faster than stacking. matrix = np.reshape(flat_polys, (len(flat_polys),len(matrix_terms))) #if cuts[0] > matrix.shape[0]: #The matrix isn't tall enough, these can't all be pivot columns. # raise TVBError("HIGHEST NOT FULL RANK. TRY HIGHER DEGREE") #Sorts the rows of the matrix so it is close to upper triangular. matrix = row_swap_matrix(matrix) return matrix, matrix_terms, cuts
def create_matrix(poly_coeffs, degree, dim, divisor_var): ''' Builds a Macaulay matrix for reduction. Parameters ---------- poly_coeffs : list. Contains numpy arrays that hold the coefficients of the polynomials to be put in the matrix. degree : int The degree of the TVB Matrix dim : int The dimension of the polynomials going into the matrix. divisor_var : int What variable is being divided by. 0 is x, 1 is y, etc. Returns ------- matrix : 2D numpy array The Telen Van Barel matrix. matrix_terms : numpy array The ith row is the term represented by the ith column of the matrix. cuts : tuple When the matrix is reduced it is split into 3 parts with restricted pivoting. These numbers indicate where those cuts happen. ''' bigShape = [degree + 1] * dim matrix_terms, cuts = get_matrix_terms(poly_coeffs, dim, divisor_var, degree) #Get the slices needed to pull the matrix_terms from the coeff matrix. matrix_term_indexes = list() for row in matrix_terms.T: matrix_term_indexes.append(row) #Adds the poly_coeffs to flat_polys, using added_zeros to make sure every term is in there. added_zeros = np.zeros(bigShape) flat_polys = list() for coeff in poly_coeffs: slices = slice_top(coeff) added_zeros[slices] = coeff flat_polys.append(added_zeros[matrix_term_indexes]) added_zeros[slices] = np.zeros_like(coeff) coeff = 0 poly_coeffs = 0 #Make the matrix. Reshape is faster than stacking. matrix = np.reshape(flat_polys, (len(flat_polys), len(matrix_terms))) #Sorts the rows of the matrix so it is close to upper triangular. matrix = row_swap_matrix(matrix) return matrix, matrix_terms, cuts
def create_matrix(poly_coeffs): ''' Builds a Macaulay matrix. Parameters ---------- poly_coeffs : list Contains numpy arrays that hold the coefficients of the polynomials to be put in the matrix. Returns ------- matrix : (M,N) ndarray The Macaulay matrix. ''' bigShape = np.maximum.reduce([p.shape for p in poly_coeffs]) #Finds the matrix terms. non_zeroSet = set() for coeff in poly_coeffs: for term in zip(*np.where(coeff != 0)): non_zeroSet.add(term) matrix_terms = np.array(non_zeroSet.pop()) for term in non_zeroSet: matrix_terms = np.vstack((matrix_terms, term)) matrix_terms = sort_matrix_terms(matrix_terms) #Get the slices needed to pull the matrix_terms from the coeff matrix. matrix_term_indexes = list() for i in range(len(bigShape)): matrix_term_indexes.append(matrix_terms.T[i]) #Adds the poly_coeffs to flat_polys, using added_zeros to make sure every term is in there. added_zeros = np.zeros(bigShape) flat_polys = list() for coeff in poly_coeffs: slices = slice_top(coeff) added_zeros[slices] = coeff flat_polys.append(added_zeros[matrix_term_indexes]) added_zeros[slices] = np.zeros_like(coeff) coeff = 0 poly_coeffs = 0 #Make the matrix matrix = np.vstack(flat_polys[::-1]) flat_polys = 0 #Sorts the rows of the matrix so it is close to upper triangular. matrix = utils.row_swap_matrix(matrix) return matrix, matrix_terms
def construction(polys, degree, dim): ''' Builds a Telen Van Barel matrix using fast construction in the Chebyshev basis. Parameters ---------- polys : list. Contains numpy arrays that hold the coefficients of the polynomials to be put in the matrix. degree : int The degree of the TVB Matrix dim : int The dimension of the polynomials going into the matrix. Returns ------- matrix : 2D numpy array The Telen Van Barel matrix. matrix_terms : numpy array The ith row is the term represented by the ith column of the matrix. cuts : tuple When the matrix is reduced it is split into 3 parts with restricted pivoting. These numbers indicate where those cuts happen. ''' bigShape = [degree+1]*dim matrix_terms, cuts = sorted_matrix_terms(degree, dim) #print(matrix_shape_stuff) matrix_term_indexes = list() for row in matrix_terms.T: matrix_term_indexes.append(row) permutations = all_permutations_cheb(degree - np.min([poly.degree for poly in polys]), dim, degree) #print(permutations) added_zeros = np.zeros(bigShape) flat_polys = list() i = 0; for poly in polys: slices = slice_top(poly.coeff) added_zeros[slices] = poly.coeff array = added_zeros[matrix_term_indexes] added_zeros[slices] = np.zeros_like(poly.coeff) #print(array) #flat_polys.append(array[np.vstack(permutations.values())]) degreeNeeded = degree - poly.degree mons = mons_ordered(dim,degreeNeeded) mons = np.pad(mons, (0,1), 'constant', constant_values = i) i += 1 flat_polys.append(array) for mon in mons[1:-1]: result = np.copy(array) for i in range(dim): if mon[i] != 0: mult = [0]*dim mult[i] = mon[i] result = np.sum(result[permutations[tuple(mult)]], axis = 0) flat_polys.append(result) #print(flat_polys) matrix = np.vstack(flat_polys) if matrix_shape_stuff[0] > matrix.shape[0]: #The matrix isn't tall enough, these can't all be pivot columns. raise TVBError("HIGHEST NOT FULL RANK. TRY HIGHER DEGREE") matrix = row_swap_matrix(matrix) #print(matrix) return matrix, matrix_terms, cuts
def createMatrixFast(polys, degree, dim): ''' Builds a Telen Van Barel matrix using fast construction. Parameters ---------- poly_coeffs : list. Contains numpy arrays that hold the coefficients of the polynomials to be put in the matrix. degree : int The degree of the TVB Matrix dim : int The dimension of the polynomials going into the matrix. Returns ------- matrix : 2D numpy array The Telen Van Barel matrix. matrix_terms : numpy array The ith row is the term represented by the ith column of the matrix. cuts : tuple When the matrix is reduced it is split into 3 parts with restricted pivoting. These numbers indicate where those cuts happen. ''' bigShape = [degree+1]*dim matrix_terms, cuts = sorted_matrix_terms(degree, dim) columns = len(matrix_terms) range_split = [num_mons_full(degree-poly.degree,dim) for poly in polys] rows = np.sum(range_split) ranges = get_ranges(range_split) #How to slice the poly into the matrix rows. matrix = np.zeros((rows,columns)) curr = 0 #Get the slices needed to pull the matrix_terms from the coeff matrix. matrix_term_indexes = list() for row in matrix_terms.T: matrix_term_indexes.append(row) permutations = None currentDegree = 2 #Adds the poly_coeffs to flat_polys, using added_zeros to make sure every term is in there. added_zeros = np.zeros(bigShape) for poly,matrix_range in zip(polys,ranges): slices = slice_top(poly.coeff) added_zeros[slices] = poly.coeff array = added_zeros[matrix_term_indexes] added_zeros[slices] = np.zeros_like(poly.coeff) permutations = memoized_all_permutations(degree - poly.degree, dim, degree, permutations, currentDegree) currentDegree = degree - poly.degree permList = list(permutations.values()) temp = array[np.reshape(permList, (len(permList), columns))[::-1]] matrix[matrix_range] = temp if matrix_shape_stuff[0] > matrix.shape[0]: #The matrix isn't tall enough, these can't all be pivot columns. raise TVBError("HIGHEST NOT FULL RANK. TRY HIGHER DEGREE") #Sorts the rows of the matrix so it is close to upper triangular. if not checkEqual([poly.degree for poly in polys]): #Will need some switching possibly if some degrees are different. matrix = row_swap_matrix(matrix) return matrix, matrix_terms, cuts
def rrqr_reduceMacaulay(matrix, matrix_terms, cuts, number_of_roots, accuracy=1.e-10): ''' Reduces a Macaulay matrix, BYU style. The matrix is split into the shape A B C D E F Where A is square and contains all the highest terms, and C contains all the x,y,z etc. terms. The lengths are determined by the matrix_shape_stuff tuple. First A and D are reduced using rrqr without pivoting, and then the rest of the matrix is multiplied by Q.T to change it accordingly. Then E is reduced by rrqr with pivoting, the rows of B are shifted accordingly, and F is multipled by Q.T to change it accordingly. This is all done in place to save memory. Parameters ---------- matrix : numpy array. The Macaulay matrix, sorted in BYU style. matrix_terms: numpy array Each row of the array contains a term in the matrix. The i'th row corresponds to the i'th column in the matrix. cuts : tuple When the matrix is reduced it is split into 3 parts with restricted pivoting. These numbers indicate where those cuts happen. Returns ------- matrix : numpy array The reduced matrix. matrix_terms: numpy array The resorted matrix_terms. ''' #print("Starting matrix.shape:\n", matrix.shape) #RRQR reduces A and D without pivoting sticking the result in it's place. Q1, matrix[:, :cuts[0]] = qr(matrix[:, :cuts[0]]) #check if there are zeros along the diagonal of R1 if any(np.isclose(np.diag(matrix[:, :cuts[0]]), 0, atol=accuracy)): raise MacaulayError("R1 IS NOT FULL RANK") #Looks like 0 but not, add to the rank. #still_good = np.sum(np.abs(matrix[:,:cuts[0]].diagonal()) < accuracy) #if abs(matrix[:,:cuts[0]].diagonal()[-1]) < accuracy: # print(matrix[:,:cuts[0]].diagonal()) # raise MacaulayError("HIGHEST NOT FULL RANK") #Multiplying the rest of the matrix by Q.T matrix[:, cuts[0]:] = Q1.T @ matrix[:, cuts[0]:] Q1 = 0 #Get rid of Q1 for memory purposes. #RRQR reduces E sticking the result in it's place. Q, matrix[cuts[0]:, cuts[0]:cuts[1]], P = qr(matrix[cuts[0]:, cuts[0]:cuts[1]], pivoting=True) #Multiplies F by Q.T. matrix[cuts[0]:, cuts[1]:] = Q.T @ matrix[cuts[0]:, cuts[1]:] Q = 0 #Get rid of Q for memory purposes. #Shifts the columns of B matrix[:cuts[0], cuts[0]:cuts[1]] = matrix[:cuts[0], cuts[0]:cuts[1]][:, P] #Checks for 0 rows and gets rid of them. #rank = np.sum(np.abs(matrix.diagonal())>accuracy) + still_good #matrix = matrix[:rank] #eliminates rows we don't care about-- those at the bottom of the matrix #since the top corner is a square identity matrix, useful_rows + number_of_roots is the width of the Macaulay matrix matrix = row_swap_matrix(matrix) for row in matrix[::-1]: if np.allclose(row, 0): matrix = matrix[:-1] else: break #print("Final matrix.shape:\n", matrix.shape) #useful_rows = matrix.shape[1] - number_of_roots #matrix = matrix[:useful_rows,:] #set very small values in the matrix to zero before backsolving matrix[np.isclose(matrix, 0, atol=accuracy)] = 0 #Resorts the matrix_terms. matrix_terms[cuts[0]:cuts[1]] = matrix_terms[cuts[0]:cuts[1]][P] #print("Macaulay1Rank:", np.sum(np.abs(matrix.diagonal())>accuracy)) return matrix, matrix_terms
def rrqr_reduceMacaulay2(matrix, matrix_terms, cuts, number_of_roots, accuracy=1.e-10): ''' Reduces a Macaulay matrix, BYU style This function does the same thing as rrqr_reduceMacaulay but uses qr_multiply instead of qr and a multiplication to make the function faster and more memory efficient. This function only works properly if the bottom left (D) part of the matrix is zero Parameters ---------- matrix : numpy array. The Macaulay matrix, sorted in BYU style. matrix_terms: numpy array Each row of the array contains a term in the matrix. The i'th row corresponds to the i'th column in the matrix. cuts : tuple When the matrix is reduced it is split into 3 parts with restricted pivoting. These numbers indicate where those cuts happen. accuracy : float What is determined to be 0. Returns ------- matrix : numpy array The reduced matrix. matrix_terms: numpy array The resorted matrix_terms. ''' #print("Starting matrix.shape:\n", matrix.shape) #RRQR reduces A and D without pivoting sticking the result in it's place. C1, matrix[:cuts[0], :cuts[0]] = qr_multiply(matrix[:, :cuts[0]], matrix[:, cuts[0]:].T, mode='right') matrix[:cuts[0], cuts[0]:] = C1.T C1 = 0 #check if there are zeros along the diagonal of R1 if any(np.isclose(np.diag(matrix[:, :cuts[0]]), 0, atol=accuracy)): raise MacaulayError("R1 IS NOT FULL RANK") #if abs(matrix[:,:cuts[0]].diagonal()[-1]) < accuracy: # raise MacaulayError("HIGHEST NOT FULL RANK") #set small values to zero before backsolving matrix[np.isclose(matrix, 0, atol=accuracy)] = 0 matrix[:cuts[0], cuts[0]:] = solve_triangular(matrix[:cuts[0], :cuts[0]], matrix[:cuts[0], cuts[0]:]) matrix[:cuts[0], :cuts[0]] = np.eye(cuts[0]) matrix[cuts[0]:, cuts[0]:] -= (matrix[cuts[0]:, :cuts[0]]) @ matrix[:cuts[0], cuts[0]:] #? C, R, P = qr_multiply(matrix[cuts[0]:, cuts[0]:cuts[1]], matrix[cuts[0]:, cuts[1]:].T, mode='right', pivoting=True) matrix = matrix[:R.shape[0] + cuts[0]] #matrix[cuts[0]:,:cuts[0]] = np.zeros_like(matrix[cuts[0]:,:cuts[0]]) matrix[cuts[0]:, cuts[0]:cuts[0] + R.shape[1]] = R matrix[cuts[0]:, cuts[0] + R.shape[1]:] = C.T C, R = 0, 0 #Shifts the columns of B. matrix[:cuts[0], cuts[0]:cuts[1]] = matrix[:cuts[0], cuts[0]:cuts[1]][:, P] matrix_terms[cuts[0]:cuts[1]] = matrix_terms[cuts[0]:cuts[1]][P] P = 0 # Check if there are no solutions #rank = np.sum(np.abs(matrix.diagonal())>accuracy) # extra_block = matrix[rank:, -matrix_shape_stuff[2]:] # Q,R = qr(extra_block) # if np.sum(np.abs(R.diagonal())>accuracy) == matrix_shape_stuff[2]: # raise ValueError("The system given has no roots.") #Get rid of 0 rows at the bottom. #matrix = matrix[:rank] #eliminates rows we don't care about-- those at the bottom of the matrix #since the top corner is a square identity matrix, always_useful_rows + number_of_roots is the width of the Macaulay matrix always_useful_rows = matrix.shape[1] - number_of_roots #matrix = matrix[:useful_rows,:] #set small values in the matrix to zero now, after the QR reduction matrix[np.isclose(matrix, 0, atol=accuracy)] = 0 #eliminate zero rows from the bottom of the matrix. Zero rows above #nonzero elements are not eliminated. This saves time since Macaulay matrices #we deal with are only zero at the very bottom matrix = row_swap_matrix(matrix) for row in matrix[::-1]: if np.allclose(row, 0): matrix = matrix[:-1] else: break return matrix, matrix_terms
def create_matrix(poly_coeffs, degree, dim, divisor_var, get_divvar_coord_from_eigval=False): ''' Builds a Macaulay matrix for reduction. Parameters ---------- poly_coeffs : list. Contains numpy arrays that hold the coefficients of the polynomials to be put in the matrix. degree : int The degree of the Macaulay Matrix dim : int The dimension of the polynomials going into the matrix. divisor_var : int What variable is being divided by. 0 is x, 1 is y, etc. Defaults to x. get_divvar_coord_from_eigval: bool Whether the divisor_var-coordinate of the roots is calculated from the eigenvalue or eigenvector. More stable to use the eigenvector. Defaults to false Returns ------- matrix : 2D numpy array The Macaulay matrix. matrix_terms : numpy array The ith row is the term represented by the ith column of the matrix. cuts : tuple When the matrix is reduced it is split into 3 parts with restricted pivoting. These numbers indicate where those cuts happen. ''' bigShape = [degree + 1] * dim #If you get_divvar_coord_from_eigval, then you should not include_divvar_squared in the basis, and vice versa include_divvar_squared = not get_divvar_coord_from_eigval matrix_terms, cuts = get_matrix_terms(poly_coeffs, dim, divisor_var, degree, include_divvar_squared) #Get the slices needed to pull the matrix_terms from the coeff matrix. matrix_term_indexes = list() for row in matrix_terms.T: matrix_term_indexes.append(row) #Adds the poly_coeffs to flat_polys, using added_zeros to make sure every term is in there. added_zeros = np.zeros(bigShape) flat_polys = list() for coeff in poly_coeffs: slices = slice_top(coeff) added_zeros[slices] = coeff flat_polys.append(added_zeros[matrix_term_indexes]) added_zeros[slices] = np.zeros_like(coeff) coeff = 0 poly_coeffs = 0 #Make the matrix. Reshape is faster than stacking. matrix = np.reshape(flat_polys, (len(flat_polys), len(matrix_terms))) #Sorts the rows of the matrix so it is close to upper triangular. matrix = row_swap_matrix(matrix) return matrix, matrix_terms, cuts