how to combine exponents? (x**a)**b => x**(a*b)? - python

how to simplify exponents in equations in sympy
from sympy import symbols
a,b,c,d,e,f=symbols('abcdef')
j=(a**b**5)**(b**10)
print j
(a**(b**5))**(b**10) #ans even after using expand simplify
# desired output
a**(b**15)
and if it is not possible with sympy which module should i import in python?
edit
even if i define 'b' as real,and also all other symbols
b=symbols('b',real=True)
not getting simplified exponents
it simplifies only if exponents are constants
a=symbols('a',real=True)
b=symbols('b',real=True)
(a**5)**10
a**50 #simplifies only if exp are numbers
(a**b**5)**b**10
(a**(b**5))**b**10 #no simplification

(xm)n = xmn is true only if m, n are real.
>>> import math
>>> x = math.e
>>> m = 2j*math.pi
>>> (x**m)**m # (e^(2πi))^(2πi) = 1^(2πi) = 1
(1.0000000000000016+0j)
>>> x**(m*m) # e^(2πi×2πi) = e^(-4π²) ≠ 1
(7.157165835186074e-18-0j)
AFAIK, sympy supports complex numbers, so I believe this simplification should not be done unless you can prove b is real.
Edit: It is also false if x is not positive.
>>> x = -2
>>> m = 2
>>> n = 0.5
>>> (x**m)**n
2.0
>>> x**(m*n)
-2.0
Edit(by gnibbler): Here is the original example with Kenny's restrictions applied
>>> from sympy import symbols
>>> a,b=symbols('ab', real=True, positive=True)
>>> j=(a**b**5)**(b**10)
>>> print j
a**(b**15)

a,b,c=symbols('abc',real=True,positive=True)
(a**b**5)**b**10
a**(b**15)#ans

This may be related to this bug.

Related

How to calculate 2x + 4 = 10 using sympy?

How to calculate 2x + 4 = 10 using Sympy? Is it even possible?
It does not run on Sympy gamma but it runs on Wolframalpha and Cymath. Is it normal or is there some built-in library that should be used with this type of equation?
To represent it,
>>> from sympy.abc import x
>>> from sympy import S, Eq, solve
>>> eq = Eq(2*x + 4, 10)
>>> pprint(eq)
2*x + 4 = 10
To solve it:
>>> solve(eq)
[3]
To interpret input:
>>> s = '2*x + 4 = 10'
>>> eq = Eq(*map(S, s.split('=')))

solving linear system 6x6 matrix using sympy

