Composite functions in python - dual compose - python

I came across the following homework problem:
My code for this problem was marked wrong and when I viewed the suggested solution, I couldn't understand where I went wrong. I ran the codes of both functions in Python IDLE compiler only to see that both functions return the same output as seen below:
>>> def dual_function(f,g,n): #Suggested solution
def helper(x):
f1,g1 = f,g
if n%2==0:
f1,g1=g1,f1
for i in range(n):
x=f1(x)
f1,g1=g1,f1
return x
return helper
>>> def dual_function_two(f,g,n): #My solution
def helper(x):
if n%2==0:
for i in range (n):
if i%2==0:
x = g(x)
else:
x = f(x)
else:
for i in range(n):
if i%2==0:
x = f(x)
else:
x = g(x)
return x
return helper
>>> add1 = lambda x: x+1
>>> add2 = lambda x: x+2
>>> dual_function(add1,add2,4)(3)
9
>>> dual_function_two(add1,add2,4)(3)
9
>>>
I would appreciate it if someone could identify the mistake in my solution. Thank you.

The suggested solution is needlessly complex. Countless reassignments of variables and a loop are a recipe for a headache. Here's a simplified alternative -
def dual (f, g, n):
if n == 0:
return lambda x: x
else:
return lambda x: f(dual(g, f, n - 1)(x))
add1 = lambda x: 1 + x
add2 = lambda x: 2 + x
print(dual(add1,add2,4)(3))
# 9
# (1 + 2 + 1 + 2 + 3)
print(dual(add1,add2,9)(3))
# 16
# (1 + 2 + 1 + 2 + 1 + 2 + 1 + 2 + 1 + 3)
print(dual(add1,add2,0)(3))
# 3
The reason this works is because in the recursive branch, we call dual with swapped arguments, dual(g,f,n-1). So f and g change places each time as n decrements down to 0, the base case, which returns the identity (no-op) function.
A slightly less readable version, but works identically -
def dual (f, g, n):
return lambda x: \
x if n == 0 else f(dual(g, f, n - 1)(x))

Related

Loop a function using the previous output as input

When my function foo generating a new element, I want to reuse the output and put it in foo n-times. How can I do it?
My function:
def foo(x):
return x + 3
print(foo(1))
>>>4
For now. I'm using this method:
print(foo(foo(foo(1))))
There are a couple ways to do what you want. First is recursion, but this involves changing foo() a bit, like so:
def foo(x, depth):
if depth <= 0:
return x
return foo(x+3, depth-1)
and you'd call it like foo(1, n)
The other way is with a loop and temp variable, like so
val = 1
for _ in range(0, n):
val = foo(val)
Use a loop for this:
value = 1
for i in range(10):
value = foo(value)
def foo(x,y):
for i in range(y):
x = x + 3
return x
print (foo(10,3))
Output:
19
What you are searching for is called recursion:
def foo(x, n=1):
if n == 0:
return x
return foo(x + 3, n - 1)
Another possible with lambda and reduce
Reduce function
from functools import reduce
def foo(x):
return x + 3
print(reduce(lambda y, _: foo(y), range(3), 1))
You will get 10 as result
# y = assigned return value of foo.
# _ = is the list of numbers from range(3) for reduce to work
# 3 = n times
# 1 = param for x in foo

How to compose a function n times in python

I know how to compose two functions by taking two functions as input and output its composition function but how can I return a composition function f(f(...f(x)))? Thanks
def compose2(f, g):
return lambda x: f(g(x))
def f1(x):
return x * 2
def f2(x):
return x + 1
f1_and_f2 = compose2(f1, f2)
f1_and_f2(1)
You use a loop, inside a nested function:
def compose(f, n):
def fn(x):
for _ in range(n):
x = f(x)
return x
return fn
fn will be have closure that retains references to the f and n that you called compose with.
Note this is mostly just copied from https://stackoverflow.com/a/16739439/2750819 but I wanted to make it clear how you can apply it for any one function n times.
def compose (*functions):
def inner(arg):
for f in reversed(functions):
arg = f(arg)
return arg
return inner
n = 10
def square (x):
return x ** 2
square_n = [square] * n
composed = compose(*square_n)
composed(2)
Output
179769313486231590772930519078902473361797697894230657273430081157732675805500963132708477322407536021120113879871393357658789768814416622492847430639474124377767893424865485276302219601246094119453082952085005768838150682342462881473913110540827237163350510684586298239947245938479716304835356329624224137216
if you want to make it one line composition,
then try this,
def f1(x):
return x * 2
def f2(x):
return x + 1
>>> out = lambda x, f=f1, f2=f2: f1(f2(x)) # a directly passing your input(1) with 2 function as an input (f1, f2) with default so you dont need to pass it as an arguments
>>> out(1)
4
>>>
>>> def compose(f1, n):
... def func(x):
... while n:
... x = f1(x)
... n = n-1
... return x
... return func
>>> d = compose(f1, 2)
>>> d(2)
8
>>> d(1)
4
>>>
you can use functools.reduce:
from functools import reduce
def compose(f1, f2):
return f2(f1)
reduce(compose, [1, f2, f1]) # f1(f2(1))
output:
4
if you want to compose same function n times:
n = 4
reduce(compose, [1, *[f1]*n]) # f1(f1(f1(f1(1))))
output:
16

How does this code work? Includes a lambda

