Python Summation Higher Order Function - python

I'm writing an iterative solution for summation, and it seems to give the correct answer. But I'm told by my tutor that it's giving the wrong result for non-commutative combine operations. I went to google but I'm still unsure what exactly it means...
Here is the recursive code I wrote:
def sum(term, a, next, b):
# First recursive version
if a > b:
return 0
else:
return term(a) + sum(term, next(a), next, b)
def accumulate(combiner, base, term, a, next, b):
# Improved version
if a > b:
return base
else:
return combiner(term(a), accumulate(combiner, base, term, next(a), next, b))
print(sum(lambda x: x, 1, lambda x: x, 5))
print(accumulate(lambda x,y: x+y, 0, lambda x: x, 1, lambda x: x, 5))
# Both solution equate to - 1 + 2 + 3 + 4 + 5
This is the iterative version I wrote that gives the wrong results for non-commutative combine operations -
Edit: accumulate_iter gives the wrong results when lambda x,y: x- y is used for combiner
def accumulate_iter(combiner, null_value, term, a, next, b):
while a <= b:
null_value = combiner(term(a), null_value)
a = next(a)
return null_value
Hoping if someone could provide a solution for this iterative version of accumulate

You accumulate_iter works fine when the combiner is commutative, but it gives different result when the combiner is non-commutative. That's because the recursive accumulate combine elements from the back to the front, but the iterative version combine them from the front to the back.
So what we need to do is to make accumulate_iter combine from behind, and following is a rewritten accumulate_iter:
def accumulate_iter(a, b, base, combiner, next, term):
# we want to combine from behind,
# but it's hard to do that since we are iterate from ahead
# here we first go through the process,
# and store the elements encounted into a list
l = []
while a <= b:
l.append(term(a))
a = next(a)
l.append(base)
print(l)
# now we can combine from behind!
while len(l)>1:
l[-2] = combiner(l[-2], l[-1])
l.pop()
return l[0]

Related

How to pass a function as an argument

I would like to find an approximate value for the number pi = 3.14.. by using the Newton method. In order to use it also for some other purpose and thus other function than sin(x), the aim is to implement a generic function that will be passed over as an argument. I have an issue in passing a function as an argument into an other function. I also tried lambda in different variations. The code I am showing below produces the error message: IndexError: list index out of range. I will appreciate your help in solving this issue and eventually make any suggestion in the code which may not be correct. Thanks.
from sympy import *
import numpy as np
import math
x = Symbol('x')
# find the derivative of f
def deriv(f,x):
h = 1e-5
return (lambda x: (f(x+h)-f(x))/h)
def newton(x0,f,err):
A = [x0]
n = 1
while abs(A[n]-A[n-1])<=err:
if n == 1:
y = lambda x0: (math.f(x0))
b = x0-y(x0)/(deriv(y,x0))
A.append(b)
n += 1
else:
k = len(A)
xk = A[k]
y = lambda xk: (math.f(xk))
b = newton(A[k],y,err)-y(newton(A[k],y,err))/deriv(y,k)
A.append(b)
n += 1
return A, A[-1]
print(newton(3,math.sin(3),0.000001))
I don't know why you use sympy because I made it without Symbol
At the beginning you have to calculate second value and append it to list A and later you can calculate abs(A[n]-A[n-1]) (or the same without n: abs(A[-1] - A[-2])) because it needs two values from this list.
Other problem is that it has to check > instead of <=.
If you want to send function sin(x) then you have to use math.sin without () and arguments.
If you want to send function sin(3*x) then you would have to use lambda x: math.sin(3*x)
import math
def deriv(f, x, h=1e-5):
return (f(x+h) - f(x)) / h
def newton(x0, f, err):
A = [x0]
x = A[-1] # get last value
b = x - (f(x) / deriv(f, x)) # calculate new value
A.append(b) # add to list
while abs(A[-1] - A[-2]) > err: # it has to be `>` instead of `<=`
x = A[-1] # get last value
b = x - (f(x) / deriv(f, x)) # calculate new value
A.append(b) # add to list
return A, A[-1]
# sin(x)
print(newton(3, math.sin, 0.000001)) # it needs function's name without `()`
# sin(3*x)
print(newton(3, lambda x:math.sin(3*x), 0.000001))
# sin(3*x) # the same without `lambda`
def function(x):
return math.sin(3*x)
print(newton(3, function, 0.000001))
Result:
([3, 3.1425464414785056, 3.1415926532960112, 3.141592653589793], 3.141592653589793)
([3, 3.150770863559604, 3.1415903295877707, 3.1415926535897936, 3.141592653589793], 3.141592653589793)
EDIT:
You may write loop in newton in different way and it will need <=
def newton(x0, f, err):
A = [x0]
while True:
x = A[-1] # get last value
b = x - (f(x) / deriv(f, x)) # calculate new value
A.append(b) # add to list
if abs(A[-1] - A[-2]) <= err:
break
return A, A[-1]

