Little puzzle on functional programming in Python - python-3.x

The input is two integers in one line, x and y. I need to write a basically one-line program which does different things with x and y, and prints the result. Say, the output should be x + 1, y * y. Or list(range(x)), y // 2. Whatever operations but different. No def functions, also 'if' and 'for' are prohibited. As far as i understand, should look something like:
print(
*map(
lambda x: ??? ,
map(
int, input().split()
)
)
)
(But lambda can only do same thing to both inputs, right? )
I know it is possible and i've been thinking about this for three days to no avail. Most probable i miss something very obvious.

Your lambda function can take an x and y and turn them into pretty much any expression. Then you would call that function, doing the processing of the inputs outside of that lambda
print(*(lambda x, y: (x+1, y*y))(*map(int, input().split())))
print(*(lambda x, y: (list(range(x)), y//2))(*map(int, input().split())))

This seems to work just fine:
print(
*(lambda x: [int(x[0]) + 1, int(x[1]) * int(x[1])])(
input().split()
)
)
No fancy functional tricks or map are needed.

Related

The initializer parameter of reduce() on the sum of elements of an iterable

A query regarding this code:
from functools import reduce
def sum_even(it):
return reduce(lambda x, y: x + y if not y % 2 else x, it,0)
print(sum_even([1, 2, 3, 4]))
Why not adding the third parameter of reduce() adds the first odd element of the list?
If you don't pass an initial element explicitly, then the first two elements of the input become the arguments to the first call to the reducer, so x would be 1 and y would be 2. Since your test only excludes odd ys, not xs, the x gets preserved, and all future xs are sums based on that initial 1. Using 0 as an explicit initial value means only 0 and (later) the accumulated total of that 0 and other even numbers is ever passed as x, so an odd number is never passed as x.
Note that this is kind of a silly way to do this. It's much simpler to build this operation from parts, using one tool to filter to even, and another to sum the surviving elements from the filtering operation. For example:
def sum_even(it):
return sum(x for x in it if not x % 2)
is shorter, clearer, and (likely) faster than the reduce you wrote.

Sympy - Find all expressions of a certain level

in the documentation it is shown, how one can use srepr(expr) to create a string containing all elements of the formula tree.
I would like to have all elements of a certain level of such a tree in a list, not as a string but as sympy objects.
For the example
from sympy import *
x,y,z = symbols('x y z')
expr = sin(x*y)/2 - x**2 + 1/y
s(repr)
"""
gives out
=> "Add(Mul(Integer(-1), Pow(Symbol('x'), Integer(2))), Mul(Rational(1, 2),
sin(Mul(Symbol('x'), Symbol('y')))), Pow(Symbol('y'), Integer(-1)))"
"""
This should lead to
first_level = [sin(x*y)/2,-x**2,1/y]
second_level[0] = [sin(x*y),2]
I assume, the fundamental question is, how to index a sympy expression according to the expression tree such that all higher levels starting from an arbitrary point are sumarized in a list element.
For the first level, it is possible to solve the task
by getting the type of the first level (Add in this case and then run)
print(list(Add.make_args(expr)))
but how does it work for expressions deeper in the tree?
I think the thing you are looking for is .args. For example your example we have:
from sympy import *
x, y, z = symbols('x y z')
expr = sin(x * y) / 2 - x ** 2 + 1 / y
first_level = expr.args
second_level = [e.args for e in first_level]
print(first_level)
print(second_level[0])
"""
(1/y, sin(x*y)/2, -x**2)
(y, -1)
"""
These give tuples, but I trust that you can convert them to lists no problem.
If you want to get directly to the bottom of the tree, use .atoms() which produces a set:
print(expr.atoms())
"""
{x, 2, y, -1, 1/2}
"""
Another thing that seems interesting is perorder_traversal() which seems to give a tree kind of object and if you iterate through it, you get something like a power set:
print([e for e in preorder_traversal(expr)])
"""
[-x**2 + sin(x*y)/2 + 1/y, 1/y, y, -1, sin(x*y)/2, 1/2, sin(x*y), x*y, x, y, -x**2, -1, x**2, x, 2]
"""
Here is the beginning of the docstring of the function:
Do a pre-order traversal of a tree.
This iterator recursively yields nodes that it has visited in a pre-order fashion. That is, it yields the current node then descends through the tree breadth-first to yield all of a node's children's pre-order traversal.
For an expression, the order of the traversal depends on the order of .args, which in many cases can be arbitrary.
If any of these are not what you want then I probably don't understand your question correctly. Apologies for that.

Multiplying functions together in Python

I am using Python at the moment and I have a function that I need to multiply against itself for different constants.
e.g. If I have f(x,y)= x^2y+a, where 'a' is some constant (possibly list of constants).
If 'a' is a list (of unknown size as it depends on the input), then if we say a = [1,3,7] the operation I want to do is
(x^2y+1)*(x^2y+3)*(x^2y+7)
but generalised to n elements in 'a'. Is there an easy way to do this in Python as I can't think of a decent way around this problem? If the size in 'a' was fixed then it would seem much easier as I could just define the functions separately and then multiply them together in a new function, but since the size isn't fixed this approach isn't suitable. Does anyone have a way around this?
You can numpy ftw, it's fairly easy to get into.
import numpy as np
a = np.array([1,3,7])
x = 10
y = 0.2
print(x ** (2*y) + a)
print(np.sum(x**(2*y)+a))
Output:
[3.51188643 5.51188643 9.51188643]
18.53565929452874
I haven't really got much for it to be honest, I'm still trying to figure out how to get the functions to not overlap.
a=[1,3,7]
for i in range(0,len(a)-1):
def f(x,y):
return (x**2)*y+a[i]
def g(x,y):
return (x**2)*y+a[i+1]
def h(x,y):
return f(x,y)*g(x,y)
f1= lambda y, x: h(x,y)
integrate.dblquad(f1, 0, 2, lambda x: 1, lambda x: 10)
I should have clarified that the end result can't be in floats as it needs to be integrated afterwards using dblquad.

Scipy.integrate gives odd results; are there best practices?

I am still struggling with scipy.integrate.quad.
Sparing all the details, I have an integral to evaluate. The function is of the form of the integral of a product of functions in x, like so:
Z(k) = f(x) g(k/x) / abs(x)
I know for certain the range of integration is between tow positive numbers. Oddly, when I pick a wide range that I know must contain all values of x that are positive - like integrating from 1 to 10,000,000 - it intgrates fast and gives an answer which looks right. But when I fingure out the exact limits - which I know sice f(x) is zero over a lot of the real line - and use those, I get another answer that is different. They aren't very different, though I know the second is more accurate.
After much fiddling I got it to work OK, but then needed to add in an exopnentiation - I was at least getting a 'smooth' answer for the computed function of z. I had this working in an OK way before I added in the exponentiation (which is needed), but now the function that gets generated (z) becomes more and more oscillatory and peculiar.
Any idea what is happening here? I know this code comes from an old Fortran library, so there must be some known issues, but I can't find references.
Here is the core code:
def normal(x, mu, sigma) :
return (1.0/((2.0*3.14159*sigma**2)**0.5)*exp(-(x-
mu)**2/(2*sigma**2)))
def integrand(x, z, mu, sigma, f) :
return np.exp(normal(z/x, mu, sigma)) * getP(x, f._x, f._y) / abs(x)
for _z in range (int(z_min), int(z_max) + 1, 1000):
z.append(_z)
pResult = quad(integrand, lb, ub,
args=(float(_z), MU-SIGMA**2/2, SIGMA, X),
points = [100000.0],
epsabs = 1, epsrel = .01) # drop error estimate of tuple
p.append(pResult[0]) # drop error estimate of tuple
By the way, getP() returns a linearly interpolated, piecewise continuous,but non-smooth function to give the integrator values that smoothly fit between the discrete 'buckets' of the histogram.
As with many numerical methods, it can be very sensitive to asymptotes, zeros, etc. The only choice is to keep giving it 'hints' if it will accept them.

Long expression crashes SymPy

I'm using 64-bit Python 3.3.1, pylab and 32GB system RAM. This function:
def sqrt2Expansion(limit):
x = Symbol('x')
term = 1+1/x
for _ in range(limit):
term = term.subs({x: (2+1/x)})
return term.subs({x: 2})
Produces expressions of this kind: 1 + 1/(2 + 1/(2 + 1/(2 + 1/(2 + 1/(2 + 1/(...)))))).
When called as: sqrt2Expansion(100) returns valid result, but sqrt2Expansion(200) produces RuntimeError with many pages of traceback and hangs up pylab/IPython interpreter with plenty of system memory left unused. Any ideas how to implement it more efficiently? I would like to call sqrt2Expansion(1000) and still get a result.
I will try to elaborate on the comment that I have posted above.
Sympy expressions are trees. Each operation is a node which has as branches its operands. For instance x+y looks like Add(x, y) and x*(y+z) like Mul(x, Add(y, z)).
Usually these expressions get automatically flattened like in Add(x, Add(y, z)) becoming Add(x, y, z), but for more complicated cases one can get very deep trees.
And deep trees can pose problems especially when either the interpreter or the library itself limits the depth of permitted recursion (as a protection against infinite recursion and exploding memory usage). Most probably this is the cause of your RuntimeError: each subs makes the tree deeper and as the tree gets deeper the recursive subs must call itself more times till it gets to the deepest node.
You can simplify the tree to something of the form polynomial/polynomial which has constant depth by using the factor method. Just change term = term.subs({x: (2+1/x)}) to term = term.subs({x: (2+1/x)}).factor().
Is there a reason that you need to do it symbolically? Just start with 2 and work from there. You will never hit recursion errors because the fraction will be flattened at each stage
In [10]: def sqrt2(limit):
....: expr = Rational(1, 2)
....: for i in range(limit):
....: expr = 1/(2 + expr)
....: return 1 + expr
....:
In [11]: sqrt2(100)
Out[11]:
552191743651117350907374866615429308899
───────────────────────────────────────
390458526450928779826062879981346977190
In [12]: sqrt2(100).evalf()
Out[12]: 1.41421356237310
In [13]: sqrt(2).evalf()
Out[13]: 1.41421356237310
In [15]: print sqrt2(1000)
173862817361510048113392732063287518809190824104684245763570072944177841306522186007881248757647526155598965224342185265607829530599877063992267115274300302346065892232737657351612082318884085720085755135975481584205200521472790368849847501114423133808690827279667023048950325351004049478273731369644053281603356987998498457434883570613383878936628838144874794543267245536801570068899/122939577152521961584762100253767379068957010866562498780385985503882964809611193975682098617378531179669585936977443997763999765977165585582873799618452910919591841027248057559735534272951945685362378851460989224784933532517808336113862600995844634542449976278852113745996406252046638163909206307472156724372191132577490597501908825040117098606797865940229949194369495682751575387690

Resources