Could any one explain the flow of this program by giving an example?
id_ = lambda x:x
// would return the number (id_(1) would return 1)
zero=map(number,0)//should return number= lambda 0: lambda 0:f(0)
So I am not able to interpret:
number = lambda x: lambda f=id_: f(x)
plus = lambda x: lambda y: y + x
id_ = lambda x: x
number = lambda x: lambda f=id_: f(x)
zero, one, two, three, four, five, six, seven, eight, nine = map(number, range(10))
plus = lambda x: lambda y: y + x
minus = lambda x: lambda y: y - x
times = lambda x: lambda y: y * x
divided_by = lambda x: lambda y: y / x
Calculations using functions:
one(plus(one()))
> 2
number():
- expects a number "A"
- returns a function "F" that expects a single argument function (or if not provided it uses "id_" by default)
When both arguments are provided the function number() gets evaluated and applies the function F to the number A
# Example 1: returns only 3 (applies "id_" by default)
print(number(3)())
Prints:
3
And when a function is provided:
def inc(x):
return x + 1
# Example 2: applies a single argument function to the number 3
print(number(3)(inc))
Which returns:
4
So now the second function you are interested in:
plus():
- expects a number
- returns a function that accept another number
When both arguments are provided the function is evaluated and returns their sum.
# Example:
print(plus(3)(4))
Prints:
7
Using the example you used in the comments:
one(plus(one()))
Starting from the innermost expression we get:
one() == 1 because one() == number(1)(f=id_) == _id(1)
Second call to plus(1) would return lambda y: y+1
Applied to the result from first step, plus(one()) == plus(1) == lambda y: y+1
So it means that plus(one()) is (in other words: "returns") itself a function and is equivalent to:
def plus_one(y):
return y + 1
Last step:
one(plus(one())) == one(plus_one) == number(1)(f=plus_one) == plus_one(1) == 1 + 1 == 2
If the lambda syntax bothers you, you can rewrite them for increased clarity (?) into full functions accordingly:
def id_(x):
return x
def number(x):
def inner(f=id_):
return f(x)
return inner
def one(f=id_):
return f(1)
def plus(x):
def add_to_x(y):
return y + x
return add_to_x
add_one = plus(one())
assert one() == number(1)(f=id_) == id_(1) == 1
assert add_one(2) == plus(1)(2) == 3
assert plus(one())(4) == plus(1)(4) == 5
assert one(plus(one())) == one(add_one) == 2

Sum of n lambda functions

I have a list of lambda functions. Lets say this one
l = [lambda x:x**i for i in range(n)]
For every n I need to be able to sum them so I'd have a function like this:
f = lambda x: x + x**2 + x**3 + ... + x**n
Is there any way?
Edit: I wasn't clear. I don't know anything about that functions.
Is this the solution you're looking for?
Python 3.x:
n = 5
g = lambda y: sum( f(y) for f in (lambda x: x**i for i in range(n)) )
print(g(5)) # 781
Python 2.x:
n = 5
g = lambda y: sum( f(y) for f in (lambda x: x**i for i in xrange(n)) )
print g(5) # 781
If you mean a finite sum, up to x**n, use the mathematical shortcut
f = lambda x: (x**(n+1) - 1) / (x - 1) if x != 1 else n
f = lambda x,n: sum( x**i for i in range(n) )
print f(3,4)
>> 40
The simplest way to do this is to avoid creating the list of lambda functions, and to instead sum over a single function. Assuming you've defined x and n, you can do:
f = lambda x, i: x**i
sum(f(x, i) for i in range(n))
In your original example, you have actually created a closure, so your lambda functions do not do what you think they do. Instead, they are all identical, since they all use the final value of i in the closure. That is certainly not what you intended.
n=5
xpower=[]
for i in range(n):
xpower.insert(i, i+1)
print(i,xpower)
f = lambda x, xpower: sum(x**xpower[i] for i in range(len(xpower)))
print("Example with n=5, x=2:"," ", f(2,xpower))

Repeat function python

I'm stuck at higher-order functions in python. I need to write a repeat function repeat that applies the function f n times on a given argument x.
For example, repeat(f, 3, x) is f(f(f(x))).
This is what I have:
def repeat(f,n,x):
if n==0:
return f(x)
else:
return repeat(f,n-1,x)
When I try to assert the following line:
plus = lambda x,y: repeat(lambda z:z+1,x,y)
assert plus(2,2) == 4
It gives me an AssertionError. I read about How to repeat a function n times but I need to have it done in this way and I can't figure it out...
You have two problems:
You are recursing the wrong number of times (if n == 1, the function should be called once); and
You aren't calling f on the returned value from the recursive call, so the function is only ever applied once.
Try:
def repeat(f, n, x):
if n == 1: # note 1, not 0
return f(x)
else:
return f(repeat(f, n-1, x)) # call f with returned value
or, alternatively:
def repeat(f, n, x):
if n == 0:
return x # note x, not f(x)
else:
return f(repeat(f, n-1, x)) # call f with returned value
(thanks to #Kevin for the latter, which supports n == 0).
Example:
>>> repeat(lambda z: z + 1, 2, 2)
4
>>> assert repeat(lambda z: z * 2, 4, 3) == 3 * 2 * 2 * 2 * 2
>>>
You've got a very simple error there, in the else block you are just passing x along without doing anything to it. Also you are applying x when n == 0, don't do that.
def repeat(f,n,x):
"""
>>> repeat(lambda x: x+1, 2, 0)
2
"""
return repeat(f, n-1, f(x)) if n > 0 else x

Categories

Resources