i am trying to solve a matrix that has 6x6 matrices as it's entries(elements)
i tried multiplying the inverse of gen to the solution matrix, but i don't trust the correctness of the answer am getting.
from sympy import Eq, solve_linear_system, Matrix,count_ops,Mul,horner
import sympy as sp
a, b, c, d, e,f = sp.symbols('a b c d e f')
ad = Matrix(([43.4,26.5,115,-40.5,52.4,0.921],
[3.78,62.9,127,-67.6,110,4.80],
[41.25,75.0,213,-88.9, 131, 5.88],
[-10.6,-68.4,-120,64.6,-132,-8.49],
[6.5,74.3,121,-72.8,179,29.7],
[1.2,30.7,49.7,-28.7,91,29.9]))
fb= Matrix(([1,0,0,0,0,0],
[0,1,0,0,0,0],
[0,0,1,0,0,0],
[0,0,0,1,0,0],
[0,0,0,0,1,0],
[0,0,0,0,0,1]))
ab = Matrix(([-0.0057],
[0.0006],
[-0.0037],
[0.0009],
[0.0025],
[0.0042]))
az = sp.symbols('az')
bz = sp.symbols('bz')
fz = sp.symbols('fz')
gen = Matrix(([az, fz, 0, 0, 0, 0,bz],
[fz,az,fz,0,0,0,bz],
[0,fz,az,fz,0,0,bz],
[0,0,fz,az,fz,0,bz],
[0,0,0,fz,az,fz,bz],
[0,0,0,0,fz,az,bz]))
answer = solve_linear_system(gen,a,b,c,d,e,f)
first_solution = answer[a]
df = count_ops(first_solution)
print(df,first_solution)
disolved = zip(first_solution.simplify().as_numer_denom(),(1,-1))
dft = Mul(*[horner(b)**e for b,e in disolved])
dff = count_ops(dft)
print(dff,dft)
_1st_solution = dft.subs({az:ad,fz:fb,bz:ab},simultaneous = True).doit()
print(_1st_solution)
when i ran my code it raised sympy.matrices.common.ShapeError
You have to be careful when using horner with expressions containing commutative symbols that are actually noncommutative (in your case because they represent matrices). Your dft expression is
(az**2*bz - bz*fz**2)/(az*(az*(az + fz) - 2*fz**2) - fz**3)
but should maybe be
(az**2 - fz**2)*(az*(az*(az + fz) - 2*fz**2) - fz**3)**(-1)*bz
You would have received a correct expression if you had created the symbols as noncommutative (as shown below).
But you can't use horner with non-commutative symbols, so I just rearranged the expression by hand; you will have to check to see that the ordering is right. As an alternative to doing the factoring by hand you might also try using factor_nc to help you -- but it won't handle horner like expression factoring:
>>> ax, bz, fz = symbols('az bz fz, commutative=False)
>>> (az**2*bz - fz**2*bz)
az**2*bz - fz**2*bz
>>> factor_nc(_)
(az**2 - fz**2)*bz

Sympy evalf doesn't work with 1 variable subs() in 2 variable expression

For a college project in python using Sympy, i need to evaluate the output of a 2 var symbolic function after partial substitution, eg:
f = (x-1)/sqrt((x-10)^2+(y-10)^2) / x = 1 => f = 0
If i use an 1 var func, it works fine:
>>> from sympy import *
>>> x = symbols('x')
>>> F = 1-x
>>> F.evalf(subs={x: 1})
0.e-125
But in the case of a 2 var function, subs doesn't seem to do the substitution right:
>>> from sympy import *
>>> x,y = symbols('x y')
>>> F = (x-1)/sqrt((x-10)**2+(y-10)**2)
>>> F.evalf(subs={x: 1})
(x - 1.0)*((x - 10.0)**2 + (y - 10.0)**2)**(-0.5)
I expected F = 0 since x = 1
I'm not a sympy expert but I found a counter example when the value of y makes the expression non-zero:
>>> F.evalf(subs={x:1,y:float("nan")})
nan
when y is nan, the result is not zero. So it's not possible to simplify the expression not knowing the value of y (note: sympy happily evaluates F.evalf(subs={x:1,y:oo}) to 0 even if the result should be nan as well)
As mentioned above if y = nan creates a math exception, and so the substitution never happens.
But i found out if i just use subs then i get what i want:
>>> F.subs(x,1)
0
now if i explicitly substitute y = nan only then i get the nan answer
>>> F.subs(y,nan)
nan
Im guessing evalf is just checking for more exceptions before it evaluates the substitution.

How to simplify matrix expressions in SymPy?

Consider the following example
import sympy as sy
n = sy.symbols('n')
A = sy.MatrixSymbol("A",n,n)
B = sy.MatrixSymbol("B",n,n)
C = sy.MatrixSymbol("C",n,n)
M = A.inverse()*B.inverse() - A.inverse()*C*B.inverse()
B.inverse()*M.inverse()*A.inverse()
The example prints out B^-1*(A^-1*B^-1 - A^-1*C*B^-1)^-1*A^-1.
Can SymPy simplify the expression to (I-C)^-1? If not, how about any of the intermediate results, like collecting common factors in M?
The work around for this is using string converting on expression:
from sympy import *
n = symbols('n')
A = MatrixSymbol("A",n,n)
B = MatrixSymbol("B",n,n)
C = MatrixSymbol("C",n,n)
M = A.inverse()*B.inverse() - A.inverse()*C*B.inverse()
expression = B.inverse()*M.inverse()*A.inverse()
# convert expression to string then simplify
simplify_expression = simplify(str(expression))
pprint(simplify_expression)
Output:
-1
─────
C - 1

Find zeros of the characteristic polynomial of a matrix with Python

Given an N x N symmetric matrix C and an N x N diagonal matrix I, find the solutions of the equation det(λI-C)=0. In other words, the (generalized) eigenvalues of C are to be found.
I know few ways how to solve this in MATLAB using build-in functions:
1st way:
function lambdas=eigenValues(C,I)
syms x;
lambdas=sort(roots(double(fliplr(coeffs(det(C-I*x))))));
2nd way:
[V,D]=eig(C,I);
However, I need to use Python. There are similar function in NumPy and SymPy, but, according to docs (numpy, sympy), they take only one matrix C, as the input. Though, the result's different from the result produced by Matlab. Also, symbolic solutions produced by SymPy aren't helpful. Maybe I am doing something wrong? How to find solution?
Example
MATLAB:
%INPUT
I =
2 0 0
0 6 0
0 0 5
C =
4 7 0
7 8 -4
0 -4 1
[v,d]=eig(C,I)
%RESULT
v =
-0.3558 -0.3109 -0.5261
0.2778 0.1344 -0.2673
0.2383 -0.3737 0.0598
d =
-0.7327 0 0
0 0.4876 0
0 0 3.7784
Python 3.5:
%INPUT
I=np.matrix([[2,0,0],
[0,6,0],
[0,0,5]])
C=np.matrix([[4,7,0],[7,8,-4],[0,-4,1]])
np.linalg.eigh(C)
%RESULT
(array([-3., 1.91723747, 14.08276253]),
matrix(
[[-0.57735027, 0.60061066, -0.55311256],
[ 0.57735027, -0.1787042 , -0.79670037],
[ 0.57735027, 0.77931486, 0.24358781]]))
At least if I has positive diagonal entries you can simply solve a transformed system:
# example problem
>>> A = np.random.random((3, 3))
>>> A = A.T # A
>>> I = np.identity(3) * np.random.random((3,))
# transform
>>> J = np.sqrt(np.einsum('ii->i', I))
>>> B = A / np.outer(J, J)
# solve
>>> eval_, evec = np.linalg.eigh(B)
# back transform result
>>> evec /= J[:, None]
# check
>>> A # evec
array([[ -1.43653725e-02, 4.14643550e-01, -2.42340866e+00],
[ -1.75615960e-03, -4.17347693e-01, -8.19546081e-01],
[ 1.90178603e-02, 1.34837899e-01, -1.69999003e+00]])
>>> eval_ * (I # evec)
array([[ -1.43653725e-02, 4.14643550e-01, -2.42340866e+00],
[ -1.75615960e-03, -4.17347693e-01, -8.19546081e-01],
[ 1.90178603e-02, 1.34837899e-01, -1.69999003e+00]])
OP's example. IMPORTANT: must use np.arrays for I and C, np.matrix will not work.
>>> I=np.array([[2,0,0],[0,6,0],[0,0,5]])
>>> C=np.array([[4,7,0],[7,8,-4],[0,-4,1]])
>>>
>>> J = np.sqrt(np.einsum('ii->i', I))
>>> B = C / np.outer(J, J)
>>> eval_, evec = np.linalg.eigh(B)
>>> evec /= J[:, None]
>>>
>>> evec
array([[-0.35578356, -0.31094779, -0.52605088],
[ 0.27778714, 0.1343625 , -0.267297 ],
[ 0.23826117, -0.37371199, 0.05975754]])
>>> eval_
array([-0.73271478, 0.48762792, 3.7784202 ])
If I has positive and negative entries use eig instead of eigh and before taking the square root cast to complex dtype.
Differing from other answers, I assume that by the symbol I you mean the identity matrix, Ix=x.
What you want to solve, Cx=λIx, is the so-called standard eigenvalue problem,
and most eigenvalue solvers tackle the problem described in that format, hence the
Numpy function has the signature eig(C).
If your C matrix is a symmetric matrix and your problem is indeed a standard eigenvalue problem I'd recommend the use of numpy.linalg.eigh, that is optimized for this type of problems.
On the contrary if your problem is really a generalized eigenvalue problem, as, e.g., the frequency equation Kx=ω²Mx you could use scipy.linalg.eigh, that supports that type of problem statement for symmetric matrices.
eigvals, eigvecs = scipy.linalg.eigh(C, I)
With respect to the discrepancies in eigenvalues, the Numpy implementation gives no guarantees w/r to their ordering, so it could be just a different ordering, but if your problem is indeed a generalized problem (I not being the identity matrix...) the solution is of course different and you have to use the Scipy implementation of eigh.
If the discrepancies is within the eigenvectors, please remember that the eigenvectors are known within an arbitrary scale factor and, again, the ordering could be undefined (but, of course, their order is the same order in which you have the eigenvalues) — the situation is a little different for scipy.linalg.eigh because in this case the eigenvalues are sorted and the eigenvectors are normalized with respect to the second matrix argument (I in your example).
Ps: scipy.linalg.eigh behaviour (i.e., sorted eigenvalues and normalized eigenvectors) is so convenient for my use cases that I use to use it also to solve standard eigenvalue problems.
Using SymPy:
>>> from sympy import *
>>> t = Symbol('t')
>>> D = diag(2,6,5)
>>> S = Matrix([[ 4, 7, 0],
[ 7, 8,-4],
[ 0,-4, 1]])
>>> (t*D - S).det()
60*t**3 - 212*t**2 - 77*t + 81
Computing the exact roots:
>>> roots = solve(60*t**3 - 212*t**2 - 77*t + 81,t)
>>> roots
[53/45 + (-1/2 - sqrt(3)*I/2)*(312469/182250 + sqrt(797521629)*I/16200)**(1/3) + 14701/(8100*(-1/2 - sqrt(3)*I/2)*(312469/182250 + sqrt(797521629)*I/16200)**(1/3)), 53/45 + 14701/(8100*(-1/2 + sqrt(3)*I/2)*(312469/182250 + sqrt(797521629)*I/16200)**(1/3)) + (-1/2 + sqrt(3)*I/2)*(312469/182250 + sqrt(797521629)*I/16200)**(1/3), 53/45 + 14701/(8100*(312469/182250 + sqrt(797521629)*I/16200)**(1/3)) + (312469/182250 + sqrt(797521629)*I/16200)**(1/3)]
Computing floating-point approximations of the roots:
>>> for r in roots:
... r.evalf()
...
0.487627918145732 + 0.e-22*I
-0.73271478047926 - 0.e-22*I
3.77842019566686 - 0.e-21*I
Note that the roots are real.

Categories