Evaluating a function over a list in Python - without using loops

There is a problem in Python which involves the evaluation of a function over a list of numbers which are provided as inputs to the following function:
f(y) = sin(3y + pi/3) + cos(4y - pi/7)
I don't think MathJax tools are available on StackOverflow so the above is the best I can do.
There are four outputs to the function: An array or list containing the values obtained by the function for each element of the input list, the minimum and maximum values in the output array / list, and an array or list of the differences between successive values obtained by the function.
Here is the code so far. We assume that only sensible inputs are passed to the function.
import sympy
def minMaxDiffValues(lst):
y = sympy.symbols('y')
f = sympy.sin(3*y + sympy.pi/3) + sympy.cos(4*y - sympy.pi/7)
values = []
for n in lst:
values.append(f.subs(y,n))
differences = []
for i in range(len(values) - 1):
differences.append(values[i + 1] - values[i])
print values
print min(values)
print max(values)
print differences
As far as I know, the above code gets the job done; I've opted to work with lists, even though I am familiar with numpy. I'll replace the print statements with a single return statement; for now I'm printing the outputs to make sure that they are correct.
The only issue is that the problem prevents the use of loops; thus I am uncertain as to how to approach such a problem for the first and last function outputs.
Is it possible to write the above function without using any loops?
You could use list comprehensions:
import sympy
def minMaxDiffValues(lst):
y = sympy.symbols('y')
f = sympy.sin(3*y + sympy.pi/3) + sympy.cos(4*y - sympy.pi/7)
values = [f.subs(y,n) for n in lst]
differences = [values[i+1] - values[i] for i in range(len(values)-1)]
print(values)
print(min(values))
print(max(values))
print(differences)
If you wanted to, you could also use the pairwise recipe from the itertools module docs:
import itertools
import sympy
def pairwise(iterable):
"s -> (s0,s1), (s1,s2), (s2, s3), ..."
a, b = itertools.tee(iterable)
next(b, None)
return zip(a, b)
def minMaxDiffValues(lst):
y = sympy.symbols('y')
f = sympy.sin(3*y + sympy.pi/3) + sympy.cos(4*y - sympy.pi/7)
values = [f.subs(y,n) for n in lst]
differences = [y - x for (x, y) in pairwise(values)]
print(values)
print(min(values))
print(max(values))
print(differences)
Using map is a way to apply a function to a list of values in a compact fashion:
>>> from sympy import y, pi
>>> f = lambda y: sin(3*y + pi/3) + cos(4*y - pi/7)
>>> vals = list(map(f, lst))
>>> d = lambda i: vals[i] - vals[i-1]
>>> difs = list(map(d, range(1, len(vals))))
And there is no visible 'for'. But as #hpaulj notes, there's one under the hood somewhere.

How do I create an accumulate code that runs by iteration?

