def _try_heuristics(f): """Find roots using formulas and some tricks. """ if f.length == 1: if f.is_constant: return [] else: return [S(0)] * f.degree if f.length == 2: if f.degree == 1: return roots_linear(f) else: return roots_binomial(f) x, result = f.symbols[0], [] for i in [S(-1), S(1)]: if f(i).expand().is_zero: f = poly_div(f, x - i)[0] result.append(i) break n = f.degree if n == 1: result += roots_linear(f) elif n == 2: result += roots_quadratic(f) elif n == 3 and flags.get('cubics', True): result += roots_cubic(f) elif n == 4 and flags.get('quartics', False): result += roots_quartic(f) return result
def angular_momentum(point, frame, *body): """Angular momentum of a system This function returns the angular momentum of a system of Particle's and/or RigidBody's. The angular momentum of such a system is equal to the vector sum of the angular momentum of its constituents. Consider a system, S, comprised of a rigid body, A, and a particle, P. The angular momentum of the system, H, is equal to the vector sum of the linear momentum of the particle, H1, and the linear momentum of the rigid body, H2, i.e- H = H1 + H2 Parameters ========== point : Point The point about which angular momentum of the system is desired. frame : ReferenceFrame The frame in which angular momentum is desired. body1, body2, body3... : Particle and/or RigidBody The body (or bodies) whose kinetic energy is required. Examples ======== >>> from sympy.physics.mechanics import Point, Particle, ReferenceFrame >>> from sympy.physics.mechanics import RigidBody, outer, angular_momentum >>> N = ReferenceFrame('N') >>> O = Point('O') >>> O.set_vel(N, 0 * N.x) >>> P = O.locatenew('P', 1 * N.x) >>> P.set_vel(N, 10 * N.x) >>> Pa = Particle('Pa', P, 1) >>> Ac = O.locatenew('Ac', 2 * N.y) >>> Ac.set_vel(N, 5 * N.y) >>> a = ReferenceFrame('a') >>> a.set_ang_vel(N, 10 * N.z) >>> I = outer(N.z, N.z) >>> A = RigidBody('A', Ac, a, 20, (I, Ac)) >>> angular_momentum(O, N, Pa, A) 10*N.z """ if not isinstance(frame, ReferenceFrame): raise TypeError('Please enter a valid ReferenceFrame') if not isinstance(point, Point): raise TypeError('Please specify a valid Point') else: angular_momentum_sys = S(0) for e in body: if isinstance(e, (RigidBody, Particle)): angular_momentum_sys += e.angular_momentum(point, frame) else: raise TypeError('*body must have only Particle or RigidBody') return angular_momentum_sys
def kinetic_energy(frame, *body): """Kinetic energy of a multibody system. This function returns the kinetic energy of a system of Particle's and/or RigidBody's. The kinetic energy of such a system is equal to the sum of the kinetic energies of its constituents. Consider a system, S, comprising a rigid body, A, and a particle, P. The kinetic energy of the system, T, is equal to the vector sum of the kinetic energy of the particle, T1, and the kinetic energy of the rigid body, T2, i.e. T = T1 + T2 Kinetic energy is a scalar. Parameters ========== frame : ReferenceFrame The frame in which the velocity or angular velocity of the body is defined. body1, body2, body3... : Particle and/or RigidBody The body (or bodies) whose kinetic energy is required. Examples ======== >>> from sympy.physics.mechanics import Point, Particle, ReferenceFrame >>> from sympy.physics.mechanics import RigidBody, outer, kinetic_energy >>> N = ReferenceFrame('N') >>> O = Point('O') >>> O.set_vel(N, 0 * N.x) >>> P = O.locatenew('P', 1 * N.x) >>> P.set_vel(N, 10 * N.x) >>> Pa = Particle('Pa', P, 1) >>> Ac = O.locatenew('Ac', 2 * N.y) >>> Ac.set_vel(N, 5 * N.y) >>> a = ReferenceFrame('a') >>> a.set_ang_vel(N, 10 * N.z) >>> I = outer(N.z, N.z) >>> A = RigidBody('A', Ac, a, 20, (I, Ac)) >>> kinetic_energy(N, Pa, A) 350 """ if not isinstance(frame, ReferenceFrame): raise TypeError('Please enter a valid ReferenceFrame') ke_sys = S(0) for e in body: if isinstance(e, (RigidBody, Particle)): ke_sys += e.kinetic_energy(frame) else: raise TypeError('*body must have only Particle or RigidBody') return ke_sys
def taylor_term(n, x, *previous_terms): if n == 0: return 1 / sympify(x) elif n < 0 or n % 2 == 0: return S.Zero else: x = sympify(x) B = S.Bernoulli(n + 1) F = C.Factorial(n + 1) return (-1)**((n + 1) // 2) * 2**(n + 1) * B / F * x**n
def potential_energy(*body): """Potential energy of a multibody system. This function returns the potential energy of a system of Particle's and/or RigidBody's. The potential energy of such a system is equal to the sum of the potential energy of its constituents. Consider a system, S, comprising a rigid body, A, and a particle, P. The potential energy of the system, V, is equal to the vector sum of the potential energy of the particle, V1, and the potential energy of the rigid body, V2, i.e. V = V1 + V2 Potential energy is a scalar. Parameters ========== body1, body2, body3... : Particle and/or RigidBody The body (or bodies) whose potential energy is required. Examples ======== >>> from sympy.physics.mechanics import Point, Particle, ReferenceFrame >>> from sympy.physics.mechanics import RigidBody, outer, potential_energy >>> from sympy import symbols >>> M, m, g, h = symbols('M m g h') >>> N = ReferenceFrame('N') >>> O = Point('O') >>> O.set_vel(N, 0 * N.x) >>> P = O.locatenew('P', 1 * N.x) >>> Pa = Particle('Pa', P, m) >>> Ac = O.locatenew('Ac', 2 * N.y) >>> a = ReferenceFrame('a') >>> I = outer(N.z, N.z) >>> A = RigidBody('A', Ac, a, M, (I, Ac)) >>> Pa.set_potential_energy(m * g * h) >>> A.set_potential_energy(M * g * h) >>> potential_energy(Pa, A) M*g*h + g*h*m """ pe_sys = S(0) for e in body: if isinstance(e, (RigidBody, Particle)): pe_sys += e.potential_energy else: raise TypeError('*body must have only Particle or RigidBody') return pe_sys
def linear_momentum(frame, *body): """Linear momentum of the system. This function returns the linear momentum of a system of Particle's and/or RigidBody's. The linear momentum of a system is equal to the vector sum of the linear momentum of its constituents. Consider a system, S, comprised of a rigid body, A, and a particle, P. The linear momentum of the system, L, is equal to the vector sum of the linear momentum of the particle, L1, and the linear momentum of the rigid body, L2, i.e- L = L1 + L2 Parameters ========== frame : ReferenceFrame The frame in which linear momentum is desired. body1, body2, body3... : Particle and/or RigidBody The body (or bodies) whose kinetic energy is required. Examples ======== >>> from sympy.physics.mechanics import Point, Particle, ReferenceFrame >>> from sympy.physics.mechanics import RigidBody, outer, linear_momentum >>> N = ReferenceFrame('N') >>> P = Point('P') >>> P.set_vel(N, 10 * N.x) >>> Pa = Particle('Pa', P, 1) >>> Ac = Point('Ac') >>> Ac.set_vel(N, 25 * N.y) >>> I = outer(N.x, N.x) >>> A = RigidBody('A', Ac, N, 20, (I, Ac)) >>> linear_momentum(N, A, Pa) 10*N.x + 500*N.y """ if not isinstance(frame, ReferenceFrame): raise TypeError('Please specify a valid ReferenceFrame') else: linear_momentum_sys = S(0) for e in body: if isinstance(e, (RigidBody, Particle)): linear_momentum_sys += e.linear_momentum(frame) else: raise TypeError('*body must have only Particle or RigidBody') return linear_momentum_sys
def get_motion_params(frame, **kwargs): """ Returns the three motion parameters - (acceleration, velocity, and position) as vectorial functions of time in the given frame. If a higher order differential function is provided, the lower order functions are used as boundary conditions. For example, given the acceleration, the velocity and position parameters are taken as boundary conditions. The values of time at which the boundary conditions are specified are taken from timevalue1(for position boundary condition) and timevalue2(for velocity boundary condition). If any of the boundary conditions are not provided, they are taken to be zero by default (zero vectors, in case of vectorial inputs). If the boundary conditions are also functions of time, they are converted to constants by substituting the time values in the dynamicsymbols._t time Symbol. This function can also be used for calculating rotational motion parameters. Have a look at the Parameters and Examples for more clarity. Parameters ========== frame : ReferenceFrame The frame to express the motion parameters in acceleration : Vector Acceleration of the object/frame as a function of time velocity : Vector Velocity as function of time or as boundary condition of velocity at time = timevalue1 position : Vector Velocity as function of time or as boundary condition of velocity at time = timevalue1 timevalue1 : sympyfiable Value of time for position boundary condition timevalue2 : sympyfiable Value of time for velocity boundary condition Examples ======== >>> from sympy.physics.mechanics import ReferenceFrame, get_motion_params, dynamicsymbols >>> from sympy import symbols >>> R = ReferenceFrame('R') >>> v1, v2, v3 = dynamicsymbols('v1 v2 v3') >>> v = v1*R.x + v2*R.y + v3*R.z >>> get_motion_params(R, position = v) (v1''*R.x + v2''*R.y + v3''*R.z, v1'*R.x + v2'*R.y + v3'*R.z, v1*R.x + v2*R.y + v3*R.z) >>> a, b, c = symbols('a b c') >>> v = a*R.x + b*R.y + c*R.z >>> get_motion_params(R, velocity = v) (0, a*R.x + b*R.y + c*R.z, a*t*R.x + b*t*R.y + c*t*R.z) >>> parameters = get_motion_params(R, acceleration = v) >>> parameters[1] a*t*R.x + b*t*R.y + c*t*R.z >>> parameters[2] a*t**2/2*R.x + b*t**2/2*R.y + c*t**2/2*R.z """ ##Helper functions def _process_vector_differential(vectdiff, condition, \ variable, ordinate, frame): """ Helper function for get_motion methods. Finds derivative of vectdiff wrt variable, and its integral using the specified boundary condition at value of variable = ordinate. Returns a tuple of - (derivative, function and integral) wrt vectdiff """ #Make sure boundary condition is independent of 'variable' if condition != 0: condition = frame.express(condition) #Special case of vectdiff == 0 if vectdiff == Vector(0): return (0, 0, condition) #Express vectdiff completely in condition's frame to give vectdiff1 vectdiff1 = frame.express(vectdiff) #Find derivative of vectdiff vectdiff2 = frame.dt(vectdiff) #Integrate and use boundary condition vectdiff0 = Vector(0) lims = (variable, ordinate, variable) for dim in frame: function1 = vectdiff1.dot(dim) abscissa = dim.dot(condition).subs({variable: ordinate}) # Indefinite integral of 'function1' wrt 'variable', using # the given initial condition (ordinate, abscissa). vectdiff0 += (integrate(function1, lims) + abscissa) * dim #Return tuple return (vectdiff2, vectdiff, vectdiff0) ##Function body _check_frame(frame) #Decide mode of operation based on user's input if 'acceleration' in kwargs: mode = 2 elif 'velocity' in kwargs: mode = 1 else: mode = 0 #All the possible parameters in kwargs #Not all are required for every case #If not specified, set to default values(may or may not be used in #calculations) conditions = [ 'acceleration', 'velocity', 'position', 'timevalue', 'timevalue1', 'timevalue2' ] for i, x in enumerate(conditions): if x not in kwargs: if i < 3: kwargs[x] = Vector(0) else: kwargs[x] = S(0) elif i < 3: _check_vector(kwargs[x]) else: kwargs[x] = sympify(kwargs[x]) if mode == 2: vel = _process_vector_differential(kwargs['acceleration'], kwargs['velocity'], dynamicsymbols._t, kwargs['timevalue2'], frame)[2] pos = _process_vector_differential(vel, kwargs['position'], dynamicsymbols._t, kwargs['timevalue1'], frame)[2] return (kwargs['acceleration'], vel, pos) elif mode == 1: return _process_vector_differential(kwargs['velocity'], kwargs['position'], dynamicsymbols._t, kwargs['timevalue1'], frame) else: vel = frame.dt(kwargs['position']) acc = frame.dt(vel) return (acc, vel, kwargs['position'])
def _eval_rewrite_as_cot(self, arg): return 1 / S.Cot(arg)
def _eval_rewrite_as_cot(self, arg): cot_half = S.Cot(S.Half * arg)**2 return (cot_half - 1) / (cot_half + 1)
def _eval_rewrite_as_cot(self, arg): cot_half = S.Cot(S.Half * arg) return 2 * cot_half / (1 + cot_half**2)
def express(expr, frame, frame2=None, variables=False): """ Global function for 'express' functionality. Re-expresses a Vector, scalar(sympyfiable) or Dyadic in given frame. Refer to the local methods of Vector and Dyadic for details. If 'variables' is True, then the coordinate variables (CoordinateSym instances) of other frames present in the vector/scalar field or dyadic expression are also substituted in terms of the base scalars of this frame. Parameters ========== expr : Vector/Dyadic/scalar(sympyfiable) The expression to re-express in ReferenceFrame 'frame' frame: ReferenceFrame The reference frame to express expr in frame2 : ReferenceFrame The other frame required for re-expression(only for Dyadic expr) variables : boolean Specifies whether to substitute the coordinate variables present in expr, in terms of those of frame Examples ======== >>> from sympy.physics.mechanics import ReferenceFrame, outer, dynamicsymbols >>> N = ReferenceFrame('N') >>> q = dynamicsymbols('q') >>> B = N.orientnew('B', 'Axis', [q, N.z]) >>> d = outer(N.x, N.x) >>> from sympy.physics.mechanics import express >>> express(d, B, N) cos(q)*(B.x|N.x) - sin(q)*(B.y|N.x) >>> express(B.x, N) cos(q)*N.x + sin(q)*N.y >>> express(N[0], B, variables=True) B_x*cos(q(t)) - B_y*sin(q(t)) """ _check_frame(frame) if expr == 0: return S(0) if isinstance(expr, Vector): #Given expr is a Vector if variables: #If variables attribute is True, substitute #the coordinate variables in the Vector frame_list = [x[-1] for x in expr.args] subs_dict = {} for f in frame_list: subs_dict.update(f.variable_map(frame)) expr = expr.subs(subs_dict) #Re-express in this frame outvec = Vector([]) for i, v in enumerate(expr.args): if v[1] != frame: temp = frame.dcm(v[1]) * v[0] if Vector.simp: temp = temp.applyfunc(lambda x: \ trigsimp(x, method='fu')) outvec += Vector([(temp, frame)]) else: outvec += Vector([v]) return outvec if isinstance(expr, Dyadic): if frame2 is None: frame2 = frame _check_frame(frame2) ol = Dyadic(0) for i, v in enumerate(expr.args): ol += express(v[0], frame, variables=variables) * \ (express(v[1], frame, variables=variables) | \ express(v[2], frame2, variables=variables)) return ol else: if variables: #Given expr is a scalar field frame_set = set([]) expr = sympify(expr) #Subsitute all the coordinate variables for x in expr.atoms(): if isinstance(x, CoordinateSym) and x.frame != frame: frame_set.add(x.frame) subs_dict = {} for f in frame_set: subs_dict.update(f.variable_map(frame)) return expr.subs(subs_dict) return expr
def poly_subresultants(f, g, *symbols, **flags): """Computes subresultant PRS of two univariate polynomials. Polynomial remainder sequence (PRS) is a fundamental tool in computer algebra as it gives as a sub-product the polynomial greatest common divisor (GCD), provided that the coefficient domain is an unique factorization domain. There are several methods for computing PRS, eg.: Euclidean PRS, where the most famous algorithm is used, primitive PRS and, finally, subresultants which are implemented here. The Euclidean approach is reasonably efficient but suffers severely from coefficient growth. The primitive algorithm avoids this but requires a lot of coefficient computations. Subresultants solve both problems and so it is efficient and have moderate coefficient growth. The current implementation uses pseudo-divisions which is well suited for coefficients in integral domains or number fields. Formally, given univariate polynomials f and g over an UFD, then a sequence (R_0, R_1, ..., R_k, 0, ...) is a polynomial remainder sequence where R_0 = f, R_1 = g, R_k != 0 and R_k is similar to gcd(f, g). The result is returned as tuple (res, R) where R is the PRS sequence and res is the resultant of the input polynomials. If only polynomial remainder sequence is important, then by setting res=False in keyword arguments expensive computation of the resultant can be avoided (only PRS is returned). For more information on the implemented algorithm refer to: [1] M. Bronstein, Symbolic Integration I: Transcendental Functions, Second Edition, Springer-Verlang, 2005 [2] M. Keber, Division-Free computation of subresultants using Bezout matrices, Tech. Report MPI-I-2006-1-006, Saarbrucken, 2006 """ if not isinstance(f, Poly): f = Poly(f, *symbols) elif symbols: raise SymbolsError("Redundant symbols were given") f, g = f.unify_with(g) if f.is_multivariate: raise MultivariatePolyError(f) else: symbols = f.symbols n, m = f.degree, g.degree if n < m: f, g = g, f n, m = m, n R = [f, g] d = n - m b = S(-1)**(d + 1) c = S(-1) B, D = [b], [d] h = poly_prem(f, g) h = h.mul_term(b) while not h.is_zero: k = h.degree R.append(h) lc = g.LC C = (-lc)**d / c**(d - 1) c = Poly.cancel(C) b = -lc * c**(m - k) f, g, m, d = g, h, k, m - k B.append(b) D.append(d) h = poly_prem(f, g) h = h.div_term(b) if not flags.get('res', True): return R if R[-1].degree > 0: return (Poly((), *symbols), R) if R[-2].is_one: return (R[-1], R) s, c, i = 1, S(1), 1 for b, d in zip(B, D)[:-1]: u = R[i - 1].degree v = R[i].degree w = R[i + 1].degree if u % 2 and v % 2: s = -s lc = R[i].LC C = c * (b / lc**(1 + d))**v * lc**(u - w) c = Poly.cancel(C) i += 1 j = R[-2].degree return (R[-1]**j * s * c, R)
def _eval_rewrite_as_exp(self, arg): neg_exp, pos_exp = S.Exp(-arg), S.Exp(arg) return (pos_exp + neg_exp) / (pos_exp - neg_exp)
def _eval_rewrite_as_exp(self, arg): return (S.Exp(arg) + S.Exp(-arg)) / 2
def roots(f, *symbols, **flags): """Computes symbolic roots of an univariate polynomial. Given an univariate polynomial f with symbolic coefficients, returns a dictionary with its roots and their multiplicities. Only roots expressible via radicals will be returned. To get a complete set of roots use RootOf class or numerical methods instead. By default cubic and quartic formulas are used in the algorithm. To disable them because of unreadable output set cubics=False or quartics=False respectively. To get roots from a specific domain set the 'domain' flag with one of the following specifiers: Z, Q, R, I, C. By default all roots are returned (this is equivalent to setting domain='C'). By default a dictionary is returned giving a compact result in case of multiple roots. However to get a tuple containing all those roots set the 'multiple' flag to True. >>> from sympy import * >>> x,y = symbols('xy') >>> roots(x**2 - 1, x) {1: 1, -1: 1} >>> roots(x**2 - y, x) {y**(1/2): 1, -y**(1/2): 1} """ if not isinstance(f, Poly): f = Poly(f, *symbols) elif symbols: raise SymbolsError("Redundant symbols were given") if f.is_multivariate: raise MultivariatePolyError(f) def _update_dict(result, root, k): if root in result: result[root] += k else: result[root] = k def _try_decompose(f): """Find roots using functional decomposition. """ factors = poly_decompose(f) result, g = {}, factors[0] for i, h in enumerate(poly_sqf(g)): for r in _try_heuristics(h): _update_dict(result, r, i + 1) for factor in factors[1:]: last, result = result.copy(), {} for last_r, i in last.iteritems(): g = factor.sub_term(last_r, (0, )) for j, h in enumerate(poly_sqf(g)): for r in _try_heuristics(h): _update_dict(result, r, i * (j + 1)) return result def _try_heuristics(f): """Find roots using formulas and some tricks. """ if f.length == 1: if f.is_constant: return [] else: return [S(0)] * f.degree if f.length == 2: if f.degree == 1: return roots_linear(f) else: return roots_binomial(f) x, result = f.symbols[0], [] for i in [S(-1), S(1)]: if f(i).expand().is_zero: f = poly_div(f, x - i)[0] result.append(i) break n = f.degree if n == 1: result += roots_linear(f) elif n == 2: result += roots_quadratic(f) elif n == 3 and flags.get('cubics', True): result += roots_cubic(f) elif n == 4 and flags.get('quartics', False): result += roots_quartic(f) return result multiple = flags.get('multiple', False) if f.length == 1: if f.is_constant: if multiple: return [] else: return {} else: result = {S(0): f.degree} else: (k, ), f = f.as_reduced() if k == 0: zeros = {} else: zeros = {S(0): k} result = {} if f.length == 2: if f.degree == 1: result[roots_linear(f)[0]] = 1 else: for r in roots_binomial(f): _update_dict(result, r, 1) elif f.degree == 2: for r in roots_quadratic(f): _update_dict(result, r, 1) else: try: _, factors = poly_factors(f) if len(factors) == 1 and factors[0][1] == 1: raise CoefficientError for factor, k in factors: for r in _try_heuristics(factor): _update_dict(result, r, k) except CoefficientError: result = _try_decompose(f) result.update(zeros) domain = flags.get('domain', None) if domain not in [None, 'C']: handlers = { 'Z': lambda r: r.is_Integer, 'Q': lambda r: r.is_Rational, 'R': lambda r: r.is_real, 'I': lambda r: r.is_imaginary, } try: query = handlers[domain] except KeyError: raise ValueError("Invalid domain: %s" % domain) for zero in dict(result).iterkeys(): if not query(zero): del result[zero] predicate = flags.get('predicate', None) if predicate is not None: for zero in dict(result).iterkeys(): if not predicate(zero): del result[zero] if not multiple: return result else: zeros = [] for zero, k in result.iteritems(): zeros.extend([zero] * k) return zeros