I want to make an integral by parts step by step, so I'm trying to write the first term: u*v (evaluated between A and B) but I have no idea of how to insert the usual bar to indicate the evaluation.
The closest thing that SymPy printers have is Subs, the inert form of substitution of one expression for another. For example
>>> u, v = x, sin(x)
>>> pprint(Subs(u*v, x, pi) - Subs(u*v, x, 0))
- (x⋅sin(x))│ + (x⋅sin(x))│
│x=0 │x=π
Or, in LaTeX terms,
>>> latex(Subs(u*v, x, pi) - Subs(u*v, x, 0))
'- \\left. x \\sin{\\left (x \\right )} \\right|_{\\substack{ x=0 }} + \\left. x \\sin{\\left (x \\right )} \\right|_{\\substack{ x=\\pi }}'
There is no logic for printing the bar with x = b on top and x = a at the bottom, because there is no class like Subs but with two substitutions for x.
To actually evaluate (not to print) such a thing, one can use
>>> (u*v).subs(x, pi) - (u*v).subs(x, 0)
0
Or, for tricky improper integrals where a limit has to be taken,
>>> (u*v)._eval_interval(x, S(0), pi)
0
The internal method _eval_interval takes limits instead of direct evaluation when needed.
Related
x+I'm using sympy to compute the Jacobian of a fairly complicated expression, and the resulting expressions are all in terms of the lowest-level symbols that I've defined. However, it would be very nice to have it in terms of some of the higher level expressions. For example, consider the basic snippet below.
>>> from sympy import *
>>> x, y = symbols('x, y')
>>> z = x + y
>>> f = z**2
>>> pprint(f)
2
(x + y)
Here, f is shown as (x + y)^2, but I would like it to be shown as z^2. Is there a way to do this in sympy?
Edit
Declaring z as a symbol and then substituting in x+y after the fact allowed me to get the Jacobian in terms of z, but my substitution wasn't able to handle the case when the terms were factored out. For example:
>>> from sympy import *
>>> x, y, z = symbols('x, y, z')
>>> f = z**2
>>> F = Matrix([f.subs(z, x+y)]).jacobian(Matrix([x, y]))
>>> F
Matrix([[2*x + 2*y, 2*x + 2*y]])
>>> F.subs(x+y, z)
Matrix([[2*x + 2*y, 2*x + 2*y]])
>>> F.subs(2*x+2*y, 2*z)
Matrix([[2*z, 2*z]])
Here, substituting x+y for z doesn't work because the expression has been expanded out to be 2x + 2y. Can F be rewritten in terms of x+y to make the substitution work no matter how it's been factored?
The subs function always works well with replacing symbols; in your case you are trying to replace a sum and that will not work well unless that sum actually literally appears as an argument in the expression tree, e.g. exp(x + y).subs(x + y, z) -> exp(z). So there are two approaches:
for a simple relationship like x + y -> z, solve for one of the variables and do the replacement x -> z - y
get your expression tree tidied up to expose the sum,
e.g.
>>> factor_terms(F).subs(x + y, z), F.subs(x, z - y)
(Matrix([[2*z, 2*z]]), Matrix([[2*z, 2*z]]))
sympy shows formulas using symbols.
Here you have two symbols x and y. z is not a symbol. It's an Add object.
>>> type(x)
<class 'sympy.core.symbol.Symbol'>
>>> type(z)
<class 'sympy.core.add.Add'>
You must create another symbol z and when you try to do something to z, let's say evaluate, diff etc, you can specify that z is x+y
In Python 2, I can write:
In [5]: points = [ (1,2), (2,3)]
In [6]: min(points, key=lambda (x, y): (x*x + y*y))
Out[6]: (1, 2)
But that is not supported in 3.x:
File "<stdin>", line 1
min(points, key=lambda (x, y): (x*x + y*y))
^
SyntaxError: invalid syntax
The straightforward workaround is to index explicitly into the tuple that was passed:
>>> min(points, key=lambda p: p[0]*p[0] + p[1]*p[1])
(1, 2)
This is very ugly. If the lambda were a function, I could do
def some_name_to_think_of(p):
x, y = p
return x*x + y*y
But because the lambda only supports a single expression, it's not possible to put the x, y = p part into it.
How else can I work around this limitation?
No, there is no other way. You covered it all. The way to go would be to raise this issue on the Python ideas mailing list, but be prepared to argue a lot over there to gain some traction.
Actually, just not to say "there is no way out", a third way could be to implement one more level of lambda calling just to unfold the parameters - but that would be at once more inefficient and harder to read than your two suggestions:
min(points, key=lambda p: (lambda x,y: (x*x + y*y))(*p))
Python 3.8 update
Since the release of Python 3.8, PEP 572 — assignment expressions — have been available as a tool.
So, if one uses a trick to execute multiple expressions inside a lambda - I usually do that by creating a tuple and just returning the last component of it, it is possible to do the following:
>>> a = lambda p:(x:=p[0], y:=p[1], x ** 2 + y ** 2)[-1]
>>> a((3,4))
25
One should keep in mind that this kind of code will seldom be more readable or practical than having a full function. Still, there are possible uses - if there are various one-liners that would operate on this point, it could be worth to have a namedtuple, and use the assignment expression to effectively "cast" the incoming sequence to the namedtuple:
>>> from collections import namedtuple
>>> point = namedtuple("point", "x y")
>>> b = lambda s: (p:=point(*s), p.x ** 2 + p.y ** 2)[-1]
According to http://www.python.org/dev/peps/pep-3113/ tuple unpacking are gone, and 2to3 will translate them like so:
As tuple parameters are used by lambdas because of the single
expression limitation, they must also be supported. This is done by
having the expected sequence argument bound to a single parameter and
then indexing on that parameter:
lambda (x, y): x + y
will be translated into:
lambda x_y: x_y[0] + x_y[1]
Which is quite similar to your implementation.
I don't know any good general alternatives to the Python 2 arguments unpacking behaviour. Here's a couple of suggestion that might be useful in some cases:
if you can't think of a name; use the name of the keyword parameter:
def key(p): # more specific name would be better
x, y = p
return x**2 + y**3
result = min(points, key=key)
you could see if a namedtuple makes your code more readable if the list is used in multiple places:
from collections import namedtuple
from itertools import starmap
points = [ (1,2), (2,3)]
Point = namedtuple('Point', 'x y')
points = list(starmap(Point, points))
result = min(points, key=lambda p: p.x**2 + p.y**3)
While the destructuring arguments was removed in Python3, it was not removed from comprehensions. It is possible to abuse it to obtain similar behavior in Python 3.
For example:
points = [(1,2), (2,3)]
print(min(points, key=lambda y: next(x*x + y*y for (x,y) in [y])))
In comparison with the accepted answer of using a wrapper, this solution is able to completely destructure the arguments while the wrapper only destructures the first level. That is, you can do
values = [(('A',1),'a'), (('B',0),'b')]
print(min(values, key=lambda y: next(b for ((a,b),c) in (y,))))
In comparison to the accepted answer using an unwrapper lambda:
values = [(('A',1),'a'), (('B',0),'b')]
print(min(points, key=lambda p: (lambda a,b: (lambda x,y: (y))(*a))(*p)))
Alternatively one can also use a list instead of a tuple.
values = [(('A',1),'a'), (('B',0),'b')]
print(min(points, key=lambda y: next(b for (a,b),c in [y])))
This is just to suggest that it can be done, and should not be taken as a recommendation. However, IMO, this is better than the hack of using using multiple expressions in a tuple and returning the last one.
I think the better syntax is x * x + y * y let x, y = point, let keyword should be more carefully chosen.
The double lambda is the closest version.
lambda point: (lambda x, y: x * x + y * y)(*point)
High order function helper would be useful in case we give it a proper name.
def destruct_tuple(f):
return lambda args: f(*args)
destruct_tuple(lambda x, y: x * x + y * y)
Consider whether you need to unpack the tuple in the first place:
min(points, key=lambda p: sum(x**2 for x in p))
or whether you need to supply explicit names when unpacking:
min(points, key=lambda p: abs(complex(*p)**2)
Based on Cuadue suggestion and your comment on unpacking still being present in comprehensions, you can use, using numpy.argmin :
result = points[numpy.argmin(x*x + y*y for x, y in points)]
Another option is to write it into a generator producing a tuple where the key is the first element. Tuples are compared starting from beginning to end so the tuple with the smallest first element is returned. You can then index into the result to get the value.
min((x * x + y * y, (x, y)) for x, y in points)[1]
There may be a real solution to this, using PyFunctional!
Although not currently supported, I've submitted a tuple arg unpacking feature request to support:
(
seq((1, 2), (3, 4))
.map(unpack=lambda a, b: a + b)
) # => [3, 7]
Since questions on Stack Overflow are not supposed to contain the answer in the question, nor have explicit "update" sections, I am converting OP's original "updates" to a proper answer and making it community wiki.
OP originally claimed that this solution was "extending the idea in the answer". I cannot discern which answer that meant, or which idea. The idea is functionally the same as anthony.hl's answer, but that came years later. Considering the state of answers at the time, I think this qualifies as OP's original work.)
Make a wrapper function that generalizes the process of unpacking the arguments, like so:
def star(f):
return lambda args: f(*args)
Now we can use this to transform the lambda we want to write, into one that will receive the argument properly:
min(points, key=star(lambda x,y: (x*x + y*y))
We can further clean this up by using functools.wraps:
import functools
def star(f):
#functools.wraps(f)
def f_inner(args):
return f(*args)
return f_inner
I am using python (3.7.3) with sympy (1.6.2) to store a function with squared terms and non-squared terms, with each term being the product of exactly two variables.
For example,
>> import sympy as sy
>> x = sy.Symbol('x')
>> y = sy.Symbol('y')
>> F = x*x+x*y
>> print(F)
x**2+x*y
I want to be able to iterate through the terms and get each operand.
For example,
terms = F.expand(basic=True).args
for term in terms
(t0,t1) = term.args
print('t0:{}, t1:{}'.format(t0,t1))
# do some stuff using t0, t1
This works for the x*y term, but not the x**2 term.
>> print((x*y).args)
(x,y)
>> print((x**2).args) # I want this to be (x,x)
(x,2)
I tried running (x**2).expand(), but this appears to be the fully expanded version of the expression.
My question is twofold:
is there a way to expand x**2 so that it is stored as x*x?
is there a better way to go about getting each operand in each term than the for loop I show above?
You could define a custom function that defactors in the way you want:
def get_factors(expr):
if expr.func == sy.Mul:
return expr.args
elif expr.func == sy.Pow:
return tuple(expr.args[0] for _ in range(expr.args[1]))
else:
raise NotImplementedError()
Usage:
>>> a, b = terms
>>> get_factors(a)
(x, x)
>>> get_factors(b)
(x, y)
I read such a script:
add_numbers = lambda x, y: x+y
add_five = lambda y: add_numbers(5,y)
It derive a new function of one variable, add_five, that adds 5 to its argument:
from this point, introduced functools
In [9]: from functools import partial
In [10]: add_five = partial(add_numbers, 5)
In [11]: add_five(7)
Out[11]: 12
As a novice, I guess it can be easily achieved by
add_five = lambda y: 5+y
add_six = lambda y: 6+y
I am confused what's the benefit if not define add_five in a straighforward method?
The utility of partial is to easily create specialised versions of functions from a general definition.
The case of adding numbers can be illustrating here add_numbers is the general case.
from functools import partial
def add_numbers(x, y):
return x + y
add5 = partial(add_nums, 5)
Here add5 is a specialised case of add_numbers roughly equivalent to
def add5(x):
return add_numbers(x, 5)
Adding numbers is a very trivial example and does not show the utility of partial
The following is a simple example that may better show the utility of partial.
Consider writing a procedure to compute the square root of a number using the Babylonian method.
def square_root(x, tolerance, convergence_test):
y = 1
while not convergence_test(x, y, tolerance):
y = (y + x/y)/2
return y
For most numbers, the convergence test can simply check the difference between y squared and x is 0. Let's call this the absolute error of the estimate
def absolute_error(x, y, tolerance):
return abs(x - y**2) <= tolerance
For very large and small numbers, using absolute error of the estimate can lead to wrong answers for various reasons. In those cases, it is better to use the relative error:
def relative_error(x, y, tolerance):
return abs(x/(y**2) - 1) <= tolerance
With partial, we can easily create specialised functions for using the either absolute and relative error.
sqrt_rel_err = partial(square_root, convergence_test=relative_error)
sqrt_abs_err = partial(square_root, convergence_test=absolute_error)
Now using either is trivial
>>> sqrt_rel_err(2, 0.00001)
1.4142156862745097
>>> sqrt_abs_err(2, 0.00001)
1.4142156862745097
And for small numbers: we see using absolute error gives the wrong answer (especially when the tolerance is greater than the number we are trying to get the square root of)
>>> x = sqrt_abs_err(1e-6, 0.00001)
>>> x**2
4.4981362843183905e-06
Whilst the relative error method yields a more accurate answer.
>>> x = sqrt_rel_err(1e-6, 0.00001)
>>> x**2
1.0000003066033492e-06
I want to receive input from a user, parse it, then perform some substitutions on the resulting expression. I know that I can use sympy.parsing.sympy_parser.parse_expr to parse arbitrary input from the user. However, I am having trouble substituting in function definitions. Is it possible to make subsitutions in this manner, and if so, how would I do so?
The overall goal is to allow a user to provide a function of x, which is then used to fit data. parse_expr gets me 95% of the way there, but I would like to provide some convenient expansions, such as shown below.
import sympy
from sympy.parsing.sympy_parser import parse_expr
x,height,mean,sigma = sympy.symbols('x height mean sigma')
gaus = height*sympy.exp(-((x-mean)/sigma)**2 / 2)
expr = parse_expr('gaus(100, 5, 0.2) + 5')
print expr.subs('gaus',gaus) # prints 'gaus(100, 5, 0.2) + 5'
print expr.subs(sympy.Symbol('gaus'),gaus) # prints 'gaus(100, 5, 0.2) + 5'
print expr.subs(sympy.Symbol('gaus')(height,mean,sigma),gaus) # prints 'gaus(100, 5, 0.2) + 5'
# Desired output: '100 * exp(-((x-5)/0.2)**2 / 2) + 5'
This is done using python 2.7.9, sympy 0.7.5.
You can use the replace method. For instance
gaus = Function("gaus") # gaus is parsed as a Function
expr.replace(gaus, Lambda((height, mean, sigma), height*sympy.exp(-((x-mean)/sigma)**2 / 2)))
replace also has other options, such as pattern matching.
After some experimentation, while I did not find a built-in solution, it was not difficult to build one that satisfies simple cases. I am not a sympy expert, and so there may be edge cases that I haven't considered.
import sympy
from sympy.core.function import AppliedUndef
def func_sub_single(expr, func_def, func_body):
"""
Given an expression and a function definition,
find/expand an instance of that function.
Ex:
linear, m, x, b = sympy.symbols('linear m x b')
func_sub_single(linear(2, 1), linear(m, b), m*x+b) # returns 2*x+1
"""
# Find the expression to be replaced, return if not there
for unknown_func in expr.atoms(AppliedUndef):
if unknown_func.func == func_def.func:
replacing_func = unknown_func
break
else:
return expr
# Map of argument name to argument passed in
arg_sub = {from_arg:to_arg for from_arg,to_arg in
zip(func_def.args, replacing_func.args)}
# The function body, now with the arguments included
func_body_subst = func_body.subs(arg_sub)
# Finally, replace the function call in the original expression.
return expr.subs(replacing_func, func_body_subst)
def func_sub(expr, func_def, func_body):
"""
Given an expression and a function definition,
find/expand all instances of that function.
Ex:
linear, m, x, b = sympy.symbols('linear m x b')
func_sub(linear(linear(2,1), linear(3,4)),
linear(m, b), m*x+b) # returns x*(2*x+1) + 3*x + 4
"""
if any(func_def.func==body_func.func for body_func in func_body.atoms(AppliedUndef)):
raise ValueError('Function may not be recursively defined')
while True:
prev = expr
expr = func_sub_single(expr, func_def, func_body)
if prev == expr:
return expr