def fourier_cos_seq(func, limits, n): """Returns the cos sequence in a Fourier series""" from sympy.integrals import integrate x, L = limits[0], limits[2] - limits[1] cos_term = cos(2 * n * pi * x / L) formula = 2 * cos_term * integrate(func * cos_term, limits) / L a0 = formula.subs(n, S.Zero) / 2 return a0, SeqFormula( 2 * cos_term * integrate(func * cos_term, limits) / L, (n, 1, oo))
def fourier_cos_seq(func, limits, n): """Returns the cos sequence in a Fourier series""" from sympy.integrals import integrate x, L = limits[0], limits[2] - limits[1] cos_term = cos(2*n*pi*x / L) formula = 2 * cos_term * integrate(func * cos_term, limits) / L a0 = formula.subs(n, S.Zero) / 2 return a0, SeqFormula(2 * cos_term * integrate(func * cos_term, limits) / L, (n, 1, oo))
def fourier_sin_seq(func, limits, n): """Returns the sin sequence in a Fourier series""" from sympy.integrals import integrate x, L = limits[0], limits[2] - limits[1] sin_term = sin(2*n*pi*x / L) return SeqFormula(2 * sin_term * integrate(func * sin_term, limits) / L, (n, 1, oo))
def bending_moment(self): """ Returns a Singularity Function expression which represents the bending moment curve of the Beam object. Examples ======== There is a beam of length 30 meters. A moment of magnitude 120 Nm is applied in the clockwise direction at the end of the beam. A pointload of magnitude 8 N is applied from the top of the beam at the starting point. There are two simple supports below the beam. One at the end and another one at a distance of 10 meters from the start. The deflection is restricted at both the supports. Using the sign convention of upward forces and clockwise moment being positive. >>> from sympy.physics.continuum_mechanics.beam import Beam >>> from sympy import symbols >>> E, I = symbols('E, I') >>> R1, R2 = symbols('R1, R2') >>> b = Beam(30, E, I) >>> b.apply_load(-8, 0, -1) >>> b.apply_load(R1, 10, -1) >>> b.apply_load(R2, 30, -1) >>> b.apply_load(120, 30, -2) >>> b.bc_deflection = [(10, 0), (30, 0)] >>> b.solve_for_reaction_loads(R1, R2) >>> b.bending_moment() -8*SingularityFunction(x, 0, 1) + 6*SingularityFunction(x, 10, 1) + 120*SingularityFunction(x, 30, 0) + 2*SingularityFunction(x, 30, 1) """ x = self.variable return integrate(self.shear_force(), x)
def fourier_sin_seq(func, limits, n): """Returns the sin sequence in a Fourier series""" from sympy.integrals import integrate x, L = limits[0], limits[2] - limits[1] sin_term = sin(2 * n * pi * x / L) return SeqFormula(2 * sin_term * integrate(func * sin_term, limits) / L, (n, 1, oo))
def singularityintegrate(f, x): """ This function handles the indefinite integrations of Singularity functions. The ``integrate`` function calls this function intenally whenever an instance of SingularityFunction is passed as argument. The idea for integration is the following: - If we are dealing with a SingularityFunction expression, i.e. ``SingularityFunction(x, a, n)``, we just return ``SingularityFunction(x, a, n + 1)/(n + 1)`` if ``n >= 0`` and ``SingularityFunction(x, a, n + 1)`` if ``n < 0``. - If the node is a multiplication or power node having a SingularityFunction term we rewrite the whole expression in terms of Heaviside and DiracDelta and then integrate the output. Lastly, we rewrite the output of integration back in terms of SingularityFunction. - If none of the above case arises, we return None. Examples ======== >>> from sympy.integrals.singularityfunctions import singularityintegrate >>> from sympy import SingularityFunction, symbols, Function >>> x, a, n, y = symbols('x a n y') >>> f = Function('f') >>> singularityintegrate(SingularityFunction(x, a, 3), x) SingularityFunction(x, a, 4)/4 >>> singularityintegrate(5*SingularityFunction(x, 5, -2), x) 5*SingularityFunction(x, 5, -1) >>> singularityintegrate(6*SingularityFunction(x, 5, -1), x) 6*SingularityFunction(x, 5, 0) >>> singularityintegrate(x*SingularityFunction(x, 0, -1), x) 0 >>> singularityintegrate(SingularityFunction(x, 1, -1) * f(x), x) f(1)*SingularityFunction(x, 1, 0) """ if not f.has(SingularityFunction): return None if f.func == SingularityFunction: x = sympify(f.args[0]) a = sympify(f.args[1]) n = sympify(f.args[2]) if n.is_positive or n.is_zero: return SingularityFunction(x, a, n + 1)/(n + 1) elif n == -1 or n == -2: return SingularityFunction(x, a, n + 1) if f.is_Mul or f.is_Pow: expr = f.rewrite(DiracDelta) expr = integrate(expr, x) return expr.rewrite(SingularityFunction) return None
def singularityintegrate(f, x): """ This function handles the indefinite integrations of Singularity functions. The ``integrate`` function calls this function internally whenever an instance of SingularityFunction is passed as argument. The idea for integration is the following: - If we are dealing with a SingularityFunction expression, i.e. ``SingularityFunction(x, a, n)``, we just return ``SingularityFunction(x, a, n + 1)/(n + 1)`` if ``n >= 0`` and ``SingularityFunction(x, a, n + 1)`` if ``n < 0``. - If the node is a multiplication or power node having a SingularityFunction term we rewrite the whole expression in terms of Heaviside and DiracDelta and then integrate the output. Lastly, we rewrite the output of integration back in terms of SingularityFunction. - If none of the above case arises, we return None. Examples ======== >>> from sympy.integrals.singularityfunctions import singularityintegrate >>> from sympy import SingularityFunction, symbols, Function >>> x, a, n, y = symbols('x a n y') >>> f = Function('f') >>> singularityintegrate(SingularityFunction(x, a, 3), x) SingularityFunction(x, a, 4)/4 >>> singularityintegrate(5*SingularityFunction(x, 5, -2), x) 5*SingularityFunction(x, 5, -1) >>> singularityintegrate(6*SingularityFunction(x, 5, -1), x) 6*SingularityFunction(x, 5, 0) >>> singularityintegrate(x*SingularityFunction(x, 0, -1), x) 0 >>> singularityintegrate(SingularityFunction(x, 1, -1) * f(x), x) f(1)*SingularityFunction(x, 1, 0) """ if not f.has(SingularityFunction): return None if f.func == SingularityFunction: x = sympify(f.args[0]) a = sympify(f.args[1]) n = sympify(f.args[2]) if n.is_positive or n.is_zero: return SingularityFunction(x, a, n + 1) / (n + 1) elif n == -1 or n == -2: return SingularityFunction(x, a, n + 1) if f.is_Mul or f.is_Power: expr = f.rewrite(DiracDelta) expr = integrate(expr, x) return expr.rewrite(SingularityFunction) return None
def _laplace_transform(f, t, s, simplify=True): """ The backend function for laplace transforms. """ from sympy import (re, Max, exp, pi, Abs, Min, periodic_argument as arg, cos, Wild, symbols) F = integrate(exp(-s * t) * f, (t, 0, oo)) if not F.has(Integral): return _simplify(F, simplify), -oo, True if not F.is_Piecewise: raise IntegralTransformError('Laplace', f, 'could not compute integral') F, cond = F.args[0] if F.has(Integral): raise IntegralTransformError('Laplace', f, 'integral in unexpected form') a = -oo aux = True conds = conjuncts(to_cnf(cond)) u = Dummy('u', real=True) p, q, w1, w2, w3 = symbols('p q w1 w2 w3', cls=Wild, exclude=[s]) for c in conds: a_ = oo aux_ = [] for d in disjuncts(c): m = d.match(abs(arg((s + w3)**p * q, w1)) < w2) if m: if m[q] > 0 and m[w2] / m[p] == pi / 2: d = re(s + m[w3]) > 0 m = d.match(0 < cos(abs(arg(s, q))) * abs(s) - p) if m: d = re(s) > m[p] d_ = d.replace(re, lambda x: x.expand().as_real_imag()[0]).subs( re(s), t) if not d.is_Relational or (d.rel_op != '<' and d.rel_op != '<=') \ or d_.has(s) or not d_.has(t): aux_ += [d] continue soln = _solve_inequality(d_, t) if not soln.is_Relational or \ (soln.rel_op != '<' and soln.rel_op != '<='): aux_ += [d] continue if soln.lhs == t: raise IntegralTransformError('Laplace', f, 'convergence not in half-plane?') else: a_ = Min(soln.lhs, a_) if a_ != oo: a = Max(a_, a) else: aux = And(aux, Or(*aux_)) return _simplify(F, simplify), a, aux
def vector_integrate(field, *region): """ Compute the integral of a vector/scalar field over a a region or a set of parameters. Examples ======== >>> from sympy.vector import CoordSys3D, ParametricRegion, vector_integrate >>> from sympy.abc import t >>> C = CoordSys3D('C') >>> region = ParametricRegion((t, t**2), (t, 1, 5)) >>> vector_integrate(C.x*C.i, region) 12 Integrals over special regions can also be calculated using geometry module. >>> from sympy.geometry import Point, Circle, Triangle >>> c = Circle(Point(0, 2), 5) >>> vector_integrate(C.x**2 + C.y**2, c) 290*pi >>> triangle = Triangle(Point(-2, 3), Point(2, 3), Point(0, 5)) >>> vector_integrate(3*C.x**2*C.y*C.i + C.j, triangle) -8 Integrals over some simple implicit regions can be computed. But in most cases, it takes too long to compute over them. >>> from sympy.abc import x, y >>> from sympy.vector import ImplicitRegion >>> c2 = ImplicitRegion((x, y), (x - 2)**2 + (y - 1)**2 - 9) >>> vector_integrate(1, c2) 12*pi >>> vector_integrate(12*C.y**3, (C.y, 1, 3)) 240 >>> vector_integrate(C.x**2*C.z, C.x) C.x**3*C.z/3 """ if len(region) == 1: if isinstance(region[0], ParametricRegion): return ParametricIntegral(field, region[0]) if isinstance(region[0], ImplicitRegion): region = parametric_region_list(region[0])[0] return vector_integrate(field, region) if isinstance(region[0], GeometryEntity): regions_list = parametric_region_list(region[0]) result = 0 for reg in regions_list: result += vector_integrate(field, reg) return result return integrate(field, *region)
def integrate(self, x=None, **kwargs): """Integrate Formal Power Series. Examples ======== >>> from sympy import fps, sin, integrate >>> from sympy.abc import x >>> f = fps(sin(x)) >>> f.integrate(x).truncate() -1 + x**2/2 - x**4/24 + O(x**6) >>> integrate(f, (x, 0, 1)) -cos(1) + 1 """ from sympy.integrals import integrate if x is None: x = self.x elif iterable(x): return integrate(self.function, x) f = integrate(self.function, x) ind = integrate(self.ind, x) ind += (f - ind).limit(x, 0) # constant of integration pow_xk = self._get_pow_x(self.xk.formula) ak = self.ak k = ak.variables[0] if ak.formula.has(x): form = [] for e, c in ak.formula.args: temp = S.Zero for t in Add.make_args(e): pow_x = self._get_pow_x(t) temp += t / (pow_xk + pow_x + 1) form.append((temp, c)) form = Piecewise(*form) ak = sequence(form.subs(k, k - 1), (k, ak.start + 1, ak.stop)) else: ak = sequence((ak.formula / (pow_xk + 1)).subs(k, k - 1), (k, ak.start + 1, ak.stop)) return self.func(f, self.x, self.x0, self.dir, (ak, self.xk, ind))
def _laplace_transform(f, t, s, simplify=True): """ The backend function for laplace transforms. """ from sympy import (re, Max, exp, pi, Abs, Min, periodic_argument as arg, cos, Wild, symbols) F = integrate(exp(-s*t) * f, (t, 0, oo)) if not F.has(Integral): return _simplify(F, simplify), -oo, True if not F.is_Piecewise: raise IntegralTransformError('Laplace', f, 'could not compute integral') F, cond = F.args[0] if F.has(Integral): raise IntegralTransformError('Laplace', f, 'integral in unexpected form') a = -oo aux = True conds = conjuncts(to_cnf(cond)) u = Dummy('u', real=True) p, q, w1, w2, w3 = symbols('p q w1 w2 w3', cls=Wild, exclude=[s]) for c in conds: a_ = oo aux_ = [] for d in disjuncts(c): m = d.match(abs(arg((s + w3)**p*q, w1)) < w2) if m: if m[q] > 0 and m[w2]/m[p] == pi/2: d = re(s + m[w3]) > 0 m = d.match(0 < cos(abs(arg(s, q)))*abs(s) - p) if m: d = re(s) > m[p] d_ = d.replace(re, lambda x: x.expand().as_real_imag()[0]).subs(re(s), t) if not d.is_Relational or (d.rel_op != '<' and d.rel_op != '<=') \ or d_.has(s) or not d_.has(t): aux_ += [d] continue soln = _solve_inequality(d_, t) if not soln.is_Relational or \ (soln.rel_op != '<' and soln.rel_op != '<='): aux_ += [d] continue if soln.lhs == t: raise IntegralTransformError('Laplace', f, 'convergence not in half-plane?') else: a_ = Min(soln.lhs, a_) if a_ != oo: a = Max(a_, a) else: aux = And(aux, Or(*aux_)) return _simplify(F, simplify), a, aux
def length(self): """The curve length. Examples ======== >>> from sympy.geometry.curve import Curve >>> from sympy.abc import t >>> Curve((t, t), (t, 0, 1)).length sqrt(2) """ integrand = sqrt(sum(diff(func, self.limits[0])**2 for func in self.functions)) return integrate(integrand, self.limits)
def length(self): """The curve length. Examples ======== >>> from sympy.geometry.curve import Curve >>> from sympy import cos, sin >>> from sympy.abc import t >>> Curve((t, t), (t, 0, 1)).length sqrt(2) """ integrand = sqrt(sum(diff(func, self.limits[0])**2 for func in self.functions)) return integrate(integrand, self.limits)
def slope(self): """ Returns a Singularity Function expression which represents the slope the elastic curve of the Beam object. Examples ======== There is a beam of length 30 meters. A moment of magnitude 120 Nm is applied in the clockwise direction at the end of the beam. A pointload of magnitude 8 N is applied from the top of the beam at the starting point. There are two simple supports below the beam. One at the end and another one at a distance of 10 meters from the start. The deflection is restricted at both the supports. Using the sign convention of upward forces and clockwise moment being positive. >>> from sympy.physics.continuum_mechanics.beam import Beam >>> from sympy import symbols >>> E, I = symbols('E, I') >>> R1, R2 = symbols('R1, R2') >>> b = Beam(30, E, I) >>> b.apply_load(-8, 0, -1) >>> b.apply_load(R1, 10, -1) >>> b.apply_load(R2, 30, -1) >>> b.apply_load(120, 30, -2) >>> b.bc_deflection = [(10, 0), (30, 0)] >>> b.solve_for_reaction_loads(R1, R2) >>> b.slope() (-4*SingularityFunction(x, 0, 2) + 3*SingularityFunction(x, 10, 2) + 120*SingularityFunction(x, 30, 1) + SingularityFunction(x, 30, 2) + 4000/3)/(E*I) """ x = self.variable E = self.elastic_modulus I = self.second_moment if not self._boundary_conditions['slope']: return diff(self.deflection(), x) C3 = Symbol('C3') slope_curve = integrate(self.bending_moment(), x) + C3 bc_eqs = [] for position, value in self._boundary_conditions['slope']: eqs = slope_curve.subs(x, position) - value bc_eqs.append(eqs) constants = list(linsolve(bc_eqs, C3)) slope_curve = slope_curve.subs({C3: constants[0][0]}) return S(1) / (E * I) * slope_curve
def slope(self): """ Returns a Singularity Function expression which represents the slope the elastic curve of the Beam object. Examples ======== There is a beam of length 30 meters. A moment of magnitude 120 Nm is applied in the clockwise direction at the end of the beam. A pointload of magnitude 8 N is applied from the top of the beam at the starting point. There are two simple supports below the beam. One at the end and another one at a distance of 10 meters from the start. The deflection is restricted at both the supports. Using the sign convention of upward forces and clockwise moment being positive. >>> from sympy.physics.continuum_mechanics.beam import Beam >>> from sympy import symbols >>> E, I = symbols('E, I') >>> R1, R2 = symbols('R1, R2') >>> b = Beam(30, E, I) >>> b.apply_load(-8, 0, -1) >>> b.apply_load(R1, 10, -1) >>> b.apply_load(R2, 30, -1) >>> b.apply_load(120, 30, -2) >>> b.bc_deflection = [(10, 0), (30, 0)] >>> b.solve_for_reaction_loads(R1, R2) >>> b.slope() (-4*SingularityFunction(x, 0, 2) + 3*SingularityFunction(x, 10, 2) + 120*SingularityFunction(x, 30, 1) + SingularityFunction(x, 30, 2) + 4000/3)/(E*I) """ x = self.variable E = self.elastic_modulus I = self.second_moment if not self._boundary_conditions['slope']: return diff(self.deflection(), x) C3 = Symbol('C3') slope_curve = integrate(self.bending_moment(), x) + C3 bc_eqs = [] for position, value in self._boundary_conditions['slope']: eqs = slope_curve.subs(x, position) - value bc_eqs.append(eqs) constants = list(linsolve(bc_eqs, C3)) slope_curve = slope_curve.subs({C3: constants[0][0]}) return S(1)/(E*I)*slope_curve
def vector_integrate(field, *region): """ Compute the integral of a vector/scalar field over a a region or a set of parameters. Examples: ========= >>> from sympy.vector import CoordSys3D, ParametricRegion, vector_integrate >>> from sympy.abc import t >>> C = CoordSys3D('C') >>> region = ParametricRegion((t, t**2), (t, 1, 5)) >>> vector_integrate(C.x*C.i, region) 12 Integrals over special regions can also be calculated using geometry module. >>> from sympy.geometry import Point, Circle, Triangle >>> c = Circle(Point(0, 2), 5) >>> vector_integrate(C.x**2 + C.y**2, c) 290*pi >>> triangle = Triangle(Point(-2, 3), Point(2, 3), Point(0, 5)) >>> vector_integrate(3*C.x**2*C.y*C.i + C.j, triangle) -8 >>> vector_integrate(12*C.y**3, (C.y, 1, 3)) 240 >>> vector_integrate(C.x**2*C.z, C.x) C.x**3*C.z/3 """ if len(region) == 1: if isinstance(region[0], ParametricRegion): return ParametricIntegral(field, region[0]) if isinstance(region[0], GeometryEntity): regions_list = parametric_region_list(region[0]) result = 0 for reg in regions_list: result += vector_integrate(field, reg) return result return integrate(field, *region)
def vector_integrate(field, *region): """ Compute the integral of a vector/scalar field over a a region or a set of parameters. Examples: ========= >>> from sympy.vector import CoordSys3D, ParametricRegion, vector_integrate >>> from sympy.abc import t >>> C = CoordSys3D('C') >>> region = ParametricRegion((t, t**2), (t, 1, 5)) >>> vector_integrate(C.x*C.i, region) 12 >>> vector_integrate(C.x**2*C.z, C.x) C.x**3*C.z/3 """ if len(region) == 1: if isinstance(region[0], ParametricRegion): return ParametricIntegral(field, region[0]) return integrate(field, *region)
def test_trim(): f = Function("f") assert trim((f(x) ** 2 + f(x)) / f(x)) == 1 + f(x) assert trim((sin(x) ** 2 + sin(x)) / sin(x)) == 1 + sin(x) assert trim((f(x) + y * f(x)) / f(x)) == 1 + y expr = integrate(1 / (x ** 3 + 1), x) assert trim(together(expr.diff(x))) == 1 / (x ** 3 + 1) assert cancel(together(expr.diff(x))) == 1 / (x ** 3 + 1) expr = together(expr.subs(x, sin(x)).diff(x)) assert trim(expr) == cos(x) / (1 + sin(x) ** 3) assert trim((2 * (1 / n - cos(n * pi) / n)) / pi) == 1 / pi / n * (2 - 2 * cos(pi * n)) assert trim(sin((f(x) ** 2 + f(x)) / f(x))) == sin(1 + f(x)) assert trim(exp(x) * sin(x) / 2 + cos(x) * exp(x)) == exp(x) * (sin(x) + 2 * cos(x)) / 2
def _fourier_transform(f, x, k, a, b, name, simplify=True): """ Compute a general fourier-type transform F(k) = a int_-oo^oo exp(b*I*x*k) f(x) dx. For suitable choice of a and b, this reduces to the standard fourier and inverse fourier transforms. """ from sympy import exp, I, oo F = integrate(a*f*exp(b*I*x*k), (x, -oo, oo)) if not F.has(Integral): return _simplify(F, simplify), True if not F.is_Piecewise: raise IntegralTransformError(name, f, 'could not compute integral') F, cond = F.args[0] if F.has(Integral): raise IntegralTransformError(name, f, 'integral in unexpected form') return _simplify(F, simplify), cond
def _fourier_transform(f, x, k, a, b, name, simplify=True): """ Compute a general fourier-type transform F(k) = a int_-oo^oo exp(b*I*x*k) f(x) dx. For suitable choice of a and b, this reduces to the standard fourier and inverse fourier transforms. """ from sympy import exp, I, oo F = integrate(a * f * exp(b * I * x * k), (x, -oo, oo)) if not F.has(Integral): return _simplify(F, simplify), True if not F.is_Piecewise: raise IntegralTransformError(name, f, 'could not compute integral') F, cond = F.args[0] if F.has(Integral): raise IntegralTransformError(name, f, 'integral in unexpected form') return _simplify(F, simplify), cond
def piecewise_integrate(self, x, **kwargs): """Return the Piecewise with each expression being replaced with its antiderivative. To obtain a continuous antiderivative, use the `integrate` function or method. Examples ======== >>> from sympy import Piecewise >>> from sympy.abc import x >>> p = Piecewise((0, x < 0), (1, x < 1), (2, True)) >>> p.piecewise_integrate(x) Piecewise((0, x < 0), (x, x < 1), (2*x, True)) Note that this does not give a continuous function, e.g. at x = 1 the 3rd condition applies and the antiderivative there is 2*x so the value of the antiderivative is 2: >>> anti = _ >>> anti.subs(x, 1) 2 The continuous derivative accounts for the integral *up to* the point of interest, however: >>> p.integrate(x) Piecewise((0, x < 0), (x, x < 1), (2*x - 1, True)) >>> _.subs(x, 1) 1 See Also ======== Piecewise._eval_integral """ from sympy.integrals import integrate return self.func(*[(integrate(e, x, **kwargs), c) for e, c in self.args])
def test_trim(): f = Function('f') assert trim((f(x)**2 + f(x)) / f(x)) == 1 + f(x) assert trim((sin(x)**2 + sin(x)) / sin(x)) == 1 + sin(x) assert trim((f(x) + y * f(x)) / f(x)) == 1 + y expr = integrate(1 / (x**3 + 1), x) assert trim(together(expr.diff(x))) == 1 / (x**3 + 1) assert cancel(together(expr.diff(x))) == 1 / (x**3 + 1) expr = together(expr.subs(x, sin(x)).diff(x)) assert trim(expr) == cos(x) / (1 + sin(x)**3) assert trim((2 * (1/n - cos(n * pi)/n))/pi) == \ 1/pi/n*(2 - 2*cos(pi*n)) assert trim(sin((f(x)**2 + f(x)) / f(x))) == sin(1 + f(x)) assert trim(exp(x)*sin(x)/2 + cos(x)*exp(x)) == \ exp(x)*(sin(x) + 2*cos(x))/2
# DEFINE LA FUNCION PARA EL CALCULO DE LA INTEGRAL # LA MISMA FUNCIÓN QUE DIJITASTE ANTERIORMENTE fun = x**2 - x + 2 # Limites de integración Lim_inf = -1 Lim_sup = 1 ############################################## P = Obtener_Periodo(Lim_inf, Lim_sup) # Calculamos la constante a0 a0 = integrate(fun, (x, -P, P)) / P #Definimos las funciones de las integrales y hallamos los coeficientes Coef_a = [] Coef_b = [] for ni in range(n): ni = ni + 1 Coef_ai = integrate(fun * (cos((ni * pi / P) * x)), (x, -P, P)) / P Coef_bi = integrate(fun * (sin((ni * pi / P) * x)), (x, -P, P)) / P Coef_a.append(Coef_ai) Coef_b.append(Coef_bi) #Generamos los arreglos para las graficas x = np.linspace(Lim_inf, Lim_sup, 100) y = np.zeros(100) + a0 / 2 yi = []
def deltaintegrate(f, x): """ deltaintegrate(f, x) The idea for integration is the following: - If we are dealing with a DiracDelta expression, i.e. DiracDelta(g(x)), we try to simplify it. If we could simplify it, then we integrate the resulting expression. We already know we can integrate a simplified expression, because only simple DiracDelta expressions are involved. If we couldn't simplify it, there are two cases: 1) The expression is a simple expression: we return the integral, taking care if we are dealing with a Derivative or with a proper DiracDelta. 2) The expression is not simple (i.e. DiracDelta(cos(x))): we can do nothing at all. - If the node is a multiplication node having a DiracDelta term: First we expand it. If the expansion did work, then we try to integrate the expansion. If not, we try to extract a simple DiracDelta term, then we have two cases: 1) We have a simple DiracDelta term, so we return the integral. 2) We didn't have a simple term, but we do have an expression with simplified DiracDelta terms, so we integrate this expression. Examples ======== >>> from sympy.abc import x, y, z >>> from sympy.integrals.deltafunctions import deltaintegrate >>> from sympy import sin, cos, DiracDelta, Heaviside >>> deltaintegrate(x*sin(x)*cos(x)*DiracDelta(x - 1), x) sin(1)*cos(1)*Heaviside(x - 1) >>> deltaintegrate(y**2*DiracDelta(x - z)*DiracDelta(y - z), y) z**2*DiracDelta(x - z)*Heaviside(y - z) See Also ======== sympy.functions.special.delta_functions.DiracDelta sympy.integrals.integrals.Integral """ if not f.has(DiracDelta): return None from sympy.integrals import Integral, integrate from sympy.solvers import solve # g(x) = DiracDelta(h(x)) if f.func == DiracDelta: h = f.simplify(x) if h == f: # can't simplify the expression #FIXME: the second term tells whether is DeltaDirac or Derivative #For integrating derivatives of DiracDelta we need the chain rule if f.is_simple(x): if (len(f.args) <= 1 or f.args[1] == 0): return Heaviside(f.args[0]) else: return (DiracDelta(f.args[0], f.args[1] - 1) / f.args[0].as_poly().LC()) else: # let's try to integrate the simplified expression fh = integrate(h, x) return fh elif f.is_Mul or f.is_Pow: # g(x) = a*b*c*f(DiracDelta(h(x)))*d*e g = f.expand() if f != g: # the expansion worked fh = integrate(g, x) if fh is not None and not isinstance(fh, Integral): return fh else: # no expansion performed, try to extract a simple DiracDelta term dg, rest_mult = change_mul(f, x) if not dg: if rest_mult: fh = integrate(rest_mult, x) return fh else: dg = dg.simplify(x) if dg.is_Mul: # Take out any extracted factors dg, rest_mult_2 = change_mul(dg, x) rest_mult = rest_mult*rest_mult_2 point = solve(dg.args[0], x)[0] return (rest_mult.subs(x, point)*Heaviside(x - point)) return None
def deltaintegrate(f, x): """ deltaintegrate(f, x) The idea for integration is the following: - If we are dealing with a DiracDelta expression, i.e. DiracDelta(g(x)), we try to simplify it. If we could simplify it, then we integrate the resulting expression. We already know we can integrate a simplified expression, because only simple DiracDelta expressions are involved. If we couldn't simplify it, there are two cases: 1) The expression is a simple expression: we return the integral, taking care if we are dealing with a Derivative or with a proper DiracDelta. 2) The expression is not simple (i.e. DiracDelta(cos(x))): we can do nothing at all. - If the node is a multiplication node having a DiracDelta term: First we expand it. If the expansion did work, then we try to integrate the expansion. If not, we try to extract a simple DiracDelta term, then we have two cases: 1) We have a simple DiracDelta term, so we return the integral. 2) We didn't have a simple term, but we do have an expression with simplified DiracDelta terms, so we integrate this expression. Examples ======== >>> from sympy.abc import x, y, z >>> from sympy.integrals.deltafunctions import deltaintegrate >>> from sympy import sin, cos, DiracDelta, Heaviside >>> deltaintegrate(x*sin(x)*cos(x)*DiracDelta(x - 1), x) sin(1)*cos(1)*Heaviside(x - 1) >>> deltaintegrate(y**2*DiracDelta(x - z)*DiracDelta(y - z), y) z**2*DiracDelta(x - z)*Heaviside(y - z) See Also ======== sympy.functions.special.delta_functions.DiracDelta sympy.integrals.integrals.Integral """ if not f.has(DiracDelta): return None from sympy.integrals import Integral, integrate from sympy.solvers import solve # g(x) = DiracDelta(h(x)) if f.func == DiracDelta: h = f.expand(diracdelta=True, wrt=x) if h == f: # can't simplify the expression # FIXME: the second term tells whether is DeltaDirac or Derivative # For integrating derivatives of DiracDelta we need the chain rule if f.is_simple(x): if len(f.args) <= 1 or f.args[1] == 0: return Heaviside(f.args[0]) else: return DiracDelta(f.args[0], f.args[1] - 1) / f.args[0].as_poly().LC() else: # let's try to integrate the simplified expression fh = integrate(h, x) return fh elif f.is_Mul or f.is_Pow: # g(x) = a*b*c*f(DiracDelta(h(x)))*d*e g = f.expand() if f != g: # the expansion worked fh = integrate(g, x) if fh is not None and not isinstance(fh, Integral): return fh else: # no expansion performed, try to extract a simple DiracDelta term deltaterm, rest_mult = change_mul(f, x) if not deltaterm: if rest_mult: fh = integrate(rest_mult, x) return fh else: deltaterm = deltaterm.expand(diracdelta=True, wrt=x) if deltaterm.is_Mul: # Take out any extracted factors deltaterm, rest_mult_2 = change_mul(deltaterm, x) rest_mult = rest_mult * rest_mult_2 point = solve(deltaterm.args[0], x)[0] # Return the largest hyperreal term left after # repeated integration by parts. For example, # # integrate(y*DiracDelta(x, 1),x) == y*DiracDelta(x,0), not 0 # # This is so Integral(y*DiracDelta(x).diff(x),x).doit() # will return y*DiracDelta(x) instead of 0 or DiracDelta(x), # both of which are correct everywhere the value is defined # but give wrong answers for nested integration. n = 0 if len(deltaterm.args) == 1 else deltaterm.args[1] m = 0 while n >= 0: r = (-1) ** n * rest_mult.diff(x, n).subs(x, point) if r is S.Zero: n -= 1 m += 1 else: if m == 0: return r * Heaviside(x - point) else: return r * DiracDelta(x, m - 1) # In some very weak sense, x=0 is still a singularity, # but we hope will not be of any practial consequence. return S.Zero return None
def __new__(cls, field, parametricregion): coord_set = _get_coord_sys_from_expr(field) if len(coord_set) == 0: coord_sys = CoordSys3D('C') elif len(coord_set) > 1: raise ValueError else: coord_sys = next(iter(coord_set)) if parametricregion.dimensions == 0: return super().__new__(cls, field, parametricregion) base_vectors = coord_sys.base_vectors() base_scalars = coord_sys.base_scalars() parametricfield = field r = Vector.zero for i in range(len(parametricregion.definition)): r += base_vectors[i] * parametricregion.definition[i] if len(coord_set) != 0: for i in range(len(parametricregion.definition)): parametricfield = parametricfield.subs( base_scalars[i], parametricregion.definition[i]) if parametricregion.dimensions == 1: parameter = parametricregion.parameters[0] r_diff = diff(r, parameter) lower, upper = parametricregion.limits[parameter][ 0], parametricregion.limits[parameter][1] if isinstance(parametricfield, Vector): integrand = simplify(r_diff.dot(parametricfield)) else: integrand = simplify(r_diff.magnitude() * parametricfield) result = integrate(integrand, (parameter, lower, upper)) elif parametricregion.dimensions == 2: u, v = cls._bounds_case(parametricregion.limits) r_u = diff(r, u) r_v = diff(r, v) normal_vector = simplify(r_u.cross(r_v)) if isinstance(parametricfield, Vector): integrand = parametricfield.dot(normal_vector) else: integrand = parametricfield * normal_vector.magnitude() integrand = simplify(integrand) lower_u, upper_u = parametricregion.limits[u][ 0], parametricregion.limits[u][1] lower_v, upper_v = parametricregion.limits[v][ 0], parametricregion.limits[v][1] result = integrate(integrand, (u, lower_u, upper_u), (v, lower_v, upper_v)) else: variables = cls._bounds_case(parametricregion.limits) coeff = Matrix( parametricregion.definition).jacobian(variables).det() integrand = simplify(parametricfield * coeff) l = [(var, parametricregion.limits[var][0], parametricregion.limits[var][1]) for var in variables] result = integrate(integrand, *l) if not isinstance(result, Integral): return result else: return super().__new__(cls, field, parametricregion)
def _laplace_transform(f, t, s_, simplify=True): """ The backend function for laplace transforms. """ from sympy import (re, Max, exp, pi, Abs, Min, periodic_argument as arg, cos, Wild, symbols, polar_lift) s = Dummy('s') F = integrate(exp(-s * t) * f, (t, 0, oo)) if not F.has(Integral): return _simplify(F.subs(s, s_), simplify), -oo, True if not F.is_Piecewise: raise IntegralTransformError('Laplace', f, 'could not compute integral') F, cond = F.args[0] if F.has(Integral): raise IntegralTransformError('Laplace', f, 'integral in unexpected form') def process_conds(conds): """ Turn ``conds`` into a strip and auxiliary conditions. """ a = -oo aux = True conds = conjuncts(to_cnf(conds)) u = Dummy('u', real=True) p, q, w1, w2, w3, w4, w5 = symbols('p q w1 w2 w3 w4 w5', cls=Wild, exclude=[s]) for c in conds: a_ = oo aux_ = [] for d in disjuncts(c): m = d.match(abs(arg((s + w3)**p * q, w1)) < w2) if not m: m = d.match(abs(arg((s + w3)**p * q, w1)) <= w2) if not m: m = d.match(abs(arg((polar_lift(s + w3))**p * q, w1)) < w2) if not m: m = d.match( abs(arg((polar_lift(s + w3))**p * q, w1)) <= w2) if m: if m[q] > 0 and m[w2] / m[p] == pi / 2: d = re(s + m[w3]) > 0 m = d.match( 0 < cos(abs(arg(s**w1 * w5, q)) * w2) * abs(s**w3)**w4 - p) if not m: m = d.match( 0 < cos(abs(arg(polar_lift(s)**w1 * w5, q)) * w2) * abs(s**w3)**w4 - p) if m and all(m[wild] > 0 for wild in [w1, w2, w3, w4, w5]): d = re(s) > m[p] d_ = d.replace(re, lambda x: x.expand().as_real_imag()[0]).subs( re(s), t) if not d.is_Relational or (d.rel_op != '<' and d.rel_op != '<=') \ or d_.has(s) or not d_.has(t): aux_ += [d] continue soln = _solve_inequality(d_, t) if not soln.is_Relational or \ (soln.rel_op != '<' and soln.rel_op != '<='): aux_ += [d] continue if soln.lhs == t: raise IntegralTransformError( 'Laplace', f, 'convergence not in half-plane?') else: a_ = Min(soln.lhs, a_) if a_ != oo: a = Max(a_, a) else: aux = And(aux, Or(*aux_)) return a, aux conds = [process_conds(c) for c in disjuncts(cond)] conds = filter(lambda x: x[1] is not False and x[0] != -oo, conds) def cnt(expr): if isinstance(expr, bool): return 0 return expr.count_ops() conds.sort(key=lambda x: (-x[0], cnt(x[1]))) if not conds: raise IntegralTransformError('Laplace', f, 'no convergence found') a, aux = conds[0] def sbs(expr): if isinstance(expr, bool): return expr return expr.subs(s, s_) if simplify: F = _simplifyconds(F, s, a) aux = _simplifyconds(aux, s, a) return _simplify(F.subs(s, s_), simplify), sbs(a), sbs(aux)
def _rsolve_hypergeometric(f, x, P, Q, k, m): """Recursive wrapper to rsolve_hypergeometric. Returns a Tuple of (formula, series independent terms, maximum power of x in independent terms) if successful otherwise ``None``. See :func:`rsolve_hypergeometric` for details. """ from sympy.polys import lcm, roots from sympy.integrals import integrate # tranformation - c proots, qroots = roots(P, k), roots(Q, k) all_roots = dict(proots) all_roots.update(qroots) scale = lcm([r.as_numer_denom()[1] for r, t in all_roots.items() if r.is_rational]) f, P, Q, m = _transformation_c(f, x, P, Q, k, m, scale) # transformation - a qroots = roots(Q, k) if qroots: k_min = Min(*qroots.keys()) else: k_min = S.Zero shift = k_min + m f, P, Q, m = _transformation_a(f, x, P, Q, k, m, shift) l = (x*f).limit(x, 0) if not isinstance(l, Limit) and l != 0: # Ideally should only be l != 0 return None qroots = roots(Q, k) if qroots: k_max = Max(*qroots.keys()) else: k_max = S.Zero ind, mp = S.Zero, -oo for i in range(k_max + m + 1): r = f.diff(x, i).limit(x, 0) / factorial(i) if r.is_finite is False: old_f = f f, P, Q, m = _transformation_a(f, x, P, Q, k, m, i) f, P, Q, m = _transformation_e(f, x, P, Q, k, m) sol, ind, mp = _rsolve_hypergeometric(f, x, P, Q, k, m) sol = _apply_integrate(sol, x, k) sol = _apply_shift(sol, i) ind = integrate(ind, x) ind += (old_f - ind).limit(x, 0) # constant of integration mp += 1 return sol, ind, mp elif r: ind += r*x**(i + shift) pow_x = Rational((i + shift), scale) if pow_x > mp: mp = pow_x # maximum power of x ind = ind.subs(x, x**(1/scale)) sol = _compute_formula(f, x, P, Q, k, m, k_max) sol = _apply_shift(sol, shift) sol = _apply_scale(sol, scale) return sol, ind, mp
def vector_integrate(field, *region): """ Compute the integral of a vector/scalar field over a a region or a set of parameters. Examples ======== >>> from sympy.vector import CoordSys3D, ParametricRegion, vector_integrate >>> from sympy.abc import x, y, t >>> C = CoordSys3D('C') >>> region = ParametricRegion((t, t**2), (t, 1, 5)) >>> vector_integrate(C.x*C.i, region) 12 Integrals over some objects of geometry module can also be calculated. >>> from sympy.geometry import Point, Circle, Triangle >>> c = Circle(Point(0, 2), 5) >>> vector_integrate(C.x**2 + C.y**2, c) 290*pi >>> triangle = Triangle(Point(-2, 3), Point(2, 3), Point(0, 5)) >>> vector_integrate(3*C.x**2*C.y*C.i + C.j, triangle) -8 Integrals over some simple implicit regions can be computed. But in most cases, it takes too long to compute over them. This is due to the expressions of parametric representation becoming large. >>> from sympy.vector import ImplicitRegion >>> c2 = ImplicitRegion((x, y), (x - 2)**2 + (y - 1)**2 - 9) >>> vector_integrate(1, c2) 6*pi Integral of fields with respect to base scalars: >>> vector_integrate(12*C.y**3, (C.y, 1, 3)) 240 >>> vector_integrate(C.x**2*C.z, C.x) C.x**3*C.z/3 >>> vector_integrate(C.x*C.i - C.y*C.k, C.x) (Integral(C.x, C.x))*C.i + (Integral(-C.y, C.x))*C.k >>> _.doit() C.x**2/2*C.i + (-C.x*C.y)*C.k """ if len(region) == 1: if isinstance(region[0], ParametricRegion): return ParametricIntegral(field, region[0]) if isinstance(region[0], ImplicitRegion): region = parametric_region_list(region[0])[0] return vector_integrate(field, region) if isinstance(region[0], GeometryEntity): regions_list = parametric_region_list(region[0]) result = 0 for reg in regions_list: result += vector_integrate(field, reg) return result return integrate(field, *region)
def _laplace_transform(f, t, s_, simplify=True): """ The backend function for laplace transforms. """ from sympy import (re, Max, exp, pi, Abs, Min, periodic_argument as arg, cos, Wild, symbols, polar_lift) s = Dummy('s') F = integrate(exp(-s*t) * f, (t, 0, oo)) if not F.has(Integral): return _simplify(F.subs(s, s_), simplify), -oo, True if not F.is_Piecewise: raise IntegralTransformError('Laplace', f, 'could not compute integral') F, cond = F.args[0] if F.has(Integral): raise IntegralTransformError('Laplace', f, 'integral in unexpected form') def process_conds(conds): """ Turn ``conds`` into a strip and auxiliary conditions. """ a = -oo aux = True conds = conjuncts(to_cnf(conds)) u = Dummy('u', real=True) p, q, w1, w2, w3, w4, w5 = symbols('p q w1 w2 w3 w4 w5', cls=Wild, exclude=[s]) for c in conds: a_ = oo aux_ = [] for d in disjuncts(c): m = d.match(abs(arg((s + w3)**p*q, w1)) < w2) if not m: m = d.match(abs(arg((s + w3)**p*q, w1)) <= w2) if not m: m = d.match(abs(arg((polar_lift(s + w3))**p*q, w1)) < w2) if not m: m = d.match(abs(arg((polar_lift(s + w3))**p*q, w1)) <= w2) if m: if m[q] > 0 and m[w2]/m[p] == pi/2: d = re(s + m[w3]) > 0 m = d.match(0 < cos(abs(arg(s**w1*w5, q))*w2)*abs(s**w3)**w4 - p) if not m: m = d.match(0 < cos(abs(arg(polar_lift(s)**w1*w5, q))*w2)*abs(s**w3)**w4 - p) if m and all(m[wild] > 0 for wild in [w1, w2, w3, w4, w5]): d = re(s) > m[p] d_ = d.replace(re, lambda x: x.expand().as_real_imag()[0]).subs(re(s), t) if not d.is_Relational or (d.rel_op != '<' and d.rel_op != '<=') \ or d_.has(s) or not d_.has(t): aux_ += [d] continue soln = _solve_inequality(d_, t) if not soln.is_Relational or \ (soln.rel_op != '<' and soln.rel_op != '<='): aux_ += [d] continue if soln.lhs == t: raise IntegralTransformError('Laplace', f, 'convergence not in half-plane?') else: a_ = Min(soln.lhs, a_) if a_ != oo: a = Max(a_, a) else: aux = And(aux, Or(*aux_)) return a, aux conds = [process_conds(c) for c in disjuncts(cond)] conds = filter(lambda x: x[1] is not False and x[0] != -oo, conds) def cnt(expr): if isinstance(expr, bool): return 0 return expr.count_ops() conds.sort(key=lambda x: (-x[0], cnt(x[1]))) if not conds: raise IntegralTransformError('Laplace', f, 'no convergence found') a, aux = conds[0] def sbs(expr): if isinstance(expr, bool): return expr return expr.subs(s, s_) if simplify: F = _simplifyconds(F, s, a) aux = _simplifyconds(aux, s, a) return _simplify(F.subs(s, s_), simplify), sbs(a), sbs(aux)
def _default_integrator(f, x): return integrate(f, (x, 0, oo))
def _eval_integral(self, x, _first=True, **kwargs): """Return the indefinite integral of the Piecewise such that subsequent substitution of x with a value will give the value of the integral (not including the constant of integration) up to that point. To only integrate the individual parts of Piecewise, use the `piecewise_integrate` method. Examples ======== >>> from sympy import Piecewise >>> from sympy.abc import x >>> p = Piecewise((0, x < 0), (1, x < 1), (2, True)) >>> p.integrate(x) Piecewise((0, x < 0), (x, x < 1), (2*x - 1, True)) >>> p.piecewise_integrate(x) Piecewise((0, x < 0), (x, x < 1), (2*x, True)) See Also ======== Piecewise.piecewise_integrate """ from sympy.integrals.integrals import integrate if _first: def handler(ipw): if isinstance(ipw, self.func): return ipw._eval_integral(x, _first=False, **kwargs) else: return ipw.integrate(x, **kwargs) irv = self._handle_irel(x, handler) if irv is not None: return irv # handle a Piecewise from -oo to oo with and no x-independent relationals # ----------------------------------------------------------------------- try: abei = self._intervals(x) except NotImplementedError: from sympy import Integral return Integral(self, x) # unevaluated pieces = [(a, b) for a, b, _, _ in abei] oo = S.Infinity done = [(-oo, oo, -1)] for k, p in enumerate(pieces): if p == (-oo, oo): # all undone intervals will get this key for j, (a, b, i) in enumerate(done): if i == -1: done[j] = a, b, k break # nothing else to consider N = len(done) - 1 for j, (a, b, i) in enumerate(reversed(done)): if i == -1: j = N - j done[j: j + 1] = _clip(p, (a, b), k) done = [(a, b, i) for a, b, i in done if a != b] # append an arg if there is a hole so a reference to # argument -1 will give Undefined if any(i == -1 for (a, b, i) in done): abei.append((-oo, oo, Undefined, -1)) # return the sum of the intervals args = [] sum = None for a, b, i in done: anti = integrate(abei[i][-2], x, **kwargs) if sum is None: sum = anti else: sum = sum.subs(x, a) if sum == Undefined: sum = 0 sum += anti._eval_interval(x, a, x) # see if we know whether b is contained in original # condition if b is S.Infinity: cond = True elif self.args[abei[i][-1]].cond.subs(x, b) == False: cond = (x < b) else: cond = (x <= b) args.append((sum, cond)) return Piecewise(*args)
def integrate(self, *args, **kwargs): from sympy.integrals import integrate return integrate(self, *args, **kwargs)
def rational_algorithm(f, x, k, order=4, full=False): """Rational algorithm for computing formula of coefficients of Formal Power Series of a function. Applicable when f(x) or some derivative of f(x) is a rational function in x. :func:`rational_algorithm` uses :func:`apart` function for partial fraction decomposition. :func:`apart` by default uses 'undetermined coefficients method'. By setting ``full=True``, 'Bronstein's algorithm' can be used instead. Looks for derivative of a function up to 4'th order (by default). This can be overridden using order option. Returns ======= formula : Expr ind : Expr Independent terms. order : int Examples ======== >>> from sympy import log, atan, I >>> from sympy.series.formal import rational_algorithm as ra >>> from sympy.abc import x, k >>> ra(1 / (1 - x), x, k) (1, 0, 0) >>> ra(log(1 + x), x, k) (-(-1)**(-k)/k, 0, 1) >>> ra(atan(x), x, k, full=True) ((-I*(-I)**(-k)/2 + I*I**(-k)/2)/k, 0, 1) Notes ===== By setting ``full=True``, range of admissible functions to be solved using ``rational_algorithm`` can be increased. This option should be used carefully as it can significantly slow down the computation as ``doit`` is performed on the :class:`RootSum` object returned by the ``apart`` function. Use ``full=False`` whenever possible. See Also ======== sympy.polys.partfrac.apart References ========== .. [1] Formal Power Series - Dominik Gruntz, Wolfram Koepf .. [2] Power Series in Computer Algebra - Wolfram Koepf """ from sympy.polys import RootSum, apart from sympy.integrals import integrate diff = f ds = [] # list of diff for i in range(order + 1): if i: diff = diff.diff(x) if diff.is_rational_function(x): coeff, sep = S.Zero, S.Zero terms = apart(diff, x, full=full) if terms.has(RootSum): terms = terms.doit() for t in Add.make_args(terms): num, den = t.as_numer_denom() if not den.has(x): sep += t else: if isinstance(den, Mul): # m*(n*x - a)**j -> (n*x - a)**j ind = den.as_independent(x) den = ind[1] num /= ind[0] # (n*x - a)**j -> (x - b) den, j = den.as_base_exp() a, xterm = den.as_coeff_add(x) # term -> m/x**n if not a: sep += t continue xc = xterm[0].coeff(x) a /= -xc num /= xc**j ak = ((-1)**j * num * binomial(j + k - 1, k).rewrite(factorial) / a**(j + k)) coeff += ak # Hacky, better way? if coeff is S.Zero: return None if (coeff.has(x) or coeff.has(zoo) or coeff.has(oo) or coeff.has(nan)): return None for j in range(i): coeff = (coeff / (k + j + 1)) sep = integrate(sep, x) sep += (ds.pop() - sep).limit(x, 0) # constant of integration return (coeff.subs(k, k - i), sep, i) else: ds.append(diff) return None
def deflection(self): """ Returns a Singularity Function expression which represents the elastic curve or deflection of the Beam object. Examples ======== There is a beam of length 30 meters. A moment of magnitude 120 Nm is applied in the clockwise direction at the end of the beam. A pointload of magnitude 8 N is applied from the top of the beam at the starting point. There are two simple supports below the beam. One at the end and another one at a distance of 10 meters from the start. The deflection is restricted at both the supports. Using the sign convention of upward forces and clockwise moment being positive. >>> from sympy.physics.continuum_mechanics.beam import Beam >>> from sympy import symbols >>> E, I = symbols('E, I') >>> R1, R2 = symbols('R1, R2') >>> b = Beam(30, E, I) >>> b.apply_load(-8, 0, -1) >>> b.apply_load(R1, 10, -1) >>> b.apply_load(R2, 30, -1) >>> b.apply_load(120, 30, -2) >>> b.bc_deflection = [(10, 0), (30, 0)] >>> b.solve_for_reaction_loads(R1, R2) >>> b.deflection() (4000*x/3 - 4*SingularityFunction(x, 0, 3)/3 + SingularityFunction(x, 10, 3) + 60*SingularityFunction(x, 30, 2) + SingularityFunction(x, 30, 3)/3 - 12000)/(E*I) """ x = self.variable E = self.elastic_modulus I = self.second_moment if self._composite_type == "hinge": return self._hinge_beam_deflection if not self._boundary_conditions['deflection'] and not self._boundary_conditions['slope']: if self._composite_type == "fixed": args = I.args conditions = [] prev_def = 0 prev_end = 0 for i in range(len(args)): if i != 0: prev_end = args[i-1][1].args[1] deflection_value = integrate(self.slope().args[i][0], (x, prev_end, x)) conditions.append(((prev_def + deflection_value), args[i][1])) prev_def = deflection_value.subs(x, args[i][1].args[1]) return Piecewise(*conditions) return S(1)/(E*I)*integrate(integrate(self.bending_moment(), x), x) elif not self._boundary_conditions['deflection']: return integrate(self.slope(), x) elif not self._boundary_conditions['slope'] and self._boundary_conditions['deflection']: if self._composite_type == "fixed": args = I.args conditions = [] prev_def = 0 prev_end = 0 for i in range(len(args)): if i != 0: prev_end = args[i-1][1].args[1] deflection_value = integrate(self.slope().args[i][0], (x, prev_end, x)) conditions.append(((prev_def + deflection_value), args[i][1])) prev_def = deflection_value.subs(x, args[i][1].args[1]) return Piecewise(*conditions) C3 = Symbol('C3') C4 = Symbol('C4') slope_curve = integrate(self.bending_moment(), x) + C3 deflection_curve = integrate(slope_curve, x) + C4 bc_eqs = [] for position, value in self._boundary_conditions['deflection']: eqs = deflection_curve.subs(x, position) - value bc_eqs.append(eqs) constants = list(linsolve(bc_eqs, (C3, C4))) deflection_curve = deflection_curve.subs({C3: constants[0][0], C4: constants[0][1]}) return S(1)/(E*I)*deflection_curve if self._composite_type == "fixed": args = I.args conditions = [] prev_def = 0 prev_end = 0 for i in range(len(args)): if i != 0: prev_end = args[i-1][1].args[1] deflection_value = integrate(self.slope().args[i][0], (x, prev_end, x)) conditions.append(((prev_def + deflection_value), args[i][1])) prev_def = deflection_value.subs(x, args[i][1].args[1]) return Piecewise(*conditions) C4 = Symbol('C4') deflection_curve = integrate((E*I)*self.slope(), x) + C4 bc_eqs = [] for position, value in self._boundary_conditions['deflection']: eqs = deflection_curve.subs(x, position) - value bc_eqs.append(eqs) constants = list(linsolve(bc_eqs, C4)) deflection_curve = deflection_curve.subs({C4: constants[0][0]}) return S(1)/(E*I)*deflection_curve
def _solve_hinge_beams(self, *reactions): """Method to find integration constants and reactional variables in a composite beam connected via hinge. This method resolves the composite Beam into its sub-beams and then equations of shear force, bending moment, slope and deflection are evaluated for both of them separately. These equations are then solved for unknown reactions and integration constants using the boundary conditions applied on the Beam. Equal deflection of both sub-beams at the hinge joint gives us another equation to solve the system. Examples ======== A combined beam, with constant fkexural rigidity E*I, is formed by joining a Beam of length 2*l to the right of another Beam of length l. The whole beam is fixed at both of its both end. A point load of magnitude P is also applied from the top at a distance of 2*l from starting point. >>> from sympy.physics.continuum_mechanics.beam import Beam >>> from sympy import symbols >>> E, I = symbols('E, I') >>> l=symbols('l', positive=True) >>> b1=Beam(l ,E,I) >>> b2=Beam(2*l ,E,I) >>> b=b1.join(b2,"hinge") >>> M1, A1, M2, A2, P = symbols('M1 A1 M2 A2 P') >>> b.apply_load(A1,0,-1) >>> b.apply_load(M1,0,-2) >>> b.apply_load(P,2*l,-1) >>> b.apply_load(A2,3*l,-1) >>> b.apply_load(M2,3*l,-2) >>> b.bc_slope=[(0,0), (3*l, 0)] >>> b.bc_deflection=[(0,0), (3*l, 0)] >>> b.solve_for_reaction_loads(M1, A1, M2, A2) >>> b.reaction_loads {A1: -5*P/18, A2: -13*P/18, M1: 5*P*l/18, M2: -4*P*l/9} >>> b.slope() Piecewise(((5*P*l*SingularityFunction(x, 0, 1)/18 - 5*P*SingularityFunction(x, 0, 2)/36 + 5*P*SingularityFunction(x, l, 2)/36)/(E*I), l >= x), ((P*l**2/18 - 4*P*l*SingularityFunction(-l + x, 2*l, 1)/9 - 5*P*SingularityFunction(-l + x, 0, 2)/36 + P*SingularityFunction(-l + x, l, 2)/2 - 13*P*SingularityFunction(-l + x, 2*l, 2)/36)/(E*I), x < 3*l)) >>> b.deflection() Piecewise(((5*P*l*SingularityFunction(x, 0, 2)/36 - 5*P*SingularityFunction(x, 0, 3)/108 + 5*P*SingularityFunction(x, l, 3)/108)/(E*I), l >= x), ((5*P*l**3/54 + P*l**2*(-l + x)/18 - 2*P*l*SingularityFunction(-l + x, 2*l, 2)/9 - 5*P*SingularityFunction(-l + x, 0, 3)/108 + P*SingularityFunction(-l + x, l, 3)/6 - 13*P*SingularityFunction(-l + x, 2*l, 3)/108)/(E*I), x < 3*l)) """ x = self.variable l = self._hinge_position E = self._elastic_modulus I = self._second_moment if isinstance(I, Piecewise): I1 = I.args[0][0] I2 = I.args[1][0] else: I1 = I2 = I load_1 = 0 # Load equation on first segment of composite beam load_2 = 0 # Load equation on second segment of composite beam # Distributing load on both segments for load in self.applied_loads: if load[1] < l: load_1 += load[0]*SingularityFunction(x, load[1], load[2]) if load[2] == 0: load_1 -= load[0]*SingularityFunction(x, load[3], load[2]) elif load[2] > 0: load_1 -= load[0]*SingularityFunction(x, load[3], load[2]) + load[0]*SingularityFunction(x, load[3], 0) elif load[1] == l: load_1 += load[0]*SingularityFunction(x, load[1], load[2]) load_2 += load[0]*SingularityFunction(x, load[1] - l, load[2]) elif load[1] > l: load_2 += load[0]*SingularityFunction(x, load[1] - l, load[2]) if load[2] == 0: load_2 -= load[0]*SingularityFunction(x, load[3] - l, load[2]) elif load[2] > 0: load_2 -= load[0]*SingularityFunction(x, load[3] - l, load[2]) + load[0]*SingularityFunction(x, load[3] - l, 0) h = Symbol('h') # Force due to hinge load_1 += h*SingularityFunction(x, l, -1) load_2 -= h*SingularityFunction(x, 0, -1) eq = [] shear_1 = integrate(load_1, x) shear_curve_1 = limit(shear_1, x, l) eq.append(shear_curve_1) bending_1 = integrate(shear_1, x) moment_curve_1 = limit(bending_1, x, l) eq.append(moment_curve_1) shear_2 = integrate(load_2, x) shear_curve_2 = limit(shear_2, x, self.length - l) eq.append(shear_curve_2) bending_2 = integrate(shear_2, x) moment_curve_2 = limit(bending_2, x, self.length - l) eq.append(moment_curve_2) C1 = Symbol('C1') C2 = Symbol('C2') C3 = Symbol('C3') C4 = Symbol('C4') slope_1 = S(1)/(E*I1)*(integrate(bending_1, x) + C1) def_1 = S(1)/(E*I1)*(integrate((E*I)*slope_1, x) + C1*x + C2) slope_2 = S(1)/(E*I2)*(integrate(integrate(integrate(load_2, x), x), x) + C3) def_2 = S(1)/(E*I2)*(integrate((E*I)*slope_2, x) + C4) for position, value in self.bc_slope: if position<l: eq.append(slope_1.subs(x, position) - value) else: eq.append(slope_2.subs(x, position - l) - value) for position, value in self.bc_deflection: if position<l: eq.append(def_1.subs(x, position) - value) else: eq.append(def_2.subs(x, position - l) - value) eq.append(def_1.subs(x, l) - def_2.subs(x, 0)) # Deflection of both the segments at hinge would be equal constants = list(linsolve(eq, C1, C2, C3, C4, h, *reactions)) reaction_values = list(constants[0])[5:] self._reaction_loads = dict(zip(reactions, reaction_values)) self._load = self._load.subs(self._reaction_loads) # Substituting constants and reactional load and moments with their corresponding values slope_1 = slope_1.subs({C1: constants[0][0], h:constants[0][4]}).subs(self._reaction_loads) def_1 = def_1.subs({C1: constants[0][0], C2: constants[0][1], h:constants[0][4]}).subs(self._reaction_loads) slope_2 = slope_2.subs({x: x-l, C3: constants[0][2], h:constants[0][4]}).subs(self._reaction_loads) def_2 = def_2.subs({x: x-l,C3: constants[0][2], C4: constants[0][3], h:constants[0][4]}).subs(self._reaction_loads) self._hinge_beam_slope = Piecewise((slope_1, x<=l), (slope_2, x<self.length)) self._hinge_beam_deflection = Piecewise((def_1, x<=l), (def_2, x<self.length))
def _eval_integral(self, x, _first=True, **kwargs): """Return the indefinite integral of the Piecewise such that subsequent substitution of x with a value will give the value of the integral (not including the constant of integration) up to that point. To only integrate the individual parts of Piecewise, use the `piecewise_integrate` method. Examples ======== >>> from sympy import Piecewise >>> from sympy.abc import x >>> p = Piecewise((0, x < 0), (1, x < 1), (2, True)) >>> p.integrate(x) Piecewise((0, x < 0), (x, x < 1), (2*x - 1, True)) >>> p.piecewise_integrate(x) Piecewise((0, x < 0), (x, x < 1), (2*x, True)) See Also ======== Piecewise.piecewise_integrate """ from sympy.integrals.integrals import integrate if _first: def handler(ipw): if isinstance(ipw, self.func): return ipw._eval_integral(x, _first=False, **kwargs) else: return ipw.integrate(x, **kwargs) irv = self._handle_irel(x, handler) if irv is not None: return irv # handle a Piecewise from -oo to oo with and no x-independent relationals # ----------------------------------------------------------------------- try: abei = self._intervals(x) except NotImplementedError: from sympy import Integral return Integral(self, x) # unevaluated pieces = [(a, b) for a, b, _, _ in abei] oo = S.Infinity done = [(-oo, oo, -1)] for k, p in enumerate(pieces): if p == (-oo, oo): # all undone intervals will get this key for j, (a, b, i) in enumerate(done): if i == -1: done[j] = a, b, k break # nothing else to consider N = len(done) - 1 for j, (a, b, i) in enumerate(reversed(done)): if i == -1: j = N - j done[j:j + 1] = _clip(p, (a, b), k) done = [(a, b, i) for a, b, i in done if a != b] # append an arg if there is a hole so a reference to # argument -1 will give Undefined if any(i == -1 for (a, b, i) in done): abei.append((-oo, oo, Undefined, -1)) # return the sum of the intervals args = [] sum = None for a, b, i in done: anti = integrate(abei[i][-2], x, **kwargs) if sum is None: sum = anti else: sum = sum.subs(x, a) if sum == Undefined: sum = 0 sum += anti._eval_interval(x, a, x) # see if we know whether b is contained in original # condition if b is S.Infinity: cond = True elif self.args[abei[i][-1]].cond.subs(x, b) == False: cond = (x < b) else: cond = (x <= b) args.append((sum, cond)) return Piecewise(*args)
def solve_for_reaction_loads(self, *reactions): """ Solves for the reaction forces. Examples ======== There is a beam of length 30 meters. A moment of magnitude 120 Nm is applied in the clockwise direction at the end of the beam. A pointload of magnitude 8 N is applied from the top of the beam at the starting point. There are two simple supports below the beam. One at the end and another one at a distance of 10 meters from the start. The deflection is restricted at both the supports. Using the sign convention of upward forces and clockwise moment being positive. >>> from sympy.physics.continuum_mechanics.beam import Beam >>> from sympy import symbols, linsolve, limit >>> E, I = symbols('E, I') >>> R1, R2 = symbols('R1, R2') >>> b = Beam(30, E, I) >>> b.apply_load(-8, 0, -1) >>> b.apply_load(R1, 10, -1) # Reaction force at x = 10 >>> b.apply_load(R2, 30, -1) # Reaction force at x = 30 >>> b.apply_load(120, 30, -2) >>> b.bc_deflection = [(10, 0), (30, 0)] >>> b.load R1*SingularityFunction(x, 10, -1) + R2*SingularityFunction(x, 30, -1) - 8*SingularityFunction(x, 0, -1) + 120*SingularityFunction(x, 30, -2) >>> b.solve_for_reaction_loads(R1, R2) >>> b.reaction_loads {R1: 6, R2: 2} >>> b.load -8*SingularityFunction(x, 0, -1) + 6*SingularityFunction(x, 10, -1) + 120*SingularityFunction(x, 30, -2) + 2*SingularityFunction(x, 30, -1) """ if self._composite_type == "hinge": return self._solve_hinge_beams(*reactions) x = self.variable l = self.length C3 = Symbol('C3') C4 = Symbol('C4') shear_curve = limit(self.shear_force(), x, l) moment_curve = limit(self.bending_moment(), x, l) slope_eqs = [] deflection_eqs = [] slope_curve = integrate(self.bending_moment(), x) + C3 for position, value in self._boundary_conditions['slope']: eqs = slope_curve.subs(x, position) - value slope_eqs.append(eqs) deflection_curve = integrate(slope_curve, x) + C4 for position, value in self._boundary_conditions['deflection']: eqs = deflection_curve.subs(x, position) - value deflection_eqs.append(eqs) solution = list((linsolve([shear_curve, moment_curve] + slope_eqs + deflection_eqs, (C3, C4) + reactions).args)[0]) solution = solution[2:] self._reaction_loads = dict(zip(reactions, solution)) self._load = self._load.subs(self._reaction_loads)
def rational_algorithm(f, x, k, order=4, full=False): """Rational algorithm for computing formula of coefficients of Formal Power Series of a function. Applicable when f(x) or some derivative of f(x) is a rational function in x. :func:`rational_algorithm` uses :func:`apart` function for partial fraction decomposition. :func:`apart` by default uses 'undetermined coefficients method'. By setting ``full=True``, 'Bronstein's algorithm' can be used instead. Looks for derivative of a function up to 4'th order (by default). This can be overriden using order option. Returns ======= formula : Expr ind : Expr Independent terms. order : int Examples ======== >>> from sympy import log, atan, I >>> from sympy.series.formal import rational_algorithm as ra >>> from sympy.abc import x, k >>> ra(1 / (1 - x), x, k) (1, 0, 0) >>> ra(log(1 + x), x, k) (-(-1)**(-k)/k, 0, 1) >>> ra(atan(x), x, k, full=True) ((-I*(-I)**(-k)/2 + I*I**(-k)/2)/k, 0, 1) Notes ===== By setting ``full=True``, range of admissible functions to be solved using ``rational_algorithm`` can be increased. This option should be used carefully as it can signifcantly slow down the computation as ``doit`` is performed on the :class:`RootSum` object returned by the ``apart`` function. Use ``full=False`` whenever possible. See Also ======== sympy.polys.partfrac.apart References ========== .. [1] Formal Power Series - Dominik Gruntz, Wolfram Koepf .. [2] Power Series in Computer Algebra - Wolfram Koepf """ from sympy.polys import RootSum, apart from sympy.integrals import integrate diff = f ds = [] # list of diff for i in range(order + 1): if i: diff = diff.diff(x) if diff.is_rational_function(x): coeff, sep = S.Zero, S.Zero terms = apart(diff, x, full=full) if terms.has(RootSum): terms = terms.doit() for t in Add.make_args(terms): num, den = t.as_numer_denom() if not den.has(x): sep += t else: if isinstance(den, Mul): # m*(n*x - a)**j -> (n*x - a)**j ind = den.as_independent(x) den = ind[1] num /= ind[0] # (n*x - a)**j -> (x - b) den, j = den.as_base_exp() a, xterm = den.as_coeff_add(x) # term -> m/x**n if not a: sep += t continue xc = xterm[0].coeff(x) a /= -xc num /= xc**j ak = ((-1)**j * num * binomial(j + k - 1, k).rewrite(factorial) / a**(j + k)) coeff += ak # Hacky, better way? if coeff is S.Zero: return None if (coeff.has(x) or coeff.has(zoo) or coeff.has(oo) or coeff.has(nan)): return None for j in range(i): coeff = (coeff / (k + j + 1)) sep = integrate(sep, x) sep += (ds.pop() - sep).limit(x, 0) # constant of integration return (coeff.subs(k, k - i), sep, i) else: ds.append(diff) return None
def deltaintegrate(f, x): """ deltaintegrate(f, x) The idea for integration is the following: - If we are dealing with a DiracDelta expression, i.e. DiracDelta(g(x)), we try to simplify it. If we could simplify it, then we integrate the resulting expression. We already know we can integrate a simplified expression, because only simple DiracDelta expressions are involved. If we couldn't simplify it, there are two cases: 1) The expression is a simple expression: we return the integral, taking care if we are dealing with a Derivative or with a proper DiracDelta. 2) The expression is not simple (i.e. DiracDelta(cos(x))): we can do nothing at all. - If the node is a multiplication node having a DiracDelta term: First we expand it. If the expansion did work, then we try to integrate the expansion. If not, we try to extract a simple DiracDelta term, then we have two cases: 1) We have a simple DiracDelta term, so we return the integral. 2) We didn't have a simple term, but we do have an expression with simplified DiracDelta terms, so we integrate this expression. Examples ======== >>> from sympy.abc import x, y, z >>> from sympy.integrals.deltafunctions import deltaintegrate >>> from sympy import sin, cos, DiracDelta, Heaviside >>> deltaintegrate(x*sin(x)*cos(x)*DiracDelta(x - 1), x) sin(1)*cos(1)*Heaviside(x - 1) >>> deltaintegrate(y**2*DiracDelta(x - z)*DiracDelta(y - z), y) z**2*DiracDelta(x - z)*Heaviside(y - z) See Also ======== sympy.functions.special.delta_functions.DiracDelta sympy.integrals.integrals.Integral """ if not f.has(DiracDelta): return None from sympy.integrals import Integral, integrate from sympy.solvers import solve # g(x) = DiracDelta(h(x)) if f.func == DiracDelta: h = f.expand(diracdelta=True, wrt=x) if h == f: # can't simplify the expression #FIXME: the second term tells whether is DeltaDirac or Derivative #For integrating derivatives of DiracDelta we need the chain rule if f.is_simple(x): if (len(f.args) <= 1 or f.args[1] == 0): return Heaviside(f.args[0]) else: return (DiracDelta(f.args[0], f.args[1] - 1) / f.args[0].as_poly().LC()) else: # let's try to integrate the simplified expression fh = integrate(h, x) return fh elif f.is_Mul or f.is_Pow: # g(x) = a*b*c*f(DiracDelta(h(x)))*d*e g = f.expand() if f != g: # the expansion worked fh = integrate(g, x) if fh is not None and not isinstance(fh, Integral): return fh else: # no expansion performed, try to extract a simple DiracDelta term deltaterm, rest_mult = change_mul(f, x) if not deltaterm: if rest_mult: fh = integrate(rest_mult, x) return fh else: deltaterm = deltaterm.expand(diracdelta=True, wrt=x) if deltaterm.is_Mul: # Take out any extracted factors deltaterm, rest_mult_2 = change_mul(deltaterm, x) rest_mult = rest_mult*rest_mult_2 point = solve(deltaterm.args[0], x)[0] # Return the largest hyperreal term left after # repeated integration by parts. For example, # # integrate(y*DiracDelta(x, 1),x) == y*DiracDelta(x,0), not 0 # # This is so Integral(y*DiracDelta(x).diff(x),x).doit() # will return y*DiracDelta(x) instead of 0 or DiracDelta(x), # both of which are correct everywhere the value is defined # but give wrong answers for nested integration. n = (0 if len(deltaterm.args)==1 else deltaterm.args[1]) m = 0 while n >= 0: r = (-1)**n*rest_mult.diff(x, n).subs(x, point) if r.is_zero: n -= 1 m += 1 else: if m == 0: return r*Heaviside(x - point) else: return r*DiracDelta(x,m-1) # In some very weak sense, x=0 is still a singularity, # but we hope will not be of any practical consequence. return S.Zero return None
def integrate(self, *args, **kwargs): """See the integrate function in sympy.integrals""" from sympy.integrals import integrate return integrate(self, *args, **kwargs)
def _eval_integral(self,x): from sympy.integrals import integrate return Piecewise(*[(integrate(e, x), c) for e, c in self.args])
def _eval_integral(self, x): from sympy.integrals import integrate return Piecewise(*[(integrate(e, x), c) for e, c in self.args])
def _rsolve_hypergeometric(f, x, P, Q, k, m): """Recursive wrapper to rsolve_hypergeometric. Returns a Tuple of (formula, series independent terms, maximum power of x in independent terms) if successful otherwise ``None``. See :func:`rsolve_hypergeometric` for details. """ from sympy.polys import lcm, roots from sympy.integrals import integrate # transformation - c proots, qroots = roots(P, k), roots(Q, k) all_roots = dict(proots) all_roots.update(qroots) scale = lcm( [r.as_numer_denom()[1] for r, t in all_roots.items() if r.is_rational]) f, P, Q, m = _transformation_c(f, x, P, Q, k, m, scale) # transformation - a qroots = roots(Q, k) if qroots: k_min = Min(*qroots.keys()) else: k_min = S.Zero shift = k_min + m f, P, Q, m = _transformation_a(f, x, P, Q, k, m, shift) l = (x * f).limit(x, 0) if not isinstance(l, Limit) and l != 0: # Ideally should only be l != 0 return None qroots = roots(Q, k) if qroots: k_max = Max(*qroots.keys()) else: k_max = S.Zero ind, mp = S.Zero, -oo for i in range(k_max + m + 1): r = f.diff(x, i).limit(x, 0) / factorial(i) if r.is_finite is False: old_f = f f, P, Q, m = _transformation_a(f, x, P, Q, k, m, i) f, P, Q, m = _transformation_e(f, x, P, Q, k, m) sol, ind, mp = _rsolve_hypergeometric(f, x, P, Q, k, m) sol = _apply_integrate(sol, x, k) sol = _apply_shift(sol, i) ind = integrate(ind, x) ind += (old_f - ind).limit(x, 0) # constant of integration mp += 1 return sol, ind, mp elif r: ind += r * x**(i + shift) pow_x = Rational((i + shift), scale) if pow_x > mp: mp = pow_x # maximum power of x ind = ind.subs(x, x**(1 / scale)) sol = _compute_formula(f, x, P, Q, k, m, k_max) sol = _apply_shift(sol, shift) sol = _apply_scale(sol, scale) return sol, ind, mp