How to obtain only rational and not floating point results using sympy - sympy

I consider following matrices:
M1 = Matrix([[1/7,2/7],[3/7,4/7]])
M2 = Matrix([[1,2],[3,4]])/7
which are evidently identical, but when I determine their determinant I obtain different results:
print(M1.det())
print(M2.det())
giving the following results:
-0.0408163265306122
-2/49
I would like the first result to be expressed as a rational and not as a floating point.

This is an example of one of the gochas and pitfalls from SymPy's documentation. My answer will basically reiterate what is said there. I highly recommend going through it.
When you type 1/7, the Python interpreter changes it into a float before SymPy has a chance to identify it as a rational number. In order for SymPy to evaluate it before Python does, you need to use some other method. You have already shown one of those other methods with M2: divide a SymPy object by 7 instead of a Python int by 7. Here are a few other ways:
from sympy import *
M = Matrix([[Rational(1, 7),Rational(2, 7)],[Rational(3, 7),Rational(4, 7)]]) # create a Rational object
print(det(M))
M = Matrix([[S(1)/7,S(2)/7],[S(3)/7,S(4)/7]]) # divide a SymPy Integer by 7
print(det(M))
M = Matrix([[S("1/7"),S("2/7")],[S("3/7"),S("4/7")]]) # let SymPy interpret it
print(det(M))
M = Matrix([[1,2],[3,4]])/7 # divide a SymPy Matrix by 7
print(det(M))
M = S("Matrix([[1/7,2/7],[3/7,4/7]])") # throw the whole thing into SymPy
print(det(M))
All of the above will give rational determinants. There are probably many more ways to make SymPy identify a rational number.

Related

sympy function compose - bizzare results

