def main(): x = Symbol("x") s = Poly(A(x), x) num = list(reversed(s.coeffs()))[:11] print s.as_expr() print num
def simplify(polynom): """Simplifies a function with binary variables """ polynom = Poly(polynom) new_polynom = 0 variables = list(polynom.free_symbols) for var_i in variables: coefficient_i = polynom.as_expr().coeff(var_i)/2 for degree in range(polynom.degree()-1): coefficient_i += polynom.as_expr().coeff(var_i ** (degree+2)) if coefficient_i.is_Float: new_polynom += float(coefficient_i) * var_i else: new_polynom += float(coefficient_i.as_coefficients_dict()[1]) * var_i for var_j in variables: if var_j != var_i: coefficient_j = coefficient_i.coeff(var_j) if coefficient_j.is_Float: new_polynom += float(coefficient_j) * var_i * var_j else: new_polynom += float(coefficient_j.as_coefficients_dict()[1]) * var_i * var_j return new_polynom + polynom.as_expr().as_coefficients_dict()[1]
def first_alpha_power_root(poly, irr_poly, p, elements_to_check=None): poly = Poly([(Poly(coeff, alpha) % irr_poly).trunc(p).as_expr() for coeff in poly.all_coeffs()], x) test_poly = Poly(1, alpha) log.debug(f"testing f:{poly}") for i in range(1, p**irr_poly.degree()): test_poly = (Poly(Poly(alpha, alpha) * test_poly, alpha) % irr_poly).set_domain(GF(p)) if elements_to_check is not None and i not in elements_to_check: continue value = Poly((Poly(poly.eval(test_poly.as_expr()), alpha) % irr_poly), alpha).trunc(p) log.debug(f"testing alpha^{i} f({test_poly})={value}") if value.is_zero: return i return -1
def plot(ax): # Declare x to be a sympy symbol, not a python variable x = symbols('x') # Declare the polynomial "fn" by providing the coefficients # of each term in in decreasing (exponent) order fn = Poly([1, -2, -120, 22, 2119, 1980], x) # fn(x) = 2x^3 - 2x^2 - 11x + 52 #fn = Poly([2, -2, -11, 52], x) # fn(x) = 2x^3 - 2x^2 - 11x + 52 # Find the real-only roots of the polynomial # and store in a numpy array of floats fn_zeros = np.asarray([np.float(r) for r in real_roots(fn)]) # Find the symbolic first derivative of "fn" and locate the real-only # zeros of this derivative to find the extrema (tangent) points fn_d1 = Derivative(fn, x, evaluate=True) fn_d1_zeros = np.asarray([np.float(r) for r in real_roots(fn_d1)]) # Combine the zeros of "fn" and the zeros of the derivative of "fn" into a # a single numpy array, then sort that array in increasing order. This array # now contains the x-coordinate of interesting points in the "fn" polynomial x_pts = np.sort(np.concatenate((fn_zeros, fn_d1_zeros))) # Get the minimum and maximum of the interesting points array x_min, x_max = x_pts[0] - 1, x_pts[-1] + 1 print(f"x_min = {x_min:.4f}, x_max = {x_max:.4f}") xa = np.linspace(x_min, x_max, 1000) # Label the graph and draw (0,0) axis lines ax.set_xlabel("x") ax.set_ylabel("y") ax.axhline(0, color='gray') ax.axvline(0, color='gray') # Create a numpy callable (numeric) function from the symbolic "fn" polynomial fn_lambda = lambdify(x, fn.as_expr(), modules='numpy') ax.plot(xa, fn_lambda(xa), linewidth=2) # Plot the zeros and derivative roots on the line graph ax.scatter(fn_zeros, fn_lambda(fn_zeros), color='red') ax.scatter(fn_d1_zeros, fn_lambda(fn_d1_zeros), color='green') # Set the graph title to the polynomial expressed in LaTeX format ax.set_title(f"$y = {latex(fn.as_expr())}$")
def tex_lin(a, b): p = Poly([a, b], x, domain='QQ') return latex(p.as_expr())
class QUBOModel: def __init__(self, model=0): """ Parameters ---------- model : sympy.core.expr.Expr or subclasses should have as input the objective function """ self.poly_model = model self.objective_function = deepcopy(model) self.constraints = [] self.penalties = [] self.qubo_matrix = None self.slacks = [] @property def poly_model(self): """The function, which will be transformed into a qubo_matrix """ return self._poly_model @poly_model.setter def poly_model(self, polynom): if isinstance(polynom, (int, float)): self._poly_model = polynom elif not Poly(polynom).is_quadratic: raise ValueError( "The poly_model is not quadratic and therefore " "cannot be transformed into a QUBO." ) else: self._poly_model = Poly(polynom) @property def variables(self): """Set of variables in the QUBOModel Object """ if not isinstance(self.poly_model, (int, float)): variables = self.poly_model.free_symbols penalties = penalty_symbols_as_set(self.penalties) if penalties: return variables.difference(penalties) return variables return set() @property def num_variables(self): return len(self.variables) @property def binary_variables(self): """Set of variables, without slack variables """ binary_variables_temp = set() if self.objective_function != 0: binary_variables_temp = binary_variables_temp.union( self.objective_function.free_symbols) if not np.array(self.constraints).all(): for cons in self.constraints: if cons is not None: binary_variables_temp = binary_variables_temp.union(cons.variables) penalties = penalty_symbols_as_set(self.penalties) if penalties: return binary_variables_temp.difference(penalties) return binary_variables_temp return binary_variables_temp @property def num_binary_variables(self): return len(self.binary_variables) @property def slack_variables(self): if not np.array(self.slacks).all(): return set() slack_variables_temp = set() for slack_cons in self.slacks: if slack_cons is not None: slack_variables_temp = slack_variables_temp.union(slack_cons.free_symbols) return slack_variables_temp @property def num_slack_variables(self): return len(self.slack_variables) @property def offset(self): """The constant in the poly_model, which will not be considered in the qubo_matrix """ if self.poly_model != 0: return float(self._poly_model.as_expr().as_coefficients_dict()[1]) return 0 @property def offset_objective_function(self): if self.objective_function != 0: return float(self.objective_function.as_expr().as_coefficients_dict()[1]) return 0 def __len__(self): return len(self.variables) def __repr__(self): return f"{self.__class__.__name__}(Size={len(self)})" def model_to_qubo(self, return_offset=False): """Transforms the QUBO Model into a Matrix, which can be used as an input for various solver Returns ------- matrix: np.array QUBO Matrix of the model. """ if isinstance(self.poly_model, (float, int)): return 0 penalties = penalty_symbols_as_set(self.penalties) variables = sort_variables(self.variables.difference(penalties)) if penalties: matrix = np.zeros((self.num_variables, self.num_variables), dtype=object) else: matrix = np.zeros((self.num_variables, self.num_variables)) for var_i_index, var_i in enumerate(variables): coefficient_i = self.poly_model.as_expr().coeff(var_i) for degree in range(self.poly_model.degree()-1): coefficient_i += self.poly_model.as_expr().coeff(var_i ** (degree+2)) if coefficient_i.is_Float: matrix[(var_i_index, var_i_index)] = float(coefficient_i) elif coefficient_i.free_symbols.issubset(penalties): matrix[(var_i_index, var_i_index)] = coefficient_i else: matrix[(var_i_index, var_i_index)] = float( coefficient_i.as_coefficients_dict()[1] ) for var_j_index, var_j in enumerate(variables): if var_j != var_i: coefficient_j = coefficient_i.coeff(var_j) if coefficient_j.is_Float: matrix[(var_i_index, var_j_index)] = float(coefficient_j)/2 matrix[(var_j_index, var_i_index)] = float(coefficient_j)/2 elif coefficient_j.free_symbols.issubset(penalties): matrix[(var_i_index, var_j_index)] = coefficient_j/2 matrix[(var_j_index, var_i_index)] = coefficient_j/2 else: matrix[(var_i_index, var_j_index)] = float( coefficient_j.as_coefficients_dict()[1] )/2 matrix[(var_j_index, var_i_index)] = float( coefficient_j.as_coefficients_dict()[1] )/2 self.qubo_matrix = matrix if return_offset: return self.qubo_matrix, self.offset return matrix def add_constraint(self, constraint, kind, penalty=None, bounds=None): """Adds Constraint to the objective function or the model. If a less than or greater than constraint is added, the corresponding slack variable doesnt consider any other constraint. The slackvariable has the symbol name "_z". Parameters ---------- constraint : sympy constraint, which should be added to the objective function kind : string 'eq' (equal), 'gt' (greater or equal than) or 'lt' (less or equal than) (in)equality penalty : float or symbol, optional Penalty factor for the constraint, by default: upper - lower bound of the constraint bounds : tuple, optional lower and upper bound for the constraint, by default None Returns ------- sympy poly_model + penalty * (constraint ** 2) Raises ------ ValueError is raised if the constraint is not linear. Otherwise it cannot transformed into a QUBO NameError is raised if neither of the kinds above is given for kind """ if not Poly(constraint).is_linear: raise ValueError( "The Constraint is not linear and therefore it " "cannot be transformed into a QUBO" ) if penalty is None: penalty = sum([abs(coef) for coef in Poly(constraint).coeffs()]) constraint, special = special_constraint(constraint, kind) if special or kind =='eq': if bounds is not None: warnings.warn( "The bounds will be ignored, since there are no " "slack variables required." ) if kind == 'eq': cons = Constraint(constraint, kind, penalty) self.poly_model = self.poly_model + cons.penalty * cons.constraint**2 cons = Constraint(constraint, kind, penalty, special) self.poly_model = self.poly_model + cons.penalty * cons.constraint self.constraints = np.append(self.constraints, cons) self.slacks = np.append(self.slacks,cons.slack) self.penalties = np.append(self.penalties, cons.penalty) return cons elif kind in ('lt', 'gt'): if kind == 'gt': constraint = -1 * constraint if bounds is None: cons = Constraint( constraint, kind, penalty, slack_variables_start_idx=self.num_variables ) else: cons = Constraint( constraint, kind, penalty, slack_variables_start_idx=self.num_variables, bounds=bounds ) if cons.slack == 400: return self.poly_model if cons.slack == 0: warnings.warn('The constraint is an equation') self.poly_model = self.poly_model + cons.penalty * cons.constraint**2 self.slacks = np.append(self.slacks, cons.slack) self.constraints = np.append(self.constraints, cons) self.penalties = np.append(self.penalties, cons.penalty) return cons if kind == 'gt': cons.constraint -= cons.slack else: cons.constraint += cons.slack self.constraints = np.append(self.constraints, cons) self.poly_model = self.poly_model + penalty * (cons.constraint ** 2) self.slacks = np.append(self.slacks, cons.slack) self.penalties = np.append(self.penalties, cons.penalty) return cons else: raise NameError('Unknown kind of inequality') def evaluate_objective_function(self, bitstring): """Evaluates the objective function for the bitstring Parameters ---------- bitstring : np.array a bistring array with 0 and 1 Returns ------- float solution of objective function at the point bitstring Raises ------ ValueError if the length of bitstring is not the same as the amount of variables without slack variables if bitstring has an element, which is non zero or not one """ if any(bit != 0 or bit != 1 for bit in bitstring): raise ValueError("bitstring must only of 0 and 1s") if not (self.num_binary_variables == len(bitstring) or self.num_variables == len(bitstring)): raise ValueError("The shape of the solution and the model does not fit.") return bitstring @ self.qubo_matrix[0:len(bitstring), 0:len(bitstring)] @ bitstring \ + self.offset_objective_function def evaluate_model(self, bitstring): """Evaluates the model, which includes the constraints. Parameters ---------- bitstring : np.array a bistring array with 0 and 1 Returns ------- float solution of model at the point bitstring Raises ------ ValueError if the length of bitstring is not the same as the amount of variables of the model if bitstring has an element, which is non zero or not one """ if any(bit != 0 or bit != 1 for bit in bitstring): raise ValueError("bitstring must only of 0 and 1s") if self.num_variables != len(bitstring): raise ValueError("The shape of the solution and the model does not fit") return bitstring @ self.qubo_matrix @ bitstring + self.offset def subs(self, input, inplace=False): """Substitues the sympy symbols in the model with the input Parameters ---------- input : array The array should contain tuples with one symbol and one int or float. inplace : bool, optional if true, the whole model will be subsituted, otherwise a copy will be created. By default False Returns ------- QUBOModel The return is the QUBOModel object """ if inplace: self.poly_model = self.poly_model.subs(input) for i, penalty in enumerate(self.penalties): if isinstance(penalty, Symbol): self.penalties[i] = self.penalties[i].subs(input) if self.qubo_matrix is not None: self.qubo_matrix = subs_matrix(self.qubo_matrix, input) self.qubo_matrix.astype('float') return self QUBOModel_copy = deepcopy(self) QUBOModel_copy.poly_model = QUBOModel_copy.poly_model.subs(input) for i, penalty in enumerate(QUBOModel_copy.penalties): if isinstance(penalty, Symbol): QUBOModel_copy.penalties[i] = QUBOModel_copy.penalties[i].subs(input) if QUBOModel_copy.qubo_matrix is not None: QUBOModel_copy.qubo_matrix = subs_matrix(QUBOModel_copy.qubo_matrix, input) QUBOModel_copy.qubo_matrix.astype('float') return QUBOModel_copy
def tex_poly(gc, domain='ZZ'): p = Poly(gc, x, domain='ZZ') ltx = latex(p.as_expr()) return ltx
G0.add_edge(argv[2 + 2 * i], argv[3 + 2 * i]) for v in G0.nodes(): G0.node[v]['state'] = 'S' s = '' for i in range(2 + 2 * nl, len(argv)): me = argv[i] s += me + ' ' if me not in G0.nodes(): print me, 'not in G' exit() G0.node[me]['state'] = 'I' #G = nx.convert_node_labels_to_integers(G0,label_attribute='id') G = deepcopy(G0) onum = Poly(0, x) oden = Poly(1, x) stepdown(Poly(1, x), Poly(1, x)) a = onum.gcd(oden) onum, no = onum.div(a) oden, no = oden.div(a) # the output format is: [active nodes (separated by blanks)], [solution polynomial] print s.strip() + ', (' + str(onum.as_expr()) + ')/(' + str( oden.as_expr()) + ')' # # # # # # # # # # # # # # # # #
def _piecewise_symbolic_integral(cache, integrand, x, y=None): """ Computes the symbolic integral of 'x' of a piecewise polynomial 'integrand'. The result might be a sympy expression or a numerical value. Parameters ---------- integrand : list A list of (lower bound, upper bound, polynomial) x : object A string/sympy expression representing the integration variable """ cache_hit = [0, 0] if (cache is not None) else None res = 0 for l, u, p in integrand: symx = symvar(x) symy = symvar(y) if y else symvar("aux_y") syml = Poly(to_sympy(l), symy, domain="QQ") symu = Poly(to_sympy(u), symy, domain="QQ") if type(p) != Poly: symp = Poly(to_sympy(p), symx, domain="QQ") else: symp = Poly(p.as_expr(), symx, symy, domain="QQ") #print("integrating", symp.as_expr(), f"in d{symx} with bounds", [syml.as_expr(), symu.as_expr()]) if cache is not None: # for cache = True """ hierarchical cache, where we cache: - the anti-derivatives for integrands, retrieved by: (None, None, integrand key) - the partial integration term, retrieved by: (lower bound key, None, integrand key) (None, upper bound key, integrand key) - the whole integration, retrieved by: (lower bound key, upper bound key, integrand key) """ # cache keys for bounds k_lower = MP2WMI.sympy_to_tuple(syml) k_upper = MP2WMI.sympy_to_tuple(symu) k_poly = MP2WMI.sympy_to_tuple( symp) # cache key for integrand polynomial k_full = (k_lower, k_upper, k_poly) #print("========= KEYS =========") #print("lower:", syml.as_expr(), "-->", k_lower) #print("upper:", symu.as_expr(), "-->", k_upper) #print("poly:", symp.as_expr(), "-->", k_poly) #print("========================") if k_full in cache: # retrieve the whole integration cache_hit[True] += 1 symintegral = MP2WMI.tuple_to_sympy( cache[k_full], symx, symy) symintegral = symintegral.subs(symintegral.gens[0], symy) else: # retrieve partial integration terms terms = [None, None] k_part_l = (k_lower, k_poly) k_part_u = (k_upper, k_poly) if k_part_l in cache: partial_l = MP2WMI.tuple_to_sympy( cache[k_part_l], symx, symy) terms[0] = partial_l.subs(partial_l.gens[0], symy) if k_part_u in cache: partial_u = MP2WMI.tuple_to_sympy( cache[k_part_u], symx, symy) terms[1] = partial_u.subs(partial_u.gens[0], symy) if None not in terms: cache_hit[True] += 1 else: # retrieve anti-derivative k_anti = (k_poly, ) if k_anti in cache: cache_hit[True] += 1 antidrv = MP2WMI.tuple_to_sympy( cache[k_anti], symx, symy) else: cache_hit[False] += 1 antidrv = symp.integrate(symx) cache[k_anti] = MP2WMI.sympy_to_tuple(antidrv) # cache partial integration terms if terms[0] is None: terms[0] = Poly(antidrv.as_expr(), symx, domain=f'QQ[{symy}]').eval( {symx: syml.as_expr()}) terms[0] = Poly(terms[0].as_expr(), symx, symy, domain="QQ") cache[k_part_l] = MP2WMI.sympy_to_tuple(terms[0]) if terms[1] is None: terms[1] = Poly(antidrv.as_expr(), symx, domain=f'QQ[{symy}]').eval( {symx: symu.as_expr()}) terms[1] = Poly(terms[1].as_expr(), symx, symy, domain="QQ") cache[k_part_u] = MP2WMI.sympy_to_tuple(terms[1]) #print("subs: (", terms[1].as_expr(), ") - (", terms[0].as_expr(), ")") symintegral = terms[1] - terms[0] if not isinstance(symintegral, Poly): symintegral = Poly(symintegral, symx, symy, domain='QQ') cache[k_full] = MP2WMI.sympy_to_tuple(symintegral) else: # for cache = False antidrv = symp.integrate(symx) lower = Poly(antidrv.as_expr(), symx, domain=f'QQ[{symy}]').eval({symx: syml.as_expr()}) lower = Poly(lower.as_expr(), symx, symy, domain="QQ") upper = Poly(antidrv.as_expr(), symx, domain=f'QQ[{symy}]').eval({symx: symu.as_expr()}) upper = Poly(upper.as_expr(), symx, symy, domain="QQ") symintegral = upper - lower res += symintegral #print("integral:", symintegral.as_expr()) #print() #print("RESULT:", res) #print("**************************************************") return res, cache_hit
def piecewise_symbolic_integral(self, integrand, x, y=None): """ Computes the symbolic integral of 'x' of a piecewise polynomial 'integrand'. The result might be a sympy expression or a numerical value. Parameters ---------- integrand : list A list of (lower bound, upper bound, polynomial) x : object A string/sympy expression representing the integration variable """ res = 0 #logger.debug(f"\t\t\t\tpiecewise_symbolic_integral") #logger.debug(f"\t\t\t\tlen(integrand): {len(integrand)} --- y: {y}") for l, u, p in integrand: symx = symvar(x) symy = symvar(y) if y else symvar("aux_y") syml = Poly(to_sympy(l), symy, domain="QQ") symu = Poly(to_sympy(u), symy, domain="QQ") #logger.debug(f"\t\t\t\t\tl: {l} --- u: {u} --- p: {p}") if type(p) != Poly: symp = Poly(to_sympy(p), symx, domain="QQ") else: symp = Poly(p.as_expr(), symx, domain=f"QQ[{symy}]") if y else p if self.cache is not None: # for cache = True """ hierarchical cache, where we cache: - the anti-derivatives for integrands, retrieved by the same integrand key - the partial integration term, retrieved by the same (integrand key, lower / upper bound key) pair - the whole integration, retrieved by the same (integrand key, lower bound key, upper bound key) pair """ bds_ks = [MPWMI.cache_key(syml)[0], MPWMI.cache_key(symu)[0]] # cache keys for bounds bds = [syml.as_expr(), symu.as_expr()] p_ks = MPWMI.cache_key(symp) # cache key for integrand polynomial trm_ks = [(bds_ks[0], p_ks[0]), (bds_ks[1], p_ks[0])] if (bds_ks[0], bds_ks[1], p_ks[0]) in self.cache: # retrieve the whole integration self.cache_hit[True] += 1 symintegral = self.cache[(bds_ks[0], bds_ks[1], p_ks[0])] symintegral = symintegral.subs(symintegral.gens[0], symy) else: terms = [] for tk in trm_ks: # retrieve partial integration terms if tk in self.cache: trm = self.cache[tk] trm = trm.subs(trm.gens[0], symy) terms.append(trm) else: terms.append(None) if None not in terms: self.cache_hit[True] += 1 else: if p_ks[0] in self.cache: # retrieve anti-derivative self.cache_hit[True] += 1 antidrv = self.cache[p_ks[0]] antidrv_expr = antidrv.as_expr().subs(antidrv.gens[0], symx) antidrv = Poly(antidrv_expr, symx, domain=f"QQ[{symy}]") if y \ else Poly(antidrv_expr, symx, domain="QQ") else: self.cache_hit[False] += 1 antidrv = symp.integrate(symx) for k in p_ks: # cache anti-derivative self.cache[k] = antidrv for i in range(len(terms)): if terms[i] is not None: continue terms[i] = antidrv.eval({symx: bds[i]}) terms[i] = Poly(terms[i].as_expr(), symy, domain="QQ") for k in p_ks: # cache partial integration terms self.cache[(bds_ks[i], k)] = terms[i] symintegral = terms[1] - terms[0] for k in p_ks: # cache the whole integration self.cache[(bds_ks[0], bds_ks[1], k)] = symintegral else: # for cache = False antidrv = symp.integrate(symx) symintegral = antidrv.eval({symx: symu.as_expr()}) - \ antidrv.eval({symx: syml.as_expr()}) res += symintegral #logger.debug(f"\t\t\t\t\tsymintegral: {symintegral}") return res
for v in G.nodes(): if G.node[v]['state'] != 'V': for u in G.nodes(): if G.node[u]['state'] != 'V': G.node[u]['state'] = 'S' G.node[v]['state'] = 'I' onum = Poly(0, x) oden = Poly(1, x) stepdown(Poly(1, x), Poly(1, x)) a = onum.mul(soden) b = sonum.mul(oden) c = a.add(b) d = oden.mul(soden) a = d.gcd(c) sonum, no = c.div(a) soden, no = d.div(a) print '(' + str(sonum.as_expr()) + ')/(' + str( soden.as_expr()) + ')' print '-------------' a = soden.mul_ground(G.number_of_nodes()) b = sonum.gcd(a) c, no = sonum.div(b) d, no = a.div(b) print s.strip() + ', (' + str(c.as_expr()) + ')/(' + str(d.as_expr()) + ')' # # # # # # # # # # # # # # # # #
from sympy import Poly, div from helpers import poly_from_int, int2base base = 2 expression = Poly('x**2 + 1', modulus=base) # enumerate polynomials enumerate_from = '010' enumerate_to = '111' digits = len(enumerate_to) for i in range(int(enumerate_from, base), int(enumerate_to, base) + 1): print(int2base(i, base).rjust(digits, '0')) divider = poly_from_int(i, base) q, r = div(expression.as_expr(), divider.as_expr(), modulus=base) if r != 0: continue print('%s - OK' % divider)
return f_4 #%% order = 4 K_x, coef = K_var_no_central([y, a], order) eq1 = Poly(xpunto, x, y).subs(x, K_x) eq1_filtrada = filtro_f(eq1, [x, y, a], order) eq2 = Poly(diff(K_x, y) * ypunto, x, y, a) eq2 = eq2.subs(x, K_x) eq2_filtrada = filtro_f(eq2, [x, y, a], order) eq_final = Poly(eq1_filtrada - eq2_filtrada, x, y, a) eq_final_info = eq_final.as_expr().as_coefficients_dict() monomios = eq_final_info.keys() monomios2 = [] for monos in monomios: monomios2.append(monos) list_res = {} for j in range(len(monomios2)): monos = monomios2[j] for k in range(len(coef)): coeff = coef[k] res = solve(monos, coeff) if len(res) > 0: if coeff not in list_res: list_res[coeff] = res[0]