modelparameters.sympy.simplify package¶
Submodules¶
modelparameters.sympy.simplify.combsimp module¶
- modelparameters.sympy.simplify.combsimp.combsimp(expr)[source]¶
Simplify combinatorial expressions.
This function takes as input an expression containing factorials, binomials, Pochhammer symbol and other “combinatorial” functions, and tries to minimize the number of those functions and reduce the size of their arguments.
The algorithm works by rewriting all combinatorial functions as expressions involving rising factorials (Pochhammer symbols) and applies recurrence relations and other transformations applicable to rising factorials, to reduce their arguments, possibly letting the resulting rising factorial to cancel. Rising factorials with the second argument being an integer are expanded into polynomial forms and finally all other rising factorial are rewritten in terms of more familiar functions. If the initial expression consisted of gamma functions alone, the result is expressed in terms of gamma functions. If the initial expression consists of gamma function with some other combinatorial, the result is expressed in terms of gamma functions.
If the result is expressed using gamma functions, the following three additional steps are performed:
Reduce the number of gammas by applying the reflection theorem gamma(x)*gamma(1-x) == pi/sin(pi*x).
Reduce the number of gammas by applying the multiplication theorem gamma(x)*gamma(x+1/n)*…*gamma(x+(n-1)/n) == C*gamma(n*x).
Reduce the number of prefactors by absorbing them into gammas, where possible.
All transformation rules can be found (or was derived from) here:
http://functions.wolfram.com/GammaBetaErf/Pochhammer/17/01/02/
http://functions.wolfram.com/GammaBetaErf/Pochhammer/27/01/0005/
Examples
>>> from ..simplify import combsimp >>> from .. import factorial, binomial >>> from ..abc import n, k
>>> combsimp(factorial(n)/factorial(n - 3)) n*(n - 2)*(n - 1) >>> combsimp(binomial(n+1, k+1)/binomial(n, k)) (n + 1)/(k + 1)
modelparameters.sympy.simplify.cse_main module¶
Tools for doing common subexpression elimination.
- modelparameters.sympy.simplify.cse_main.cse(exprs, symbols=None, optimizations=None, postprocess=None, order='canonical', ignore=())[source]¶
Perform common subexpression elimination on an expression.
- Parameters:
exprs (list of sympy expressions, or a single sympy expression) – The expressions to reduce.
symbols (infinite iterator yielding unique Symbols) – The symbols used to label the common subexpressions which are pulled out. The
numbered_symbols
generator is useful. The default is a stream of symbols of the form “x0”, “x1”, etc. This must be an infinite iterator.optimizations (list of (callable, callable) pairs) – The (preprocessor, postprocessor) pairs of external optimization functions. Optionally ‘basic’ can be passed for a set of predefined basic optimizations. Such ‘basic’ optimizations were used by default in old implementation, however they can be really slow on larger expressions. Now, no pre or post optimizations are made by default.
postprocess (a function which accepts the two return values of cse and) – returns the desired form of output from cse, e.g. if you want the replacements reversed the function might be the following lambda: lambda r, e: return reversed(r), e
order (string, 'none' or 'canonical') – The order by which Mul and Add arguments are processed. If set to ‘canonical’, arguments will be canonically ordered. If set to ‘none’, ordering will be faster but dependent on expressions hashes, thus machine dependent and variable. For large expressions where speed is a concern, use the setting order=’none’.
ignore (iterable of Symbols) – Substitutions containing any Symbol from
ignore
will be ignored.
- Returns:
replacements (list of (Symbol, expression) pairs) – All of the common subexpressions that were replaced. Subexpressions earlier in this list might show up in subexpressions later in this list.
reduced_exprs (list of sympy expressions) – The reduced expressions with all of the replacements above.
Examples
>>> from .. import cse, SparseMatrix >>> from ..abc import x, y, z, w >>> cse(((w + x + y + z)*(w + y + z))/(w + x)**3) ([(x0, y + z), (x1, w + x)], [(w + x0)*(x0 + x1)/x1**3])
Note that currently, y + z will not get substituted if -y - z is used.
>>> cse(((w + x + y + z)*(w - y - z))/(w + x)**3) ([(x0, w + x)], [(w - y - z)*(x0 + y + z)/x0**3])
List of expressions with recursive substitutions:
>>> m = SparseMatrix([x + y, x + y + z]) >>> cse([(x+y)**2, x + y + z, y + z, x + z + y, m]) ([(x0, x + y), (x1, x0 + z)], [x0**2, x1, y + z, x1, Matrix([ [x0], [x1]])])
Note: the type and mutability of input matrices is retained.
>>> isinstance(_[1][-1], SparseMatrix) True
The user may disallow substitutions containing certain symbols: >>> cse([y**2*(x + 1), 3*y**2*(x + 1)], ignore=(y,)) ([(x0, x + 1)], [x0*y**2, 3*x0*y**2])
- modelparameters.sympy.simplify.cse_main.cse_separate(r, e)[source]¶
Move expressions that are in the form (symbol, expr) out of the expressions and sort them into the replacements using the reps_toposort.
Examples
>>> from .cse_main import cse_separate >>> from ..abc import x, y, z >>> from .. import cos, exp, cse, Eq, symbols >>> x0, x1 = symbols('x:2') >>> eq = (x + 1 + exp((x + 1)/(y + 1)) + cos(y + 1)) >>> cse([eq, Eq(x, z + 1), z - 2], postprocess=cse_separate) in [ ... [[(x0, y + 1), (x, z + 1), (x1, x + 1)], ... [x1 + exp(x1/x0) + cos(x0), z - 2]], ... [[(x1, y + 1), (x, z + 1), (x0, x + 1)], ... [x0 + exp(x0/x1) + cos(x1), z - 2]]] ... True
- modelparameters.sympy.simplify.cse_main.opt_cse(exprs, order='canonical')[source]¶
Find optimization opportunities in Adds, Muls, Pows and negative coefficient Muls
- Parameters:
exprs (list of sympy expressions) – The expressions to optimize.
order (string, 'none' or 'canonical') – The order by which Mul and Add arguments are processed. For large expressions where speed is a concern, use the setting order=’none’.
- Returns:
opt_subs – The expression substitutions which can be useful to optimize CSE.
- Return type:
dictionary of expression substitutions
Examples
>>> from .cse_main import opt_cse >>> from ..abc import x >>> opt_subs = opt_cse([x**-2]) >>> print(opt_subs) {x**(-2): 1/(x**2)}
- modelparameters.sympy.simplify.cse_main.postprocess_for_cse(expr, optimizations)[source]¶
Postprocess an expression after common subexpression elimination to return the expression to canonical sympy form.
- Parameters:
expr (sympy expression) – The target expression to transform.
optimizations (list of (callable, callable) pairs, optional) – The (preprocessor, postprocessor) pairs. The postprocessors will be applied in reversed order to undo the effects of the preprocessors correctly.
- Returns:
expr – The transformed expression.
- Return type:
sympy expression
- modelparameters.sympy.simplify.cse_main.preprocess_for_cse(expr, optimizations)[source]¶
Preprocess an expression to optimize for common subexpression elimination.
- Parameters:
expr (sympy expression) – The target expression to optimize.
optimizations (list of (callable, callable) pairs) – The (preprocessor, postprocessor) pairs.
- Returns:
expr – The transformed expression.
- Return type:
sympy expression
- modelparameters.sympy.simplify.cse_main.reps_toposort(r)[source]¶
Sort replacements r so (k1, v1) appears before (k2, v2) if k2 is in v1’s free symbols. This orders items in the way that cse returns its results (hence, in order to use the replacements in a substitution option it would make sense to reverse the order).
Examples
>>> from .cse_main import reps_toposort >>> from ..abc import x, y >>> from .. import Eq >>> for l, r in reps_toposort([(x, y + 1), (y, 2)]): ... print(Eq(l, r)) ... Eq(y, 2) Eq(x, y + 1)
- modelparameters.sympy.simplify.cse_main.tree_cse(exprs, symbols, opt_subs=None, order='canonical', ignore=())[source]¶
Perform raw CSE on expression tree, taking opt_subs into account.
- Parameters:
exprs (list of sympy expressions) – The expressions to reduce.
symbols (infinite iterator yielding unique Symbols) – The symbols used to label the common subexpressions which are pulled out.
opt_subs (dictionary of expression substitutions) – The expressions to be substituted before any CSE action is performed.
order (string, 'none' or 'canonical') – The order by which Mul and Add arguments are processed. For large expressions where speed is a concern, use the setting order=’none’.
ignore (iterable of Symbols) – Substitutions containing any Symbol from
ignore
will be ignored.
modelparameters.sympy.simplify.cse_opts module¶
Optimizations of the expression tree representation for better CSE opportunities.
modelparameters.sympy.simplify.epathtools module¶
Tools for manipulation of expressions using paths.
- class modelparameters.sympy.simplify.epathtools.EPath(path)[source]¶
Bases:
object
Manipulate expressions using paths.
EPath grammar in EBNF notation:
literal ::= /[A-Za-z_][A-Za-z_0-9]*/ number ::= /-?\d+/ type ::= literal attribute ::= literal "?" all ::= "*" slice ::= "[" number? (":" number? (":" number?)?)? "]" range ::= all | slice query ::= (type | attribute) ("|" (type | attribute))* selector ::= range | query range? path ::= "/" selector ("/" selector)*
See the docstring of the epath() function.
- apply(expr, func, args=None, kwargs=None)[source]¶
Modify parts of an expression selected by a path.
Examples
>>> from .epathtools import EPath >>> from .. import sin, cos, E >>> from ..abc import x, y, z, t
>>> path = EPath("/*/[0]/Symbol") >>> expr = [((x, 1), 2), ((3, y), z)]
>>> path.apply(expr, lambda expr: expr**2) [((x**2, 1), 2), ((3, y**2), z)]
>>> path = EPath("/*/*/Symbol") >>> expr = t + sin(x + 1) + cos(x + y + E)
>>> path.apply(expr, lambda expr: 2*expr) t + sin(2*x + 1) + cos(2*x + 2*y + E)
- select(expr)[source]¶
Retrieve parts of an expression selected by a path.
Examples
>>> from .epathtools import EPath >>> from .. import sin, cos, E >>> from ..abc import x, y, z, t
>>> path = EPath("/*/[0]/Symbol") >>> expr = [((x, 1), 2), ((3, y), z)]
>>> path.select(expr) [x, y]
>>> path = EPath("/*/*/Symbol") >>> expr = t + sin(x + 1) + cos(x + y + E)
>>> path.select(expr) [x, x, y]
- modelparameters.sympy.simplify.epathtools.epath(path, expr=None, func=None, args=None, kwargs=None)[source]¶
Manipulate parts of an expression selected by a path.
This function allows to manipulate large nested expressions in single line of code, utilizing techniques to those applied in XML processing standards (e.g. XPath).
If
func
isNone
,epath()
retrieves elements selected by thepath
. Otherwise it appliesfunc
to each matching element.Note that it is more efficient to create an EPath object and use the select and apply methods of that object, since this will compile the path string only once. This function should only be used as a convenient shortcut for interactive use.
This is the supported syntax:
- select all:
/*
Equivalent of
for arg in args:
.
- select all:
- select slice:
/[0]
or/[1:5]
or/[1:5:2]
Supports standard Python’s slice syntax.
- select slice:
- select by type:
/list
or/list|tuple
Emulates
isinstance()
.
- select by type:
- select by attribute:
/__iter__?
Emulates
hasattr()
.
- select by attribute:
- Parameters:
path (str | EPath) – A path as a string or a compiled EPath.
expr (Basic | iterable) – An expression or a container of expressions.
func (callable (optional)) – A callable that will be applied to matching parts.
args (tuple (optional)) – Additional positional arguments to
func
.kwargs (dict (optional)) – Additional keyword arguments to
func
.
Examples
>>> from .epathtools import epath >>> from .. import sin, cos, E >>> from ..abc import x, y, z, t
>>> path = "/*/[0]/Symbol" >>> expr = [((x, 1), 2), ((3, y), z)]
>>> epath(path, expr) [x, y] >>> epath(path, expr, lambda expr: expr**2) [((x**2, 1), 2), ((3, y**2), z)]
>>> path = "/*/*/Symbol" >>> expr = t + sin(x + 1) + cos(x + y + E)
>>> epath(path, expr) [x, x, y] >>> epath(path, expr, lambda expr: 2*expr) t + sin(2*x + 1) + cos(2*x + 2*y + E)
modelparameters.sympy.simplify.fu module¶
Implementation of the trigsimp algorithm by Fu et al.
The idea behind the fu
algorithm is to use a sequence of rules, applied
in what is heuristically known to be a smart order, to select a simpler
expression that is equivalent to the input.
There are transform rules in which a single rule is applied to the expression tree. The following are just mnemonic in nature; see the docstrings for examples.
TR0 - simplify expression TR1 - sec-csc to cos-sin TR2 - tan-cot to sin-cos ratio TR2i - sin-cos ratio to tan TR3 - angle canonicalization TR4 - functions at special angles TR5 - powers of sin to powers of cos TR6 - powers of cos to powers of sin TR7 - reduce cos power (increase angle) TR8 - expand products of sin-cos to sums TR9 - contract sums of sin-cos to products TR10 - separate sin-cos arguments TR10i - collect sin-cos arguments TR11 - reduce double angles TR12 - separate tan arguments TR12i - collect tan arguments TR13 - expand product of tan-cot TRmorrie - prod(cos(x*2**i), (i, 0, k - 1)) -> sin(2**k*x)/(2**k*sin(x)) TR14 - factored powers of sin or cos to cos or sin power TR15 - negative powers of sin to cot power TR16 - negative powers of cos to tan power TR22 - tan-cot powers to negative powers of sec-csc functions TR111 - negative sin-cos-tan powers to csc-sec-cot
There are 4 combination transforms (CTR1 - CTR4) in which a sequence of transformations are applied and the simplest expression is selected from a few options.
Finally, there are the 2 rule lists (RL1 and RL2), which apply a
sequence of transformations and combined transformations, and the fu
algorithm itself, which applies rules and rule lists and selects the
best expressions. There is also a function L
which counts the number
of trigonometric functions that appear in the expression.
Other than TR0, re-writing of expressions is not done by the transformations.
e.g. TR10i finds pairs of terms in a sum that are in the form like
cos(x)*cos(y) + sin(x)*sin(y)
. Such expression are targeted in a bottom-up
traversal of the expression, but no manipulation to make them appear is
attempted. For example,
Set-up for examples below:
>>> from .fu import fu, L, TR9, TR10i, TR11 >>> from .. import factor, sin, cos, powsimp >>> from ..abc import x, y, z, a >>> from time import time
>>> eq = cos(x + y)/cos(x)
>>> TR10i(eq.expand(trig=True))
-sin(x)*sin(y)/cos(x) + cos(y)
If the expression is put in “normal” form (with a common denominator) then the transformation is successful:
>>> TR10i(_.normal())
cos(x + y)/cos(x)
TR11’s behavior is similar. It rewrites double angles as smaller angles but doesn’t do any simplification of the result.
>>> TR11(sin(2)**a*cos(1)**(-a), 1)
(2*sin(1)*cos(1))**a*cos(1)**(-a)
>>> powsimp(_)
(2*sin(1))**a
The temptation is to try make these TR rules “smarter” but that should really be done at a higher level; the TR rules should try maintain the “do one thing well” principle. There is one exception, however. In TR10i and TR9 terms are recognized even when they are each multiplied by a common factor:
>>> fu(a*cos(x)*cos(y) + a*sin(x)*sin(y))
a*cos(x - y)
Factoring with factor_terms
is used but it it “JIT”-like, being delayed
until it is deemed necessary. Furthermore, if the factoring does not
help with the simplification, it is not retained, so
a*cos(x)*cos(y) + a*sin(x)*sin(z)
does not become the factored
(but unsimplified in the trigonometric sense) expression:
>>> fu(a*cos(x)*cos(y) + a*sin(x)*sin(z))
a*sin(x)*sin(z) + a*cos(x)*cos(y)
In some cases factoring might be a good idea, but the user is left to make that decision. For example:
>>> expr=((15*sin(2*x) + 19*sin(x + y) + 17*sin(x + z) + 19*cos(x - z) +
... 25)*(20*sin(2*x) + 15*sin(x + y) + sin(y + z) + 14*cos(x - z) +
... 14*cos(y - z))*(9*sin(2*y) + 12*sin(y + z) + 10*cos(x - y) + 2*cos(y -
... z) + 18)).expand(trig=True).expand()
In the expanded state, there are nearly 1000 trig functions:
>>> L(expr)
932
If the expression where factored first, this would take time but the resulting expression would be transformed very quickly:
>>> def clock(f, n=2):
... t=time(); f(); return round(time()-t, n)
...
>>> clock(lambda: factor(expr))
0.86
>>> clock(lambda: TR10i(expr), 3)
0.016
If the unexpanded expression is used, the transformation takes longer but not as long as it took to factor it and then transform it:
>>> clock(lambda: TR10i(expr), 2)
0.28
So neither expansion nor factoring is used in TR10i
: if the
expression is already factored (or partially factored) then expansion
with trig=True
would destroy what is already known and take
longer; if the expression is expanded, factoring may take longer than
simply applying the transformation itself.
Although the algorithms should be canonical, always giving the same result, they may not yield the best result. This, in general, is the nature of simplification where searching all possible transformation paths is very expensive. Here is a simple example. There are 6 terms in the following sum:
>>> expr = (sin(x)**2*cos(y)*cos(z) + sin(x)*sin(y)*cos(x)*cos(z) +
... sin(x)*sin(z)*cos(x)*cos(y) + sin(y)*sin(z)*cos(x)**2 + sin(y)*sin(z) +
... cos(y)*cos(z))
>>> args = expr.args
Serendipitously, fu gives the best result:
>>> fu(expr)
3*cos(y - z)/2 - cos(2*x + y + z)/2
But if different terms were combined, a less-optimal result might be
obtained, requiring some additional work to get better simplification,
but still less than optimal. The following shows an alternative form
of expr
that resists optimal simplification once a given step
is taken since it leads to a dead end:
>>> TR9(-cos(x)**2*cos(y + z) + 3*cos(y - z)/2 +
... cos(y + z)/2 + cos(-2*x + y + z)/4 - cos(2*x + y + z)/4)
sin(2*x)*sin(y + z)/2 - cos(x)**2*cos(y + z) + 3*cos(y - z)/2 + cos(y + z)/2
Here is a smaller expression that exhibits the same behavior:
>>> a = sin(x)*sin(z)*cos(x)*cos(y) + sin(x)*sin(y)*cos(x)*cos(z)
>>> TR10i(a)
sin(x)*sin(y + z)*cos(x)
>>> newa = _
>>> TR10i(expr - a) # this combines two more of the remaining terms
sin(x)**2*cos(y)*cos(z) + sin(y)*sin(z)*cos(x)**2 + cos(y - z)
>>> TR10i(_ + newa) == _ + newa # but now there is no more simplification
True
Without getting lucky or trying all possible pairings of arguments, the final result may be less than optimal and impossible to find without better heuristics or brute force trial of all possibilities.
Notes
This work was started by Dimitar Vlahovski at the Technological School “Electronic systems” (30.11.2011).
References
Fu, Hongguang, Xiuqin Zhong, and Zhenbing Zeng. “Automated and readable simplification of trigonometric expressions.” Mathematical and computer modelling 44.11 (2006): 1169-1177. http://rfdz.ph-noe.ac.at/fileadmin/Mathematik_Uploads/ACDCA/DESTIME2006/DES_contribs/Fu/simplification.pdf
http://www.sosmath.com/trig/Trig5/trig5/pdf/pdf.html gives a formula sheet.
- modelparameters.sympy.simplify.fu.L(rv)[source]¶
Return count of trigonometric functions in expression.
Examples
>>> from .fu import L >>> from ..abc import x >>> from .. import cos, sin >>> L(cos(x)+sin(x)) 2
- modelparameters.sympy.simplify.fu.TR0(rv)[source]¶
Simplification of rational polynomials, trying to simplify the expression, e.g. combine things like 3*x + 2*x, etc….
- modelparameters.sympy.simplify.fu.TR1(rv)[source]¶
Replace sec, csc with 1/cos, 1/sin
Examples
>>> from .fu import TR1, sec, csc >>> from ..abc import x >>> TR1(2*csc(x) + sec(x)) 1/cos(x) + 2/sin(x)
- modelparameters.sympy.simplify.fu.TR10(rv, first=True)[source]¶
Separate sums in
cos
andsin
.Examples
>>> from .fu import TR10 >>> from ..abc import a, b, c >>> from .. import cos, sin >>> TR10(cos(a + b)) -sin(a)*sin(b) + cos(a)*cos(b) >>> TR10(sin(a + b)) sin(a)*cos(b) + sin(b)*cos(a) >>> TR10(sin(a + b + c)) (-sin(a)*sin(b) + cos(a)*cos(b))*sin(c) + (sin(a)*cos(b) + sin(b)*cos(a))*cos(c)
- modelparameters.sympy.simplify.fu.TR10i(rv)[source]¶
Sum of products to function of sum.
Examples
>>> from .fu import TR10i >>> from .. import cos, sin, pi, Add, Mul, sqrt, Symbol >>> from ..abc import x, y
>>> TR10i(cos(1)*cos(3) + sin(1)*sin(3)) cos(2) >>> TR10i(cos(1)*sin(3) + sin(1)*cos(3) + cos(3)) cos(3) + sin(4) >>> TR10i(sqrt(2)*cos(x)*x + sqrt(6)*sin(x)*x) 2*sqrt(2)*x*sin(x + pi/6)
- modelparameters.sympy.simplify.fu.TR11(rv, base=None)[source]¶
Function of double angle to product. The
base
argument can be used to indicate what is the un-doubled argument, e.g. if 3*pi/7 is the base then cosine and sine functions with argument 6*pi/7 will be replaced.Examples
>>> from .fu import TR11 >>> from .. import cos, sin, pi >>> from ..abc import x >>> TR11(sin(2*x)) 2*sin(x)*cos(x) >>> TR11(cos(2*x)) -sin(x)**2 + cos(x)**2 >>> TR11(sin(4*x)) 4*(-sin(x)**2 + cos(x)**2)*sin(x)*cos(x) >>> TR11(sin(4*x/3)) 4*(-sin(x/3)**2 + cos(x/3)**2)*sin(x/3)*cos(x/3)
If the arguments are simply integers, no change is made unless a base is provided:
>>> TR11(cos(2)) cos(2) >>> TR11(cos(4), 2) -sin(2)**2 + cos(2)**2
There is a subtle issue here in that autosimplification will convert some higher angles to lower angles
>>> cos(6*pi/7) + cos(3*pi/7) -cos(pi/7) + cos(3*pi/7)
The 6*pi/7 angle is now pi/7 but can be targeted with TR11 by supplying the 3*pi/7 base:
>>> TR11(_, 3*pi/7) -sin(3*pi/7)**2 + cos(3*pi/7)**2 + cos(3*pi/7)
- modelparameters.sympy.simplify.fu.TR111(rv)[source]¶
Convert f(x)**-i to g(x)**i where either
i
is an integer or the base is positive and f, g are: tan, cot; sin, csc; or cos, sec.Examples
>>> from .fu import TR111 >>> from ..abc import x >>> from .. import tan >>> TR111(1 - 1/tan(x)**2) -cot(x)**2 + 1
- modelparameters.sympy.simplify.fu.TR12(rv, first=True)[source]¶
Separate sums in
tan
.Examples
>>> from .fu import TR12 >>> from ..abc import x, y >>> from .. import tan >>> from .fu import TR12 >>> TR12(tan(x + y)) (tan(x) + tan(y))/(-tan(x)*tan(y) + 1)
- modelparameters.sympy.simplify.fu.TR12i(rv)[source]¶
Combine tan arguments as (tan(y) + tan(x))/(tan(x)*tan(y) - 1) -> -tan(x + y)
Examples
>>> from .fu import TR12i >>> from .. import tan >>> from ..abc import a, b, c >>> ta, tb, tc = [tan(i) for i in (a, b, c)] >>> TR12i((ta + tb)/(-ta*tb + 1)) tan(a + b) >>> TR12i((ta + tb)/(ta*tb - 1)) -tan(a + b) >>> TR12i((-ta - tb)/(ta*tb - 1)) tan(a + b) >>> eq = (ta + tb)/(-ta*tb + 1)**2*(-3*ta - 3*tc)/(2*(ta*tc - 1)) >>> TR12i(eq.expand()) -3*tan(a + b)*tan(a + c)/(2*(tan(a) + tan(b) - 1))
- modelparameters.sympy.simplify.fu.TR13(rv)[source]¶
Change products of
tan
orcot
.Examples
>>> from .fu import TR13 >>> from .. import tan, cot, cos >>> TR13(tan(3)*tan(2)) -tan(2)/tan(5) - tan(3)/tan(5) + 1 >>> TR13(cot(3)*cot(2)) cot(2)*cot(5) + 1 + cot(3)*cot(5)
- modelparameters.sympy.simplify.fu.TR14(rv, first=True)[source]¶
Convert factored powers of sin and cos identities into simpler expressions.
Examples
>>> from .fu import TR14 >>> from ..abc import x, y >>> from .. import cos, sin >>> TR14((cos(x) - 1)*(cos(x) + 1)) -sin(x)**2 >>> TR14((sin(x) - 1)*(sin(x) + 1)) -cos(x)**2 >>> p1 = (cos(x) + 1)*(cos(x) - 1) >>> p2 = (cos(y) - 1)*2*(cos(y) + 1) >>> p3 = (3*(cos(y) - 1))*(3*(cos(y) + 1)) >>> TR14(p1*p2*p3*(x - 1)) -18*(x - 1)*sin(x)**2*sin(y)**4
- modelparameters.sympy.simplify.fu.TR15(rv, max=4, pow=False)[source]¶
Convert sin(x)*-2 to 1 + cot(x)**2.
See _TR56 docstring for advanced use of
max
andpow
.Examples
>>> from .fu import TR15 >>> from ..abc import x >>> from .. import cos, sin >>> TR15(1 - 1/sin(x)**2) -cot(x)**2
- modelparameters.sympy.simplify.fu.TR16(rv, max=4, pow=False)[source]¶
Convert cos(x)*-2 to 1 + tan(x)**2.
See _TR56 docstring for advanced use of
max
andpow
.Examples
>>> from .fu import TR16 >>> from ..abc import x >>> from .. import cos, sin >>> TR16(1 - 1/cos(x)**2) -tan(x)**2
- modelparameters.sympy.simplify.fu.TR2(rv)[source]¶
Replace tan and cot with sin/cos and cos/sin
Examples
>>> from .fu import TR2 >>> from ..abc import x >>> from .. import tan, cot, sin, cos >>> TR2(tan(x)) sin(x)/cos(x) >>> TR2(cot(x)) cos(x)/sin(x) >>> TR2(tan(tan(x) - sin(x)/cos(x))) 0
- modelparameters.sympy.simplify.fu.TR22(rv, max=4, pow=False)[source]¶
Convert tan(x)**2 to sec(x)**2 - 1 and cot(x)**2 to csc(x)**2 - 1.
See _TR56 docstring for advanced use of
max
andpow
.Examples
>>> from .fu import TR22 >>> from ..abc import x >>> from .. import tan, cot >>> TR22(1 + tan(x)**2) sec(x)**2 >>> TR22(1 + cot(x)**2) csc(x)**2
- modelparameters.sympy.simplify.fu.TR2i(rv, half=False)[source]¶
- Converts ratios involving sin and cos as follows::
sin(x)/cos(x) -> tan(x) sin(x)/(cos(x) + 1) -> tan(x/2) if half=True
Examples
>>> from .fu import TR2i >>> from ..abc import x, a >>> from .. import sin, cos >>> TR2i(sin(x)/cos(x)) tan(x)
Powers of the numerator and denominator are also recognized
>>> TR2i(sin(x)**2/(cos(x) + 1)**2, half=True) tan(x/2)**2
The transformation does not take place unless assumptions allow (i.e. the base must be positive or the exponent must be an integer for both numerator and denominator)
>>> TR2i(sin(x)**a/(cos(x) + 1)**a) (cos(x) + 1)**(-a)*sin(x)**a
- modelparameters.sympy.simplify.fu.TR3(rv)[source]¶
Induced formula: example sin(-a) = -sin(a)
Examples
>>> from .fu import TR3 >>> from ..abc import x, y >>> from .. import pi >>> from .. import cos >>> TR3(cos(y - x*(y - x))) cos(x*(x - y) + y) >>> cos(pi/2 + x) -sin(x) >>> cos(30*pi/2 + x) -cos(x)
- modelparameters.sympy.simplify.fu.TR4(rv)[source]¶
Identify values of special angles.
a= 0 pi/6 pi/4 pi/3 pi/2
tan(a) 0 sqt(3)/3 1 sqrt(3) –
Examples
>>> from .fu import TR4 >>> from .. import pi >>> from .. import cos, sin, tan, cot >>> for s in (0, pi/6, pi/4, pi/3, pi/2): ... print('%s %s %s %s' % (cos(s), sin(s), tan(s), cot(s))) ... 1 0 0 zoo sqrt(3)/2 1/2 sqrt(3)/3 sqrt(3) sqrt(2)/2 sqrt(2)/2 1 1 1/2 sqrt(3)/2 sqrt(3) sqrt(3)/3 0 1 zoo 0
- modelparameters.sympy.simplify.fu.TR5(rv, max=4, pow=False)[source]¶
Replacement of sin**2 with 1 - cos(x)**2.
See _TR56 docstring for advanced use of
max
andpow
.Examples
>>> from .fu import TR5 >>> from ..abc import x >>> from .. import sin >>> TR5(sin(x)**2) -cos(x)**2 + 1 >>> TR5(sin(x)**-2) # unchanged sin(x)**(-2) >>> TR5(sin(x)**4) (-cos(x)**2 + 1)**2
- modelparameters.sympy.simplify.fu.TR6(rv, max=4, pow=False)[source]¶
Replacement of cos**2 with 1 - sin(x)**2.
See _TR56 docstring for advanced use of
max
andpow
.Examples
>>> from .fu import TR6 >>> from ..abc import x >>> from .. import cos >>> TR6(cos(x)**2) -sin(x)**2 + 1 >>> TR6(cos(x)**-2) #unchanged cos(x)**(-2) >>> TR6(cos(x)**4) (-sin(x)**2 + 1)**2
- modelparameters.sympy.simplify.fu.TR7(rv)[source]¶
Lowering the degree of cos(x)**2
Examples
>>> from .fu import TR7 >>> from ..abc import x >>> from .. import cos >>> TR7(cos(x)**2) cos(2*x)/2 + 1/2 >>> TR7(cos(x)**2 + 1) cos(2*x)/2 + 3/2
- modelparameters.sympy.simplify.fu.TR8(rv, first=True)[source]¶
Converting products of
cos
and/orsin
to a sum or difference ofcos
and orsin
terms.Examples
>>> from .fu import TR8, TR7 >>> from .. import cos, sin >>> TR8(cos(2)*cos(3)) cos(5)/2 + cos(1)/2 >>> TR8(cos(2)*sin(3)) sin(5)/2 + sin(1)/2 >>> TR8(sin(2)*sin(3)) -cos(5)/2 + cos(1)/2
- modelparameters.sympy.simplify.fu.TR9(rv)[source]¶
Sum of
cos
orsin
terms as a product ofcos
orsin
.Examples
>>> from .fu import TR9 >>> from .. import cos, sin >>> TR9(cos(1) + cos(2)) 2*cos(1/2)*cos(3/2) >>> TR9(cos(1) + 2*sin(1) + 2*sin(2)) cos(1) + 4*sin(3/2)*cos(1/2)
If no change is made by TR9, no re-arrangement of the expression will be made. For example, though factoring of common term is attempted, if the factored expression wasn’t changed, the original expression will be returned:
>>> TR9(cos(3) + cos(3)*cos(2)) cos(3) + cos(2)*cos(3)
- modelparameters.sympy.simplify.fu.TRmorrie(rv)[source]¶
Returns cos(x)*cos(2*x)*…*cos(2**(k-1)*x) -> sin(2**k*x)/(2**k*sin(x))
Examples
>>> from .fu import TRmorrie, TR8, TR3 >>> from ..abc import x >>> from .. import Mul, cos, pi >>> TRmorrie(cos(x)*cos(2*x)) sin(4*x)/(4*sin(x)) >>> TRmorrie(7*Mul(*[cos(x) for x in range(10)])) 7*sin(12)*sin(16)*cos(5)*cos(7)*cos(9)/(64*sin(1)*sin(3))
Sometimes autosimplification will cause a power to be not recognized. e.g. in the following, cos(4*pi/7) automatically simplifies to -cos(3*pi/7) so only 2 of the 3 terms are recognized:
>>> TRmorrie(cos(pi/7)*cos(2*pi/7)*cos(4*pi/7)) -sin(3*pi/7)*cos(3*pi/7)/(4*sin(pi/7))
A touch by TR8 resolves the expression to a Rational
>>> TR8(_) -1/8
In this case, if eq is unsimplified, the answer is obtained directly:
>>> eq = cos(pi/9)*cos(2*pi/9)*cos(3*pi/9)*cos(4*pi/9) >>> TRmorrie(eq) 1/16
But if angles are made canonical with TR3 then the answer is not simplified without further work:
>>> TR3(eq) sin(pi/18)*cos(pi/9)*cos(2*pi/9)/2 >>> TRmorrie(_) sin(pi/18)*sin(4*pi/9)/(8*sin(pi/9)) >>> TR8(_) cos(7*pi/18)/(16*sin(pi/9)) >>> TR3(_) 1/16
The original expression would have resolve to 1/16 directly with TR8, however:
>>> TR8(eq) 1/16
References
- modelparameters.sympy.simplify.fu.as_f_sign_1(e)[source]¶
If
e
is a sum that can be written asg*(a + s)
wheres
is+/-1
, returng
,a
, ands
wherea
does not have a leading negative coefficient.Examples
>>> from .fu import as_f_sign_1 >>> from ..abc import x >>> as_f_sign_1(x + 1) (1, x, 1) >>> as_f_sign_1(x - 1) (1, x, -1) >>> as_f_sign_1(-x + 1) (-1, x, -1) >>> as_f_sign_1(-x - 1) (-1, x, 1) >>> as_f_sign_1(2*x + 2) (2, x, 1)
- modelparameters.sympy.simplify.fu.fu(rv, measure=<function <lambda>>)[source]¶
Attempt to simplify expression by using transformation rules given in the algorithm by Fu et al.
fu()
will try to minimize the objective functionmeasure
. By default this first minimizes the number of trig terms and then minimizes the number of total operations.Examples
>>> from .fu import fu >>> from .. import cos, sin, tan, pi, S, sqrt >>> from ..abc import x, y, a, b
>>> fu(sin(50)**2 + cos(50)**2 + sin(pi/6)) 3/2 >>> fu(sqrt(6)*cos(x) + sqrt(2)*sin(x)) 2*sqrt(2)*sin(x + pi/3)
CTR1 example
>>> eq = sin(x)**4 - cos(y)**2 + sin(y)**2 + 2*cos(x)**2 >>> fu(eq) cos(x)**4 - 2*cos(y)**2 + 2
CTR2 example
>>> fu(S.Half - cos(2*x)/2) sin(x)**2
CTR3 example
>>> fu(sin(a)*(cos(b) - sin(b)) + cos(a)*(sin(b) + cos(b))) sqrt(2)*sin(a + b + pi/4)
CTR4 example
>>> fu(sqrt(3)*cos(x)/2 + sin(x)/2) sin(x + pi/3)
Example 1
>>> fu(1-sin(2*x)**2/4-sin(y)**2-cos(x)**4) -cos(x)**2 + cos(y)**2
Example 2
>>> fu(cos(4*pi/9)) sin(pi/18) >>> fu(cos(pi/9)*cos(2*pi/9)*cos(3*pi/9)*cos(4*pi/9)) 1/16
Example 3
>>> fu(tan(7*pi/18)+tan(5*pi/18)-sqrt(3)*tan(5*pi/18)*tan(7*pi/18)) -sqrt(3)
Objective function example
>>> fu(sin(x)/cos(x)) # default objective function tan(x) >>> fu(sin(x)/cos(x), measure=lambda x: -x.count_ops()) # maximize op count sin(x)/cos(x)
References
http://rfdz.ph-noe.ac.at/fileadmin/Mathematik_Uploads/ACDCA/ DESTIME2006/DES_contribs/Fu/simplification.pdf
- modelparameters.sympy.simplify.fu.hyper_as_trig(rv)[source]¶
Return an expression containing hyperbolic functions in terms of trigonometric functions. Any trigonometric functions initially present are replaced with Dummy symbols and the function to undo the masking and the conversion back to hyperbolics is also returned. It should always be true that:
t, f = hyper_as_trig(expr) expr == f(t)
Examples
>>> from .fu import hyper_as_trig, fu >>> from ..abc import x >>> from .. import cosh, sinh >>> eq = sinh(x)**2 + cosh(x)**2 >>> t, f = hyper_as_trig(eq) >>> f(fu(t)) cosh(2*x)
References
- modelparameters.sympy.simplify.fu.process_common_addends(rv, do, key2=None, key1=True)[source]¶
Apply
do
to addends ofrv
that (if key1=True) share at least a common absolute value of their coefficient and the value ofkey2
when applied to the argument. Ifkey1
is Falsekey2
must be supplied and will be the only key applied.
- modelparameters.sympy.simplify.fu.trig_split(a, b, two=False)[source]¶
Return the gcd, s1, s2, a1, a2, bool where
- If two is False (default) then::
a + b = gcd*(s1*f(a1) + s2*f(a2)) where f = cos if bool else sin
- else:
- if bool, a + b was +/- cos(a1)*cos(a2) +/- sin(a1)*sin(a2) and equals
n1*gcd*cos(a - b) if n1 == n2 else n1*gcd*cos(a + b)
- else a + b was +/- cos(a1)*sin(a2) +/- sin(a1)*cos(a2) and equals
n1*gcd*sin(a + b) if n1 = n2 else n1*gcd*sin(b - a)
Examples
>>> from .fu import trig_split >>> from ..abc import x, y, z >>> from .. import cos, sin, sqrt
>>> trig_split(cos(x), cos(y)) (1, 1, 1, x, y, True) >>> trig_split(2*cos(x), -2*cos(y)) (2, 1, -1, x, y, True) >>> trig_split(cos(x)*sin(y), cos(y)*sin(y)) (sin(y), 1, 1, x, y, True)
>>> trig_split(cos(x), -sqrt(3)*sin(x), two=True) (2, 1, -1, x, pi/6, False) >>> trig_split(cos(x), sin(x), two=True) (sqrt(2), 1, 1, x, pi/4, False) >>> trig_split(cos(x), -sin(x), two=True) (sqrt(2), 1, -1, x, pi/4, False) >>> trig_split(sqrt(2)*cos(x), -sqrt(6)*sin(x), two=True) (2*sqrt(2), 1, -1, x, pi/6, False) >>> trig_split(-sqrt(6)*cos(x), -sqrt(2)*sin(x), two=True) (-2*sqrt(2), 1, 1, x, pi/3, False) >>> trig_split(cos(x)/sqrt(6), sin(x)/sqrt(2), two=True) (sqrt(6)/3, 1, 1, x, pi/6, False) >>> trig_split(-sqrt(6)*cos(x)*sin(y), -sqrt(2)*sin(x)*sin(y), two=True) (-2*sqrt(2)*sin(y), 1, 1, x, pi/3, False)
>>> trig_split(cos(x), sin(x)) >>> trig_split(cos(x), sin(z)) >>> trig_split(2*cos(x), -sin(x)) >>> trig_split(cos(x), -sqrt(3)*sin(x)) >>> trig_split(cos(x)*cos(y), sin(x)*sin(z)) >>> trig_split(cos(x)*cos(y), sin(x)*sin(y)) >>> trig_split(-sqrt(6)*cos(x), sqrt(2)*sin(x)*sin(y), two=True)
modelparameters.sympy.simplify.hyperexpand module¶
Expand Hypergeometric (and Meijer G) functions into named special functions.
The algorithm for doing this uses a collection of lookup tables of hypergeometric functions, and various of their properties, to expand many hypergeometric functions in terms of special functions.
- It is based on the following paper:
Kelly B. Roach. Meijer G Function Representations. In: Proceedings of the 1997 International Symposium on Symbolic and Algebraic Computation, pages 205-211, New York, 1997. ACM.
It is described in great(er) detail in the Sphinx documentation.
- class modelparameters.sympy.simplify.hyperexpand.Formula(func, z, res, symbols, B=None, C=None, M=None)[source]¶
Bases:
object
This class represents hypergeometric formulae.
Its data members are: - z, the argument - closed_form, the closed form expression - symbols, the free symbols (parameters) in the formula - func, the function - B, C, M (see _compute_basis)
>>> from ..abc import a, b, z >>> from .hyperexpand import Formula, Hyper_Function >>> func = Hyper_Function((a/2, a/3 + b, (1+a)/2), (a, b, (a+b)/7)) >>> f = Formula(func, z, None, [a, b])
- property closed_form¶
- class modelparameters.sympy.simplify.hyperexpand.FormulaCollection[source]¶
Bases:
object
A collection of formulae to use as origins.
- lookup_origin(func)[source]¶
Given the suitable target
func
, try to find an origin in our knowledge base.>>> from .hyperexpand import (FormulaCollection, ... Hyper_Function) >>> f = FormulaCollection() >>> f.lookup_origin(Hyper_Function((), ())).closed_form exp(_z) >>> f.lookup_origin(Hyper_Function([1], ())).closed_form HyperRep_power1(-1, _z)
>>> from .. import S >>> i = Hyper_Function([S('1/4'), S('3/4 + 4')], [S.Half]) >>> f.lookup_origin(i).closed_form HyperRep_sqrts1(-1/4, _z)
- class modelparameters.sympy.simplify.hyperexpand.G_Function(an, ap, bm, bq)[source]¶
Bases:
Expr
A Meijer G-function.
- property args¶
Returns a tuple of arguments of ‘self’.
Examples
>>> from .. import cot >>> from ..abc import x, y
>>> cot(x).args (x,)
>>> cot(x).args[0] x
>>> (x*y).args (x, y)
>>> (x*y).args[1] y
Notes
Never use self._args, always use self.args. Only use _args in __new__ when creating a new function. Don’t override .args() from Basic (so that it’s easy to change the interface in the future if needed).
- compute_buckets()[source]¶
Compute buckets for the fours sets of parameters.
We guarantee that any two equal Mod objects returned are actually the same, and that the buckets are sorted by real part (an and bq descendending, bm and ap ascending).
Examples
>>> from .hyperexpand import G_Function >>> from ..abc import y >>> from .. import S, symbols
>>> a, b = [1, 3, 2, S(3)/2], [1 + y, y, 2, y + 3] >>> G_Function(a, b, [2], [y]).compute_buckets() ({0: [3, 2, 1], 1/2: [3/2]}, {0: [2], y: [y, y + 1, y + 3]}, {0: [2]}, {y: [y]})
- default_assumptions = {}¶
- property signature¶
- class modelparameters.sympy.simplify.hyperexpand.Hyper_Function(ap, bq)[source]¶
Bases:
Expr
A generalized hypergeometric function.
- property args¶
Returns a tuple of arguments of ‘self’.
Examples
>>> from .. import cot >>> from ..abc import x, y
>>> cot(x).args (x,)
>>> cot(x).args[0] x
>>> (x*y).args (x, y)
>>> (x*y).args[1] y
Notes
Never use self._args, always use self.args. Only use _args in __new__ when creating a new function. Don’t override .args() from Basic (so that it’s easy to change the interface in the future if needed).
- build_invariants()[source]¶
Compute the invariant vector.
- The invariant vector is:
(gamma, ((s1, n1), …, (sk, nk)), ((t1, m1), …, (tr, mr)))
- where gamma is the number of integer a < 0,
s1 < … < sk nl is the number of parameters a_i congruent to sl mod 1 t1 < … < tr ml is the number of parameters b_i congruent to tl mod 1
If the index pair contains parameters, then this is not truly an invariant, since the parameters cannot be sorted uniquely mod1.
>>> from .hyperexpand import Hyper_Function >>> from .. import S >>> ap = (S(1)/2, S(1)/3, S(-1)/2, -2) >>> bq = (1, 2)
- Here gamma = 1,
- k = 3, s1 = 0, s2 = 1/3, s3 = 1/2
n1 = 1, n2 = 1, n2 = 2
- r = 1, t1 = 0
m1 = 2:
>>> Hyper_Function(ap, bq).build_invariants() (1, ((0, 1), (1/3, 1), (1/2, 2)), ((0, 2),))
- default_assumptions = {}¶
- difficulty(func)[source]¶
Estimate how many steps it takes to reach
func
from self. Return -1 if impossible.
- property gamma¶
Number of upper parameters that are negative integers
This is a transformation invariant.
- property sizes¶
- class modelparameters.sympy.simplify.hyperexpand.MeijerFormula(an, ap, bm, bq, z, symbols, B, C, M, matcher)[source]¶
Bases:
object
This class represents a Meijer G-function formula.
Its data members are: - z, the argument - symbols, the free symbols (parameters) in the formula - func, the function - B, C, M (c/f ordinary Formula)
- property closed_form¶
- class modelparameters.sympy.simplify.hyperexpand.MeijerFormulaCollection[source]¶
Bases:
object
This class holds a collection of meijer g formulae.
- class modelparameters.sympy.simplify.hyperexpand.MeijerShiftA(bi)[source]¶
Bases:
Operator
Increment an upper b index.
- class modelparameters.sympy.simplify.hyperexpand.MeijerShiftB(bi)[source]¶
Bases:
Operator
Decrement an upper a index.
- class modelparameters.sympy.simplify.hyperexpand.MeijerShiftC(bi)[source]¶
Bases:
Operator
Increment a lower b index.
- class modelparameters.sympy.simplify.hyperexpand.MeijerShiftD(bi)[source]¶
Bases:
Operator
Decrement a lower a index.
- class modelparameters.sympy.simplify.hyperexpand.MeijerUnShiftA(an, ap, bm, bq, i, z)[source]¶
Bases:
Operator
Decrement an upper b index.
- class modelparameters.sympy.simplify.hyperexpand.MeijerUnShiftB(an, ap, bm, bq, i, z)[source]¶
Bases:
Operator
Increment an upper a index.
- class modelparameters.sympy.simplify.hyperexpand.MeijerUnShiftC(an, ap, bm, bq, i, z)[source]¶
Bases:
Operator
Decrement a lower b index.
- class modelparameters.sympy.simplify.hyperexpand.MeijerUnShiftD(an, ap, bm, bq, i, z)[source]¶
Bases:
Operator
Increment a lower a index.
- class modelparameters.sympy.simplify.hyperexpand.MultOperator(p)[source]¶
Bases:
Operator
Simply multiply by a “constant”
- class modelparameters.sympy.simplify.hyperexpand.Operator[source]¶
Bases:
object
Base class for operators to be applied to our functions.
These operators are differential operators. They are by convention expressed in the variable D = z*d/dz (although this base class does not actually care). Note that when the operator is applied to an object, we typically do not blindly differentiate but instead use a different representation of the z*d/dz operator (see make_derivative_operator).
To subclass from this, define a __init__ method that initalises a self._poly variable. This variable stores a polynomial. By convention the generator is z*d/dz, and acts to the right of all coefficients.
- Thus this poly
x**2 + 2*z*x + 1
- represents the differential operator
(z*d/dz)**2 + 2*z**2*d/dz.
This class is used only in the implementation of the hypergeometric function expansion algorithm.
- apply(obj, op)[source]¶
Apply
self
to the objectobj
, where the generator isop
.>>> from .hyperexpand import Operator >>> from ..polys.polytools import Poly >>> from ..abc import x, y, z >>> op = Operator() >>> op._poly = Poly(x**2 + z*x + y, x) >>> op.apply(z**7, lambda f: f.diff(z)) y*z**7 + 7*z**7 + 42*z**5
- class modelparameters.sympy.simplify.hyperexpand.ReduceOrder(ai, bj)[source]¶
Bases:
Operator
Reduce Order by cancelling an upper and a lower index.
- class modelparameters.sympy.simplify.hyperexpand.ShiftA(ai)[source]¶
Bases:
Operator
Increment an upper index.
- class modelparameters.sympy.simplify.hyperexpand.ShiftB(bi)[source]¶
Bases:
Operator
Decrement a lower index.
- class modelparameters.sympy.simplify.hyperexpand.UnShiftA(ap, bq, i, z)[source]¶
Bases:
Operator
Decrement an upper index.
- class modelparameters.sympy.simplify.hyperexpand.UnShiftB(ap, bq, i, z)[source]¶
Bases:
Operator
Increment a lower index.
- modelparameters.sympy.simplify.hyperexpand.add_formulae(formulae)[source]¶
Create our knowledge base.
- modelparameters.sympy.simplify.hyperexpand.apply_operators(obj, ops, op)[source]¶
Apply the list of operators
ops
to objectobj
, substitutingop
for the generator.
- modelparameters.sympy.simplify.hyperexpand.build_hypergeometric_formula(func)[source]¶
Create a formula object representing the hypergeometric function
func
.
- modelparameters.sympy.simplify.hyperexpand.devise_plan(target, origin, z)[source]¶
Devise a plan (consisting of shift and un-shift operators) to be applied to the hypergeometric function
target
to yieldorigin
. Returns a list of operators.>>> from .hyperexpand import devise_plan, Hyper_Function >>> from ..abc import z
Nothing to do:
>>> devise_plan(Hyper_Function((1, 2), ()), Hyper_Function((1, 2), ()), z) [] >>> devise_plan(Hyper_Function((), (1, 2)), Hyper_Function((), (1, 2)), z) []
Very simple plans:
>>> devise_plan(Hyper_Function((2,), ()), Hyper_Function((1,), ()), z) [<Increment upper 1.>] >>> devise_plan(Hyper_Function((), (2,)), Hyper_Function((), (1,)), z) [<Increment lower index #0 of [], [1].>]
Several buckets:
>>> from .. import S >>> devise_plan(Hyper_Function((1, S.Half), ()), ... Hyper_Function((2, S('3/2')), ()), z) [<Decrement upper index #0 of [3/2, 1], [].>, <Decrement upper index #0 of [2, 3/2], [].>]
A slightly more complicated plan:
>>> devise_plan(Hyper_Function((1, 3), ()), Hyper_Function((2, 2), ()), z) [<Increment upper 2.>, <Decrement upper index #0 of [2, 2], [].>]
Another more complicated plan: (note that the ap have to be shifted first!)
>>> devise_plan(Hyper_Function((1, -1), (2,)), Hyper_Function((3, -2), (4,)), z) [<Decrement lower 3.>, <Decrement lower 4.>, <Decrement upper index #1 of [-1, 2], [4].>, <Decrement upper index #1 of [-1, 3], [4].>, <Increment upper -2.>]
- modelparameters.sympy.simplify.hyperexpand.devise_plan_meijer(fro, to, z)[source]¶
Find operators to convert G-function
fro
into G-functionto
.It is assumed that fro and to have the same signatures, and that in fact any corresponding pair of parameters differs by integers, and a direct path is possible. I.e. if there are parameters a1 b1 c1 and a2 b2 c2 it is assumed that a1 can be shifted to a2, etc. The only thing this routine determines is the order of shifts to apply, nothing clever will be tried. It is also assumed that fro is suitable.
>>> from .hyperexpand import (devise_plan_meijer, ... G_Function) >>> from ..abc import z
Empty plan:
>>> devise_plan_meijer(G_Function([1], [2], [3], [4]), ... G_Function([1], [2], [3], [4]), z) []
Very simple plans:
>>> devise_plan_meijer(G_Function([0], [], [], []), ... G_Function([1], [], [], []), z) [<Increment upper a index #0 of [0], [], [], [].>] >>> devise_plan_meijer(G_Function([0], [], [], []), ... G_Function([-1], [], [], []), z) [<Decrement upper a=0.>] >>> devise_plan_meijer(G_Function([], [1], [], []), ... G_Function([], [2], [], []), z) [<Increment lower a index #0 of [], [1], [], [].>]
Slightly more complicated plans:
>>> devise_plan_meijer(G_Function([0], [], [], []), ... G_Function([2], [], [], []), z) [<Increment upper a index #0 of [1], [], [], [].>, <Increment upper a index #0 of [0], [], [], [].>] >>> devise_plan_meijer(G_Function([0], [], [0], []), ... G_Function([-1], [], [1], []), z) [<Increment upper b=0.>, <Decrement upper a=0.>]
Order matters:
>>> devise_plan_meijer(G_Function([0], [], [0], []), ... G_Function([1], [], [1], []), z) [<Increment upper a index #0 of [0], [], [1], [].>, <Increment upper b=0.>]
- modelparameters.sympy.simplify.hyperexpand.hyperexpand(f, allow_hyper=False, rewrite='default', place=None)[source]¶
Expand hypergeometric functions. If allow_hyper is True, allow partial simplification (that is a result different from input, but still containing hypergeometric functions).
If a G-function has expansions both at zero and at infinity,
place
can be set to0
orzoo
to indicate the preferred choice.Examples
>>> from .hyperexpand import hyperexpand >>> from ..functions import hyper >>> from ..abc import z >>> hyperexpand(hyper([], [], z)) exp(z)
Non-hyperegeometric parts of the expression and hypergeometric expressions that are not recognised are left unchanged:
>>> hyperexpand(1 + hyper([1, 1, 1], [], z)) hyper((1, 1, 1), (), z) + 1
- modelparameters.sympy.simplify.hyperexpand.hyperexpand_special(ap, bq, z)[source]¶
Try to find a closed-form expression for hyper(ap, bq, z), where
z
is supposed to be a “special” value, e.g. 1.This function tries various of the classical summation formulae (Gauss, Saalschuetz, etc).
- modelparameters.sympy.simplify.hyperexpand.make_derivative_operator(M, z)[source]¶
Create a derivative operator, to be passed to Operator.apply.
- modelparameters.sympy.simplify.hyperexpand.make_simp(z)[source]¶
Create a function that simplifies rational functions in
z
.
- modelparameters.sympy.simplify.hyperexpand.reduce_order(func)[source]¶
Given the hypergeometric function
func
, find a sequence of operators to reduces order as much as possible.Return (newfunc, [operators]), where applying the operators to the hypergeometric function newfunc yields func.
Examples
>>> from .hyperexpand import reduce_order, Hyper_Function >>> reduce_order(Hyper_Function((1, 2), (3, 4))) (Hyper_Function((1, 2), (3, 4)), []) >>> reduce_order(Hyper_Function((1,), (1,))) (Hyper_Function((), ()), [<Reduce order by cancelling upper 1 with lower 1.>]) >>> reduce_order(Hyper_Function((2, 4), (3, 3))) (Hyper_Function((2,), (3,)), [<Reduce order by cancelling upper 4 with lower 3.>])
- modelparameters.sympy.simplify.hyperexpand.reduce_order_meijer(func)[source]¶
Given the Meijer G function parameters,
func
, find a sequence of operators that reduces order as much as possible.Return newfunc, [operators].
Examples
>>> from .hyperexpand import (reduce_order_meijer, ... G_Function) >>> reduce_order_meijer(G_Function([3, 4], [5, 6], [3, 4], [1, 2]))[0] G_Function((4, 3), (5, 6), (3, 4), (2, 1)) >>> reduce_order_meijer(G_Function([3, 4], [5, 6], [3, 4], [1, 8]))[0] G_Function((3,), (5, 6), (3, 4), (1,)) >>> reduce_order_meijer(G_Function([3, 4], [5, 6], [7, 5], [1, 5]))[0] G_Function((3,), (), (), (1,)) >>> reduce_order_meijer(G_Function([3, 4], [5, 6], [7, 5], [5, 3]))[0] G_Function((), (), (), ())
- modelparameters.sympy.simplify.hyperexpand.try_lerchphi(func)[source]¶
Try to find an expression for Hyper_Function
func
in terms of Lerch Transcendents.Return None if no such expression can be found.
modelparameters.sympy.simplify.hyperexpand_doc module¶
modelparameters.sympy.simplify.powsimp module¶
- modelparameters.sympy.simplify.powsimp.powdenest(eq, force=False, polar=False)[source]¶
Collect exponents on powers as assumptions allow.
- Given
(bb**be)**e
, this can be simplified as follows: if
bb
is positive, ore
is an integer, or|be| < 1
then this simplifies tobb**(be*e)
Given a product of powers raised to a power,
(bb1**be1 * bb2**be2...)**e
, simplification can be done as follows:if e is positive, the gcd of all bei can be joined with e;
all non-negative bb can be separated from those that are negative and their gcd can be joined with e; autosimplification already handles this separation.
integer factors from powers that have integers in the denominator of the exponent can be removed from any term and the gcd of such integers can be joined with e
Setting
force
to True will make symbols that are not explicitly negative behave as though they are positive, resulting in more denesting.Setting
polar
to True will do simplifications on the Riemann surface of the logarithm, also resulting in more denestings.When there are sums of logs in exp() then a product of powers may be obtained e.g.
exp(3*(log(a) + 2*log(b)))
- >a**3*b**6
.Examples
>>> from ..abc import a, b, x, y, z >>> from .. import Symbol, exp, log, sqrt, symbols, powdenest
>>> powdenest((x**(2*a/3))**(3*x)) (x**(2*a/3))**(3*x) >>> powdenest(exp(3*x*log(2))) 2**(3*x)
Assumptions may prevent expansion:
>>> powdenest(sqrt(x**2)) sqrt(x**2)
>>> p = symbols('p', positive=True) >>> powdenest(sqrt(p**2)) p
No other expansion is done.
>>> i, j = symbols('i,j', integer=True) >>> powdenest((x**x)**(i + j)) # -X-> (x**x)**i*(x**x)**j x**(x*(i + j))
But exp() will be denested by moving all non-log terms outside of the function; this may result in the collapsing of the exp to a power with a different base:
>>> powdenest(exp(3*y*log(x))) x**(3*y) >>> powdenest(exp(y*(log(a) + log(b)))) (a*b)**y >>> powdenest(exp(3*(log(a) + log(b)))) a**3*b**3
If assumptions allow, symbols can also be moved to the outermost exponent:
>>> i = Symbol('i', integer=True) >>> powdenest(((x**(2*i))**(3*y))**x) ((x**(2*i))**(3*y))**x >>> powdenest(((x**(2*i))**(3*y))**x, force=True) x**(6*i*x*y)
>>> powdenest(((x**(2*a/3))**(3*y/i))**x) ((x**(2*a/3))**(3*y/i))**x >>> powdenest((x**(2*i)*y**(4*i))**z, force=True) (x*y**2)**(2*i*z)
>>> n = Symbol('n', negative=True)
>>> powdenest((x**i)**y, force=True) x**(i*y) >>> powdenest((n**i)**x, force=True) (n**i)**x
- Given
- modelparameters.sympy.simplify.powsimp.powsimp(expr, deep=False, combine='all', force=False, measure=<function count_ops>)[source]¶
reduces expression by combining powers with similar bases and exponents.
Notes
If deep is True then powsimp() will also simplify arguments of functions. By default deep is set to False.
If force is True then bases will be combined without checking for assumptions, e.g. sqrt(x)*sqrt(y) -> sqrt(x*y) which is not true if x and y are both negative.
You can make powsimp() only combine bases or only combine exponents by changing combine=’base’ or combine=’exp’. By default, combine=’all’, which does both. combine=’base’ will only combine:
a a a 2x x x * y => (x*y) as well as things like 2 => 4
and combine=’exp’ will only combine
a b (a + b) x * x => x
combine=’exp’ will strictly only combine exponents in the way that used to be automatic. Also use deep=True if you need the old behavior.
When combine=’all’, ‘exp’ is evaluated first. Consider the first example below for when there could be an ambiguity relating to this. This is done so things like the second example can be completely combined. If you want ‘base’ combined first, do something like powsimp(powsimp(expr, combine=’base’), combine=’exp’).
Examples
>>> from .. import powsimp, exp, log, symbols >>> from ..abc import x, y, z, n >>> powsimp(x**y*x**z*y**z, combine='all') x**(y + z)*y**z >>> powsimp(x**y*x**z*y**z, combine='exp') x**(y + z)*y**z >>> powsimp(x**y*x**z*y**z, combine='base', force=True) x**y*(x*y)**z
>>> powsimp(x**z*x**y*n**z*n**y, combine='all', force=True) (n*x)**(y + z) >>> powsimp(x**z*x**y*n**z*n**y, combine='exp') n**(y + z)*x**(y + z) >>> powsimp(x**z*x**y*n**z*n**y, combine='base', force=True) (n*x)**y*(n*x)**z
>>> x, y = symbols('x y', positive=True) >>> powsimp(log(exp(x)*exp(y))) log(exp(x)*exp(y)) >>> powsimp(log(exp(x)*exp(y)), deep=True) x + y
Radicals with Mul bases will be combined if combine=’exp’
>>> from .. import sqrt, Mul >>> x, y = symbols('x y')
Two radicals are automatically joined through Mul:
>>> a=sqrt(x*sqrt(y)) >>> a*a**3 == a**4 True
But if an integer power of that radical has been autoexpanded then Mul does not join the resulting factors:
>>> a**4 # auto expands to a Mul, no longer a Pow x**2*y >>> _*a # so Mul doesn't combine them x**2*y*sqrt(x*sqrt(y)) >>> powsimp(_) # but powsimp will (x*sqrt(y))**(5/2) >>> powsimp(x*y*a) # but won't when doing so would violate assumptions x*y*sqrt(x*sqrt(y))
modelparameters.sympy.simplify.radsimp module¶
- modelparameters.sympy.simplify.radsimp.collect(expr, syms, func=None, evaluate=None, exact=False, distribute_order_term=True)[source]¶
Collect additive terms of an expression.
This function collects additive terms of an expression with respect to a list of expression up to powers with rational exponents. By the term symbol here are meant arbitrary expressions, which can contain powers, products, sums etc. In other words symbol is a pattern which will be searched for in the expression’s terms.
The input expression is not expanded by
collect()
, so user is expected to provide an expression is an appropriate form. This makescollect()
more predictable as there is no magic happening behind the scenes. However, it is important to note, that powers of products are converted to products of powers using theexpand_power_base()
function.There are two possible types of output. First, if
evaluate
flag is set, this function will return an expression with collected terms or else it will return a dictionary with expressions up to rational powers as keys and collected coefficients as values.Examples
>>> from .. import S, collect, expand, factor, Wild >>> from ..abc import a, b, c, x, y, z
This function can collect symbolic coefficients in polynomials or rational expressions. It will manage to find all integer or rational powers of collection variable:
>>> collect(a*x**2 + b*x**2 + a*x - b*x + c, x) c + x**2*(a + b) + x*(a - b)
The same result can be achieved in dictionary form:
>>> d = collect(a*x**2 + b*x**2 + a*x - b*x + c, x, evaluate=False) >>> d[x**2] a + b >>> d[x] a - b >>> d[S.One] c
You can also work with multivariate polynomials. However, remember that this function is greedy so it will care only about a single symbol at time, in specification order:
>>> collect(x**2 + y*x**2 + x*y + y + a*y, [x, y]) x**2*(y + 1) + x*y + y*(a + 1)
Also more complicated expressions can be used as patterns:
>>> from .. import sin, log >>> collect(a*sin(2*x) + b*sin(2*x), sin(2*x)) (a + b)*sin(2*x) >>> collect(a*x*log(x) + b*(x*log(x)), x*log(x)) x*(a + b)*log(x)
You can use wildcards in the pattern:
>>> w = Wild('w1') >>> collect(a*x**y - b*x**y, w**y) x**y*(a - b)
It is also possible to work with symbolic powers, although it has more complicated behavior, because in this case power’s base and symbolic part of the exponent are treated as a single symbol:
>>> collect(a*x**c + b*x**c, x) a*x**c + b*x**c >>> collect(a*x**c + b*x**c, x**c) x**c*(a + b)
However if you incorporate rationals to the exponents, then you will get well known behavior:
>>> collect(a*x**(2*c) + b*x**(2*c), x**c) x**(2*c)*(a + b)
Note also that all previously stated facts about
collect()
function apply to the exponential function, so you can get:>>> from .. import exp >>> collect(a*exp(2*x) + b*exp(2*x), exp(x)) (a + b)*exp(2*x)
If you are interested only in collecting specific powers of some symbols then set
exact
flag in arguments:>>> collect(a*x**7 + b*x**7, x, exact=True) a*x**7 + b*x**7 >>> collect(a*x**7 + b*x**7, x**7, exact=True) x**7*(a + b)
You can also apply this function to differential equations, where derivatives of arbitrary order can be collected. Note that if you collect with respect to a function or a derivative of a function, all derivatives of that function will also be collected. Use
exact=True
to prevent this from happening:>>> from .. import Derivative as D, collect, Function >>> f = Function('f') (x) >>> collect(a*D(f,x) + b*D(f,x), D(f,x)) (a + b)*Derivative(f(x), x) >>> collect(a*D(D(f,x),x) + b*D(D(f,x),x), f) (a + b)*Derivative(f(x), x, x) >>> collect(a*D(D(f,x),x) + b*D(D(f,x),x), D(f,x), exact=True) a*Derivative(f(x), x, x) + b*Derivative(f(x), x, x) >>> collect(a*D(f,x) + b*D(f,x) + a*f + b*f, f) (a + b)*f(x) + (a + b)*Derivative(f(x), x)
Or you can even match both derivative order and exponent at the same time:
>>> collect(a*D(D(f,x),x)**2 + b*D(D(f,x),x)**2, D(f,x)) (a + b)*Derivative(f(x), x, x)**2
Finally, you can apply a function to each of the collected coefficients. For example you can factorize symbolic coefficients of polynomial:
>>> f = expand((x + a + 1)**3) >>> collect(f, x, factor) x**3 + 3*x**2*(a + 1) + 3*x*(a + 1)**2 + (a + 1)**3
Note
Arguments are expected to be in expanded form, so you might have to call
expand()
prior to calling this function.See also
- modelparameters.sympy.simplify.radsimp.collect_const(expr, *vars, **kwargs)[source]¶
A non-greedy collection of terms with similar number coefficients in an Add expr. If
vars
is given then only those constants will be targeted. Although any Number can also be targeted, if this is not desired setNumbers=False
and no Float or Rational will be collected.Examples
>>> from .. import sqrt >>> from ..abc import a, s, x, y, z >>> from .radsimp import collect_const >>> collect_const(sqrt(3) + sqrt(3)*(1 + sqrt(2))) sqrt(3)*(sqrt(2) + 2) >>> collect_const(sqrt(3)*s + sqrt(7)*s + sqrt(3) + sqrt(7)) (sqrt(3) + sqrt(7))*(s + 1) >>> s = sqrt(2) + 2 >>> collect_const(sqrt(3)*s + sqrt(3) + sqrt(7)*s + sqrt(7)) (sqrt(2) + 3)*(sqrt(3) + sqrt(7)) >>> collect_const(sqrt(3)*s + sqrt(3) + sqrt(7)*s + sqrt(7), sqrt(3)) sqrt(7) + sqrt(3)*(sqrt(2) + 3) + sqrt(7)*(sqrt(2) + 2)
The collection is sign-sensitive, giving higher precedence to the unsigned values:
>>> collect_const(x - y - z) x - (y + z) >>> collect_const(-y - z) -(y + z) >>> collect_const(2*x - 2*y - 2*z, 2) 2*(x - y - z) >>> collect_const(2*x - 2*y - 2*z, -2) 2*x - 2*(y + z)
See also
- modelparameters.sympy.simplify.radsimp.collect_sqrt(expr, evaluate=None)[source]¶
Return expr with terms having common square roots collected together. If
evaluate
is False a count indicating the number of sqrt-containing terms will be returned and, if non-zero, the terms of the Add will be returned, else the expression itself will be returned as a single term. Ifevaluate
is True, the expression with any collected terms will be returned.Note: since I = sqrt(-1), it is collected, too.
Examples
>>> from .. import sqrt >>> from .radsimp import collect_sqrt >>> from ..abc import a, b
>>> r2, r3, r5 = [sqrt(i) for i in [2, 3, 5]] >>> collect_sqrt(a*r2 + b*r2) sqrt(2)*(a + b) >>> collect_sqrt(a*r2 + b*r2 + a*r3 + b*r3) sqrt(2)*(a + b) + sqrt(3)*(a + b) >>> collect_sqrt(a*r2 + b*r2 + a*r3 + b*r5) sqrt(3)*a + sqrt(5)*b + sqrt(2)*(a + b)
If evaluate is False then the arguments will be sorted and returned as a list and a count of the number of sqrt-containing terms will be returned:
>>> collect_sqrt(a*r2 + b*r2 + a*r3 + b*r5, evaluate=False) ((sqrt(3)*a, sqrt(5)*b, sqrt(2)*(a + b)), 3) >>> collect_sqrt(a*sqrt(2) + b, evaluate=False) ((b, sqrt(2)*a), 1) >>> collect_sqrt(a + b, evaluate=False) ((a + b,), 0)
See also
- modelparameters.sympy.simplify.radsimp.expand_denom(expr, **hints)¶
- modelparameters.sympy.simplify.radsimp.expand_fraction(expr, **hints)¶
- modelparameters.sympy.simplify.radsimp.expand_numer(expr, **hints)¶
- modelparameters.sympy.simplify.radsimp.fraction(expr, exact=False)[source]¶
Returns a pair with expression’s numerator and denominator. If the given expression is not a fraction then this function will return the tuple (expr, 1).
This function will not make any attempt to simplify nested fractions or to do any term rewriting at all.
If only one of the numerator/denominator pair is needed then use numer(expr) or denom(expr) functions respectively.
>>> from .. import fraction, Rational, Symbol >>> from ..abc import x, y
>>> fraction(x/y) (x, y) >>> fraction(x) (x, 1)
>>> fraction(1/y**2) (1, y**2)
>>> fraction(x*y/2) (x*y, 2) >>> fraction(Rational(1, 2)) (1, 2)
This function will also work fine with assumptions:
>>> k = Symbol('k', negative=True) >>> fraction(x * y**k) (x, y**(-k))
If we know nothing about sign of some exponent and ‘exact’ flag is unset, then structure this exponent’s structure will be analyzed and pretty fraction will be returned:
>>> from .. import exp, Mul >>> fraction(2*x**(-y)) (2, x**y)
>>> fraction(exp(-x)) (1, exp(x))
>>> fraction(exp(-x), exact=True) (exp(-x), 1)
The exact flag will also keep any unevaluated Muls from being evaluated:
>>> u = Mul(2, x + 1, evaluate=False) >>> fraction(u) (2*x + 2, 1) >>> fraction(u, exact=True) (2*(x + 1), 1)
- modelparameters.sympy.simplify.radsimp.rad_rationalize(num, den)[source]¶
Rationalize num/den by removing square roots in the denominator; num and den are sum of terms whose squares are rationals
Examples
>>> from .. import sqrt >>> from .radsimp import rad_rationalize >>> rad_rationalize(sqrt(3), 1 + sqrt(2)/3) (-sqrt(3) + sqrt(6)/3, -7/9)
- modelparameters.sympy.simplify.radsimp.radsimp(expr, symbolic=True, max_terms=4)[source]¶
Rationalize the denominator by removing square roots.
Note: the expression returned from radsimp must be used with caution since if the denominator contains symbols, it will be possible to make substitutions that violate the assumptions of the simplification process: that for a denominator matching a + b*sqrt(c), a != +/-b*sqrt(c). (If there are no symbols, this assumptions is made valid by collecting terms of sqrt(c) so the match variable
a
does not containsqrt(c)
.) If you do not want the simplification to occur for symbolic denominators, setsymbolic
to False.If there are more than
max_terms
radical terms then the expression is returned unchanged.Examples
>>> from .. import radsimp, sqrt, Symbol, denom, pprint, I >>> from .. import factor_terms, fraction, signsimp >>> from .radsimp import collect_sqrt >>> from ..abc import a, b, c
>>> radsimp(1/(2 + sqrt(2))) (-sqrt(2) + 2)/2 >>> x,y = map(Symbol, 'xy') >>> e = ((2 + 2*sqrt(2))*x + (2 + sqrt(8))*y)/(2 + sqrt(2)) >>> radsimp(e) sqrt(2)*(x + y)
No simplification beyond removal of the gcd is done. One might want to polish the result a little, however, by collecting square root terms:
>>> r2 = sqrt(2) >>> r5 = sqrt(5) >>> ans = radsimp(1/(y*r2 + x*r2 + a*r5 + b*r5)); pprint(ans) ___ ___ ___ ___ \/ 5 *a + \/ 5 *b - \/ 2 *x - \/ 2 *y ------------------------------------------ 2 2 2 2 5*a + 10*a*b + 5*b - 2*x - 4*x*y - 2*y
>>> n, d = fraction(ans) >>> pprint(factor_terms(signsimp(collect_sqrt(n))/d, radical=True)) ___ ___ \/ 5 *(a + b) - \/ 2 *(x + y) ------------------------------------------ 2 2 2 2 5*a + 10*a*b + 5*b - 2*x - 4*x*y - 2*y
If radicals in the denominator cannot be removed or there is no denominator, the original expression will be returned.
>>> radsimp(sqrt(2)*x + sqrt(2)) sqrt(2)*x + sqrt(2)
Results with symbols will not always be valid for all substitutions:
>>> eq = 1/(a + b*sqrt(c)) >>> eq.subs(a, b*sqrt(c)) 1/(2*b*sqrt(c)) >>> radsimp(eq).subs(a, b*sqrt(c)) nan
If symbolic=False, symbolic denominators will not be transformed (but numeric denominators will still be processed):
>>> radsimp(eq, symbolic=False) 1/(a + b*sqrt(c))
- modelparameters.sympy.simplify.radsimp.rcollect(expr, *vars)[source]¶
Recursively collect sums in an expression.
Examples
>>> from ..simplify import rcollect >>> from ..abc import x, y
>>> expr = (x**2*y + x*y + x + y)/(x + y)
>>> rcollect(expr, y) (x + y*(x**2 + x + 1))/(x + y)
See also
- modelparameters.sympy.simplify.radsimp.split_surds(expr)[source]¶
split an expression with terms whose squares are rationals into a sum of terms whose surds squared have gcd equal to g and a sum of terms with surds squared prime with g
Examples
>>> from .. import sqrt >>> from .radsimp import split_surds >>> split_surds(3*sqrt(3) + sqrt(5)/7 + sqrt(6) + sqrt(10) + sqrt(15)) (3, sqrt(2) + sqrt(5) + 3, sqrt(5)/7 + sqrt(10))
modelparameters.sympy.simplify.ratsimp module¶
- modelparameters.sympy.simplify.ratsimp.ratsimp(expr)[source]¶
Put an expression over a common denominator, cancel and reduce.
Examples
>>> from .. import ratsimp >>> from ..abc import x, y >>> ratsimp(1/x + 1/y) (x + y)/(x*y)
- modelparameters.sympy.simplify.ratsimp.ratsimpmodprime(expr, G, *gens, **args)[source]¶
Simplifies a rational expression
expr
modulo the prime ideal generated byG
.G
should be a Groebner basis of the ideal.>>> from .ratsimp import ratsimpmodprime >>> from ..abc import x, y >>> eq = (x + y**5 + y)/(x - y) >>> ratsimpmodprime(eq, [x*y**5 - x - y], x, y, order='lex') (x**2 + x*y + x + y)/(x**2 - x*y)
If
polynomial
is False, the algorithm computes a rational simplification which minimizes the sum of the total degrees of the numerator and the denominator.If
polynomial
is True, this function just brings numerator and denominator into a canonical form. This is much faster, but has potentially worse results.References
M. Monagan, R. Pearce, Rational Simplification Modulo a Polynomial Ideal, http://citeseer.ist.psu.edu/viewdoc/summary?doi=10.1.1.163.6984 (specifically, the second algorithm)
modelparameters.sympy.simplify.simplify module¶
- modelparameters.sympy.simplify.simplify.besselsimp(expr)[source]¶
Simplify bessel-type functions.
This routine tries to simplify bessel-type functions. Currently it only works on the Bessel J and I functions, however. It works by looking at all such functions in turn, and eliminating factors of “I” and “-1” (actually their polar equivalents) in front of the argument. Then, functions of half-integer order are rewritten using strigonometric functions and functions of integer order (> 1) are rewritten using functions of low order. Finally, if the expression was changed, compute factorization of the result with factor().
>>> from .. import besselj, besseli, besselsimp, polar_lift, I, S >>> from ..abc import z, nu >>> besselsimp(besselj(nu, z*polar_lift(-1))) exp(I*pi*nu)*besselj(nu, z) >>> besselsimp(besseli(nu, z*polar_lift(-I))) exp(-I*pi*nu/2)*besselj(nu, z) >>> besselsimp(besseli(S(-1)/2, z)) sqrt(2)*cosh(z)/(sqrt(pi)*sqrt(z)) >>> besselsimp(z*besseli(0, z) + z*(besseli(2, z))/2 + besseli(1, z)) 3*z*besseli(0, z)/2
- modelparameters.sympy.simplify.simplify.bottom_up(rv, F, atoms=False, nonbasic=False)[source]¶
Apply
F
to all expressions in an expression tree from the bottom up. Ifatoms
is True, applyF
even if there are no args; ifnonbasic
is True, try to applyF
to non-Basic objects.
- modelparameters.sympy.simplify.simplify.clear_coefficients(expr, rhs=0)[source]¶
Return p, r where p is the expression obtained when Rational additive and multiplicative coefficients of expr have been stripped away in a naive fashion (i.e. without simplification). The operations needed to remove the coefficients will be applied to rhs and returned as r.
Examples
>>> from .simplify import clear_coefficients >>> from ..abc import x, y >>> from .. import Dummy >>> expr = 4*y*(6*x + 3) >>> clear_coefficients(expr - 2) (y*(2*x + 1), 1/6)
When solving 2 or more expressions like expr = a, expr = b, etc…, it is advantageous to provide a Dummy symbol for rhs and simply replace it with a, b, etc… in r.
>>> rhs = Dummy('rhs') >>> clear_coefficients(expr, rhs) (y*(2*x + 1), _rhs/12) >>> _[1].subs(rhs, 2) 1/6
- modelparameters.sympy.simplify.simplify.factor_sum(self, limits=None, radical=False, clear=False, fraction=False, sign=True)[source]¶
Helper function for Sum simplification
if limits is specified, “self” is the inner part of a sum
Returns the sum with constant factors brought outside
- modelparameters.sympy.simplify.simplify.hypersimilar(f, g, k)[source]¶
Returns True if ‘f’ and ‘g’ are hyper-similar.
Similarity in hypergeometric sense means that a quotient of f(k) and g(k) is a rational function in k. This procedure is useful in solving recurrence relations.
For more information see hypersimp().
- modelparameters.sympy.simplify.simplify.hypersimp(f, k)[source]¶
Given combinatorial term f(k) simplify its consecutive term ratio i.e. f(k+1)/f(k). The input term can be composed of functions and integer sequences which have equivalent representation in terms of gamma special function.
The algorithm performs three basic steps:
Rewrite all functions in terms of gamma, if possible.
Rewrite all occurrences of gamma in terms of products of gamma and rising factorial with integer, absolute constant exponent.
Perform simplification of nested fractions, powers and if the resulting expression is a quotient of polynomials, reduce their total degree.
If f(k) is hypergeometric then as result we arrive with a quotient of polynomials of minimal degree. Otherwise None is returned.
For more information on the implemented algorithm refer to:
W. Koepf, Algorithms for m-fold Hypergeometric Summation, Journal of Symbolic Computation (1995) 20, 399-417
- modelparameters.sympy.simplify.simplify.logcombine(expr, force=False)[source]¶
Takes logarithms and combines them using the following rules:
log(x) + log(y) == log(x*y) if both are not negative
a*log(x) == log(x**a) if x is positive and a is real
If
force
is True then the assumptions above will be assumed to hold if there is no assumption already in place on a quantity. For example, ifa
is imaginary or the argument negative, force will not perform a combination but ifa
is a symbol with no assumptions the change will take place.Examples
>>> from .. import Symbol, symbols, log, logcombine, I >>> from ..abc import a, x, y, z >>> logcombine(a*log(x) + log(y) - log(z)) a*log(x) + log(y) - log(z) >>> logcombine(a*log(x) + log(y) - log(z), force=True) log(x**a*y/z) >>> x,y,z = symbols('x,y,z', positive=True) >>> a = Symbol('a', real=True) >>> logcombine(a*log(x) + log(y) - log(z)) log(x**a*y/z)
The transformation is limited to factors and/or terms that contain logs, so the result depends on the initial state of expansion:
>>> eq = (2 + 3*I)*log(x) >>> logcombine(eq, force=True) == eq True >>> logcombine(eq.expand(), force=True) log(x**2) + I*log(x**3)
See also
posify
replace all symbols with symbols having positive assumptions
- modelparameters.sympy.simplify.simplify.nsimplify(expr, constants=(), tolerance=None, full=False, rational=None, rational_conversion='base10')[source]¶
Find a simple representation for a number or, if there are free symbols or if rational=True, then replace Floats with their Rational equivalents. If no change is made and rational is not False then Floats will at least be converted to Rationals.
For numerical expressions, a simple formula that numerically matches the given numerical expression is sought (and the input should be possible to evalf to a precision of at least 30 digits).
Optionally, a list of (rationally independent) constants to include in the formula may be given.
A lower tolerance may be set to find less exact matches. If no tolerance is given then the least precise value will set the tolerance (e.g. Floats default to 15 digits of precision, so would be tolerance=10**-15).
With full=True, a more extensive search is performed (this is useful to find simpler numbers when the tolerance is set low).
When converting to rational, if rational_conversion=’base10’ (the default), then convert floats to rationals using their base-10 (string) representation. When rational_conversion=’exact’ it uses the exact, base-2 representation.
Examples
>>> from .. import nsimplify, sqrt, GoldenRatio, exp, I, exp, pi >>> nsimplify(4/(1+sqrt(5)), [GoldenRatio]) -2 + 2*GoldenRatio >>> nsimplify((1/(exp(3*pi*I/5)+1))) 1/2 - I*sqrt(sqrt(5)/10 + 1/4) >>> nsimplify(I**I, [pi]) exp(-pi/2) >>> nsimplify(pi, tolerance=0.01) 22/7
>>> nsimplify(0.333333333333333, rational=True, rational_conversion='exact') 6004799503160655/18014398509481984 >>> nsimplify(0.333333333333333, rational=True) 1/3
See also
sympy.core.function.nfloat
- modelparameters.sympy.simplify.simplify.nthroot(expr, n, max_len=4, prec=15)[source]¶
compute a real nth-root of a sum of surds
- Parameters:
expr (sum of surds) –
n (integer) –
max_len (maximum number of surds passed as constants to
nsimplify
) –Algorithm –
========= –
a (First nsimplify is used to get a candidate root; if it is not) –
its (root the minimal polynomial is computed; the answer is one of) –
roots. –
Examples
>>> from .simplify import nthroot >>> from .. import Rational, sqrt >>> nthroot(90 + 34*sqrt(7), 3) sqrt(7) + 3
- modelparameters.sympy.simplify.simplify.posify(eq)[source]¶
Return eq (with generic symbols made positive) and a dictionary containing the mapping between the old and new symbols.
Any symbol that has positive=None will be replaced with a positive dummy symbol having the same name. This replacement will allow more symbolic processing of expressions, especially those involving powers and logarithms.
A dictionary that can be sent to subs to restore eq to its original symbols is also returned.
>>> from .. import posify, Symbol, log, solve >>> from ..abc import x >>> posify(x + Symbol('p', positive=True) + Symbol('n', negative=True)) (_x + n + p, {_x: x})
>>> eq = 1/x >>> log(eq).expand() log(1/x) >>> log(posify(eq)[0]).expand() -log(_x) >>> p, rep = posify(eq) >>> log(p).expand().subs(rep) -log(x)
It is possible to apply the same transformations to an iterable of expressions:
>>> eq = x**2 - 4 >>> solve(eq, x) [-2, 2] >>> eq_x, reps = posify([eq, x]); eq_x [_x**2 - 4, _x] >>> solve(*eq_x) [2]
- modelparameters.sympy.simplify.simplify.product_mul(self, other, method=0)[source]¶
Helper function for Product simplification
- modelparameters.sympy.simplify.simplify.product_simplify(s)[source]¶
Main function for Product simplification
- modelparameters.sympy.simplify.simplify.separatevars(expr, symbols=[], dict=False, force=False)[source]¶
Separates variables in an expression, if possible. By default, it separates with respect to all symbols in an expression and collects constant coefficients that are independent of symbols.
If dict=True then the separated terms will be returned in a dictionary keyed to their corresponding symbols. By default, all symbols in the expression will appear as keys; if symbols are provided, then all those symbols will be used as keys, and any terms in the expression containing other symbols or non-symbols will be returned keyed to the string ‘coeff’. (Passing None for symbols will return the expression in a dictionary keyed to ‘coeff’.)
If force=True, then bases of powers will be separated regardless of assumptions on the symbols involved.
Notes
The order of the factors is determined by Mul, so that the separated expressions may not necessarily be grouped together.
Although factoring is necessary to separate variables in some expressions, it is not necessary in all cases, so one should not count on the returned factors being factored.
Examples
>>> from ..abc import x, y, z, alpha >>> from .. import separatevars, sin >>> separatevars((x*y)**y) (x*y)**y >>> separatevars((x*y)**y, force=True) x**y*y**y
>>> e = 2*x**2*z*sin(y)+2*z*x**2 >>> separatevars(e) 2*x**2*z*(sin(y) + 1) >>> separatevars(e, symbols=(x, y), dict=True) {'coeff': 2*z, x: x**2, y: sin(y) + 1} >>> separatevars(e, [x, y, alpha], dict=True) {'coeff': 2*z, alpha: 1, x: x**2, y: sin(y) + 1}
If the expression is not really separable, or is only partially separable, separatevars will do the best it can to separate it by using factoring.
>>> separatevars(x + x*y - 3*x**2) -x*(3*x - y - 1)
If the expression is not separable then expr is returned unchanged or (if dict=True) then None is returned.
>>> eq = 2*x + y*sin(x) >>> separatevars(eq) == eq True >>> separatevars(2*x + y*sin(x), symbols=(x, y), dict=True) == None True
- modelparameters.sympy.simplify.simplify.signsimp(expr, evaluate=None)[source]¶
Make all Add sub-expressions canonical wrt sign.
If an Add subexpression,
a
, can have a sign extracted, as determined by could_extract_minus_sign, it is replaced with Mul(-1, a, evaluate=False). This allows signs to be extracted from powers and products.Examples
>>> from .. import signsimp, exp, symbols >>> from ..abc import x, y >>> i = symbols('i', odd=True) >>> n = -1 + 1/x >>> n/x/(-n)**2 - 1/n/x (-1 + 1/x)/(x*(1 - 1/x)**2) - 1/(x*(-1 + 1/x)) >>> signsimp(_) 0 >>> x*n + x*-n x*(-1 + 1/x) + x*(1 - 1/x) >>> signsimp(_) 0
Since powers automatically handle leading signs
>>> (-2)**i -2**i
signsimp can be used to put the base of a power with an integer exponent into canonical form:
>>> n**i (-1 + 1/x)**i
By default, signsimp doesn’t leave behind any hollow simplification: if making an Add canonical wrt sign didn’t change the expression, the original Add is restored. If this is not desired then the keyword
evaluate
can be set to False:>>> e = exp(y - x) >>> signsimp(e) == e True >>> signsimp(e, evaluate=False) exp(-(x - y))
- modelparameters.sympy.simplify.simplify.simplify(expr, ratio=1.7, measure=<function count_ops>, fu=False)[source]¶
Simplifies the given expression.
Simplification is not a well defined term and the exact strategies this function tries can change in the future versions of SymPy. If your algorithm relies on “simplification” (whatever it is), try to determine what you need exactly - is it powsimp()?, radsimp()?, together()?, logcombine()?, or something else? And use this particular function directly, because those are well defined and thus your algorithm will be robust.
Nonetheless, especially for interactive use, or when you don’t know anything about the structure of the expression, simplify() tries to apply intelligent heuristics to make the input expression “simpler”. For example:
>>> from .. import simplify, cos, sin >>> from ..abc import x, y >>> a = (x + x**2)/(x*sin(y)**2 + x*cos(y)**2) >>> a (x**2 + x)/(x*sin(y)**2 + x*cos(y)**2) >>> simplify(a) x + 1
Note that we could have obtained the same result by using specific simplification functions:
>>> from .. import trigsimp, cancel >>> trigsimp(a) (x**2 + x)/x >>> cancel(_) x + 1
In some cases, applying
simplify()
may actually result in some more complicated expression. The defaultratio=1.7
prevents more extreme cases: if (result length)/(input length) > ratio, then input is returned unmodified. Themeasure
parameter lets you specify the function used to determine how complex an expression is. The function should take a single argument as an expression and return a number such that if expressiona
is more complex than expressionb
, thenmeasure(a) > measure(b)
. The default measure function iscount_ops()
, which returns the total number of operations in the expression.For example, if
ratio=1
,simplify
output can’t be longer than input.>>> from .. import sqrt, simplify, count_ops, oo >>> root = 1/(sqrt(2)+3)
Since
simplify(root)
would result in a slightly longer expression, root is returned unchanged instead:>>> simplify(root, ratio=1) == root True
If
ratio=oo
, simplify will be applied anyway:>>> count_ops(simplify(root, ratio=oo)) > count_ops(root) True
Note that the shortest expression is not necessary the simplest, so setting
ratio
to 1 may not be a good idea. Heuristically, the default valueratio=1.7
seems like a reasonable choice.You can easily define your own measure function based on what you feel should represent the “size” or “complexity” of the input expression. Note that some choices, such as
lambda expr: len(str(expr))
may appear to be good metrics, but have other problems (in this case, the measure function may slow down simplify too much for very large expressions). If you don’t know what a good metric would be, the default,count_ops
, is a good one.For example:
>>> from .. import symbols, log >>> a, b = symbols('a b', positive=True) >>> g = log(a) + log(b) + log(a)*log(1/b) >>> h = simplify(g) >>> h log(a*b**(-log(a) + 1)) >>> count_ops(g) 8 >>> count_ops(h) 5
So you can see that
h
is simpler thang
using the count_ops metric. However, we may not like howsimplify
(in this case, usinglogcombine
) has created theb**(log(1/a) + 1)
term. A simple way to reduce this would be to give more weight to powers as operations incount_ops
. We can do this by using thevisual=True
option:>>> print(count_ops(g, visual=True)) 2*ADD + DIV + 4*LOG + MUL >>> print(count_ops(h, visual=True)) 2*LOG + MUL + POW + SUB
>>> from .. import Symbol, S >>> def my_measure(expr): ... POW = Symbol('POW') ... # Discourage powers by giving POW a weight of 10 ... count = count_ops(expr, visual=True).subs(POW, 10) ... # Every other operation gets a weight of 1 (the default) ... count = count.replace(Symbol, type(S.One)) ... return count >>> my_measure(g) 8 >>> my_measure(h) 14 >>> 15./8 > 1.7 # 1.7 is the default ratio True >>> simplify(g, measure=my_measure) -log(a)*log(b) + log(a) + log(b)
Note that because
simplify()
internally tries many different simplification strategies and then compares them using the measure function, we get a completely different result that is still different from the input expression by doing this.
- modelparameters.sympy.simplify.simplify.sum_add(self, other, method=0)[source]¶
Helper function for Sum simplification
modelparameters.sympy.simplify.sqrtdenest module¶
- exception modelparameters.sympy.simplify.sqrtdenest.SqrtdenestStopIteration[source]¶
Bases:
StopIteration
- modelparameters.sympy.simplify.sqrtdenest.is_algebraic(p)[source]¶
Return True if p is comprised of only Rationals or square roots of Rationals and algebraic operations.
Examples
>>> from ..functions.elementary.miscellaneous import sqrt >>> from .sqrtdenest import is_algebraic >>> from .. import cos >>> is_algebraic(sqrt(2)*(3/(sqrt(7) + sqrt(5)*sqrt(2)))) True >>> is_algebraic(sqrt(2)*(3/(sqrt(7) + sqrt(5)*cos(2)))) False
- modelparameters.sympy.simplify.sqrtdenest.is_sqrt(expr)[source]¶
Return True if expr is a sqrt, otherwise False.
- modelparameters.sympy.simplify.sqrtdenest.sqrt_biquadratic_denest(expr, a, b, r, d2)[source]¶
denest expr = sqrt(a + b*sqrt(r)) where a, b, r are linear combinations of square roots of positive rationals on the rationals (SQRR) and r > 0, b != 0, d2 = a**2 - b**2*r > 0
If it cannot denest it returns None.
ALGORITHM Search for a solution A of type SQRR of the biquadratic equation 4*A**4 - 4*a*A**2 + b**2*r = 0 (1) sqd = sqrt(a**2 - b**2*r) Choosing the sqrt to be positive, the possible solutions are A = sqrt(a/2 +/- sqd/2) Since a, b, r are SQRR, then a**2 - b**2*r is a SQRR, so if sqd can be denested, it is done by _sqrtdenest_rec, and the result is a SQRR. Similarly for A. Examples of solutions (in both cases a and sqd are positive):
Example of expr with solution sqrt(a/2 + sqd/2) but not solution sqrt(a/2 - sqd/2): expr = sqrt(-sqrt(15) - sqrt(2)*sqrt(-sqrt(5) + 5) - sqrt(3) + 8) a = -sqrt(15) - sqrt(3) + 8; sqd = -2*sqrt(5) - 2 + 4*sqrt(3)
Example of expr with solution sqrt(a/2 - sqd/2) but not solution sqrt(a/2 + sqd/2): w = 2 + r2 + r3 + (1 + r3)*sqrt(2 + r2 + 5*r3) expr = sqrt((w**2).expand()) a = 4*sqrt(6) + 8*sqrt(2) + 47 + 28*sqrt(3) sqd = 29 + 20*sqrt(3)
Define B = b/2*A; eq.(1) implies a = A**2 + B**2*r; then expr**2 = a + b*sqrt(r) = (A + B*sqrt(r))**2
Examples
>>> from .. import sqrt >>> from .sqrtdenest import _sqrt_match, sqrt_biquadratic_denest >>> z = sqrt((2*sqrt(2) + 4)*sqrt(2 + sqrt(2)) + 5*sqrt(2) + 8) >>> a, b, r = _sqrt_match(z**2) >>> d2 = a**2 - b**2*r >>> sqrt_biquadratic_denest(z, a, b, r, d2) sqrt(2) + sqrt(sqrt(2) + 2) + 2
- modelparameters.sympy.simplify.sqrtdenest.sqrt_depth(p)[source]¶
Return the maximum depth of any square root argument of p.
>>> from ..functions.elementary.miscellaneous import sqrt >>> from .sqrtdenest import sqrt_depth
Neither of these square roots contains any other square roots so the depth is 1:
>>> sqrt_depth(1 + sqrt(2)*(1 + sqrt(3))) 1
The sqrt(3) is contained within a square root so the depth is 2:
>>> sqrt_depth(1 + sqrt(2)*sqrt(1 + sqrt(3))) 2
- modelparameters.sympy.simplify.sqrtdenest.sqrtdenest(expr, max_iter=3)[source]¶
Denests sqrts in an expression that contain other square roots if possible, otherwise returns the expr unchanged. This is based on the algorithms of [1].
Examples
>>> from .sqrtdenest import sqrtdenest >>> from .. import sqrt >>> sqrtdenest(sqrt(5 + 2 * sqrt(6))) sqrt(2) + sqrt(3)
See also
sympy.solvers.solvers.unrad
References
[1] http://researcher.watson.ibm.com/researcher/files/us-fagin/symb85.pdf
[2] D. J. Jeffrey and A. D. Rich, ‘Symplifying Square Roots of Square Roots by Denesting’ (available at http://www.cybertester.com/data/denest.pdf)
modelparameters.sympy.simplify.traversaltools module¶
Tools for applying functions to specified parts of expressions.
- modelparameters.sympy.simplify.traversaltools.use(expr, func, level=0, args=(), kwargs={})[source]¶
Use
func
to transformexpr
at the given level.Examples
>>> from .. import use, expand >>> from ..abc import x, y
>>> f = (x + y)**2*x + 1
>>> use(f, expand, level=2) x*(x**2 + 2*x*y + y**2) + 1 >>> expand(f) x**3 + 2*x**2*y + x*y**2 + 1
modelparameters.sympy.simplify.trigsimp module¶
- modelparameters.sympy.simplify.trigsimp.exptrigsimp(expr, simplify=True)[source]¶
Simplifies exponential / trigonometric / hyperbolic functions. When
simplify
is True (default) the expression obtained after the simplification step will be then be passed through simplify to precondition it so the final transformations will be applied.Examples
>>> from .. import exptrigsimp, exp, cosh, sinh >>> from ..abc import z
>>> exptrigsimp(exp(z) + exp(-z)) 2*cosh(z) >>> exptrigsimp(cosh(z) - sinh(z)) exp(-z)
- modelparameters.sympy.simplify.trigsimp.futrig(e, **kwargs)[source]¶
Return simplified
e
using Fu-like transformations. This is not the “Fu” algorithm. This is called by default fromtrigsimp
. By default, hyperbolics subexpressions will be simplified, but this can be disabled by settinghyper=False
.Examples
>>> from .. import trigsimp, tan, sinh, tanh >>> from .trigsimp import futrig >>> from ..abc import x >>> trigsimp(1/tan(x)**2) tan(x)**(-2)
>>> futrig(sinh(x)/tanh(x)) cosh(x)
- modelparameters.sympy.simplify.trigsimp.trigsimp(expr, **opts)[source]¶
reduces expression by using known trig identities
Notes
method: - Determine the method to use. Valid choices are ‘matching’ (default), ‘groebner’, ‘combined’, and ‘fu’. If ‘matching’, simplify the expression recursively by targeting common patterns. If ‘groebner’, apply an experimental groebner basis algorithm. In this case further options are forwarded to
trigsimp_groebner
, please refer to its docstring. If ‘combined’, first run the groebner basis algorithm with small default parameters, then run the ‘matching’ algorithm. ‘fu’ runs the collection of trigonometric transformations described by Fu, et al. (see the fu docstring).Examples
>>> from .. import trigsimp, sin, cos, log >>> from ..abc import x, y >>> e = 2*sin(x)**2 + 2*cos(x)**2 >>> trigsimp(e) 2
Simplification occurs wherever trigonometric functions are located.
>>> trigsimp(log(e)) log(2)
Using method=”groebner” (or “combined”) might lead to greater simplification.
The old trigsimp routine can be accessed as with method ‘old’.
>>> from .. import coth, tanh >>> t = 3*tanh(x)**7 - 2/coth(x)**7 >>> trigsimp(t, method='old') == t True >>> trigsimp(t) tanh(x)**7
- modelparameters.sympy.simplify.trigsimp.trigsimp_groebner(expr, hints=[], quick=False, order='grlex', polynomial=False)[source]¶
Simplify trigonometric expressions using a groebner basis algorithm.
This routine takes a fraction involving trigonometric or hyperbolic expressions, and tries to simplify it. The primary metric is the total degree. Some attempts are made to choose the simplest possible expression of the minimal degree, but this is non-rigorous, and also very slow (see the
quick=True
option).If
polynomial
is set to True, instead of simplifying numerator and denominator together, this function just brings numerator and denominator into a canonical form. This is much faster, but has potentially worse results. However, if the input is a polynomial, then the result is guaranteed to be an equivalent polynomial of minimal degree.The most important option is hints. Its entries can be any of the following:
a natural number
a function
an iterable of the form (func, var1, var2, …)
anything else, interpreted as a generator
A number is used to indicate that the search space should be increased. A function is used to indicate that said function is likely to occur in a simplified expression. An iterable is used indicate that func(var1 + var2 + …) is likely to occur in a simplified . An additional generator also indicates that it is likely to occur. (See examples below).
This routine carries out various computationally intensive algorithms. The option
quick=True
can be used to suppress one particularly slow step (at the expense of potentially more complicated results, but never at the expense of increased total degree).Examples
>>> from ..abc import x, y >>> from .. import sin, tan, cos, sinh, cosh, tanh >>> from .trigsimp import trigsimp_groebner
Suppose you want to simplify
sin(x)*cos(x)
. Naively, nothing happens:>>> ex = sin(x)*cos(x) >>> trigsimp_groebner(ex) sin(x)*cos(x)
This is because
trigsimp_groebner
only looks for a simplification involving justsin(x)
andcos(x)
. You can tell it to also try2*x
by passinghints=[2]
:>>> trigsimp_groebner(ex, hints=[2]) sin(2*x)/2 >>> trigsimp_groebner(sin(x)**2 - cos(x)**2, hints=[2]) -cos(2*x)
Increasing the search space this way can quickly become expensive. A much faster way is to give a specific expression that is likely to occur:
>>> trigsimp_groebner(ex, hints=[sin(2*x)]) sin(2*x)/2
Hyperbolic expressions are similarly supported:
>>> trigsimp_groebner(sinh(2*x)/sinh(x)) 2*cosh(x)
Note how no hints had to be passed, since the expression already involved
2*x
.The tangent function is also supported. You can either pass
tan
in the hints, to indicate that than should be tried whenever cosine or sine are, or you can pass a specific generator:>>> trigsimp_groebner(sin(x)/cos(x), hints=[tan]) tan(x) >>> trigsimp_groebner(sinh(x)/cosh(x), hints=[tanh(x)]) tanh(x)
Finally, you can use the iterable form to suggest that angle sum formulae should be tried:
>>> ex = (tan(x) + tan(y))/(1 - tan(x)*tan(y)) >>> trigsimp_groebner(ex, hints=[(tan, x, y)]) tan(x + y)
- modelparameters.sympy.simplify.trigsimp.trigsimp_old(expr, **opts)[source]¶
reduces expression by using known trig identities
Notes
deep: - Apply trigsimp inside all objects with arguments
recursive: - Use common subexpression elimination (cse()) and apply trigsimp recursively (this is quite expensive if the expression is large)
method: - Determine the method to use. Valid choices are ‘matching’ (default), ‘groebner’, ‘combined’, ‘fu’ and ‘futrig’. If ‘matching’, simplify the expression recursively by pattern matching. If ‘groebner’, apply an experimental groebner basis algorithm. In this case further options are forwarded to
trigsimp_groebner
, please refer to its docstring. If ‘combined’, first run the groebner basis algorithm with small default parameters, then run the ‘matching’ algorithm. ‘fu’ runs the collection of trigonometric transformations described by Fu, et al. (see the fu docstring) while futrig runs a subset of Fu-transforms that mimic the behavior of trigsimp.compare: - show input and output from trigsimp and futrig when different, but returns the trigsimp value.
Examples
>>> from .. import trigsimp, sin, cos, log, cosh, sinh, tan, cot >>> from ..abc import x, y >>> e = 2*sin(x)**2 + 2*cos(x)**2 >>> trigsimp(e, old=True) 2 >>> trigsimp(log(e), old=True) log(2*sin(x)**2 + 2*cos(x)**2) >>> trigsimp(log(e), deep=True, old=True) log(2)
Using method=”groebner” (or “combined”) can sometimes lead to a lot more simplification:
>>> e = (-sin(x) + 1)/cos(x) + cos(x)/(-sin(x) + 1) >>> trigsimp(e, old=True) (-sin(x) + 1)/cos(x) + cos(x)/(-sin(x) + 1) >>> trigsimp(e, method="groebner", old=True) 2/cos(x)
>>> trigsimp(1/cot(x)**2, compare=True, old=True) futrig: tan(x)**2 cot(x)**(-2)
Module contents¶
The module helps converting SymPy expressions into shorter forms of them.
for example: the expression E**(pi*I) will be converted into -1 the expression (x+x)**2 will be converted into 4*x**2