def solve(self, qr_reduction=True, reducedGroebner=True): ''' The main function. Initializes the matrix, adds the phi's and r's, and then reduces it. Repeats until the reduction no longer adds any more polynomials to the matrix. Print statements let us see the progress of the code. ''' MultiCheb.clearTime() MultiPower.clearTime() startTime = time.time() polys_were_added = True i = 1 #Tracks what loop we are on. while polys_were_added: #print("Starting Loop #"+str(i)) #print("Num Polys - ", len(self.new_polys + self.old_polys)) self.initialize_np_matrix() self.add_phi_to_matrix() self.add_r_to_matrix() self.create_matrix() #print(self.np_matrix.shape) polys_were_added = self.reduce_matrix( qr_reduction=qr_reduction, triangular_solve=False ) #Get rid of triangular solve when done testing i += 1 #print("Basis found!") self.get_groebner() if reducedGroebner: self.reduce_groebner_basis() endTime = time.time() #print("WE WIN") print("Run time was {} seconds".format(endTime - startTime)) print(times) MultiCheb.printTime() MultiPower.printTime() #print("Basis - ") #for poly in self.groebner_basis: # print(poly.coeff) #break #print just one return self.groebner_basis
def reduce_matrix(self, qr_reduction=True, triangular_solve=False): ''' Reduces the matrix fully using either QR or LU decomposition. Adds the new_poly's to old_poly's, and adds to new_poly's any polynomials created by the reduction that have new leading monomials. Returns-True if new polynomials were found, False otherwise. ''' startTime = time.time() if qr_reduction: independentRows, dependentRows, Q = self.fullRank(self.np_matrix) fullRankMatrix = self.np_matrix[independentRows] startRRQR = time.time() reduced_matrix = self.rrqr_reduce(fullRankMatrix) non_zero_rows = np.sum(abs(reduced_matrix), axis=1) != 0 reduced_matrix = reduced_matrix[ non_zero_rows, :] #Only keeps the non_zero_polymonials endRRQR = time.time() times["rrqr_reduce"] += (endRRQR - startRRQR) ''' #If I decide to use the fully reduce method. Q,R = qr(self.np_matrix) reduced_matrix = self.fully_reduce(R) non_zero_rows = np.sum(abs(reduced_matrix),axis=1)>0 ##Increasing this will get rid of small things. reduced_matrix = reduced_matrix[non_zero_rows,:] #Only keeps the non_zero_polymonials ''' startTri = time.time() if triangular_solve: reduced_matrix = self.triangular_solve(reduced_matrix) if clean: reduced_matrix = self.clean_zeros_from_matrix( reduced_matrix) endTri = time.time() times["triangular_solve"] += (endTri - startTri) #plt.matshow(reduced_matrix) #plt.matshow([i==0 for i in reduced_matrix]) #plt.matshow([abs(i)<self.global_accuracy for i in reduced_matrix]) else: #This thing is very behind the times. P, L, U = lu(self.np_matrix) reduced_matrix = U #reduced_matrix = self.fully_reduce(reduced_matrix, qr_reduction = False) #Get the new polynomials new_poly_spots = list() old_poly_spots = list() startLooking = time.time() already_looked_at = set( ) #rows whose leading monomial we've already checked for i, j in zip(*np.where(reduced_matrix != 0)): if i in already_looked_at: #We've already looked at this row continue elif self.matrix_terms[ j] in self.lead_term_set: #The leading monomial is not new. if self.matrix_terms[ j] in self.original_lms: #Reduced old poly. Only used if triangular solve is done. old_poly_spots.append(i) already_looked_at.add(i) continue else: already_looked_at.add(i) new_poly_spots.append( i) #This row gives a new leading monomial endLooking = time.time() times["looking"] += (endLooking - startLooking) if triangular_solve: self.old_polys = self.get_polys_from_matrix( old_poly_spots, reduced_matrix) else: self.old_polys = self.new_polys + self.old_polys self.new_polys = self.get_polys_from_matrix(new_poly_spots, reduced_matrix) endTime = time.time() times["reduce_matrix"] += (endTime - startTime) if len(self.old_polys + self.new_polys) == 0: print( "ERROR ERROR ERROR ERROR ERROR NOT GOOD NO POLYNOMIALS IN THE BASIS FIX THIS ASAP!!!!!!!!!!!!!" ) print(reduced_matrix) print(times) MultiCheb.printTime() return len(self.new_polys) > 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 returns ------- list of numpy arrays the common roots of the polynomials ''' times["reducePoly"] = 0 Polynomial.clearTime() startTime = time.time() # Determine polynomial type poly_type = '' if (all(type(p) == MultiCheb for p in polys)): poly_type = 'MultiCheb' elif (all(type(p) == MultiPower for p in polys)): poly_type = 'MultiPower' else: raise ValueError('All polynomials must be the same type') # Calculate groebner basis startBasis = time.time() if method == 'Groebner': G = Groebner(polys) GB = G.solve() else: GB = Macaulay(polys) endBasis = time.time() times["basis"] = (endBasis - startBasis) dim = max(g.dim for g in GB) # dimension of the polynomials # Check for no solutions if len(GB) == 1 and all([i == 1 for i in GB[0].coeff.shape]): print("No solutions") return -1 startRandPoly = time.time() # Make sure ideal is zero-dimensional and get random polynomial f, var_list = _random_poly(poly_type, dim) if not _test_zero_dimensional(var_list, GB): print("Ideal is not zero-dimensional; cannot calculate roots.") return -1 endRandPoly = time.time() times["randPoly"] = (endRandPoly - startRandPoly) # Get multiplication matrix startVectorBasis = time.time() VB, var_dict = vectorSpaceBasis(GB) endVectorBasis = time.time() times["vectorBasis"] = (endVectorBasis - startVectorBasis) #print("VB:", VB) #print("var_dict:", var_dict) startMultMatrix = time.time() m_f = multMatrix(f, GB, VB) endMultMatrix = time.time() times["multMatrix"] = (endMultMatrix - startMultMatrix) startEndStuff = time.time() # Get list of indexes of single variables and store vars that were not # in the vector space basis. var_indexes = np.array([-1 for i in range(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: vnib = True # Get left eigenvectors eig = np.linalg.eig(m_f.T)[1] num_vectors = eig.shape[1] eig_vectors = [eig[:, i].tolist() for i in range(num_vectors)] # columns of eig roots = [] for v in eig_vectors: 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[0] 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.evaluate_at(root) * -1 root[pos] = var_value roots.append(root) endEndStuff = time.time() times["endStuff"] = (endEndStuff - startEndStuff) endTime = time.time() totalTime = (endTime - startTime) print("Total run time for roots is {}".format(totalTime)) print(times) MultiCheb.printTime() MultiPower.printTime() Polynomial.printTime() print((times["basis"] + times["multMatrix"]) / totalTime) return roots
def Macaulay(initial_poly_list, global_accuracy = 1.e-10): """ Macaulay will take a list of polynomials and use them to construct a Macaulay matrix. parameters -------- initial_poly_list: A list of polynomials global_accuracy: How small we want a number to be before assuming it is zero. -------- Returns ----------- Reduced Macaulay matrix that can be passed into the root finder. ----------- """ times = {} startTime = time.time() MultiCheb.clearTime() MultiPower.clearTime() Power = bool if all([type(p) == MultiPower for p in initial_poly_list]): Power = True elif all([type(p) == MultiCheb for p in initial_poly_list]): Power = False else: print([type(p) == MultiPower for p in initial_poly_list]) raise ValueError('Bad polynomials in list') poly_list = [] degree = find_degree(initial_poly_list) startAdding = time.time() for i in initial_poly_list: poly_list = add_polys(degree, i, poly_list) endAdding = time.time() times["adding polys"] = (endAdding - startAdding) startCreate = time.time() matrix, matrix_terms = create_matrix(poly_list) endCreate = time.time() times["create matrix"] = (endCreate - startCreate) #plt.matshow([i==0 for i in matrix]) startReduce = time.time() matrix = rrqr_reduce(matrix) matrix = clean_zeros_from_matrix(matrix) non_zero_rows = np.sum(abs(matrix),axis=1) != 0 matrix = matrix[non_zero_rows,:] #Only keeps the non_zero_polymonials endReduce = time.time() times["reduce matrix"] = (endReduce - startReduce) #plt.matshow([i==0 for i in matrix]) startTri = time.time() matrix = triangular_solve(matrix) matrix = clean_zeros_from_matrix(matrix) endTri = time.time() times["triangular solve"] = (endTri - startTri) #plt.matshow([i==0 for i in matrix]) startGetPolys = time.time() rows = get_good_rows(matrix, matrix_terms) final_polys = get_poly_from_matrix(rows,matrix,matrix_terms,Power) endGetPolys = time.time() times["get polys"] = (endGetPolys - startGetPolys) endTime = time.time() print("Macaulay run time is {} seconds".format(endTime-startTime)) print(times) MultiCheb.printTime() MultiPower.printTime() #for poly in final_polys: # print(poly.lead_term) return final_polys
# 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.evaluate_at(root) * -1 root[pos] = var_value roots.append(root) endEndStuff = time.time() times["endStuff"] = (endEndStuff - startEndStuff) endTime = time.time() totalTime = (endTime - startTime) print("Total run time for roots is {}".format(totalTime)) print(times) MultiCheb.printTime() MultiPower.printTime() Polynomial.printTime() print((times["basis"]+times["multMatrix"])/totalTime) return roots def multMatrix(poly, GB, basis): ''' Finds the matrix of the linear operator m_f on A = C[x_1,...,x_n]/I where f is the polynomial argument. The linear operator m_f is defined as m_f([g]) = [f]*[g] where [f] represents the coset of f in A. Since m_f is a linear operator on A, it can be represented by its matrix with respect to the vector space basis. parameters ----------