I am trying to create an "accumulate" code that run via iteration. In general, a combiner takes in 2 parameters e.g. combiner(x, y) which returns a function e.g. (x+y) and term determines the function of each a value e.g. term(x) gives you x^2 means that the next value of a will be x^2, and next will be the function that determines the next value after a e.g. x = x+1.
I am having issues with my code as it runs an unnecessary additional loop in certain cases (the null value has to be the last value that the loop processes before exiting the while loop e.g.
def accumulate_iter(combiner, null_value, term, a, next, b):
result = term(a)
while a<=b:
a = next(a)
if a<=b:
result = combiner(term(a), result)
else:
result = combiner(null_value, result)
return result
An example of the input will be:
accumulate_iter(lambda x,y: xy, 1, lambda x: xx, 1, lambda x: x+1, 5)
and the output will give you: 14400
def accumulate_iter(combiner, term, a, next, b):
result = term(a)
while a <= b:
a = next(a)
if a <= b:
result = combiner(term(a), result)
return result
print(accumulate_iter(lambda x, y: x * y, lambda x: x * x, 1, lambda x: x + 1, 5))
Output:
14400
You could also get rid of the extra loop iteration completely so you don't need the extra (x<=y) test:
def accumulate_iter(combiner, term, a, next, b):
result = term(a)
a = next(a)
while a <= b:
result = combiner(term(a), result)
a = next(a)
return result
Note that this second version is more true to what's really going on. The loop "combines things", which means you need two things to combine, but you only pick up one new thing on each iteration. So it's natural to have a special case before the loop that deals with the first term and moves past it.

multiple values of a variable in same equation

A = [18.0,10.0]; B = [13.0,15.0]; C = [10.5,12.0];
these are the variables and think about function like
def hlf(A,B,C):
return A**(-1.0/2.0)-0.2*B-43+C
print "T:"
hlf(A,B,C)
Firstly, I want to use first values of the A B and C in the equation. After I want to use second values. How can I do this ?
map + list
Note map can take multiple iterable arguments:
res = map(hlf, A, B, C)
[-34.86429773960448, -33.68377223398316]
In Python 2.7, map returns a list. In Python 3.x map returns an iterator, so you can either iterate lazily or exhaust via list, i.e. list(map(hfl, A, B, C)).
Reference:
map(function, iterable, ...)
...If additional iterable arguments are passed, function must
take that many arguments and is applied to the items from all
iterables in parallel.
zip + list comprehension
You can use zip within a list comprehension. For clarity, you should avoid naming your arguments the same as your variables.
A = [18.0,10.0]; B = [13.0,15.0]; C = [10.5,12.0];
def hlf(x, y, z):
return x**(-1.0/2.0) - 0.2*y - 43 + z
res = [hlf(*vars) for vars in zip(A, B, C)]
[-34.86429773960448, -33.68377223398316]
Vectorize with Numpy. Best Performace
Normally its much better try to vectorize this kind of operations with numpy, because the best performance results. When you vectorize instead to use a loop, you are using all your cores, and its the fastest solution. You should vectorize the operation with numpy. Something like this:
import numpy as np
A = [18.0,10.0]; B = [13.0,15.0]; C = [10.5,12.0];
a = np.array(A)
b = np.array(B)
c = np.array(C)
And now your function with the new vectors like arguments:
def hlf(a_vector,b_vector,c_vector):
return a_vector**(-1.0/2.0)-0.2*b_vector-43+c_vector
And finally call your new function vectorized:
print (hlf(a_vector = a,b_vector = b,c_vector = c))
Output:
>>> array([-34.86429774, -33.68377223])
If you want to keep your function as is, you should call it N times with:
for i in range(N):
result = hlf(A[i], B[i], C[i])
print(result)
Another interesting method is to make a generator with your function:
A = [18.0,10.0]
B = [13.0,15.0]
C = [10.5,12.0];
def hlf(*args):
i=0
while i < len(args[0]):
yield args[0][i]**(-1.0/2.0) - 0.2*args[1][i] - 43 + args[2][i]
i += 1
results = hlf(A, B, C)
for r in results:
print(r)
Output:
-34.86429773960448
-33.68377223398316
Last one is rather edicational if you want to practice python generators.

Fibonacci numbers, with an one-liner in Python 3?

I know there is nothing wrong with writing with proper function structure, but I would like to know how can I find nth fibonacci number with most Pythonic way with a one-line.
I wrote that code, but It didn't seem to me best way:
>>> fib = lambda n:reduce(lambda x, y: (x[0]+x[1], x[0]), [(1,1)]*(n-2))[0]
>>> fib(8)
13
How could it be better and simplier?
fib = lambda n:reduce(lambda x,n:[x[1],x[0]+x[1]], range(n),[0,1])[0]
(this maintains a tuple mapped from [a,b] to [b,a+b], initialized to [0,1], iterated N times, then takes the first tuple element)
>>> fib(1000)
43466557686937456435688527675040625802564660517371780402481729089536555417949051
89040387984007925516929592259308032263477520968962323987332247116164299644090653
3187938298969649928516003704476137795166849228875L
(note that in this numbering, fib(0) = 0, fib(1) = 1, fib(2) = 1, fib(3) = 2, etc.)
(also note: reduce is a builtin in Python 2.7 but not in Python 3; you'd need to execute from functools import reduce in Python 3.)
A rarely seen trick is that a lambda function can refer to itself recursively:
fib = lambda n: n if n < 2 else fib(n-1) + fib(n-2)
By the way, it's rarely seen because it's confusing, and in this case it is also inefficient. It's much better to write it on multiple lines:
def fibs():
a = 0
b = 1
while True:
yield a
a, b = b, a + b
I recently learned about using matrix multiplication to generate Fibonacci numbers, which was pretty cool. You take a base matrix:
[1, 1]
[1, 0]
and multiply it by itself N times to get:
[F(N+1), F(N)]
[F(N), F(N-1)]
This morning, doodling in the steam on the shower wall, I realized that you could cut the running time in half by starting with the second matrix, and multiplying it by itself N/2 times, then using N to pick an index from the first row/column.
With a little squeezing, I got it down to one line:
import numpy
def mm_fib(n):
return (numpy.matrix([[2,1],[1,1]])**(n//2))[0,(n+1)%2]
>>> [mm_fib(i) for i in range(20)]
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181]
This is a closed expression for the Fibonacci series that uses integer arithmetic, and is quite efficient.
fib = lambda n:pow(2<<n,n+1,(4<<2*n)-(2<<n)-1)%(2<<n)
>> fib(1000)
4346655768693745643568852767504062580256466051737178
0402481729089536555417949051890403879840079255169295
9225930803226347752096896232398733224711616429964409
06533187938298969649928516003704476137795166849228875L
It computes the result in O(log n) arithmetic operations, each acting on integers with O(n) bits. Given that the result (the nth Fibonacci number) is O(n) bits, the method is quite reasonable.
It's based on genefib4 from http://fare.tunes.org/files/fun/fibonacci.lisp , which in turn was based on an a less efficient closed-form integer expression of mine (see: http://paulhankin.github.io/Fibonacci/)
If we consider the "most Pythonic way" to be elegant and effective then:
def fib(nr):
return int(((1 + math.sqrt(5)) / 2) ** nr / math.sqrt(5) + 0.5)
wins hands down. Why use a inefficient algorithm (and if you start using memoization we can forget about the oneliner) when you can solve the problem just fine in O(1) by approximation the result with the golden ratio? Though in reality I'd obviously write it in this form:
def fib(nr):
ratio = (1 + math.sqrt(5)) / 2
return int(ratio ** nr / math.sqrt(5) + 0.5)
More efficient and much easier to understand.
This is a non-recursive (anonymous) memoizing one liner
fib = lambda x,y=[1,1]:([(y.append(y[-1]+y[-2]),y[-1])[1] for i in range(1+x-len(y))],y[x])[1]
fib = lambda n, x=0, y=1 : x if not n else fib(n-1, y, x+y)
run time O(n), fib(0) = 0, fib(1) = 1, fib(2) = 1 ...
I'm Python newcomer, but did some measure for learning purposes. I've collected some fibo algorithm and took some measure.
from datetime import datetime
import matplotlib.pyplot as plt
from functools import wraps
from functools import reduce
from functools import lru_cache
import numpy
def time_it(f):
#wraps(f)
def wrapper(*args, **kwargs):
start_time = datetime.now()
f(*args, **kwargs)
end_time = datetime.now()
elapsed = end_time - start_time
elapsed = elapsed.microseconds
return elapsed
return wrapper
#time_it
def fibslow(n):
if n <= 1:
return n
else:
return fibslow(n-1) + fibslow(n-2)
#time_it
#lru_cache(maxsize=10)
def fibslow_2(n):
if n <= 1:
return n
else:
return fibslow_2(n-1) + fibslow_2(n-2)
#time_it
def fibfast(n):
if n <= 1:
return n
a, b = 0, 1
for i in range(1, n+1):
a, b = b, a + b
return a
#time_it
def fib_reduce(n):
return reduce(lambda x, n: [x[1], x[0]+x[1]], range(n), [0, 1])[0]
#time_it
def mm_fib(n):
return (numpy.matrix([[2, 1], [1, 1]])**(n//2))[0, (n+1) % 2]
#time_it
def fib_ia(n):
return pow(2 << n, n+1, (4 << 2 * n) - (2 << n)-1) % (2 << n)
if __name__ == '__main__':
X = range(1, 200)
# fibslow_times = [fibslow(i) for i in X]
fibslow_2_times = [fibslow_2(i) for i in X]
fibfast_times = [fibfast(i) for i in X]
fib_reduce_times = [fib_reduce(i) for i in X]
fib_mm_times = [mm_fib(i) for i in X]
fib_ia_times = [fib_ia(i) for i in X]
# print(fibslow_times)
# print(fibfast_times)
# print(fib_reduce_times)
plt.figure()
# plt.plot(X, fibslow_times, label='Slow Fib')
plt.plot(X, fibslow_2_times, label='Slow Fib w cache')
plt.plot(X, fibfast_times, label='Fast Fib')
plt.plot(X, fib_reduce_times, label='Reduce Fib')
plt.plot(X, fib_mm_times, label='Numpy Fib')
plt.plot(X, fib_ia_times, label='Fib ia')
plt.xlabel('n')
plt.ylabel('time (microseconds)')
plt.legend()
plt.show()
The result is usually the same.
Fiboslow_2 with recursion and cache, Fib integer arithmetic and Fibfast algorithms seems the best ones. Maybe my decorator not the best thing to measure performance, but for an overview it seemed good.
Another example, taking the cue from Mark Byers's answer:
fib = lambda n,a=0,b=1: a if n<=0 else fib(n-1,b,a+b)
I wanted to see if I could create an entire sequence, not just the final value.
The following will generate a list of length 100. It excludes the leading [0, 1] and works for both Python2 and Python3. No other lines besides the one!
(lambda i, x=[0,1]: [(x.append(x[y+1]+x[y]), x[y+1]+x[y])[1] for y in range(i)])(100)
Output
[1,
2,
3,
...
218922995834555169026,
354224848179261915075,
573147844013817084101]
Here's an implementation that doesn't use recursion, and only memoizes the last two values instead of the whole sequence history.
nthfib() below is the direct solution to the original problem (as long as imports are allowed)
It's less elegant than using the Reduce methods above, but, although slightly different that what was asked for, it gains the ability to to be used more efficiently as an infinite generator if one needs to output the sequence up to the nth number as well (re-writing slightly as fibgen() below).
from itertools import imap, islice, repeat
nthfib = lambda n: next(islice((lambda x=[0, 1]: imap((lambda x: (lambda setx=x.__setitem__, x0_temp=x[0]: (x[1], setx(0, x[1]), setx(1, x0_temp+x[1]))[0])()), repeat(x)))(), n-1, None))
>>> nthfib(1000)
43466557686937456435688527675040625802564660517371780402481729089536555417949051
89040387984007925516929592259308032263477520968962323987332247116164299644090653
3187938298969649928516003704476137795166849228875L
from itertools import imap, islice, repeat
fibgen = lambda:(lambda x=[0,1]: imap((lambda x: (lambda setx=x.__setitem__, x0_temp=x[0]: (x[1], setx(0, x[1]), setx(1, x0_temp+x[1]))[0])()), repeat(x)))()
>>> list(islice(fibgen(),12))
[1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144]
def fib(n):
x =[0,1]
for i in range(n):
x=[x[1],x[0]+x[1]]
return x[0]
take the cue from Jason S, i think my version have a better understanding.
Starting Python 3.8, and the introduction of assignment expressions (PEP 572) (:= operator), we can use and update a variable within a list comprehension:
fib = lambda n,x=(0,1):[x := (x[1], sum(x)) for i in range(n+1)][-1][0]
This:
Initiates the duo n-1 and n-2 as a tuple x=(0, 1)
As part of a list comprehension looping n times, x is updated via an assignment expression (x := (x[1], sum(x))) to the new n-1 and n-2 values
Finally, we return from the last iteration, the first part of the x
To solve this problem I got inspired by a similar question here in Stackoverflow Single Statement Fibonacci, and I got this single line function that can output a list of fibonacci sequence. Though, this is a Python 2 script, not tested on Python 3:
(lambda n, fib=[0,1]: fib[:n]+[fib.append(fib[-1] + fib[-2]) or fib[-1] for i in range(n-len(fib))])(10)
assign this lambda function to a variable to reuse it:
fib = (lambda n, fib=[0,1]: fib[:n]+[fib.append(fib[-1] + fib[-2]) or fib[-1] for i in range(n-len(fib))])
fib(10)
output is a list of fibonacci sequence:
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
I don't know if this is the most pythonic method but this is the best i could come up with:->
Fibonacci = lambda x,y=[1,1]:[1]*x if (x<2) else ([y.append(y[q-1] + y[q-2]) for q in range(2,x)],y)[1]
The above code doesn't use recursion, just a list to store the values.
My 2 cents
# One Liner
def nthfibonacci(n):
return long(((((1+5**.5)/2)**n)-(((1-5**.5)/2)**n))/5**.5)
OR
# Steps
def nthfibonacci(nth):
sq5 = 5**.5
phi1 = (1+sq5)/2
phi2 = -1 * (phi1 -1)
n1 = phi1**(nth+1)
n2 = phi2**(nth+1)
return long((n1 - n2)/sq5)
Why not use a list comprehension?
from math import sqrt, floor
[floor(((1+sqrt(5))**n-(1-sqrt(5))**n)/(2**n*sqrt(5))) for n in range(100)]
Without math imports, but less pretty:
[int(((1+(5**0.5))**n-(1-(5**0.5))**n)/(2**n*(5**0.5))) for n in range(100)]
import math
sqrt_five = math.sqrt(5)
phi = (1 + sqrt_five) / 2
fib = lambda n : int(round(pow(phi, n) / sqrt_five))
print([fib(i) for i in range(1, 26)])
single line lambda fibonacci but with some extra variables
Similar:
def fibonacci(n):
f=[1]+[0]
for i in range(n):
f=[sum(f)] + f[:-1]
print f[1]
A simple Fibonacci number generator using recursion
fib = lambda x: 1-x if x < 2 else fib(x-1)+fib(x-2)
print fib(100)
This takes forever to calculate fib(100) in my computer.
There is also closed form of Fibonacci numbers.
fib = lambda n: int(1/sqrt(5)*((1+sqrt(5))**n-(1-sqrt(5))**n)/2**n)
print fib(50)
This works nearly up to 72 numbers due to precision problem.
Lambda with logical operators
fibonacci_oneline = lambda n = 10, out = []: [ out.append(i) or i if i <= 1 else out.append(out[-1] + out[-2]) or out[-1] for i in range(n)]
here is how i do it ,however the function returns None for the list comprehension line part to allow me to insert a loop inside ..
so basically what it does is appending new elements of the fib seq inside of a list which is over two elements
>>f=lambda list,x :print('The list must be of 2 or more') if len(list)<2 else [list.append(list[-1]+list[-2]) for i in range(x)]
>>a=[1,2]
>>f(a,7)
You can generate once a list with some values and use as needed:
fib_fix = []
fib = lambda x: 1 if x <=2 else fib_fix[x-3] if x-2 <= len(fib_fix) else (fib_fix.append(fib(x-2) + fib(x-1)) or fib_fix[-1])
fib_x = lambda x: [fib(n) for n in range(1,x+1)]
fib_100 = fib_x(100)
than for example:
a = fib_fix[76]

Categories

Resources