def test_mon_mult_random(): np.random.seed(988) #test with random matrices possible_dim = np.random.randint(1,5, (1,10)) dim = possible_dim[0, np.random.randint(1,9)] shape = list() for i in range(dim): shape.append(np.random.randint(2,4)) matrix1 = np.random.randint(1,11,(shape)) M1 = MultiPower(matrix1) shape2 = list() for i in range(dim): shape2.append(np.random.randint(2,4)) matrix2 = np.ones(shape2) M2 = MultiPower(matrix2) M3 = M1*M2 for index, i in np.ndenumerate(M2.coeff): if sum(index) == 0: M4 = MultiPower.mon_mult(M1, index) else: M4 = M4 + MultiPower.mon_mult(M1, index) if M3.shape != M4.shape: new_M3_coeff, new_M4_coeff = utils.match_size(M3.coeff,M4.coeff) else: new_M3_coeff, new_M4_coeff = M3.coeff, M4.coeff assert np.allclose(new_M3_coeff, new_M4_coeff)
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
def __sub__(self, other): ''' Subtraction of two MultiCheb polynomials. Parameters ---------- other : MultiCheb Returns ------- MultiCheb The coeff values are the result of self.coeff - other.coeff. ''' if self.shape != other.shape: new_self, new_other = match_size(self.coeff, other.coeff) else: new_self, new_other = self.coeff, other.coeff return MultiCheb((new_self - (new_other)), clean_zeros=False)
def __add__(self, other): ''' Addition of two MultiPower polynomials. Parameters ---------- other : MultiPower Returns ------- MultiPower object The sum of the coeff of self and coeff of other. ''' if self.shape != other.shape: new_self, new_other = match_size(self.coeff, other.coeff) else: new_self, new_other = self.coeff, other.coeff return MultiPower((new_self + new_other), clean_zeros=False)
def __mul__(self, other): ''' Multiplication of two MultiPower polynomials. Parameters ---------- other : MultiPower object Returns ------- MultiPower object The result of self*other. ''' if self.shape != other.shape: new_self, new_other = match_size(self.coeff, other.coeff) else: new_self, new_other = self.coeff, other.coeff return MultiPower(convolve(new_self, new_other))
def __add__(self, other): ''' Addition of two MultiCheb polynomials. Parameters ---------- other : MultiCheb Returns ------- MultiCheb The sum of the coeff of self and coeff of other. ''' if self.shape != other.shape: new_self, new_other = match_size(self.coeff, other.coeff) else: new_self, new_other = self.coeff, other.coeff return MultiCheb(new_self + new_other)
def bivariate_roots(f, g): """Calculates the common roots of f and g using the bezout resultant method. Parameters ---------- f, g : MultiCheb objects Returns ------- roots """ F, G = utils.match_size(f.coeff, g.coeff) n = max(F.shape) # F, G = np.zeros((n,n)), np.zeros((n,n)) # F = F + utils.match_size(F, f_coeffs)[1] # Square matrix for f # G = G + utils.match_size(G, g_coeffs)[1] # Square matrix for g A = np.zeros((n - 1, n - 1, 2 * n - 1)) a, b, c = (np.vstack([np.ones( (n - 1, 1)), 2]) / 2).T, np.zeros(n), np.ones(n) / 2 for i in range(1, n + 1): for j in range(1, n + 1): AA = np.array([[0] + list(F[:, i - 1][::-1])]) v = G[:, j - 1][::-1].reshape((-1, 1)) X, ignored = DLP(AA, v, a, b, c) if i == 1 or j == 1: cc = np.zeros(max(i, j)) cc[0] = 1 else: cc = np.zeros(i + j - 1) cc[-1] = .5 cc[abs(i - j)] = .5 cc = cc[::-1] for k in range(len(cc)): A[:, :, -1 - k] = A[:, :, -1 - k] + X[1:, 1:] * cc[-1 - k] nrmA = np.linalg.norm(A[:, :, -1], 'fro') for ii in range(A.shape[2]): if np.linalg.norm(A[:, :, ii], 'fro') / nrmA > 1e-20: break A = A[:, :, ii:] ns = A.shape AA = A.reshape(ns[0], ns[1] * ns[2], order='F') n = ns[0] v = np.random.rand(n, 1) a, b, c = (np.vstack([np.ones( (n - 1, 1)), 2]) / 2).T, np.zeros(n), np.ones(n) / 2 X, Y = DLP(AA, v, a, b, c) yvals, V = sLA.eig(Y, -X) y = yvals x = np.divide(V[-2, :], V[-1, :]) t = np.copy(x) x = x[np.logical_and(np.logical_and(np.imag(y) == 0, abs(y) < 1), abs(x) < 1)] y = y[np.logical_and(np.logical_and(np.imag(y) == 0, abs(y) < 1), abs(t) < 1)] return list(zip(x, y))