def __lin_reduce__(par_integral): used_chung_wu = False _k = Symbol("k_l") _num, _denom = par_integral.as_numer_denom() constant = 1 factors = _denom.as_ordered_factors() if len(factors) > 1: _denom = factors[1] constant = factors[0] assert factors[0].is_constant( ), "assumed first factor is a constant prefactor but might need to do something smarter" #assert has single term with power tup = list( _denom.as_powers_dict().items() )[-1] #the single pair of; term and power but there may be an integer constant prefactor _p = expand( tup[0]) #expand inside so that we have just a polynommial in k _power = tup[1] #_p = _p.subs(_k, -1*_k) _p = collect(_p, Symbol("k_l")) #organise the poly into powers of k p = Poly(_p, _k) coeff = p.all_coeffs() assert len( coeff ) == 3, "there is a problem. the polynomial in the propagator is not of order 2 in loop momentum" _denom.as_powers_dict().items() el = determine_elimination_variable(p) aps = list(__alpha_params__(_p)) if el != None: print("Apply checng-wu, setting", el, "to 1") _p = _p.subs(el, 1) #cheng-wu says set one of the variables = 1 coeff = Poly(_p, _k).all_coeffs() #refresh coefficients used_chung_wu = True elif len(aps) == 2: #TODO - there is a smarter choice to make here - we should coose the param that simplifies the expression the most _p = simplify( _p.subs(aps[0], 1 - aps[1]) ) #special case simplification assuming we dont want to use them for linearisation coeff = Poly(_p, _k).all_coeffs() #refresh coefficients _p = simplify(_p / coeff[0]) p = Poly(_p, _k) coeff = p.all_coeffs() if len(coeff) == 3 and coeff[1] == 0: pass else: sub = Symbol("k_l") - (coeff[1]) / 2 _p = expand(_p.subs(_k, sub)) p = Poly(_p) kpropagator.__assert_k2_coeff__(_p) return _num / (constant * (_p**_power)), used_chung_wu, p
def power_dict(n, irr, p): result = {(1, ): 0} test_poly = Poly(1, alpha) for i in range(1, n - 1): test_poly = (Poly(Poly(alpha, alpha) * test_poly, alpha) % irr).set_domain(GF(p)) if tuple(test_poly.all_coeffs()) in result: return result result[tuple(test_poly.all_coeffs())] = i return result
def gauss_lobatto_points(p): """ Returns the list of Gauss-Lobatto points of the order 'p'. """ x = Symbol("x") print "creating" e = legendre(p, x).diff(x) e = Poly(e, x) print "polydone" if e == 0: return [] print "roots" if e == 1: r = [] else: with workdps(40): r, err = polyroots(e.all_coeffs(), error=True) #if err > 1e-40: # raise Exception("Internal Error: Root is not precise") print "done" p = [] p.append("-1.0") for x in r: if abs(x) < 1e-40: x = 0 p.append(str(x)) p.append("1.0") return p
def sym_probs(num_dice=1, die_faces=6, success_count=None, obstacle_limit=10, log=False): # This is so much easier when not exploding, just discreet normal if success_count == None: success_count = die_faces // 2 # Probability of a die roll being a success success_chance = Rational(str(success_count) + "/" + str(die_faces)) # Probability of a die roll failing failure_chance = 1 - success_chance if log: print( f"Die faces: {die_faces}, success count: {success_count}, success chance: {success_chance}" ) pol = Poly(failure_chance + success_chance * x, x)**num_dice coeffs = np.array(pol.all_coeffs()) if log: print("Generating function: ", pol) print("Cummulative prob (low means raise obstacle limit): ", float(coeffs.sum())) cum_coeffs = coeffs.cumsum()[::-1] + (1 - coeffs.sum()) return cum_coeffs
def sym_explode_probs(num_dice=1, die_faces=6, success_count=None, explode_count=1, obstacle_limit=10, log=False): # This is so much easier when not exploding, just discreet normal if success_count == None: success_count = die_faces // 2 # Probability of a die roll being a success success_chance = Rational(str(success_count) + "/" + str(die_faces)) # Probability of a *success* exploding explode_chance = Rational(str(explode_count) + "/" + str(success_count)) # Probability of a die roll failing failure_chance = 1 - success_chance # Probability of a *success* not exploding dud_chance = 1 - explode_chance if log: print( f"Die faces: {die_faces}, success count: {success_count}, success chance: {success_chance}, explode count: {explode_count}, explode_chance: {explode_chance}" ) # There is probably a way to do this that doesn't involve calculating the # first two terms and finding the ratio this is how I did it by hand though # and I don't remember enough combinatorics to know a better way p_0 = failure_chance p_1 = success_chance * (dud_chance + explode_chance * failure_chance) p_2 = success_chance * explode_chance * success_chance * ( dud_chance + explode_chance * failure_chance) if log: print("p_0 = ", p_0) print("p_1 = ", p_1) print("p_2 = ", p_2) term_relation = p_2 / p_1 # We will need p_0 to be the failure chance, that doesn't always work out, so we force it # I don't really know why this works, but it does in the BW case initial = p_1 / term_relation correction = p_0 - initial if log: print("term relation = ", term_relation) print("initial = ", initial) print("correction = ", correction) p_n = initial * (success_chance * explode_chance)**(n) g = Sum(p_n * x**n, (n, 0, obstacle_limit)).doit() pol = Poly(g + correction, x)**num_dice coeffs = np.array(pol.all_coeffs()) if log: print("Generating function: ", pol) print("Cummulative prob (low means raise obstacle limit): ", float(coeffs.sum())) print("Coefficients: ", coeffs[::-1]) # We do this here so our cummulative sum includes higher order terms cum_coeffs = coeffs.cumsum()[::-1] + (1 - coeffs.sum()) return cum_coeffs
def _eval_expand_func(self, **hints): from sympy import exp, I, floor, Add, Poly, Dummy, exp_polar, unpolarify z, s, a = self.args if z == 1: return zeta(s, a) if s.is_Integer and s <= 0: t = Dummy('t') p = Poly((t + a)**(-s), t) start = 1/(1 - t) res = S(0) for c in reversed(p.all_coeffs()): res += c*start start = t*start.diff(t) return res.subs(t, z) if a.is_Rational: # See section 18 of # Kelly B. Roach. Hypergeometric Function Representations. # In: Proceedings of the 1997 International Symposium on Symbolic and # Algebraic Computation, pages 205-211, New York, 1997. ACM. # TODO should something be polarified here? add = S(0) mul = S(1) # First reduce a to the interaval (0, 1] if a > 1: n = floor(a) if n == a: n -= 1 a -= n mul = z**(-n) add = Add(*[-z**(k - n)/(a + k)**s for k in xrange(n)]) elif a <= 0: n = floor(-a) + 1 a += n mul = z**n add = Add(*[z**(n - 1 - k)/(a - k - 1)**s for k in xrange(n)]) m, n = S([a.p, a.q]) zet = exp_polar(2*pi*I/n) root = z**(1/n) return add + mul*n**(s - 1)*Add( *[polylog(s, zet**k*root)._eval_expand_func(**hints) / (unpolarify(zet)**k*root)**m for k in xrange(n)]) # TODO use minpoly instead of ad-hoc methods when issue 2789 is fixed if z.func is exp and (z.args[0]/(pi*I)).is_Rational or z in [-1, I, -I]: # TODO reference? if z == -1: p, q = S([1, 2]) elif z == I: p, q = S([1, 4]) elif z == -I: p, q = S([-1, 4]) else: arg = z.args[0]/(2*pi*I) p, q = S([arg.p, arg.q]) return Add(*[exp(2*pi*I*k*p/q)/q**s*zeta(s, (k + a)/q) for k in xrange(q)]) return lerchphi(z, s, a)
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 zero_upper_bound_of_positive_poly(poly): poly = Poly(poly.expand()) cs = poly.all_coeffs() cs0 = abs(cs[0]) assert cs[0] == LC(poly) height = max(map(abs, cs)) upper = ceiling(two * height / cs0) upper = int(upper) assert upper >= 2 return upper
def extract_coefficients(func, t): tx = (diff(func[0], t)) ty = (diff(func[1], t)) eq = together(tx * tx + ty * ty) n, _ = fraction(eq) poly = Poly(n, t) coeffs = poly.all_coeffs() coeffs.reverse() return poly, coeffs
def read_input(): global epsilon, kmax, tries epsilon = float(en_eps.get()) kmax = int(sb_kmax.get()) tries = int(sb_tries.get()) expr = str(en_func.get()) transformations = (standard_transformations + (implicit_multiplication_application,)) expr = Poly(parse_expr(expr, transformations=transformations), x) coefficients = expr.all_coeffs() return expr, coefficients
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 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 _valid_expr(expr): """ return coefficients of expr if it is a univariate polynomial with integer coefficients else raise a ValueError. """ from sympy import Poly from sympy.polys.domains import ZZ if not expr.is_polynomial(): raise ValueError("The expression should be a polynomial") polynomial = Poly(expr) if not polynomial.is_univariate: raise ValueError("The expression should be univariate") if not polynomial.domain == ZZ: raise ValueError("The expression should should have integer coefficients") return polynomial.all_coeffs()
def gauss_lobatto_points(p): """ Returns the list of Gauss-Lobatto points of the order 'p'. """ x = Symbol("x") e = (1-x**2)*legendre(p, x).diff(x) e = Poly(e, x) if e == 0: return [] with workdps(40): r, err = polyroots(e.all_coeffs(), error=True) if err > 1e-40: raise Exception("Internal Error: Root is not precise") p = [] for x in r: if abs(x) < 1e-40: x = 0 p.append(str(x)) return p
def _valid_expr(expr): """This function is used by `polynomial_congruence`. If `expr` is a univariate polynomial will integer coefficients the it returns its coefficients, otherwise it raises Valuerror """ from sympy import Poly from sympy.polys.domains import ZZ if not expr.is_polynomial(): raise ValueError("The expression should be a polynomial") polynomial = Poly(expr) if not polynomial.is_univariate: raise ValueError("The expression should be univariate") if not polynomial.domain == ZZ: raise ValueError( "The expression should should have integer coefficients") return polynomial.all_coeffs()
def minimal_poly(i, n, q, irr_poly): ti = int(i) checked = np.zeros(n, dtype=bool) checked[ti] = True poly = Poly(x - alpha**ti, x) for k in range(n): ti = (ti * q) % n if checked[ti]: polys = [(Poly(c, alpha) % irr_poly).trunc(q) for c in poly.all_coeffs()] for p in polys: if p.degree() > 0: raise Exception("Couldn't find minimal polynomial") coeffs = [p.nth(0) for p in polys] return Poly(coeffs, x) checked[ti] = True poly = poly * Poly(x - alpha**ti, x) return None
def min_poly(i, prim_poly): """ Calculate minimal polynomial for a given i and primitive polynomial. """ checked = np.zeros(n, dtype=bool) checked[i] = True poly = Poly(x - alpha**i, x) for j in range(n): i = (i * q) % n if checked[i]: polys = [(Poly(c, alpha) % prim_poly).trunc(q) for c in poly.all_coeffs()] for p in polys: if p.degree() > 0: raise Exception('Couldnt find minimal polynomial') coeffs = [p.nth(0) for p in polys] return Poly(coeffs, x) poly = poly * Poly(x - alpha**i, x) return None
print 'W0: ', W0 print 'B: ', B, '\n' # Defining a list [0,0,...1] of size N+1 required to generate the coefficients of Nth order Cheyshev Polynomial c = zeros(N+1) c[-1] = 1.0 # TnS = polynomial.chebyshev.Chebyshev(c) TnS_coeff = polynomial.chebyshev.cheb2poly(TnS.coef) # print 'Coefficients: ', TnS_coeff CnW = 0.0 for i in xrange(int(N+1)): CnW = CnW + TnS_coeff[i]*(-1j*s)**i # HcS_sq = 1.0/(1.0 + (eps**2)*(CnW**2)) denom_all = Poly(1.0 + (eps**2)*(CnW**2), s) # print denom_all denom_all = denom_all.all_coeffs() leading_coeff = denom_all[0] denom_all = [i/leading_coeff for i in denom_all] norm_fac = (leading_coeff/abs(leading_coeff))*pow(abs(leading_coeff),0.5) poles_all = roots(denom_all) poles_LHP = zeros(N,dtype=complex64) j = 0 denominator_LHP = 1.0 + 0j for i in xrange(int(2*N)): if ((poles_all[i]).real<0): poles_LHP[j] = poles_all[i] j = j+1 denominator_LHP = expand(denominator_LHP*(s-poles_all[i])) # print poles denom_poly = Poly(denominator_LHP,s) denom_poly = denom_poly.all_coeffs()
def synthetic(divisor: int, dividend: str, quiet=False): eqn = toValidEqn(dividend) eqn = sympify("Eq(" + eqn + ", 0)") symbol = list(eqn.free_symbols)[0] eqn = Poly(eqn, symbol) coeffs = eqn.all_coeffs() current = coeffs[0] new_coeffs = [] middle_numbers = [''] for coefficient in coeffs[1:]: new_coeffs.append(current) current = Decimal(str(divisor)) * Decimal(str(current)) middle_numbers.append(current) current += Decimal(str(coefficient)) coefficient_printable = '' middle_numbers_printable = '' new_coeffs_printable = '' for coef, num, new_coef in zip(coeffs, middle_numbers, new_coeffs + [current]): coef = str(coef) num = str(num) new_coef = str(new_coef) # pad numbers with space max_length_number = max(len(coef), len(num), len(new_coef)) coef = coef.rjust(max_length_number) num = num.rjust(max_length_number) new_coef = new_coef.rjust(max_length_number) coefficient_printable = coefficient_printable + ' ' + coef middle_numbers_printable = middle_numbers_printable + ' ' + num new_coeffs_printable = new_coeffs_printable + ' ' + new_coef # remove extra whitespace coefficient_printable = '|' + coefficient_printable[4:] middle_numbers_printable = '|' + middle_numbers_printable[4:] new_coeffs_printable = ' ' + new_coeffs_printable[4:] if not quiet: print(theme['styles']['normal'] + str(divisor) + ' ' + coefficient_printable) print((len(str(divisor)) + 2) * ' ' + '\u001b[4m' + middle_numbers_printable + '\u001b[0m') print(theme['styles']['normal'] + (len(str(divisor)) + 2) * ' ' + new_coeffs_printable) print() degree = len(new_coeffs) - 1 equation = '' for coef in new_coeffs: if coef != 0: # skip coefs that are 0 if degree != len(new_coeffs) and coef > 0: # not first number and positive equation += '+' equation += str(coef) if coef != 1 else '' if degree != 0: equation += str(symbol) if degree > 1: equation += f'^{degree}' degree -= 1 return equation.lstrip('+')
def poly2list(p): if p == 0: return [0] return Poly.all_coeffs(p)
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
for k in range(len(Ds[l])): solns[m][sol_ind] = solns[m][sol_ind].subs( Ds[l][k], solns[l][1 + k]) Lambdap_exp = log(2) / tau.subs(sigb, S) for i in range(len(Cs)): Lambdap_exp += log(2) / tau.subs(sigb, S) * solns[i][0].expand() * a**(2 * i + 2) lam0, lam1, n = symbols('lam0 lam1 n') lam_prl = lambda t: (lam0 + lam1 * t**n) / (1 + t**n) tau_prl = lambda x: integrate(1 / V / lam_prl((x - S) / V + S), (V, 1, 2)) Lambdap_exp_prl = Lambdap_exp.replace(Function('tau')(S), tau_prl(S)) p = Poly(Lambdap_exp_prl, a) Clst = p.all_coeffs() C6_S = Clst[-7].subs([(lam0, 1), (lam1, 0), (n, 2)]).doit().evalf() C4_S = Clst[-5].subs([(lam0, 1), (lam1, 0), (n, 2)]).doit().evalf() C2_S = Clst[-3].subs([(lam0, 1), (lam1, 0), (n, 2)]).doit().evalf() C0_S = Clst[-1].subs([(lam0, 1), (lam1, 0), (n, 2)]).doit().evalf() for s in np.arange(0.01, 1.01, 0.01): C6 = C6_S.subs([(S, s)]).doit().evalf() C4 = C4_S.subs([(S, s)]).doit().evalf() C2 = C2_S.subs([(S, s)]).doit().evalf() C0 = C0_S.subs([(S, s)]).doit().evalf() np.savetxt('C_damage_S={:.2f}.out'.format(s), [C0, C2, C4, C6]) C6_S = Clst[-7].subs([(lam0, 0.2), (lam1, 1.2), (n, 2)]).doit().evalf() C4_S = Clst[-5].subs([(lam0, 0.2), (lam1, 1.2), (n, 2)]).doit().evalf()
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
# plot(abs(freq_res_LPF), (s,0,100)) print 'HcS: ', HcS HcS_Bandpass = HcS.subs(s, transform) # freq_res_BPF = HcS_Bandpass.subs(s,1j*2.0*pi*s) # plot(abs(freq_res_BPF), (s,0,50)) print 'HcS_Bandpass: '******'Hz: ', Hz # print 'Numerator: ', fraction(Hz)[0] # print 'Denominator: ', fraction(Hz)[1] ax = Poly(fraction(Hz)[0], x) # Separating out the numerator ax = ax.all_coeffs() # Array of size [(order of ax) + 1] with ax[0] being coeff of x^n ax = list(reversed(ax)) # Reversing it so that ax[0] is coeff of order x^0 ay = Poly(fraction(Hz)[1], x) # Separating out the denominator ay = ay.all_coeffs() ay = list(reversed(ay)) norm_fac = ay[0] # print 'ay[0]: ', ay[0] ax = [i/norm_fac for i in ax] ay = [i/norm_fac for i in ay] print 'ax: ', ax print 'ay: ', ay # print 'Length of ax: ', len(ax) # print 'Length of ay: ', len(ay) # # ax[i] and ay[i] are the coefficients of x[n-i] and y[n-i] respectively in the difference equation. # The difference equation is implemented by the function 'filter' on any specified x[n]