m2m模型翻译
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

7336 lines
264 KiB

"""
Utility functions for Rubi integration.
See: http://www.apmaths.uwo.ca/~arich/IntegrationRules/PortableDocumentFiles/Integration%20utility%20functions.pdf
"""
from sympy.external import import_module
matchpy = import_module("matchpy")
from sympy.concrete.summations import Sum
from sympy.core.add import Add
from sympy.core.basic import Basic
from sympy.core.containers import Dict
from sympy.core.evalf import N
from sympy.core.expr import UnevaluatedExpr
from sympy.core.exprtools import factor_terms
from sympy.core.function import (Function, WildFunction, expand, expand_trig)
from sympy.core.mul import Mul
from sympy.core.numbers import (E, Float, I, Integer, Rational, oo, pi, zoo)
from sympy.core.power import Pow
from sympy.core.singleton import S
from sympy.core.symbol import (Dummy, Symbol, Wild, symbols)
from sympy.core.sympify import sympify
from sympy.core.traversal import postorder_traversal
from sympy.functions.combinatorial.factorials import factorial
from sympy.functions.elementary.complexes import im, re, Abs, sign
from sympy.functions.elementary.exponential import exp as sym_exp, log as sym_log, LambertW
from sympy.functions.elementary.hyperbolic import acosh, asinh, atanh, acoth, acsch, asech, cosh, sinh, tanh, coth, sech, csch
from sympy.functions.elementary.integers import floor, frac
from sympy.functions.elementary.miscellaneous import (Max, Min, sqrt)
from sympy.functions.elementary.trigonometric import atan, acsc, asin, acot, acos, asec, atan2, sin, cos, tan, cot, csc, sec
from sympy.functions.special.elliptic_integrals import elliptic_f, elliptic_e, elliptic_pi
from sympy.functions.special.error_functions import erf, fresnelc, fresnels, erfc, erfi, Ei, expint, li, Si, Ci, Shi, Chi
from sympy.functions.special.gamma_functions import (digamma, gamma, loggamma, polygamma, uppergamma)
from sympy.functions.special.hyper import (appellf1, hyper, TupleArg)
from sympy.functions.special.zeta_functions import polylog, zeta
from sympy.integrals.integrals import Integral
from sympy.logic.boolalg import And, Or
from sympy.ntheory.factor_ import (factorint, factorrat)
from sympy.polys.partfrac import apart
from sympy.polys.polyerrors import (PolynomialDivisionFailed, PolynomialError, UnificationFailed)
from sympy.polys.polytools import (discriminant, factor, gcd, lcm, poly, sqf, sqf_list, Poly, degree, quo, rem, total_degree)
from sympy.sets.sets import FiniteSet
from sympy.simplify.powsimp import powdenest
from sympy.simplify.radsimp import collect
from sympy.simplify.simplify import fraction, simplify, cancel, powsimp, nsimplify
from sympy.utilities.decorator import doctest_depends_on
from sympy.utilities.iterables import flatten
from sympy.core.random import randint
class rubi_unevaluated_expr(UnevaluatedExpr):
"""
This is needed to convert `exp` as `Pow`.
SymPy's UnevaluatedExpr has an issue with `is_commutative`.
"""
@property
def is_commutative(self):
from sympy.core.logic import fuzzy_and
return fuzzy_and(a.is_commutative for a in self.args)
_E = rubi_unevaluated_expr(E)
class rubi_exp(Function):
"""
SymPy's exp is not identified as `Pow`. So it is not matched with `Pow`.
Like `a = exp(2)` is not identified as `Pow(E, 2)`. Rubi rules need it.
So, another exp has been created only for rubi module.
Examples
========
>>> from sympy import Pow, exp as sym_exp
>>> isinstance(sym_exp(2), Pow)
False
>>> from sympy.integrals.rubi.utility_function import rubi_exp
>>> isinstance(rubi_exp(2), Pow)
True
"""
@classmethod
def eval(cls, *args):
return Pow(_E, args[0])
class rubi_log(Function):
"""
For rule matching different `exp` has been used. So for proper results,
`log` is modified little only for case when it encounters rubi's `exp`.
For other cases it is same.
Examples
========
>>> from sympy.integrals.rubi.utility_function import rubi_exp, rubi_log
>>> a = rubi_exp(2)
>>> rubi_log(a)
2
"""
@classmethod
def eval(cls, *args):
if args[0].has(_E):
return sym_log(args[0]).doit()
else:
return sym_log(args[0])
if matchpy:
from matchpy import Arity, Operation, CustomConstraint, Pattern, ReplacementRule, ManyToOneReplacer
from sympy.integrals.rubi.symbol import WC
from matchpy import is_match, replace_all
class UtilityOperator(Operation):
name = 'UtilityOperator'
arity = Arity.variadic
commutative = False
associative = True
Operation.register(rubi_log)
Operation.register(rubi_exp)
A_, B_, C_, F_, G_, a_, b_, c_, d_, e_, f_, g_, h_, i_, j_, k_, l_, m_, \
n_, p_, q_, r_, t_, u_, v_, s_, w_, x_, z_ = [WC(i) for i in 'ABCFGabcdefghijklmnpqrtuvswxz']
a, b, c, d, e = symbols('a b c d e')
Int = Integral
def replace_pow_exp(z):
"""
This function converts back rubi's `exp` to general SymPy's `exp`.
Examples
========
>>> from sympy.integrals.rubi.utility_function import rubi_exp, replace_pow_exp
>>> expr = rubi_exp(5)
>>> expr
E**5
>>> replace_pow_exp(expr)
exp(5)
"""
z = S(z)
if z.has(_E):
z = z.replace(_E, E)
return z
def Simplify(expr):
expr = simplify(expr)
return expr
def Set(expr, value):
return {expr: value}
def With(subs, expr):
if isinstance(subs, dict):
k = list(subs.keys())[0]
expr = expr.xreplace({k: subs[k]})
else:
for i in subs:
k = list(i.keys())[0]
expr = expr.xreplace({k: i[k]})
return expr
def Module(subs, expr):
return With(subs, expr)
def Scan(f, expr):
# evaluates f applied to each element of expr in turn.
for i in expr:
yield f(i)
def MapAnd(f, l, x=None):
# MapAnd[f,l] applies f to the elements of list l until False is returned; else returns True
if x:
for i in l:
if f(i, x) == False:
return False
return True
else:
for i in l:
if f(i) == False:
return False
return True
def FalseQ(u):
if isinstance(u, (Dict, dict)):
return FalseQ(*list(u.values()))
return u == False
def ZeroQ(*expr):
if len(expr) == 1:
if isinstance(expr[0], list):
return list(ZeroQ(i) for i in expr[0])
else:
return Simplify(expr[0]) == 0
else:
return all(ZeroQ(i) for i in expr)
def OneQ(a):
if a == S(1):
return True
return False
def NegativeQ(u):
u = Simplify(u)
if u in (zoo, oo):
return False
if u.is_comparable:
res = u < 0
if not res.is_Relational:
return res
return False
def NonzeroQ(expr):
return Simplify(expr) != 0
def FreeQ(nodes, var):
if isinstance(nodes, list):
return not any(S(expr).has(var) for expr in nodes)
else:
nodes = S(nodes)
return not nodes.has(var)
def NFreeQ(nodes, var):
""" Note that in rubi 4.10.8 this function was not defined in `Integration Utility Functions.m`,
but was used in rules. So explicitly its returning `False`
"""
return False
# return not FreeQ(nodes, var)
def List(*var):
return list(var)
def PositiveQ(var):
var = Simplify(var)
if var in (zoo, oo):
return False
if var.is_comparable:
res = var > 0
if not res.is_Relational:
return res
return False
def PositiveIntegerQ(*args):
return all(var.is_Integer and PositiveQ(var) for var in args)
def NegativeIntegerQ(*args):
return all(var.is_Integer and NegativeQ(var) for var in args)
def IntegerQ(var):
var = Simplify(var)
if isinstance(var, (int, Integer)):
return True
else:
return var.is_Integer
def IntegersQ(*var):
return all(IntegerQ(i) for i in var)
def _ComplexNumberQ(var):
i = S(im(var))
if isinstance(i, (Integer, Float)):
return i != 0
else:
return False
def ComplexNumberQ(*var):
"""
ComplexNumberQ(m, n,...) returns True if m, n, ... are all explicit complex numbers, else it returns False.
Examples
========
>>> from sympy.integrals.rubi.utility_function import ComplexNumberQ
>>> from sympy import I
>>> ComplexNumberQ(1 + I*2, I)
True
>>> ComplexNumberQ(2, I)
False
"""
return all(_ComplexNumberQ(i) for i in var)
def PureComplexNumberQ(*var):
return all((_ComplexNumberQ(i) and re(i)==0) for i in var)
def RealNumericQ(u):
return u.is_real
def PositiveOrZeroQ(u):
return u.is_real and u >= 0
def NegativeOrZeroQ(u):
return u.is_real and u <= 0
def FractionOrNegativeQ(u):
return FractionQ(u) or NegativeQ(u)
def NegQ(var):
return Not(PosQ(var)) and NonzeroQ(var)
def Equal(a, b):
return a == b
def Unequal(a, b):
return a != b
def IntPart(u):
# IntPart[u] returns the sum of the integer terms of u.
if ProductQ(u):
if IntegerQ(First(u)):
return First(u)*IntPart(Rest(u))
elif IntegerQ(u):
return u
elif FractionQ(u):
return IntegerPart(u)
elif SumQ(u):
res = 0
for i in u.args:
res += IntPart(i)
return res
return 0
def FracPart(u):
# FracPart[u] returns the sum of the non-integer terms of u.
if ProductQ(u):
if IntegerQ(First(u)):
return First(u)*FracPart(Rest(u))
if IntegerQ(u):
return 0
elif FractionQ(u):
return FractionalPart(u)
elif SumQ(u):
res = 0
for i in u.args:
res += FracPart(i)
return res
else:
return u
def RationalQ(*nodes):
return all(var.is_Rational for var in nodes)
def ProductQ(expr):
return S(expr).is_Mul
def SumQ(expr):
return expr.is_Add
def NonsumQ(expr):
return not SumQ(expr)
def Subst(a, x, y):
if None in [a, x, y]:
return None
if a.has(Function('Integrate')):
# substituting in `Function(Integrate)` won't take care of properties of Integral
a = a.replace(Function('Integrate'), Integral)
return a.subs(x, y)
# return a.xreplace({x: y})
def First(expr, d=None):
"""
Gives the first element if it exists, or d otherwise.
Examples
========
>>> from sympy.integrals.rubi.utility_function import First
>>> from sympy.abc import a, b, c
>>> First(a + b + c)
a
>>> First(a*b*c)
a
"""
if isinstance(expr, list):
return expr[0]
if isinstance(expr, Symbol):
return expr
else:
if SumQ(expr) or ProductQ(expr):
l = Sort(expr.args)
return l[0]
else:
return expr.args[0]
def Rest(expr):
"""
Gives rest of the elements if it exists
Examples
========
>>> from sympy.integrals.rubi.utility_function import Rest
>>> from sympy.abc import a, b, c
>>> Rest(a + b + c)
b + c
>>> Rest(a*b*c)
b*c
"""
if isinstance(expr, list):
return expr[1:]
else:
if SumQ(expr) or ProductQ(expr):
l = Sort(expr.args)
return expr.func(*l[1:])
else:
return expr.args[1]
def SqrtNumberQ(expr):
# SqrtNumberQ[u] returns True if u^2 is a rational number; else it returns False.
if PowerQ(expr):
m = expr.base
n = expr.exp
return (IntegerQ(n) and SqrtNumberQ(m)) or (IntegerQ(n-S(1)/2) and RationalQ(m))
elif expr.is_Mul:
return all(SqrtNumberQ(i) for i in expr.args)
else:
return RationalQ(expr) or expr == I
def SqrtNumberSumQ(u):
return SumQ(u) and SqrtNumberQ(First(u)) and SqrtNumberQ(Rest(u)) or ProductQ(u) and SqrtNumberQ(First(u)) and SqrtNumberSumQ(Rest(u))
def LinearQ(expr, x):
"""
LinearQ(expr, x) returns True iff u is a polynomial of degree 1.
Examples
========
>>> from sympy.integrals.rubi.utility_function import LinearQ
>>> from sympy.abc import x, y, a
>>> LinearQ(a, x)
False
>>> LinearQ(3*x + y**2, x)
True
>>> LinearQ(3*x + y**2, y)
False
"""
if isinstance(expr, list):
return all(LinearQ(i, x) for i in expr)
elif expr.is_polynomial(x):
if degree(Poly(expr, x), gen=x) == 1:
return True
return False
def Sqrt(a):
return sqrt(a)
def ArcCosh(a):
return acosh(a)
class Util_Coefficient(Function):
def doit(self):
if len(self.args) == 2:
n = 1
else:
n = Simplify(self.args[2])
if NumericQ(n):
expr = expand(self.args[0])
if isinstance(n, (int, Integer)):
return expr.coeff(self.args[1], n)
else:
return expr.coeff(self.args[1]**n)
else:
return self
def Coefficient(expr, var, n=1):
"""
Coefficient(expr, var) gives the coefficient of form in the polynomial expr.
Coefficient(expr, var, n) gives the coefficient of var**n in expr.
Examples
========
>>> from sympy.integrals.rubi.utility_function import Coefficient
>>> from sympy.abc import x, a, b, c
>>> Coefficient(7 + 2*x + 4*x**3, x, 1)
2
>>> Coefficient(a + b*x + c*x**3, x, 0)
a
>>> Coefficient(a + b*x + c*x**3, x, 4)
0
>>> Coefficient(b*x + c*x**3, x, 3)
c
"""
if NumericQ(n):
if expr == 0 or n in (zoo, oo):
return 0
expr = expand(expr)
if isinstance(n, (int, Integer)):
return expr.coeff(var, n)
else:
return expr.coeff(var**n)
return Util_Coefficient(expr, var, n)
def Denominator(var):
var = Simplify(var)
if isinstance(var, Pow):
if isinstance(var.exp, Integer):
if var.exp > 0:
return Pow(Denominator(var.base), var.exp)
elif var.exp < 0:
return Pow(Numerator(var.base), -1*var.exp)
elif isinstance(var, Add):
var = factor(var)
return fraction(var)[1]
def Hypergeometric2F1(a, b, c, z):
return hyper([a, b], [c], z)
def Not(var):
if isinstance(var, bool):
return not var
elif var.is_Relational:
var = False
return not var
def FractionalPart(a):
return frac(a)
def IntegerPart(a):
return floor(a)
def AppellF1(a, b1, b2, c, x, y):
return appellf1(a, b1, b2, c, x, y)
def EllipticPi(*args):
return elliptic_pi(*args)
def EllipticE(*args):
return elliptic_e(*args)
def EllipticF(Phi, m):
return elliptic_f(Phi, m)
def ArcTan(a, b = None):
if b is None:
return atan(a)
else:
return atan2(a, b)
def ArcCot(a):
return acot(a)
def ArcCoth(a):
return acoth(a)
def ArcTanh(a):
return atanh(a)
def ArcSin(a):
return asin(a)
def ArcSinh(a):
return asinh(a)
def ArcCos(a):
return acos(a)
def ArcCsc(a):
return acsc(a)
def ArcSec(a):
return asec(a)
def ArcCsch(a):
return acsch(a)
def ArcSech(a):
return asech(a)
def Sinh(u):
return sinh(u)
def Tanh(u):
return tanh(u)
def Cosh(u):
return cosh(u)
def Sech(u):
return sech(u)
def Csch(u):
return csch(u)
def Coth(u):
return coth(u)
def LessEqual(*args):
for i in range(0, len(args) - 1):
try:
if args[i] > args[i + 1]:
return False
except (IndexError, NotImplementedError):
return False
return True
def Less(*args):
for i in range(0, len(args) - 1):
try:
if args[i] >= args[i + 1]:
return False
except (IndexError, NotImplementedError):
return False
return True
def Greater(*args):
for i in range(0, len(args) - 1):
try:
if args[i] <= args[i + 1]:
return False
except (IndexError, NotImplementedError):
return False
return True
def GreaterEqual(*args):
for i in range(0, len(args) - 1):
try:
if args[i] < args[i + 1]:
return False
except (IndexError, NotImplementedError):
return False
return True
def FractionQ(*args):
"""
FractionQ(m, n,...) returns True if m, n, ... are all explicit fractions, else it returns False.
Examples
========
>>> from sympy import S
>>> from sympy.integrals.rubi.utility_function import FractionQ
>>> FractionQ(S('3'))
False
>>> FractionQ(S('3')/S('2'))
True
"""
return all(i.is_Rational for i in args) and all(Denominator(i) != S(1) for i in args)
def IntLinearcQ(a, b, c, d, m, n, x):
# returns True iff (a+b*x)^m*(c+d*x)^n is integrable wrt x in terms of non-hypergeometric functions.
return IntegerQ(m) or IntegerQ(n) or IntegersQ(S(3)*m, S(3)*n) or IntegersQ(S(4)*m, S(4)*n) or IntegersQ(S(2)*m, S(6)*n) or IntegersQ(S(6)*m, S(2)*n) or IntegerQ(m + n)
Defer = UnevaluatedExpr
def Expand(expr):
return expr.expand()
def IndependentQ(u, x):
"""
If u is free from x IndependentQ(u, x) returns True else False.
Examples
========
>>> from sympy.integrals.rubi.utility_function import IndependentQ
>>> from sympy.abc import x, a, b
>>> IndependentQ(a + b*x, x)
False
>>> IndependentQ(a + b, x)
True
"""
return FreeQ(u, x)
def PowerQ(expr):
return expr.is_Pow or ExpQ(expr)
def IntegerPowerQ(u):
if isinstance(u, sym_exp): #special case for exp
return IntegerQ(u.args[0])
return PowerQ(u) and IntegerQ(u.args[1])
def PositiveIntegerPowerQ(u):
if isinstance(u, sym_exp):
return IntegerQ(u.args[0]) and PositiveQ(u.args[0])
return PowerQ(u) and IntegerQ(u.args[1]) and PositiveQ(u.args[1])
def FractionalPowerQ(u):
if isinstance(u, sym_exp):
return FractionQ(u.args[0])
return PowerQ(u) and FractionQ(u.args[1])
def AtomQ(expr):
expr = sympify(expr)
if isinstance(expr, list):
return False
if expr in [None, True, False, _E]: # [None, True, False] are atoms in mathematica and _E is also an atom
return True
# elif isinstance(expr, list):
# return all(AtomQ(i) for i in expr)
else:
return expr.is_Atom
def ExpQ(u):
u = replace_pow_exp(u)
return Head(u) in (sym_exp, rubi_exp)
def LogQ(u):
return u.func in (sym_log, Log)
def Head(u):
return u.func
def MemberQ(l, u):
if isinstance(l, list):
return u in l
else:
return u in l.args
def TrigQ(u):
if AtomQ(u):
x = u
else:
x = Head(u)
return MemberQ([sin, cos, tan, cot, sec, csc], x)
def SinQ(u):
return Head(u) == sin
def CosQ(u):
return Head(u) == cos
def TanQ(u):
return Head(u) == tan
def CotQ(u):
return Head(u) == cot
def SecQ(u):
return Head(u) == sec
def CscQ(u):
return Head(u) == csc
def Sin(u):
return sin(u)
def Cos(u):
return cos(u)
def Tan(u):
return tan(u)
def Cot(u):
return cot(u)
def Sec(u):
return sec(u)
def Csc(u):
return csc(u)
def HyperbolicQ(u):
if AtomQ(u):
x = u
else:
x = Head(u)
return MemberQ([sinh, cosh, tanh, coth, sech, csch], x)
def SinhQ(u):
return Head(u) == sinh
def CoshQ(u):
return Head(u) == cosh
def TanhQ(u):
return Head(u) == tanh
def CothQ(u):
return Head(u) == coth
def SechQ(u):
return Head(u) == sech
def CschQ(u):
return Head(u) == csch
def InverseTrigQ(u):
if AtomQ(u):
x = u
else:
x = Head(u)
return MemberQ([asin, acos, atan, acot, asec, acsc], x)
def SinCosQ(f):
return MemberQ([sin, cos, sec, csc], Head(f))
def SinhCoshQ(f):
return MemberQ([sinh, cosh, sech, csch], Head(f))
def LeafCount(expr):
return len(list(postorder_traversal(expr)))
def Numerator(u):
u = Simplify(u)
if isinstance(u, Pow):
if isinstance(u.exp, Integer):
if u.exp > 0:
return Pow(Numerator(u.base), u.exp)
elif u.exp < 0:
return Pow(Denominator(u.base), -1*u.exp)
elif isinstance(u, Add):
u = factor(u)
return fraction(u)[0]
def NumberQ(u):
if isinstance(u, (int, float)):
return True
return u.is_number
def NumericQ(u):
return N(u).is_number
def Length(expr):
"""
Returns number of elements in the expression just as SymPy's len.
Examples
========
>>> from sympy.integrals.rubi.utility_function import Length
>>> from sympy.abc import x, a, b
>>> from sympy import cos, sin
>>> Length(a + b)
2
>>> Length(sin(a)*cos(a))
2
"""
if isinstance(expr, list):
return len(expr)
return len(expr.args)
def ListQ(u):
return isinstance(u, list)
def Im(u):
u = S(u)
return im(u.doit())
def Re(u):
u = S(u)
return re(u.doit())
def InverseHyperbolicQ(u):
if not u.is_Atom:
u = Head(u)
return u in [acosh, asinh, atanh, acoth, acsch, acsch]
def InverseFunctionQ(u):
# returns True if u is a call on an inverse function; else returns False.
return LogQ(u) or InverseTrigQ(u) and Length(u) <= 1 or InverseHyperbolicQ(u) or u.func == polylog
def TrigHyperbolicFreeQ(u, x):
# If u is free of trig, hyperbolic and calculus functions involving x, TrigHyperbolicFreeQ[u,x] returns true; else it returns False.
if AtomQ(u):
return True
else:
if TrigQ(u) | HyperbolicQ(u) | CalculusQ(u):
return FreeQ(u, x)
else:
for i in u.args:
if not TrigHyperbolicFreeQ(i, x):
return False
return True
def InverseFunctionFreeQ(u, x):
# If u is free of inverse, calculus and hypergeometric functions involving x, InverseFunctionFreeQ[u,x] returns true; else it returns False.
if AtomQ(u):
return True
else:
if InverseFunctionQ(u) or CalculusQ(u) or u.func in (hyper, appellf1):
return FreeQ(u, x)
else:
for i in u.args:
if not ElementaryFunctionQ(i):
return False
return True
def RealQ(u):
if ListQ(u):
return MapAnd(RealQ, u)
elif NumericQ(u):
return ZeroQ(Im(N(u)))
elif PowerQ(u):
u = u.base
v = u.exp
return RealQ(u) & RealQ(v) & (IntegerQ(v) | PositiveOrZeroQ(u))
elif u.is_Mul:
return all(RealQ(i) for i in u.args)
elif u.is_Add:
return all(RealQ(i) for i in u.args)
elif u.is_Function:
f = u.func
u = u.args[0]
if f in [sin, cos, tan, cot, sec, csc, atan, acot, erf]:
return RealQ(u)
else:
if f in [asin, acos]:
return LessEqual(-1, u, 1)
else:
if f == sym_log:
return PositiveOrZeroQ(u)
else:
return False
else:
return False
def EqQ(u, v):
return ZeroQ(u - v)
def FractionalPowerFreeQ(u):
if AtomQ(u):
return True
elif FractionalPowerQ(u):
return False
def ComplexFreeQ(u):
if AtomQ(u) and Not(ComplexNumberQ(u)):
return True
else:
return False
def PolynomialQ(u, x = None):
if x is None :
return u.is_polynomial()
if isinstance(x, Pow):
if isinstance(x.exp, Integer):
deg = degree(u, x.base)
if u.is_polynomial(x):
if deg % x.exp !=0 :
return False
try:
p = Poly(u, x.base)
except PolynomialError:
return False
c_list = p.all_coeffs()
coeff_list = c_list[:-1:x.exp]
coeff_list += [c_list[-1]]
for i in coeff_list:
if not i == 0:
index = c_list.index(i)
c_list[index] = 0
if all(i == 0 for i in c_list):
return True
else:
return False
else:
return False
elif isinstance(x.exp, (Float, Rational)): #not full - proof
if FreeQ(simplify(u), x.base) and Exponent(u, x.base) == 0:
if not all(FreeQ(u, i) for i in x.base.free_symbols):
return False
if isinstance(x, Mul):
return all(PolynomialQ(u, i) for i in x.args)
return u.is_polynomial(x)
def FactorSquareFree(u):
return sqf(u)
def PowerOfLinearQ(expr, x):
u = Wild('u')
w = Wild('w')
m = Wild('m')
n = Wild('n')
Match = expr.match(u**m)
if PolynomialQ(Match[u], x) and FreeQ(Match[m], x):
if IntegerQ(Match[m]):
e = FactorSquareFree(Match[u]).match(w**n)
if FreeQ(e[n], x) and LinearQ(e[w], x):
return True
else:
return False
else:
return LinearQ(Match[u], x)
else:
return False
def Exponent(expr, x):
expr = Expand(S(expr))
if S(expr).is_number or (not expr.has(x)):
return 0
if PolynomialQ(expr, x):
if isinstance(x, Rational):
return degree(Poly(expr, x), x)
return degree(expr, gen = x)
else:
return 0
def ExponentList(expr, x):
expr = Expand(S(expr))
if S(expr).is_number or (not expr.has(x)):
return [0]
if expr.is_Add:
expr = collect(expr, x)
lst = []
k = 1
for t in expr.args:
if t.has(x):
if isinstance(x, Rational):
lst += [degree(Poly(t, x), x)]
else:
lst += [degree(t, gen = x)]
else:
if k == 1:
lst += [0]
k += 1
lst.sort()
return lst
else:
if isinstance(x, Rational):
return [degree(Poly(expr, x), x)]
else:
return [degree(expr, gen = x)]
def QuadraticQ(u, x):
# QuadraticQ(u, x) returns True iff u is a polynomial of degree 2 and not a monomial of the form a x^2
if ListQ(u):
for expr in u:
if Not(PolyQ(expr, x, 2) and Not(Coefficient(expr, x, 0) == 0 and Coefficient(expr, x, 1) == 0)):
return False
return True
else:
return PolyQ(u, x, 2) and Not(Coefficient(u, x, 0) == 0 and Coefficient(u, x, 1) == 0)
def LinearPairQ(u, v, x):
# LinearPairQ(u, v, x) returns True iff u and v are linear not equal x but u/v is a constant wrt x
return LinearQ(u, x) and LinearQ(v, x) and NonzeroQ(u-x) and ZeroQ(Coefficient(u, x, 0)*Coefficient(v, x, 1)-Coefficient(u, x, 1)*Coefficient(v, x, 0))
def BinomialParts(u, x):
if PolynomialQ(u, x):
if Exponent(u, x) > 0:
lst = ExponentList(u, x)
if len(lst)==1:
return [0, Coefficient(u, x, Exponent(u, x)), Exponent(u, x)]
elif len(lst) == 2 and lst[0] == 0:
return [Coefficient(u, x, 0), Coefficient(u, x, Exponent(u, x)), Exponent(u, x)]
else:
return False
else:
return False
elif PowerQ(u):
if u.base == x and FreeQ(u.exp, x):
return [0, 1, u.exp]
else:
return False
elif ProductQ(u):
if FreeQ(First(u), x):
lst2 = BinomialParts(Rest(u), x)
if AtomQ(lst2):
return False
else:
return [First(u)*lst2[0], First(u)*lst2[1], lst2[2]]
elif FreeQ(Rest(u), x):
lst1 = BinomialParts(First(u), x)
if AtomQ(lst1):
return False
else:
return [Rest(u)*lst1[0], Rest(u)*lst1[1], lst1[2]]
lst1 = BinomialParts(First(u), x)
if AtomQ(lst1):
return False
lst2 = BinomialParts(Rest(u), x)
if AtomQ(lst2):
return False
a = lst1[0]
b = lst1[1]
m = lst1[2]
c = lst2[0]
d = lst2[1]
n = lst2[2]
if ZeroQ(a):
if ZeroQ(c):
return [0, b*d, m + n]
elif ZeroQ(m + n):
return [b*d, b*c, m]
else:
return False
if ZeroQ(c):
if ZeroQ(m + n):
return [b*d, a*d, n]
else:
return False
if EqQ(m, n) and ZeroQ(a*d + b*c):
return [a*c, b*d, 2*m]
else:
return False
elif SumQ(u):
if FreeQ(First(u),x):
lst2 = BinomialParts(Rest(u), x)
if AtomQ(lst2):
return False
else:
return [First(u) + lst2[0], lst2[1], lst2[2]]
elif FreeQ(Rest(u), x):
lst1 = BinomialParts(First(u), x)
if AtomQ(lst1):
return False
else:
return[Rest(u) + lst1[0], lst1[1], lst1[2]]
lst1 = BinomialParts(First(u), x)
if AtomQ(lst1):
return False
lst2 = BinomialParts(Rest(u),x)
if AtomQ(lst2):
return False
if EqQ(lst1[2], lst2[2]):
return [lst1[0] + lst2[0], lst1[1] + lst2[1], lst1[2]]
else:
return False
else:
return False
def TrinomialParts(u, x):
# If u is equivalent to a trinomial of the form a + b*x^n + c*x^(2*n) where n!=0, b!=0 and c!=0, TrinomialParts[u,x] returns the list {a,b,c,n}; else it returns False.
u = sympify(u)
if PolynomialQ(u, x):
lst = CoefficientList(u, x)
if len(lst)<3 or EvenQ(sympify(len(lst))) or ZeroQ((len(lst)+1)/2):
return False
#Catch(
# Scan(Function(if ZeroQ(lst), Null, Throw(False), Drop(Drop(Drop(lst, [(len(lst)+1)/2]), 1), -1];
# [First(lst), lst[(len(lst)+1)/2], Last(lst), (len(lst)-1)/2]):
if PowerQ(u):
if EqQ(u.exp, 2):
lst = BinomialParts(u.base, x)
if not lst or ZeroQ(lst[0]):
return False
else:
return [lst[0]**2, 2*lst[0]*lst[1], lst[1]**2, lst[2]]
else:
return False
if ProductQ(u):
if FreeQ(First(u), x):
lst2 = TrinomialParts(Rest(u), x)
if not lst2:
return False
else:
return [First(u)*lst2[0], First(u)*lst2[1], First(u)*lst2[2], lst2[3]]
if FreeQ(Rest(u), x):
lst1 = TrinomialParts(First(u), x)
if not lst1:
return False
else:
return [Rest(u)*lst1[0], Rest(u)*lst1[1], Rest(u)*lst1[2], lst1[3]]
lst1 = BinomialParts(First(u), x)
if not lst1:
return False
lst2 = BinomialParts(Rest(u), x)
if not lst2:
return False
a = lst1[0]
b = lst1[1]
m = lst1[2]
c = lst2[0]
d = lst2[1]
n = lst2[2]
if EqQ(m, n) and NonzeroQ(a*d+b*c):
return [a*c, a*d + b*c, b*d, m]
else:
return False
if SumQ(u):
if FreeQ(First(u), x):
lst2 = TrinomialParts(Rest(u), x)
if not lst2:
return False
else:
return [First(u)+lst2[0], lst2[1], lst2[2], lst2[3]]
if FreeQ(Rest(u), x):
lst1 = TrinomialParts(First(u), x)
if not lst1:
return False
else:
return [Rest(u)+lst1[0], lst1[1], lst1[2], lst1[3]]
lst1 = TrinomialParts(First(u), x)
if not lst1:
lst3 = BinomialParts(First(u), x)
if not lst3:
return False
lst2 = TrinomialParts(Rest(u), x)
if not lst2:
lst4 = BinomialParts(Rest(u), x)
if not lst4:
return False
if EqQ(lst3[2], 2*lst4[2]):
return [lst3[0]+lst4[0], lst4[1], lst3[1], lst4[2]]
if EqQ(lst4[2], 2*lst3[2]):
return [lst3[0]+lst4[0], lst3[1], lst4[1], lst3[2]]
else:
return False
if EqQ(lst3[2], lst2[3]) and NonzeroQ(lst3[1]+lst2[1]):
return [lst3[0]+lst2[0], lst3[1]+lst2[1], lst2[2], lst2[3]]
if EqQ(lst3[2], 2*lst2[3]) and NonzeroQ(lst3[1]+lst2[2]):
return [lst3[0]+lst2[0], lst2[1], lst3[1]+lst2[2], lst2[3]]
else:
return False
lst2 = TrinomialParts(Rest(u), x)
if AtomQ(lst2):
lst4 = BinomialParts(Rest(u), x)
if not lst4:
return False
if EqQ(lst4[2], lst1[3]) and NonzeroQ(lst1[1]+lst4[0]):
return [lst1[0]+lst4[0], lst1[1]+lst4[1], lst1[2], lst1[3]]
if EqQ(lst4[2], 2*lst1[3]) and NonzeroQ(lst1[2]+lst4[1]):
return [lst1[0]+lst4[0], lst1[1], lst1[2]+lst4[1], lst1[3]]
else:
return False
if EqQ(lst1[3], lst2[3]) and NonzeroQ(lst1[1]+lst2[1]) and NonzeroQ(lst1[2]+lst2[2]):
return [lst1[0]+lst2[0], lst1[1]+lst2[1], lst1[2]+lst2[2], lst1[3]]
else:
return False
else:
return False
def PolyQ(u, x, n=None):
# returns True iff u is a polynomial of degree n.
if ListQ(u):
return all(PolyQ(i, x) for i in u)
if n is None:
if u == x:
return False
elif isinstance(x, Pow):
n = x.exp
x_base = x.base
if FreeQ(n, x_base):
if PositiveIntegerQ(n):
return PolyQ(u, x_base) and (PolynomialQ(u, x) or PolynomialQ(Together(u), x))
elif AtomQ(n):
return PolynomialQ(u, x) and FreeQ(CoefficientList(u, x), x_base)
else:
return False
return PolynomialQ(u, x) or PolynomialQ(u, Together(x))
else:
return PolynomialQ(u, x) and Coefficient(u, x, n) != 0 and Exponent(u, x) == n
def EvenQ(u):
# gives True if expr is an even integer, and False otherwise.
return isinstance(u, (Integer, int)) and u%2 == 0
def OddQ(u):
# gives True if expr is an odd integer, and False otherwise.
return isinstance(u, (Integer, int)) and u%2 == 1
def PerfectSquareQ(u):
# (* If u is a rational number whose squareroot is rational or if u is of the form u1^n1 u2^n2 ...
# and n1, n2, ... are even, PerfectSquareQ[u] returns True; else it returns False. *)
if RationalQ(u):
return Greater(u, 0) and RationalQ(Sqrt(u))
elif PowerQ(u):
return EvenQ(u.exp)
elif ProductQ(u):
return PerfectSquareQ(First(u)) and PerfectSquareQ(Rest(u))
elif SumQ(u):
s = Simplify(u)
if NonsumQ(s):
return PerfectSquareQ(s)
return False
else:
return False
def NiceSqrtAuxQ(u):
if RationalQ(u):
return u > 0
elif PowerQ(u):
return EvenQ(u.exp)
elif ProductQ(u):
return NiceSqrtAuxQ(First(u)) and NiceSqrtAuxQ(Rest(u))
elif SumQ(u):
s = Simplify(u)
return NonsumQ(s) and NiceSqrtAuxQ(s)
else:
return False
def NiceSqrtQ(u):
return Not(NegativeQ(u)) and NiceSqrtAuxQ(u)
def Together(u):
return factor(u)
def PosAux(u):
if RationalQ(u):
return u>0
elif NumberQ(u):
if ZeroQ(Re(u)):
return Im(u) > 0
else:
return Re(u) > 0
elif NumericQ(u):
v = N(u)
if ZeroQ(Re(v)):
return Im(v) > 0
else:
return Re(v) > 0
elif PowerQ(u):
if OddQ(u.exp):
return PosAux(u.base)
else:
return True
elif ProductQ(u):
if PosAux(First(u)):
return PosAux(Rest(u))
else:
return not PosAux(Rest(u))
elif SumQ(u):
return PosAux(First(u))
else:
res = u > 0
if res in(True, False):
return res
return True
def PosQ(u):
# If u is not 0 and has a positive form, PosQ[u] returns True, else it returns False.
return PosAux(TogetherSimplify(u))
def CoefficientList(u, x):
if PolynomialQ(u, x):
return list(reversed(Poly(u, x).all_coeffs()))
else:
return []
def ReplaceAll(expr, args):
if isinstance(args, list):
n_args = {}
for i in args:
n_args.update(i)
return expr.subs(n_args)
return expr.subs(args)
def ExpandLinearProduct(v, u, a, b, x):
# If u is a polynomial in x, ExpandLinearProduct[v,u,a,b,x] expands v*u into a sum of terms of the form c*v*(a+b*x)^n.
if FreeQ([a, b], x) and PolynomialQ(u, x):
lst = CoefficientList(ReplaceAll(u, {x: (x - a)/b}), x)
lst = [SimplifyTerm(i, x) for i in lst]
res = 0
for k in range(1, len(lst)+1):
res = res + Simplify(v*lst[k-1]*(a + b*x)**(k - 1))
return res
return u*v
def GCD(*args):
args = S(args)
if len(args) == 1:
if isinstance(args[0], (int, Integer)):
return args[0]
else:
return S(1)
return gcd(*args)
def ContentFactor(expn):
return factor_terms(expn)
def NumericFactor(u):
# returns the real numeric factor of u.
if NumberQ(u):
if ZeroQ(Im(u)):
return u
elif ZeroQ(Re(u)):
return Im(u)
else:
return S(1)
elif PowerQ(u):
if RationalQ(u.base) and RationalQ(u.exp):
if u.exp > 0:
return 1/Denominator(u.base)
else:
return 1/(1/Denominator(u.base))
else:
return S(1)
elif ProductQ(u):
return Mul(*[NumericFactor(i) for i in u.args])
elif SumQ(u):
if LeafCount(u) < 50:
c = ContentFactor(u)
if SumQ(c):
return S(1)
else:
return NumericFactor(c)
else:
m = NumericFactor(First(u))
n = NumericFactor(Rest(u))
if m < 0 and n < 0:
return -GCD(-m, -n)
else:
return GCD(m, n)
return S(1)
def NonnumericFactors(u):
if NumberQ(u):
if ZeroQ(Im(u)):
return S(1)
elif ZeroQ(Re(u)):
return I
return u
elif PowerQ(u):
if RationalQ(u.base) and FractionQ(u.exp):
return u/NumericFactor(u)
return u
elif ProductQ(u):
result = 1
for i in u.args:
result *= NonnumericFactors(i)
return result
elif SumQ(u):
if LeafCount(u) < 50:
i = ContentFactor(u)
if SumQ(i):
return u
else:
return NonnumericFactors(i)
n = NumericFactor(u)
result = 0
for i in u.args:
result += i/n
return result
return u
def MakeAssocList(u, x, alst=None):
# (* MakeAssocList[u,x,alst] returns an association list of gensymed symbols with the nonatomic
# parameters of a u that are not integer powers, products or sums. *)
if alst is None:
alst = []
u = replace_pow_exp(u)
x = replace_pow_exp(x)
if AtomQ(u):
return alst
elif IntegerPowerQ(u):
return MakeAssocList(u.base, x, alst)
elif ProductQ(u) or SumQ(u):
return MakeAssocList(Rest(u), x, MakeAssocList(First(u), x, alst))
elif FreeQ(u, x):
tmp = []
for i in alst:
if PowerQ(i):
if i.exp == u:
tmp.append(i)
break
elif len(i.args) > 1: # make sure args has length > 1, else causes index error some times
if i.args[1] == u:
tmp.append(i)
break
if tmp == []:
alst.append(u)
return alst
return alst
def GensymSubst(u, x, alst=None):
# (* GensymSubst[u,x,alst] returns u with the kernels in alst free of x replaced by gensymed names. *)
if alst is None:
alst =[]
u = replace_pow_exp(u)
x = replace_pow_exp(x)
if AtomQ(u):
return u
elif IntegerPowerQ(u):
return GensymSubst(u.base, x, alst)**u.exp
elif ProductQ(u) or SumQ(u):
return u.func(*[GensymSubst(i, x, alst) for i in u.args])
elif FreeQ(u, x):
tmp = []
for i in alst:
if PowerQ(i):
if i.exp == u:
tmp.append(i)
break
elif len(i.args) > 1: # make sure args has length > 1, else causes index error some times
if i.args[1] == u:
tmp.append(i)
break
if tmp == []:
return u
return tmp[0][0]
return u
def KernelSubst(u, x, alst):
# (* KernelSubst[u,x,alst] returns u with the gensymed names in alst replaced by kernels free of x. *)
if AtomQ(u):
tmp = []
for i in alst:
if i.args[0] == u:
tmp.append(i)
break
if tmp == []:
return u
elif len(tmp[0].args) > 1: # make sure args has length > 1, else causes index error some times
return tmp[0].args[1]
elif IntegerPowerQ(u):
tmp = KernelSubst(u.base, x, alst)
if u.exp < 0 and ZeroQ(tmp):
return 'Indeterminate'
return tmp**u.exp
elif ProductQ(u) or SumQ(u):
return u.func(*[KernelSubst(i, x, alst) for i in u.args])
return u
def ExpandExpression(u, x):
if AlgebraicFunctionQ(u, x) and Not(RationalFunctionQ(u, x)):
v = ExpandAlgebraicFunction(u, x)
else:
v = S(0)
if SumQ(v):
return ExpandCleanup(v, x)
v = SmartApart(u, x)
if SumQ(v):
return ExpandCleanup(v, x)
v = SmartApart(RationalFunctionFactors(u, x), x, x)
if SumQ(v):
w = NonrationalFunctionFactors(u, x)
return ExpandCleanup(v.func(*[i*w for i in v.args]), x)
v = Expand(u)
if SumQ(v):
return ExpandCleanup(v, x)
v = Expand(u)
if SumQ(v):
return ExpandCleanup(v, x)
return SimplifyTerm(u, x)
def Apart(u, x):
if RationalFunctionQ(u, x):
return apart(u, x)
return u
def SmartApart(*args):
if len(args) == 2:
u, x = args
alst = MakeAssocList(u, x)
tmp = KernelSubst(Apart(GensymSubst(u, x, alst), x), x, alst)
if tmp == 'Indeterminate':
return u
return tmp
u, v, x = args
alst = MakeAssocList(u, x)
tmp = KernelSubst(Apart(GensymSubst(u, x, alst), x), x, alst)
if tmp == 'Indeterminate':
return u
return tmp
def MatchQ(expr, pattern, *var):
# returns the matched arguments after matching pattern with expression
match = expr.match(pattern)
if match:
return tuple(match[i] for i in var)
else:
return None
def PolynomialQuotientRemainder(p, q, x):
return [PolynomialQuotient(p, q, x), PolynomialRemainder(p, q, x)]
def FreeFactors(u, x):
# returns the product of the factors of u free of x.
if ProductQ(u):
result = 1
for i in u.args:
if FreeQ(i, x):
result *= i
return result
elif FreeQ(u, x):
return u
else:
return S(1)
def NonfreeFactors(u, x):
"""
Returns the product of the factors of u not free of x.
Examples
========
>>> from sympy.integrals.rubi.utility_function import NonfreeFactors
>>> from sympy.abc import x, a, b
>>> NonfreeFactors(a, x)
1
>>> NonfreeFactors(x + a, x)
a + x
>>> NonfreeFactors(a*b*x, x)
x
"""
if ProductQ(u):
result = 1
for i in u.args:
if not FreeQ(i, x):
result *= i
return result
elif FreeQ(u, x):
return 1
else:
return u
def RemoveContentAux(expr, x):
return RemoveContentAux_replacer.replace(UtilityOperator(expr, x))
def RemoveContent(u, x):
v = NonfreeFactors(u, x)
w = Together(v)
if EqQ(FreeFactors(w, x), 1):
return RemoveContentAux(v, x)
else:
return RemoveContentAux(NonfreeFactors(w, x), x)
def FreeTerms(u, x):
"""
Returns the sum of the terms of u free of x.
Examples
========
>>> from sympy.integrals.rubi.utility_function import FreeTerms
>>> from sympy.abc import x, a, b
>>> FreeTerms(a, x)
a
>>> FreeTerms(x*a, x)
0
>>> FreeTerms(a*x + b, x)
b
"""
if SumQ(u):
result = 0
for i in u.args:
if FreeQ(i, x):
result += i
return result
elif FreeQ(u, x):
return u
else:
return 0
def NonfreeTerms(u, x):
# returns the sum of the terms of u free of x.
if SumQ(u):
result = S(0)
for i in u.args:
if not FreeQ(i, x):
result += i
return result
elif not FreeQ(u, x):
return u
else:
return S(0)
def ExpandAlgebraicFunction(expr, x):
if ProductQ(expr):
u_ = Wild('u', exclude=[x])
n_ = Wild('n', exclude=[x])
v_ = Wild('v')
pattern = u_*v_
match = expr.match(pattern)
if match:
keys = [u_, v_]
if len(keys) == len(match):
u, v = tuple([match[i] for i in keys])
if SumQ(v):
u, v = v, u
if not FreeQ(u, x) and SumQ(u):
result = 0
for i in u.args:
result += i*v
return result
pattern = u_**n_*v_
match = expr.match(pattern)
if match:
keys = [u_, n_, v_]
if len(keys) == len(match):
u, n, v = tuple([match[i] for i in keys])
if PositiveIntegerQ(n) and SumQ(u):
w = Expand(u**n)
result = 0
for i in w.args:
result += i*v
return result
return expr
def CollectReciprocals(expr, x):
# Basis: e/(a+b x)+f/(c+d x)==(c e+a f+(d e+b f) x)/(a c+(b c+a d) x+b d x^2)
if SumQ(expr):
u_ = Wild('u')
a_ = Wild('a', exclude=[x])
b_ = Wild('b', exclude=[x])
c_ = Wild('c', exclude=[x])
d_ = Wild('d', exclude=[x])
e_ = Wild('e', exclude=[x])
f_ = Wild('f', exclude=[x])
pattern = u_ + e_/(a_ + b_*x) + f_/(c_+d_*x)
match = expr.match(pattern)
if match:
try: # .match() does not work peoperly always
keys = [u_, a_, b_, c_, d_, e_, f_]
u, a, b, c, d, e, f = tuple([match[i] for i in keys])
if ZeroQ(b*c + a*d) & ZeroQ(d*e + b*f):
return CollectReciprocals(u + (c*e + a*f)/(a*c + b*d*x**2),x)
elif ZeroQ(b*c + a*d) & ZeroQ(c*e + a*f):
return CollectReciprocals(u + (d*e + b*f)*x/(a*c + b*d*x**2),x)
except:
pass
return expr
def ExpandCleanup(u, x):
v = CollectReciprocals(u, x)
if SumQ(v):
res = 0
for i in v.args:
res += SimplifyTerm(i, x)
v = res
if SumQ(v):
return UnifySum(v, x)
else:
return v
else:
return v
def AlgebraicFunctionQ(u, x, flag=False):
if ListQ(u):
if u == []:
return True
elif AlgebraicFunctionQ(First(u), x, flag):
return AlgebraicFunctionQ(Rest(u), x, flag)
else:
return False
elif AtomQ(u) or FreeQ(u, x):
return True
elif PowerQ(u):
if RationalQ(u.exp) | flag & FreeQ(u.exp, x):
return AlgebraicFunctionQ(u.base, x, flag)
elif ProductQ(u) | SumQ(u):
for i in u.args:
if not AlgebraicFunctionQ(i, x, flag):
return False
return True
return False
def Coeff(expr, form, n=1):
if n == 1:
return Coefficient(Together(expr), form, n)
else:
coef1 = Coefficient(expr, form, n)
coef2 = Coefficient(Together(expr), form, n)
if Simplify(coef1 - coef2) == 0:
return coef1
else:
return coef2
def LeadTerm(u):
if SumQ(u):
return First(u)
return u
def RemainingTerms(u):
if SumQ(u):
return Rest(u)
return u
def LeadFactor(u):
# returns the leading factor of u.
if ComplexNumberQ(u) and Re(u) == 0:
if Im(u) == S(1):
return u
else:
return LeadFactor(Im(u))
elif ProductQ(u):
return LeadFactor(First(u))
return u
def RemainingFactors(u):
# returns the remaining factors of u.
if ComplexNumberQ(u) and Re(u) == 0:
if Im(u) == 1:
return S(1)
else:
return I*RemainingFactors(Im(u))
elif ProductQ(u):
return RemainingFactors(First(u))*Rest(u)
return S(1)
def LeadBase(u):
"""
returns the base of the leading factor of u.
Examples
========
>>> from sympy.integrals.rubi.utility_function import LeadBase
>>> from sympy.abc import a, b, c
>>> LeadBase(a**b)
a
>>> LeadBase(a**b*c)
a
"""
v = LeadFactor(u)
if PowerQ(v):
return v.base
return v
def LeadDegree(u):
# returns the degree of the leading factor of u.
v = LeadFactor(u)
if PowerQ(v):
return v.exp
return v
def Numer(expr):
# returns the numerator of u.
if PowerQ(expr):
if expr.exp < 0:
return 1
if ProductQ(expr):
return Mul(*[Numer(i) for i in expr.args])
return Numerator(expr)
def Denom(u):
# returns the denominator of u
if PowerQ(u):
if u.exp < 0:
return u.args[0]**(-u.args[1])
elif ProductQ(u):
return Mul(*[Denom(i) for i in u.args])
return Denominator(u)
def hypergeom(n, d, z):
return hyper(n, d, z)
def Expon(expr, form):
return Exponent(Together(expr), form)
def MergeMonomials(expr, x):
u_ = Wild('u')
p_ = Wild('p', exclude=[x, 1, 0])
a_ = Wild('a', exclude=[x])
b_ = Wild('b', exclude=[x, 0])
c_ = Wild('c', exclude=[x])
d_ = Wild('d', exclude=[x, 0])
n_ = Wild('n', exclude=[x])
m_ = Wild('m', exclude=[x])
# Basis: If m/n\[Element]\[DoubleStruckCapitalZ], then z^m (c z^n)^p==(c z^n)^(m/n+p)/c^(m/n)
pattern = u_*(a_ + b_*x)**m_*(c_*(a_ + b_*x)**n_)**p_
match = expr.match(pattern)
if match:
keys = [u_, a_, b_, m_, c_, n_, p_]
if len(keys) == len(match):
u, a, b, m, c, n, p = tuple([match[i] for i in keys])
if IntegerQ(m/n):
if u*(c*(a + b*x)**n)**(m/n + p)/c**(m/n) is S.NaN:
return expr
else:
return u*(c*(a + b*x)**n)**(m/n + p)/c**(m/n)
# Basis: If m\[Element]\[DoubleStruckCapitalZ] \[And] b c-a d==0, then (a+b z)^m==b^m/d^m (c+d z)^m
pattern = u_*(a_ + b_*x)**m_*(c_ + d_*x)**n_
match = expr.match(pattern)
if match:
keys = [u_, a_, b_, m_, c_, d_, n_]
if len(keys) == len(match):
u, a, b, m, c, d, n = tuple([match[i] for i in keys])
if IntegerQ(m) and ZeroQ(b*c - a*d):
if u*b**m/d**m*(c + d*x)**(m + n) is S.NaN:
return expr
else:
return u*b**m/d**m*(c + d*x)**(m + n)
return expr
def PolynomialDivide(u, v, x):
quo = PolynomialQuotient(u, v, x)
rem = PolynomialRemainder(u, v, x)
s = 0
for i in ExponentList(quo, x):
s += Simp(Together(Coefficient(quo, x, i)*x**i), x)
quo = s
rem = Together(rem)
free = FreeFactors(rem, x)
rem = NonfreeFactors(rem, x)
monomial = x**Min(*ExponentList(rem, x))
if NegQ(Coefficient(rem, x, 0)):
monomial = -monomial
s = 0
for i in ExponentList(rem, x):
s += Simp(Together(Coefficient(rem, x, i)*x**i/monomial), x)
rem = s
if BinomialQ(v, x):
return quo + free*monomial*rem/ExpandToSum(v, x)
else:
return quo + free*monomial*rem/v
def BinomialQ(u, x, n=None):
"""
If u is equivalent to an expression of the form a + b*x**n, BinomialQ(u, x, n) returns True, else it returns False.
Examples
========
>>> from sympy.integrals.rubi.utility_function import BinomialQ
>>> from sympy.abc import x
>>> BinomialQ(x**9, x)
True
>>> BinomialQ((1 + x)**3, x)
False
"""
if ListQ(u):
for i in u:
if Not(BinomialQ(i, x, n)):
return False
return True
elif NumberQ(x):
return False
return ListQ(BinomialParts(u, x))
def TrinomialQ(u, x):
"""
If u is equivalent to an expression of the form a + b*x**n + c*x**(2*n) where n, b and c are not 0,
TrinomialQ(u, x) returns True, else it returns False.
Examples
========
>>> from sympy.integrals.rubi.utility_function import TrinomialQ
>>> from sympy.abc import x
>>> TrinomialQ((7 + 2*x**6 + 3*x**12), x)
True
>>> TrinomialQ(x**2, x)
False
"""
if ListQ(u):
for i in u.args:
if Not(TrinomialQ(i, x)):
return False
return True
check = False
u = replace_pow_exp(u)
if PowerQ(u):
if u.exp == 2 and BinomialQ(u.base, x):
check = True
return ListQ(TrinomialParts(u,x)) and Not(QuadraticQ(u, x)) and Not(check)
def GeneralizedBinomialQ(u, x):
"""
If u is equivalent to an expression of the form a*x**q+b*x**n where n, q and b are not 0,
GeneralizedBinomialQ(u, x) returns True, else it returns False.
Examples
========
>>> from sympy.integrals.rubi.utility_function import GeneralizedBinomialQ
>>> from sympy.abc import a, x, q, b, n
>>> GeneralizedBinomialQ(a*x**q, x)
False
"""
if ListQ(u):
return all(GeneralizedBinomialQ(i, x) for i in u)
return ListQ(GeneralizedBinomialParts(u, x))
def GeneralizedTrinomialQ(u, x):
"""
If u is equivalent to an expression of the form a*x**q+b*x**n+c*x**(2*n-q) where n, q, b and c are not 0,
GeneralizedTrinomialQ(u, x) returns True, else it returns False.
Examples
========
>>> from sympy.integrals.rubi.utility_function import GeneralizedTrinomialQ
>>> from sympy.abc import x
>>> GeneralizedTrinomialQ(7 + 2*x**6 + 3*x**12, x)
False
"""
if ListQ(u):
return all(GeneralizedTrinomialQ(i, x) for i in u)
return ListQ(GeneralizedTrinomialParts(u, x))
def FactorSquareFreeList(poly):
r = sqf_list(poly)
result = [[1, 1]]
for i in r[1]:
result.append(list(i))
return result
def PerfectPowerTest(u, x):
# If u (x) is equivalent to a polynomial raised to an integer power greater than 1,
# PerfectPowerTest[u,x] returns u (x) as an expanded polynomial raised to the power;
# else it returns False.
if PolynomialQ(u, x):
lst = FactorSquareFreeList(u)
gcd = 0
v = 1
if lst[0] == [1, 1]:
lst = Rest(lst)
for i in lst:
gcd = GCD(gcd, i[1])
if gcd > 1:
for i in lst:
v = v*i[0]**(i[1]/gcd)
return Expand(v)**gcd
else:
return False
return False
def SquareFreeFactorTest(u, x):
# If u (x) can be square free factored, SquareFreeFactorTest[u,x] returns u (x) in
# factored form; else it returns False.
if PolynomialQ(u, x):
v = FactorSquareFree(u)
if PowerQ(v) or ProductQ(v):
return v
return False
return False
def RationalFunctionQ(u, x):
# If u is a rational function of x, RationalFunctionQ[u,x] returns True; else it returns False.
if AtomQ(u) or FreeQ(u, x):
return True
elif IntegerPowerQ(u):
return RationalFunctionQ(u.base, x)
elif ProductQ(u) or SumQ(u):
for i in u.args:
if Not(RationalFunctionQ(i, x)):
return False
return True
return False
def RationalFunctionFactors(u, x):
# RationalFunctionFactors[u,x] returns the product of the factors of u that are rational functions of x.
if ProductQ(u):
res = 1
for i in u.args:
if RationalFunctionQ(i, x):
res *= i
return res
elif RationalFunctionQ(u, x):
return u
return S(1)
def NonrationalFunctionFactors(u, x):
if ProductQ(u):
res = 1
for i in u.args:
if not RationalFunctionQ(i, x):
res *= i
return res
elif RationalFunctionQ(u, x):
return S(1)
return u
def Reverse(u):
if isinstance(u, list):
return list(reversed(u))
else:
l = list(u.args)
return u.func(*list(reversed(l)))
def RationalFunctionExponents(u, x):
"""
u is a polynomial or rational function of x.
RationalFunctionExponents(u, x) returns a list of the exponent of the
numerator of u and the exponent of the denominator of u.
Examples
========
>>> from sympy.integrals.rubi.utility_function import RationalFunctionExponents
>>> from sympy.abc import x, a
>>> RationalFunctionExponents(x, x)
[1, 0]
>>> RationalFunctionExponents(x**(-1), x)
[0, 1]
>>> RationalFunctionExponents(x**(-1)*a, x)
[0, 1]
"""
if PolynomialQ(u, x):
return [Exponent(u, x), 0]
elif IntegerPowerQ(u):
if PositiveQ(u.exp):
return u.exp*RationalFunctionExponents(u.base, x)
return (-u.exp)*Reverse(RationalFunctionExponents(u.base, x))
elif ProductQ(u):
lst1 = RationalFunctionExponents(First(u), x)
lst2 = RationalFunctionExponents(Rest(u), x)
return [lst1[0] + lst2[0], lst1[1] + lst2[1]]
elif SumQ(u):
v = Together(u)
if SumQ(v):
lst1 = RationalFunctionExponents(First(u), x)
lst2 = RationalFunctionExponents(Rest(u), x)
return [Max(lst1[0] + lst2[1], lst2[0] + lst1[1]), lst1[1] + lst2[1]]
else:
return RationalFunctionExponents(v, x)
return [0, 0]
def RationalFunctionExpand(expr, x):
# expr is a polynomial or rational function of x.
# RationalFunctionExpand[u,x] returns the expansion of the factors of u that are rational functions times the other factors.
def cons_f1(n):
return FractionQ(n)
cons1 = CustomConstraint(cons_f1)
def cons_f2(x, v):
if not isinstance(x, Symbol):
return False
return UnsameQ(v, x)
cons2 = CustomConstraint(cons_f2)
def With1(n, u, x, v):
w = RationalFunctionExpand(u, x)
return If(SumQ(w), Add(*[i*v**n for i in w.args]), v**n*w)
pattern1 = Pattern(UtilityOperator(u_*v_**n_, x_), cons1, cons2)
rule1 = ReplacementRule(pattern1, With1)
def With2(u, x):
v = ExpandIntegrand(u, x)
def _consf_u(a, b, c, d, p, m, n, x):
return And(FreeQ(List(a, b, c, d, p), x), IntegersQ(m, n), Equal(m, Add(n, S(-1))))
cons_u = CustomConstraint(_consf_u)
pat = Pattern(UtilityOperator(x_**WC('m', S(1))*(x_*WC('d', S(1)) + c_)**p_/(x_**n_*WC('b', S(1)) + a_), x_), cons_u)
result_matchq = is_match(UtilityOperator(u, x), pat)
if UnsameQ(v, u) and not result_matchq:
return v
else:
v = ExpandIntegrand(RationalFunctionFactors(u, x), x)
w = NonrationalFunctionFactors(u, x)
if SumQ(v):
return Add(*[i*w for i in v.args])
else:
return v*w
pattern2 = Pattern(UtilityOperator(u_, x_))
rule2 = ReplacementRule(pattern2, With2)
expr = expr.replace(sym_exp, rubi_exp)
res = replace_all(UtilityOperator(expr, x), [rule1, rule2])
return replace_pow_exp(res)
def ExpandIntegrand(expr, x, extra=None):
expr = replace_pow_exp(expr)
if extra is not None:
extra, x = x, extra
w = ExpandIntegrand(extra, x)
r = NonfreeTerms(w, x)
if SumQ(r):
result = [expr*FreeTerms(w, x)]
for i in r.args:
result.append(MergeMonomials(expr*i, x))
return r.func(*result)
else:
return expr*FreeTerms(w, x) + MergeMonomials(expr*r, x)
else:
u_ = Wild('u', exclude=[0, 1])
a_ = Wild('a', exclude=[x])
b_ = Wild('b', exclude=[x, 0])
F_ = Wild('F', exclude=[0])
c_ = Wild('c', exclude=[x])
d_ = Wild('d', exclude=[x, 0])
n_ = Wild('n', exclude=[0, 1])
pattern = u_*(a_ + b_*F_)**n_
match = expr.match(pattern)
if match:
if MemberQ([asin, acos, asinh, acosh], match[F_].func):
keys = [u_, a_, b_, F_, n_]
if len(match) == len(keys):
u, a, b, F, n = tuple([match[i] for i in keys])
match = F.args[0].match(c_ + d_*x)
if match:
keys = c_, d_
if len(keys) == len(match):
c, d = tuple([match[i] for i in keys])
if PolynomialQ(u, x):
F = F.func
return ExpandLinearProduct((a + b*F(c + d*x))**n, u, c, d, x)
expr = expr.replace(sym_exp, rubi_exp)
res = replace_all(UtilityOperator(expr, x), ExpandIntegrand_rules, max_count = 1)
return replace_pow_exp(res)
def SimplerQ(u, v):
# If u is simpler than v, SimplerQ(u, v) returns True, else it returns False. SimplerQ(u, u) returns False
if IntegerQ(u):
if IntegerQ(v):
if Abs(u)==Abs(v):
return v<0
else:
return Abs(u)<Abs(v)
else:
return True
elif IntegerQ(v):
return False
elif FractionQ(u):
if FractionQ(v):
if Denominator(u) == Denominator(v):
return SimplerQ(Numerator(u), Numerator(v))
else:
return Denominator(u)<Denominator(v)
else:
return True
elif FractionQ(v):
return False
elif (Re(u)==0 or Re(u) == 0) and (Re(v)==0 or Re(v) == 0):
return SimplerQ(Im(u), Im(v))
elif ComplexNumberQ(u):
if ComplexNumberQ(v):
if Re(u) == Re(v):
return SimplerQ(Im(u), Im(v))
else:
return SimplerQ(Re(u),Re(v))
else:
return False
elif NumberQ(u):
if NumberQ(v):
return OrderedQ([u,v])
else:
return True
elif NumberQ(v):
return False
elif AtomQ(u) or (Head(u) == re) or (Head(u) == im):
if AtomQ(v) or (Head(u) == re) or (Head(u) == im):
return OrderedQ([u,v])
else:
return True
elif AtomQ(v) or (Head(u) == re) or (Head(u) == im):
return False
elif Head(u) == Head(v):
if Length(u) == Length(v):
for i in range(len(u.args)):
if not u.args[i] == v.args[i]:
return SimplerQ(u.args[i], v.args[i])
return False
return Length(u) < Length(v)
elif LeafCount(u) < LeafCount(v):
return True
elif LeafCount(v) < LeafCount(u):
return False
return Not(OrderedQ([v,u]))
def SimplerSqrtQ(u, v):
# If Rt(u, 2) is simpler than Rt(v, 2), SimplerSqrtQ(u, v) returns True, else it returns False. SimplerSqrtQ(u, u) returns False
if NegativeQ(v) and Not(NegativeQ(u)):
return True
if NegativeQ(u) and Not(NegativeQ(v)):
return False
sqrtu = Rt(u, S(2))
sqrtv = Rt(v, S(2))
if IntegerQ(sqrtu):
if IntegerQ(sqrtv):
return sqrtu<sqrtv
else:
return True
if IntegerQ(sqrtv):
return False
if RationalQ(sqrtu):
if RationalQ(sqrtv):
return sqrtu<sqrtv
else:
return True
if RationalQ(sqrtv):
return False
if PosQ(u):
if PosQ(v):
return LeafCount(sqrtu)<LeafCount(sqrtv)
else:
return True
if PosQ(v):
return False
if LeafCount(sqrtu)<LeafCount(sqrtv):
return True
if LeafCount(sqrtv)<LeafCount(sqrtu):
return False
else:
return Not(OrderedQ([v, u]))
def SumSimplerQ(u, v):
"""
If u + v is simpler than u, SumSimplerQ(u, v) returns True, else it returns False.
If for every term w of v there is a term of u equal to n*w where n<-1/2, u + v will be simpler than u.
Examples
========
>>> from sympy.integrals.rubi.utility_function import SumSimplerQ
>>> from sympy.abc import x
>>> from sympy import S
>>> SumSimplerQ(S(4 + x),S(3 + x**3))
False
"""
if RationalQ(u, v):
if v == S(0):
return False
elif v > S(0):
return u < -S(1)
else:
return u >= -v
else:
return SumSimplerAuxQ(Expand(u), Expand(v))
def BinomialDegree(u, x):
# if u is a binomial. BinomialDegree[u,x] returns the degree of x in u.
bp = BinomialParts(u, x)
if bp == False:
return bp
return bp[2]
def TrinomialDegree(u, x):
# If u is equivalent to a trinomial of the form a + b*x^n + c*x^(2*n) where n!=0, b!=0 and c!=0, TrinomialDegree[u,x] returns n
t = TrinomialParts(u, x)
if t:
return t[3]
return t
def CancelCommonFactors(u, v):
def _delete_cases(a, b):
# only for CancelCommonFactors
lst = []
deleted = False
for i in a.args:
if i == b and not deleted:
deleted = True
continue
lst.append(i)
return a.func(*lst)
# CancelCommonFactors[u,v] returns {u',v'} are the noncommon factors of u and v respectively.
if ProductQ(u):
if ProductQ(v):
if MemberQ(v, First(u)):
return CancelCommonFactors(Rest(u), _delete_cases(v, First(u)))
else:
lst = CancelCommonFactors(Rest(u), v)
return [First(u)*lst[0], lst[1]]
else:
if MemberQ(u, v):
return [_delete_cases(u, v), 1]
else:
return[u, v]
elif ProductQ(v):
if MemberQ(v, u):
return [1, _delete_cases(v, u)]
else:
return [u, v]
return[u, v]
def SimplerIntegrandQ(u, v, x):
lst = CancelCommonFactors(u, v)
u1 = lst[0]
v1 = lst[1]
if Head(u1) == Head(v1) and Length(u1) == 1 and Length(v1) == 1:
return SimplerIntegrandQ(u1.args[0], v1.args[0], x)
if 4*LeafCount(u1) < 3*LeafCount(v1):
return True
if RationalFunctionQ(u1, x):
if RationalFunctionQ(v1, x):
t1 = 0
t2 = 0
for i in RationalFunctionExponents(u1, x):
t1 += i
for i in RationalFunctionExponents(v1, x):
t2 += i
return t1 < t2
else:
return True
else:
return False
def GeneralizedBinomialDegree(u, x):
b = GeneralizedBinomialParts(u, x)
if b:
return b[2] - b[3]
def GeneralizedBinomialParts(expr, x):
expr = Expand(expr)
if GeneralizedBinomialMatchQ(expr, x):
a = Wild('a', exclude=[x])
b = Wild('b', exclude=[x])
n = Wild('n', exclude=[x])
q = Wild('q', exclude=[x])
Match = expr.match(a*x**q + b*x**n)
if Match and PosQ(Match[q] - Match[n]):
return [Match[b], Match[a], Match[q], Match[n]]
else:
return False
def GeneralizedTrinomialDegree(u, x):
t = GeneralizedTrinomialParts(u, x)
if t:
return t[3] - t[4]
def GeneralizedTrinomialParts(expr, x):
expr = Expand(expr)
if GeneralizedTrinomialMatchQ(expr, x):
a = Wild('a', exclude=[x, 0])
b = Wild('b', exclude=[x, 0])
c = Wild('c', exclude=[x])
n = Wild('n', exclude=[x, 0])
q = Wild('q', exclude=[x])
Match = expr.match(a*x**q + b*x**n+c*x**(2*n-q))
if Match and expr.is_Add:
return [Match[c], Match[b], Match[a], Match[n], 2*Match[n]-Match[q]]
else:
return False
def MonomialQ(u, x):
# If u is of the form a*x^n where n!=0 and a!=0, MonomialQ[u,x] returns True; else False
if isinstance(u, list):
return all(MonomialQ(i, x) for i in u)
else:
a = Wild('a', exclude=[x])
b = Wild('b', exclude=[x])
re = u.match(a*x**b)
if re:
return True
return False
def MonomialSumQ(u, x):
# if u(x) is a sum and each term is free of x or an expression of the form a*x^n, MonomialSumQ(u, x) returns True; else it returns False
if SumQ(u):
for i in u.args:
if Not(FreeQ(i, x) or MonomialQ(i, x)):
return False
return True
@doctest_depends_on(modules=('matchpy',))
def MinimumMonomialExponent(u, x):
"""
u is sum whose terms are monomials. MinimumMonomialExponent(u, x) returns the exponent of the term having the smallest exponent
Examples
========
>>> from sympy.integrals.rubi.utility_function import MinimumMonomialExponent
>>> from sympy.abc import x
>>> MinimumMonomialExponent(x**2 + 5*x**2 + 3*x**5, x)
2
>>> MinimumMonomialExponent(x**2 + 5*x**2 + 1, x)
0
"""
n =MonomialExponent(First(u), x)
for i in u.args:
if PosQ(n - MonomialExponent(i, x)):
n = MonomialExponent(i, x)
return n
def MonomialExponent(u, x):
# u is a monomial. MonomialExponent(u, x) returns the exponent of x in u
a = Wild('a', exclude=[x])
b = Wild('b', exclude=[x])
re = u.match(a*x**b)
if re:
return re[b]
def LinearMatchQ(u, x):
# LinearMatchQ(u, x) returns True iff u matches patterns of the form a+b*x where a and b are free of x
if isinstance(u, list):
return all(LinearMatchQ(i, x) for i in u)
else:
a = Wild('a', exclude=[x])
b = Wild('b', exclude=[x])
re = u.match(a + b*x)
if re:
return True
return False
def PowerOfLinearMatchQ(u, x):
if isinstance(u, list):
for i in u:
if not PowerOfLinearMatchQ(i, x):
return False
return True
else:
a = Wild('a', exclude=[x])
b = Wild('b', exclude=[x, 0])
m = Wild('m', exclude=[x, 0])
Match = u.match((a + b*x)**m)
if Match:
return True
else:
return False
def QuadraticMatchQ(u, x):
if ListQ(u):
return all(QuadraticMatchQ(i, x) for i in u)
pattern1 = Pattern(UtilityOperator(x_**2*WC('c', 1) + x_*WC('b', 1) + WC('a', 0), x_), CustomConstraint(lambda a, b, c, x: FreeQ([a, b, c], x)))
pattern2 = Pattern(UtilityOperator(x_**2*WC('c', 1) + WC('a', 0), x_), CustomConstraint(lambda a, c, x: FreeQ([a, c], x)))
u1 = UtilityOperator(u, x)
return is_match(u1, pattern1) or is_match(u1, pattern2)
def CubicMatchQ(u, x):
if isinstance(u, list):
return all(CubicMatchQ(i, x) for i in u)
else:
pattern1 = Pattern(UtilityOperator(x_**3*WC('d', 1) + x_**2*WC('c', 1) + x_*WC('b', 1) + WC('a', 0), x_), CustomConstraint(lambda a, b, c, d, x: FreeQ([a, b, c, d], x)))
pattern2 = Pattern(UtilityOperator(x_**3*WC('d', 1) + x_*WC('b', 1) + WC('a', 0), x_), CustomConstraint(lambda a, b, d, x: FreeQ([a, b, d], x)))
pattern3 = Pattern(UtilityOperator(x_**3*WC('d', 1) + x_**2*WC('c', 1) + WC('a', 0), x_), CustomConstraint(lambda a, c, d, x: FreeQ([a, c, d], x)))
pattern4 = Pattern(UtilityOperator(x_**3*WC('d', 1) + WC('a', 0), x_), CustomConstraint(lambda a, d, x: FreeQ([a, d], x)))
u1 = UtilityOperator(u, x)
if is_match(u1, pattern1) or is_match(u1, pattern2) or is_match(u1, pattern3) or is_match(u1, pattern4):
return True
else:
return False
def BinomialMatchQ(u, x):
if isinstance(u, list):
return all(BinomialMatchQ(i, x) for i in u)
else:
pattern = Pattern(UtilityOperator(x_**WC('n', S(1))*WC('b', S(1)) + WC('a', S(0)), x_) , CustomConstraint(lambda a, b, n, x: FreeQ([a,b,n],x)))
u = UtilityOperator(u, x)
return is_match(u, pattern)
def TrinomialMatchQ(u, x):
if isinstance(u, list):
return all(TrinomialMatchQ(i, x) for i in u)
else:
pattern = Pattern(UtilityOperator(x_**WC('j', S(1))*WC('c', S(1)) + x_**WC('n', S(1))*WC('b', S(1)) + WC('a', S(0)), x_) , CustomConstraint(lambda a, b, c, n, x: FreeQ([a, b, c, n], x)), CustomConstraint(lambda j, n: ZeroQ(j-2*n) ))
u = UtilityOperator(u, x)
return is_match(u, pattern)
def GeneralizedBinomialMatchQ(u, x):
if isinstance(u, list):
return all(GeneralizedBinomialMatchQ(i, x) for i in u)
else:
a = Wild('a', exclude=[x, 0])
b = Wild('b', exclude=[x, 0])
n = Wild('n', exclude=[x, 0])
q = Wild('q', exclude=[x, 0])
Match = u.match(a*x**q + b*x**n)
if Match and len(Match) == 4 and Match[q] != 0 and Match[n] != 0:
return True
else:
return False
def GeneralizedTrinomialMatchQ(u, x):
if isinstance(u, list):
return all(GeneralizedTrinomialMatchQ(i, x) for i in u)
else:
a = Wild('a', exclude=[x, 0])
b = Wild('b', exclude=[x, 0])
n = Wild('n', exclude=[x, 0])
c = Wild('c', exclude=[x, 0])
q = Wild('q', exclude=[x, 0])
Match = u.match(a*x**q + b*x**n + c*x**(2*n - q))
if Match and len(Match) == 5 and 2*Match[n] - Match[q] != 0 and Match[n] != 0:
return True
else:
return False
def QuotientOfLinearsMatchQ(u, x):
if isinstance(u, list):
return all(QuotientOfLinearsMatchQ(i, x) for i in u)
else:
a = Wild('a', exclude=[x])
b = Wild('b', exclude=[x])
d = Wild('d', exclude=[x])
c = Wild('c', exclude=[x])
e = Wild('e')
Match = u.match(e*(a + b*x)/(c + d*x))
if Match and len(Match) == 5:
return True
else:
return False
def PolynomialTermQ(u, x):
a = Wild('a', exclude=[x])
n = Wild('n', exclude=[x])
Match = u.match(a*x**n)
if Match and IntegerQ(Match[n]) and Greater(Match[n], S(0)):
return True
else:
return False
def PolynomialTerms(u, x):
s = 0
for i in u.args:
if PolynomialTermQ(i, x):
s = s + i
return s
def NonpolynomialTerms(u, x):
s = 0
for i in u.args:
if not PolynomialTermQ(i, x):
s = s + i
return s
def PseudoBinomialParts(u, x):
if PolynomialQ(u, x) and Greater(Expon(u, x), S(2)):
n = Expon(u, x)
d = Rt(Coefficient(u, x, n), n)
c = d**(-n + S(1))*Coefficient(u, x, n + S(-1))/n
a = Simplify(u - (c + d*x)**n)
if NonzeroQ(a) and FreeQ(a, x):
return [a, S(1), c, d, n]
else:
return False
else:
return False
def NormalizePseudoBinomial(u, x):
lst = PseudoBinomialParts(u, x)
if lst:
return (lst[0] + lst[1]*(lst[2] + lst[3]*x)**lst[4])
def PseudoBinomialPairQ(u, v, x):
lst1 = PseudoBinomialParts(u, x)
if AtomQ(lst1):
return False
else:
lst2 = PseudoBinomialParts(v, x)
if AtomQ(lst2):
return False
else:
return Drop(lst1, 2) == Drop(lst2, 2)
def PseudoBinomialQ(u, x):
lst = PseudoBinomialParts(u, x)
if lst:
return True
else:
return False
def PolynomialGCD(f, g):
return gcd(f, g)
def PolyGCD(u, v, x):
# (* u and v are polynomials in x. *)
# (* PolyGCD[u,v,x] returns the factors of the gcd of u and v dependent on x. *)
return NonfreeFactors(PolynomialGCD(u, v), x)
def AlgebraicFunctionFactors(u, x, flag=False):
# (* AlgebraicFunctionFactors[u,x] returns the product of the factors of u that are algebraic functions of x. *)
if ProductQ(u):
result = 1
for i in u.args:
if AlgebraicFunctionQ(i, x, flag):
result *= i
return result
if AlgebraicFunctionQ(u, x, flag):
return u
return 1
def NonalgebraicFunctionFactors(u, x):
"""
NonalgebraicFunctionFactors[u,x] returns the product of the factors of u that are not algebraic functions of x.
Examples
========
>>> from sympy.integrals.rubi.utility_function import NonalgebraicFunctionFactors
>>> from sympy.abc import x
>>> from sympy import sin
>>> NonalgebraicFunctionFactors(sin(x), x)
sin(x)
>>> NonalgebraicFunctionFactors(x, x)
1
"""
if ProductQ(u):
result = 1
for i in u.args:
if not AlgebraicFunctionQ(i, x):
result *= i
return result
if AlgebraicFunctionQ(u, x):
return 1
return u
def QuotientOfLinearsP(u, x):
if LinearQ(u, x):
return True
elif SumQ(u):
if FreeQ(u.args[0], x):
return QuotientOfLinearsP(Rest(u), x)
elif LinearQ(Numerator(u), x) and LinearQ(Denominator(u), x):
return True
elif ProductQ(u):
if FreeQ(First(u), x):
return QuotientOfLinearsP(Rest(u), x)
elif Numerator(u) == 1 and PowerQ(u):
return QuotientOfLinearsP(Denominator(u), x)
return u == x or FreeQ(u, x)
def QuotientOfLinearsParts(u, x):
# If u is equivalent to an expression of the form (a+b*x)/(c+d*x), QuotientOfLinearsParts[u,x]
# returns the list {a, b, c, d}.
if LinearQ(u, x):
return [Coefficient(u, x, 0), Coefficient(u, x, 1), 1, 0]
elif PowerQ(u):
if Numerator(u) == 1:
u = Denominator(u)
r = QuotientOfLinearsParts(u, x)
return [r[2], r[3], r[0], r[1]]
elif SumQ(u):
a = First(u)
if FreeQ(a, x):
u = Rest(u)
r = QuotientOfLinearsParts(u, x)
return [r[0] + a*r[2], r[1] + a*r[3], r[2], r[3]]
elif ProductQ(u):
a = First(u)
if FreeQ(a, x):
r = QuotientOfLinearsParts(Rest(u), x)
return [a*r[0], a*r[1], r[2], r[3]]
a = Numerator(u)
d = Denominator(u)
if LinearQ(a, x) and LinearQ(d, x):
return [Coefficient(a, x, 0), Coefficient(a, x, 1), Coefficient(d, x, 0), Coefficient(d, x, 1)]
elif u == x:
return [0, 1, 1, 0]
elif FreeQ(u, x):
return [u, 0, 1, 0]
return [u, 0, 1, 0]
def QuotientOfLinearsQ(u, x):
# (*QuotientOfLinearsQ[u,x] returns True iff u is equivalent to an expression of the form (a+b x)/(c+d x) where b!=0 and d!=0.*)
if ListQ(u):
for i in u:
if not QuotientOfLinearsQ(i, x):
return False
return True
q = QuotientOfLinearsParts(u, x)
return QuotientOfLinearsP(u, x) and NonzeroQ(q[1]) and NonzeroQ(q[3])
def Flatten(l):
return flatten(l)
def Sort(u, r=False):
return sorted(u, key=lambda x: x.sort_key(), reverse=r)
# (*Definition: A number is absurd if it is a rational number, a positive rational number raised to a fractional power, or a product of absurd numbers.*)
def AbsurdNumberQ(u):
# (* AbsurdNumberQ[u] returns True if u is an absurd number, else it returns False. *)
if PowerQ(u):
v = u.exp
u = u.base
return RationalQ(u) and u > 0 and FractionQ(v)
elif ProductQ(u):
return all(AbsurdNumberQ(i) for i in u.args)
return RationalQ(u)
def AbsurdNumberFactors(u):
# (* AbsurdNumberFactors[u] returns the product of the factors of u that are absurd numbers. *)
if AbsurdNumberQ(u):
return u
elif ProductQ(u):
result = S(1)
for i in u.args:
if AbsurdNumberQ(i):
result *= i
return result
return NumericFactor(u)
def NonabsurdNumberFactors(u):
# (* NonabsurdNumberFactors[u] returns the product of the factors of u that are not absurd numbers. *)
if AbsurdNumberQ(u):
return S(1)
elif ProductQ(u):
result = 1
for i in u.args:
result *= NonabsurdNumberFactors(i)
return result
return NonnumericFactors(u)
def SumSimplerAuxQ(u, v):
if SumQ(v):
return (RationalQ(First(v)) or SumSimplerAuxQ(u,First(v))) and (RationalQ(Rest(v)) or SumSimplerAuxQ(u,Rest(v)))
elif SumQ(u):
return SumSimplerAuxQ(First(u), v) or SumSimplerAuxQ(Rest(u), v)
else:
return v!=0 and NonnumericFactors(u)==NonnumericFactors(v) and (NumericFactor(u)/NumericFactor(v)<-1/2 or NumericFactor(u)/NumericFactor(v)==-1/2 and NumericFactor(u)<0)
def Prepend(l1, l2):
if not isinstance(l2, list):
return [l2] + l1
return l2 + l1
def Drop(lst, n):
if isinstance(lst, list):
if isinstance(n, list):
lst = lst[:(n[0]-1)] + lst[n[1]:]
elif n > 0:
lst = lst[n:]
elif n < 0:
lst = lst[:-n]
else:
return lst
return lst
return lst.func(*[i for i in Drop(list(lst.args), n)])
def CombineExponents(lst):
if Length(lst) < 2:
return lst
elif lst[0][0] == lst[1][0]:
return CombineExponents(Prepend(Drop(lst,2),[lst[0][0], lst[0][1] + lst[1][1]]))
return Prepend(CombineExponents(Rest(lst)), First(lst))
def FactorInteger(n, l=None):
if isinstance(n, (int, Integer)):
return sorted(factorint(n, limit=l).items())
else:
return sorted(factorrat(n, limit=l).items())
def FactorAbsurdNumber(m):
# (* m must be an absurd number. FactorAbsurdNumber[m] returns the prime factorization of m *)
# (* as list of base-degree pairs where the bases are prime numbers and the degrees are rational. *)
if RationalQ(m):
return FactorInteger(m)
elif PowerQ(m):
r = FactorInteger(m.base)
return [r[0], r[1]*m.exp]
# CombineExponents[Sort[Flatten[Map[FactorAbsurdNumber,Apply[List,m]],1], Function[i1[[1]]<i2[[1]]]]]
return list((m.as_base_exp(),))
def SubstForInverseFunction(*args):
"""
SubstForInverseFunction(u, v, w, x) returns u with subexpressions equal to v replaced by x and x replaced by w.
Examples
========
>>> from sympy.integrals.rubi.utility_function import SubstForInverseFunction
>>> from sympy.abc import x, a, b
>>> SubstForInverseFunction(a, a, b, x)
a
>>> SubstForInverseFunction(x**a, x**a, b, x)
x
>>> SubstForInverseFunction(a*x**a, a, b, x)
a*b**a
"""
if len(args) == 3:
u, v, x = args[0], args[1], args[2]
return SubstForInverseFunction(u, v, (-Coefficient(v.args[0], x, 0) + InverseFunction(Head(v))(x))/Coefficient(v.args[0], x, 1), x)
elif len(args) == 4:
u, v, w, x = args[0], args[1], args[2], args[3]
if AtomQ(u):
if u == x:
return w
return u
elif Head(u) == Head(v) and ZeroQ(u.args[0] - v.args[0]):
return x
res = [SubstForInverseFunction(i, v, w, x) for i in u.args]
return u.func(*res)
def SubstForFractionalPower(u, v, n, w, x):
# (* SubstForFractionalPower[u,v,n,w,x] returns u with subexpressions equal to v^(m/n) replaced
# by x^m and x replaced by w. *)
if AtomQ(u):
if u == x:
return w
return u
elif FractionalPowerQ(u):
if ZeroQ(u.base - v):
return x**(n*u.exp)
res = [SubstForFractionalPower(i, v, n, w, x) for i in u.args]
return u.func(*res)
def SubstForFractionalPowerOfQuotientOfLinears(u, x):
# (* If u has a subexpression of the form ((a+b*x)/(c+d*x))^(m/n) where m and n>1 are integers,
# SubstForFractionalPowerOfQuotientOfLinears[u,x] returns the list {v,n,(a+b*x)/(c+d*x),b*c-a*d} where v is u
# with subexpressions of the form ((a+b*x)/(c+d*x))^(m/n) replaced by x^m and x replaced
lst = FractionalPowerOfQuotientOfLinears(u, 1, False, x)
if AtomQ(lst) or AtomQ(lst[1]):
return False
n = lst[0]
tmp = lst[1]
lst = QuotientOfLinearsParts(tmp, x)
a, b, c, d = lst[0], lst[1], lst[2], lst[3]
if ZeroQ(d):
return False
lst = Simplify(x**(n - 1)*SubstForFractionalPower(u, tmp, n, (-a + c*x**n)/(b - d*x**n), x)/(b - d*x**n)**2)
return [NonfreeFactors(lst, x), n, tmp, FreeFactors(lst, x)*(b*c - a*d)]
def FractionalPowerOfQuotientOfLinears(u, n, v, x):
# (* If u has a subexpression of the form ((a+b*x)/(c+d*x))^(m/n),
# FractionalPowerOfQuotientOfLinears[u,1,False,x] returns {n,(a+b*x)/(c+d*x)}; else it returns False. *)
if AtomQ(u) or FreeQ(u, x):
return [n, v]
elif CalculusQ(u):
return False
elif FractionalPowerQ(u):
if QuotientOfLinearsQ(u.base, x) and Not(LinearQ(u.base, x)) and (FalseQ(v) or ZeroQ(u.base - v)):
return [LCM(Denominator(u.exp), n), u.base]
lst = [n, v]
for i in u.args:
lst = FractionalPowerOfQuotientOfLinears(i, lst[0], lst[1],x)
if AtomQ(lst):
return False
return lst
def SubstForFractionalPowerQ(u, v, x):
# (* If the substitution x=v^(1/n) will not complicate algebraic subexpressions of u,
# SubstForFractionalPowerQ[u,v,x] returns True; else it returns False. *)
if AtomQ(u) or FreeQ(u, x):
return True
elif FractionalPowerQ(u):
return SubstForFractionalPowerAuxQ(u, v, x)
return all(SubstForFractionalPowerQ(i, v, x) for i in u.args)
def SubstForFractionalPowerAuxQ(u, v, x):
if AtomQ(u):
return False
elif FractionalPowerQ(u):
if ZeroQ(u.base - v):
return True
return any(SubstForFractionalPowerAuxQ(i, v, x) for i in u.args)
def FractionalPowerOfSquareQ(u):
# (* If a subexpression of u is of the form ((v+w)^2)^n where n is a fraction, *)
# (* FractionalPowerOfSquareQ[u] returns (v+w)^2; else it returns False. *)
if AtomQ(u):
return False
elif FractionalPowerQ(u):
a_ = Wild('a', exclude=[0])
b_ = Wild('b', exclude=[0])
c_ = Wild('c', exclude=[0])
match = u.base.match(a_*(b_ + c_)**(S(2)))
if match:
keys = [a_, b_, c_]
if len(keys) == len(match):
a, b, c = tuple(match[i] for i in keys)
if NonsumQ(a):
return (b + c)**S(2)
for i in u.args:
tmp = FractionalPowerOfSquareQ(i)
if Not(FalseQ(tmp)):
return tmp
return False
def FractionalPowerSubexpressionQ(u, v, w):
# (* If a subexpression of u is of the form w^n where n is a fraction but not equal to v, *)
# (* FractionalPowerSubexpressionQ[u,v,w] returns True; else it returns False. *)
if AtomQ(u):
return False
elif FractionalPowerQ(u):
if PositiveQ(u.base/w):
return Not(u.base == v) and LeafCount(w) < 3*LeafCount(v)
for i in u.args:
if FractionalPowerSubexpressionQ(i, v, w):
return True
return False
def Apply(f, lst):
return f(*lst)
def FactorNumericGcd(u):
# (* FactorNumericGcd[u] returns u with the gcd of the numeric coefficients of terms of sums factored out. *)
if PowerQ(u):
if RationalQ(u.exp):
return FactorNumericGcd(u.base)**u.exp
elif ProductQ(u):
res = [FactorNumericGcd(i) for i in u.args]
return Mul(*res)
elif SumQ(u):
g = GCD([NumericFactor(i) for i in u.args])
r = Add(*[i/g for i in u.args])
return g*r
return u
def MergeableFactorQ(bas, deg, v):
# (* MergeableFactorQ[bas,deg,v] returns True iff bas equals the base of a factor of v or bas is a factor of every term of v. *)
if bas == v:
return RationalQ(deg + S(1)) and (deg + 1>=0 or RationalQ(deg) and deg>0)
elif PowerQ(v):
if bas == v.base:
return RationalQ(deg+v.exp) and (deg+v.exp>=0 or RationalQ(deg) and deg>0)
return SumQ(v.base) and IntegerQ(v.exp) and (Not(IntegerQ(deg) or IntegerQ(deg/v.exp))) and MergeableFactorQ(bas, deg/v.exp, v.base)
elif ProductQ(v):
return MergeableFactorQ(bas, deg, First(v)) or MergeableFactorQ(bas, deg, Rest(v))
return SumQ(v) and MergeableFactorQ(bas, deg, First(v)) and MergeableFactorQ(bas, deg, Rest(v))
def MergeFactor(bas, deg, v):
# (* If MergeableFactorQ[bas,deg,v], MergeFactor[bas,deg,v] return the product of bas^deg and v,
# but with bas^deg merged into the factor of v whose base equals bas. *)
if bas == v:
return bas**(deg + 1)
elif PowerQ(v):
if bas == v.base:
return bas**(deg + v.exp)
return MergeFactor(bas, deg/v.exp, v.base**v.exp)
elif ProductQ(v):
if MergeableFactorQ(bas, deg, First(v)):
return MergeFactor(bas, deg, First(v))*Rest(v)
return First(v)*MergeFactor(bas, deg, Rest(v))
return MergeFactor(bas, deg, First(v)) + MergeFactor(bas, deg, Rest(v))
def MergeFactors(u, v):
# (* MergeFactors[u,v] returns the product of u and v, but with the mergeable factors of u merged into v. *)
if ProductQ(u):
return MergeFactors(Rest(u), MergeFactors(First(u), v))
elif PowerQ(u):
if MergeableFactorQ(u.base, u.exp, v):
return MergeFactor(u.base, u.exp, v)
elif RationalQ(u.exp) and u.exp < -1 and MergeableFactorQ(u.base, -S(1), v):
return MergeFactors(u.base**(u.exp + 1), MergeFactor(u.base, -S(1), v))
return u*v
elif MergeableFactorQ(u, S(1), v):
return MergeFactor(u, S(1), v)
return u*v
def TrigSimplifyQ(u):
# (* TrigSimplifyQ[u] returns True if TrigSimplify[u] actually simplifies u; else False. *)
return ActivateTrig(u) != TrigSimplify(u)
def TrigSimplify(u):
# (* TrigSimplify[u] returns a bottom-up trig simplification of u. *)
return ActivateTrig(TrigSimplifyRecur(u))
def TrigSimplifyRecur(u):
if AtomQ(u):
return u
return TrigSimplifyAux(u.func(*[TrigSimplifyRecur(i) for i in u.args]))
def Order(expr1, expr2):
if expr1 == expr2:
return 0
elif expr1.sort_key() > expr2.sort_key():
return -1
return 1
def FactorOrder(u, v):
if u == 1:
if v == 1:
return 0
return -1
elif v == 1:
return 1
return Order(u, v)
def Smallest(num1, num2=None):
if num2 is None:
lst = num1
num = lst[0]
for i in Rest(lst):
num = Smallest(num, i)
return num
return Min(num1, num2)
def OrderedQ(l):
return l == Sort(l)
def MinimumDegree(deg1, deg2):
if RationalQ(deg1):
if RationalQ(deg2):
return Min(deg1, deg2)
return deg1
elif RationalQ(deg2):
return deg2
deg = Simplify(deg1- deg2)
if RationalQ(deg):
if deg > 0:
return deg2
return deg1
elif OrderedQ([deg1, deg2]):
return deg1
return deg2
def PositiveFactors(u):
# (* PositiveFactors[u] returns the positive factors of u *)
if ZeroQ(u):
return S(1)
elif RationalQ(u):
return Abs(u)
elif PositiveQ(u):
return u
elif ProductQ(u):
res = 1
for i in u.args:
res *= PositiveFactors(i)
return res
return 1
def Sign(u):
return sign(u)
def NonpositiveFactors(u):
# (* NonpositiveFactors[u] returns the nonpositive factors of u *)
if ZeroQ(u):
return u
elif RationalQ(u):
return Sign(u)
elif PositiveQ(u):
return S(1)
elif ProductQ(u):
res = S(1)
for i in u.args:
res *= NonpositiveFactors(i)
return res
return u
def PolynomialInAuxQ(u, v, x):
if u == v:
return True
elif AtomQ(u):
return u != x
elif PowerQ(u):
if PowerQ(v):
if u.base == v.base:
return PositiveIntegerQ(u.exp/v.exp)
return PositiveIntegerQ(u.exp) and PolynomialInAuxQ(u.base, v, x)
elif SumQ(u) or ProductQ(u):
for i in u.args:
if Not(PolynomialInAuxQ(i, v, x)):
return False
return True
return False
def PolynomialInQ(u, v, x):
"""
If u is a polynomial in v(x), PolynomialInQ(u, v, x) returns True, else it returns False.
Examples
========
>>> from sympy.integrals.rubi.utility_function import PolynomialInQ
>>> from sympy.abc import x
>>> from sympy import log, S
>>> PolynomialInQ(S(1), log(x), x)
True
>>> PolynomialInQ(log(x), log(x), x)
True
>>> PolynomialInQ(1 + log(x)**2, log(x), x)
True
"""
return PolynomialInAuxQ(u, NonfreeFactors(NonfreeTerms(v, x), x), x)
def ExponentInAux(u, v, x):
if u == v:
return S(1)
elif AtomQ(u):
return S(0)
elif PowerQ(u):
if PowerQ(v):
if u.base == v.base:
return u.exp/v.exp
return u.exp*ExponentInAux(u.base, v, x)
elif ProductQ(u):
return Add(*[ExponentInAux(i, v, x) for i in u.args])
return Max(*[ExponentInAux(i, v, x) for i in u.args])
def ExponentIn(u, v, x):
return ExponentInAux(u, NonfreeFactors(NonfreeTerms(v, x), x), x)
def PolynomialInSubstAux(u, v, x):
if u == v:
return x
elif AtomQ(u):
return u
elif PowerQ(u):
if PowerQ(v):
if u.base == v.base:
return x**(u.exp/v.exp)
return PolynomialInSubstAux(u.base, v, x)**u.exp
return u.func(*[PolynomialInSubstAux(i, v, x) for i in u.args])
def PolynomialInSubst(u, v, x):
# If u is a polynomial in v[x], PolynomialInSubst[u,v,x] returns the polynomial u in x.
w = NonfreeTerms(v, x)
return ReplaceAll(PolynomialInSubstAux(u, NonfreeFactors(w, x), x), {x: x - FreeTerms(v, x)/FreeFactors(w, x)})
def Distrib(u, v):
# Distrib[u,v] returns the sum of u times each term of v.
if SumQ(v):
return Add(*[u*i for i in v.args])
return u*v
def DistributeDegree(u, m):
# DistributeDegree[u,m] returns the product of the factors of u each raised to the mth degree.
if AtomQ(u):
return u**m
elif PowerQ(u):
return u.base**(u.exp*m)
elif ProductQ(u):
return Mul(*[DistributeDegree(i, m) for i in u.args])
return u**m
def FunctionOfPower(*args):
"""
FunctionOfPower[u,x] returns the gcd of the integer degrees of x in u.
Examples
========
>>> from sympy.integrals.rubi.utility_function import FunctionOfPower
>>> from sympy.abc import x
>>> FunctionOfPower(x, x)
1
>>> FunctionOfPower(x**3, x)
3
"""
if len(args) == 2:
return FunctionOfPower(args[0], None, args[1])
u, n, x = args
if FreeQ(u, x):
return n
elif u == x:
return S(1)
elif PowerQ(u):
if u.base == x and IntegerQ(u.exp):
if n is None:
return u.exp
return GCD(n, u.exp)
tmp = n
for i in u.args:
tmp = FunctionOfPower(i, tmp, x)
return tmp
def DivideDegreesOfFactors(u, n):
"""
DivideDegreesOfFactors[u,n] returns the product of the base of the factors of u raised to the degree of the factors divided by n.
Examples
========
>>> from sympy import S
>>> from sympy.integrals.rubi.utility_function import DivideDegreesOfFactors
>>> from sympy.abc import a, b
>>> DivideDegreesOfFactors(a**b, S(3))
a**(b/3)
"""
if ProductQ(u):
return Mul(*[LeadBase(i)**(LeadDegree(i)/n) for i in u.args])
return LeadBase(u)**(LeadDegree(u)/n)
def MonomialFactor(u, x):
# MonomialFactor[u,x] returns the list {n,v} where x^n*v==u and n is free of x.
if AtomQ(u):
if u == x:
return [S(1), S(1)]
return [S(0), u]
elif PowerQ(u):
if IntegerQ(u.exp):
lst = MonomialFactor(u.base, x)
return [lst[0]*u.exp, lst[1]**u.exp]
elif u.base == x and FreeQ(u.exp, x):
return [u.exp, S(1)]
return [S(0), u]
elif ProductQ(u):
lst1 = MonomialFactor(First(u), x)
lst2 = MonomialFactor(Rest(u), x)
return [lst1[0] + lst2[0], lst1[1]*lst2[1]]
elif SumQ(u):
lst = [MonomialFactor(i, x) for i in u.args]
deg = lst[0][0]
for i in Rest(lst):
deg = MinimumDegree(deg, i[0])
if ZeroQ(deg) or RationalQ(deg) and deg < 0:
return [S(0), u]
return [deg, Add(*[x**(i[0] - deg)*i[1] for i in lst])]
return [S(0), u]
def FullSimplify(expr):
return Simplify(expr)
def FunctionOfLinearSubst(u, a, b, x):
if FreeQ(u, x):
return u
elif LinearQ(u, x):
tmp = Coefficient(u, x, 1)
if tmp == b:
tmp = S(1)
else:
tmp = tmp/b
return Coefficient(u, x, S(0)) - a*tmp + tmp*x
elif PowerQ(u):
if FreeQ(u.base, x):
return E**(FullSimplify(FunctionOfLinearSubst(Log(u.base)*u.exp, a, b, x)))
lst = MonomialFactor(u, x)
if ProductQ(u) and NonzeroQ(lst[0]):
if RationalQ(LeadFactor(lst[1])) and LeadFactor(lst[1]) < 0:
return -FunctionOfLinearSubst(DivideDegreesOfFactors(-lst[1], lst[0])*x, a, b, x)**lst[0]
return FunctionOfLinearSubst(DivideDegreesOfFactors(lst[1], lst[0])*x, a, b, x)**lst[0]
return u.func(*[FunctionOfLinearSubst(i, a, b, x) for i in u.args])
def FunctionOfLinear(*args):
# (* If u (x) is equivalent to an expression of the form f (a+b*x) and not the case that a==0 and
# b==1, FunctionOfLinear[u,x] returns the list {f (x),a,b}; else it returns False. *)
if len(args) == 2:
u, x = args
lst = FunctionOfLinear(u, False, False, x, False)
if AtomQ(lst) or FalseQ(lst[0]) or (lst[0] == 0 and lst[1] == 1):
return False
return [FunctionOfLinearSubst(u, lst[0], lst[1], x), lst[0], lst[1]]
u, a, b, x, flag = args
if FreeQ(u, x):
return [a, b]
elif CalculusQ(u):
return False
elif LinearQ(u, x):
if FalseQ(a):
return [Coefficient(u, x, 0), Coefficient(u, x, 1)]
lst = CommonFactors([b, Coefficient(u, x, 1)])
if ZeroQ(Coefficient(u, x, 0)) and Not(flag):
return [0, lst[0]]
elif ZeroQ(b*Coefficient(u, x, 0) - a*Coefficient(u, x, 1)):
return [a/lst[1], lst[0]]
return [0, 1]
elif PowerQ(u):
if FreeQ(u.base, x):
return FunctionOfLinear(Log(u.base)*u.exp, a, b, x, False)
lst = MonomialFactor(u, x)
if ProductQ(u) and NonzeroQ(lst[0]):
if False and IntegerQ(lst[0]) and lst[0] != -1 and FreeQ(lst[1], x):
if RationalQ(LeadFactor(lst[1])) and LeadFactor(lst[1]) < 0:
return FunctionOfLinear(DivideDegreesOfFactors(-lst[1], lst[0])*x, a, b, x, False)
return FunctionOfLinear(DivideDegreesOfFactors(lst[1], lst[0])*x, a, b, x, False)
return False
lst = [a, b]
for i in u.args:
lst = FunctionOfLinear(i, lst[0], lst[1], x, SumQ(u))
if AtomQ(lst):
return False
return lst
def NormalizeIntegrand(u, x):
v = NormalizeLeadTermSigns(NormalizeIntegrandAux(u, x))
if v == NormalizeLeadTermSigns(u):
return u
else:
return v
def NormalizeIntegrandAux(u, x):
if SumQ(u):
l = 0
for i in u.args:
l += NormalizeIntegrandAux(i, x)
return l
if ProductQ(MergeMonomials(u, x)):
l = 1
for i in MergeMonomials(u, x).args:
l *= NormalizeIntegrandFactor(i, x)
return l
else:
return NormalizeIntegrandFactor(MergeMonomials(u, x), x)
def NormalizeIntegrandFactor(u, x):
if PowerQ(u):
if FreeQ(u.exp, x):
bas = NormalizeIntegrandFactorBase(u.base, x)
deg = u.exp
if IntegerQ(deg) and SumQ(bas):
if all(MonomialQ(i, x) for i in bas.args):
mi = MinimumMonomialExponent(bas, x)
q = 0
for i in bas.args:
q += Simplify(i/x**mi)
return x**(mi*deg)*q**deg
else:
return bas**deg
else:
return bas**deg
if PowerQ(u):
if FreeQ(u.base, x):
return u.base**NormalizeIntegrandFactorBase(u.exp, x)
bas = NormalizeIntegrandFactorBase(u, x)
if SumQ(bas):
if all(MonomialQ(i, x) for i in bas.args):
mi = MinimumMonomialExponent(bas, x)
z = 0
for j in bas.args:
z += j/x**mi
return x**mi*z
else:
return bas
else:
return bas
def NormalizeIntegrandFactorBase(expr, x):
m = Wild('m', exclude=[x])
u = Wild('u')
match = expr.match(x**m*u)
if match and SumQ(u):
l = 0
for i in u.args:
l += NormalizeIntegrandFactorBase((x**m*i), x)
return l
if BinomialQ(expr, x):
if BinomialMatchQ(expr, x):
return expr
else:
return ExpandToSum(expr, x)
elif TrinomialQ(expr, x):
if TrinomialMatchQ(expr, x):
return expr
else:
return ExpandToSum(expr, x)
elif ProductQ(expr):
l = 1
for i in expr.args:
l *= NormalizeIntegrandFactor(i, x)
return l
elif PolynomialQ(expr, x) and Exponent(expr, x) <= 4:
return ExpandToSum(expr, x)
elif SumQ(expr):
w = Wild('w')
m = Wild('m', exclude=[x])
v = TogetherSimplify(expr)
if SumQ(v) or v.match(x**m*w) and SumQ(w) or LeafCount(v) > LeafCount(expr) + 2:
return UnifySum(expr, x)
else:
return NormalizeIntegrandFactorBase(v, x)
else:
return expr
def NormalizeTogether(u):
return NormalizeLeadTermSigns(Together(u))
def NormalizeLeadTermSigns(u):
if ProductQ(u):
t = 1
for i in u.args:
lst = SignOfFactor(i)
if lst[0] == 1:
t *= lst[1]
else:
t *= AbsorbMinusSign(lst[1])
return t
else:
lst = SignOfFactor(u)
if lst[0] == 1:
return lst[1]
else:
return AbsorbMinusSign(lst[1])
def AbsorbMinusSign(expr, *x):
m = Wild('m', exclude=[x])
u = Wild('u')
v = Wild('v')
match = expr.match(u*v**m)
if match:
if len(match) == 3:
if SumQ(match[v]) and OddQ(match[m]):
return match[u]*(-match[v])**match[m]
return -expr
def NormalizeSumFactors(u):
if AtomQ(u):
return u
elif ProductQ(u):
k = 1
for i in u.args:
k *= NormalizeSumFactors(i)
return SignOfFactor(k)[0]*SignOfFactor(k)[1]
elif SumQ(u):
k = 0
for i in u.args:
k += NormalizeSumFactors(i)
return k
else:
return u
def SignOfFactor(u):
if RationalQ(u) and u < 0 or SumQ(u) and NumericFactor(First(u)) < 0:
return [-1, -u]
elif IntegerPowerQ(u):
if SumQ(u.base) and NumericFactor(First(u.base)) < 0:
return [(-1)**u.exp, (-u.base)**u.exp]
elif ProductQ(u):
k = 1
h = 1
for i in u.args:
k *= SignOfFactor(i)[0]
h *= SignOfFactor(i)[1]
return [k, h]
return [1, u]
def NormalizePowerOfLinear(u, x):
v = FactorSquareFree(u)
if PowerQ(v):
if LinearQ(v.base, x) and FreeQ(v.exp, x):
return ExpandToSum(v.base, x)**v.exp
return ExpandToSum(v, x)
def SimplifyIntegrand(u, x):
v = NormalizeLeadTermSigns(NormalizeIntegrandAux(Simplify(u), x))
if 5*LeafCount(v) < 4*LeafCount(u):
return v
if v != NormalizeLeadTermSigns(u):
return v
else:
return u
def SimplifyTerm(u, x):
v = Simplify(u)
w = Together(v)
if LeafCount(v) < LeafCount(w):
return NormalizeIntegrand(v, x)
else:
return NormalizeIntegrand(w, x)
def TogetherSimplify(u):
v = Together(Simplify(Together(u)))
return FixSimplify(v)
def SmartSimplify(u):
v = Simplify(u)
w = factor(v)
if LeafCount(w) < LeafCount(v):
v = w
if Not(FalseQ(w == FractionalPowerOfSquareQ(v))) and FractionalPowerSubexpressionQ(u, w, Expand(w)):
v = SubstForExpn(v, w, Expand(w))
else:
v = FactorNumericGcd(v)
return FixSimplify(v)
def SubstForExpn(u, v, w):
if u == v:
return w
if AtomQ(u):
return u
else:
k = 0
for i in u.args:
k += SubstForExpn(i, v, w)
return k
def ExpandToSum(u, *x):
if len(x) == 1:
x = x[0]
expr = 0
if PolyQ(S(u), x):
for t in ExponentList(u, x):
expr += Coeff(u, x, t)*x**t
return expr
if BinomialQ(u, x):
i = BinomialParts(u, x)
expr += i[0] + i[1]*x**i[2]
return expr
if TrinomialQ(u, x):
i = TrinomialParts(u, x)
expr += i[0] + i[1]*x**i[3] + i[2]*x**(2*i[3])
return expr
if GeneralizedBinomialMatchQ(u, x):
i = GeneralizedBinomialParts(u, x)
expr += i[0]*x**i[3] + i[1]*x**i[2]
return expr
if GeneralizedTrinomialMatchQ(u, x):
i = GeneralizedTrinomialParts(u, x)
expr += i[0]*x**i[4] + i[1]*x**i[3] + i[2]*x**(2*i[3]-i[4])
return expr
else:
return Expand(u)
else:
v = x[0]
x = x[1]
w = ExpandToSum(v, x)
r = NonfreeTerms(w, x)
if SumQ(r):
k = u*FreeTerms(w, x)
for i in r.args:
k += MergeMonomials(u*i, x)
return k
else:
return u*FreeTerms(w, x) + MergeMonomials(u*r, x)
def UnifySum(u, x):
if SumQ(u):
t = 0
lst = []
for i in u.args:
lst += [i]
for j in UnifyTerms(lst, x):
t += j
return t
else:
return SimplifyTerm(u, x)
def UnifyTerms(lst, x):
if lst==[]:
return lst
else:
return UnifyTerm(First(lst), UnifyTerms(Rest(lst), x), x)
def UnifyTerm(term, lst, x):
if lst==[]:
return [term]
tmp = Simplify(First(lst)/term)
if FreeQ(tmp, x):
return Prepend(Rest(lst), [(1+tmp)*term])
else:
return Prepend(UnifyTerm(term, Rest(lst), x), [First(lst)])
def CalculusQ(u):
return False
def FunctionOfInverseLinear(*args):
# (* If u is a function of an inverse linear binomial of the form 1/(a+b*x),
# FunctionOfInverseLinear[u,x] returns the list {a,b}; else it returns False. *)
if len(args) == 2:
u, x = args
return FunctionOfInverseLinear(u, None, x)
u, lst, x = args
if FreeQ(u, x):
return lst
elif u == x:
return False
elif QuotientOfLinearsQ(u, x):
tmp = Drop(QuotientOfLinearsParts(u, x), 2)
if tmp[1] == 0:
return False
elif lst is None:
return tmp
elif ZeroQ(lst[0]*tmp[1] - lst[1]*tmp[0]):
return lst
return False
elif CalculusQ(u):
return False
tmp = lst
for i in u.args:
tmp = FunctionOfInverseLinear(i, tmp, x)
if AtomQ(tmp):
return False
return tmp
def PureFunctionOfSinhQ(u, v, x):
# (* If u is a pure function of Sinh[v] and/or Csch[v], PureFunctionOfSinhQ[u,v,x] returns True;
# else it returns False. *)
if AtomQ(u):
return u != x
elif CalculusQ(u):
return False
elif HyperbolicQ(u) and ZeroQ(u.args[0] - v):
return SinhQ(u) or CschQ(u)
for i in u.args:
if Not(PureFunctionOfSinhQ(i, v, x)):
return False
return True
def PureFunctionOfTanhQ(u, v , x):
# (* If u is a pure function of Tanh[v] and/or Coth[v], PureFunctionOfTanhQ[u,v,x] returns True;
# else it returns False. *)
if AtomQ(u):
return u != x
elif CalculusQ(u):
return False
elif HyperbolicQ(u) and ZeroQ(u.args[0] - v):
return TanhQ(u) or CothQ(u)
for i in u.args:
if Not(PureFunctionOfTanhQ(i, v, x)):
return False
return True
def PureFunctionOfCoshQ(u, v, x):
# (* If u is a pure function of Cosh[v] and/or Sech[v], PureFunctionOfCoshQ[u,v,x] returns True;
# else it returns False. *)
if AtomQ(u):
return u != x
elif CalculusQ(u):
return False
elif HyperbolicQ(u) and ZeroQ(u.args[0] - v):
return CoshQ(u) or SechQ(u)
for i in u.args:
if Not(PureFunctionOfCoshQ(i, v, x)):
return False
return True
def IntegerQuotientQ(u, v):
# (* If u/v is an integer, IntegerQuotientQ[u,v] returns True; else it returns False. *)
return IntegerQ(Simplify(u/v))
def OddQuotientQ(u, v):
# (* If u/v is odd, OddQuotientQ[u,v] returns True; else it returns False. *)
return OddQ(Simplify(u/v))
def EvenQuotientQ(u, v):
# (* If u/v is even, EvenQuotientQ[u,v] returns True; else it returns False. *)
return EvenQ(Simplify(u/v))
def FindTrigFactor(func1, func2, u, v, flag):
# (* If func[w]^m is a factor of u where m is odd and w is an integer multiple of v,
# FindTrigFactor[func1,func2,u,v,True] returns the list {w,u/func[w]^n}; else it returns False. *)
# (* If func[w]^m is a factor of u where m is odd and w is an integer multiple of v not equal to v,
# FindTrigFactor[func1,func2,u,v,False] returns the list {w,u/func[w]^n}; else it returns False. *)
if u == 1:
return False
elif (Head(LeadBase(u)) == func1 or Head(LeadBase(u)) == func2) and OddQ(LeadDegree(u)) and IntegerQuotientQ(LeadBase(u).args[0], v) and (flag or NonzeroQ(LeadBase(u).args[0] - v)):
return [LeadBase[u].args[0], RemainingFactors(u)]
lst = FindTrigFactor(func1, func2, RemainingFactors(u), v, flag)
if AtomQ(lst):
return False
return [lst[0], LeadFactor(u)*lst[1]]
def FunctionOfSinhQ(u, v, x):
# (* If u is a function of Sinh[v], FunctionOfSinhQ[u,v,x] returns True; else it returns False. *)
if AtomQ(u):
return u != x
elif CalculusQ(u):
return False
elif HyperbolicQ(u) and IntegerQuotientQ(u.args[0], v):
if OddQuotientQ(u.args[0], v):
# (* Basis: If m odd, Sinh[m*v]^n is a function of Sinh[v]. *)
return SinhQ(u) or CschQ(u)
# (* Basis: If m even, Cos[m*v]^n is a function of Sinh[v]. *)
return CoshQ(u) or SechQ(u)
elif IntegerPowerQ(u):
if HyperbolicQ(u.base) and IntegerQuotientQ(u.base.args[0], v):
if EvenQ(u.exp):
# (* Basis: If m integer and n even, Hyper[m*v]^n is a function of Sinh[v]. *)
return True
return FunctionOfSinhQ(u.base, v, x)
elif ProductQ(u):
if CoshQ(u.args[0]) and SinhQ(u.args[1]) and ZeroQ(u.args[0].args[0] - v/2) and ZeroQ(u.args[1].args[0] - v/2):
return FunctionOfSinhQ(Drop(u, 2), v, x)
lst = FindTrigFactor(Sinh, Csch, u, v, False)
if ListQ(lst) and EvenQuotientQ(lst[0], v):
# (* Basis: If m even and n odd, Sinh[m*v]^n == Cosh[v]*u where u is a function of Sinh[v]. *)
return FunctionOfSinhQ(Cosh(v)*lst[1], v, x)
lst = FindTrigFactor(Cosh, Sech, u, v, False)
if ListQ(lst) and OddQuotientQ(lst[0], v):
# (* Basis: If m odd and n odd, Cosh[m*v]^n == Cosh[v]*u where u is a function of Sinh[v]. *)
return FunctionOfSinhQ(Cosh(v)*lst[1], v, x)
lst = FindTrigFactor(Tanh, Coth, u, v, True)
if ListQ(lst):
# (* Basis: If m integer and n odd, Tanh[m*v]^n == Cosh[v]*u where u is a function of Sinh[v]. *)
return FunctionOfSinhQ(Cosh(v)*lst[1], v, x)
return all(FunctionOfSinhQ(i, v, x) for i in u.args)
return all(FunctionOfSinhQ(i, v, x) for i in u.args)
def FunctionOfCoshQ(u, v, x):
#(* If u is a function of Cosh[v], FunctionOfCoshQ[u,v,x] returns True; else it returns False. *)
if AtomQ(u):
return u != x
elif CalculusQ(u):
return False
elif HyperbolicQ(u) and IntegerQuotientQ(u.args[0], v):
# (* Basis: If m integer, Cosh[m*v]^n is a function of Cosh[v]. *)
return CoshQ(u) or SechQ(u)
elif IntegerPowerQ(u):
if HyperbolicQ(u.base) and IntegerQuotientQ(u.base.args[0], v):
if EvenQ(u.exp):
# (* Basis: If m integer and n even, Hyper[m*v]^n is a function of Cosh[v]. *)
return True
return FunctionOfCoshQ(u.base, v, x)
elif ProductQ(u):
lst = FindTrigFactor(Sinh, Csch, u, v, False)
if ListQ(lst):
# (* Basis: If m integer and n odd, Sinh[m*v]^n == Sinh[v]*u where u is a function of Cosh[v]. *)
return FunctionOfCoshQ(Sinh(v)*lst[1], v, x)
lst = FindTrigFactor(Tanh, Coth, u, v, True)
if ListQ(lst):
# (* Basis: If m integer and n odd, Tanh[m*v]^n == Sinh[v]*u where u is a function of Cosh[v]. *)
return FunctionOfCoshQ(Sinh(v)*lst[1], v, x)
return all(FunctionOfCoshQ(i, v, x) for i in u.args)
return all(FunctionOfCoshQ(i, v, x) for i in u.args)
def OddHyperbolicPowerQ(u, v, x):
if SinhQ(u) or CoshQ(u) or SechQ(u) or CschQ(u):
return OddQuotientQ(u.args[0], v)
if PowerQ(u):
return OddQ(u.exp) and OddHyperbolicPowerQ(u.base, v, x)
if ProductQ(u):
if Not(EqQ(FreeFactors(u, x), 1)):
return OddHyperbolicPowerQ(NonfreeFactors(u, x), v, x)
lst = []
for i in u.args:
if Not(FunctionOfTanhQ(i, v, x)):
lst.append(i)
if lst == []:
return True
return Length(lst)==1 and OddHyperbolicPowerQ(lst[0], v, x)
if SumQ(u):
return all(OddHyperbolicPowerQ(i, v, x) for i in u.args)
return False
def FunctionOfTanhQ(u, v, x):
#(* If u is a function of the form f[Tanh[v],Coth[v]] where f is independent of x,
# FunctionOfTanhQ[u,v,x] returns True; else it returns False. *)
if AtomQ(u):
return u != x
elif CalculusQ(u):
return False
elif HyperbolicQ(u) and IntegerQuotientQ(u.args[0], v):
return TanhQ(u) or CothQ(u) or EvenQuotientQ(u.args[0], v)
elif PowerQ(u):
if EvenQ(u.exp) and HyperbolicQ(u.base) and IntegerQuotientQ(u.base.args[0], v):
return True
elif EvenQ(u.args[1]) and SumQ(u.args[0]):
return FunctionOfTanhQ(Expand(u.args[0]**2, v, x))
if ProductQ(u):
lst = []
for i in u.args:
if Not(FunctionOfTanhQ(i, v, x)):
lst.append(i)
if lst == []:
return True
return Length(lst)==2 and OddHyperbolicPowerQ(lst[0], v, x) and OddHyperbolicPowerQ(lst[1], v, x)
return all(FunctionOfTanhQ(i, v, x) for i in u.args)
def FunctionOfTanhWeight(u, v, x):
"""
u is a function of the form f(tanh(v), coth(v)) where f is independent of x.
FunctionOfTanhWeight(u, v, x) returns a nonnegative number if u is best considered a function of tanh(v), else it returns a negative number.
Examples
========
>>> from sympy import sinh, log, tanh
>>> from sympy.abc import x
>>> from sympy.integrals.rubi.utility_function import FunctionOfTanhWeight
>>> FunctionOfTanhWeight(x, log(x), x)
0
>>> FunctionOfTanhWeight(sinh(log(x)), log(x), x)
0
>>> FunctionOfTanhWeight(tanh(log(x)), log(x), x)
1
"""
if AtomQ(u):
return S(0)
elif CalculusQ(u):
return S(0)
elif HyperbolicQ(u) and IntegerQuotientQ(u.args[0], v):
if TanhQ(u) and ZeroQ(u.args[0] - v):
return S(1)
elif CothQ(u) and ZeroQ(u.args[0] - v):
return S(-1)
return S(0)
elif PowerQ(u):
if EvenQ(u.exp) and HyperbolicQ(u.base) and IntegerQuotientQ(u.base.args[0], v):
if TanhQ(u.base) or CoshQ(u.base) or SechQ(u.base):
return S(1)
return S(-1)
if ProductQ(u):
if all(FunctionOfTanhQ(i, v, x) for i in u.args):
return Add(*[FunctionOfTanhWeight(i, v, x) for i in u.args])
return S(0)
return Add(*[FunctionOfTanhWeight(i, v, x) for i in u.args])
def FunctionOfHyperbolicQ(u, v, x):
# (* If u (x) is equivalent to a function of the form f (Sinh[v],Cosh[v],Tanh[v],Coth[v],Sech[v],Csch[v])
# where f is independent of x, FunctionOfHyperbolicQ[u,v,x] returns True; else it returns False. *)
if AtomQ(u):
return u != x
elif CalculusQ(u):
return False
elif HyperbolicQ(u) and IntegerQuotientQ(u.args[0], v):
return True
return all(FunctionOfHyperbolicQ(i, v, x) for i in u.args)
def SmartNumerator(expr):
if PowerQ(expr):
n = expr.exp
u = expr.base
if RationalQ(n) and n < 0:
return SmartDenominator(u**(-n))
elif ProductQ(expr):
return Mul(*[SmartNumerator(i) for i in expr.args])
return Numerator(expr)
def SmartDenominator(expr):
if PowerQ(expr):
u = expr.base
n = expr.exp
if RationalQ(n) and n < 0:
return SmartNumerator(u**(-n))
elif ProductQ(expr):
return Mul(*[SmartDenominator(i) for i in expr.args])
return Denominator(expr)
def ActivateTrig(u):
return u
def ExpandTrig(*args):
if len(args) == 2:
u, x = args
return ActivateTrig(ExpandIntegrand(u, x))
u, v, x = args
w = ExpandTrig(v, x)
z = ActivateTrig(u)
if SumQ(w):
return w.func(*[z*i for i in w.args])
return z*w
def TrigExpand(u):
return expand_trig(u)
# SubstForTrig[u_,sin_,cos_,v_,x_] :=
# If[AtomQ[u],
# u,
# If[TrigQ[u] && IntegerQuotientQ[u[[1]],v],
# If[u[[1]]===v || ZeroQ[u[[1]]-v],
# If[SinQ[u],
# sin,
# If[CosQ[u],
# cos,
# If[TanQ[u],
# sin/cos,
# If[CotQ[u],
# cos/sin,
# If[SecQ[u],
# 1/cos,
# 1/sin]]]]],
# Map[Function[SubstForTrig[#,sin,cos,v,x]],
# ReplaceAll[TrigExpand[Head[u][Simplify[u[[1]]/v]*x]],x->v]]],
# If[ProductQ[u] && CosQ[u[[1]]] && SinQ[u[[2]]] && ZeroQ[u[[1,1]]-v/2] && ZeroQ[u[[2,1]]-v/2],
# sin/2*SubstForTrig[Drop[u,2],sin,cos,v,x],
# Map[Function[SubstForTrig[#,sin,cos,v,x]],u]]]]
def SubstForTrig(u, sin_ , cos_, v, x):
# (* u (v) is an expression of the form f (Sin[v],Cos[v],Tan[v],Cot[v],Sec[v],Csc[v]). *)
# (* SubstForTrig[u,sin,cos,v,x] returns the expression f (sin,cos,sin/cos,cos/sin,1/cos,1/sin). *)
if AtomQ(u):
return u
elif TrigQ(u) and IntegerQuotientQ(u.args[0], v):
if u.args[0] == v or ZeroQ(u.args[0] - v):
if SinQ(u):
return sin_
elif CosQ(u):
return cos_
elif TanQ(u):
return sin_/cos_
elif CotQ(u):
return cos_/sin_
elif SecQ(u):
return 1/cos_
return 1/sin_
r = ReplaceAll(TrigExpand(Head(u)(Simplify(u.args[0]/v*x))), {x: v})
return r.func(*[SubstForTrig(i, sin_, cos_, v, x) for i in r.args])
if ProductQ(u) and CosQ(u.args[0]) and SinQ(u.args[1]) and ZeroQ(u.args[0].args[0] - v/2) and ZeroQ(u.args[1].args[0] - v/2):
return sin(x)/2*SubstForTrig(Drop(u, 2), sin_, cos_, v, x)
return u.func(*[SubstForTrig(i, sin_, cos_, v, x) for i in u.args])
def SubstForHyperbolic(u, sinh_, cosh_, v, x):
# (* u (v) is an expression of the form f (Sinh[v],Cosh[v],Tanh[v],Coth[v],Sech[v],Csch[v]). *)
# (* SubstForHyperbolic[u,sinh,cosh,v,x] returns the expression
# f (sinh,cosh,sinh/cosh,cosh/sinh,1/cosh,1/sinh). *)
if AtomQ(u):
return u
elif HyperbolicQ(u) and IntegerQuotientQ(u.args[0], v):
if u.args[0] == v or ZeroQ(u.args[0] - v):
if SinhQ(u):
return sinh_
elif CoshQ(u):
return cosh_
elif TanhQ(u):
return sinh_/cosh_
elif CothQ(u):
return cosh_/sinh_
if SechQ(u):
return 1/cosh_
return 1/sinh_
r = ReplaceAll(TrigExpand(Head(u)(Simplify(u.args[0]/v)*x)), {x: v})
return r.func(*[SubstForHyperbolic(i, sinh_, cosh_, v, x) for i in r.args])
elif ProductQ(u) and CoshQ(u.args[0]) and SinhQ(u.args[1]) and ZeroQ(u.args[0].args[0] - v/2) and ZeroQ(u.args[1].args[0] - v/2):
return sinh(x)/2*SubstForHyperbolic(Drop(u, 2), sinh_, cosh_, v, x)
return u.func(*[SubstForHyperbolic(i, sinh_, cosh_, v, x) for i in u.args])
def InertTrigFreeQ(u):
return FreeQ(u, sin) and FreeQ(u, cos) and FreeQ(u, tan) and FreeQ(u, cot) and FreeQ(u, sec) and FreeQ(u, csc)
def LCM(a, b):
return lcm(a, b)
def SubstForFractionalPowerOfLinear(u, x):
# (* If u has a subexpression of the form (a+b*x)^(m/n) where m and n>1 are integers,
# SubstForFractionalPowerOfLinear[u,x] returns the list {v,n,a+b*x,1/b} where v is u
# with subexpressions of the form (a+b*x)^(m/n) replaced by x^m and x replaced
# by -a/b+x^n/b, and all times x^(n-1); else it returns False. *)
lst = FractionalPowerOfLinear(u, S(1), False, x)
if AtomQ(lst) or FalseQ(lst[1]):
return False
n = lst[0]
a = Coefficient(lst[1], x, 0)
b = Coefficient(lst[1], x, 1)
tmp = Simplify(x**(n-1)*SubstForFractionalPower(u, lst[1], n, -a/b + x**n/b, x))
return [NonfreeFactors(tmp, x), n, lst[1], FreeFactors(tmp, x)/b]
def FractionalPowerOfLinear(u, n, v, x):
# If u has a subexpression of the form (a + b*x)**(m/n), FractionalPowerOfLinear(u, 1, False, x) returns [n, a + b*x], else it returns False.
if AtomQ(u) or FreeQ(u, x):
return [n, v]
elif CalculusQ(u):
return False
elif FractionalPowerQ(u):
if LinearQ(u.base, x) and (FalseQ(v) or ZeroQ(u.base - v)):
return [LCM(Denominator(u.exp), n), u.base]
lst = [n, v]
for i in u.args:
lst = FractionalPowerOfLinear(i, lst[0], lst[1], x)
if AtomQ(lst):
return False
return lst
def InverseFunctionOfLinear(u, x):
# (* If u has a subexpression of the form g[a+b*x] where g is an inverse function,
# InverseFunctionOfLinear[u,x] returns g[a+b*x]; else it returns False. *)
if AtomQ(u) or CalculusQ(u) or FreeQ(u, x):
return False
elif InverseFunctionQ(u) and LinearQ(u.args[0], x):
return u
for i in u.args:
tmp = InverseFunctionOfLinear(i, x)
if Not(AtomQ(tmp)):
return tmp
return False
def InertTrigQ(*args):
if len(args) == 1:
f = args[0]
l = [sin,cos,tan,cot,sec,csc]
return any(Head(f) == i for i in l)
elif len(args) == 2:
f, g = args
if f == g:
return InertTrigQ(f)
return InertReciprocalQ(f, g) or InertReciprocalQ(g, f)
else:
f, g, h = args
return InertTrigQ(g, f) and InertTrigQ(g, h)
def InertReciprocalQ(f, g):
return (f.func == sin and g.func == csc) or (f.func == cos and g.func == sec) or (f.func == tan and g.func == cot)
def DeactivateTrig(u, x):
# (* u is a function of trig functions of a linear function of x. *)
# (* DeactivateTrig[u,x] returns u with the trig functions replaced with inert trig functions. *)
return FixInertTrigFunction(DeactivateTrigAux(u, x), x)
def FixInertTrigFunction(u, x):
return u
def DeactivateTrigAux(u, x):
if AtomQ(u):
return u
elif TrigQ(u) and LinearQ(u.args[0], x):
v = ExpandToSum(u.args[0], x)
if SinQ(u):
return sin(v)
elif CosQ(u):
return cos(v)
elif TanQ(u):
return tan(u)
elif CotQ(u):
return cot(v)
elif SecQ(u):
return sec(v)
return csc(v)
elif HyperbolicQ(u) and LinearQ(u.args[0], x):
v = ExpandToSum(I*u.args[0], x)
if SinhQ(u):
return -I*sin(v)
elif CoshQ(u):
return cos(v)
elif TanhQ(u):
return -I*tan(v)
elif CothQ(u):
I*cot(v)
elif SechQ(u):
return sec(v)
return I*csc(v)
return u.func(*[DeactivateTrigAux(i, x) for i in u.args])
def PowerOfInertTrigSumQ(u, func, x):
p_ = Wild('p', exclude=[x])
q_ = Wild('q', exclude=[x])
a_ = Wild('a', exclude=[x])
b_ = Wild('b', exclude=[x])
c_ = Wild('c', exclude=[x])
d_ = Wild('d', exclude=[x])
n_ = Wild('n', exclude=[x])
w_ = Wild('w')
pattern = (a_ + b_*(c_*func(w_))**p_)**n_
match = u.match(pattern)
if match:
keys = [a_, b_, c_, n_, p_, w_]
if len(keys) == len(match):
return True
pattern = (a_ + b_*(d_*func(w_))**p_ + c_*(d_*func(w_))**q_)**n_
match = u.match(pattern)
if match:
keys = [a_, b_, c_, d_, n_, p_, q_, w_]
if len(keys) == len(match):
return True
return False
def PiecewiseLinearQ(*args):
# (* If the derivative of u wrt x is a constant wrt x, PiecewiseLinearQ[u,x] returns True;
# else it returns False. *)
if len(args) == 3:
u, v, x = args
return PiecewiseLinearQ(u, x) and PiecewiseLinearQ(v, x)
u, x = args
if LinearQ(u, x):
return True
c_ = Wild('c', exclude=[x])
F_ = Wild('F', exclude=[x])
v_ = Wild('v')
match = u.match(Log(c_*F_**v_))
if match:
if len(match) == 3:
if LinearQ(match[v_], x):
return True
try:
F = type(u)
G = type(u.args[0])
v = u.args[0].args[0]
if LinearQ(v, x):
if MemberQ([[atanh, tanh], [atanh, coth], [acoth, coth], [acoth, tanh], [atan, tan], [atan, cot], [acot, cot], [acot, tan]], [F, G]):
return True
except:
pass
return False
def KnownTrigIntegrandQ(lst, u, x):
if u == 1:
return True
a_ = Wild('a', exclude=[x])
b_ = Wild('b', exclude=[x, 0])
func_ = WildFunction('func')
m_ = Wild('m', exclude=[x])
A_ = Wild('A', exclude=[x])
B_ = Wild('B', exclude=[x, 0])
C_ = Wild('C', exclude=[x, 0])
match = u.match((a_ + b_*func_)**m_)
if match:
func = match[func_]
if LinearQ(func.args[0], x) and MemberQ(lst, func.func):
return True
match = u.match((a_ + b_*func_)**m_*(A_ + B_*func_))
if match:
func = match[func_]
if LinearQ(func.args[0], x) and MemberQ(lst, func.func):
return True
match = u.match(A_ + C_*func_**2)
if match:
func = match[func_]
if LinearQ(func.args[0], x) and MemberQ(lst, func.func):
return True
match = u.match(A_ + B_*func_ + C_*func_**2)
if match:
func = match[func_]
if LinearQ(func.args[0], x) and MemberQ(lst, func.func):
return True
match = u.match((a_ + b_*func_)**m_*(A_ + C_*func_**2))
if match:
func = match[func_]
if LinearQ(func.args[0], x) and MemberQ(lst, func.func):
return True
match = u.match((a_ + b_*func_)**m_*(A_ + B_*func_ + C_*func_**2))
if match:
func = match[func_]
if LinearQ(func.args[0], x) and MemberQ(lst, func.func):
return True
return False
def KnownSineIntegrandQ(u, x):
return KnownTrigIntegrandQ([sin, cos], u, x)
def KnownTangentIntegrandQ(u, x):
return KnownTrigIntegrandQ([tan], u, x)
def KnownCotangentIntegrandQ(u, x):
return KnownTrigIntegrandQ([cot], u, x)
def KnownSecantIntegrandQ(u, x):
return KnownTrigIntegrandQ([sec, csc], u, x)
def TryPureTanSubst(u, x):
a_ = Wild('a', exclude=[x])
b_ = Wild('b', exclude=[x])
c_ = Wild('c', exclude=[x])
G_ = Wild('G')
F = u.func
try:
if MemberQ([atan, acot, atanh, acoth], F):
match = u.args[0].match(c_*(a_ + b_*G_))
if match:
if len(match) == 4:
G = match[G_]
if MemberQ([tan, cot, tanh, coth], G.func):
if LinearQ(G.args[0], x):
return True
except:
pass
return False
def TryTanhSubst(u, x):
if LogQ(u):
return False
elif not FalseQ(FunctionOfLinear(u, x)):
return False
a_ = Wild('a', exclude=[x])
m_ = Wild('m', exclude=[x])
p_ = Wild('p', exclude=[x])
r_, s_, t_, n_, b_, f_, g_ = map(Wild, 'rstnbfg')
match = u.match(r_*(s_ + t_)**n_)
if match:
if len(match) == 4:
r, s, t, n = [match[i] for i in [r_, s_, t_, n_]]
if IntegerQ(n) and PositiveQ(n):
return False
match = u.match(1/(a_ + b_*f_**n_))
if match:
if len(match) == 4:
a, b, f, n = [match[i] for i in [a_, b_, f_, n_]]
if SinhCoshQ(f) and IntegerQ(n) and n > 2:
return False
match = u.match(f_*g_)
if match:
if len(match) == 2:
f, g = match[f_], match[g_]
if SinhCoshQ(f) and SinhCoshQ(g):
if IntegersQ(f.args[0]/x, g.args[0]/x):
return False
match = u.match(r_*(a_*s_**m_)**p_)
if match:
if len(match) == 5:
r, a, s, m, p = [match[i] for i in [r_, a_, s_, m_, p_]]
if Not(m==2 and (s == Sech(x) or s == Csch(x))):
return False
if u != ExpandIntegrand(u, x):
return False
return True
def TryPureTanhSubst(u, x):
F = u.func
a_ = Wild('a', exclude=[x])
G_ = Wild('G')
if F == sym_log:
return False
match = u.args[0].match(a_*G_)
if match and len(match) == 2:
G = match[G_].func
if MemberQ([atanh, acoth], F) and MemberQ([tanh, coth], G):
return False
if u != ExpandIntegrand(u, x):
return False
return True
def AbsurdNumberGCD(*seq):
# (* m, n, ... must be absurd numbers. AbsurdNumberGCD[m,n,...] returns the gcd of m, n, ... *)
lst = list(seq)
if Length(lst) == 1:
return First(lst)
return AbsurdNumberGCDList(FactorAbsurdNumber(First(lst)), FactorAbsurdNumber(AbsurdNumberGCD(*Rest(lst))))
def AbsurdNumberGCDList(lst1, lst2):
# (* lst1 and lst2 must be absurd number prime factorization lists. *)
# (* AbsurdNumberGCDList[lst1,lst2] returns the gcd of the absurd numbers represented by lst1 and lst2. *)
if lst1 == []:
return Mul(*[i[0]**Min(i[1],0) for i in lst2])
elif lst2 == []:
return Mul(*[i[0]**Min(i[1],0) for i in lst1])
elif lst1[0][0] == lst2[0][0]:
if lst1[0][1] <= lst2[0][1]:
return lst1[0][0]**lst1[0][1]*AbsurdNumberGCDList(Rest(lst1), Rest(lst2))
return lst1[0][0]**lst2[0][1]*AbsurdNumberGCDList(Rest(lst1), Rest(lst2))
elif lst1[0][0] < lst2[0][0]:
if lst1[0][1] < 0:
return lst1[0][0]**lst1[0][1]*AbsurdNumberGCDList(Rest(lst1), lst2)
return AbsurdNumberGCDList(Rest(lst1), lst2)
elif lst2[0][1] < 0:
return lst2[0][0]**lst2[0][1]*AbsurdNumberGCDList(lst1, Rest(lst2))
return AbsurdNumberGCDList(lst1, Rest(lst2))
def ExpandTrigExpand(u, F, v, m, n, x):
w = Expand(TrigExpand(F.xreplace({x: n*x}))**m).xreplace({x: v})
if SumQ(w):
t = 0
for i in w.args:
t += u*i
return t
else:
return u*w
def ExpandTrigReduce(*args):
if len(args) == 3:
u = args[0]
v = args[1]
x = args[2]
w = ExpandTrigReduce(v, x)
if SumQ(w):
t = 0
for i in w.args:
t += u*i
return t
else:
return u*w
else:
u = args[0]
x = args[1]
return ExpandTrigReduceAux(u, x)
def ExpandTrigReduceAux(u, x):
v = TrigReduce(u).expand()
if SumQ(v):
t = 0
for i in v.args:
t += NormalizeTrig(i, x)
return t
return NormalizeTrig(v, x)
def NormalizeTrig(v, x):
a = Wild('a', exclude=[x])
n = Wild('n', exclude=[x, 0])
F = Wild('F')
expr = a*F**n
M = v.match(expr)
if M and len(M[F].args) == 1 and PolynomialQ(M[F].args[0], x) and Exponent(M[F].args[0], x) > 0:
u = M[F].args[0]
return M[a]*M[F].xreplace({u: ExpandToSum(u, x)})**M[n]
else:
return v
#=================================
def TrigToExp(expr):
ex = expr.rewrite(sin, sym_exp).rewrite(cos, sym_exp).rewrite(tan, sym_exp).rewrite(sec, sym_exp).rewrite(csc, sym_exp).rewrite(cot, sym_exp)
return ex.replace(sym_exp, rubi_exp)
def ExpandTrigToExp(u, *args):
if len(args) == 1:
x = args[0]
return ExpandTrigToExp(1, u, x)
else:
v = args[0]
x = args[1]
w = TrigToExp(v)
k = 0
if SumQ(w):
for i in w.args:
k += SimplifyIntegrand(u*i, x)
w = k
else:
w = SimplifyIntegrand(u*w, x)
return ExpandIntegrand(FreeFactors(w, x), NonfreeFactors(w, x),x)
#======================================
def TrigReduce(i):
"""
TrigReduce(expr) rewrites products and powers of trigonometric functions in expr in terms of trigonometric functions with combined arguments.
Examples
========
>>> from sympy import sin, cos
>>> from sympy.integrals.rubi.utility_function import TrigReduce
>>> from sympy.abc import x
>>> TrigReduce(cos(x)**2)
cos(2*x)/2 + 1/2
>>> TrigReduce(cos(x)**2*sin(x))
sin(x)/4 + sin(3*x)/4
>>> TrigReduce(cos(x)**2+sin(x))
sin(x) + cos(2*x)/2 + 1/2
"""
if SumQ(i):
t = 0
for k in i.args:
t += TrigReduce(k)
return t
if ProductQ(i):
if any(PowerQ(k) for k in i.args):
if (i.rewrite((sin, sinh), sym_exp).rewrite((cos, cosh), sym_exp).expand().rewrite(sym_exp, sin)).has(I, cosh, sinh):
return i.rewrite((sin, sinh), sym_exp).rewrite((cos, cosh), sym_exp).expand().rewrite(sym_exp, sin).simplify()
else:
return i.rewrite((sin, sinh), sym_exp).rewrite((cos, cosh), sym_exp).expand().rewrite(sym_exp, sin)
else:
a = Wild('a')
b = Wild('b')
v = Wild('v')
Match = i.match(v*sin(a)*cos(b))
if Match:
a = Match[a]
b = Match[b]
v = Match[v]
return i.subs(v*sin(a)*cos(b), v*S(1)/2*(sin(a + b) + sin(a - b)))
Match = i.match(v*sin(a)*sin(b))
if Match:
a = Match[a]
b = Match[b]
v = Match[v]
return i.subs(v*sin(a)*sin(b), v*S(1)/2*cos(a - b) - cos(a + b))
Match = i.match(v*cos(a)*cos(b))
if Match:
a = Match[a]
b = Match[b]
v = Match[v]
return i.subs(v*cos(a)*cos(b), v*S(1)/2*cos(a + b) + cos(a - b))
Match = i.match(v*sinh(a)*cosh(b))
if Match:
a = Match[a]
b = Match[b]
v = Match[v]
return i.subs(v*sinh(a)*cosh(b), v*S(1)/2*(sinh(a + b) + sinh(a - b)))
Match = i.match(v*sinh(a)*sinh(b))
if Match:
a = Match[a]
b = Match[b]
v = Match[v]
return i.subs(v*sinh(a)*sinh(b), v*S(1)/2*cosh(a - b) - cosh(a + b))
Match = i.match(v*cosh(a)*cosh(b))
if Match:
a = Match[a]
b = Match[b]
v = Match[v]
return i.subs(v*cosh(a)*cosh(b), v*S(1)/2*cosh(a + b) + cosh(a - b))
if PowerQ(i):
if i.has(sin, sinh):
if (i.rewrite((sin, sinh), sym_exp).expand().rewrite(sym_exp, sin)).has(I, cosh, sinh):
return i.rewrite((sin, sinh), sym_exp).expand().rewrite(sym_exp, sin).simplify()
else:
return i.rewrite((sin, sinh), sym_exp).expand().rewrite(sym_exp, sin)
if i.has(cos, cosh):
if (i.rewrite((cos, cosh), sym_exp).expand().rewrite(sym_exp, cos)).has(I, cosh, sinh):
return i.rewrite((cos, cosh), sym_exp).expand().rewrite(sym_exp, cos).simplify()
else:
return i.rewrite((cos, cosh), sym_exp).expand().rewrite(sym_exp, cos)
return i
def FunctionOfTrig(u, *args):
# If u is a function of trig functions of v where v is a linear function of x,
# FunctionOfTrig[u,x] returns v; else it returns False.
if len(args) == 1:
x = args[0]
v = FunctionOfTrig(u, None, x)
if v:
return v
else:
return False
else:
v, x = args
if AtomQ(u):
if u == x:
return False
else:
return v
if TrigQ(u) and LinearQ(u.args[0], x):
if v is None:
return u.args[0]
else:
a = Coefficient(v, x, 0)
b = Coefficient(v, x, 1)
c = Coefficient(u.args[0], x, 0)
d = Coefficient(u.args[0], x, 1)
if ZeroQ(a*d - b*c) and RationalQ(b/d):
return a/Numerator(b/d) + b*x/Numerator(b/d)
else:
return False
if HyperbolicQ(u) and LinearQ(u.args[0], x):
if v is None:
return I*u.args[0]
a = Coefficient(v, x, 0)
b = Coefficient(v, x, 1)
c = I*Coefficient(u.args[0], x, 0)
d = I*Coefficient(u.args[0], x, 1)
if ZeroQ(a*d - b*c) and RationalQ(b/d):
return a/Numerator(b/d) + b*x/Numerator(b/d)
else:
return False
if CalculusQ(u):
return False
else:
w = v
for i in u.args:
w = FunctionOfTrig(i, w, x)
if FalseQ(w):
return False
return w
def AlgebraicTrigFunctionQ(u, x):
# If u is algebraic function of trig functions, AlgebraicTrigFunctionQ(u,x) returns True; else it returns False.
if AtomQ(u):
return True
elif TrigQ(u) and LinearQ(u.args[0], x):
return True
elif HyperbolicQ(u) and LinearQ(u.args[0], x):
return True
elif PowerQ(u):
if FreeQ(u.exp, x):
return AlgebraicTrigFunctionQ(u.base, x)
elif ProductQ(u) or SumQ(u):
for i in u.args:
if not AlgebraicTrigFunctionQ(i, x):
return False
return True
return False
def FunctionOfHyperbolic(u, *x):
# If u is a function of hyperbolic trig functions of v where v is linear in x,
# FunctionOfHyperbolic(u,x) returns v; else it returns False.
if len(x) == 1:
x = x[0]
v = FunctionOfHyperbolic(u, None, x)
if v is None:
return False
else:
return v
else:
v = x[0]
x = x[1]
if AtomQ(u):
if u == x:
return False
return v
if HyperbolicQ(u) and LinearQ(u.args[0], x):
if v is None:
return u.args[0]
a = Coefficient(v, x, 0)
b = Coefficient(v, x, 1)
c = Coefficient(u.args[0], x, 0)
d = Coefficient(u.args[0], x, 1)
if ZeroQ(a*d - b*c) and RationalQ(b/d):
return a/Numerator(b/d) + b*x/Numerator(b/d)
else:
return False
if CalculusQ(u):
return False
w = v
for i in u.args:
if w == FunctionOfHyperbolic(i, w, x):
return False
return w
def FunctionOfQ(v, u, x, PureFlag=False):
# v is a function of x. If u is a function of v, FunctionOfQ(v, u, x) returns True; else it returns False. *)
if FreeQ(u, x):
return False
elif AtomQ(v):
return True
elif ProductQ(v) and Not(EqQ(FreeFactors(v, x), 1)):
return FunctionOfQ(NonfreeFactors(v, x), u, x, PureFlag)
elif PureFlag:
if SinQ(v) or CscQ(v):
return PureFunctionOfSinQ(u, v.args[0], x)
elif CosQ(v) or SecQ(v):
return PureFunctionOfCosQ(u, v.args[0], x)
elif TanQ(v):
return PureFunctionOfTanQ(u, v.args[0], x)
elif CotQ(v):
return PureFunctionOfCotQ(u, v.args[0], x)
elif SinhQ(v) or CschQ(v):
return PureFunctionOfSinhQ(u, v.args[0], x)
elif CoshQ(v) or SechQ(v):
return PureFunctionOfCoshQ(u, v.args[0], x)
elif TanhQ(v):
return PureFunctionOfTanhQ(u, v.args[0], x)
elif CothQ(v):
return PureFunctionOfCothQ(u, v.args[0], x)
else:
return FunctionOfExpnQ(u, v, x) != False
elif SinQ(v) or CscQ(v):
return FunctionOfSinQ(u, v.args[0], x)
elif CosQ(v) or SecQ(v):
return FunctionOfCosQ(u, v.args[0], x)
elif TanQ(v) or CotQ(v):
FunctionOfTanQ(u, v.args[0], x)
elif SinhQ(v) or CschQ(v):
return FunctionOfSinhQ(u, v.args[0], x)
elif CoshQ(v) or SechQ(v):
return FunctionOfCoshQ(u, v.args[0], x)
elif TanhQ(v) or CothQ(v):
return FunctionOfTanhQ(u, v.args[0], x)
return FunctionOfExpnQ(u, v, x) != False
def FunctionOfExpnQ(u, v, x):
if u == v:
return 1
if AtomQ(u):
if u == x:
return False
else:
return 0
if CalculusQ(u):
return False
if PowerQ(u):
if FreeQ(u.exp, x):
if ZeroQ(u.base - v):
if IntegerQ(u.exp):
return u.exp
else:
return 1
if PowerQ(v):
if FreeQ(v.exp, x) and ZeroQ(u.base-v.base):
if RationalQ(v.exp):
if RationalQ(u.exp) and IntegerQ(u.exp/v.exp) and (v.exp>0 or u.exp<0):
return u.exp/v.exp
else:
return False
if IntegerQ(Simplify(u.exp/v.exp)):
return Simplify(u.exp/v.exp)
else:
return False
return FunctionOfExpnQ(u.base, v, x)
if ProductQ(u) and Not(EqQ(FreeFactors(u, x), 1)):
return FunctionOfExpnQ(NonfreeFactors(u, x), v, x)
if ProductQ(u) and ProductQ(v):
deg1 = FunctionOfExpnQ(First(u), First(v), x)
if deg1==False:
return False
deg2 = FunctionOfExpnQ(Rest(u), Rest(v), x);
if deg1==deg2 and FreeQ(Simplify(u/v^deg1), x):
return deg1
else:
return False
lst = []
for i in u.args:
if FunctionOfExpnQ(i, v, x) is False:
return False
lst.append(FunctionOfExpnQ(i, v, x))
return Apply(GCD, lst)
def PureFunctionOfSinQ(u, v, x):
# If u is a pure function of Sin(v) and/or Csc(v), PureFunctionOfSinQ(u, v, x) returns True; else it returns False.
if AtomQ(u):
return u!=x
if CalculusQ(u):
return False
if TrigQ(u) and ZeroQ(u.args[0]-v):
return SinQ(u) or CscQ(u)
for i in u.args:
if Not(PureFunctionOfSinQ(i, v, x)):
return False
return True
def PureFunctionOfCosQ(u, v, x):
# If u is a pure function of Cos(v) and/or Sec(v), PureFunctionOfCosQ(u, v, x) returns True; else it returns False.
if AtomQ(u):
return u!=x
if CalculusQ(u):
return False
if TrigQ(u) and ZeroQ(u.args[0]-v):
return CosQ(u) or SecQ(u)
for i in u.args:
if Not(PureFunctionOfCosQ(i, v, x)):
return False
return True
def PureFunctionOfTanQ(u, v, x):
# If u is a pure function of Tan(v) and/or Cot(v), PureFunctionOfTanQ(u, v, x) returns True; else it returns False.
if AtomQ(u):
return u!=x
if CalculusQ(u):
return False
if TrigQ(u) and ZeroQ(u.args[0]-v):
return TanQ(u) or CotQ(u)
for i in u.args:
if Not(PureFunctionOfTanQ(i, v, x)):
return False
return True
def PureFunctionOfCotQ(u, v, x):
# If u is a pure function of Cot(v), PureFunctionOfCotQ(u, v, x) returns True; else it returns False.
if AtomQ(u):
return u!=x
if CalculusQ(u):
return False
if TrigQ(u) and ZeroQ(u.args[0]-v):
return CotQ(u)
for i in u.args:
if Not(PureFunctionOfCotQ(i, v, x)):
return False
return True
def FunctionOfCosQ(u, v, x):
# If u is a function of Cos[v], FunctionOfCosQ[u,v,x] returns True; else it returns False.
if AtomQ(u):
return u != x
elif CalculusQ(u):
return False
elif TrigQ(u) and IntegerQuotientQ(u.args[0], v):
# Basis: If m integer, Cos[m*v]^n is a function of Cos[v]. *)
return CosQ(u) or SecQ(u)
elif IntegerPowerQ(u):
if TrigQ(u.base) and IntegerQuotientQ(u.base.args[0], v):
if EvenQ(u.exp):
# Basis: If m integer and n even, Trig[m*v]^n is a function of Cos[v]. *)
return True
return FunctionOfCosQ(u.base, v, x)
elif ProductQ(u):
lst = FindTrigFactor(sin, csc, u, v, False)
if ListQ(lst):
# (* Basis: If m integer and n odd, Sin[m*v]^n == Sin[v]*u where u is a function of Cos[v]. *)
return FunctionOfCosQ(Sin(v)*lst[1], v, x)
lst = FindTrigFactor(tan, cot, u, v, True)
if ListQ(lst):
# (* Basis: If m integer and n odd, Tan[m*v]^n == Sin[v]*u where u is a function of Cos[v]. *)
return FunctionOfCosQ(Sin(v)*lst[1], v, x)
return all(FunctionOfCosQ(i, v, x) for i in u.args)
return all(FunctionOfCosQ(i, v, x) for i in u.args)
def FunctionOfSinQ(u, v, x):
# If u is a function of Sin[v], FunctionOfSinQ[u,v,x] returns True; else it returns False.
if AtomQ(u):
return u != x
elif CalculusQ(u):
return False
elif TrigQ(u) and IntegerQuotientQ(u.args[0], v):
if OddQuotientQ(u.args[0], v):
# Basis: If m odd, Sin[m*v]^n is a function of Sin[v].
return SinQ(u) or CscQ(u)
# Basis: If m even, Cos[m*v]^n is a function of Sin[v].
return CosQ(u) or SecQ(u)
elif IntegerPowerQ(u):
if TrigQ(u.base) and IntegerQuotientQ(u.base.args[0], v):
if EvenQ(u.exp):
# Basis: If m integer and n even, Hyper[m*v]^n is a function of Sin[v].
return True
return FunctionOfSinQ(u.base, v, x)
elif ProductQ(u):
if CosQ(u.args[0]) and SinQ(u.args[1]) and ZeroQ(u.args[0].args[0] - v/2) and ZeroQ(u.args[1].args[0] - v/2):
return FunctionOfSinQ(Drop(u, 2), v, x)
lst = FindTrigFactor(sin, csch, u, v, False)
if ListQ(lst) and EvenQuotientQ(lst[0], v):
# Basis: If m even and n odd, Sin[m*v]^n == Cos[v]*u where u is a function of Sin[v].
return FunctionOfSinQ(Cos(v)*lst[1], v, x)
lst = FindTrigFactor(cos, sec, u, v, False)
if ListQ(lst) and OddQuotientQ(lst[0], v):
# Basis: If m odd and n odd, Cos[m*v]^n == Cos[v]*u where u is a function of Sin[v].
return FunctionOfSinQ(Cos(v)*lst[1], v, x)
lst = FindTrigFactor(tan, cot, u, v, True)
if ListQ(lst):
# Basis: If m integer and n odd, Tan[m*v]^n == Cos[v]*u where u is a function of Sin[v].
return FunctionOfSinQ(Cos(v)*lst[1], v, x)
return all(FunctionOfSinQ(i, v, x) for i in u.args)
return all(FunctionOfSinQ(i, v, x) for i in u.args)
def OddTrigPowerQ(u, v, x):
if SinQ(u) or CosQ(u) or SecQ(u) or CscQ(u):
return OddQuotientQ(u.args[0], v)
if PowerQ(u):
return OddQ(u.exp) and OddTrigPowerQ(u.base, v, x)
if ProductQ(u):
if not FreeFactors(u, x) == 1:
return OddTrigPowerQ(NonfreeFactors(u, x), v, x)
lst = []
for i in u.args:
if Not(FunctionOfTanQ(i, v, x)):
lst.append(i)
if lst == []:
return True
return Length(lst)==1 and OddTrigPowerQ(lst[0], v, x)
if SumQ(u):
return all(OddTrigPowerQ(i, v, x) for i in u.args)
return False
def FunctionOfTanQ(u, v, x):
# If u is a function of the form f[Tan[v],Cot[v]] where f is independent of x,
# FunctionOfTanQ[u,v,x] returns True; else it returns False.
if AtomQ(u):
return u != x
elif CalculusQ(u):
return False
elif TrigQ(u) and IntegerQuotientQ(u.args[0], v):
return TanQ(u) or CotQ(u) or EvenQuotientQ(u.args[0], v)
elif PowerQ(u):
if EvenQ(u.exp) and TrigQ(u.base) and IntegerQuotientQ(u.base.args[0], v):
return True
elif EvenQ(u.exp) and SumQ(u.base):
return FunctionOfTanQ(Expand(u.base**2, v, x))
if ProductQ(u):
lst = []
for i in u.args:
if Not(FunctionOfTanQ(i, v, x)):
lst.append(i)
if lst == []:
return True
return Length(lst)==2 and OddTrigPowerQ(lst[0], v, x) and OddTrigPowerQ(lst[1], v, x)
return all(FunctionOfTanQ(i, v, x) for i in u.args)
def FunctionOfTanWeight(u, v, x):
# (* u is a function of the form f[Tan[v],Cot[v]] where f is independent of x.
# FunctionOfTanWeight[u,v,x] returns a nonnegative number if u is best considered a function
# of Tan[v]; else it returns a negative number. *)
if AtomQ(u):
return S(0)
elif CalculusQ(u):
return S(0)
elif TrigQ(u) and IntegerQuotientQ(u.args[0], v):
if TanQ(u) and ZeroQ(u.args[0] - v):
return S(1)
elif CotQ(u) and ZeroQ(u.args[0] - v):
return S(-1)
return S(0)
elif PowerQ(u):
if EvenQ(u.exp) and TrigQ(u.base) and IntegerQuotientQ(u.base.args[0], v):
if TanQ(u.base) or CosQ(u.base) or SecQ(u.base):
return S(1)
return S(-1)
if ProductQ(u):
if all(FunctionOfTanQ(i, v, x) for i in u.args):
return Add(*[FunctionOfTanWeight(i, v, x) for i in u.args])
return S(0)
return Add(*[FunctionOfTanWeight(i, v, x) for i in u.args])
def FunctionOfTrigQ(u, v, x):
# If u (x) is equivalent to a function of the form f (Sin[v],Cos[v],Tan[v],Cot[v],Sec[v],Csc[v]) where f is independent of x, FunctionOfTrigQ[u,v,x] returns True; else it returns False.
if AtomQ(u):
return u != x
elif CalculusQ(u):
return False
elif TrigQ(u) and IntegerQuotientQ(u.args[0], v):
return True
return all(FunctionOfTrigQ(i, v, x) for i in u.args)
def FunctionOfDensePolynomialsQ(u, x):
# If all occurrences of x in u (x) are in dense polynomials, FunctionOfDensePolynomialsQ[u,x] returns True; else it returns False.
if FreeQ(u, x):
return True
if PolynomialQ(u, x):
return Length(ExponentList(u, x)) > 1
return all(FunctionOfDensePolynomialsQ(i, x) for i in u.args)
def FunctionOfLog(u, *args):
# If u (x) is equivalent to an expression of the form f (Log[a*x^n]), FunctionOfLog[u,x] returns
# the list {f (x),a*x^n,n}; else it returns False.
if len(args) == 1:
x = args[0]
lst = FunctionOfLog(u, False, False, x)
if AtomQ(lst) or FalseQ(lst[1]) or not isinstance(x, Symbol):
return False
else:
return lst
else:
v = args[0]
n = args[1]
x = args[2]
if AtomQ(u):
if u==x:
return False
else:
return [u, v, n]
if CalculusQ(u):
return False
lst = BinomialParts(u.args[0], x)
if LogQ(u) and ListQ(lst) and ZeroQ(lst[0]):
if FalseQ(v) or u.args[0] == v:
return [x, u.args[0], lst[2]]
else:
return False
lst = [0, v, n]
l = []
for i in u.args:
lst = FunctionOfLog(i, lst[1], lst[2], x)
if AtomQ(lst):
return False
else:
l.append(lst[0])
return [u.func(*l), lst[1], lst[2]]
def PowerVariableExpn(u, m, x):
# If m is an integer, u is an expression of the form f((c*x)**n) and g=GCD(m,n)>1,
# PowerVariableExpn(u,m,x) returns the list {x**(m/g)*f((c*x)**(n/g)),g,c}; else it returns False.
if IntegerQ(m):
lst = PowerVariableDegree(u, m, 1, x)
if not lst:
return False
else:
return [x**(m/lst[0])*PowerVariableSubst(u, lst[0], x), lst[0], lst[1]]
else:
return False
def PowerVariableDegree(u, m, c, x):
if FreeQ(u, x):
return [m, c]
if AtomQ(u) or CalculusQ(u):
return False
if PowerQ(u):
if FreeQ(u.base/x, x):
if ZeroQ(m) or m == u.exp and c == u.base/x:
return [u.exp, u.base/x]
if IntegerQ(u.exp) and IntegerQ(m) and GCD(m, u.exp)>1 and c==u.base/x:
return [GCD(m, u.exp), c]
else:
return False
lst = [m, c]
for i in u.args:
if PowerVariableDegree(i, lst[0], lst[1], x) == False:
return False
lst1 = PowerVariableDegree(i, lst[0], lst[1], x)
if not lst1:
return False
else:
return lst1
def PowerVariableSubst(u, m, x):
if FreeQ(u, x) or AtomQ(u) or CalculusQ(u):
return u
if PowerQ(u):
if FreeQ(u.base/x, x):
return x**(u.exp/m)
if ProductQ(u):
l = 1
for i in u.args:
l *= (PowerVariableSubst(i, m, x))
return l
if SumQ(u):
l = 0
for i in u.args:
l += (PowerVariableSubst(i, m, x))
return l
return u
def EulerIntegrandQ(expr, x):
a = Wild('a', exclude=[x])
b = Wild('b', exclude=[x])
n = Wild('n', exclude=[x, 0])
m = Wild('m', exclude=[x, 0])
p = Wild('p', exclude=[x, 0])
u = Wild('u')
v = Wild('v')
# Pattern 1
M = expr.match((a*x + b*u**n)**p)
if M:
if len(M) == 5 and FreeQ([M[a], M[b]], x) and IntegerQ(M[n] + 1/2) and QuadraticQ(M[u], x) and Not(RationalQ(M[p])) or NegativeIntegerQ(M[p]) and Not(BinomialQ(M[u], x)):
return True
# Pattern 2
M = expr.match(v**m*(a*x + b*u**n)**p)
if M:
if len(M) == 6 and FreeQ([M[a], M[b]], x) and ZeroQ(M[u] - M[v]) and IntegersQ(2*M[m], M[n] + 1/2) and QuadraticQ(M[u], x) and Not(RationalQ(M[p])) or NegativeIntegerQ(M[p]) and Not(BinomialQ(M[u], x)):
return True
# Pattern 3
M = expr.match(u**n*v**p)
if M:
if len(M) == 3 and NegativeIntegerQ(M[p]) and IntegerQ(M[n] + 1/2) and QuadraticQ(M[u], x) and QuadraticQ(M[v], x) and Not(BinomialQ(M[v], x)):
return True
else:
return False
def FunctionOfSquareRootOfQuadratic(u, *args):
if len(args) == 1:
x = args[0]
pattern = Pattern(UtilityOperator(x_**WC('m', 1)*(a_ + x**WC('n', 1)*WC('b', 1))**p_, x), CustomConstraint(lambda a, b, m, n, p, x: FreeQ([a, b, m, n, p], x)))
M = is_match(UtilityOperator(u, args[0]), pattern)
if M:
return False
tmp = FunctionOfSquareRootOfQuadratic(u, False, x)
if AtomQ(tmp) or FalseQ(tmp[0]):
return False
tmp = tmp[0]
a = Coefficient(tmp, x, 0)
b = Coefficient(tmp, x, 1)
c = Coefficient(tmp, x, 2)
if ZeroQ(a) and ZeroQ(b) or ZeroQ(b**2-4*a*c):
return False
if PosQ(c):
sqrt = Rt(c, S(2));
q = a*sqrt + b*x + sqrt*x**2
r = b + 2*sqrt*x
return [Simplify(SquareRootOfQuadraticSubst(u, q/r, (-a+x**2)/r, x)*q/r**2), Simplify(sqrt*x + Sqrt(tmp)), 2]
if PosQ(a):
sqrt = Rt(a, S(2))
q = c*sqrt - b*x + sqrt*x**2
r = c - x**2
return [Simplify(SquareRootOfQuadraticSubst(u, q/r, (-b+2*sqrt*x)/r, x)*q/r**2), Simplify((-sqrt+Sqrt(tmp))/x), 1]
sqrt = Rt(b**2 - 4*a*c, S(2))
r = c - x**2
return[Simplify(-sqrt*SquareRootOfQuadraticSubst(u, -sqrt*x/r, -(b*c+c*sqrt+(-b+sqrt)*x**2)/(2*c*r), x)*x/r**2), FullSimplify(2*c*Sqrt(tmp)/(b-sqrt+2*c*x)), 3]
else:
v = args[0]
x = args[1]
if AtomQ(u) or FreeQ(u, x):
return [v]
if PowerQ(u):
if FreeQ(u.exp, x):
if FractionQ(u.exp) and Denominator(u.exp) == 2 and PolynomialQ(u.base, x) and Exponent(u.base, x) == 2:
if FalseQ(v) or u.base == v:
return [u.base]
else:
return False
return FunctionOfSquareRootOfQuadratic(u.base, v, x)
if ProductQ(u) or SumQ(u):
lst = [v]
lst1 = []
for i in u.args:
if FunctionOfSquareRootOfQuadratic(i, lst[0], x) == False:
return False
lst1 = FunctionOfSquareRootOfQuadratic(i, lst[0], x)
return lst1
else:
return False
def SquareRootOfQuadraticSubst(u, vv, xx, x):
# SquareRootOfQuadraticSubst(u, vv, xx, x) returns u with fractional powers replaced by vv raised to the power and x replaced by xx.
if AtomQ(u) or FreeQ(u, x):
if u==x:
return xx
return u
if PowerQ(u):
if FreeQ(u.exp, x):
if FractionQ(u.exp) and Denominator(u.exp)==2 and PolynomialQ(u.base, x) and Exponent(u.base, x)==2:
return vv**Numerator(u.exp)
return SquareRootOfQuadraticSubst(u.base, vv, xx, x)**u.exp
elif SumQ(u):
t = 0
for i in u.args:
t += SquareRootOfQuadraticSubst(i, vv, xx, x)
return t
elif ProductQ(u):
t = 1
for i in u.args:
t *= SquareRootOfQuadraticSubst(i, vv, xx, x)
return t
def Divides(y, u, x):
# If u divided by y is free of x, Divides[y,u,x] returns the quotient; else it returns False.
v = Simplify(u/y)
if FreeQ(v, x):
return v
else:
return False
def DerivativeDivides(y, u, x):
"""
If y not equal to x, y is easy to differentiate wrt x, and u divided by the derivative of y
is free of x, DerivativeDivides[y,u,x] returns the quotient; else it returns False.
"""
from matchpy import is_match
pattern0 = Pattern(Mul(a , b_), CustomConstraint(lambda a, b : FreeQ(a, b)))
def f1(y, u, x):
if PolynomialQ(y, x):
return PolynomialQ(u, x) and Exponent(u, x) == Exponent(y, x) - 1
else:
return EasyDQ(y, x)
if is_match(y, pattern0):
return False
elif f1(y, u, x):
v = D(y ,x)
if EqQ(v, 0):
return False
else:
v = Simplify(u/v)
if FreeQ(v, x):
return v
else:
return False
else:
return False
def EasyDQ(expr, x):
# If u is easy to differentiate wrt x, EasyDQ(u, x) returns True; else it returns False *)
u = Wild('u',exclude=[1])
m = Wild('m',exclude=[x, 0])
M = expr.match(u*x**m)
if M:
return EasyDQ(M[u], x)
if AtomQ(expr) or FreeQ(expr, x) or Length(expr)==0:
return True
elif CalculusQ(expr):
return False
elif Length(expr)==1:
return EasyDQ(expr.args[0], x)
elif BinomialQ(expr, x) or ProductOfLinearPowersQ(expr, x):
return True
elif RationalFunctionQ(expr, x) and RationalFunctionExponents(expr, x)==[1, 1]:
return True
elif ProductQ(expr):
if FreeQ(First(expr), x):
return EasyDQ(Rest(expr), x)
elif FreeQ(Rest(expr), x):
return EasyDQ(First(expr), x)
else:
return False
elif SumQ(expr):
return EasyDQ(First(expr), x) and EasyDQ(Rest(expr), x)
elif Length(expr)==2:
if FreeQ(expr.args[0], x):
EasyDQ(expr.args[1], x)
elif FreeQ(expr.args[1], x):
return EasyDQ(expr.args[0], x)
else:
return False
return False
def ProductOfLinearPowersQ(u, x):
# ProductOfLinearPowersQ(u, x) returns True iff u is a product of factors of the form v^n where v is linear in x
v = Wild('v')
n = Wild('n', exclude=[x])
M = u.match(v**n)
return FreeQ(u, x) or M and LinearQ(M[v], x) or ProductQ(u) and ProductOfLinearPowersQ(First(u), x) and ProductOfLinearPowersQ(Rest(u), x)
def Rt(u, n):
return RtAux(TogetherSimplify(u), n)
def NthRoot(u, n):
return nsimplify(u**(S(1)/n))
def AtomBaseQ(u):
# If u is an atom or an atom raised to an odd degree, AtomBaseQ(u) returns True; else it returns False
return AtomQ(u) or PowerQ(u) and OddQ(u.args[1]) and AtomBaseQ(u.args[0])
def SumBaseQ(u):
# If u is a sum or a sum raised to an odd degree, SumBaseQ(u) returns True; else it returns False
return SumQ(u) or PowerQ(u) and OddQ(u.args[1]) and SumBaseQ(u.args[0])
def NegSumBaseQ(u):
# If u is a sum or a sum raised to an odd degree whose lead term has a negative form, NegSumBaseQ(u) returns True; else it returns False
return SumQ(u) and NegQ(First(u)) or PowerQ(u) and OddQ(u.args[1]) and NegSumBaseQ(u.args[0])
def AllNegTermQ(u):
# If all terms of u have a negative form, AllNegTermQ(u) returns True; else it returns False
if PowerQ(u):
if OddQ(u.exp):
return AllNegTermQ(u.base)
if SumQ(u):
return NegQ(First(u)) and AllNegTermQ(Rest(u))
return NegQ(u)
def SomeNegTermQ(u):
# If some term of u has a negative form, SomeNegTermQ(u) returns True; else it returns False
if PowerQ(u):
if OddQ(u.exp):
return SomeNegTermQ(u.base)
if SumQ(u):
return NegQ(First(u)) or SomeNegTermQ(Rest(u))
return NegQ(u)
def TrigSquareQ(u):
# If u is an expression of the form Sin(z)^2 or Cos(z)^2, TrigSquareQ(u) returns True, else it returns False
return PowerQ(u) and EqQ(u.args[1], 2) and MemberQ([sin, cos], Head(u.args[0]))
def RtAux(u, n):
if PowerQ(u):
return u.base**(u.exp/n)
if ComplexNumberQ(u):
a = Re(u)
b = Im(u)
if Not(IntegerQ(a) and IntegerQ(b)) and IntegerQ(a/(a**2 + b**2)) and IntegerQ(b/(a**2 + b**2)):
# Basis: a+b*I==1/(a/(a^2+b^2)-b/(a^2+b^2)*I)
return S(1)/RtAux(a/(a**2 + b**2) - b/(a**2 + b**2)*I, n)
else:
return NthRoot(u, n)
if ProductQ(u):
lst = SplitProduct(PositiveQ, u)
if ListQ(lst):
return RtAux(lst[0], n)*RtAux(lst[1], n)
lst = SplitProduct(NegativeQ, u)
if ListQ(lst):
if EqQ(lst[0], -1):
v = lst[1]
if PowerQ(v):
if NegativeQ(v.exp):
return 1/RtAux(-v.base**(-v.exp), n)
if ProductQ(v):
if ListQ(SplitProduct(SumBaseQ, v)):
lst = SplitProduct(AllNegTermQ, v)
if ListQ(lst):
return RtAux(-lst[0], n)*RtAux(lst[1], n)
lst = SplitProduct(NegSumBaseQ, v)
if ListQ(lst):
return RtAux(-lst[0], n)*RtAux(lst[1], n)
lst = SplitProduct(SomeNegTermQ, v)
if ListQ(lst):
return RtAux(-lst[0], n)*RtAux(lst[1], n)
lst = SplitProduct(SumBaseQ, v)
return RtAux(-lst[0], n)*RtAux(lst[1], n)
lst = SplitProduct(AtomBaseQ, v)
if ListQ(lst):
return RtAux(-lst[0], n)*RtAux(lst[1], n)
else:
return RtAux(-First(v), n)*RtAux(Rest(v), n)
if OddQ(n):
return -RtAux(v, n)
else:
return NthRoot(u, n)
else:
return RtAux(-lst[0], n)*RtAux(-lst[1], n)
lst = SplitProduct(AllNegTermQ, u)
if ListQ(lst) and ListQ(SplitProduct(SumBaseQ, lst[1])):
return RtAux(-lst[0], n)*RtAux(-lst[1], n)
lst = SplitProduct(NegSumBaseQ, u)
if ListQ(lst) and ListQ(SplitProduct(NegSumBaseQ, lst[1])):
return RtAux(-lst[0], n)*RtAux(-lst[1], n)
return u.func(*[RtAux(i, n) for i in u.args])
v = TrigSquare(u)
if Not(AtomQ(v)):
return RtAux(v, n)
if OddQ(n) and NegativeQ(u):
return -RtAux(-u, n)
if OddQ(n) and NegQ(u) and PosQ(-u):
return -RtAux(-u, n)
else:
return NthRoot(u, n)
def TrigSquare(u):
# If u is an expression of the form a-a*Sin(z)^2 or a-a*Cos(z)^2, TrigSquare(u) returns Cos(z)^2 or Sin(z)^2 respectively,
# else it returns False.
if SumQ(u):
for i in u.args:
v = SplitProduct(TrigSquareQ, i)
if v == False or SplitSum(v, u) == False:
return False
lst = SplitSum(SplitProduct(TrigSquareQ, i))
if lst and ZeroQ(lst[1][2] + lst[1]):
if Head(lst[0][0].args[0]) == sin:
return lst[1]*cos(lst[1][1][1][1])**2
return lst[1]*sin(lst[1][1][1][1])**2
else:
return False
else:
return False
def IntSum(u, x):
# If u is free of x or of the form c*(a+b*x)^m, IntSum[u,x] returns the antiderivative of u wrt x;
# else it returns d*Int[v,x] where d*v=u and d is free of x.
return Add(*[Integral(i, x) for i in u.args])
def IntTerm(expr, x):
# If u is of the form c*(a+b*x)**m, IntTerm(u,x) returns the antiderivative of u wrt x;
# else it returns d*Int(v,x) where d*v=u and d is free of x.
c = Wild('c', exclude=[x])
m = Wild('m', exclude=[x, 0])
v = Wild('v')
M = expr.match(c/v)
if M and len(M) == 2 and FreeQ(M[c], x) and LinearQ(M[v], x):
return Simp(M[c]*Log(RemoveContent(M[v], x))/Coefficient(M[v], x, 1), x)
M = expr.match(c*v**m)
if M and len(M) == 3 and NonzeroQ(M[m] + 1) and LinearQ(M[v], x):
return Simp(M[c]*M[v]**(M[m] + 1)/(Coefficient(M[v], x, 1)*(M[m] + 1)), x)
if SumQ(expr):
t = 0
for i in expr.args:
t += IntTerm(i, x)
return t
else:
u = expr
return Dist(FreeFactors(u,x), Integral(NonfreeFactors(u, x), x), x)
def Map2(f, lst1, lst2):
result = []
for i in range(0, len(lst1)):
result.append(f(lst1[i], lst2[i]))
return result
def ConstantFactor(u, x):
# (* ConstantFactor[u,x] returns a 2-element list of the factors of u[x] free of x and the
# factors not free of u[x]. Common constant factors of the terms of sums are also collected. *)
if FreeQ(u, x):
return [u, S(1)]
elif AtomQ(u):
return [S(1), u]
elif PowerQ(u):
if FreeQ(u.exp, x):
lst = ConstantFactor(u.base, x)
if IntegerQ(u.exp):
return [lst[0]**u.exp, lst[1]**u.exp]
tmp = PositiveFactors(lst[0])
if tmp == 1:
return [S(1), u]
return [tmp**u.exp, (NonpositiveFactors(lst[0])*lst[1])**u.exp]
elif ProductQ(u):
lst = [ConstantFactor(i, x) for i in u.args]
return [Mul(*[First(i) for i in lst]), Mul(*[i[1] for i in lst])]
elif SumQ(u):
lst1 = [ConstantFactor(i, x) for i in u.args]
if SameQ(*[i[1] for i in lst1]):
return [Add(*[i[0] for i in lst]), lst1[0][1]]
lst2 = CommonFactors([First(i) for i in lst1])
return [First(lst2), Add(*Map2(Mul, Rest(lst2), [i[1] for i in lst1]))]
return [S(1), u]
def SameQ(*args):
for i in range(0, len(args) - 1):
if args[i] != args[i+1]:
return False
return True
def ReplacePart(lst, a, b):
lst[b] = a
return lst
def CommonFactors(lst):
# (* If lst is a list of n terms, CommonFactors[lst] returns a n+1-element list whose first
# element is the product of the factors common to all terms of lst, and whose remaining
# elements are quotients of each term divided by the common factor. *)
lst1 = [NonabsurdNumberFactors(i) for i in lst]
lst2 = [AbsurdNumberFactors(i) for i in lst]
num = AbsurdNumberGCD(*lst2)
common = num
lst2 = [i/num for i in lst2]
while (True):
lst3 = [LeadFactor(i) for i in lst1]
if SameQ(*lst3):
common = common*lst3[0]
lst1 = [RemainingFactors(i) for i in lst1]
elif (all((LogQ(i) and IntegerQ(First(i)) and First(i) > 0) for i in lst3) and
all(RationalQ(i) for i in [FullSimplify(j/First(lst3)) for j in lst3])):
lst4 = [FullSimplify(j/First(lst3)) for j in lst3]
num = GCD(*lst4)
common = common*Log((First(lst3)[0])**num)
lst2 = [lst2[i]*lst4[i]/num for i in range(0, len(lst2))]
lst1 = [RemainingFactors(i) for i in lst1]
lst4 = [LeadDegree(i) for i in lst1]
if SameQ(*[LeadBase(i) for i in lst1]) and RationalQ(*lst4):
num = Smallest(lst4)
base = LeadBase(lst1[0])
if num != 0:
common = common*base**num
lst2 = [lst2[i]*base**(lst4[i] - num) for i in range(0, len(lst2))]
lst1 = [RemainingFactors(i) for i in lst1]
elif (Length(lst1) == 2 and ZeroQ(LeadBase(lst1[0]) + LeadBase(lst1[1])) and
NonzeroQ(lst1[0] - 1) and IntegerQ(lst4[0]) and FractionQ(lst4[1])):
num = Min(*lst4)
base = LeadBase(lst1[1])
if num != 0:
common = common*base**num
lst2 = [lst2[0]*(-1)**lst4[0], lst2[1]]
lst2 = [lst2[i]*base**(lst4[i] - num) for i in range(0, len(lst2))]
lst1 = [RemainingFactors(i) for i in lst1]
elif (Length(lst1) == 2 and ZeroQ(lst1[0] + LeadBase(lst1[1])) and
NonzeroQ(lst1[1] - 1) and IntegerQ(lst1[1]) and FractionQ(lst4[0])):
num = Min(*lst4)
base = LeadBase(lst1[0])
if num != 0:
common = common*base**num
lst2 = [lst2[0], lst2[1]*(-1)**lst4[1]]
lst2 = [lst2[i]*base**(lst4[i] - num) for i in range(0, len(lst2))]
lst1 = [RemainingFactors(i) for i in lst1]
else:
num = MostMainFactorPosition(lst3)
lst2 = ReplacePart(lst2, lst3[num]*lst2[num], num)
lst1 = ReplacePart(lst1, RemainingFactors(lst1[num]), num)
if all(i==1 for i in lst1):
return Prepend(lst2, common)
def MostMainFactorPosition(lst):
factor = S(1)
num = 0
for i in range(0, Length(lst)):
if FactorOrder(lst[i], factor) > 0:
factor = lst[i]
num = i
return num
SbaseS, SexponS = None, None
SexponFlagS = False
def FunctionOfExponentialQ(u, x):
# (* FunctionOfExponentialQ[u,x] returns True iff u is a function of F^v where F is a constant and v is linear in x, *)
# (* and such an exponential explicitly occurs in u (i.e. not just implicitly in hyperbolic functions). *)
global SbaseS, SexponS, SexponFlagS
SbaseS, SexponS = None, None
SexponFlagS = False
res = FunctionOfExponentialTest(u, x)
return res and SexponFlagS
def FunctionOfExponential(u, x):
global SbaseS, SexponS, SexponFlagS
# (* u is a function of F^v where v is linear in x. FunctionOfExponential[u,x] returns F^v. *)
SbaseS, SexponS = None, None
SexponFlagS = False
FunctionOfExponentialTest(u, x)
return SbaseS**SexponS
def FunctionOfExponentialFunction(u, x):
global SbaseS, SexponS, SexponFlagS
# (* u is a function of F^v where v is linear in x. FunctionOfExponentialFunction[u,x] returns u with F^v replaced by x. *)
SbaseS, SexponS = None, None
SexponFlagS = False
FunctionOfExponentialTest(u, x)
return SimplifyIntegrand(FunctionOfExponentialFunctionAux(u, x), x)
def FunctionOfExponentialFunctionAux(u, x):
# (* u is a function of F^v where v is linear in x, and the fluid variables $base$=F and $expon$=v. *)
# (* FunctionOfExponentialFunctionAux[u,x] returns u with F^v replaced by x. *)
global SbaseS, SexponS, SexponFlagS
if AtomQ(u):
return u
elif PowerQ(u):
if FreeQ(u.base, x) and LinearQ(u.exp, x):
if ZeroQ(Coefficient(SexponS, x, 0)):
return u.base**Coefficient(u.exp, x, 0)*x**FullSimplify(Log(u.base)*Coefficient(u.exp, x, 1)/(Log(SbaseS)*Coefficient(SexponS, x, 1)))
return x**FullSimplify(Log(u.base)*Coefficient(u.exp, x, 1)/(Log(SbaseS)*Coefficient(SexponS, x, 1)))
elif HyperbolicQ(u) and LinearQ(u.args[0], x):
tmp = x**FullSimplify(Coefficient(u.args[0], x, 1)/(Log(SbaseS)*Coefficient(SexponS, x, 1)))
if SinhQ(u):
return tmp/2 - 1/(2*tmp)
elif CoshQ(u):
return tmp/2 + 1/(2*tmp)
elif TanhQ(u):
return (tmp - 1/tmp)/(tmp + 1/tmp)
elif CothQ(u):
return (tmp + 1/tmp)/(tmp - 1/tmp)
elif SechQ(u):
return 2/(tmp + 1/tmp)
return 2/(tmp - 1/tmp)
if PowerQ(u):
if FreeQ(u.base, x) and SumQ(u.exp):
return FunctionOfExponentialFunctionAux(u.base**First(u.exp), x)*FunctionOfExponentialFunctionAux(u.base**Rest(u.exp), x)
return u.func(*[FunctionOfExponentialFunctionAux(i, x) for i in u.args])
def FunctionOfExponentialTest(u, x):
# (* FunctionOfExponentialTest[u,x] returns True iff u is a function of F^v where F is a constant and v is linear in x. *)
# (* Before it is called, the fluid variables $base$ and $expon$ should be set to Null and $exponFlag$ to False. *)
# (* If u is a function of F^v, $base$ and $expon$ are set to F and v, respectively. *)
# (* If an explicit exponential occurs in u, $exponFlag$ is set to True. *)
global SbaseS, SexponS, SexponFlagS
if FreeQ(u, x):
return True
elif u == x or CalculusQ(u):
return False
elif PowerQ(u):
if FreeQ(u.base, x) and LinearQ(u.exp, x):
SexponFlagS = True
return FunctionOfExponentialTestAux(u.base, u.exp, x)
elif HyperbolicQ(u) and LinearQ(u.args[0], x):
return FunctionOfExponentialTestAux(E, u.args[0], x)
if PowerQ(u):
if FreeQ(u.base, x) and SumQ(u.exp):
return FunctionOfExponentialTest(u.base**First(u.exp), x) and FunctionOfExponentialTest(u.base**Rest(u.exp), x)
return all(FunctionOfExponentialTest(i, x) for i in u.args)
def FunctionOfExponentialTestAux(base, expon, x):
global SbaseS, SexponS, SexponFlagS
if SbaseS is None:
SbaseS = base
SexponS = expon
return True
tmp = FullSimplify(Log(base)*Coefficient(expon, x, 1)/(Log(SbaseS)*Coefficient(SexponS, x, 1)))
if Not(RationalQ(tmp)):
return False
elif ZeroQ(Coefficient(SexponS, x, 0)) or NonzeroQ(tmp - FullSimplify(Log(base)*Coefficient(expon, x, 0)/(Log(SbaseS)*Coefficient(SexponS, x, 0)))):
if PositiveIntegerQ(base, SbaseS) and base < SbaseS:
SbaseS = base
SexponS = expon
tmp = 1/tmp
SexponS = Coefficient(SexponS, x, 1)*x/Denominator(tmp)
if tmp < 0 and NegQ(Coefficient(SexponS, x, 1)):
SexponS = -SexponS
return True
SexponS = SexponS/Denominator(tmp)
if tmp < 0 and NegQ(Coefficient(SexponS, x, 1)):
SexponS = -SexponS
return True
def stdev(lst):
"""Calculates the standard deviation for a list of numbers."""
num_items = len(lst)
mean = sum(lst) / num_items
differences = [x - mean for x in lst]
sq_differences = [d ** 2 for d in differences]
ssd = sum(sq_differences)
variance = ssd / num_items
sd = sqrt(variance)
return sd
def rubi_test(expr, x, optimal_output, expand=False, _hyper_check=False, _diff=False, _numerical=False):
#Returns True if (expr - optimal_output) is equal to 0 or a constant
#expr: integrated expression
#x: integration variable
#expand=True equates `expr` with `optimal_output` in expanded form
#_hyper_check=True evaluates numerically
#_diff=True differentiates the expressions before equating
#_numerical=True equates the expressions at random `x`. Normally used for large expressions.
from sympy.simplify.simplify import nsimplify
if not expr.has(csc, sec, cot, csch, sech, coth):
optimal_output = process_trig(optimal_output)
if expr == optimal_output:
return True
if simplify(expr) == simplify(optimal_output):
return True
if nsimplify(expr) == nsimplify(optimal_output):
return True
if expr.has(sym_exp):
expr = powsimp(powdenest(expr), force=True)
if simplify(expr) == simplify(powsimp(optimal_output, force=True)):
return True
res = expr - optimal_output
if _numerical:
args = res.free_symbols
rand_val = []
try:
for i in range(0, 5): # check at 5 random points
rand_x = randint(1, 40)
substitutions = {s: rand_x for s in args}
rand_val.append(float(abs(res.subs(substitutions).n())))
if stdev(rand_val) < Pow(10, -3):
return True
except:
pass
# return False
dres = res.diff(x)
if _numerical:
args = dres.free_symbols
rand_val = []
try:
for i in range(0, 5): # check at 5 random points
rand_x = randint(1, 40)
substitutions = {s: rand_x for s in args}
rand_val.append(float(abs(dres.subs(substitutions).n())))
if stdev(rand_val) < Pow(10, -3):
return True
# return False
except:
pass
# return False
r = Simplify(nsimplify(res))
if r == 0 or (not r.has(x)):
return True
if _diff:
if dres == 0:
return True
elif Simplify(dres) == 0:
return True
if expand: # expands the expression and equates
e = res.expand()
if Simplify(e) == 0 or (not e.has(x)):
return True
return False
def If(cond, t, f):
# returns t if condition is true else f
if cond:
return t
return f
def IntQuadraticQ(a, b, c, d, e, m, p, x):
# (* IntQuadraticQ[a,b,c,d,e,m,p,x] returns True iff (d+e*x)^m*(a+b*x+c*x^2)^p is integrable wrt x in terms of non-Appell functions. *)
return IntegerQ(p) or PositiveIntegerQ(m) or IntegersQ(2*m, 2*p) or IntegersQ(m, 4*p) or IntegersQ(m, p + S(1)/3) and (ZeroQ(c**2*d**2 - b*c*d*e + b**2*e**2 - 3*a*c*e**2) or ZeroQ(c**2*d**2 - b*c*d*e - 2*b**2*e**2 + 9*a*c*e**2))
def IntBinomialQ(*args):
#(* IntBinomialQ(a,b,c,n,m,p,x) returns True iff (c*x)^m*(a+b*x^n)^p is integrable wrt x in terms of non-hypergeometric functions. *)
if len(args) == 8:
a, b, c, d, n, p, q, x = args
return IntegersQ(p,q) or PositiveIntegerQ(p) or PositiveIntegerQ(q) or (ZeroQ(n-2) or ZeroQ(n-4)) and (IntegersQ(p,4*q) or IntegersQ(4*p,q)) or ZeroQ(n-2) and (IntegersQ(2*p,2*q) or IntegersQ(3*p,q) and ZeroQ(b*c+3*a*d) or IntegersQ(p,3*q) and ZeroQ(3*b*c+a*d))
elif len(args) == 7:
a, b, c, n, m, p, x = args
return IntegerQ(2*p) or IntegerQ((m+1)/n + p) or (ZeroQ(n - 2) or ZeroQ(n - 4)) and IntegersQ(2*m, 4*p) or ZeroQ(n - 2) and IntegerQ(6*p) and (IntegerQ(m) or IntegerQ(m - p))
elif len(args) == 10:
a, b, c, d, e, m, n, p, q, x = args
return IntegersQ(p,q) or PositiveIntegerQ(p) or PositiveIntegerQ(q) or ZeroQ(n-2) and IntegerQ(m) and IntegersQ(2*p,2*q) or ZeroQ(n-4) and (IntegersQ(m,p,2*q) or IntegersQ(m,2*p,q))
def RectifyTangent(*args):
# (* RectifyTangent(u,a,b,r,x) returns an expression whose derivative equals the derivative of r*ArcTan(a+b*Tan(u)) wrt x. *)
if len(args) == 5:
u, a, b, r, x = args
t1 = Together(a)
t2 = Together(b)
if (PureComplexNumberQ(t1) or (ProductQ(t1) and any(PureComplexNumberQ(i) for i in t1.args))) and (PureComplexNumberQ(t2) or ProductQ(t2) and any(PureComplexNumberQ(i) for i in t2.args)):
c = a/I
d = b/I
if NegativeQ(d):
return RectifyTangent(u, -a, -b, -r, x)
e = SmartDenominator(Together(c + d*x))
c = c*e
d = d*e
if EvenQ(Denominator(NumericFactor(Together(u)))):
return I*r*Log(RemoveContent(Simplify((c+e)**2+d**2)+Simplify((c+e)**2-d**2)*Cos(2*u)+Simplify(2*(c+e)*d)*Sin(2*u),x))/4 - I*r*Log(RemoveContent(Simplify((c-e)**2+d**2)+Simplify((c-e)**2-d**2)*Cos(2*u)+Simplify(2*(c-e)*d)*Sin(2*u),x))/4
return I*r*Log(RemoveContent(Simplify((c+e)**2)+Simplify(2*(c+e)*d)*Cos(u)*Sin(u)-Simplify((c+e)**2-d**2)*Sin(u)**2,x))/4 - I*r*Log(RemoveContent(Simplify((c-e)**2)+Simplify(2*(c-e)*d)*Cos(u)*Sin(u)-Simplify((c-e)**2-d**2)*Sin(u)**2,x))/4
elif NegativeQ(b):
return RectifyTangent(u, -a, -b, -r, x)
elif EvenQ(Denominator(NumericFactor(Together(u)))):
return r*SimplifyAntiderivative(u,x) + r*ArcTan(Simplify((2*a*b*Cos(2*u)-(1+a**2-b**2)*Sin(2*u))/(a**2+(1+b)**2+(1+a**2-b**2)*Cos(2*u)+2*a*b*Sin(2*u))))
return r*SimplifyAntiderivative(u,x) - r*ArcTan(ActivateTrig(Simplify((a*b-2*a*b*cos(u)**2+(1+a**2-b**2)*cos(u)*sin(u))/(b*(1+b)+(1+a**2-b**2)*cos(u)**2+2*a*b*cos(u)*sin(u)))))
u, a, b, x = args
t = Together(a)
if PureComplexNumberQ(t) or (ProductQ(t) and any(PureComplexNumberQ(i) for i in t.args)):
c = a/I
if NegativeQ(c):
return RectifyTangent(u, -a, -b, x)
if ZeroQ(c - 1):
if EvenQ(Denominator(NumericFactor(Together(u)))):
return I*b*ArcTanh(Sin(2*u))/2
return I*b*ArcTanh(2*cos(u)*sin(u))/2
e = SmartDenominator(c)
c = c*e
return I*b*Log(RemoveContent(e*Cos(u)+c*Sin(u),x))/2 - I*b*Log(RemoveContent(e*Cos(u)-c*Sin(u),x))/2
elif NegativeQ(a):
return RectifyTangent(u, -a, -b, x)
elif ZeroQ(a - 1):
return b*SimplifyAntiderivative(u, x)
elif EvenQ(Denominator(NumericFactor(Together(u)))):
c = Simplify((1 + a)/(1 - a))
numr = SmartNumerator(c)
denr = SmartDenominator(c)
return b*SimplifyAntiderivative(u,x) - b*ArcTan(NormalizeLeadTermSigns(denr*Sin(2*u)/(numr+denr*Cos(2*u)))),
elif PositiveQ(a - 1):
c = Simplify(1/(a - 1))
numr = SmartNumerator(c)
denr = SmartDenominator(c)
return b*SimplifyAntiderivative(u,x) + b*ArcTan(NormalizeLeadTermSigns(denr*Cos(u)*Sin(u)/(numr+denr*Sin(u)**2))),
c = Simplify(a/(1 - a))
numr = SmartNumerator(c)
denr = SmartDenominator(c)
return b*SimplifyAntiderivative(u,x) - b*ArcTan(NormalizeLeadTermSigns(denr*Cos(u)*Sin(u)/(numr+denr*Cos(u)**2)))
def RectifyCotangent(*args):
#(* RectifyCotangent[u,a,b,r,x] returns an expression whose derivative equals the derivative of r*ArcTan[a+b*Cot[u]] wrt x. *)
if len(args) == 5:
u, a, b, r, x = args
t1 = Together(a)
t2 = Together(b)
if (PureComplexNumberQ(t1) or (ProductQ(t1) and any(PureComplexNumberQ(i) for i in t1.args))) and (PureComplexNumberQ(t2) or ProductQ(t2) and any(PureComplexNumberQ(i) for i in t2.args)):
c = a/I
d = b/I
if NegativeQ(d):
return RectifyTangent(u,-a,-b,-r,x)
e = SmartDenominator(Together(c + d*x))
c = c*e
d = d*e
if EvenQ(Denominator(NumericFactor(Together(u)))):
return I*r*Log(RemoveContent(Simplify((c+e)**2+d**2)-Simplify((c+e)**2-d**2)*Cos(2*u)+Simplify(2*(c+e)*d)*Sin(2*u),x))/4 - I*r*Log(RemoveContent(Simplify((c-e)**2+d**2)-Simplify((c-e)**2-d**2)*Cos(2*u)+Simplify(2*(c-e)*d)*Sin(2*u),x))/4
return I*r*Log(RemoveContent(Simplify((c+e)**2)-Simplify((c+e)**2-d**2)*Cos(u)**2+Simplify(2*(c+e)*d)*Cos(u)*Sin(u),x))/4 - I*r*Log(RemoveContent(Simplify((c-e)**2)-Simplify((c-e)**2-d**2)*Cos(u)**2+Simplify(2*(c-e)*d)*Cos(u)*Sin(u),x))/4
elif NegativeQ(b):
return RectifyCotangent(u,-a,-b,-r,x)
elif EvenQ(Denominator(NumericFactor(Together(u)))):
return -r*SimplifyAntiderivative(u,x) - r*ArcTan(Simplify((2*a*b*Cos(2*u)+(1+a**2-b**2)*Sin(2*u))/(a**2+(1+b)**2-(1+a**2-b**2)*Cos(2*u)+2*a*b*Sin(2*u))))
return -r*SimplifyAntiderivative(u,x) - r*ArcTan(ActivateTrig(Simplify((a*b-2*a*b*sin(u)**2+(1+a**2-b**2)*cos(u)*sin(u))/(b*(1+b)+(1+a**2-b**2)*sin(u)**2+2*a*b*cos(u)*sin(u)))))
u, a, b, x = args
t = Together(a)
if PureComplexNumberQ(t) or (ProductQ(t) and any(PureComplexNumberQ(i) for i in t.args)):
c = a/I
if NegativeQ(c):
return RectifyCotangent(u,-a,-b,x)
elif ZeroQ(c - 1):
if EvenQ(Denominator(NumericFactor(Together(u)))):
return -I*b*ArcTanh(Sin(2*u))/2
return -I*b*ArcTanh(2*Cos(u)*Sin(u))/2
e = SmartDenominator(c)
c = c*e
return -I*b*Log(RemoveContent(c*Cos(u)+e*Sin(u),x))/2 + I*b*Log(RemoveContent(c*Cos(u)-e*Sin(u),x))/2
elif NegativeQ(a):
return RectifyCotangent(u,-a,-b,x)
elif ZeroQ(a-1):
return b*SimplifyAntiderivative(u,x)
elif EvenQ(Denominator(NumericFactor(Together(u)))):
c = Simplify(a - 1)
numr = SmartNumerator(c)
denr = SmartDenominator(c)
return b*SimplifyAntiderivative(u,x) - b*ArcTan(NormalizeLeadTermSigns(denr*Cos(u)*Sin(u)/(numr+denr*Cos(u)**2)))
c = Simplify(a/(1-a))
numr = SmartNumerator(c)
denr = SmartDenominator(c)
return b*SimplifyAntiderivative(u,x) + b*ArcTan(NormalizeLeadTermSigns(denr*Cos(u)*Sin(u)/(numr+denr*Sin(u)**2)))
def Inequality(*args):
f = args[1::2]
e = args[0::2]
r = []
for i in range(0, len(f)):
r.append(f[i](e[i], e[i + 1]))
return all(r)
def Condition(r, c):
# returns r if c is True
if c:
return r
else:
raise NotImplementedError('In Condition()')
def Simp(u, x):
u = replace_pow_exp(u)
return NormalizeSumFactors(SimpHelp(u, x))
def SimpHelp(u, x):
if AtomQ(u):
return u
elif FreeQ(u, x):
v = SmartSimplify(u)
if LeafCount(v) <= LeafCount(u):
return v
return u
elif ProductQ(u):
#m = MatchQ[Rest[u],a_.+n_*Pi+b_.*v_ /; FreeQ[{a,b},x] && Not[FreeQ[v,x]] && EqQ[n^2,1/4]]
#if EqQ(First(u), S(1)/2) and m:
# if
#If[EqQ[First[u],1/2] && MatchQ[Rest[u],a_.+n_*Pi+b_.*v_ /; FreeQ[{a,b},x] && Not[FreeQ[v,x]] && EqQ[n^2,1/4]],
# If[MatchQ[Rest[u],n_*Pi+b_.*v_ /; FreeQ[b,x] && Not[FreeQ[v,x]] && EqQ[n^2,1/4]],
# Map[Function[1/2*#],Rest[u]],
# If[MatchQ[Rest[u],m_*a_.+n_*Pi+p_*b_.*v_ /; FreeQ[{a,b},x] && Not[FreeQ[v,x]] && IntegersQ[m/2,p/2]],
# Map[Function[1/2*#],Rest[u]],
# u]],
v = FreeFactors(u, x)
w = NonfreeFactors(u, x)
v = NumericFactor(v)*SmartSimplify(NonnumericFactors(v)*x**2)/x**2
if ProductQ(w):
w = Mul(*[SimpHelp(i,x) for i in w.args])
else:
w = SimpHelp(w, x)
w = FactorNumericGcd(w)
v = MergeFactors(v, w)
if ProductQ(v):
return Mul(*[SimpFixFactor(i, x) for i in v.args])
return v
elif SumQ(u):
Pi = pi
a_ = Wild('a', exclude=[x])
b_ = Wild('b', exclude=[x, 0])
n_ = Wild('n', exclude=[x, 0, 0])
pattern = a_ + n_*Pi + b_*x
match = u.match(pattern)
m = False
if match:
if EqQ(match[n_]**3, S(1)/16):
m = True
if m:
return u
elif PolynomialQ(u, x) and Exponent(u, x) <= 0:
return SimpHelp(Coefficient(u, x, 0), x)
elif PolynomialQ(u, x) and Exponent(u, x) == 1 and Coefficient(u, x, 0) == 0:
return SimpHelp(Coefficient(u, x, 1), x)*x
v = 0
w = 0
for i in u.args:
if FreeQ(i, x):
v = i + v
else:
w = i + w
v = SmartSimplify(v)
if SumQ(w):
w = Add(*[SimpHelp(i, x) for i in w.args])
else:
w = SimpHelp(w, x)
return v + w
return u.func(*[SimpHelp(i, x) for i in u.args])
def SplitProduct(func, u):
#(* If func[v] is True for a factor v of u, SplitProduct[func,u] returns {v, u/v} where v is the first such factor; else it returns False. *)
if ProductQ(u):
if func(First(u)):
return [First(u), Rest(u)]
lst = SplitProduct(func, Rest(u))
if AtomQ(lst):
return False
return [lst[0], First(u)*lst[1]]
if func(u):
return [u, 1]
return False
def SplitSum(func, u):
# (* If func[v] is nonatomic for a term v of u, SplitSum[func,u] returns {func[v], u-v} where v is the first such term; else it returns False. *)
if SumQ(u):
if Not(AtomQ(func(First(u)))):
return [func(First(u)), Rest(u)]
lst = SplitSum(func, Rest(u))
if AtomQ(lst):
return False
return [lst[0], First(u) + lst[1]]
elif Not(AtomQ(func(u))):
return [func(u), 0]
return False
def SubstFor(*args):
if len(args) == 4:
w, v, u, x = args
# u is a function of v. SubstFor(w,v,u,x) returns w times u with v replaced by x.
return SimplifyIntegrand(w*SubstFor(v, u, x), x)
v, u, x = args
# u is a function of v. SubstFor(v, u, x) returns u with v replaced by x.
if AtomQ(v):
return Subst(u, v, x)
elif Not(EqQ(FreeFactors(v, x), 1)):
return SubstFor(NonfreeFactors(v, x), u, x/FreeFactors(v, x))
elif SinQ(v):
return SubstForTrig(u, x, Sqrt(1 - x**2), v.args[0], x)
elif CosQ(v):
return SubstForTrig(u, Sqrt(1 - x**2), x, v.args[0], x)
elif TanQ(v):
return SubstForTrig(u, x/Sqrt(1 + x**2), 1/Sqrt(1 + x**2), v.args[0], x)
elif CotQ(v):
return SubstForTrig(u, 1/Sqrt(1 + x**2), x/Sqrt(1 + x**2), v.args[0], x)
elif SecQ(v):
return SubstForTrig(u, 1/Sqrt(1 - x**2), 1/x, v.args[0], x)
elif CscQ(v):
return SubstForTrig(u, 1/x, 1/Sqrt(1 - x**2), v.args[0], x)
elif SinhQ(v):
return SubstForHyperbolic(u, x, Sqrt(1 + x**2), v.args[0], x)
elif CoshQ(v):
return SubstForHyperbolic(u, Sqrt( - 1 + x**2), x, v.args[0], x)
elif TanhQ(v):
return SubstForHyperbolic(u, x/Sqrt(1 - x**2), 1/Sqrt(1 - x**2), v.args[0], x)
elif CothQ(v):
return SubstForHyperbolic(u, 1/Sqrt( - 1 + x**2), x/Sqrt( - 1 + x**2), v.args[0], x)
elif SechQ(v):
return SubstForHyperbolic(u, 1/Sqrt( - 1 + x**2), 1/x, v.args[0], x)
elif CschQ(v):
return SubstForHyperbolic(u, 1/x, 1/Sqrt(1 + x**2), v.args[0], x)
else:
return SubstForAux(u, v, x)
def SubstForAux(u, v, x):
# u is a function of v. SubstForAux(u, v, x) returns u with v replaced by x.
if u==v:
return x
elif AtomQ(u):
if PowerQ(v):
if FreeQ(v.exp, x) and ZeroQ(u - v.base):
return x**Simplify(1/v.exp)
return u
elif PowerQ(u):
if FreeQ(u.exp, x):
if ZeroQ(u.base - v):
return x**u.exp
if PowerQ(v):
if FreeQ(v.exp, x) and ZeroQ(u.base - v.base):
return x**Simplify(u.exp/v.exp)
return SubstForAux(u.base, v, x)**u.exp
elif ProductQ(u) and Not(EqQ(FreeFactors(u, x), 1)):
return FreeFactors(u, x)*SubstForAux(NonfreeFactors(u, x), v, x)
elif ProductQ(u) and ProductQ(v):
return SubstForAux(First(u), First(v), x)
return u.func(*[SubstForAux(i, v, x) for i in u.args])
def FresnelS(x):
return fresnels(x)
def FresnelC(x):
return fresnelc(x)
def Erf(x):
return erf(x)
def Erfc(x):
return erfc(x)
def Erfi(x):
return erfi(x)
class Gamma(Function):
@classmethod
def eval(cls,*args):
a = args[0]
if len(args) == 1:
return gamma(a)
else:
b = args[1]
if (NumericQ(a) and NumericQ(b)) or a == 1:
return uppergamma(a, b)
def FunctionOfTrigOfLinearQ(u, x):
# If u is an algebraic function of trig functions of a linear function of x,
# FunctionOfTrigOfLinearQ[u,x] returns True; else it returns False.
if FunctionOfTrig(u, None, x) and AlgebraicTrigFunctionQ(u, x) and FunctionOfLinear(FunctionOfTrig(u, None, x), x):
return True
else:
return False
def ElementaryFunctionQ(u):
# ElementaryExpressionQ[u] returns True if u is a sum, product, or power and all the operands
# are elementary expressions; or if u is a call on a trig, hyperbolic, or inverse function
# and all the arguments are elementary expressions; else it returns False.
if AtomQ(u):
return True
elif SumQ(u) or ProductQ(u) or PowerQ(u) or TrigQ(u) or HyperbolicQ(u) or InverseFunctionQ(u):
for i in u.args:
if not ElementaryFunctionQ(i):
return False
return True
return False
def Complex(a, b):
return a + I*b
def UnsameQ(a, b):
return a != b
@doctest_depends_on(modules=('matchpy',))
def _SimpFixFactor():
replacer = ManyToOneReplacer()
pattern1 = Pattern(UtilityOperator(Pow(Add(Mul(Complex(S(0), c_), WC('a', S(1))), Mul(Complex(S(0), d_), WC('b', S(1)))), WC('p', S(1))), x_), CustomConstraint(lambda p: IntegerQ(p)))
rule1 = ReplacementRule(pattern1, lambda b, c, x, a, p, d : Mul(Pow(I, p), SimpFixFactor(Pow(Add(Mul(a, c), Mul(b, d)), p), x)))
replacer.add(rule1)
pattern2 = Pattern(UtilityOperator(Pow(Add(Mul(Complex(S(0), d_), WC('a', S(1))), Mul(Complex(S(0), e_), WC('b', S(1))), Mul(Complex(S(0), f_), WC('c', S(1)))), WC('p', S(1))), x_), CustomConstraint(lambda p: IntegerQ(p)))
rule2 = ReplacementRule(pattern2, lambda b, c, x, f, a, p, e, d : Mul(Pow(I, p), SimpFixFactor(Pow(Add(Mul(a, d), Mul(b, e), Mul(c, f)), p), x)))
replacer.add(rule2)
pattern3 = Pattern(UtilityOperator(Pow(Add(Mul(WC('a', S(1)), Pow(c_, r_)), Mul(WC('b', S(1)), Pow(x_, WC('n', S(1))))), WC('p', S(1))), x_), CustomConstraint(lambda a, x: FreeQ(a, x)), CustomConstraint(lambda b, x: FreeQ(b, x)), CustomConstraint(lambda c, x: FreeQ(c, x)), CustomConstraint(lambda n, p: IntegersQ(n, p)), CustomConstraint(lambda c: AtomQ(c)), CustomConstraint(lambda r: RationalQ(r)), CustomConstraint(lambda r: Less(r, S(0))))
rule3 = ReplacementRule(pattern3, lambda b, c, r, n, x, a, p : Mul(Pow(c, Mul(r, p)), SimpFixFactor(Pow(Add(a, Mul(Mul(b, Pow(Pow(c, r), S(-1))), Pow(x, n))), p), x)))
replacer.add(rule3)
pattern4 = Pattern(UtilityOperator(Pow(Add(WC('a', S(0)), Mul(WC('b', S(1)), Pow(c_, r_), Pow(x_, WC('n', S(1))))), WC('p', S(1))), x_), CustomConstraint(lambda a, x: FreeQ(a, x)), CustomConstraint(lambda b, x: FreeQ(b, x)), CustomConstraint(lambda c, x: FreeQ(c, x)), CustomConstraint(lambda n, p: IntegersQ(n, p)), CustomConstraint(lambda c: AtomQ(c)), CustomConstraint(lambda r: RationalQ(r)), CustomConstraint(lambda r: Less(r, S(0))))
rule4 = ReplacementRule(pattern4, lambda b, c, r, n, x, a, p : Mul(Pow(c, Mul(r, p)), SimpFixFactor(Pow(Add(Mul(a, Pow(Pow(c, r), S(-1))), Mul(b, Pow(x, n))), p), x)))
replacer.add(rule4)
pattern5 = Pattern(UtilityOperator(Pow(Add(Mul(WC('a', S(1)), Pow(c_, WC('s', S(1)))), Mul(WC('b', S(1)), Pow(c_, WC('r', S(1))), Pow(x_, WC('n', S(1))))), WC('p', S(1))), x_), CustomConstraint(lambda a, x: FreeQ(a, x)), CustomConstraint(lambda b, x: FreeQ(b, x)), CustomConstraint(lambda c, x: FreeQ(c, x)), CustomConstraint(lambda n, p: IntegersQ(n, p)), CustomConstraint(lambda r, s: RationalQ(s, r)), CustomConstraint(lambda r, s: Inequality(S(0), Less, s, LessEqual, r)), CustomConstraint(lambda p, c, s: UnsameQ(Pow(c, Mul(s, p)), S(-1))))
rule5 = ReplacementRule(pattern5, lambda b, c, r, n, x, a, p, s : Mul(Pow(c, Mul(s, p)), SimpFixFactor(Pow(Add(a, Mul(b, Pow(c, Add(r, Mul(S(-1), s))), Pow(x, n))), p), x)))
replacer.add(rule5)
pattern6 = Pattern(UtilityOperator(Pow(Add(Mul(WC('a', S(1)), Pow(c_, WC('s', S(1)))), Mul(WC('b', S(1)), Pow(c_, WC('r', S(1))), Pow(x_, WC('n', S(1))))), WC('p', S(1))), x_), CustomConstraint(lambda a, x: FreeQ(a, x)), CustomConstraint(lambda b, x: FreeQ(b, x)), CustomConstraint(lambda c, x: FreeQ(c, x)), CustomConstraint(lambda n, p: IntegersQ(n, p)), CustomConstraint(lambda r, s: RationalQ(s, r)), CustomConstraint(lambda s, r: Less(S(0), r, s)), CustomConstraint(lambda p, c, r: UnsameQ(Pow(c, Mul(r, p)), S(-1))))
rule6 = ReplacementRule(pattern6, lambda b, c, r, n, x, a, p, s : Mul(Pow(c, Mul(r, p)), SimpFixFactor(Pow(Add(Mul(a, Pow(c, Add(s, Mul(S(-1), r)))), Mul(b, Pow(x, n))), p), x)))
replacer.add(rule6)
return replacer
@doctest_depends_on(modules=('matchpy',))
def SimpFixFactor(expr, x):
r = SimpFixFactor_replacer.replace(UtilityOperator(expr, x))
if isinstance(r, UtilityOperator):
return expr
return r
@doctest_depends_on(modules=('matchpy',))
def _FixSimplify():
Plus = Add
def cons_f1(n):
return OddQ(n)
cons1 = CustomConstraint(cons_f1)
def cons_f2(m):
return RationalQ(m)
cons2 = CustomConstraint(cons_f2)
def cons_f3(n):
return FractionQ(n)
cons3 = CustomConstraint(cons_f3)
def cons_f4(u):
return SqrtNumberSumQ(u)
cons4 = CustomConstraint(cons_f4)
def cons_f5(v):
return SqrtNumberSumQ(v)
cons5 = CustomConstraint(cons_f5)
def cons_f6(u):
return PositiveQ(u)
cons6 = CustomConstraint(cons_f6)
def cons_f7(v):
return PositiveQ(v)
cons7 = CustomConstraint(cons_f7)
def cons_f8(v):
return SqrtNumberSumQ(S(1)/v)
cons8 = CustomConstraint(cons_f8)
def cons_f9(m):
return IntegerQ(m)
cons9 = CustomConstraint(cons_f9)
def cons_f10(u):
return NegativeQ(u)
cons10 = CustomConstraint(cons_f10)
def cons_f11(n, m, a, b):
return RationalQ(a, b, m, n)
cons11 = CustomConstraint(cons_f11)
def cons_f12(a):
return Greater(a, S(0))
cons12 = CustomConstraint(cons_f12)
def cons_f13(b):
return Greater(b, S(0))
cons13 = CustomConstraint(cons_f13)
def cons_f14(p):
return PositiveIntegerQ(p)
cons14 = CustomConstraint(cons_f14)
def cons_f15(p):
return IntegerQ(p)
cons15 = CustomConstraint(cons_f15)
def cons_f16(p, n):
return Greater(-n + p, S(0))
cons16 = CustomConstraint(cons_f16)
def cons_f17(a, b):
return SameQ(a + b, S(0))
cons17 = CustomConstraint(cons_f17)
def cons_f18(n):
return Not(IntegerQ(n))
cons18 = CustomConstraint(cons_f18)
def cons_f19(c, a, b, d):
return ZeroQ(-a*d + b*c)
cons19 = CustomConstraint(cons_f19)
def cons_f20(a):
return Not(RationalQ(a))
cons20 = CustomConstraint(cons_f20)
def cons_f21(t):
return IntegerQ(t)
cons21 = CustomConstraint(cons_f21)
def cons_f22(n, m):
return RationalQ(m, n)
cons22 = CustomConstraint(cons_f22)
def cons_f23(n, m):
return Inequality(S(0), Less, m, LessEqual, n)
cons23 = CustomConstraint(cons_f23)
def cons_f24(p, n, m):
return RationalQ(m, n, p)
cons24 = CustomConstraint(cons_f24)
def cons_f25(p, n, m):
return Inequality(S(0), Less, m, LessEqual, n, LessEqual, p)
cons25 = CustomConstraint(cons_f25)
def cons_f26(p, n, m, q):
return Inequality(S(0), Less, m, LessEqual, n, LessEqual, p, LessEqual, q)
cons26 = CustomConstraint(cons_f26)
def cons_f27(w):
return Not(RationalQ(w))
cons27 = CustomConstraint(cons_f27)
def cons_f28(n):
return Less(n, S(0))
cons28 = CustomConstraint(cons_f28)
def cons_f29(n, w, v):
return ZeroQ(v + w**(-n))
cons29 = CustomConstraint(cons_f29)
def cons_f30(n):
return IntegerQ(n)
cons30 = CustomConstraint(cons_f30)
def cons_f31(w, v):
return ZeroQ(v + w)
cons31 = CustomConstraint(cons_f31)
def cons_f32(p, n):
return IntegerQ(n/p)
cons32 = CustomConstraint(cons_f32)
def cons_f33(w, v):
return ZeroQ(v - w)
cons33 = CustomConstraint(cons_f33)
def cons_f34(p, n):
return IntegersQ(n, n/p)
cons34 = CustomConstraint(cons_f34)
def cons_f35(a):
return AtomQ(a)
cons35 = CustomConstraint(cons_f35)
def cons_f36(b):
return AtomQ(b)
cons36 = CustomConstraint(cons_f36)
pattern1 = Pattern(UtilityOperator((w_ + Complex(S(0), b_)*WC('v', S(1)))**WC('n', S(1))*Complex(S(0), a_)*WC('u', S(1))), cons1)
def replacement1(n, u, w, v, a, b):
return (S(-1))**(n/S(2) + S(1)/2)*a*u*FixSimplify((b*v - w*Complex(S(0), S(1)))**n)
rule1 = ReplacementRule(pattern1, replacement1)
def With2(m, n, u, w, v):
z = u**(m/GCD(m, n))*v**(n/GCD(m, n))
if Or(AbsurdNumberQ(z), SqrtNumberSumQ(z)):
return True
return False
pattern2 = Pattern(UtilityOperator(u_**WC('m', S(1))*v_**n_*WC('w', S(1))), cons2, cons3, cons4, cons5, cons6, cons7, CustomConstraint(With2))
def replacement2(m, n, u, w, v):
z = u**(m/GCD(m, n))*v**(n/GCD(m, n))
return FixSimplify(w*z**GCD(m, n))
rule2 = ReplacementRule(pattern2, replacement2)
def With3(m, n, u, w, v):
z = u**(m/GCD(m, -n))*v**(n/GCD(m, -n))
if Or(AbsurdNumberQ(z), SqrtNumberSumQ(z)):
return True
return False
pattern3 = Pattern(UtilityOperator(u_**WC('m', S(1))*v_**n_*WC('w', S(1))), cons2, cons3, cons4, cons8, cons6, cons7, CustomConstraint(With3))
def replacement3(m, n, u, w, v):
z = u**(m/GCD(m, -n))*v**(n/GCD(m, -n))
return FixSimplify(w*z**GCD(m, -n))
rule3 = ReplacementRule(pattern3, replacement3)
def With4(m, n, u, w, v):
z = v**(n/GCD(m, n))*(-u)**(m/GCD(m, n))
if Or(AbsurdNumberQ(z), SqrtNumberSumQ(z)):
return True
return False
pattern4 = Pattern(UtilityOperator(u_**WC('m', S(1))*v_**n_*WC('w', S(1))), cons9, cons3, cons4, cons5, cons10, cons7, CustomConstraint(With4))
def replacement4(m, n, u, w, v):
z = v**(n/GCD(m, n))*(-u)**(m/GCD(m, n))
return FixSimplify(-w*z**GCD(m, n))
rule4 = ReplacementRule(pattern4, replacement4)
def With5(m, n, u, w, v):
z = v**(n/GCD(m, -n))*(-u)**(m/GCD(m, -n))
if Or(AbsurdNumberQ(z), SqrtNumberSumQ(z)):
return True
return False
pattern5 = Pattern(UtilityOperator(u_**WC('m', S(1))*v_**n_*WC('w', S(1))), cons9, cons3, cons4, cons8, cons10, cons7, CustomConstraint(With5))
def replacement5(m, n, u, w, v):
z = v**(n/GCD(m, -n))*(-u)**(m/GCD(m, -n))
return FixSimplify(-w*z**GCD(m, -n))
rule5 = ReplacementRule(pattern5, replacement5)
def With6(p, m, n, u, w, v, a, b):
c = a**(m/p)*b**n
if RationalQ(c):
return True
return False
pattern6 = Pattern(UtilityOperator(a_**m_*(b_**n_*WC('v', S(1)) + u_)**WC('p', S(1))*WC('w', S(1))), cons11, cons12, cons13, cons14, CustomConstraint(With6))
def replacement6(p, m, n, u, w, v, a, b):
c = a**(m/p)*b**n
return FixSimplify(w*(a**(m/p)*u + c*v)**p)
rule6 = ReplacementRule(pattern6, replacement6)
pattern7 = Pattern(UtilityOperator(a_**WC('m', S(1))*(a_**n_*WC('u', S(1)) + b_**WC('p', S(1))*WC('v', S(1)))*WC('w', S(1))), cons2, cons3, cons15, cons16, cons17)
def replacement7(p, m, n, u, w, v, a, b):
return FixSimplify(a**(m + n)*w*((S(-1))**p*a**(-n + p)*v + u))
rule7 = ReplacementRule(pattern7, replacement7)
def With8(m, d, n, w, c, a, b):
q = b/d
if FreeQ(q, Plus):
return True
return False
pattern8 = Pattern(UtilityOperator((a_ + b_)**WC('m', S(1))*(c_ + d_)**n_*WC('w', S(1))), cons9, cons18, cons19, CustomConstraint(With8))
def replacement8(m, d, n, w, c, a, b):
q = b/d
return FixSimplify(q**m*w*(c + d)**(m + n))
rule8 = ReplacementRule(pattern8, replacement8)
pattern9 = Pattern(UtilityOperator((a_**WC('m', S(1))*WC('u', S(1)) + a_**WC('n', S(1))*WC('v', S(1)))**WC('t', S(1))*WC('w', S(1))), cons20, cons21, cons22, cons23)
def replacement9(m, n, u, w, v, a, t):
return FixSimplify(a**(m*t)*w*(a**(-m + n)*v + u)**t)
rule9 = ReplacementRule(pattern9, replacement9)
pattern10 = Pattern(UtilityOperator((a_**WC('m', S(1))*WC('u', S(1)) + a_**WC('n', S(1))*WC('v', S(1)) + a_**WC('p', S(1))*WC('z', S(1)))**WC('t', S(1))*WC('w', S(1))), cons20, cons21, cons24, cons25)
def replacement10(p, m, n, u, w, v, a, z, t):
return FixSimplify(a**(m*t)*w*(a**(-m + n)*v + a**(-m + p)*z + u)**t)
rule10 = ReplacementRule(pattern10, replacement10)
pattern11 = Pattern(UtilityOperator((a_**WC('m', S(1))*WC('u', S(1)) + a_**WC('n', S(1))*WC('v', S(1)) + a_**WC('p', S(1))*WC('z', S(1)) + a_**WC('q', S(1))*WC('y', S(1)))**WC('t', S(1))*WC('w', S(1))), cons20, cons21, cons24, cons26)
def replacement11(p, m, n, u, q, w, v, a, z, y, t):
return FixSimplify(a**(m*t)*w*(a**(-m + n)*v + a**(-m + p)*z + a**(-m + q)*y + u)**t)
rule11 = ReplacementRule(pattern11, replacement11)
pattern12 = Pattern(UtilityOperator((sqrt(v_)*WC('b', S(1)) + sqrt(v_)*WC('c', S(1)) + sqrt(v_)*WC('d', S(1)) + sqrt(v_)*WC('a', S(1)) + WC('u', S(0)))*WC('w', S(1))))
def replacement12(d, u, w, v, c, a, b):
return FixSimplify(w*(u + sqrt(v)*FixSimplify(a + b + c + d)))
rule12 = ReplacementRule(pattern12, replacement12)
pattern13 = Pattern(UtilityOperator((sqrt(v_)*WC('b', S(1)) + sqrt(v_)*WC('c', S(1)) + sqrt(v_)*WC('a', S(1)) + WC('u', S(0)))*WC('w', S(1))))
def replacement13(u, w, v, c, a, b):
return FixSimplify(w*(u + sqrt(v)*FixSimplify(a + b + c)))
rule13 = ReplacementRule(pattern13, replacement13)
pattern14 = Pattern(UtilityOperator((sqrt(v_)*WC('b', S(1)) + sqrt(v_)*WC('a', S(1)) + WC('u', S(0)))*WC('w', S(1))))
def replacement14(u, w, v, a, b):
return FixSimplify(w*(u + sqrt(v)*FixSimplify(a + b)))
rule14 = ReplacementRule(pattern14, replacement14)
pattern15 = Pattern(UtilityOperator(v_**m_*w_**n_*WC('u', S(1))), cons2, cons27, cons3, cons28, cons29)
def replacement15(m, n, u, w, v):
return -FixSimplify(u*v**(m + S(-1)))
rule15 = ReplacementRule(pattern15, replacement15)
pattern16 = Pattern(UtilityOperator(v_**m_*w_**WC('n', S(1))*WC('u', S(1))), cons2, cons27, cons30, cons31)
def replacement16(m, n, u, w, v):
return (S(-1))**n*FixSimplify(u*v**(m + n))
rule16 = ReplacementRule(pattern16, replacement16)
pattern17 = Pattern(UtilityOperator(w_**WC('n', S(1))*(-v_**WC('p', S(1)))**m_*WC('u', S(1))), cons2, cons27, cons32, cons33)
def replacement17(p, m, n, u, w, v):
return (S(-1))**(n/p)*FixSimplify(u*(-v**p)**(m + n/p))
rule17 = ReplacementRule(pattern17, replacement17)
pattern18 = Pattern(UtilityOperator(w_**WC('n', S(1))*(-v_**WC('p', S(1)))**m_*WC('u', S(1))), cons2, cons27, cons34, cons31)
def replacement18(p, m, n, u, w, v):
return (S(-1))**(n + n/p)*FixSimplify(u*(-v**p)**(m + n/p))
rule18 = ReplacementRule(pattern18, replacement18)
pattern19 = Pattern(UtilityOperator((a_ - b_)**WC('m', S(1))*(a_ + b_)**WC('m', S(1))*WC('u', S(1))), cons9, cons35, cons36)
def replacement19(m, u, a, b):
return u*(a**S(2) - b**S(2))**m
rule19 = ReplacementRule(pattern19, replacement19)
pattern20 = Pattern(UtilityOperator((S(729)*c - e*(-S(20)*e + S(540)))**WC('m', S(1))*WC('u', S(1))), cons2)
def replacement20(m, u):
return u*(a*e**S(2) - b*d*e + c*d**S(2))**m
rule20 = ReplacementRule(pattern20, replacement20)
pattern21 = Pattern(UtilityOperator((S(729)*c + e*(S(20)*e + S(-540)))**WC('m', S(1))*WC('u', S(1))), cons2)
def replacement21(m, u):
return u*(a*e**S(2) - b*d*e + c*d**S(2))**m
rule21 = ReplacementRule(pattern21, replacement21)
pattern22 = Pattern(UtilityOperator(u_))
def replacement22(u):
return u
rule22 = ReplacementRule(pattern22, replacement22)
return [rule1, rule2, rule3, rule4, rule5, rule6, rule7, rule8, rule9, rule10, rule11, rule12, rule13, rule14, rule15, rule16, rule17, rule18, rule19, rule20, rule21, rule22, ]
@doctest_depends_on(modules=('matchpy',))
def FixSimplify(expr):
if isinstance(expr, (list, tuple, TupleArg)):
return [replace_all(UtilityOperator(i), FixSimplify_rules) for i in expr]
return replace_all(UtilityOperator(expr), FixSimplify_rules)
@doctest_depends_on(modules=('matchpy',))
def _SimplifyAntiderivativeSum():
replacer = ManyToOneReplacer()
pattern1 = Pattern(UtilityOperator(Add(Mul(Log(Add(a_, Mul(WC('b', S(1)), Pow(Tan(u_), WC('n', S(1)))))), WC('A', S(1))), Mul(Log(Cos(u_)), WC('B', S(1))), WC('v', S(0))), x_), CustomConstraint(lambda a, x: FreeQ(a, x)), CustomConstraint(lambda b, x: FreeQ(b, x)), CustomConstraint(lambda A, x: FreeQ(A, x)), CustomConstraint(lambda B, x: FreeQ(B, x)), CustomConstraint(lambda n: IntegerQ(n)), CustomConstraint(lambda B, A, n: ZeroQ(Add(Mul(n, A), Mul(S(1), B)))))
rule1 = ReplacementRule(pattern1, lambda n, x, v, b, B, A, u, a : Add(SimplifyAntiderivativeSum(v, x), Mul(A, Log(RemoveContent(Add(Mul(a, Pow(Cos(u), n)), Mul(b, Pow(Sin(u), n))), x)))))
replacer.add(rule1)
pattern2 = Pattern(UtilityOperator(Add(Mul(Log(Add(Mul(Pow(Cot(u_), WC('n', S(1))), WC('b', S(1))), a_)), WC('A', S(1))), Mul(Log(Sin(u_)), WC('B', S(1))), WC('v', S(0))), x_), CustomConstraint(lambda a, x: FreeQ(a, x)), CustomConstraint(lambda b, x: FreeQ(b, x)), CustomConstraint(lambda A, x: FreeQ(A, x)), CustomConstraint(lambda B, x: FreeQ(B, x)), CustomConstraint(lambda n: IntegerQ(n)), CustomConstraint(lambda B, A, n: ZeroQ(Add(Mul(n, A), Mul(S(1), B)))))
rule2 = ReplacementRule(pattern2, lambda n, x, v, b, B, A, a, u : Add(SimplifyAntiderivativeSum(v, x), Mul(A, Log(RemoveContent(Add(Mul(a, Pow(Sin(u), n)), Mul(b, Pow(Cos(u), n))), x)))))
replacer.add(rule2)
pattern3 = Pattern(UtilityOperator(Add(Mul(Log(Add(a_, Mul(WC('b', S(1)), Pow(Tan(u_), WC('n', S(1)))))), WC('A', S(1))), Mul(Log(Add(c_, Mul(WC('d', S(1)), Pow(Tan(u_), WC('n', S(1)))))), WC('B', S(1))), WC('v', S(0))), x_), CustomConstraint(lambda a, x: FreeQ(a, x)), CustomConstraint(lambda b, x: FreeQ(b, x)), CustomConstraint(lambda c, x: FreeQ(c, x)), CustomConstraint(lambda d, x: FreeQ(d, x)), CustomConstraint(lambda A, x: FreeQ(A, x)), CustomConstraint(lambda B, x: FreeQ(B, x)), CustomConstraint(lambda n: IntegerQ(n)), CustomConstraint(lambda B, A: ZeroQ(Add(A, B))))
rule3 = ReplacementRule(pattern3, lambda n, x, v, b, A, B, u, c, d, a : Add(SimplifyAntiderivativeSum(v, x), Mul(A, Log(RemoveContent(Add(Mul(a, Pow(Cos(u), n)), Mul(b, Pow(Sin(u), n))), x))), Mul(B, Log(RemoveContent(Add(Mul(c, Pow(Cos(u), n)), Mul(d, Pow(Sin(u), n))), x)))))
replacer.add(rule3)
pattern4 = Pattern(UtilityOperator(Add(Mul(Log(Add(Mul(Pow(Cot(u_), WC('n', S(1))), WC('b', S(1))), a_)), WC('A', S(1))), Mul(Log(Add(Mul(Pow(Cot(u_), WC('n', S(1))), WC('d', S(1))), c_)), WC('B', S(1))), WC('v', S(0))), x_), CustomConstraint(lambda a, x: FreeQ(a, x)), CustomConstraint(lambda b, x: FreeQ(b, x)), CustomConstraint(lambda c, x: FreeQ(c, x)), CustomConstraint(lambda d, x: FreeQ(d, x)), CustomConstraint(lambda A, x: FreeQ(A, x)), CustomConstraint(lambda B, x: FreeQ(B, x)), CustomConstraint(lambda n: IntegerQ(n)), CustomConstraint(lambda B, A: ZeroQ(Add(A, B))))
rule4 = ReplacementRule(pattern4, lambda n, x, v, b, A, B, c, a, d, u : Add(SimplifyAntiderivativeSum(v, x), Mul(A, Log(RemoveContent(Add(Mul(b, Pow(Cos(u), n)), Mul(a, Pow(Sin(u), n))), x))), Mul(B, Log(RemoveContent(Add(Mul(d, Pow(Cos(u), n)), Mul(c, Pow(Sin(u), n))), x)))))
replacer.add(rule4)
pattern5 = Pattern(UtilityOperator(Add(Mul(Log(Add(a_, Mul(WC('b', S(1)), Pow(Tan(u_), WC('n', S(1)))))), WC('A', S(1))), Mul(Log(Add(c_, Mul(WC('d', S(1)), Pow(Tan(u_), WC('n', S(1)))))), WC('B', S(1))), Mul(Log(Add(e_, Mul(WC('f', S(1)), Pow(Tan(u_), WC('n', S(1)))))), WC('C', S(1))), WC('v', S(0))), x_), CustomConstraint(lambda a, x: FreeQ(a, x)), CustomConstraint(lambda b, x: FreeQ(b, x)), CustomConstraint(lambda c, x: FreeQ(c, x)), CustomConstraint(lambda d, x: FreeQ(d, x)), CustomConstraint(lambda e, x: FreeQ(e, x)), CustomConstraint(lambda f, x: FreeQ(f, x)), CustomConstraint(lambda A, x: FreeQ(A, x)), CustomConstraint(lambda B, x: FreeQ(B, x)), CustomConstraint(lambda C, x: FreeQ(C, x)), CustomConstraint(lambda n: IntegerQ(n)), CustomConstraint(lambda B, A, C: ZeroQ(Add(A, B, C))))
rule5 = ReplacementRule(pattern5, lambda n, e, x, v, b, A, B, u, c, f, d, a, C : Add(SimplifyAntiderivativeSum(v, x), Mul(A, Log(RemoveContent(Add(Mul(a, Pow(Cos(u), n)), Mul(b, Pow(Sin(u), n))), x))), Mul(B, Log(RemoveContent(Add(Mul(c, Pow(Cos(u), n)), Mul(d, Pow(Sin(u), n))), x))), Mul(C, Log(RemoveContent(Add(Mul(e, Pow(Cos(u), n)), Mul(f, Pow(Sin(u), n))), x)))))
replacer.add(rule5)
pattern6 = Pattern(UtilityOperator(Add(Mul(Log(Add(Mul(Pow(Cot(u_), WC('n', S(1))), WC('b', S(1))), a_)), WC('A', S(1))), Mul(Log(Add(Mul(Pow(Cot(u_), WC('n', S(1))), WC('d', S(1))), c_)), WC('B', S(1))), Mul(Log(Add(Mul(Pow(Cot(u_), WC('n', S(1))), WC('f', S(1))), e_)), WC('C', S(1))), WC('v', S(0))), x_), CustomConstraint(lambda a, x: FreeQ(a, x)), CustomConstraint(lambda b, x: FreeQ(b, x)), CustomConstraint(lambda c, x: FreeQ(c, x)), CustomConstraint(lambda d, x: FreeQ(d, x)), CustomConstraint(lambda e, x: FreeQ(e, x)), CustomConstraint(lambda f, x: FreeQ(f, x)), CustomConstraint(lambda A, x: FreeQ(A, x)), CustomConstraint(lambda B, x: FreeQ(B, x)), CustomConstraint(lambda C, x: FreeQ(C, x)), CustomConstraint(lambda n: IntegerQ(n)), CustomConstraint(lambda B, A, C: ZeroQ(Add(A, B, C))))
rule6 = ReplacementRule(pattern6, lambda n, e, x, v, b, A, B, c, a, f, d, u, C : Add(SimplifyAntiderivativeSum(v, x), Mul(A, Log(RemoveContent(Add(Mul(b, Pow(Cos(u), n)), Mul(a, Pow(Sin(u), n))), x))), Mul(B, Log(RemoveContent(Add(Mul(d, Pow(Cos(u), n)), Mul(c, Pow(Sin(u), n))), x))), Mul(C, Log(RemoveContent(Add(Mul(f, Pow(Cos(u), n)), Mul(e, Pow(Sin(u), n))), x)))))
replacer.add(rule6)
return replacer
@doctest_depends_on(modules=('matchpy',))
def SimplifyAntiderivativeSum(expr, x):
r = SimplifyAntiderivativeSum_replacer.replace(UtilityOperator(expr, x))
if isinstance(r, UtilityOperator):
return expr
return r
@doctest_depends_on(modules=('matchpy',))
def _SimplifyAntiderivative():
replacer = ManyToOneReplacer()
pattern2 = Pattern(UtilityOperator(Log(Mul(c_, u_)), x_), CustomConstraint(lambda c, x: FreeQ(c, x)))
rule2 = ReplacementRule(pattern2, lambda x, c, u : SimplifyAntiderivative(Log(u), x))
replacer.add(rule2)
pattern3 = Pattern(UtilityOperator(Log(Pow(u_, n_)), x_), CustomConstraint(lambda n, x: FreeQ(n, x)))
rule3 = ReplacementRule(pattern3, lambda x, n, u : Mul(n, SimplifyAntiderivative(Log(u), x)))
replacer.add(rule3)
pattern7 = Pattern(UtilityOperator(Log(Pow(f_, u_)), x_), CustomConstraint(lambda f, x: FreeQ(f, x)))
rule7 = ReplacementRule(pattern7, lambda x, f, u : Mul(Log(f), SimplifyAntiderivative(u, x)))
replacer.add(rule7)
pattern8 = Pattern(UtilityOperator(Log(Add(a_, Mul(WC('b', S(1)), Tan(u_)))), x_), CustomConstraint(lambda a, x: FreeQ(a, x)), CustomConstraint(lambda b, x: FreeQ(b, x)), CustomConstraint(lambda b, a: ZeroQ(Add(Pow(a, S(2)), Pow(b, S(2))))))
rule8 = ReplacementRule(pattern8, lambda x, b, u, a : Add(Mul(Mul(b, Pow(a, S(1))), SimplifyAntiderivative(u, x)), Mul(S(1), SimplifyAntiderivative(Log(Cos(u)), x))))
replacer.add(rule8)
pattern9 = Pattern(UtilityOperator(Log(Add(Mul(Cot(u_), WC('b', S(1))), a_)), x_), CustomConstraint(lambda a, x: FreeQ(a, x)), CustomConstraint(lambda b, x: FreeQ(b, x)), CustomConstraint(lambda b, a: ZeroQ(Add(Pow(a, S(2)), Pow(b, S(2))))))
rule9 = ReplacementRule(pattern9, lambda x, b, u, a : Add(Mul(Mul(Mul(S(1), b), Pow(a, S(1))), SimplifyAntiderivative(u, x)), Mul(S(1), SimplifyAntiderivative(Log(Sin(u)), x))))
replacer.add(rule9)
pattern10 = Pattern(UtilityOperator(ArcTan(Mul(WC('a', S(1)), Tan(u_))), x_), CustomConstraint(lambda a, x: FreeQ(a, x)), CustomConstraint(lambda a: PositiveQ(Pow(a, S(2)))), CustomConstraint(lambda u: ComplexFreeQ(u)))
rule10 = ReplacementRule(pattern10, lambda x, u, a : RectifyTangent(u, a, S(1), x))
replacer.add(rule10)
pattern11 = Pattern(UtilityOperator(ArcCot(Mul(WC('a', S(1)), Tan(u_))), x_), CustomConstraint(lambda a, x: FreeQ(a, x)), CustomConstraint(lambda a: PositiveQ(Pow(a, S(2)))), CustomConstraint(lambda u: ComplexFreeQ(u)))
rule11 = ReplacementRule(pattern11, lambda x, u, a : RectifyTangent(u, a, S(1), x))
replacer.add(rule11)
pattern12 = Pattern(UtilityOperator(ArcCot(Mul(WC('a', S(1)), Tanh(u_))), x_), CustomConstraint(lambda a, x: FreeQ(a, x)), CustomConstraint(lambda u: ComplexFreeQ(u)))
rule12 = ReplacementRule(pattern12, lambda x, u, a : Mul(S(1), SimplifyAntiderivative(ArcTan(Mul(a, Tanh(u))), x)))
replacer.add(rule12)
pattern13 = Pattern(UtilityOperator(ArcTanh(Mul(WC('a', S(1)), Tan(u_))), x_), CustomConstraint(lambda a, x: FreeQ(a, x)), CustomConstraint(lambda a: PositiveQ(Pow(a, S(2)))), CustomConstraint(lambda u: ComplexFreeQ(u)))
rule13 = ReplacementRule(pattern13, lambda x, u, a : RectifyTangent(u, Mul(I, a), Mul(S(1), I), x))
replacer.add(rule13)
pattern14 = Pattern(UtilityOperator(ArcCoth(Mul(WC('a', S(1)), Tan(u_))), x_), CustomConstraint(lambda a, x: FreeQ(a, x)), CustomConstraint(lambda a: PositiveQ(Pow(a, S(2)))), CustomConstraint(lambda u: ComplexFreeQ(u)))
rule14 = ReplacementRule(pattern14, lambda x, u, a : RectifyTangent(u, Mul(I, a), Mul(S(1), I), x))
replacer.add(rule14)
pattern15 = Pattern(UtilityOperator(ArcTanh(Tanh(u_)), x_))
rule15 = ReplacementRule(pattern15, lambda x, u : SimplifyAntiderivative(u, x))
replacer.add(rule15)
pattern16 = Pattern(UtilityOperator(ArcCoth(Tanh(u_)), x_))
rule16 = ReplacementRule(pattern16, lambda x, u : SimplifyAntiderivative(u, x))
replacer.add(rule16)
pattern17 = Pattern(UtilityOperator(ArcCot(Mul(Cot(u_), WC('a', S(1)))), x_), CustomConstraint(lambda a, x: FreeQ(a, x)), CustomConstraint(lambda a: PositiveQ(Pow(a, S(2)))), CustomConstraint(lambda u: ComplexFreeQ(u)))
rule17 = ReplacementRule(pattern17, lambda x, u, a : RectifyCotangent(u, a, S(1), x))
replacer.add(rule17)
pattern18 = Pattern(UtilityOperator(ArcTan(Mul(Cot(u_), WC('a', S(1)))), x_), CustomConstraint(lambda a, x: FreeQ(a, x)), CustomConstraint(lambda a: PositiveQ(Pow(a, S(2)))), CustomConstraint(lambda u: ComplexFreeQ(u)))
rule18 = ReplacementRule(pattern18, lambda x, u, a : RectifyCotangent(u, a, S(1), x))
replacer.add(rule18)
pattern19 = Pattern(UtilityOperator(ArcTan(Mul(Coth(u_), WC('a', S(1)))), x_), CustomConstraint(lambda a, x: FreeQ(a, x)), CustomConstraint(lambda u: ComplexFreeQ(u)))
rule19 = ReplacementRule(pattern19, lambda x, u, a : Mul(S(1), SimplifyAntiderivative(ArcTan(Mul(Tanh(u), Pow(a, S(1)))), x)))
replacer.add(rule19)
pattern20 = Pattern(UtilityOperator(ArcCoth(Mul(Cot(u_), WC('a', S(1)))), x_), CustomConstraint(lambda a, x: FreeQ(a, x)), CustomConstraint(lambda a: PositiveQ(Pow(a, S(2)))), CustomConstraint(lambda u: ComplexFreeQ(u)))
rule20 = ReplacementRule(pattern20, lambda x, u, a : RectifyCotangent(u, Mul(I, a), I, x))
replacer.add(rule20)
pattern21 = Pattern(UtilityOperator(ArcTanh(Mul(Cot(u_), WC('a', S(1)))), x_), CustomConstraint(lambda a, x: FreeQ(a, x)), CustomConstraint(lambda a: PositiveQ(Pow(a, S(2)))), CustomConstraint(lambda u: ComplexFreeQ(u)))
rule21 = ReplacementRule(pattern21, lambda x, u, a : RectifyCotangent(u, Mul(I, a), I, x))
replacer.add(rule21)
pattern22 = Pattern(UtilityOperator(ArcCoth(Coth(u_)), x_))
rule22 = ReplacementRule(pattern22, lambda x, u : SimplifyAntiderivative(u, x))
replacer.add(rule22)
pattern23 = Pattern(UtilityOperator(ArcTanh(Mul(Coth(u_), WC('a', S(1)))), x_), CustomConstraint(lambda a, x: FreeQ(a, x)), CustomConstraint(lambda u: ComplexFreeQ(u)))
rule23 = ReplacementRule(pattern23, lambda x, u, a : SimplifyAntiderivative(ArcTanh(Mul(Tanh(u), Pow(a, S(1)))), x))
replacer.add(rule23)
pattern24 = Pattern(UtilityOperator(ArcTanh(Coth(u_)), x_))
rule24 = ReplacementRule(pattern24, lambda x, u : SimplifyAntiderivative(u, x))
replacer.add(rule24)
pattern25 = Pattern(UtilityOperator(ArcTan(Mul(WC('c', S(1)), Add(a_, Mul(WC('b', S(1)), Tan(u_))))), x_), CustomConstraint(lambda a, x: FreeQ(a, x)), CustomConstraint(lambda b, x: FreeQ(b, x)), CustomConstraint(lambda c, x: FreeQ(c, x)), CustomConstraint(lambda c, a: PositiveQ(Mul(Pow(a, S(2)), Pow(c, S(2))))), CustomConstraint(lambda c, b: PositiveQ(Mul(Pow(b, S(2)), Pow(c, S(2))))), CustomConstraint(lambda u: ComplexFreeQ(u)))
rule25 = ReplacementRule(pattern25, lambda x, a, b, u, c : RectifyTangent(u, Mul(a, c), Mul(b, c), S(1), x))
replacer.add(rule25)
pattern26 = Pattern(UtilityOperator(ArcTanh(Mul(WC('c', S(1)), Add(a_, Mul(WC('b', S(1)), Tan(u_))))), x_), CustomConstraint(lambda a, x: FreeQ(a, x)), CustomConstraint(lambda b, x: FreeQ(b, x)), CustomConstraint(lambda c, x: FreeQ(c, x)), CustomConstraint(lambda c, a: PositiveQ(Mul(Pow(a, S(2)), Pow(c, S(2))))), CustomConstraint(lambda c, b: PositiveQ(Mul(Pow(b, S(2)), Pow(c, S(2))))), CustomConstraint(lambda u: ComplexFreeQ(u)))
rule26 = ReplacementRule(pattern26, lambda x, a, b, u, c : RectifyTangent(u, Mul(I, a, c), Mul(I, b, c), Mul(S(1), I), x))
replacer.add(rule26)
pattern27 = Pattern(UtilityOperator(ArcTan(Mul(WC('c', S(1)), Add(Mul(Cot(u_), WC('b', S(1))), a_))), x_), CustomConstraint(lambda a, x: FreeQ(a, x)), CustomConstraint(lambda b, x: FreeQ(b, x)), CustomConstraint(lambda c, x: FreeQ(c, x)), CustomConstraint(lambda c, a: PositiveQ(Mul(Pow(a, S(2)), Pow(c, S(2))))), CustomConstraint(lambda c, b: PositiveQ(Mul(Pow(b, S(2)), Pow(c, S(2))))), CustomConstraint(lambda u: ComplexFreeQ(u)))
rule27 = ReplacementRule(pattern27, lambda x, a, b, u, c : RectifyCotangent(u, Mul(a, c), Mul(b, c), S(1), x))
replacer.add(rule27)
pattern28 = Pattern(UtilityOperator(ArcTanh(Mul(WC('c', S(1)), Add(Mul(Cot(u_), WC('b', S(1))), a_))), x_), CustomConstraint(lambda a, x: FreeQ(a, x)), CustomConstraint(lambda b, x: FreeQ(b, x)), CustomConstraint(lambda c, x: FreeQ(c, x)), CustomConstraint(lambda c, a: PositiveQ(Mul(Pow(a, S(2)), Pow(c, S(2))))), CustomConstraint(lambda c, b: PositiveQ(Mul(Pow(b, S(2)), Pow(c, S(2))))), CustomConstraint(lambda u: ComplexFreeQ(u)))
rule28 = ReplacementRule(pattern28, lambda x, a, b, u, c : RectifyCotangent(u, Mul(I, a, c), Mul(I, b, c), Mul(S(1), I), x))
replacer.add(rule28)
pattern29 = Pattern(UtilityOperator(ArcTan(Add(WC('a', S(0)), Mul(WC('b', S(1)), Tan(u_)), Mul(WC('c', S(1)), Pow(Tan(u_), S(2))))), x_), CustomConstraint(lambda a, x: FreeQ(a, x)), CustomConstraint(lambda b, x: FreeQ(b, x)), CustomConstraint(lambda c, x: FreeQ(c, x)), CustomConstraint(lambda u: ComplexFreeQ(u)))
rule29 = ReplacementRule(pattern29, lambda x, a, b, u, c : If(EvenQ(Denominator(NumericFactor(Together(u)))), ArcTan(NormalizeTogether(Mul(Add(a, c, S(1), Mul(Add(a, Mul(S(1), c), S(1)), Cos(Mul(S(2), u))), Mul(b, Sin(Mul(S(2), u)))), Pow(Add(a, c, S(1), Mul(Add(a, Mul(S(1), c), S(1)), Cos(Mul(S(2), u))), Mul(b, Sin(Mul(S(2), u)))), S(1))))), ArcTan(NormalizeTogether(Mul(Add(c, Mul(Add(a, Mul(S(1), c), S(1)), Pow(Cos(u), S(2))), Mul(b, Cos(u), Sin(u))), Pow(Add(c, Mul(Add(a, Mul(S(1), c), S(1)), Pow(Cos(u), S(2))), Mul(b, Cos(u), Sin(u))), S(1)))))))
replacer.add(rule29)
pattern30 = Pattern(UtilityOperator(ArcTan(Add(WC('a', S(0)), Mul(WC('b', S(1)), Add(WC('d', S(0)), Mul(WC('e', S(1)), Tan(u_)))), Mul(WC('c', S(1)), Pow(Add(WC('f', S(0)), Mul(WC('g', S(1)), Tan(u_))), S(2))))), x_), CustomConstraint(lambda a, x: FreeQ(a, x)), CustomConstraint(lambda b, x: FreeQ(b, x)), CustomConstraint(lambda c, x: FreeQ(c, x)), CustomConstraint(lambda u: ComplexFreeQ(u)))
rule30 = ReplacementRule(pattern30, lambda x, d, a, e, f, b, u, c, g : SimplifyAntiderivative(ArcTan(Add(a, Mul(b, d), Mul(c, Pow(f, S(2))), Mul(Add(Mul(b, e), Mul(S(2), c, f, g)), Tan(u)), Mul(c, Pow(g, S(2)), Pow(Tan(u), S(2))))), x))
replacer.add(rule30)
pattern31 = Pattern(UtilityOperator(ArcTan(Add(WC('a', S(0)), Mul(WC('c', S(1)), Pow(Tan(u_), S(2))))), x_), CustomConstraint(lambda a, x: FreeQ(a, x)), CustomConstraint(lambda c, x: FreeQ(c, x)), CustomConstraint(lambda u: ComplexFreeQ(u)))
rule31 = ReplacementRule(pattern31, lambda x, c, u, a : If(EvenQ(Denominator(NumericFactor(Together(u)))), ArcTan(NormalizeTogether(Mul(Add(a, c, S(1), Mul(Add(a, Mul(S(1), c), S(1)), Cos(Mul(S(2), u)))), Pow(Add(a, c, S(1), Mul(Add(a, Mul(S(1), c), S(1)), Cos(Mul(S(2), u)))), S(1))))), ArcTan(NormalizeTogether(Mul(Add(c, Mul(Add(a, Mul(S(1), c), S(1)), Pow(Cos(u), S(2)))), Pow(Add(c, Mul(Add(a, Mul(S(1), c), S(1)), Pow(Cos(u), S(2)))), S(1)))))))
replacer.add(rule31)
pattern32 = Pattern(UtilityOperator(ArcTan(Add(WC('a', S(0)), Mul(WC('c', S(1)), Pow(Add(WC('f', S(0)), Mul(WC('g', S(1)), Tan(u_))), S(2))))), x_), CustomConstraint(lambda a, x: FreeQ(a, x)), CustomConstraint(lambda c, x: FreeQ(c, x)), CustomConstraint(lambda u: ComplexFreeQ(u)))
rule32 = ReplacementRule(pattern32, lambda x, a, f, u, c, g : SimplifyAntiderivative(ArcTan(Add(a, Mul(c, Pow(f, S(2))), Mul(Mul(S(2), c, f, g), Tan(u)), Mul(c, Pow(g, S(2)), Pow(Tan(u), S(2))))), x))
replacer.add(rule32)
return replacer
@doctest_depends_on(modules=('matchpy',))
def SimplifyAntiderivative(expr, x):
r = SimplifyAntiderivative_replacer.replace(UtilityOperator(expr, x))
if isinstance(r, UtilityOperator):
if ProductQ(expr):
u, c = S(1), S(1)
for i in expr.args:
if FreeQ(i, x):
c *= i
else:
u *= i
if FreeQ(c, x) and c != S(1):
v = SimplifyAntiderivative(u, x)
if SumQ(v) and NonsumQ(u):
return Add(*[c*i for i in v.args])
return c*v
elif LogQ(expr):
F = expr.args[0]
if MemberQ([cot, sec, csc, coth, sech, csch], Head(F)):
return -SimplifyAntiderivative(Log(1/F), x)
if MemberQ([Log, atan, acot], Head(expr)):
F = Head(expr)
G = expr.args[0]
if MemberQ([cot, sec, csc, coth, sech, csch], Head(G)):
return -SimplifyAntiderivative(F(1/G), x)
if MemberQ([atanh, acoth], Head(expr)):
F = Head(expr)
G = expr.args[0]
if MemberQ([cot, sec, csc, coth, sech, csch], Head(G)):
return SimplifyAntiderivative(F(1/G), x)
u = expr
if FreeQ(u, x):
return S(0)
elif LogQ(u):
return Log(RemoveContent(u.args[0], x))
elif SumQ(u):
return SimplifyAntiderivativeSum(Add(*[SimplifyAntiderivative(i, x) for i in u.args]), x)
return u
else:
return r
@doctest_depends_on(modules=('matchpy',))
def _TrigSimplifyAux():
replacer = ManyToOneReplacer()
pattern1 = Pattern(UtilityOperator(Mul(WC('u', S(1)), Pow(Add(Mul(WC('a', S(1)), Pow(v_, WC('m', S(1)))), Mul(WC('b', S(1)), Pow(v_, WC('n', S(1))))), p_))), CustomConstraint(lambda v: InertTrigQ(v)), CustomConstraint(lambda p: IntegerQ(p)), CustomConstraint(lambda n, m: RationalQ(m, n)), CustomConstraint(lambda n, m: Less(m, n)))
rule1 = ReplacementRule(pattern1, lambda n, a, p, m, u, v, b : Mul(u, Pow(v, Mul(m, p)), Pow(TrigSimplifyAux(Add(a, Mul(b, Pow(v, Add(n, Mul(S(-1), m)))))), p)))
replacer.add(rule1)
pattern2 = Pattern(UtilityOperator(Add(Mul(Pow(cos(u_), S('2')), WC('a', S(1))), WC('v', S(0)), Mul(WC('b', S(1)), Pow(sin(u_), S('2'))))), CustomConstraint(lambda b, a: SameQ(a, b)))
rule2 = ReplacementRule(pattern2, lambda u, v, b, a : Add(a, v))
replacer.add(rule2)
pattern3 = Pattern(UtilityOperator(Add(WC('v', S(0)), Mul(WC('a', S(1)), Pow(sec(u_), S('2'))), Mul(WC('b', S(1)), Pow(tan(u_), S('2'))))), CustomConstraint(lambda b, a: SameQ(a, Mul(S(-1), b))))
rule3 = ReplacementRule(pattern3, lambda u, v, b, a : Add(a, v))
replacer.add(rule3)
pattern4 = Pattern(UtilityOperator(Add(Mul(Pow(csc(u_), S('2')), WC('a', S(1))), Mul(Pow(cot(u_), S('2')), WC('b', S(1))), WC('v', S(0)))), CustomConstraint(lambda b, a: SameQ(a, Mul(S(-1), b))))
rule4 = ReplacementRule(pattern4, lambda u, v, b, a : Add(a, v))
replacer.add(rule4)
pattern5 = Pattern(UtilityOperator(Pow(Add(Mul(Pow(cos(u_), S('2')), WC('a', S(1))), WC('v', S(0)), Mul(WC('b', S(1)), Pow(sin(u_), S('2')))), n_)))
rule5 = ReplacementRule(pattern5, lambda n, a, u, v, b : Pow(Add(Mul(Add(b, Mul(S(-1), a)), Pow(Sin(u), S('2'))), a, v), n))
replacer.add(rule5)
pattern6 = Pattern(UtilityOperator(Add(WC('w', S(0)), u_, Mul(WC('v', S(1)), Pow(sin(z_), S('2'))))), CustomConstraint(lambda u, v: SameQ(u, Mul(S(-1), v))))
rule6 = ReplacementRule(pattern6, lambda u, w, z, v : Add(Mul(u, Pow(Cos(z), S('2'))), w))
replacer.add(rule6)
pattern7 = Pattern(UtilityOperator(Add(Mul(Pow(cos(z_), S('2')), WC('v', S(1))), WC('w', S(0)), u_)), CustomConstraint(lambda u, v: SameQ(u, Mul(S(-1), v))))
rule7 = ReplacementRule(pattern7, lambda z, w, v, u : Add(Mul(u, Pow(Sin(z), S('2'))), w))
replacer.add(rule7)
pattern8 = Pattern(UtilityOperator(Add(WC('w', S(0)), u_, Mul(WC('v', S(1)), Pow(tan(z_), S('2'))))), CustomConstraint(lambda u, v: SameQ(u, v)))
rule8 = ReplacementRule(pattern8, lambda u, w, z, v : Add(Mul(u, Pow(Sec(z), S('2'))), w))
replacer.add(rule8)
pattern9 = Pattern(UtilityOperator(Add(Mul(Pow(cot(z_), S('2')), WC('v', S(1))), WC('w', S(0)), u_)), CustomConstraint(lambda u, v: SameQ(u, v)))
rule9 = ReplacementRule(pattern9, lambda z, w, v, u : Add(Mul(u, Pow(Csc(z), S('2'))), w))
replacer.add(rule9)
pattern10 = Pattern(UtilityOperator(Add(WC('w', S(0)), u_, Mul(WC('v', S(1)), Pow(sec(z_), S('2'))))), CustomConstraint(lambda u, v: SameQ(u, Mul(S(-1), v))))
rule10 = ReplacementRule(pattern10, lambda u, w, z, v : Add(Mul(v, Pow(Tan(z), S('2'))), w))
replacer.add(rule10)
pattern11 = Pattern(UtilityOperator(Add(Mul(Pow(csc(z_), S('2')), WC('v', S(1))), WC('w', S(0)), u_)), CustomConstraint(lambda u, v: SameQ(u, Mul(S(-1), v))))
rule11 = ReplacementRule(pattern11, lambda z, w, v, u : Add(Mul(v, Pow(Cot(z), S('2'))), w))
replacer.add(rule11)
pattern12 = Pattern(UtilityOperator(Mul(WC('u', S(1)), Pow(Add(Mul(cos(v_), WC('b', S(1))), a_), S(-1)), Pow(sin(v_), S('2')))), CustomConstraint(lambda b, a: ZeroQ(Add(Pow(a, S('2')), Mul(S(-1), Pow(b, S('2')))))))
rule12 = ReplacementRule(pattern12, lambda u, v, b, a : Mul(u, Add(Mul(S(1), Pow(a, S(-1))), Mul(S(-1), Mul(Cos(v), Pow(b, S(-1)))))))
replacer.add(rule12)
pattern13 = Pattern(UtilityOperator(Mul(Pow(cos(v_), S('2')), WC('u', S(1)), Pow(Add(a_, Mul(WC('b', S(1)), sin(v_))), S(-1)))), CustomConstraint(lambda b, a: ZeroQ(Add(Pow(a, S('2')), Mul(S(-1), Pow(b, S('2')))))))
rule13 = ReplacementRule(pattern13, lambda u, v, b, a : Mul(u, Add(Mul(S(1), Pow(a, S(-1))), Mul(S(-1), Mul(Sin(v), Pow(b, S(-1)))))))
replacer.add(rule13)
pattern14 = Pattern(UtilityOperator(Mul(WC('u', S(1)), Pow(tan(v_), WC('n', S(1))), Pow(Add(a_, Mul(WC('b', S(1)), Pow(tan(v_), WC('n', S(1))))), S(-1)))), CustomConstraint(lambda n: PositiveIntegerQ(n)), CustomConstraint(lambda a: NonsumQ(a)))
rule14 = ReplacementRule(pattern14, lambda n, a, u, v, b : Mul(u, Pow(Add(b, Mul(a, Pow(Cot(v), n))), S(-1))))
replacer.add(rule14)
pattern15 = Pattern(UtilityOperator(Mul(Pow(cot(v_), WC('n', S(1))), WC('u', S(1)), Pow(Add(Mul(Pow(cot(v_), WC('n', S(1))), WC('b', S(1))), a_), S(-1)))), CustomConstraint(lambda n: PositiveIntegerQ(n)), CustomConstraint(lambda a: NonsumQ(a)))
rule15 = ReplacementRule(pattern15, lambda n, a, u, v, b : Mul(u, Pow(Add(b, Mul(a, Pow(Tan(v), n))), S(-1))))
replacer.add(rule15)
pattern16 = Pattern(UtilityOperator(Mul(WC('u', S(1)), Pow(sec(v_), WC('n', S(1))), Pow(Add(a_, Mul(WC('b', S(1)), Pow(sec(v_), WC('n', S(1))))), S(-1)))), CustomConstraint(lambda n: PositiveIntegerQ(n)), CustomConstraint(lambda a: NonsumQ(a)))
rule16 = ReplacementRule(pattern16, lambda n, a, u, v, b : Mul(u, Pow(Add(b, Mul(a, Pow(Cos(v), n))), S(-1))))
replacer.add(rule16)
pattern17 = Pattern(UtilityOperator(Mul(Pow(csc(v_), WC('n', S(1))), WC('u', S(1)), Pow(Add(Mul(Pow(csc(v_), WC('n', S(1))), WC('b', S(1))), a_), S(-1)))), CustomConstraint(lambda n: PositiveIntegerQ(n)), CustomConstraint(lambda a: NonsumQ(a)))
rule17 = ReplacementRule(pattern17, lambda n, a, u, v, b : Mul(u, Pow(Add(b, Mul(a, Pow(Sin(v), n))), S(-1))))
replacer.add(rule17)
pattern18 = Pattern(UtilityOperator(Mul(WC('u', S(1)), Pow(Add(a_, Mul(WC('b', S(1)), Pow(sec(v_), WC('n', S(1))))), S(-1)), Pow(tan(v_), WC('n', S(1))))), CustomConstraint(lambda n: PositiveIntegerQ(n)), CustomConstraint(lambda a: NonsumQ(a)))
rule18 = ReplacementRule(pattern18, lambda n, a, u, v, b : Mul(u, Mul(Pow(Sin(v), n), Pow(Add(b, Mul(a, Pow(Cos(v), n))), S(-1)))))
replacer.add(rule18)
pattern19 = Pattern(UtilityOperator(Mul(Pow(cot(v_), WC('n', S(1))), WC('u', S(1)), Pow(Add(Mul(Pow(csc(v_), WC('n', S(1))), WC('b', S(1))), a_), S(-1)))), CustomConstraint(lambda n: PositiveIntegerQ(n)), CustomConstraint(lambda a: NonsumQ(a)))
rule19 = ReplacementRule(pattern19, lambda n, a, u, v, b : Mul(u, Mul(Pow(Cos(v), n), Pow(Add(b, Mul(a, Pow(Sin(v), n))), S(-1)))))
replacer.add(rule19)
pattern20 = Pattern(UtilityOperator(Mul(WC('u', S(1)), Pow(Add(Mul(WC('a', S(1)), Pow(sec(v_), WC('n', S(1)))), Mul(WC('b', S(1)), Pow(tan(v_), WC('n', S(1))))), WC('p', S(1))))), CustomConstraint(lambda n, p: IntegersQ(n, p)))
rule20 = ReplacementRule(pattern20, lambda n, a, p, u, v, b : Mul(u, Pow(Sec(v), Mul(n, p)), Pow(Add(a, Mul(b, Pow(Sin(v), n))), p)))
replacer.add(rule20)
pattern21 = Pattern(UtilityOperator(Mul(Pow(Add(Mul(Pow(csc(v_), WC('n', S(1))), WC('a', S(1))), Mul(Pow(cot(v_), WC('n', S(1))), WC('b', S(1)))), WC('p', S(1))), WC('u', S(1)))), CustomConstraint(lambda n, p: IntegersQ(n, p)))
rule21 = ReplacementRule(pattern21, lambda n, a, p, u, v, b : Mul(u, Pow(Csc(v), Mul(n, p)), Pow(Add(a, Mul(b, Pow(Cos(v), n))), p)))
replacer.add(rule21)
pattern22 = Pattern(UtilityOperator(Mul(WC('u', S(1)), Pow(Add(Mul(WC('b', S(1)), Pow(sin(v_), WC('n', S(1)))), Mul(WC('a', S(1)), Pow(tan(v_), WC('n', S(1))))), WC('p', S(1))))), CustomConstraint(lambda n, p: IntegersQ(n, p)))
rule22 = ReplacementRule(pattern22, lambda n, a, p, u, v, b : Mul(u, Pow(Tan(v), Mul(n, p)), Pow(Add(a, Mul(b, Pow(Cos(v), n))), p)))
replacer.add(rule22)
pattern23 = Pattern(UtilityOperator(Mul(Pow(Add(Mul(Pow(cot(v_), WC('n', S(1))), WC('a', S(1))), Mul(Pow(cos(v_), WC('n', S(1))), WC('b', S(1)))), WC('p', S(1))), WC('u', S(1)))), CustomConstraint(lambda n, p: IntegersQ(n, p)))
rule23 = ReplacementRule(pattern23, lambda n, a, p, u, v, b : Mul(u, Pow(Cot(v), Mul(n, p)), Pow(Add(a, Mul(b, Pow(Sin(v), n))), p)))
replacer.add(rule23)
pattern24 = Pattern(UtilityOperator(Mul(Pow(cos(v_), WC('m', S(1))), WC('u', S(1)), Pow(Add(WC('a', S(0)), Mul(WC('c', S(1)), Pow(sec(v_), WC('n', S(1)))), Mul(WC('b', S(1)), Pow(tan(v_), WC('n', S(1))))), WC('p', S(1))))), CustomConstraint(lambda n, p, m: IntegersQ(m, n, p)))
rule24 = ReplacementRule(pattern24, lambda n, a, c, p, m, u, v, b : Mul(u, Pow(Cos(v), Add(m, Mul(S(-1), Mul(n, p)))), Pow(Add(c, Mul(b, Pow(Sin(v), n)), Mul(a, Pow(Cos(v), n))), p)))
replacer.add(rule24)
pattern25 = Pattern(UtilityOperator(Mul(WC('u', S(1)), Pow(sec(v_), WC('m', S(1))), Pow(Add(WC('a', S(0)), Mul(WC('c', S(1)), Pow(sec(v_), WC('n', S(1)))), Mul(WC('b', S(1)), Pow(tan(v_), WC('n', S(1))))), WC('p', S(1))))), CustomConstraint(lambda n, p, m: IntegersQ(m, n, p)))
rule25 = ReplacementRule(pattern25, lambda n, a, c, p, m, u, v, b : Mul(u, Pow(Sec(v), Add(m, Mul(n, p))), Pow(Add(c, Mul(b, Pow(Sin(v), n)), Mul(a, Pow(Cos(v), n))), p)))
replacer.add(rule25)
pattern26 = Pattern(UtilityOperator(Mul(Pow(Add(WC('a', S(0)), Mul(Pow(cot(v_), WC('n', S(1))), WC('b', S(1))), Mul(Pow(csc(v_), WC('n', S(1))), WC('c', S(1)))), WC('p', S(1))), WC('u', S(1)), Pow(sin(v_), WC('m', S(1))))), CustomConstraint(lambda n, p, m: IntegersQ(m, n, p)))
rule26 = ReplacementRule(pattern26, lambda n, a, c, p, m, u, v, b : Mul(u, Pow(Sin(v), Add(m, Mul(S(-1), Mul(n, p)))), Pow(Add(c, Mul(b, Pow(Cos(v), n)), Mul(a, Pow(Sin(v), n))), p)))
replacer.add(rule26)
pattern27 = Pattern(UtilityOperator(Mul(Pow(csc(v_), WC('m', S(1))), Pow(Add(WC('a', S(0)), Mul(Pow(cot(v_), WC('n', S(1))), WC('b', S(1))), Mul(Pow(csc(v_), WC('n', S(1))), WC('c', S(1)))), WC('p', S(1))), WC('u', S(1)))), CustomConstraint(lambda n, p, m: IntegersQ(m, n, p)))
rule27 = ReplacementRule(pattern27, lambda n, a, c, p, m, u, v, b : Mul(u, Pow(Csc(v), Add(m, Mul(n, p))), Pow(Add(c, Mul(b, Pow(Cos(v), n)), Mul(a, Pow(Sin(v), n))), p)))
replacer.add(rule27)
pattern28 = Pattern(UtilityOperator(Mul(WC('u', S(1)), Pow(Add(Mul(Pow(csc(v_), WC('m', S(1))), WC('a', S(1))), Mul(WC('b', S(1)), Pow(sin(v_), WC('n', S(1))))), WC('p', S(1))))), CustomConstraint(lambda n, m: IntegersQ(m, n)))
rule28 = ReplacementRule(pattern28, lambda n, a, p, m, u, v, b : If(And(ZeroQ(Add(m, n, S(-2))), ZeroQ(Add(a, b))), Mul(u, Pow(Mul(a, Mul(Pow(Cos(v), S('2')), Pow(Pow(Sin(v), m), S(-1)))), p)), Mul(u, Pow(Mul(Add(a, Mul(b, Pow(Sin(v), Add(m, n)))), Pow(Pow(Sin(v), m), S(-1))), p))))
replacer.add(rule28)
pattern29 = Pattern(UtilityOperator(Mul(WC('u', S(1)), Pow(Add(Mul(Pow(cos(v_), WC('n', S(1))), WC('b', S(1))), Mul(WC('a', S(1)), Pow(sec(v_), WC('m', S(1))))), WC('p', S(1))))), CustomConstraint(lambda n, m: IntegersQ(m, n)))
rule29 = ReplacementRule(pattern29, lambda n, a, p, m, u, v, b : If(And(ZeroQ(Add(m, n, S(-2))), ZeroQ(Add(a, b))), Mul(u, Pow(Mul(a, Mul(Pow(Sin(v), S('2')), Pow(Pow(Cos(v), m), S(-1)))), p)), Mul(u, Pow(Mul(Add(a, Mul(b, Pow(Cos(v), Add(m, n)))), Pow(Pow(Cos(v), m), S(-1))), p))))
replacer.add(rule29)
pattern30 = Pattern(UtilityOperator(u_))
rule30 = ReplacementRule(pattern30, lambda u : u)
replacer.add(rule30)
return replacer
@doctest_depends_on(modules=('matchpy',))
def TrigSimplifyAux(expr):
return TrigSimplifyAux_replacer.replace(UtilityOperator(expr))
def Cancel(expr):
return cancel(expr)
class Util_Part(Function):
def doit(self):
i = Simplify(self.args[0])
if len(self.args) > 2 :
lst = list(self.args[1:])
else:
lst = self.args[1]
if isinstance(i, (int, Integer)):
if isinstance(lst, list):
return lst[i - 1]
elif AtomQ(lst):
return lst
return lst.args[i - 1]
else:
return self
def Part(lst, i): #see i = -1
if isinstance(lst, list):
return Util_Part(i, *lst).doit()
return Util_Part(i, lst).doit()
def PolyLog(n, p, z=None):
return polylog(n, p)
def D(f, x):
try:
return f.diff(x)
except ValueError:
return Function('D')(f, x)
def IntegralFreeQ(u):
return FreeQ(u, Integral)
def Dist(u, v, x):
#Dist(u,v) returns the sum of u times each term of v, provided v is free of Int
u = replace_pow_exp(u) # to replace back to SymPy's exp
v = replace_pow_exp(v)
w = Simp(u*x**2, x)/x**2
if u == 1:
return v
elif u == 0:
return 0
elif NumericFactor(u) < 0 and NumericFactor(-u) > 0:
return -Dist(-u, v, x)
elif SumQ(v):
return Add(*[Dist(u, i, x) for i in v.args])
elif IntegralFreeQ(v):
return Simp(u*v, x)
elif w != u and FreeQ(w, x) and w == Simp(w, x) and w == Simp(w*x**2, x)/x**2:
return Dist(w, v, x)
else:
return Simp(u*v, x)
def PureFunctionOfCothQ(u, v, x):
# If u is a pure function of Coth[v], PureFunctionOfCothQ[u,v,x] returns True;
if AtomQ(u):
return u != x
elif CalculusQ(u):
return False
elif HyperbolicQ(u) and ZeroQ(u.args[0] - v):
return CothQ(u)
return all(PureFunctionOfCothQ(i, v, x) for i in u.args)
def LogIntegral(z):
return li(z)
def ExpIntegralEi(z):
return Ei(z)
def ExpIntegralE(a, b):
return expint(a, b).evalf()
def SinIntegral(z):
return Si(z)
def CosIntegral(z):
return Ci(z)
def SinhIntegral(z):
return Shi(z)
def CoshIntegral(z):
return Chi(z)
class PolyGamma(Function):
@classmethod
def eval(cls, *args):
if len(args) == 2:
return polygamma(args[0], args[1])
return digamma(args[0])
def LogGamma(z):
return loggamma(z)
class ProductLog(Function):
@classmethod
def eval(cls, *args):
if len(args) == 2:
return LambertW(args[1], args[0]).evalf()
return LambertW(args[0]).evalf()
def Factorial(a):
return factorial(a)
def Zeta(*args):
return zeta(*args)
def HypergeometricPFQ(a, b, c):
return hyper(a, b, c)
def Sum_doit(exp, args):
"""
This function perform summation using SymPy's `Sum`.
Examples
========
>>> from sympy.integrals.rubi.utility_function import Sum_doit
>>> from sympy.abc import x
>>> Sum_doit(2*x + 2, [x, 0, 1.7])
6
"""
exp = replace_pow_exp(exp)
if not isinstance(args[2], (int, Integer)):
new_args = [args[0], args[1], Floor(args[2])]
return Sum(exp, new_args).doit()
return Sum(exp, args).doit()
def PolynomialQuotient(p, q, x):
try:
p = poly(p, x)
q = poly(q, x)
except:
p = poly(p)
q = poly(q)
try:
return quo(p, q).as_expr()
except (PolynomialDivisionFailed, UnificationFailed):
return p/q
def PolynomialRemainder(p, q, x):
try:
p = poly(p, x)
q = poly(q, x)
except:
p = poly(p)
q = poly(q)
try:
return rem(p, q).as_expr()
except (PolynomialDivisionFailed, UnificationFailed):
return S(0)
def Floor(x, a = None):
if a is None:
return floor(x)
return a*floor(x/a)
def Factor(var):
return factor(var)
def Rule(a, b):
return {a: b}
def Distribute(expr, *args):
if len(args) == 1:
if isinstance(expr, args[0]):
return expr
else:
return expr.expand()
if len(args) == 2:
if isinstance(expr, args[1]):
return expr.expand()
else:
return expr
return expr.expand()
def CoprimeQ(*args):
args = S(args)
g = gcd(*args)
if g == 1:
return True
return False
def Discriminant(a, b):
try:
return discriminant(a, b)
except PolynomialError:
return Function('Discriminant')(a, b)
def Negative(x):
return x < S(0)
def Quotient(m, n):
return Floor(m/n)
def process_trig(expr):
"""
This function processes trigonometric expressions such that all `cot` is
rewritten in terms of `tan`, `sec` in terms of `cos`, `csc` in terms of `sin` and
similarly for `coth`, `sech` and `csch`.
Examples
========
>>> from sympy.integrals.rubi.utility_function import process_trig
>>> from sympy.abc import x
>>> from sympy import coth, cot, csc
>>> process_trig(x*cot(x))
x/tan(x)
>>> process_trig(coth(x)*csc(x))
1/(sin(x)*tanh(x))
"""
expr = expr.replace(lambda x: isinstance(x, cot), lambda x: 1/tan(x.args[0]))
expr = expr.replace(lambda x: isinstance(x, sec), lambda x: 1/cos(x.args[0]))
expr = expr.replace(lambda x: isinstance(x, csc), lambda x: 1/sin(x.args[0]))
expr = expr.replace(lambda x: isinstance(x, coth), lambda x: 1/tanh(x.args[0]))
expr = expr.replace(lambda x: isinstance(x, sech), lambda x: 1/cosh(x.args[0]))
expr = expr.replace(lambda x: isinstance(x, csch), lambda x: 1/sinh(x.args[0]))
return expr
def _ExpandIntegrand():
Plus = Add
Times = Mul
def cons_f1(m):
return PositiveIntegerQ(m)
cons1 = CustomConstraint(cons_f1)
def cons_f2(d, c, b, a):
return ZeroQ(-a*d + b*c)
cons2 = CustomConstraint(cons_f2)
def cons_f3(a, x):
return FreeQ(a, x)
cons3 = CustomConstraint(cons_f3)
def cons_f4(b, x):
return FreeQ(b, x)
cons4 = CustomConstraint(cons_f4)
def cons_f5(c, x):
return FreeQ(c, x)
cons5 = CustomConstraint(cons_f5)
def cons_f6(d, x):
return FreeQ(d, x)
cons6 = CustomConstraint(cons_f6)
def cons_f7(e, x):
return FreeQ(e, x)
cons7 = CustomConstraint(cons_f7)
def cons_f8(f, x):
return FreeQ(f, x)
cons8 = CustomConstraint(cons_f8)
def cons_f9(g, x):
return FreeQ(g, x)
cons9 = CustomConstraint(cons_f9)
def cons_f10(h, x):
return FreeQ(h, x)
cons10 = CustomConstraint(cons_f10)
def cons_f11(e, b, c, f, n, p, F, x, d, m):
if not isinstance(x, Symbol):
return False
return FreeQ(List(F, b, c, d, e, f, m, n, p), x)
cons11 = CustomConstraint(cons_f11)
def cons_f12(F, x):
return FreeQ(F, x)
cons12 = CustomConstraint(cons_f12)
def cons_f13(m, x):
return FreeQ(m, x)
cons13 = CustomConstraint(cons_f13)
def cons_f14(n, x):
return FreeQ(n, x)
cons14 = CustomConstraint(cons_f14)
def cons_f15(p, x):
return FreeQ(p, x)
cons15 = CustomConstraint(cons_f15)
def cons_f16(e, b, c, f, n, a, p, F, x, d, m):
if not isinstance(x, Symbol):
return False
return FreeQ(List(F, a, b, c, d, e, f, m, n, p), x)
cons16 = CustomConstraint(cons_f16)
def cons_f17(n, m):
return IntegersQ(m, n)
cons17 = CustomConstraint(cons_f17)
def cons_f18(n):
return Less(n, S(0))
cons18 = CustomConstraint(cons_f18)
def cons_f19(x, u):
if not isinstance(x, Symbol):
return False
return PolynomialQ(u, x)
cons19 = CustomConstraint(cons_f19)
def cons_f20(G, F, u):
return SameQ(F(u)*G(u), S(1))
cons20 = CustomConstraint(cons_f20)
def cons_f21(q, x):
return FreeQ(q, x)
cons21 = CustomConstraint(cons_f21)
def cons_f22(F):
return MemberQ(List(ArcSin, ArcCos, ArcSinh, ArcCosh), F)
cons22 = CustomConstraint(cons_f22)
def cons_f23(j, n):
return ZeroQ(j - S(2)*n)
cons23 = CustomConstraint(cons_f23)
def cons_f24(A, x):
return FreeQ(A, x)
cons24 = CustomConstraint(cons_f24)
def cons_f25(B, x):
return FreeQ(B, x)
cons25 = CustomConstraint(cons_f25)
def cons_f26(m, u, x):
if not isinstance(x, Symbol):
return False
def _cons_f_u(d, w, c, p, x):
return And(FreeQ(List(c, d), x), IntegerQ(p), Greater(p, m))
cons_u = CustomConstraint(_cons_f_u)
pat = Pattern(UtilityOperator((c_ + x_*WC('d', S(1)))**p_*WC('w', S(1)), x_), cons_u)
result_matchq = is_match(UtilityOperator(u, x), pat)
return Not(And(PositiveIntegerQ(m), result_matchq))
cons26 = CustomConstraint(cons_f26)
def cons_f27(b, v, n, a, x, u, m):
if not isinstance(x, Symbol):
return False
return And(FreeQ(List(a, b, m), x), NegativeIntegerQ(n), Not(IntegerQ(m)), PolynomialQ(u, x), PolynomialQ(v, x),\
RationalQ(m), Less(m, -1), GreaterEqual(Exponent(u, x), (-n - IntegerPart(m))*Exponent(v, x)))
cons27 = CustomConstraint(cons_f27)
def cons_f28(v, n, x, u, m):
if not isinstance(x, Symbol):
return False
return And(FreeQ(List(a, b, m), x), NegativeIntegerQ(n), Not(IntegerQ(m)), PolynomialQ(u, x),\
PolynomialQ(v, x), GreaterEqual(Exponent(u, x), -n*Exponent(v, x)))
cons28 = CustomConstraint(cons_f28)
def cons_f29(n):
return PositiveIntegerQ(n/S(4))
cons29 = CustomConstraint(cons_f29)
def cons_f30(n):
return IntegerQ(n)
cons30 = CustomConstraint(cons_f30)
def cons_f31(n):
return Greater(n, S(1))
cons31 = CustomConstraint(cons_f31)
def cons_f32(n, m):
return Less(S(0), m, n)
cons32 = CustomConstraint(cons_f32)
def cons_f33(n, m):
return OddQ(n/GCD(m, n))
cons33 = CustomConstraint(cons_f33)
def cons_f34(a, b):
return PosQ(a/b)
cons34 = CustomConstraint(cons_f34)
def cons_f35(n, m, p):
return IntegersQ(m, n, p)
cons35 = CustomConstraint(cons_f35)
def cons_f36(n, m, p):
return Less(S(0), m, p, n)
cons36 = CustomConstraint(cons_f36)
def cons_f37(q, n, m, p):
return IntegersQ(m, n, p, q)
cons37 = CustomConstraint(cons_f37)
def cons_f38(n, q, m, p):
return Less(S(0), m, p, q, n)
cons38 = CustomConstraint(cons_f38)
def cons_f39(n):
return IntegerQ(n/S(2))
cons39 = CustomConstraint(cons_f39)
def cons_f40(p):
return NegativeIntegerQ(p)
cons40 = CustomConstraint(cons_f40)
def cons_f41(n, m):
return IntegersQ(m, n/S(2))
cons41 = CustomConstraint(cons_f41)
def cons_f42(n, m):
return Unequal(m, n/S(2))
cons42 = CustomConstraint(cons_f42)
def cons_f43(c, b, a):
return NonzeroQ(-S(4)*a*c + b**S(2))
cons43 = CustomConstraint(cons_f43)
def cons_f44(j, n, m):
return IntegersQ(m, n, j)
cons44 = CustomConstraint(cons_f44)
def cons_f45(n, m):
return Less(S(0), m, S(2)*n)
cons45 = CustomConstraint(cons_f45)
def cons_f46(n, m, p):
return Not(And(Equal(m, n), Equal(p, S(-1))))
cons46 = CustomConstraint(cons_f46)
def cons_f47(v, x):
if not isinstance(x, Symbol):
return False
return PolynomialQ(v, x)
cons47 = CustomConstraint(cons_f47)
def cons_f48(v, x):
if not isinstance(x, Symbol):
return False
return BinomialQ(v, x)
cons48 = CustomConstraint(cons_f48)
def cons_f49(v, x, u):
if not isinstance(x, Symbol):
return False
return Inequality(Exponent(u, x), Equal, Exponent(v, x) + S(-1), GreaterEqual, S(2))
cons49 = CustomConstraint(cons_f49)
def cons_f50(v, x, u):
if not isinstance(x, Symbol):
return False
return GreaterEqual(Exponent(u, x), Exponent(v, x))
cons50 = CustomConstraint(cons_f50)
def cons_f51(p):
return Not(IntegerQ(p))
cons51 = CustomConstraint(cons_f51)
def With2(e, b, c, f, n, a, g, h, x, d, m):
tmp = a*h - b*g
k = Symbol('k')
return f**(e*(c + d*x)**n)*SimplifyTerm(h**(-m)*tmp**m, x)/(g + h*x) + Sum_doit(f**(e*(c + d*x)**n)*(a + b*x)**(-k + m)*SimplifyTerm(b*h**(-k)*tmp**(k - 1), x), List(k, 1, m))
pattern2 = Pattern(UtilityOperator(f_**((x_*WC('d', S(1)) + WC('c', S(0)))**WC('n', S(1))*WC('e', S(1)))*(x_*WC('b', S(1)) + WC('a', S(0)))**WC('m', S(1))/(x_*WC('h', S(1)) + WC('g', S(0))), x_), cons3, cons4, cons5, cons6, cons7, cons8, cons9, cons10, cons1, cons2)
rule2 = ReplacementRule(pattern2, With2)
pattern3 = Pattern(UtilityOperator(F_**((x_*WC('d', S(1)) + WC('c', S(0)))**WC('n', S(1))*WC('b', S(1)))*x_**WC('m', S(1))*(e_ + x_*WC('f', S(1)))**WC('p', S(1)), x_), cons12, cons4, cons5, cons6, cons7, cons8, cons13, cons14, cons15, cons11)
def replacement3(e, b, c, f, n, p, F, x, d, m):
return If(And(PositiveIntegerQ(m, p), LessEqual(m, p), Or(EqQ(n, S(1)), ZeroQ(-c*f + d*e))), ExpandLinearProduct(F**(b*(c + d*x)**n)*(e + f*x)**p, x**m, e, f, x), If(PositiveIntegerQ(p), Distribute(F**(b*(c + d*x)**n)*x**m*(e + f*x)**p, Plus, Times), ExpandIntegrand(F**(b*(c + d*x)**n), x**m*(e + f*x)**p, x)))
rule3 = ReplacementRule(pattern3, replacement3)
pattern4 = Pattern(UtilityOperator(F_**((x_*WC('d', S(1)) + WC('c', S(0)))**WC('n', S(1))*WC('b', S(1)) + WC('a', S(0)))*x_**WC('m', S(1))*(e_ + x_*WC('f', S(1)))**WC('p', S(1)), x_), cons12, cons3, cons4, cons5, cons6, cons7, cons8, cons13, cons14, cons15, cons16)
def replacement4(e, b, c, f, n, a, p, F, x, d, m):
return If(And(PositiveIntegerQ(m, p), LessEqual(m, p), Or(EqQ(n, S(1)), ZeroQ(-c*f + d*e))), ExpandLinearProduct(F**(a + b*(c + d*x)**n)*(e + f*x)**p, x**m, e, f, x), If(PositiveIntegerQ(p), Distribute(F**(a + b*(c + d*x)**n)*x**m*(e + f*x)**p, Plus, Times), ExpandIntegrand(F**(a + b*(c + d*x)**n), x**m*(e + f*x)**p, x)))
rule4 = ReplacementRule(pattern4, replacement4)
def With5(b, v, c, n, a, F, u, x, d, m):
if not isinstance(x, Symbol) or not (FreeQ([F, a, b, c, d], x) and IntegersQ(m, n) and n < 0):
return False
w = ExpandIntegrand((a + b*x)**m*(c + d*x)**n, x)
w = ReplaceAll(w, Rule(x, F**v))
if SumQ(w):
return True
return False
pattern5 = Pattern(UtilityOperator((F_**v_*WC('b', S(1)) + a_)**WC('m', S(1))*(F_**v_*WC('d', S(1)) + c_)**n_*WC('u', S(1)), x_), cons12, cons3, cons4, cons5, cons6, cons17, cons18, CustomConstraint(With5))
def replacement5(b, v, c, n, a, F, u, x, d, m):
w = ReplaceAll(ExpandIntegrand((a + b*x)**m*(c + d*x)**n, x), Rule(x, F**v))
return w.func(*[u*i for i in w.args])
rule5 = ReplacementRule(pattern5, replacement5)
def With6(e, b, c, f, n, a, x, u, d, m):
if not isinstance(x, Symbol) or not (FreeQ([a, b, c, d, e, f, m, n], x) and PolynomialQ(u,x)):
return False
v = ExpandIntegrand(u*(a + b*x)**m, x)
if SumQ(v):
return True
return False
pattern6 = Pattern(UtilityOperator(f_**((x_*WC('d', S(1)) + WC('c', S(0)))**WC('n', S(1))*WC('e', S(1)))*u_*(x_*WC('b', S(1)) + WC('a', S(0)))**WC('m', S(1)), x_), cons3, cons4, cons5, cons6, cons7, cons8, cons13, cons14, cons19, CustomConstraint(With6))
def replacement6(e, b, c, f, n, a, x, u, d, m):
v = ExpandIntegrand(u*(a + b*x)**m, x)
return Distribute(f**(e*(c + d*x)**n)*v, Plus, Times)
rule6 = ReplacementRule(pattern6, replacement6)
pattern7 = Pattern(UtilityOperator(u_*(x_*WC('b', S(1)) + WC('a', S(0)))**WC('m', S(1))*Log((x_**WC('n', S(1))*WC('e', S(1)) + WC('d', S(0)))**WC('p', S(1))*WC('c', S(1))), x_), cons3, cons4, cons5, cons6, cons7, cons13, cons14, cons15, cons19)
def replacement7(e, b, c, n, a, p, x, u, d, m):
return ExpandIntegrand(Log(c*(d + e*x**n)**p), u*(a + b*x)**m, x)
rule7 = ReplacementRule(pattern7, replacement7)
pattern8 = Pattern(UtilityOperator(f_**((x_*WC('d', S(1)) + WC('c', S(0)))**WC('n', S(1))*WC('e', S(1)))*u_, x_), cons5, cons6, cons7, cons8, cons14, cons19)
def replacement8(e, c, f, n, x, u, d):
return If(EqQ(n, S(1)), ExpandIntegrand(f**(e*(c + d*x)**n), u, x), ExpandLinearProduct(f**(e*(c + d*x)**n), u, c, d, x))
rule8 = ReplacementRule(pattern8, replacement8)
# pattern9 = Pattern(UtilityOperator(F_**u_*(G_*u_*WC('b', S(1)) + a_)**WC('n', S(1)), x_), cons3, cons4, cons17, cons20)
# def replacement9(b, G, n, a, F, u, x, m):
# return ReplaceAll(ExpandIntegrand(x**(-m)*(a + b*x)**n, x), Rule(x, G(u)))
# rule9 = ReplacementRule(pattern9, replacement9)
pattern10 = Pattern(UtilityOperator(u_*(WC('a', S(0)) + WC('b', S(1))*Log(((x_*WC('f', S(1)) + WC('e', S(0)))**WC('p', S(1))*WC('d', S(1)))**WC('q', S(1))*WC('c', S(1))))**n_, x_), cons3, cons4, cons5, cons6, cons7, cons8, cons14, cons15, cons21, cons19)
def replacement10(e, b, c, f, n, a, p, x, u, d, q):
return ExpandLinearProduct((a + b*Log(c*(d*(e + f*x)**p)**q))**n, u, e, f, x)
rule10 = ReplacementRule(pattern10, replacement10)
# pattern11 = Pattern(UtilityOperator(u_*(F_*(x_*WC('d', S(1)) + WC('c', S(0)))*WC('b', S(1)) + WC('a', S(0)))**n_, x_), cons3, cons4, cons5, cons6, cons14, cons19, cons22)
# def replacement11(b, c, n, a, F, u, x, d):
# return ExpandLinearProduct((a + b*F(c + d*x))**n, u, c, d, x)
# rule11 = ReplacementRule(pattern11, replacement11)
pattern12 = Pattern(UtilityOperator(WC('u', S(1))/(x_**n_*WC('a', S(1)) + sqrt(c_ + x_**j_*WC('d', S(1)))*WC('b', S(1))), x_), cons3, cons4, cons5, cons6, cons14, cons23)
def replacement12(b, c, n, a, x, u, d, j):
return ExpandIntegrand(u*(a*x**n - b*sqrt(c + d*x**(S(2)*n)))/(-b**S(2)*c + x**(S(2)*n)*(a**S(2) - b**S(2)*d)), x)
rule12 = ReplacementRule(pattern12, replacement12)
pattern13 = Pattern(UtilityOperator((a_ + x_*WC('b', S(1)))**m_/(c_ + x_*WC('d', S(1))), x_), cons3, cons4, cons5, cons6, cons1)
def replacement13(b, c, a, x, d, m):
if RationalQ(a, b, c, d):
return ExpandExpression((a + b*x)**m/(c + d*x), x)
else:
tmp = a*d - b*c
k = Symbol("k")
return Sum_doit((a + b*x)**(-k + m)*SimplifyTerm(b*d**(-k)*tmp**(k + S(-1)), x), List(k, S(1), m)) + SimplifyTerm(d**(-m)*tmp**m, x)/(c + d*x)
rule13 = ReplacementRule(pattern13, replacement13)
pattern14 = Pattern(UtilityOperator((A_ + x_*WC('B', S(1)))*(a_ + x_*WC('b', S(1)))**WC('m', S(1))/(c_ + x_*WC('d', S(1))), x_), cons3, cons4, cons5, cons6, cons24, cons25, cons1)
def replacement14(b, B, A, c, a, x, d, m):
if RationalQ(a, b, c, d, A, B):
return ExpandExpression((A + B*x)*(a + b*x)**m/(c + d*x), x)
else:
tmp1 = (A*d - B*c)/d
tmp2 = ExpandIntegrand((a + b*x)**m/(c + d*x), x)
tmp2 = If(SumQ(tmp2), tmp2.func(*[SimplifyTerm(tmp1*i, x) for i in tmp2.args]), SimplifyTerm(tmp1*tmp2, x))
return SimplifyTerm(B/d, x)*(a + b*x)**m + tmp2
rule14 = ReplacementRule(pattern14, replacement14)
def With15(b, a, x, u, m):
tmp1 = ExpandLinearProduct((a + b*x)**m, u, a, b, x)
if not IntegerQ(m):
return tmp1
else:
tmp2 = ExpandExpression(u*(a + b*x)**m, x)
if SumQ(tmp2) and LessEqual(LeafCount(tmp2), LeafCount(tmp1) + S(2)):
return tmp2
else:
return tmp1
pattern15 = Pattern(UtilityOperator(u_*(a_ + x_*WC('b', S(1)))**m_, x_), cons3, cons4, cons13, cons19, cons26)
rule15 = ReplacementRule(pattern15, With15)
pattern16 = Pattern(UtilityOperator(u_*v_**n_*(a_ + x_*WC('b', S(1)))**m_, x_), cons27)
def replacement16(b, v, n, a, x, u, m):
s = PolynomialQuotientRemainder(u, v**(-n)*(a+b*x)**(-IntegerPart(m)), x)
return ExpandIntegrand((a + b*x)**FractionalPart(m)*s[0], x) + ExpandIntegrand(v**n*(a + b*x)**m*s[1], x)
rule16 = ReplacementRule(pattern16, replacement16)
pattern17 = Pattern(UtilityOperator(u_*v_**n_*(a_ + x_*WC('b', S(1)))**m_, x_), cons28)
def replacement17(b, v, n, a, x, u, m):
s = PolynomialQuotientRemainder(u, v**(-n),x)
return ExpandIntegrand((a + b*x)**(m)*s[0], x) + ExpandIntegrand(v**n*(a + b*x)**m*s[1], x)
rule17 = ReplacementRule(pattern17, replacement17)
def With18(b, n, a, x, u):
r = Numerator(Rt(-a/b, S(2)))
s = Denominator(Rt(-a/b, S(2)))
return r/(S(2)*a*(r + s*u**(n/S(2)))) + r/(S(2)*a*(r - s*u**(n/S(2))))
pattern18 = Pattern(UtilityOperator(S(1)/(a_ + u_**n_*WC('b', S(1))), x_), cons3, cons4, cons29)
rule18 = ReplacementRule(pattern18, With18)
def With19(b, n, a, x, u):
k = Symbol("k")
r = Numerator(Rt(-a/b, n))
s = Denominator(Rt(-a/b, n))
return Sum_doit(r/(a*n*(-(-1)**(2*k/n)*s*u + r)), List(k, 1, n))
pattern19 = Pattern(UtilityOperator(S(1)/(a_ + u_**n_*WC('b', S(1))), x_), cons3, cons4, cons30, cons31)
rule19 = ReplacementRule(pattern19, With19)
def With20(b, n, a, x, u, m):
k = Symbol("k")
g = GCD(m, n)
r = Numerator(Rt(a/b, n/GCD(m, n)))
s = Denominator(Rt(a/b, n/GCD(m, n)))
return If(CoprimeQ(g + m, n), Sum_doit((-1)**(-2*k*m/n)*r*(-r/s)**(m/g)/(a*n*((-1)**(2*g*k/n)*s*u**g + r)), List(k, 1, n/g)), Sum_doit((-1)**(2*k*(g + m)/n)*r*(-r/s)**(m/g)/(a*n*((-1)**(2*g*k/n)*r + s*u**g)), List(k, 1, n/g)))
pattern20 = Pattern(UtilityOperator(u_**WC('m', S(1))/(a_ + u_**n_*WC('b', S(1))), x_), cons3, cons4, cons17, cons32, cons33, cons34)
rule20 = ReplacementRule(pattern20, With20)
def With21(b, n, a, x, u, m):
k = Symbol("k")
g = GCD(m, n)
r = Numerator(Rt(-a/b, n/GCD(m, n)))
s = Denominator(Rt(-a/b, n/GCD(m, n)))
return If(Equal(n/g, S(2)), s/(S(2)*b*(r + s*u**g)) - s/(S(2)*b*(r - s*u**g)), If(CoprimeQ(g + m, n), Sum_doit((S(-1))**(-S(2)*k*m/n)*r*(r/s)**(m/g)/(a*n*(-(S(-1))**(S(2)*g*k/n)*s*u**g + r)), List(k, S(1), n/g)), Sum_doit((S(-1))**(S(2)*k*(g + m)/n)*r*(r/s)**(m/g)/(a*n*((S(-1))**(S(2)*g*k/n)*r - s*u**g)), List(k, S(1), n/g))))
pattern21 = Pattern(UtilityOperator(u_**WC('m', S(1))/(a_ + u_**n_*WC('b', S(1))), x_), cons3, cons4, cons17, cons32)
rule21 = ReplacementRule(pattern21, With21)
def With22(b, c, n, a, x, u, d, m):
k = Symbol("k")
r = Numerator(Rt(-a/b, n))
s = Denominator(Rt(-a/b, n))
return Sum_doit((c*r + (-1)**(-2*k*m/n)*d*r*(r/s)**m)/(a*n*(-(-1)**(2*k/n)*s*u + r)), List(k, 1, n))
pattern22 = Pattern(UtilityOperator((c_ + u_**WC('m', S(1))*WC('d', S(1)))/(a_ + u_**n_*WC('b', S(1))), x_), cons3, cons4, cons5, cons6, cons17, cons32)
rule22 = ReplacementRule(pattern22, With22)
def With23(e, b, c, n, a, p, x, u, d, m):
k = Symbol("k")
r = Numerator(Rt(-a/b, n))
s = Denominator(Rt(-a/b, n))
return Sum_doit((c*r + (-1)**(-2*k*p/n)*e*r*(r/s)**p + (-1)**(-2*k*m/n)*d*r*(r/s)**m)/(a*n*(-(-1)**(2*k/n)*s*u + r)), List(k, 1, n))
pattern23 = Pattern(UtilityOperator((u_**p_*WC('e', S(1)) + u_**WC('m', S(1))*WC('d', S(1)) + WC('c', S(0)))/(a_ + u_**n_*WC('b', S(1))), x_), cons3, cons4, cons5, cons6, cons7, cons35, cons36)
rule23 = ReplacementRule(pattern23, With23)
def With24(e, b, c, f, n, a, p, x, u, d, q, m):
k = Symbol("k")
r = Numerator(Rt(-a/b, n))
s = Denominator(Rt(-a/b, n))
return Sum_doit((c*r + (-1)**(-2*k*q/n)*f*r*(r/s)**q + (-1)**(-2*k*p/n)*e*r*(r/s)**p + (-1)**(-2*k*m/n)*d*r*(r/s)**m)/(a*n*(-(-1)**(2*k/n)*s*u + r)), List(k, 1, n))
pattern24 = Pattern(UtilityOperator((u_**p_*WC('e', S(1)) + u_**q_*WC('f', S(1)) + u_**WC('m', S(1))*WC('d', S(1)) + WC('c', S(0)))/(a_ + u_**n_*WC('b', S(1))), x_), cons3, cons4, cons5, cons6, cons7, cons8, cons37, cons38)
rule24 = ReplacementRule(pattern24, With24)
def With25(c, n, a, p, x, u):
q = Symbol('q')
return ReplaceAll(ExpandIntegrand(c**(-p), (c*x - q)**p*(c*x + q)**p, x), List(Rule(q, Rt(-a*c, S(2))), Rule(x, u**(n/S(2)))))
pattern25 = Pattern(UtilityOperator((a_ + u_**WC('n', S(1))*WC('c', S(1)))**p_, x_), cons3, cons5, cons39, cons40)
rule25 = ReplacementRule(pattern25, With25)
def With26(c, n, a, p, x, u, m):
q = Symbol('q')
return ReplaceAll(ExpandIntegrand(c**(-p), x**m*(c*x**(n/S(2)) - q)**p*(c*x**(n/S(2)) + q)**p, x), List(Rule(q, Rt(-a*c, S(2))), Rule(x, u)))
pattern26 = Pattern(UtilityOperator(u_**WC('m', S(1))*(u_**WC('n', S(1))*WC('c', S(1)) + WC('a', S(0)))**p_, x_), cons3, cons5, cons41, cons40, cons32, cons42)
rule26 = ReplacementRule(pattern26, With26)
def With27(b, c, n, a, p, x, u, j):
q = Symbol('q')
return ReplaceAll(ExpandIntegrand(S(4)**(-p)*c**(-p), (b + S(2)*c*x - q)**p*(b + S(2)*c*x + q)**p, x), List(Rule(q, Rt(-S(4)*a*c + b**S(2), S(2))), Rule(x, u**n)))
pattern27 = Pattern(UtilityOperator((u_**WC('j', S(1))*WC('c', S(1)) + u_**WC('n', S(1))*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons3, cons4, cons5, cons30, cons23, cons40, cons43)
rule27 = ReplacementRule(pattern27, With27)
def With28(b, c, n, a, p, x, u, j, m):
q = Symbol('q')
return ReplaceAll(ExpandIntegrand(S(4)**(-p)*c**(-p), x**m*(b + S(2)*c*x**n - q)**p*(b + S(2)*c*x**n + q)**p, x), List(Rule(q, Rt(-S(4)*a*c + b**S(2), S(2))), Rule(x, u)))
pattern28 = Pattern(UtilityOperator(u_**WC('m', S(1))*(u_**WC('j', S(1))*WC('c', S(1)) + u_**WC('n', S(1))*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons3, cons4, cons5, cons44, cons23, cons40, cons45, cons46, cons43)
rule28 = ReplacementRule(pattern28, With28)
def With29(b, c, n, a, x, u, d, j):
q = Rt(-a/b, S(2))
return -(c - d*q)/(S(2)*b*q*(q + u**n)) - (c + d*q)/(S(2)*b*q*(q - u**n))
pattern29 = Pattern(UtilityOperator((u_**WC('n', S(1))*WC('d', S(1)) + WC('c', S(0)))/(a_ + u_**WC('j', S(1))*WC('b', S(1))), x_), cons3, cons4, cons5, cons6, cons14, cons23)
rule29 = ReplacementRule(pattern29, With29)
def With30(e, b, c, f, n, a, g, x, u, d, j):
q = Rt(-S(4)*a*c + b**S(2), S(2))
r = TogetherSimplify((-b*e*g + S(2)*c*(d + e*f))/q)
return (e*g - r)/(b + 2*c*u**n + q) + (e*g + r)/(b + 2*c*u**n - q)
pattern30 = Pattern(UtilityOperator(((u_**WC('n', S(1))*WC('g', S(1)) + WC('f', S(0)))*WC('e', S(1)) + WC('d', S(0)))/(u_**WC('j', S(1))*WC('c', S(1)) + u_**WC('n', S(1))*WC('b', S(1)) + WC('a', S(0))), x_), cons3, cons4, cons5, cons6, cons7, cons8, cons9, cons14, cons23, cons43)
rule30 = ReplacementRule(pattern30, With30)
def With31(v, x, u):
lst = CoefficientList(u, x)
i = Symbol('i')
return x**Exponent(u, x)*lst[-1]/v + Sum_doit(x**(i - 1)*Part(lst, i), List(i, 1, Exponent(u, x)))/v
pattern31 = Pattern(UtilityOperator(u_/v_, x_), cons19, cons47, cons48, cons49)
rule31 = ReplacementRule(pattern31, With31)
pattern32 = Pattern(UtilityOperator(u_/v_, x_), cons19, cons47, cons50)
def replacement32(v, x, u):
return PolynomialDivide(u, v, x)
rule32 = ReplacementRule(pattern32, replacement32)
pattern33 = Pattern(UtilityOperator(u_*(x_*WC('a', S(1)))**p_, x_), cons51, cons19)
def replacement33(x, a, u, p):
return ExpandToSum((a*x)**p, u, x)
rule33 = ReplacementRule(pattern33, replacement33)
pattern34 = Pattern(UtilityOperator(v_**p_*WC('u', S(1)), x_), cons51)
def replacement34(v, x, u, p):
return ExpandIntegrand(NormalizeIntegrand(v**p, x), u, x)
rule34 = ReplacementRule(pattern34, replacement34)
pattern35 = Pattern(UtilityOperator(u_, x_))
def replacement35(x, u):
return ExpandExpression(u, x)
rule35 = ReplacementRule(pattern35, replacement35)
return [ rule2,rule3, rule4, rule5, rule6, rule7, rule8, rule10, rule12, rule13, rule14, rule15, rule16, rule17, rule18, rule19, rule20, rule21, rule22, rule23, rule24, rule25, rule26, rule27, rule28, rule29, rule30, rule31, rule32, rule33, rule34, rule35]
def _RemoveContentAux():
def cons_f1(b, a):
return IntegersQ(a, b)
cons1 = CustomConstraint(cons_f1)
def cons_f2(b, a):
return Equal(a + b, S(0))
cons2 = CustomConstraint(cons_f2)
def cons_f3(m):
return RationalQ(m)
cons3 = CustomConstraint(cons_f3)
def cons_f4(m, n):
return RationalQ(m, n)
cons4 = CustomConstraint(cons_f4)
def cons_f5(m, n):
return GreaterEqual(-m + n, S(0))
cons5 = CustomConstraint(cons_f5)
def cons_f6(a, x):
return FreeQ(a, x)
cons6 = CustomConstraint(cons_f6)
def cons_f7(m, n, p):
return RationalQ(m, n, p)
cons7 = CustomConstraint(cons_f7)
def cons_f8(m, p):
return GreaterEqual(-m + p, S(0))
cons8 = CustomConstraint(cons_f8)
pattern1 = Pattern(UtilityOperator(a_**m_*WC('u', S(1)) + b_*WC('v', S(1)), x_), cons1, cons2, cons3)
def replacement1(v, x, a, u, m, b):
return If(Greater(m, S(1)), RemoveContentAux(a**(m + S(-1))*u - v, x), RemoveContentAux(-a**(-m + S(1))*v + u, x))
rule1 = ReplacementRule(pattern1, replacement1)
pattern2 = Pattern(UtilityOperator(a_**WC('m', S(1))*WC('u', S(1)) + a_**WC('n', S(1))*WC('v', S(1)), x_), cons6, cons4, cons5)
def replacement2(n, v, x, u, m, a):
return RemoveContentAux(a**(-m + n)*v + u, x)
rule2 = ReplacementRule(pattern2, replacement2)
pattern3 = Pattern(UtilityOperator(a_**WC('m', S(1))*WC('u', S(1)) + a_**WC('n', S(1))*WC('v', S(1)) + a_**WC('p', S(1))*WC('w', S(1)), x_), cons6, cons7, cons5, cons8)
def replacement3(n, v, x, p, u, w, m, a):
return RemoveContentAux(a**(-m + n)*v + a**(-m + p)*w + u, x)
rule3 = ReplacementRule(pattern3, replacement3)
pattern4 = Pattern(UtilityOperator(u_, x_))
def replacement4(u, x):
return If(And(SumQ(u), NegQ(First(u))), -u, u)
rule4 = ReplacementRule(pattern4, replacement4)
return [rule1, rule2, rule3, rule4, ]
IntHide = Int
Log = rubi_log
Null = None
if matchpy:
RemoveContentAux_replacer = ManyToOneReplacer(* _RemoveContentAux())
ExpandIntegrand_rules = _ExpandIntegrand()
TrigSimplifyAux_replacer = _TrigSimplifyAux()
SimplifyAntiderivative_replacer = _SimplifyAntiderivative()
SimplifyAntiderivativeSum_replacer = _SimplifyAntiderivativeSum()
FixSimplify_rules = _FixSimplify()
SimpFixFactor_replacer = _SimpFixFactor()