def myroots(expr_1, expr_2, input_type, output_type): from sympy import roots, sympify, latex expr_1 = sympify(expr_1) expr_2 = sympify(expr_2) input_type = str(input_type) output_type = str(output_type) if input_type == 'LaTeX': print('roots({}, {}) = '.format(latex(expr_1), latex(expr_2))) elif input_type == 'SymPy': print('roots({}, {}) = '.format(expr_1, expr_2)) else: print("Wrong input type") if output_type == 'LaTeX': print(latex(roots((expr_1), expr_2))) elif output_type == 'SymPy': print(roots((expr_1), expr_2)) else: print("Wrong output type")
def get_harmonic_standard_deviations_around_minima(self, temperature=300.0 * unit.kelvin): kB = unit.BOLTZMANN_CONSTANT_kB * unit.AVOGADRO_CONSTANT_NA Eo = self.parameters['Eo'] a = self.parameters['a'] b = self.parameters['b'] k = self.parameters['k'] x, y, z = sy.symbols('x y z') xu = x * unit.nanometers yu = y * unit.nanometers zu = z * unit.nanometers potential_x = Eo * ((xu / a)**4 - 2.0 * (xu / a)**2) - (b / a) * xu potential_y = 0.5 * k * (yu**2) potential_z = 0.5 * k * (zu**2) g = sy.diff(potential_y, y) gg = sy.diff(potential_y, y, y) roots_diff = sy.roots(g, y) root_y = None sigma_y = None for root in roots_diff.keys(): effective_k = gg.subs(y, root) if effective_k > 0: root_y = root * unit.nanometers sigma_y = np.sqrt(kB * temperature / (effective_k * unit.kilocalories_per_mole / unit.nanometers**2)) g = sy.diff(potential_x, x) gg = sy.diff(potential_x, x, x) roots_diff = sy.roots(g, x) roots = [] sigmas = [] for root in roots_diff.keys(): effective_k = gg.subs(x, root) if effective_k > 0: root_3d = np.zeros([3], dtype=float) * unit.nanometers root_3d[0] = root * unit.nanometers root_3d[1] = root_y root_3d[2] = root_y roots.append(root_3d) sigma_3d = np.zeros([3], dtype=float) * unit.nanometers sigma_3d[0] = np.sqrt( kB * temperature / (effective_k * unit.kilocalories_per_mole / unit.nanometers**2)) sigma_3d[1] = sigma_y sigma_3d[2] = sigma_y sigmas.append(sigma_3d) del (x, y, z) return roots, sigmas
def f2zpk(function: Basic, var: Symbol) -> Tuple[Dict[Basic, int], Dict[Basic, int], Basic]: numer, denom = f2nd(function) numer_lc, denom_lc = map(lambda expr: leading_coeff(expr, var), (numer, denom)) # It's not really necesary to devide by the leading # coefficient, but what do I know return roots(numer/numer_lc, var), \ roots(denom/denom_lc, var), numer_lc/denom_lc
def get_small_oscillations_time_periods_around_minima(self): Eo = self.parameters['Eo'] a = self.parameters['a'] b = self.parameters['b'] k = self.parameters['k'] mass = self.parameters['mass'] x, y, z = sy.symbols('x y z') xu = x * unit.nanometers yu = y * unit.nanometers zu = z * unit.nanometers potential_x = Eo * ((xu / a)**4 - 2.0 * (xu / a)**2) - (b / a) * xu potential_y = 0.5 * k * (yu**2) potential_z = 0.5 * k * (zu**2) g = sy.diff(potential_y, y) gg = sy.diff(potential_y, y, y) roots_diff = sy.roots(g, y) root_y = None T_y = None for root in roots_diff.keys(): effective_k = gg.subs(y, root) if effective_k > 0: root_y = root * unit.nanometers T_y = 2 * np.pi * np.sqrt( mass / (effective_k * unit.kilocalories_per_mole / unit.nanometers**2)) g = sy.diff(potential_x, x) gg = sy.diff(potential_x, x, x) roots_diff = sy.roots(g, x) roots = [] Ts = [] for root in roots_diff.keys(): effective_k = gg.subs(x, root) if effective_k > 0: root_3d = np.zeros([3], dtype=float) * unit.nanometers root_3d[0] = root * unit.nanometers root_3d[1] = root_y root_3d[2] = root_y roots.append(root_3d) T_3d = np.zeros([3], dtype=float) * unit.picoseconds T_3d[0] = 2 * np.pi * np.sqrt( mass / (effective_k * unit.kilocalories_per_mole / unit.nanometers**2)) T_3d[1] = T_y T_3d[2] = T_y Ts.append(T_3d) del (x, y, z) return roots, Ts
def analyze_controller(self, K): if self.control_tfs is None: self.get_controller_transfer_functions() for X_r in self.X_r: # set all others in X_r to zero tfs = [ sp.simplify( tf.subs([(X_r_, 0) for X_r_ in self.X_r if X_r_ is not X_r]) / X_r) for tf in self.control_tfs ] for X, tf in zip(self.X, tfs): numerator, denominator = tf.as_numer_denom() routh_table = np.array(routh(sp.Poly(denominator, self.s))) routh_conditions = routh_table[:, 0] tf = self.phys.apply_substitutions(tf) numerator = self.phys.apply_substitutions(numerator) denominator = self.phys.apply_substitutions(denominator) zeros = sp.roots( numerator.subs(zip(self.k_pd_mat.flatten(), K.flatten())), self.s) poles = sp.roots( denominator.subs(zip(self.k_pd_mat.flatten(), K.flatten())), self.s) gain = get_gain( self.s, tf.subs(zip(self.k_pd_mat.flatten(), K.flatten())), zeros, poles) zeros_description = ', '.join([ str(zero.evalf(6)) if multiplicity == 1 else f'{zero.evalf(6)} (x{multiplicity})' for zero, multiplicity in zeros.items() ]) poles_description = ', '.join([ str(pole.evalf(6)) if multiplicity == 1 else f'{pole.evalf(6)} (x{multiplicity})' for pole, multiplicity in poles.items() ]) routh_conditions_description = '\n'.join([ to_string(condition.evalf(3)) for condition in routh_conditions ]) print( f'{X}/{X_r}: Routh Conditions:\n{routh_conditions_description}\nGain: {gain.evalf(6)}\n' f'Poles: {poles_description}\nZeros: {zeros_description}\n\n' )
def get_world_segments(root_a, root_b, root_c, initial_t, final_t, intersection_radius): """ The world consists of three axis lines, six circles marking the intersections, and a single parametric curve. @return: a collection of (p0, p1, style) triples """ seg_length_min = 0.1 segments = [] # add the axis line segments d = 5 f_x = pcurve.LineSegment(np.array([-d, 0, 0]), np.array([d, 0, 0])) f_y = pcurve.LineSegment(np.array([0, -d, 0]), np.array([0, d, 0])) f_z = pcurve.LineSegment(np.array([0, 0, -d]), np.array([0, 0, d])) x_axis_segs = pcurve.get_piecewise_curve(f_x, 0, 1, 10, seg_length_min) y_axis_segs = pcurve.get_piecewise_curve(f_y, 0, 1, 10, seg_length_min) z_axis_segs = pcurve.get_piecewise_curve(f_z, 0, 1, 10, seg_length_min) segments.extend((p0, p1, STYLE_X) for p0, p1 in x_axis_segs) segments.extend((p0, p1, STYLE_Y) for p0, p1 in y_axis_segs) segments.extend((p0, p1, STYLE_Z) for p0, p1 in z_axis_segs) # add the parametric curve roots = (root_a, root_b, root_c) polys = interlace.roots_to_differential_polys(roots) f_poly = interlace.Multiplex((sympyutils.WrappedUniPoly(p) for p in polys)) poly_segs = pcurve.get_piecewise_curve(f_poly, initial_t, final_t, 10, seg_length_min) segments.extend((p0, p1, STYLE_CURVE) for p0, p1 in poly_segs) # add the intersection circles x_roots_symbolic = sympy.roots(polys[0]) y_roots_symbolic = sympy.roots(polys[1]) z_roots_symbolic = sympy.roots(polys[2]) x_roots = [float(r) for r in x_roots_symbolic] y_roots = [float(r) for r in y_roots_symbolic] z_roots = [float(r) for r in z_roots_symbolic] for r in x_roots: f = pcurve.OrthoCircle(f_poly(r), intersection_radius, 0) segs = pcurve.get_piecewise_curve(f, 0, 1, 10, seg_length_min) segments.extend((p0, p1, STYLE_X) for p0, p1 in segs) for r in y_roots: f = pcurve.OrthoCircle(f_poly(r), intersection_radius, 1) segs = pcurve.get_piecewise_curve(f, 0, 1, 10, seg_length_min) segments.extend((p0, p1, STYLE_Y) for p0, p1 in segs) for r in z_roots: f = pcurve.OrthoCircle(f_poly(r), intersection_radius, 2) segs = pcurve.get_piecewise_curve(f, 0, 1, 10, seg_length_min) segments.extend((p0, p1, STYLE_Z) for p0, p1 in segs) # return the segments return segments
def ZPK(self): """Convert to pole-zero-gain (PZK) form. See also canonical, general, mixedfrac, and partfrac""" N, D, delay = self._as_ratfun_delay() K = sym.cancel(N.LC() / D.LC()) if delay != 0: K *= sym.exp(self.var * delay) zeros = sym.roots(N) poles = sym.roots(D) return self.__class__(_zp2tf(zeros, poles, K, self.var))
def ZPK(self): """Convert to pole-zero-gain (PZK) form. See also canonical, general, mixedfrac, and partfrac""" N, D, delay = self.as_ratfun_delay() K = sym.cancel(N.LC() / D.LC()) if delay != 0: K *= sym.exp(self.var * delay) zeros = sym.roots(N) poles = sym.roots(D) return _zp2tf(zeros, poles, K, self.var)
def get_coordinates_maximum(self): Eo = self.parameters['Eo'] a = self.parameters['a'] b = self.parameters['b'] k = self.parameters['k'] x, y, z = sy.symbols('x y z') xu = x * unit.nanometers yu = y * unit.nanometers zu = z * unit.nanometers potential_x = Eo * ((xu / a)**4 - 2.0 * (xu / a)**2) - (b / a) * xu potential_y = 0.5 * k * (yu**2) potential_z = 0.5 * k * (zu**2) g = sy.diff(potential_x, x) gg = sy.diff(potential_x, x, x) roots_diff = sy.roots(g, x) roots = [] for root in roots_diff.keys(): effective_k = gg.subs(x, root) if effective_k < 0: root_3d = np.zeros([3], dtype=float) * unit.nanometers root_3d[0] = root * unit.nanometers roots.append(root_3d) del (x, y, z) return roots
def test_singularities(self): S1 = sympify(singularities(f1,x,y)) S2 = sympify(singularities(f2,x,y)) S3 = sympify(singularities(f3,x,y)) S4 = sympify(singularities(f4,x,y)) S5 = sympify(singularities(f5,x,y)) S6 = sympify(singularities(f6,x,y)) # S7 = sympify(singularities(f7,x,y)) # S8 = sympify(singularities(f8,x,y)) S9 = sympify(singularities(f9,x,y)) S10= sympify(singularities(f10,x,y)) rt5 = sympy.roots(x**2 + 1, x).keys() S1act = sympify([ ((0,0,1),(2,2,1)), ((0,1,0),(2,1,2)) ]) S2act = sympify([ ((0,0,1),(3,4,2)), ((0,1,0),(4,9,1)) ]) S3act = sympify([ ((0,0,1),(2,1,2)), ((1,-1,1),(2,1,2)), ((1,1,1),(2,1,2)) ]) S4act = sympify([ ((0,0,1),(2,1,2)) ]) S5act = sympify([ ((0,0,1),(3,3,3)), ((1,rt5[1],0),(3,3,3)), ((1,rt5[0],0),(3,3,3)) ]) S6act = sympify([ ((0,0,1),(2,2,2)), ((1,0,0),(2,2,2)) ]) # S7act = sympify([((0,1,0),(3,6,3))]) # S8act = sympify([ # ((0,1,0),(6,21,3)), # ((1,0,0),(3,7,2)) # ]) S9act = sympify([((0,1,0),(5,12,1))]) S10act= sympify([ ((0,1,0),(3,6,1)), ((1,0,0),(4,6,4)) ]) self.assertItemsEqual(S1,S1act) self.assertItemsEqual(S2,S2act) self.assertItemsEqual(S3,S3act) self.assertItemsEqual(S4,S4act) self.assertItemsEqual(S5,S5act) self.assertItemsEqual(S6,S6act) # self.assertItemsEqual(S7,S7act) # self.assertItemsEqual(S8,S8act) self.assertItemsEqual(S9,S9act) self.assertItemsEqual(S10,S10act)
def test_singular_points(self): S1 = singularities(f1,x,y) S2 = singularities(f2,x,y) S3 = singularities(f3,x,y) S4 = singularities(f4,x,y) S5 = singularities(f5,x,y) S6 = singularities(f6,x,y) S7 = singularities(f7,x,y) S8 = singularities(f8,x,y) S9 = singularities(f9,x,y) S10= singularities(f10,x,y) rt5 = [rt for rt,_ in sympy.roots(x**2 + 1, x).iteritems()] S1act = [(0,0,1),(0,1,0)] S2act = [(0,0,1),(0,1,0)] S3act = [(0,0,1),(1,-1,1),(1,1,1)] S4act = [(0,0,1)] S5act = [(0,0,1),(rt5[0],1,0),(rt5[1],1,0)] S6act = [(0,0,1),(1,0,0)] S7act = [(0,1,0)] S8act = [(0,1,0),(1,0,0)] S9act = [(0,1,0)] S10act= [(0,1,0),(1,0,0)] self.assertItemsEqual(S1,S1act) self.assertItemsEqual(S2,S2act) self.assertItemsEqual(S3,S3act) self.assertItemsEqual(S4,S4act) self.assertItemsEqual(S5,S5act) self.assertItemsEqual(S6,S6act) self.assertItemsEqual(S7,S7act) self.assertItemsEqual(S8,S8act) self.assertItemsEqual(S9,S9act) self.assertItemsEqual(S10,S10act)
def characteristic_roots(self): """Compute the roots of the characteristic equation. :returns: List of roots returned by :mod:`sympy`. """ return sympy.roots(self.characteristic_poly())
def polyroots(poly, var): """Return roots of polynomial `poly` for variable `var`.""" roots = sym.roots(poly) num_roots = 0 for root, n in roots.items(): num_roots += n if num_roots != poly.degree(): if poly.degree() >= 5: warn( 'Cannot find symbolic roots for polynomial of degree %d, see Abel-Ruffini theorem' % poly.degree()) # If the coefficients of the polynomial are numerical, # the SymPy nroots function can be used to find # numerical approximations to the roots. a = set() a.add(var) if poly.free_symbols == a: warn('Only %d of %d roots found, using numerical approximation' % (num_roots, poly.degree())) nroots = poly.nroots() roots = {} for root in nroots: if root in roots: roots[root] += 1 else: roots[root] = 1 return roots warn('Only %d of %d roots found' % (num_roots, poly.degree())) return roots
def test_legendre(): raises(ValueError, lambda: legendre(-1, x)) assert legendre(0, x) == 1 assert legendre(1, x) == x assert legendre(2, x) == ((3 * x**2 - 1) / 2).expand() assert legendre(3, x) == ((5 * x**3 - 3 * x) / 2).expand() assert legendre(4, x) == ((35 * x**4 - 30 * x**2 + 3) / 8).expand() assert legendre(5, x) == ((63 * x**5 - 70 * x**3 + 15 * x) / 8).expand() assert legendre(6, x) == ((231 * x**6 - 315 * x**4 + 105 * x**2 - 5) / 16).expand() assert legendre(10, -1) == 1 assert legendre(11, -1) == -1 assert legendre(10, 1) == 1 assert legendre(11, 1) == 1 assert legendre(10, 0) != 0 assert legendre(11, 0) == 0 assert roots(legendre(4, x), x) == { sqrt(Rational(3, 7) - Rational(2, 35) * sqrt(30)): 1, -sqrt(Rational(3, 7) - Rational(2, 35) * sqrt(30)): 1, sqrt(Rational(3, 7) + Rational(2, 35) * sqrt(30)): 1, -sqrt(Rational(3, 7) + Rational(2, 35) * sqrt(30)): 1, } n = Symbol("n") X = legendre(n, x) assert isinstance(X, legendre) assert legendre(-n, x) == legendre(n - 1, x) assert legendre(n, -x) == (-1)**n * legendre(n, x) assert diff(legendre( n, x), x) == n * (x * legendre(n, x) - legendre(n - 1, x)) / (x**2 - 1) assert diff(legendre(n, x), n) == Derivative(legendre(n, x), n)
def get_pane_tikz_lines(poly_pair, color_pair, t0, t1): """ This is called maybe three times. @param poly_pair: the lower and higher order Poly objects @param color_pair: the polynomial colors @param t0: initial time @param t1: final time @return: a list of tikz lines """ lines = [] pa, pb = poly_pair ca, cb = color_pair # draw the segmentation corresponding to the lower order polynomial for left, right, sign in get_segmentation(pa, t0, t1): width = {-1 : '0.5mm', 1 : '2mm'}[sign] line = '\\draw[color=%s,line width=%s] (%s, 0) -- (%s, 0);' % ( ca, width, left, right) lines.append(line) # draw the cuts corresponding to the higher order polynomial for r in sorted(sympy.roots(pb)): cut = float(r) line = '\\draw[color=%s,line width=0.5mm] (%s, -3mm) -- (%s, 3mm);' % ( cb, cut, cut) lines.append(line) return lines
def test_legendre(): raises(ValueError, lambda: legendre(-1, x)) assert legendre(0, x) == 1 assert legendre(1, x) == x assert legendre(2, x) == ((3*x**2 - 1)/2).expand() assert legendre(3, x) == ((5*x**3 - 3*x)/2).expand() assert legendre(4, x) == ((35*x**4 - 30*x**2 + 3)/8).expand() assert legendre(5, x) == ((63*x**5 - 70*x**3 + 15*x)/8).expand() assert legendre(6, x) == ((231*x**6 - 315*x**4 + 105*x**2 - 5)/16).expand() assert legendre(10, -1) == 1 assert legendre(11, -1) == -1 assert legendre(10, 1) == 1 assert legendre(11, 1) == 1 assert legendre(10, 0) != 0 assert legendre(11, 0) == 0 assert roots(legendre(4, x), x) == { sqrt(Rational(3, 7) - Rational(2, 35)*sqrt(30)): 1, -sqrt(Rational(3, 7) - Rational(2, 35)*sqrt(30)): 1, sqrt(Rational(3, 7) + Rational(2, 35)*sqrt(30)): 1, -sqrt(Rational(3, 7) + Rational(2, 35)*sqrt(30)): 1, } n = Symbol("n") X = legendre(n, x) assert isinstance(X, legendre) assert legendre(-n, x) == legendre(n - 1, x) assert legendre(n, -x) == (-1)**n*legendre(n, x) assert diff(legendre(n, x), x) == \ n*(x*legendre(n, x) - legendre(n - 1, x))/(x**2 - 1) assert diff(legendre(n, x), n) == Derivative(legendre(n, x), n)
def factor_linear_quadratic(f, x, as_list=False): """ Factors a polynomial f(x) with real coefficients into linear and quadratic terms. Will not work if f depends on variables other than x. Returns a tuple with the constant coefficient and a list of the factors if as_list is True. """ factors = [] origin_roots = 0 for root, multiplicity in sp.roots(f, x).items(): if root == 0: factors.append((x, multiplicity)) origin_roots = multiplicity elif root.is_real: factors.append((x - root, multiplicity)) elif sp.im(root) > 0: factors.append((sp.expand( (x - root) * (x - sp.conjugate(root))), multiplicity)) coefficient = (f / x ** origin_roots).subs(x, 0) / \ sp.prod([factor.subs(x, 0) ** multiplicity for factor, multiplicity in factors if factor != x]) if as_list: return coefficient, factors return coefficient * sp.prod( [factor**multiplicity for factor, multiplicity in factors])
def _roots(poly, var): """ like roots, but works on higher-order polynomials. """ r = roots(poly, var, multiple=True) n = degree(poly) if len(r) != n: r = [rootof(poly, var, k) for k in range(n)] return r
def as_ZPK(self): """Decompose expression into zeros, poles, gain, undef where expression = K * (prod_n (var - z_n) / (prod_n (var - p_n)) * undef """ Bpoly = self.Bpoly Apoly = self.Apoly K = sym.cancel(Bpoly.LC() / Apoly.LC()) if self.delay != 0: K *= sym.exp(self.var * self.delay) zeros = sym.roots(Bpoly) poles = sym.roots(Apoly) return zeros, poles, K, self.undef
def find_roots(equation): poly_values = [] for key, value in equation.items(): # poly_values.append(float(value.split("*r")[0])) poly_values.append(parse_expr(value.split("*r")[0])) poly_roots = sy.roots(poly_values) print("roots:", poly_roots) return poly_roots
def get_poles_from_matrix(a, show_steps=False): '''Takes the A matrix of a system and returns the poles, format is {pole: multiplicity} can be used to determine stability''' ss = sy.symbols('s') char_mtx = ss * sy.eye(a.rows) - a char_eq = char_mtx.det() if show_steps: display(char_mtx) display(char_eq) return (sy.roots(char_eq))
def d1c_roots(self, h_): # substitute U_0**2 into eq. 2.8 for given value of h and # simplify to create a polynomial in d1c d1cp = WHBase.eq28().subs(U0 ** 2, u_squared()) d1cp = d1cp.subs({h: h_, S: self.S, d0: self.d0}) d1cp = sp.fraction(d1cp.simplify())[0] # get all roots of this polynomial d1c_roots = sp.roots(d1cp, filter=None, multiple=True) return np.array(d1c_roots, dtype=complex)
def test_legendre(): assert legendre(0, x) == 1 assert legendre(1, x) == x assert legendre(2, x) == ((3 * x**2 - 1) / 2).expand() assert legendre(3, x) == ((5 * x**3 - 3 * x) / 2).expand() assert legendre(4, x) == ((35 * x**4 - 30 * x**2 + 3) / 8).expand() assert legendre(5, x) == ((63 * x**5 - 70 * x**3 + 15 * x) / 8).expand() assert (legendre(6, x) == ((231 * x**6 - 315 * x**4 + 105 * x**2 - 5) / 16).expand()) assert legendre(10, -1) == 1 assert legendre(11, -1) == -1 assert legendre(10, 1) == 1 assert legendre(11, 1) == 1 assert legendre(10, 0) != 0 assert legendre(11, 0) == 0 assert legendre(-1, x) == 1 k = Symbol("k") assert legendre(5 - k, x).subs(k, 2) == ((5 * x**3 - 3 * x) / 2).expand() assert roots(legendre(4, x), x) == { sqrt(Rational(3, 7) - Rational(2, 35) * sqrt(30)): 1, -sqrt(Rational(3, 7) - Rational(2, 35) * sqrt(30)): 1, sqrt(Rational(3, 7) + Rational(2, 35) * sqrt(30)): 1, -sqrt(Rational(3, 7) + Rational(2, 35) * sqrt(30)): 1, } n = Symbol("n") X = legendre(n, x) assert isinstance(X, legendre) assert unchanged(legendre, n, x) assert legendre(n, 0) == sqrt(pi) / (gamma(S.Half - n / 2) * gamma(n / 2 + 1)) assert legendre(n, 1) == 1 assert legendre(n, oo) is oo assert legendre(-n, x) == legendre(n - 1, x) assert legendre(n, -x) == (-1)**n * legendre(n, x) assert unchanged(legendre, -n + k, x) assert conjugate(legendre(n, x)) == legendre(n, conjugate(x)) assert diff(legendre( n, x), x) == n * (x * legendre(n, x) - legendre(n - 1, x)) / (x**2 - 1) assert diff(legendre(n, x), n) == Derivative(legendre(n, x), n) _k = Dummy("k") assert (legendre(n, x).rewrite("polynomial").dummy_eq( Sum( (-1)**_k * (S.Half - x / 2)**_k * (x / 2 + S.Half)**(-_k + n) * binomial(n, _k)**2, (_k, 0, n), ))) raises(ArgumentIndexError, lambda: legendre(n, x).fdiff(1)) raises(ArgumentIndexError, lambda: legendre(n, x).fdiff(3))
def rivnynnya(equt): """ Function to find all roots (returns a dict of them) Here: key - root; value - number of its repetitions >>> 'r**2 - 2* r + 1' {1: 2} """ result = roots(equt) return result
def getSols(poly, sym, orderDiff): df = poly polyDiffs = [] diffRoots = [] for i in range(1 + orderDiff): polyDiffs += [df] roots = sympy.roots(df) diffRoots += [roots] df = df.diff() return polyDiffs, diffRoots
def ZPK(self): """Convert to zero-pole-gain (ZPK) form. See also canonical, general, standard, timeconst, and partfrac""" N, D, delay, undef = self.as_ratfun_delay_undef() var = self.var Npoly = sym.Poly(N, var) Dpoly = sym.Poly(D, var) K = sym.cancel(Npoly.LC() / Dpoly.LC()) if delay != 0: K *= sym.exp(self.var * delay) zeros = sym.roots(Npoly) poles = sym.roots(Dpoly) return _zp2tf(zeros, poles, K, self.var) * undef
def getSols(poly, sym, orderDiff): df = poly polyDiffs = [] diffRoots = [] for i in range(1+orderDiff): polyDiffs += [df] roots = sympy.roots(df) diffRoots += [roots] df = df.diff() return polyDiffs, diffRoots
def test_roots_to_poly(self): roots = (1.0, 4.0, 5.0) p = sympyutils.roots_to_poly(roots) self.assertTrue(p.is_monic) root_to_count = sympy.roots(p) self.assertEqual(set(root_to_count.values()), set([1])) observed = set(root_to_count.keys()) expected = set(roots) for r_observed, r_expected in zip(sorted(observed), sorted(expected)): self.assertAlmostEqual(r_observed, r_expected)
def ZPK(self): """Convert to pole-zero-gain (PZK) form. See also canonical, general, mixedfrac, and partfrac""" N, D, delay, undef = self.as_ratfun_delay_undef() var = self.var Npoly = sym.Poly(N, var) Dpoly = sym.Poly(D, var) K = sym.cancel(Npoly.LC() / Dpoly.LC()) if delay != 0: K *= sym.exp(self.var * delay) zeros = sym.roots(Npoly) poles = sym.roots(Dpoly) return _zp2tf(zeros, poles, K, self.var) * undef
def singular_term(F,X,Y,L,I,version): """ Computes a single set of singular terms of the Puiseux expansions. For `I=1`, the function computes the first term of each finite `\mathbb{K}` expansion. For `I=2`, it computes the other terms of the expansion. """ T = [] # if the curve is singular then compute the singular tuples # otherwise, use the standard newton polygon method if is_singular(F,X,Y): for (q,m,l,Phi) in desingularize(F,X,Y): for eta in Phi.all_roots(radicals=True): tau = (q,1,m,1,sympy.together(eta)) T.append((tau,0,1)) else: # each side of the newton polygon corresponds to a K-term. for (q,m,l,Phi) in polygon(F,X,Y,I): # the rational method if version == 'rational': u,v = _bezout(q,m) # each newton polygon side has a characteristic # polynomial. For each square-free factor, each root # corresponds to a K-term for (Psi,r) in _square_free(Phi,_Z): Psi = sympy.Poly(Psi,_Z) # compute the roots of Psi. Use the RootOf construct if # possible. In the case when Psi is over EX (i.e. when # RootOf doesn't work) then compute symbolic roots. try: roots = Psi.all_roots(radicals=True) except NotImplementedError: roots = sympy.roots(Psi,_Z).keys() for xi in roots: # the classical version returns the "raw" roots if version == 'classical': P = sympy.Poly(_U**q-xi,_U) beta = RootOf(P,0,radicals=True) tau = (q,1,m,beta,1) T.append((tau,l,r)) # the rational version rescales parameters so as # to include ony rational terms in the Puiseux # expansions. if version == 'rational': mu = xi**(-v) beta = sympy.together(xi**u) tau = (q,mu,m,beta,1) T.append((tau,l,r)) return T
def run_copper_smith(f, N, h, k): X = s.S(s.ceiling((s.Pow(2, - 1 / 2) * s.Pow(h * k, -1 / (h * k - 1))) * s.Pow(N, (h - 1) / (h * k - 1))) - 1) gen = lll(generate(f, N, h, k, X), s.S(0.75)) final_poly = [gen[0][i] / s.Pow(X, i) for i in range(len(gen[0]))][::-1] roots = s.roots(final_poly) for r in roots: print(r) return roots
def timeconst(self): """Convert rational function to time constant form with unity lowest power of denominator. See also canonical, general, partfrac, standard, and ZPK""" N, D, delay, undef = self.as_ratfun_delay_undef() var = self.var Npoly = sym.Poly(N, var) Dpoly = sym.Poly(D, var) K = sym.cancel(Npoly.LC() / Dpoly.LC()) if delay != 0: K *= sym.exp(self.var * delay) zeros = sym.roots(Npoly) poles = sym.roots(Dpoly) return _tc2tf(zeros, poles, K, self.var) * undef
def _singular_points_finite(f,x,y): """ Returns the finite singular points of f. """ S = [] # compute the finite singularities: use the resultant p = sympy.Poly(f,[x,y]) n = p.degree(y) res = sympy.Poly(sympy.resultant(p,p.diff(y),y),x) for xk,deg in sympy.roots(res,x).iteritems(): if deg > 1: fxk = sympy.Poly(f.subs({x:xk,y:_Z}), _Z) for ykj,_ in sympy.roots(fxk, _Z).iteritems(): fx = f.diff(x) fy = f.diff(y) subs = {x:xk,y:ykj} if (fx.subs(subs) == 0) and (fy.subs(subs) == 0): S.append((xk,ykj,1)) return S
def fund_ries(drc): a2,a1,a0 = drc r = roots(a2*t**2 + a1*t +a0,t) kl = list(r.keys()) if len(kl) == 2: # jednoduche korene r1,r2 = kl re_k,im_k = r1.as_real_imag() if im_k == 0: # jednoduche realne korene return exp(r1*t), exp(r2*t) else: # komplexne zdruz.korene return exp(re_k*t)*sin(im_k*t), exp(re_k*t)*cos(im_k*t) else: # dvojnasobny koren return exp(kl[0]*t), t*exp(kl[0]*t)
def solve_eq(init_conditions, associated): degree = len(init_conditions) eq = util.characteristic_eq(degree, associated) rts = roots(parse_expr(eq)) nr_of_a = util.nr_of_alphas(rts) if len(rts) == 1: alphas = util.find_alphas_sol2(rts, init_conditions, nr_of_a) return util.build_solution2(rts, alphas) else: alphas = util.find_alphas_sol1(rts, init_conditions, nr_of_a) return util.build_solution1(rts, alphas)
def _singular_points_infinite(f,x,y): """ Returns the singular points of f at infinity. """ S = [] # compute homogenous polynomial F, d = homogenize(f,x,y,_z) # find singular points at infinity F0 = sympy.Poly(F.subs([(_z,0)]),[x,y]) domain = sympy.QQ[sympy.I] solsX1 = sympy.roots(F0.subs({x:1,y:_Z}),_Z).keys() solsY1 = sympy.roots(F0.subs({y:1,x:_Z}),_Z).keys() all_sols = [ (1,yi,0) for yi in solsX1 ] all_sols.extend( [ (xi,1,0) for xi in solsY1 ] ) # these points are in projective space, so filter out equal points # such as (1,I,0) == (-I,1,0). We normalize these projective # points such that 1 appears in either the x- or y- coordinate sols = [] for xi,yi,zi in all_sols: normalized = (1,yi/xi,0) if xi != sympy.S(0) else (xi/yi,1,0) if not normalized in sols: sols.append(normalized) # Filter out any points that are not singular by checking if the # gradient vanishes. grad = [F.diff(var) for var in [x,y,_z]] for xi,yi,zi in sols: fsub = lambda e,x=x,y=y,_z=_z,xi=xi,yi=yi,zi=zi: \ e.subs({x:xi,y:yi,_z:zi}).simplify() != sympy.S(0) if not any(map(fsub,grad)): S.append((xi,yi,zi)) return S
def tustin(tf, sRate): s = getMapping(tf)['s'] T = 1 / sRate poles = sympy.roots(sympy.denom(tf), s, multiple=True) centroid = np.mean(np.abs(poles)) invz = sympy.Symbol('invz', real=True) # normalized center frequency derived from poles of filter SISO transfer function w0 = 2 * np.pi * centroid / (sRate * 2 * np.pi) # modified bilinear transform w/ frequency warping bt = w0 / sympy.tan(w0 * T / 2) * ((1 - invz) / (1 + invz)) dt = sympy.simplify(tf.subs({s: bt})) b = sympy.Poly(sympy.numer(dt)).all_coeffs()[::-1] a = sympy.Poly(sympy.denom(dt)).all_coeffs()[::-1] normalize = lambda x: float(x / a[0]) return (map(normalize, b), map(normalize, a))
def test_ndiff_roots_symbolic(self): roots = (1.25, 4.5, 5.75) a, b, c = roots polys = roots_to_differential_polys(roots) # compute linear root manually r = float(a + b + c) / 3 # check linear root observed = sorted(float(r) for r in sympy.roots(polys[0])) expected = sorted([r]) self.assertTrue(np.allclose(observed, expected)) # compute quadratic roots manually A = a * a + b * b + c * c B = a * b + a * c + b * c S = a + b + c r0 = float(S + math.sqrt(A - B)) / 3 r1 = float(S - math.sqrt(A - B)) / 3 # check quadratic roots observed = sorted(float(r) for r in sympy.roots(polys[1])) expected = sorted([r0, r1]) self.assertTrue(np.allclose(observed, expected)) # check cubic roots observed = sorted(float(r) for r in sympy.roots(polys[2])) expected = sorted(roots) self.assertTrue(np.allclose(observed, expected))
def tustin(tf, sRate): s = getMapping(tf)['s'] T = 1/sRate poles = sympy.roots(sympy.denom(tf), s, multiple=True) centroid = np.mean(np.abs(poles)) invz = sympy.Symbol('invz', real=True) # normalized center frequency derived from poles of filter SISO transfer function w0 = 2*np.pi*centroid/(sRate*2*np.pi) # modified bilinear transform w/ frequency warping bt = w0/sympy.tan(w0*T/2) * ((1-invz)/(1+invz)) dt = sympy.simplify(tf.subs({s: bt})) b = sympy.Poly(sympy.numer(dt)).all_coeffs()[::-1] a = sympy.Poly(sympy.denom(dt)).all_coeffs()[::-1] normalize = lambda x: float(x/a[0]) return (map(normalize, b), map(normalize, a))
def test_ndiff_roots_symbolic(self): roots = (1.25, 4.5, 5.75) a, b, c = roots polys = roots_to_differential_polys(roots) # compute linear root manually r = float(a + b + c) / 3 # check linear root observed = sorted(float(r) for r in sympy.roots(polys[0])) expected = sorted([r]) self.assertTrue(np.allclose(observed, expected)) # compute quadratic roots manually A = a*a + b*b + c*c B = a*b + a*c + b*c S = a + b + c r0 = float(S + math.sqrt(A - B)) / 3 r1 = float(S - math.sqrt(A - B)) / 3 # check quadratic roots observed = sorted(float(r) for r in sympy.roots(polys[1])) expected = sorted([r0, r1]) self.assertTrue(np.allclose(observed, expected)) # check cubic roots observed = sorted(float(r) for r in sympy.roots(polys[2])) expected = sorted(roots) self.assertTrue(np.allclose(observed, expected))
def _solve(self): """ Solve the recurrence relation into a closed form Returns: String: The solved recurrence relation in string format """ logging.info("Started solving recurrence relation: %s" % str(self._recurrence)) self._degree, homogenous, nonHomogenous, linear = self._analyseExpression() msg = "homogenous" if nonHomogenous == 0 else "nonhomogenous" logging.info("Analyzation complete, It is a %s recurrence relation with degree %d" % (msg, self._degree)) if nonHomogenous != 0: logging.info("The part that makes the recurrence nonhomogenous is: %s" % str(nonHomogenous)) if not linear: raise RecurrenceSolveFailed("The equation is not linear") characteristicEq = self._getCharacteristicEquation(homogenous) logging.info("The characteristic equation is: %s" % str(characteristicEq)) # get roots of characteristic equations and remove # the complex roots realRoots = { s:m for (s,m) in sympy.roots(characteristicEq).items() if sympy.I not in s.atoms() } logging.info("With roots: multiplicities: %s" % str(realRoots)) # the sum of the multiplicity must be the same as the degree # else we can't solve the equation if sum(realRoots.values()) != self._degree: msg = "The characteristic equation \"%s\" has the following real roots: %s, and the multiplicities is not the same as the degree" % (str(characteristicEq), str(realRoots)) raise RecurrenceSolveFailed(msg) generalSolution, ctx = self._getGeneralSolution(realRoots) logging.info("The general solution has the form: %s" % str(generalSolution)) solved = sympy.sympify("0") if nonHomogenous == 0: solved = self._calculateClosedFromGeneralSolution(generalSolution, ctx) else: solved = self._solveNonHomogeneous(realRoots, homogenous, nonHomogenous, generalSolution, ctx) logging.info("Solved raw: %s" % str(solved)) solved = solved.simplify() logging.info("Solved simplified: %s" % str(solved)) return solved
def ballpath(xinit=0, yinit=0, vxinit=1, vyinit=1): x0val = xinit y0val = yinit v0xval = vxinit v0yval = vyinit # create symbolic exprs for ball path and intersection polynomial x0, y0, v0x, v0y, t = symbols('x0 y0 v0x v0y t') xt = x0 + v0x * t yt = y0 + v0y * t - (1 / 2) * 9.8 * (t**2) pgen = poly(xt**2 + yt**2 - 1, t) # create actual functions from symbolic exprs xtf = lambdify((t, x0, v0x), xt) ytf = lambdify((t, y0, v0y), yt) vytf = lambdify((t, v0y), diff(yt, t)) while True: # subst current conditions into intersect poly p = pgen.subs({x0: x0val, y0: y0val, v0x: v0xval, v0y: v0yval}) # solve for t rts = roots(p, t) rts = np.array([complex(r) for r in rts.keys()]) tcol = np.min(rts[np.logical_and(rts > 0, np.imag(rts) == 0)]).real # find intersect point and speed at the moment xcol = xtf(tcol, x0val, v0xval) ycol = ytf(tcol, y0val, v0yval) vxcol = v0xval vycol = vytf(tcol, v0yval) vcol = np.array([[vxcol], [vycol]]) # calculate speed vector after bounce alpha = np.arctan2(ycol, xcol) - np.arctan2(vycol, vxcol) R = np.array([[np.cos(2*alpha), -np.sin(2*alpha)], \ [np.sin(2*alpha), np.cos(2*alpha)]]) newv0 = R @ -vcol tvals = np.linspace(0, tcol, 100) xvals = xtf(tvals, x0val, v0xval) yvals = ytf(tvals, y0val, v0yval) yield (xvals.tolist(), yvals.tolist()) x0val = xcol y0val = ycol v0xval = newv0[0].item() v0yval = newv0[1].item()
def get_segmentation(p, t0, t1): """ A segmentation is a sequence of triples (left, right, sign). @param p: a sympy Poly @param t0: initial time @param t1: final time @return: a segmentation """ roots = sorted(float(r) for r in sympy.roots(p)) points = [t0] + roots + [t1] segmentation = [] for left, right in iterutils.pairwise(points): mid = (left + right) / 2 sign = -1 if p.eval(mid) <= 0 else 1 seg = (left, right, sign) segmentation.append(seg) return segmentation
def test_poly(): output("""\ poly_:{ r:{$[prec>=abs(x:reim x)1;x 0;x]} each .qml.poly x; r iasc {x:reim x;(abs x 1;neg x 1;x 0)} each r};""") for A in poly_subjects: A = sp.Poly(A, sp.Symbol("x")) if A.degree() <= 3 and all(a.is_real for a in A.all_coeffs()): R = [] for r in sp.roots(A, multiple=True): r = sp.simplify(sp.expand_complex(r)) R.append(r) R.sort(key=lambda x: (abs(sp.im(x)), -sp.im(x), sp.re(x))) else: R = mp.polyroots([mp.mpc(*(a.evalf(mp.mp.dps)).as_real_imag()) for a in A.all_coeffs()]) R.sort(key=lambda x: (abs(x.imag), -x.imag, x.real)) assert len(R) == A.degree() test("poly_", A.all_coeffs(), R, complex_pair=True)
def given(): xp0 = randrange(7, 10) pmax = randrange(7, 10) Ep = R(-pmax, xp0) * x + pmax E = sympy.integrate(Ep, x) b = randrange(2, xp0 - 2) cmax = int(Ep.subs(x, b).n()) c = randrange(1, cmax) a = R(randrange(1, pmax - c), b * b) Kp = a * (x - b) ** 2 + c Gp = Ep - Kp rG = [r.n() for r in sympy.roots(Gp) if r > 0][0] G = sympy.integrate(Gp, x) mG = G.subs(x, rG) Ko = int(mG - 1) / 2 #K = sympy.integrate(Kp,x)+Ko #G = E.n()-K.n() #rts = sorted([r.n() for r in sympy.roots(G) if r > 0]) g = Struct(pmax=pmax, xp0=xp0, Ko=Ko, Kp=sympy.sstr(Kp)) return g
def test_legendre(): assert legendre(0, x) == 1 assert legendre(1, x) == x assert legendre(2, x) == ((3*x**2-1)/2).expand() assert legendre(3, x) == ((5*x**3-3*x)/2).expand() assert legendre(4, x) == ((35*x**4-30*x**2+3)/8).expand() assert legendre(5, x) == ((63*x**5-70*x**3+15*x)/8).expand() assert legendre(6, x) == ((231*x**6-315*x**4+105*x**2-5)/16).expand() assert legendre(10, -1) == 1 assert legendre(11, -1) == -1 assert legendre(10, 1) == 1 assert legendre(11, 1) == 1 assert legendre(10, 0) != 0 assert legendre(11, 0) == 0 assert roots(legendre(4,x), x) == { sqrt(Rational(3, 7) - Rational(2, 35)*sqrt(30)): 1, -sqrt(Rational(3, 7) - Rational(2, 35)*sqrt(30)): 1, sqrt(Rational(3, 7) + Rational(2, 35)*sqrt(30)): 1, -sqrt(Rational(3, 7) + Rational(2, 35)*sqrt(30)): 1, }
def get_pane_tikz_lines(poly_pair, color_pair, t0, t1): """ This is called maybe three times. @param poly_pair: the lower and higher order Poly objects @param color_pair: the polynomial colors @param t0: initial time @param t1: final time @return: a list of tikz lines """ lines = [] pa, pb = poly_pair ca, cb = color_pair # draw the segmentation corresponding to the lower order polynomial for left, right, sign in get_segmentation(pa, t0, t1): width = {-1: "0.5mm", 1: "2mm"}[sign] line = "\\draw[color=%s,line width=%s] (%s, 0) -- (%s, 0);" % (ca, width, left, right) lines.append(line) # draw the cuts corresponding to the higher order polynomial for r in sorted(sympy.roots(pb)): cut = float(r) line = "\\draw[color=%s,line width=0.5mm] (%s, -3mm) -- (%s, 3mm);" % (cb, cut, cut) lines.append(line) return lines
def calc(g): Kp = S(g.Kp) Ep = R(-g.pmax, g.xp0) * x + g.pmax E = sympy.integrate(Ep, x) K = sympy.integrate(Kp, x) + S(g.Ko) Gp = Ep - Kp rG = [r.n() for r in sympy.roots(Gp) if r > 0][0] G = E - K mG = G.subs(x, rG) kk = sympy.Wild('kk') dd = sympy.Wild('dd') kd = Ep.match(kk * x + dd) p = kd[kk] * x / 2 + kd[dd] mp = p.subs(x, rG) el = S(1 + kd[dd] / (kd[kk] * x / 2)) return [ sympy.sstr(Ep), sympy.sstr(E), sympy.sstr(K), sympy.sstr(p), sympy.sstr(el), rG, mp]
def coefficient(polinom_in): """ :param polinom_in: :return: """ edge_dot = [] polinom_antispace = re.sub(r'\s', '', polinom_in) edge_y = test_eval(0, polinom_antispace) # нахождение максимального y при x=0 edge_y = edge_y * 1.03 r = roots(polinom_antispace) #получаю словарь возможных корней(пересечение с x) edge_list_x = [] for k in r.keys(): if k.__class__.__name__ == "Float": if float(k) > 0: edge_list_x.append(float(k)) edge_x = min(edge_list_x) edge_x = edge_x * 1.03 print edge_x edge_dot.append(edge_x) edge_dot.append(edge_y) return edge_dot # возвращает список с точкой пересечения оси икс и игрик
phi_sum = np.zeros(np.diag(Phi[:,0]).shape) for i in xrange(Phi.shape[1]): phi_sum+= alpha[i] * np.diag(Phi[:,i]) (lambda_2 * phi_sum)**(-.5) # # implementing the set-level optimization # alternate between alpha and sigma optimization from sympy import roots,symbols,I from sympy.utilities.lambdify import lambdify x,a_rootvar,b_rootvar,d_rootvar = symbols('x,a_rootvar,b_rootvar,d_rootvar') root_list = roots(a_rootvar*x**3 +b_rootvar*x**2 +d_rootvar,x).keys() root_exprs = [ root_expr.as_real_imag() for root_expr in root_list] def get_real_root(a,b,d): """ Get the real solution to the equation in x a*x**3 + b*x**2 + d = 0 """ real_soln_idx = np.argmin(np.abs([root_exprs[n][1].evalf(subs={a_rootvar:a,b_rootvar:b,d_rootvar:d}) for n in xrange(len(root_exprs))])) return root_exprs[real_soln_idx][0].evalf(subs={a_rootvar:a,b_rootvar:b,d_rootvar:d}) # now we are going to
def log_to_real(h, q, x, t): """Convert complex logarithms to real functions. Given real field K and polynomials h in K[t,x] and q in K[t], returns real function f such that: ___ df d \ ` -- = -- ) a log(h(a, x)) dx dx /__, a | q(a) = 0 """ u, v = symbols('u v') H = h.subs({t:u+I*v}).as_basic().expand() Q = q.subs({t:u+I*v}).as_basic().expand() H_map = collect(H, I, evaluate=False) Q_map = collect(Q, I, evaluate=False) a, b = H_map.get(S(1), S(0)), H_map.get(I, S(0)) c, d = Q_map.get(S(1), S(0)), Q_map.get(I, S(0)) R = Poly(resultant(c, d, v), u) R_u = roots(R, domain='R') if len(R_u) != number_of_real_roots(R): return None result = S(0) for r_u in R_u.iterkeys(): C = Poly(c.subs({u:r_u}), v) R_v = roots(C, domain='R') if len(R_v) != number_of_real_roots(C): return None for r_v in R_v: if not r_v.is_positive: continue D = d.subs({u:r_u, v:r_v}) if D.evalf(chop=True) != 0: continue A = Poly(a.subs({u:r_u, v:r_v}), x) B = Poly(b.subs({u:r_u, v:r_v}), x) AB = (A**2 + B**2).as_basic() result += r_u*log(AB) + r_v*log_to_atan(A, B) R_q = roots(q, domain='R') if len(R_q) != number_of_real_roots(q): return None for r in R_q.iterkeys(): result += r*log(h.subs(t, r).as_basic()) return result
def log_to_real(h, q, x, t): """ Convert complex logarithms to real functions. Given real field K and polynomials h in K[t,x] and q in K[t], returns real function f such that: ___ df d \ ` -- = -- ) a log(h(a, x)) dx dx /__, a | q(a) = 0 Examples ======== >>> from sympy.integrals.rationaltools import log_to_real >>> from sympy.abc import x, y >>> from sympy import Poly, sqrt, S >>> log_to_real(Poly(x + 3*y/2 + S(1)/2, x, domain='QQ[y]'), ... Poly(3*y**2 + 1, y, domain='ZZ'), x, y) 2*sqrt(3)*atan(2*sqrt(3)*x/3 + sqrt(3)/3)/3 >>> log_to_real(Poly(x**2 - 1, x, domain='ZZ'), ... Poly(-2*y + 1, y, domain='ZZ'), x, y) log(x**2 - 1)/2 See Also ======== log_to_atan """ u, v = symbols('u,v', cls=Dummy) H = h.as_expr().subs({t: u + I*v}).expand() Q = q.as_expr().subs({t: u + I*v}).expand() H_map = collect(H, I, evaluate=False) Q_map = collect(Q, I, evaluate=False) a, b = H_map.get(S(1), S(0)), H_map.get(I, S(0)) c, d = Q_map.get(S(1), S(0)), Q_map.get(I, S(0)) R = Poly(resultant(c, d, v), u) R_u = roots(R, filter='R') if len(R_u) != R.count_roots(): return None result = S(0) for r_u in R_u.keys(): C = Poly(c.subs({u: r_u}), v) R_v = roots(C, filter='R') if len(R_v) != C.count_roots(): return None for r_v in R_v: if not r_v.is_positive: continue D = d.subs({u: r_u, v: r_v}) if D.evalf(chop=True) != 0: continue A = Poly(a.subs({u: r_u, v: r_v}), x) B = Poly(b.subs({u: r_u, v: r_v}), x) AB = (A**2 + B**2).as_expr() result += r_u*log(AB) + r_v*log_to_atan(A, B) R_q = roots(q, filter='R') if len(R_q) != q.count_roots(): return None for r in R_q.keys(): result += r*log(h.as_expr().subs(t, r)) return result
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 eval(cls, f, *gens): from sympy import roots rootslist = list(roots(f, *gens, filter='R').keys()) rootslist.sort(key=customized_sort_key) return TupleNoParen(*rootslist)
def integral_basis(f,x,y): """ Compute the integral basis {b1, ..., bg} of the algebraic function field C[x,y] / (f). """ # If the curve is not monic then map y |-> y/lc(x) where lc(x) # is the leading coefficient of f T = sympy.Dummy('T') d = sympy.degree(f,y) lc = sympy.LC(f,y) if x in lc: f = sympy.ratsimp( f.subs(y,y/lc)*lc**(d-1) ) else: f = f/lc lc = 1 # # Compute df # p = sympy.Poly(f,[x,y]) n = p.degree(y) res = sympy.resultant(p,p.diff(y),y) factors = sympy.factor_list(res)[1] df = [k for k,deg in factors if (deg > 1) and (sympy.LC(k) == 1)] # # Compute series truncations at appropriate x points # alpha = [] r = [] for l in range(len(df)): k = df[l] alphak = sympy.roots(k).keys()[0] rk = compute_series_truncations(f,x,y,alphak,T) alpha.append(alphak) r.append(rk) # # Main Loop # a = [sympy.Dummy('a%d'%k) for k in xrange(n)] b = [1] for d in range(1,n): bd = y*b[-1] for l in range(len(df)): k = df[l] alphak = alpha[l] rk = r[l] found_something = True while found_something: # construct system of equations consisting of the coefficients # of negative powers of (x-alphak) in the substitutions # A(r_{k,1}),...,A(r_{k,n}) A = (sum(ak*bk for ak,bk in zip(a,b)) + bd) / (x - alphak) coeffs = [] for rki in rk: # substitute and extract coefficients A_rki = A.subs(y,rki) coeffs.extend(_negative_power_coeffs(A_rki, x, alphak)) # solve the coefficient equations for a0,...,a_{d-1} coeffs = [coeff.as_numer_denom()[0] for coeff in coeffs] sols = sympy.solve_poly_system(coeffs, a[:d]) if sols is None or sols == []: found_something = False else: sol = sols[0] bdm1 = sum( sol[i]*bk for i,bk in zip(range(d),b) ) bd = (bdm1 + bd) / k # bd found. Append to list of basis elements b.append( bd ) # finally, convert back to singularized curve if necessary for i in xrange(1,len(b)): b[i] = b[i].subs(y,y*lc).ratsimp() return b
def build_series(pis,x,y,T,a,parametric): """ Builds all Puiseux series from pi data. `\pi_i=(q,\mu,m,\beta,\eta), X \mapsto\mu X^q,Y \mapsto X^m(\beta+\eta Y)` Algorithm: Uses the formulas from p. 135 "Rational puiseux expandsions" by D. Duval. The indexing is adjusted: m,beta,mu,eta are all shifted down by one. However, the intexing on qh should match that of D. Duval. """ series = [] # build singular part of expansion series for pi in pis: q,mu,m,beta,eta = zip(*pi) R = len(pi) qh = build_qh_dict(q) # compute X = lam*T**e e = qh[(0,R)] lam = reduce(lambda z1,z2: z1*z2, (mu[k]**qh[(0,k)] for k in xrange(R))) X = sympy.simplify(lam)*T**e + a # compute Y = \sum_{h=1}^R alpha_h * T**n_h. if parametric: Y = sympy.S(0) else: lams = sympy.roots(lam*_Z**e - 1,_Z,multiple=True) Y = [sympy.S(0) for _ in xrange(e)] n_h = sympy.S(0) eta_h = sympy.S(1) for h in xrange(0,R): eta_h *= eta[h] n_h += m[h] * qh[(h+1,R)] alpha_h = sympy.S(1) for i in xrange(0,h): alpha_h *= mu[i+1]**sum(m[j]*qh[(j+1,i)] for j in xrange(0,i)) for i in xrange(h,R-1): alpha_h *= mu[i+1]**sum(m[j]*qh[(j+1,i)] for j in xrange(0,h)) alpha_h *= eta_h*beta[h] if parametric: Y += sympy.simplify(alpha_h)*T**n_h else: s_h = sympy.Rational(n_h,e) for i in xrange(e): alpha_h_i = sympy.simplify(alpha_h*(lams[i]**n_h)) Y[i] += alpha_h_i*(x-a)**s_h # All puiseux series associated with this place are computed. # Add to series list. if parametric: series.append((X,Y)) else: series.append(Y) return series
# In[8]: invL(G) # The characteristic equation is the denominator of the transfer function # In[5]: ce = sympy.Eq(sympy.denom(G), 0) ce # In[6]: roots = sympy.roots(ce, s) roots # The shape of the inverse Laplace depends on the nature of the roots, which depends on the value of $\zeta$ # Overdamped: $\zeta>1$. Two distinct real roots # In[3]: G # In[7]: invL(G.subs({zeta: 2}))