def get_R_i_for(self, coeffs, var): # TODO: Rewrite this function in a more pythonic way. N_p = 0 numerator = 0.0 denominator = 0.0 for k in [ x for x in self.clean_c_matrix.expectances if not x == sympy.S(1.0) ]: degree = sum(list(sympy.degree_list(k))) N_p = max([degree, N_p]) # Isn't this the same as 'self.order'? for k in [ x for x in self.clean_c_matrix.expectances if not x == sympy.S(1.0) ]: if list(sympy.degree_list(k, gens=var))[0] == N_p: numerator = (coeffs.get(k, 0.0)** 2) * self.clean_c_matrix.expectances[k] if sum(list(sympy.degree_list(k))) == N_p: denominator += (coeffs.get(k, 0.0)** 2) * self.clean_c_matrix.expectances[k] numerator = [ (coeffs.get(x, 0.0)**2) * self.clean_c_matrix.expectances[x] for x in self.clean_c_matrix.expectances if not x == sympy.S(1.0) and list(sympy.degree_list(x, gens=var))[0] == self.order ][0] if denominator == 0: return 0 return numerator / denominator
def __init__(self, polynomials, variables): """ A class that takes two lists, a list of polynomials and list of variables. Returns the Dixon matrix of the multivariate system. Parameters ---------- polynomials : list of polynomials A list of m n-degree polynomials variables: list A list of all n variables """ self.polynomials = polynomials self.variables = variables self.n = len(self.variables) self.m = len(self.polynomials) a = IndexedBase("alpha") # A list of n alpha variables (the replacing variables) self.dummy_variables = [a[i] for i in range(self.n)] # A list of the d_max of each variable. self.max_degrees = [ max(degree_list(poly)[i] for poly in self.polynomials) for i in range(self.n) ]
def get_sos(poly, max_mult_power=3, epsilon=0.001): """ :param poly: sympy polynomial :param max_mult_power: :param dsdp_solver: :param dsdp_options: :param eig_tol: :param epsilon: :return: string with status whether poly is a sum of squares of polynomials, and a sympy expression that is the SOSRF decomposition of the poly """ # check polynomial is nonconstant and even-degreed in every variable if poly == 0: _status = 'Zero polynomial.' return _status, nan else: _poly_expanded = expand(poly) _degree_list = degree_list(_poly_expanded) _coeffs = _poly_expanded.coeffs() if np.all([_d == 0 for _d in _degree_list]): _status = 'Constant polynomial.' return _status, nan elif np.any([_d % 2 for _d in _degree_list]): _status = 'One of the variables in the polynomial has odd degree. Not a sum of squares.' return _status, nan elif np.all([_f >= 0 for _f in _coeffs]): _status = 'Exact SOS decomposition found.' return _status, _poly_expanded indices = np.array(list(poly.as_dict().keys())) monoms = get_pts_in_cvx_hull(indices) num_alpha = monoms.shape[0] if not num_alpha: _status = 'Error in computing monomial indices.' return _status, nan coeff_leading, max_even_divisor, remainder = get_max_even_divisor(poly) if remainder == 1: _status = 'Exact SOS decomposition found.' sos = coeff_leading * max_even_divisor return _status, sos else: _status = 'No exact SOS decomposition found.' sos = nan # let's try clearing denominators _mult = get_special_sos_multiplier(remainder) for r in range(max_mult_power): # r=1 print(f'Trying multiplier power: {r}') status_, sos_ = get_sos_helper(poly=(_mult**r * remainder).as_poly(), epsilon=epsilon) if status_ == 'Exact SOS decomposition found.': _status = status_ sos = (1 / _mult** r) * coeff_leading * max_even_divisor * sos_.as_expr() return _status, sos return _status, sos
def __init__(self, polynomials, variables): """ A class that takes two lists, a list of polynomials and list of variables. Returns the Dixon matrix of the multivariate system. Parameters ---------- polynomials : list of polynomials A list of m n-degree polynomials variables: list A list of all n variables """ self.polynomials = polynomials self.variables = variables self.n = len(self.variables) self.m = len(self.polynomials) a = IndexedBase("alpha") # A list of n alpha variables (the replacing variables) self.dummy_variables = [a[i] for i in range(self.n)] # A list of the d_max of each variable. self.max_degrees = [ max(degree_list(poly)[i] for poly in self.polynomials) for i in range(self.n)]
def check_condition_one(self, coeffs, j_k): numerator = sum([(coeffs[k]**2) * self.clean_c_matrix.expectances[k] for k in coeffs if not k == sympy.S(1.0) and sum(list(sympy.degree_list(k))) == self.order]) denominator = sum([(coeffs[k]**2) * self.clean_c_matrix.expectances[k] for k in coeffs if not k == sympy.S(1.0)]) if denominator == 0: return False # The number is a constant! No need to partition here eta_k = numerator / denominator return (eta_k**self.alpha) * j_k >= self.theta_1
def get_max_degrees(self, polynomial): r""" Returns a list of the maximum degree of each variable appearing in the coefficients of the Dixon polynomial. The coefficients are viewed as polys in x_1, ... , x_n. """ deg_lists = [degree_list(Poly(poly, self.variables)) for poly in polynomial.coeffs()] max_degrees = [max(degs) for degs in zip(*deg_lists)] return max_degrees
def get_sos(polynomial, max_mult_power=3, dsdp_solver='dsdp', dsdp_options=DSDP_OPTIONS, eig_tol=-1e-07, epsilon=1e-07): """ :param polynomial: sympy polynomial :param max_mult_power: :param dsdp_solver: :param dsdp_options: :param eig_tol: :param epsilon: :return: string with status whether poly is a sum of squares of polynomials, and a sympy expression that is the SOSRF decomposition of the poly """ if polynomial == 0: _status = 'Zero polynomial.' return _status, nan # check polynomial is nonconstant if np.all([_d == 0 for _d in degree_list(polynomial)]): _status = 'Constant polynomial.' return _status, nan poly_indices = np.array(list(polynomial.as_poly().as_dict().keys())) monoms = get_pts_in_cvx_hull(poly_indices) num_alpha = monoms.shape[0] if not num_alpha: _status = 'Error in computing monomial indices.' return _status, nan degree = polynomial.as_poly().degree() if degree % 2: _status = 'Polynomial has odd degree. Not a sum of squares.' return _status, nan coeff_leading, max_even_divisor, remainder = get_max_even_divisor(polynomial) if remainder == 1: _status = 'Exact SOS decomposition found.' sos = coeff_leading * max_even_divisor else: _mult = get_poly_multiplier(remainder) for r in range(max_mult_power): print(f'Trying multiplier power: {r}') status_, sos_ = get_sos_helper2((_mult ** r * remainder).as_poly()) if status_ == 'Exact SOS decomposition found.': _status = 'Exact SOS decomposition found.' sos = (1 / _mult ** r) * coeff_leading * max_even_divisor * sos_.as_expr() break else: _status = 'No exact SOS decomposition found.' sos = nan return _status, sos
def get_dixon_matrix(self, polynomial): r""" Construct the Dixon matrix from the coefficients of polynomial \alpha. Each coefficient is viewed as a polynomial of x_1, ..., x_n. """ # A list of coefficients (in x_i, ..., x_n terms) of the power # products a_1, ..., a_n in Dixon's polynomial. coefficients = polynomial.coeffs() max_degrees = [ max( degree_list(Poly(poly, self.variables))[i] for poly in coefficients) for i in range(self.n) ] print('max_degrees = ', max_degrees, '\n') monomials = list(itermonomials_degree_list(self.variables, max_degrees)) monomials = sorted(monomials, reverse=True, key=monomial_key('lex', self.variables)) print('monomials - column headers :: ', monomials, '\n') dixon_matrix = Matrix( [[Poly(c, *self.variables).coeff_monomial(m) for m in monomials] for c in coefficients]) keep = [ column for column in range(dixon_matrix.shape[-1]) if any([element != 0 for element in dixon_matrix[:, column]]) ] return dixon_matrix[:, keep]
def DixonMatrix_apply(polys, xlist, alist): res = DixonPolynomial_apply(polys, xlist, alist) if isinstance(res, String): return res xsym = [i.to_sympy() for i in xlist.leaves] asym = [i.to_sympy() for i in alist.leaves] xasym = asym + xsym ###concatenating the a,x lists dix_pol = res.to_sympy() if dix_pol == sympy.sympify(0): ###check for zero return from_sympy(dix_pol) pol = sympy.poly(dix_pol, xasym) ##create sympy.poly object maxdegvec = sympy.degree_list( pol, xasym ) ###this is MaxDegVec function in mathematica. No function was written since ###its built in # print(maxdegvec) res_in = [] res_out = [] mat_dim_col = 1 mat_dim_row = 1 for i in range(len(maxdegvec) // 2): mat_dim_row = mat_dim_row * ( maxdegvec[i] + 1 ) ###Number of rows in the matrix equal to the monomials that can be #formed from the a list for i in range(len(maxdegvec) // 2, len(maxdegvec)): ###Number of collums in the matrix equal to the monomials that can be # formed from the x list mat_dim_col = mat_dim_col * (maxdegvec[i] + 1) A = sympy.zeros(mat_dim_row, mat_dim_col) #####The function lesslists is done by the command range which give a list with all the numbers less than the argument ####The itertools.products is essentially the cartesian product for the range lists that correspongd to different variables ####For example if the max degree in a,b is 1,2 we ll get two lists [0,1],[0,1,2] and the cartesian produst will be ###the couples [0,0],[0,1],[0,2],[1,0],[1,1],[1,2] this are the half-monomials as they represent the exponets for the ###a-list. ###The same proccess is repeated with the x list to get another half set of exponents for n, i in enumerate( itertools.product( *[range(i + 1) for i in maxdegvec[:len(maxdegvec) // 2]])): ##a-list exp for m, j in enumerate( itertools.product( *[range(i + 1) for i in maxdegvec[len(maxdegvec) // 2:]])): ##x-list exp # res_in.append() monomial = sympy.sympify(1) for e1, x1 in zip( list(i) + list(j), xasym ): ###this loop builds the monomials after the two half sets are joined monomial = monomial * x1**e1 res_out.append(pol.coeff_monomial(monomial)) A[n, m] = pol.coeff_monomial( monomial ) ##No problem with the constant term as with mathematica #####This if-statement is used only for a case where the matrix is a row vector or a col vector or a scalar ###In that case the "from_sympy" command will not return a 2d matrix but MAthematica alwyas gives 2d matrix(list of lists) if int(mat_dim_col) == 1 | int(mat_dim_row) == 1: res_in = from_sympy(A[0, 0]) res_out = [Expression('List', *[res_in])] return Expression('List', *res_out) return from_sympy(A)