I'm not sure if the following is possible. I tried looking at the docs, but see a lot of physics stuff and not quite what I want.
Is it possible to be like matrixcalculus.org, and specify say a general matrix Q of shape (m,n), x, a vector of shape n, and do this kind of calculation. Rather than limiting it to a set number of dimensions and specifying each element individually
You can use MatrixSymbol:
In [5]: n = Symbol('n')
In [6]: Q = MatrixSymbol('Q', n, n)
In [7]: x = MatrixSymbol('x', n, 1)
In [8]: f = x.T # Q # x
In [9]: f
Out[9]:
T
x ⋅Q⋅x
In [10]: diff(f, x)
Out[10]:
T
Q⋅x + Q ⋅x
If you substitute a concrete value for n then as_explicit can give you the expanded result:
In [11]: diff(f, x).subs(n, 2).as_explicit()
Out[11]:
⎡2⋅Q₀₀⋅x₀₀ + Q₀₁⋅x₁₀ + Q₁₀⋅x₁₀⎤
⎢ ⎥
⎣Q₀₁⋅x₀₀ + Q₁₀⋅x₀₀ + 2⋅Q₁₁⋅x₁₀⎦
https://docs.sympy.org/latest/modules/matrices/expressions.html
Related
I am a bit confused how to use Indexed objects in Sympy. Suppose I have the following setup:
from sympy import *
x = IndexedBase('x')
i = Idx('i')
s = Sum(x[i], (i, 0, 5))
s
Output:
5
___
╲
╲
╱ x[i]
╱
‾‾‾
i = 0
Which ofcourse is equal to
x[0] + x[1] + x[2] + x[3] + x[4] + x[5]
By doing s.doit(). Now, how do I substitute x with some range? I expected the following to work:
s.subs(x, list(range(6)))
But it does not do anything it would seem. However s.doit().subs(x[0], 0) works, but it will only substitute 1 element. Is it not intended to substitute IndexedBase with some list?
When using SymPy, there is one thing to always keep in mind: the only objects SymPy operates on is SymPy's object. Consider this example:
expr = x + 3
r = expr.subs(x, 2)
print(r, type(r))
5 <class 'sympy.core.numbers.Integer'>
Here, we passed a int number to subs, but SymPy internally converted it to an Integer number. Then, it performed the addition, producing the Integer number 5.
There are occasions in which the input parameter cannot be converted to something SymPy can understand. Your example is one such occasion. Let's use sympify (or its alias S) to verify how your list is going to be converted to a SymPy object:
l = list(range(6))
c = sympify(l)
type(c)
# out: list
As we can see, SymPy is unable to convert an object of type list, hence it is unable to use it. In short, this is the reason your code doesn't produce the correct output.
However, let's try the same trick with a tuple:
c = sympify(tuple(l))
type(c)
# out: Tuple
Here, SymPy converted a Python object of type tuple to a SymPy object of type Tuple. Now, the substitution should produce the correct result:
s.doit().subs(x, tuple(l))
# out: 15
Here are the most common SymPy objects the support iteration: Tuple, Matrix, Array.
from sympy import *
x = Symbol('x')
c, k = symbols('c, k', real=True, nonnegative=True)
integrate(exp(-c * k * x**2), (x, -oo, oo))
Produces
(sqrt(pi)*sqrt(polar_lift(c))*sqrt(polar_lift(k))/(c*k)
I don't want polar_lift in the output, is there an assumption I can add, or something else I can do to get a cleaner result?
You've set the symbols to be nonnegative which implies the possibility that they are both zero in which case the integral does not converge. If the symbols are both positive (i.e. not zero) then you get a simple result:
In [85]: x = Symbol('x')
In [86]: c, k = symbols('c, k', positive=True)
In [87]: integrate(exp(-c * k * x**2), (x, -oo, oo))
Out[87]:
√π
─────
√c⋅√k
For example, Volume of a rectangular box can be calculated as V = L * W * H
Suppose we know V, L, W, then we can solve for H.
Suppose we know V, H, W, then we can solve for V.
Suppose we know L, W, H, then we can solve for V.
And e.t.c
Is there a way to solve in python (I am trying Sympy currently) to solve it based on the input given?
Sure I can use cases of ifs, but I will need to write 4 equations to solve and that is for a short equation.
Any suggestion is appreciated.
Kind regards,
Iwan
This answer to a similar question may help you. Basically you can define the general equation, get values for all but one variable, substitution them into the general equation then pass that expression to solve (or else just pass all equations to solve, which I show below):
from sympy import Eq, solve, Tuple, S
from sympy.abc import v,l,w,h
eq = Eq(v, l*w*h)
variables = eq.free_symbols
got = []
vs = ', '.join(([str(i) for i in variables]))
print('enter 3 known values of {%s} as equality, e.g. h=2' % vs)
for i in range(3):
if 0: # change to 1 to get real input
e = input()
else:
e = ['v=20','w=5','h=1'][i]
got.append(Eq(*[S(j) for j in e.split('=')]))
x = ({v,l,w,h} - Tuple(*got).free_symbols).pop()
ans = solve([eq]+got)
print('consistent values: %s' % ans)
print('%s = %s' % (x.name, ans[0][x])
gives
enter 3 known values of {v, h, w, l} as equality, e.g. h=2
consistent values: [{v: 20, h: 1, w: 5, l: 4}]
l = 4
As an introduction i want to point out that if one has a matrix A consisting of 4 submatrices in a 2x2 pattern, where the diagonal matrices are square, then if we denote its inverse as X, the submatrix X22 = (A22-A21(A11^-1)A12)^-1, which is quite easy to show by hand.
I was trying to do the same for a matrix of 4x4 submatrices, but its quite tedious by hand. So I thought Sympy would be of some help. But I cannot figure out how (I have started by just trying to reproduce the 2x2 result).
I've tried:
import sympy as s
def blockmatrix(name, sizes, names=None):
if names is None:
names = sizes
ll = []
for i, (s1, n1) in enumerate(zip(sizes, names)):
l = []
for j, (s2, n2) in enumerate(zip(sizes, names)):
l.append(s.MatrixSymbol(name+str(n1)+str(n2), s1, s2))
ll.append(l)
return ll
def eyes(*sizes):
ll = []
for i, s1 in enumerate(sizes):
l = []
for j, s2 in enumerate(sizes):
if i==j:
l.append(s.Identity(s1))
continue
l.append(s.ZeroMatrix(s1, s2))
ll.append(l)
return ll
n1, n2 = s.symbols("n1, n2", integer=True, positive=True, nonzero=True)
M = s.Matrix(blockmatrix("m", (n1, n2)))
X = s.Matrix(blockmatrix("x", (n1, n2)))
I = s.Matrix(eyes(n1, n2))
s.solve(M*X[:, 1:]-I[:, 1:], X[:, 1:])
but it just returns an empty list instead of the result.
I have also tried:
Using M*X==I but that just returns False (boolean, not an Expression)
Entering a list of equations
Using 'ordinary' symbols with commutative=False instead of MatrixSymbols -- this gives an exception with GeneratorsError: non-commutative generators: (x12, x22)
but all without luck.
Can you show how to derive a result with Sympy similar to the one I gave as an example for X22?
The most similar other questions on solving with MatrixSymbols seem to have been solved by working around doing exactly that, by using an array of the inner symbols or some such instead. But since I am dealing with symbolically sized MatrixSymbols, that is not an option for me.
Is this what you mean by a matrix of 2x2 matrices?
>>> a = [MatrixSymbol(i,2,2) for i in symbols('a1:5')]
>>> A = Matrix(2,2,a)
>>> X = A.inv()
>>> print(X[1,1]) # [1,1] instead of [2,2] because indexing starts at 0
a1*(a1*a3 - a3*a1)**(-1)
[You indicated not and pointed out that the above is not correct -- that appears to be an issue that should be resolved.]
I am not sure why this isn't implemented, but we can do the solving manually as follows:
>>> n = 2
>>> v = symbols('b:%s'%n**2,commutative=False)
>>> A = Matrix(n,n,symbols('a:%s'%n**2,commutative=False))
>>> B = Matrix(n,n,v)
>>> eqs = list(A*B - eye(n))
>>> for i in range(n**2):
... s = solve(eqs[i],v[i])[0]
... eqs[i+1:] = [e.subs(v[i],s) for e in eqs[i+1:]]
...
>>> s # solution for v[3] which is B22
(-a2*a0**(-1)*a1 + a3)**(-1)
You can change n to 3 and see a modestly complicated expression. Change it to 4 and check the result by hand to give a new definition to the word "tedious" ;-)
The special structure of the equations to be solved can allow for a faster solution, too: the variable of interest is the last factor in each term containing it:
>>> for i in range(n**2):
... c,d = eqs[i].expand().as_independent(v[i])
... assert all(j.args[-1]==v[i] for j in Add.make_args(d))
... s = 1/d.subs(v[i], 1)*-c
... eqs[i+1:] = [e.subs(v[i], s) for e in eqs[i+1:]]
I have an equation that is of the form (in LaTeX syntax):
\sum_{k=0}^{K-1} a_k = 0
a_k is "a subscript k", one of a list of variables that I'm setting up a system of linear equations in. I would like to be able to express this equation to SymPy in as compact of a way as possible. It seems like I would want to use its Sum() function to express the summation, but I'm not sure how to tell it that on term k in the sum, a_k refers to the k-th symbol.
Is this possible, for instance if I set up a list of symbols like this?
a = [sympy.symbols('a' + str(i)) for i in xrange(K)]
Do you mean something like this?
In [1]: a = IndexedBase("a")
In [2]: Sum(a[k], (k, 0, K-1))
Out[2]:
K - 1
___
╲
╲ a[k]
╱
╱
‾‾‾
k = 0
IndexedBase are supposed to create a variable that needs to specify an index each time it is used. If the indices are different, the variables should be considered different (e.g. a[k] vs a[j]).
In case your summation has known limits (i.e. non literal), you may expand it:
In [3]: Sum(a[k], (k, 0, 10))
Out[3]:
10
___
╲
╲ a[k]
╱
╱
‾‾‾
k = 0
In [4]: Sum(a[k], (k, 0, 10)).doit()
Out[4]: a[0] + a[1] + a[2] + a[3] + a[4] + a[5] + a[6] + a[7] + a[8] + a[9] + a[10]
Unfortunately, not all of SymPy's algorithms support IndexedBase objects completely. Replacement with a Symbol is advised in such cases.