I'm trying to compose two functions and I get a bizzare result
'''
#!/usr/bin/python
from sympy import *
init_printing(use_unicode=True)
x= symbols('x')
f = x/(x+1);
g = x/(x+2);
print(compose(f,g))
This shows : x/((x + 1)*(x + 2))
Should be x/(2x+2)
I don't get it. Does anyone has an idea?
Thanks
Despite being available in the top-level sympy namespace under the plain name compose, sympy.compose doesn't actually do general function composition.
sympy.compose is actually sympy.polys.polytools.compose. It's actually a function for polynomial composition. When you try to compose x/(x+1) and x/(x+2), it ends up interpreting these inputs as multivariate polynomials in 3 variables, x, 1/(x+1), and 1/(x+2), and the results are total nonsense.

Sympy: Simplify small compound fraction with squares and roots

I have got the following situation (in Sympy 1.8):
from sympy import *
u = symbols('u') # not necessarily positive
term = sqrt(1/u**2)/sqrt(u**2)
The term renders as
How can I simplify this to 1/u**2, i.e. ?
I have tried many functions from https://docs.sympy.org/latest/tutorial/simplification.html, and some arguments listed in https://docs.sympy.org/latest/modules/simplify/simplify.html but could not get it to work.
The variable needs to be declared as real number:
u=symbols('u', real=True)
Then the term is auto-simplified.
(I suggested a corresponding Sympy documentation change.)

sympy separate fractions from variables

Using sympy how do I keep fractions separate from variables
Mul(Fraction(3,5), Pow(K, Integer(2)))
2
3⋅K
────
5
to
3 2
─ K
5
I know this simplified version is not too bad, but when i have really big equations, it gets messy
I'm not very familiar with pretty printing or LaTeX printing but I managed to come up with something. Put UnevaluatedExpr in each of the arguments of Mul:
from sympy import *
from fractions import Fraction
K = symbols("K")
expr1 = Mul(UnevaluatedExpr(Fraction(3,5)), UnevaluatedExpr(Pow(K, Integer(2))))
expr2 = Mul(UnevaluatedExpr(pi/5), UnevaluatedExpr(Pow(K, Integer(2))))
expr3 = ((UnevaluatedExpr(S(1)*3123456789/512345679) * UnevaluatedExpr(Pow(K, Integer(2)))))
pprint(expr1)
pprint(expr2)
pprint(expr3)
Produces:
2
3/5⋅K
π 2
─⋅K
5
1041152263 2
──────────⋅K
170781893
I couldn't find a way to make it print a stacked fraction for the slashed fraction 3/5. Longer fractions seem to work though. If you are printing in LaTeX however, the documentation suggests something like latex(expr1, fold_frac_powers=False) to correct this.
Too bad I couldn't find an elegant solution like putting init_printing(div_stack_symbols=False) at the top of the document.
To elaborate on Maelstrom's Answer, you need to do 2 things to make this work like you want:
Create the separate fraction you want as its own expression.
Prevent the numerator or denominator from being modified when the expression is combined with other expressions.
What Maelstrom showed will work, but it's much more complicated than what's actually needed. Here's a much cleaner solution:
from sympy import *
K = symbols("K")
# Step 1: make the fraction
# This seems to be a weird workaround to prevent fractions from being broken
# apart. See the note after this code block.
lh_frac = UnevaluatedExpr(3) / 5
# Step 2: prevent the fraction from being modified
# Creating a new multiplication expression will normally modify the involved
# expressions as sympy sees fit. Setting evaluate to False prevents that.
expr = Mul(lh_frac , Pow(K, 2), evaluate=False)
pprint(expr)
gives:
3 2
-*K
5
Important Note:
Doing lh_frac = UnevaluatedExpr(3) / 5 is not how fractions involving 2 literal numbers should typically be created. Normally, you would do:
lh_frac = Rational(3, 5)
as shown in the sympy docs. However, that gives undesirable output for our use case right now:
2
3*K
----
5
This outcome is surprising to me; setting evaluate to False inside Mul should be sufficient to do what we want. I have an open question about this.

Using sympy.integrate on a function that involves int()

I'm trying to integrate functions in Python. scipy.integrate.quad seems to work ok; but just be sure I'd like to check the results against other integration code. It was suggested that I try sympy.integrate. Now the code for the functions I want to integrate contains int(), which I use to convert floats into ints. This is ok for quad, but not for sympy.integrate.
Here's a simple example that reproduces the error:
import sympy
def f(x):
return sympy.exp(int(x))
sympy.symbols('x')
print(sympy.integrate(f(x),(x,0,2)))
This yields the error: TypeError: can't convert symbols to int
So is there a way to integrate functions that involve int() with scipy.integrate?
Thanks
To use integrate f must be a SymPy symbolic function which disallows your particular use of int. int(x) where x is a Symbol will always yield a type error however you could represent this symbolically using the floor function:
def f(x):
return sympy.exp(sympy.floor(x))
However, using floor may defeat some of the purpose of using SymPy in the first place because it will probably prevent discovery of an analytic solution as the following python session demonstrates:
>>> from sympy import *
>>> x = symbols("x")
>>> integrate(exp(floor(x)), (x, 0, 2)) # use of floor prevents evaluated result
Integral(exp(floor(x)), (x, 0, 2))
Though you can use the evalf method to compute a numeric result (which is ultimately performed by mpmath):
>>> integrate(exp(floor(x)), (x, 0, 2)).evalf()
3.7
(perhaps this result suggests sympy could better handle this integral? Wolfram Alpha computes this as 1 + e = 3.71828... so I suppose there is at least a floating point precision bug here too - see comment re ceiling)
In any case, I don't know if you consider that an appropriate result considering the version of f without floor:
>>> integrate(exp(x), (x, 0, 2))
-1 + exp(2)
>>> _.evalf()
6.38905609893065

How to check whether a symbolic expression is rational?

I'm using Sympy and I haven't found a simple way of testing for x ∈ Q.
Context: I have a set of solutions of a set of very simple, 2DoF eigenvalue problems (e.g.,
) and I want to check if one of these solutions is rational (or, in other words, if the solution doesn't contains a square root).
A direct way of checking is what I would like the best, but I could accept also an answer that deals with finding (not finding) a square root in the solution.
The function rational = lambda x: all(i.exp.is_Integer for i in x.atoms(Pow)) is a direct translation of your criteria to return True if all powers (if present) are integers.
>>> from sympy import Pow, S, sqrt
>>> rational = lambda x: all(i.exp.is_Integer for i in x.atoms(Pow))
>>> rational(S.Half)
True
>>> rational(sqrt(3))
False
>>> rational(3/(1+sqrt(3)))
False