def linear_arg(arg): """ Test if arg is of form a*s+b, raise exception if not. """ if not arg.is_polynomial(s): raise exception(fact) p = Poly(arg, s) if p.degree() != 1: raise exception(fact) return p.all_coeffs()
def lower_degree_to(polynomial: Poly, max_polynomial_degree: int) -> Poly: """ Lowers the degree of the polynomial by using Chebyshev polynomials. :param polynomial: polynomial to lower the degree of :param max_polynomial_degree: maximum polynomial degree to lower to :return: polynomial with the degree less than or equal to `max_polynomial_degree` :rtype: Poly """ while polynomial.degree() > max_polynomial_degree: normalised_chebyshev_polynomial = get_normalised_nth_chebyshev_polynomial(polynomial.degree()) polynomial -= normalised_chebyshev_polynomial * polynomial.LC() return polynomial
def fn(theta, phi, pa, tau): x = Symbol('x') pa = Symbol('pa') phi = Symbol('phi') theta = Symbol('theta') tau = Symbol('tau') f = (2 * pa * phi**2) / tau**5 + x**5 + ( 2 * pa * phi**2 * cos(theta) ) / tau**5 - (2 * pa**2 * phi**2 * cos(theta)) / tau**5 - ( 2 * pa * phi**2 * cos(theta)**2 ) / tau**5 - (2 * pa * phi**2 * cos(theta)**3) / tau**5 + ( 2 * pa**2 * phi**2 * cos(theta)**3) / tau**5 + x**4 * ( 4 / tau + cos(theta) / tau - (2 * pa * cos(theta)) / tau - cos(theta)**2 / tau) + x * ( tau**(-4) + (4 * phi**2) / tau**4 + (4 * pa * phi**2) / tau**4 + cos(theta) / tau**4 - (2 * pa * cos(theta)) / tau**4 + (4 * phi**2 * cos(theta)) / tau**4 - (2 * pa * phi**2 * cos(theta)) / tau**4 - (2 * pa**2 * phi**2 * cos(theta)) / tau**4 - cos(theta)**2 / tau**4 - (4 * phi**2 * cos(theta)**2) / tau**4 - cos(theta)**3 / tau**4 + (2 * pa * cos(theta)**3) / tau**4 - (4 * phi**2 * cos(theta)**3) / tau**4 + (6 * pa * phi**2 * cos(theta)**3) / tau**4 - (2 * pa**2 * phi**2 * cos(theta)**3) / tau**4) + x**2 * ( 4 / tau**3 + (8 * phi**2) / tau**3 + (2 * pa * phi**2) / tau**3 + (3 * cos(theta)) / tau**3 - (6 * pa * cos(theta)) / tau**3 + (4 * phi**2 * cos(theta)) / tau**3 - (4 * pa * phi**2 * cos(theta)) / tau**3 - (3 * cos(theta)**2) / tau**3 - (4 * phi**2 * cos(theta)**2) / tau**3 + (2 * pa * phi**2 * cos(theta)**2) / tau**3 - (2 * cos(theta)**3) / tau**3 + (4 * pa * cos(theta)**3) / tau**3) + x**3 * ( 6 / tau**2 + (4 * phi**2) / tau**2 + (3 * cos(theta)) / tau**2 - (6 * pa * cos(theta)) / tau**2 - (3 * cos(theta)**2) / tau**2 - cos(theta)**3 / tau**2 + (2 * pa * cos(theta)**3) / tau**2) p = Poly(f, x) ans = [p.root(k).evalf() for k in range(p.degree())] for i, a in enumerate(ans): print(i, a) return ans
def check_convergence(numer, denom, n): """ Returns (h, g, p) where -- h is: > 0 for convergence of rate 1/factorial(n)**h < 0 for divergence of rate factorial(n)**(-h) = 0 for geometric or polynomial convergence or divergence -- abs(g) is: > 1 for geometric convergence of rate 1/h**n < 1 for geometric divergence of rate h**n = 1 for polynomial convergence or divergence (g < 0 indicates an alternating series) -- p is: > 1 for polynomial convergence of rate 1/n**h <= 1 for polynomial divergence of rate n**(-h) """ from sympy import Poly npol = Poly(numer, n) dpol = Poly(denom, n) p = npol.degree() q = dpol.degree() rate = q - p if rate: return rate, None, None constant = dpol.LC() / npol.LC() if abs(constant) != 1: return rate, constant, None if npol.degree() == dpol.degree() == 0: return rate, constant, 0 pc = npol.all_coeffs()[1] qc = dpol.all_coeffs()[1] return rate, constant, (qc - pc) / dpol.LC()
def check_convergence(numer, denom, n): """ Returns (h, g, p) where -- h is: > 0 for convergence of rate 1/factorial(n)**h < 0 for divergence of rate factorial(n)**(-h) = 0 for geometric or polynomial convergence or divergence -- abs(g) is: > 1 for geometric convergence of rate 1/h**n < 1 for geometric divergence of rate h**n = 1 for polynomial convergence or divergence (g < 0 indicates an alternating series) -- p is: > 1 for polynomial convergence of rate 1/n**h <= 1 for polynomial divergence of rate n**(-h) """ from sympy import Poly npol = Poly(numer, n) dpol = Poly(denom, n) p = npol.degree() q = dpol.degree() rate = q - p if rate: return rate, None, None constant = dpol.LC() / npol.LC() if abs(constant) != 1: return rate, constant, None if npol.degree() == dpol.degree() == 0: return rate, constant, 0 pc = npol.all_coeffs()[1] qc = dpol.all_coeffs()[1] return rate, constant, (qc - pc)/dpol.LC()
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 _rewrite_gamma(f, s, a, b): """ Try to rewrite the product f(s) as a product of gamma functions, so that the inverse mellin transform of f can be expressed as a meijer G function. Return (an, ap), (bm, bq), arg, exp, fac such that G((an, ap), (bm, bq), arg/z**exp)*fac is the inverse mellin transform of f(s). Raises IntegralTransformError or MellinTransformStripError on failure. It is asserted that f has no poles in the fundamental strip designated by (a, b). One of a and b is allowed to be None. The fundamental strip is important, because it determines the inversion contour. This function can handle exponentials, linear factors, trigonometric functions. This is a helper function for inverse_mellin_transform that will not attempt any transformations on f. >>> from sympy.integrals.transforms import _rewrite_gamma >>> from sympy.abc import s >>> from sympy import oo >>> _rewrite_gamma(s*(s+3)*(s-1), s, -oo, oo) (([], [-3, 0, 1]), ([-2, 1, 2], []), 1, 1, -1) >>> _rewrite_gamma((s-1)**2, s, -oo, oo) (([], [1, 1]), ([2, 2], []), 1, 1, 1) Importance of the fundamental strip: >>> _rewrite_gamma(1/s, s, 0, oo) (([1], []), ([], [0]), 1, 1, 1) >>> _rewrite_gamma(1/s, s, None, oo) (([1], []), ([], [0]), 1, 1, 1) >>> _rewrite_gamma(1/s, s, 0, None) (([1], []), ([], [0]), 1, 1, 1) >>> _rewrite_gamma(1/s, s, -oo, 0) (([], [1]), ([0], []), 1, 1, -1) >>> _rewrite_gamma(1/s, s, None, 0) (([], [1]), ([0], []), 1, 1, -1) >>> _rewrite_gamma(1/s, s, -oo, None) (([], [1]), ([0], []), 1, 1, -1) >>> _rewrite_gamma(2**(-s+3), s, -oo, oo) (([], []), ([], []), 1/2, 1, 8) """ from itertools import repeat from sympy import (Poly, gamma, Mul, re, RootOf, exp as exp_, E, expand, roots, ilcm, pi, sin, cos, tan, cot, igcd, exp_polar) # Our strategy will be as follows: # 1) Guess a constant c such that the inversion integral should be # performed wrt s'=c*s (instead of plain s). Write s for s'. # 2) Process all factors, rewrite them independently as gamma functions in # argument s, or exponentials of s. # 3) Try to transform all gamma functions s.t. they have argument # a+s or a-s. # 4) Check that the resulting G function parameters are valid. # 5) Combine all the exponentials. a_, b_ = S([a, b]) def left(c, is_numer): """ Decide whether pole at c lies to the left of the fundamental strip. """ # heuristically, this is the best chance for us to solve the inequalities c = expand(re(c)) if a_ is None: return c < b_ if b_ is None: return c <= a_ if (c >= b_) is True: return False if (c <= a_) is True: return True if is_numer: return None if a_.free_symbols or b_.free_symbols or c.free_symbols: return None # XXX #raise IntegralTransformError('Inverse Mellin', f, # 'Could not determine position of singularity %s' # ' relative to fundamental strip' % c) raise MellinTransformStripError('Pole inside critical strip?') # 1) s_multipliers = [] for g in f.atoms(gamma): if not g.has(s): continue arg = g.args[0] if arg.is_Add: arg = arg.as_independent(s)[1] coeff, _ = arg.as_coeff_mul(s) s_multipliers += [coeff] for g in f.atoms(sin, cos, tan, cot): if not g.has(s): continue arg = g.args[0] if arg.is_Add: arg = arg.as_independent(s)[1] coeff, _ = arg.as_coeff_mul(s) s_multipliers += [coeff/pi] s_multipliers = [abs(x) for x in s_multipliers if x.is_real] common_coefficient = S(1) for x in s_multipliers: if not x.is_Rational: common_coefficient = x break s_multipliers = [x/common_coefficient for x in s_multipliers] if any(not x.is_Rational for x in s_multipliers): raise NotImplementedError s_multiplier = common_coefficient/reduce(ilcm, [S(x.q) for x in s_multipliers], S(1)) if s_multiplier == common_coefficient: if len(s_multipliers) == 0: s_multiplier = common_coefficient else: s_multiplier = common_coefficient \ *reduce(igcd, [S(x.p) for x in s_multipliers]) exponent = S(1) fac = S(1) f = f.subs(s, s/s_multiplier) fac /= s_multiplier exponent = 1/s_multiplier if a_ is not None: a_ *= s_multiplier if b_ is not None: b_ *= s_multiplier # 2) numer, denom = f.as_numer_denom() numer = Mul.make_args(numer) denom = Mul.make_args(denom) args = zip(numer, repeat(True)) + zip(denom, repeat(False)) facs = [] dfacs = [] # *_gammas will contain pairs (a, c) representing Gamma(a*s + c) numer_gammas = [] denom_gammas = [] # exponentials will contain bases for exponentials of s exponentials = [] def exception(fact): return IntegralTransformError("Inverse Mellin", f, "Unrecognised form '%s'." % fact) while args: fact, is_numer = args.pop() if is_numer: ugammas, lgammas = numer_gammas, denom_gammas ufacs, lfacs = facs, dfacs else: ugammas, lgammas = denom_gammas, numer_gammas ufacs, lfacs = dfacs, facs def linear_arg(arg): """ Test if arg is of form a*s+b, raise exception if not. """ if not arg.is_polynomial(s): raise exception(fact) p = Poly(arg, s) if p.degree() != 1: raise exception(fact) return p.all_coeffs() # constants if not fact.has(s): ufacs += [fact] # exponentials elif fact.is_Pow or isinstance(fact, exp_): if fact.is_Pow: base = fact.base exp = fact.exp else: base = exp_polar(1) exp = fact.args[0] if exp.is_Integer: cond = is_numer if exp < 0: cond = not cond args += [(base, cond)]*abs(exp) continue elif not base.has(s): a, b = linear_arg(exp) if not is_numer: base = 1/base exponentials += [base**a] facs += [base**b] else: raise exception(fact) # linear factors elif fact.is_polynomial(s): p = Poly(fact, s) if p.degree() != 1: # We completely factor the poly. For this we need the roots. # Now roots() only works in some cases (low degree), and RootOf # only works without parameters. So try both... coeff = p.LT()[1] rs = roots(p, s) if len(rs) != p.degree(): rs = RootOf.all_roots(p) ufacs += [coeff] args += [(s - c, is_numer) for c in rs] continue a, c = p.all_coeffs() ufacs += [a] c /= -a # Now need to convert s - c if left(c, is_numer): ugammas += [(S(1), -c + 1)] lgammas += [(S(1), -c)] else: ufacs += [-1] ugammas += [(S(-1), c + 1)] lgammas += [(S(-1), c)] elif isinstance(fact, gamma): a, b = linear_arg(fact.args[0]) if is_numer: if (a > 0 and (left(-b/a, is_numer) is False)) or \ (a < 0 and (left(-b/a, is_numer) is True)): raise NotImplementedError('Gammas partially over the strip.') ugammas += [(a, b)] elif isinstance(fact, sin): # We try to re-write all trigs as gammas. This is not in # general the best strategy, since sometimes this is impossible, # but rewriting as exponentials would work. However trig functions # in inverse mellin transforms usually all come from simplifying # gamma terms, so this should work. a = fact.args[0] if is_numer: # No problem with the poles. gamma1, gamma2, fac_ = gamma(a/pi), gamma(1 - a/pi), pi else: gamma1, gamma2, fac_ = _rewrite_sin(linear_arg(a), s, a_, b_) args += [(gamma1, not is_numer), (gamma2, not is_numer)] ufacs += [fac_] elif isinstance(fact, tan): a = fact.args[0] args += [(sin(a, evaluate=False), is_numer), (sin(pi/2 - a, evaluate=False), not is_numer)] elif isinstance(fact, cos): a = fact.args[0] args += [(sin(pi/2 - a, evaluate=False), is_numer)] elif isinstance(fact, cot): a = fact.args[0] args += [(sin(pi/2 - a, evaluate=False), is_numer), (sin(a, evaluate=False), not is_numer)] else: raise exception(fact) fac *= Mul(*facs)/Mul(*dfacs) # 3) an, ap, bm, bq = [], [], [], [] for gammas, plus, minus, is_numer in [(numer_gammas, an, bm, True), (denom_gammas, bq, ap, False)]: while gammas: a, c = gammas.pop() if a != -1 and a != +1: # We use the gamma function multiplication theorem. p = abs(S(a)) newa = a/p newc = c/p assert a.is_Integer for k in range(p): gammas += [(newa, newc + k/p)] if is_numer: fac *= (2*pi)**((1 - p)/2) * p**(c - S(1)/2) exponentials += [p**a] else: fac /= (2*pi)**((1 - p)/2) * p**(c - S(1)/2) exponentials += [p**(-a)] continue if a == +1: plus.append(1 - c) else: minus.append(c) # 4) # TODO # 5) arg = Mul(*exponentials) # for testability, sort the arguments an.sort() ap.sort() bm.sort() bq.sort() return (an, ap), (bm, bq), arg, exponent, fac
def _rewrite_gamma(f, s, a, b): """ Try to rewrite the product f(s) as a product of gamma functions, so that the inverse mellin transform of f can be expressed as a meijer G function. Return (an, ap), (bm, bq), arg, exp, fac such that G((an, ap), (bm, bq), arg/z**exp)*fac is the inverse mellin transform of f(s). Raises IntegralTransformError or ValueError on failure. It is asserted that f has no poles in the fundamental strip designated by (a, b). One of a and b is allowed to be None. The fundamental strip is important, because it determines the inversion contour. This function can handle exponentials, linear factors, trigonometric functions. This is a helper function for inverse_mellin_transform that will not attempt any transformations on f. >>> from sympy.integrals.transforms import _rewrite_gamma >>> from sympy.abc import s >>> from sympy import oo >>> _rewrite_gamma(s*(s+3)*(s-1), s, -oo, oo) (([], [-3, 0, 1]), ([-2, 1, 2], []), 1, 1, -1) >>> _rewrite_gamma((s-1)**2, s, -oo, oo) (([], [1, 1]), ([2, 2], []), 1, 1, 1) Importance of the fundamental strip: >>> _rewrite_gamma(1/s, s, 0, oo) (([1], []), ([], [0]), 1, 1, 1) >>> _rewrite_gamma(1/s, s, None, oo) (([1], []), ([], [0]), 1, 1, 1) >>> _rewrite_gamma(1/s, s, 0, None) (([1], []), ([], [0]), 1, 1, 1) >>> _rewrite_gamma(1/s, s, -oo, 0) (([], [1]), ([0], []), 1, 1, -1) >>> _rewrite_gamma(1/s, s, None, 0) (([], [1]), ([0], []), 1, 1, -1) >>> _rewrite_gamma(1/s, s, -oo, None) (([], [1]), ([0], []), 1, 1, -1) >>> _rewrite_gamma(2**(-s+3), s, -oo, oo) (([], []), ([], []), 1/2, 1, 8) """ from itertools import repeat from sympy import (Poly, gamma, Mul, re, RootOf, exp as exp_, E, expand, roots, ilcm, pi, sin, cos, tan, cot, igcd) # Our strategy will be as follows: # 1) Guess a constant c such that the inversion integral should be # performed wrt s'=c*s (instead of plain s). Write s for s'. # 2) Process all factors, rewrite them independently as gamma functions in # argument s, or exponentials of s. # 3) Try to transform all gamma functions s.t. they have argument # a+s or a-s. # 4) Check that the resulting G function parameters are valid. # 5) Combine all the exponentials. a_, b_ = S([a, b]) def left(c, is_numer): """ Decide whether pole at c lies to the left of the fundamental strip. """ # heuristically, this is the best chance for us to solve the inequalities c = expand(re(c)) if a_ is None: return c < b_ if b_ is None: return c <= a_ if (c >= b_) is True: return False if (c <= a_) is True: return True if is_numer: return None if a_.free_symbols or b_.free_symbols or c.free_symbols: return None # XXX #raise IntegralTransformError('Inverse Mellin', f, # 'Could not determine position of singularity %s' # ' relative to fundamental strip' % c) raise ValueError('Pole inside critical strip?') # 1) s_multipliers = [] for g in f.atoms(gamma): if not g.has(s): continue arg = g.args[0] if arg.is_Add: arg = arg.as_independent(s)[1] coeff, _ = arg.as_coeff_mul(s) s_multipliers += [coeff] for g in f.atoms(sin, cos, tan, cot): if not g.has(s): continue arg = g.args[0] if arg.is_Add: arg = arg.as_independent(s)[1] coeff, _ = arg.as_coeff_mul(s) s_multipliers += [coeff / pi] s_multipliers = [abs(x) for x in s_multipliers if x.is_real] common_coefficient = S(1) for x in s_multipliers: if not x.is_Rational: common_coefficient = x break s_multipliers = [x / common_coefficient for x in s_multipliers] if any(not x.is_Rational for x in s_multipliers): raise NotImplementedError s_multiplier = common_coefficient / reduce( ilcm, [S(x.q) for x in s_multipliers], S(1)) if s_multiplier == common_coefficient: if len(s_multipliers) == 0: s_multiplier = common_coefficient else: s_multiplier = common_coefficient \ *reduce(igcd, [S(x.p) for x in s_multipliers]) exponent = S(1) fac = S(1) f = f.subs(s, s / s_multiplier) fac /= s_multiplier exponent = 1 / s_multiplier if a_ is not None: a_ *= s_multiplier if b_ is not None: b_ *= s_multiplier # 2) numer, denom = f.as_numer_denom() numer = Mul.make_args(numer) denom = Mul.make_args(denom) args = zip(numer, repeat(True)) + zip(denom, repeat(False)) facs = [] dfacs = [] # *_gammas will contain pairs (a, c) representing Gamma(a*s + c) numer_gammas = [] denom_gammas = [] # exponentials will contain bases for exponentials of s exponentials = [] def exception(fact): return IntegralTransformError("Inverse Mellin", f, "Unrecognised form '%s'." % fact) while args: fact, is_numer = args.pop() if is_numer: ugammas, lgammas = numer_gammas, denom_gammas ufacs, lfacs = facs, dfacs else: ugammas, lgammas = denom_gammas, numer_gammas ufacs, lfacs = dfacs, facs def linear_arg(arg): """ Test if arg is of form a*s+b, raise exception if not. """ if not arg.is_polynomial(s): raise exception(fact) p = Poly(arg, s) if p.degree() != 1: raise exception(fact) return p.all_coeffs() # constants if not fact.has(s): ufacs += [fact] # exponentials elif fact.is_Pow or isinstance(fact, exp_): if fact.is_Pow: base = fact.base exp = fact.exp else: base = E exp = fact.args[0] if exp.is_Integer: cond = is_numer if exp < 0: cond = not cond args += [(base, cond)] * abs(exp) continue elif not base.has(s): a, b = linear_arg(exp) if not is_numer: base = 1 / base exponentials += [base**a] facs += [base**b] else: raise exception(fact) # linear factors elif fact.is_polynomial(s): p = Poly(fact, s) if p.degree() != 1: # We completely factor the poly. For this we need the roots. # Now roots() only works in some cases (low degree), and RootOf # only works without parameters. So try both... coeff = p.LT()[1] rs = roots(p, s) if len(rs) != p.degree(): rs = RootOf.all_roots(p) ufacs += [coeff] args += [(s - c, is_numer) for c in rs] continue a, c = p.all_coeffs() ufacs += [a] c /= -a # Now need to convert s - c if left(c, is_numer): ugammas += [(S(1), -c + 1)] lgammas += [(S(1), -c)] else: ufacs += [-1] ugammas += [(S(-1), c + 1)] lgammas += [(S(-1), c)] elif isinstance(fact, gamma): a, b = linear_arg(fact.args[0]) if is_numer: if (a > 0 and (left(-b/a, is_numer) is False)) or \ (a < 0 and (left(-b/a, is_numer) is True)): raise NotImplementedError( 'Gammas partially over the strip.') ugammas += [(a, b)] elif isinstance(fact, sin): # We try to re-write all trigs as gammas. This is not in # general the best strategy, since sometimes this is impossible, # but rewriting as exponentials would work. However trig functions # in inverse mellin transforms usually all come from simplifying # gamma terms, so this should work. a = fact.args[0] if is_numer: # No problem with the poles. gamma1, gamma2, fac_ = gamma(a / pi), gamma(1 - a / pi), pi else: gamma1, gamma2, fac_ = _rewrite_sin(linear_arg(a), s, a_, b_) args += [(gamma1, not is_numer), (gamma2, not is_numer)] ufacs += [fac_] elif isinstance(fact, tan): a = fact.args[0] args += [(sin(a, evaluate=False), is_numer), (sin(pi / 2 - a, evaluate=False), not is_numer)] elif isinstance(fact, cos): a = fact.args[0] args += [(sin(pi / 2 - a, evaluate=False), is_numer)] elif isinstance(fact, cot): a = fact.args[0] args += [(sin(pi / 2 - a, evaluate=False), is_numer), (sin(a, evaluate=False), not is_numer)] else: raise exception(fact) fac *= Mul(*facs) / Mul(*dfacs) # 3) an, ap, bm, bq = [], [], [], [] for gammas, plus, minus, is_numer in [(numer_gammas, an, bm, True), (denom_gammas, bq, ap, False)]: while gammas: a, c = gammas.pop() if a != -1 and a != +1: # We use the gamma function multiplication theorem. p = abs(S(a)) newa = a / p newc = c / p assert a.is_Integer for k in range(p): gammas += [(newa, newc + k / p)] if is_numer: fac *= (2 * pi)**((1 - p) / 2) * p**(c - S(1) / 2) exponentials += [p**a] else: fac /= (2 * pi)**((1 - p) / 2) * p**(c - S(1) / 2) exponentials += [p**(-a)] continue if a == +1: plus.append(1 - c) else: minus.append(c) # 4) # TODO # 5) arg = Mul(*exponentials) # for testability, sort the arguments an.sort() ap.sort() bm.sort() bq.sort() return (an, ap), (bm, bq), arg, exponent, fac
def _expansion_search(expr, rep_list, lib=None): """ Search for and substitute terms that match a series expansion of fundamental math functions. e: expression rep_list: list containing dummy variables """ if debug: print("_expansion_search: ", expr) try: if isinstance(expr, Mul): exprs = [expr] elif isinstance(expr, Add): exprs = expr.args else: return expr if lib is not None: fncs, series = lib else: fncs, series = _fncs, _series newargs = [] for expr in exprs: # Try to simplify the expression if isinstance(expr, Mul): # Split the expression into a LIST of commutative and a LIST of non-commutative factor (i.e. operators). c, nc = expr.args_cnc() if nc and c: # Construct an expression of commutative elements ONLY. expr = Mul(*c).expand() #out = find_expansion(expr, *rep_list) eq = Poly(expr, *rep_list) bdict = eq.as_dict() if any([ n > 1 for n in [sum([i != 0 for i in k]) for k in bdict.keys()] ]): raise ValueError( "Expressions cross-products of symbols are not supported (yet?).." ) # Construct the list of 'vectors' vecl = [] fncl = [] for x in rep_list: for n in range(3): #range(eq.degree()-1): X = pow(x, n) vecl.extend([((X * p.subs(_s, x)).expand() + O(pow(x, eq.degree() + 1))).removeO() for p in series]) fncl.extend([X * f(x) for f in fncs]) vecl.extend( [pow(x, n) for n in range(max(eq.degree(), 3))]) fncl.extend( [pow(x, n) for n in range(max(eq.degree(), 3))]) # Create vector coefficients q = symbols(f'q:{len(vecl)}') # Take inner product of 'vector' list and vector coefficients A = Add(*[x * y for x, y in zip(q, vecl)]).as_poly(*rep_list) terms = [] for k, eq in A.as_dict().items(): terms.append(eq - bdict.get(k, 0)) H = linsolve(terms, *q) h = H.subs({k: 0 for k in q}) out = Add(*[c * fnc for fnc, c in zip(fncl, list(h)[0])]) newargs.append(out * Mul(*nc)) else: newargs.append(expr) else: newargs.append(expr) return Add(*newargs) except Exception as e: print("Failed to identify series expansions: " + str(e)) return e
if len(uniq_b) == max_size: break if flag_all: break if not flag_all: ans.append(p) if __name__ == '__main__': print('Enter the polynomial: ', end='') from sympy import Poly, Symbol polynom = Poly(input()) d = polynom.degree() + 1 a = Symbol('a') symbols = [] for symbol in polynom.free_symbols: symbols.append(str(symbol)) symbols.sort() replace_symbols = {} j = 0 for symbol in symbols: replace_symbols[symbol] = a**(d**j) j += 1 for symbol in replace_symbols:
def sturm(): divid = [fx, diff(fx)] # Array where equations will be stored while True: test = Poly(divid[-1], x) if len(test.coeffs()) > 1: q, r = div(divid[-2], divid[-1], x) # Taking quotient and remainder of dividing divid.append(-1 * r) else: break print('\n Let\'s calculate dividing of a polynomials: ') for i in divid: print('f' + str(divid.index(i)) + '(x): ' + str(i)) # Create information table table = [[' '], ['-inf'], ['+inf']] for i in divid: table[0].append('f' + str(divid.index(i)) + '(x)') # Better information association test = Poly(i, x) # -inf if (test.degree() % 2 == 0 and test.coeffs()[0] > 0) or \ (test.degree() % 2 != 0 and test.coeffs()[0] < 0): table[1].append('+') else: table[1].append('-') # +inf if test.coeffs()[0] > 0: table[2].append('+') else: table[2].append('-') qwe = changes(table) mininf = qwe[0] plusinf = qwe[1] # Add found data to a table for better user experience table[0].append('Sign changes') table[1].append(mininf) table[2].append(plusinf) print('---------') print( '\n\n Then we need to calculate number of sign changes for (-inf) and (+inf) cases. ' ) print(' Let\'s create a table to visualize our results: ') for i in table: print() for j in i: if table.index(i) == 0: print(' ' + j, end='') else: print(j, end=' ' + ' ' * i.index(j)) print( '\n\n As we see, our equation has {0} - {1} = {2} real roots.'.format( mininf, plusinf, mininf - plusinf)) print('---------') print('\n\n Now we need to define possible intervals for roots. ') print( ' Let\'s create a table with calculated functions in possible root interval. ' ) # Creating a table results = [[' ']] for i in divid: results[0].append('f' + str(divid.index(i)) + '(x) ') # Better information association for i in range(floor(Rlo), ceil(Rup + 1)): results.append(['x = ' + str(i)]) # Calculate value for each function and possible variable count = 1 for j in range(floor(Rlo), ceil(Rup + 1)): for i in divid: if i.evalf(subs={x: j}) > 0: results[count].append('+') else: results[count].append('-') count += 1 # Check number of sign changes ert = changes(results) results[0].append('Sign changes') for i in range(1, len(results)): results[i].append(ert[i - 1]) # Printing table for i in results: print() for j in i: if results.index(i) == 0: print(' ' + j, end='') else: print(j, end=' ' + ' ' * i.index(j)) send = [] for i in range(1, len(results) - 1): if results[i][-1] != results[i + 1][-1]: temp = [i for i in range(floor(Rlo), ceil(Rup + 1))] send.append((temp[i - 1], temp[i])) # Check if we need extended computations analys = False for i in range(1, len(send)): if send[i][0] == send[i - 1][1]: analys = True break if len(send) != mininf - plusinf or analys is True: print( '\n\nWARNING!!! PROGRAM CALCULATE VALUES FROM {0} TO {1} with step 0.1. IT\'S NOT SHOWN IN A TABLE.' .format(floor(Rlo), ceil(Rup + 1)) + '\nIT HAPPENS BECAUSE TWO OR MORE ROOTS LIE IN INTERVAL WITH SIZE LESS THAN 1' + '\nOR THEIR INTERVALS STARTS AND BEGINS AT ONE POINT RESPECTIVELY.' + '\nWITHOUT THIS CHECKING CALCULATIONS WILL BE WRONG.') send = deepanalysis(divid) print('\n As we can see, roots of equation lie in intervals: ') for i in send: print(i) return send # Return intervals of roots