Implicit linsolve() in Sympy and then lambdify - python

I'm asking is it possible to get np.linalg.solve() out of the lambdify on an expression involving solving?
For example, let
from sympy import MatrixSymbol, linsolve, lambdify
A = MatrixSymbol('A', 3, 3)
b = MatrixSymbol('b', 3, 1)
func = lambdify((A, b), linsolve((A, b)), modules="numpy")
Is it possible to generate the func(A, b) = np.linalg.solve(A, b)?
The above code for sure does not work. It will first fail at linsolve((A, b)).
My attempt would be somehow mark linsolve((A, b)) as an implicit expression so that lambdify can recognize it and thus link it with np.linalg.solve. But I don't find if sympy support this.

You can use function sympy.codegen.matrix_nodes.MatrixSolve instead of sympy.linsolve.
from sympy import MatrixSymbol, lambdify
from sympy.codegen.matrix_nodes import MatrixSolve
A = MatrixSymbol('A', 3, 3)
b = MatrixSymbol('b', 3, 1)
func = lambdify((A, b), MatrixSolve(A, b), modules="numpy")

With MatrixSolve, lambdify performs a simple lexical replacement:
In [87]: MatrixSolve(A,b)
Out[87]: MatrixSolve(MatrixSymbol(Str('A'), Integer(3), Integer(3)), vector=MatrixSymbol(Str('b'), Integer(3), Integer(1)))
In [88]: func = lambdify((A, b), MatrixSolve(A, b), modules="numpy")
In [89]: func
Out[89]: <function _lambdifygenerated(A, b)>
In [90]: func?
Signature: func(A, b)
Docstring:
Created with lambdify. Signature:
func(A, b)
Expression:
MatrixSolve(A, vector=b)
Source code:
def _lambdifygenerated(A, b):
return (solve(A, b))
Or use print(func.__doc__) to display that doc if not in ipython/isympy.
Your original problem was with using sympy.linsolve:
In [81]: linsolve((A,b))
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
<ipython-input-81-9ddeeeb0f242> in <module>
----> 1 linsolve((A,b))
/usr/local/lib/python3.8/dist-packages/sympy/solvers/solveset.py in linsolve(system, *symbols)
2630 if not isinstance(system[0], MatrixBase):
2631 if sym_gen or not symbols:
-> 2632 raise ValueError(filldedent('''
2633 When passing a system of equations, the explicit
2634 symbols for which a solution is being sought must
ValueError:
When passing a system of equations, the explicit symbols for which a
solution is being sought must be given as a sequence, too.

Related

Obtaining a function given by the user in Python

I'm having a problem to read a function using the parse_expr sympy function.
Here's how I'm using it:
from sympy import*
import sympy as smp
import numpy as np
from sympy.parsing.sympy_parser import parse_expr
print("Welcome...")
x=smp.Symbol('x')
function=input("Enter your function in terms of X\nIf you want to use Fixed point method input de G(x) expresion\n")
function=parse_expr(function, x)
And here's what I'm getting:
Welcome...
Enter your function in terms of X
If you want to use Fixed point method input de G(x) expresion
2*x
Traceback (most recent call last):
File "c:\Users\jp159\Desktop\Desktop\Studies\Exercises.py", line 8, in <module>
function=parse_expr(function, x)
File "C:\Users\jp159\AppData\Local\Programs\Python\Python39\lib\site-packages\sympy\parsing\sympy_parser.py", line 988, in parse_expr
raise TypeError('expecting local_dict to be a dict')
TypeError: expecting local_dict to be a dict
In an isympy session initialized with:
>>> from __future__ import division
>>> from sympy import *
>>> x, y, z, t = symbols('x y z t')
>>> k, m, n = symbols('k m n', integer=True)
>>> f, g, h = symbols('f g h', cls=Function)
>>> init_printing()
Documentation can be found at https://docs.sympy.org/1.8/
Since local_dict is optional, lets omit it:
In [1]: parse_expr('2*x')
Out[1]: 2⋅x
but we can make a dict - that references one of the defined symbols:
In [4]: parse_expr('2*x',{'x':x})
Out[4]: 2⋅x
In [5]: parse_expr('2*x',{'x':y})
Out[5]: 2⋅y
I can also use a string that doesn't look like any defined symbol:
In [7]: parse_expr('2*X')
Out[7]: 2⋅X
In [8]: _.free_symbols
Out[8]: {X}
One key skill for new programmers is reading the documentation. Yes, often that can be hard to understand, but still it should be the first stop. SO (and general web searches) should come later.
sympy is written in Python, so as basic knowledge of that language is assumed.

derivatives by a and b, using using algorithmic differentiation

I've been tasked to find the derivatives by a and b, using jax, for this
function
now, the reason I'm here is because I don't know enough Python, and this for the course in question, we haven't been thought python either.
the assignment is:
return a tuple (dfa, dfb) such that dfa is the partial derivatives of f by a,
and dfb is the partial derivative of f by b
now, I was able to do it the normal way:
def function(a, b):
dfa = sym.diff((2/b)*sym.cos(a)*sym.exp(-a*a/b*b), a)
dfb = sym.diff((2/b)*sym.cos(a)*sym.exp(-a*a/b*b), a)
return (dfa, dfb)
but im not familiar with algorithmic differentiation, using the example we were given, i've tried this:
def foo():
x = (2/b)*sym.cos(a)
y = sym.exp(-sym.Pow(a/b,2))
return (x*y)
def f_partial_derviatives_algo():
return jax.grad(foo)
but I'm getting this error:
cannot unpack non-iterable function object
If anyone can help with understanding how i can do something like that, It would be greatly appreciated
JAX and sympy are not compatible. You should either use one or the other, and not try to combine the two.
If you want to compute the partial derivatives of this function at some value using JAX, you can write something like this:
import jax.numpy as jnp
from jax import grad
def f(a, b):
return (2 / b) * jnp.cos(a) * jnp.exp(- a ** 2 / b ** 2)
df_da = grad(f, argnums=0)
df_db = grad(f, argnums=1)
print(df_da(1.0, 1.0), df_db(1.0, 1.0))
# -1.4141841 0.3975322

Evaluate Derivative of Function at a Point Python 2.7

I have the following function:
import sympy as sp
def inverted(q, m, a, nu):
return (-1)**(m+1)*(a/m)**m*sp.exp(m)*q**(-nu)*sp.diff(1/(sp.sqrt(a**2+q**2))*(sp.sqrt(a**2+q**2)-a)**(nu), a, m+1)
I want to define some lambda function such that
f100 = lambda a, q: inverted(q, 100, a, 0)
However, when I try to examine
q = sp.symbols('q')
f100(1000.0, q)
I get the following output:
ValueError:
Can't calculate 101st derivative wrt 10.
Obviously, what is happening is when I call f100(1000.0, q), the function refers back to inverted and the issue arises. I was hoping for a way around this.
Seems like you have to make a a variable first so diff works. It doesn't work if you fix a before (I think because you differentiate with respect to a). You can substitute a with 1000 afterwards.
import sympy as sp
def inverted(q, m, a, nu):
return (-1)**(m+1)*(a/m)**m*sp.exp(m)*q**(-nu)*sp.diff(1/(sp.sqrt(a**2+q**2))*(sp.sqrt(a**2+q**2)-a)**(nu), a, m+1)
f100 = lambda a, q: inverted(q, 100, a, 0)
q, a = sp.symbols('q, a')
print(f100(a, q).subs(a, 1000))

SymPy: Evaluate given expression with given variables

I have a sympy expression involving two variables a, b. I would now like to evaluate this expression for specific values of a and b. Using a lambda like
import sympy
def get_expression(a, b):
# Complex function with a simple result. I have no control here.
return a*b + 2
a = sympy.Symbol('a')
b = sympy.Symbol('b')
z = get_expression(a, b)
f = lambda a, b: z
print(f(1, 1))
only gives
a*b + 2
though.
Any hints?
Turns out that lambdify is what I need:
f = sympy.lambdify([a, b], z)
print(f(1, 1))

SymPy lambdify raises OverflowError: math range error

So, I have this code
from __future__ import division, print_function
import sympy as sp
import numpy as np
from sympy.utilities.lambdify import *
u = np.random.uniform(4, 6, 500)
w, k = sp.symbols('w k')
f = sp.log((k - w) * sp.exp((k - w)**5))
l = sum(f.subs(dict(k=k)) for k in u)
And now I want to use l as a function of w. So I know of some options
z_lambdify = lambdify(w, l)
z_subs = lambda x: l.subs(w, x)
The first function gives an error
>>> z_lambdify(1)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<string>", line 1, in <lambda>
OverflowError: math range error
>>> z_lambdify(4)
40.862695278600114
While the second gives answers
>>> z_subs(1)
11469.9130597554
>>> z_subs(4)
40.8626952786003
I would just use this, but it is very slow. Any way to get around this (fixing the lamdify error or a way of using l as a function that is not so slow)?
Version: Python 2.7.6, NumPy 1.8.1, SymPy 0.7.4.1
Answering your question:
The problem is that:
z_lambdify = lambdify(w, l)
tells the new function to perform the calculations using the built-in math functions, which you can check running with cProfile.run('z_lambdify(1)'); while doing z_subs(1) calls sympy functions. To get the same behavior you should tell lambdify() to use the same module:
z_lambdify = lambdify(w, l, "sympy")
Important suggestion:
You should simplify your function already at its definition and then useNumPy to perform the calculations much more efficiently. Using some simple algebra your function can be rewritten in a "non-overflowing" format as:
f = lambda k, w: np.log(k - w) + (k - w)**5
such that your desired answer can be achieved doing:
f(k=u, w=1).sum()
when you do f(k=u, w=1) you get an array with the same shape of u, where each value represents the result of the function evaluated with each value of u. You can use this function to simultaneously evaluate f() for different values of k and w, i.e. passing w as another array with the same shape of u instead of using a constant value.

Categories

Resources