How to commute two operators in python? - python

Let's say I have operator A and operator B which act on f(x) = 2x for example. How do I create a function that says whether A(B(f(x))) == B(A(f(x))) in python?
Here is my attempt:
#Commutation: Creating a function that checks whether operators A and B commutate on some dummy function f(x) = 2*x
#[A,B](2x) =?= 0
def commutate(A,B):
f = lambda x: 2*x
if lambda x: A(B(f)) - B(A(f)) == 0:
print('A and B commute!')
else:
print('A and B do not commute!')
A = lambda x: f(x)**2
B = lambda x: np.log(f(x))
commutate(A,B)
The issue is that I'm always getting that the operators A and B commute, even when giving Operators that don't. I suspect this might have to do with the fact that I can't Define operators like that in python?

In general, it is not possible, based on Rice theorem. Because you desire to check a non-trivial property for two pieces of code, i.e., the property is commutativeness and piece of code here means functions. Hence, it proves that deciding that "any given f and g functions are commutative" is undecidable. Therefore, you can't write such a function to check the commutativeness for two functions.

In your code you have the line
if lambda x: A(B(f)) - B(A(f)) == 0:
In this line you are generating a lambda that is calling the operators on the address of f rather than a result of calling f. Also, you are not calling the lambda that you define in the if statement, so you are checking if the address of the lambda function is True/False which is not what you are looking for.
Lambdas are just functions, but you could test if the operators are commutative on a specific value:
def commutate(A, B, value):
f = lambda x: 2 * x
if A(B(f(value))) == B(A(f(value))):
print(f"A and B commute on value {value}!")
else:
print(f"A and B do not commute on value {value}!")

Related

What is the mechanism behind a function that contains a lambda expression? (Python)

During a tutorial I stumbled upon the following example.
I get the general purpose and mechanism of functions. They get parameters such as "a", "b" and "c" (example below).
But how come that we can "link" the function to an object f that itself can contain 0 as parameters that will then be computed by our lambda expression?
def build_quadratic_function(a,b,c):
return lambda x: a*x**2 + b*x+c
f = build_quadratic_function(2,3,-5)
f(0)
yields:
-5
In layman words, how does the function "know" that 0 must be read by the lambda expression that is contained in the function?
Can somebody explain the mechanism behind it?
Thank you!
def build_quadratic_function(a,b,c):
return lambda x: a*x**2 + b*x + c
is (in all important aspects) equivalent to
def build_quadratic_function(a,b,c):
def func(x):
return a*x**2 + b*x + c
return func
In both cases, the inner function, be it an anonymous one or not, is holding onto the variables in the enclosing scope. You have discovered so called closures.
>>> import inspect
>>> f = build_quadratic_function(2, 3, -5)
>>> inspect.getclosurevars(f)
ClosureVars(nonlocals={'a': 2, 'b': 3, 'c': -5}, globals={}, builtins={}, unbound=set())
A very similar example can be found in the documentation.
Lambdas are small anonymous functions. They can be used wherever function objects are required. They are syntactically restricted to a single expression. Semantically, they are just syntactic sugar for a normal function definition. Like nested function definitions, lambda functions can reference variables from the containing scope.
Therefore if you define a custom function that contains a lambda, and then fix its parameters, it's essentially the same as defining a lambda function and then passing the expression.
For the sake of your example:
def build_quadratic_function(a,b,c):
return lambda x: a*x**2 + b*x+c
f = build_quadratic_function(2,3,-5)
Would create the same output as:
f = lambda x: 2*x**2 + 3*x - 5
In either case, when you call f(0) then the expression gets evaluated with value 0 returning -5.
2*0**2 + 3*0 - 5 = - 5
The improvement using a custom function over the simple definition of the lambda itself is you can modify the a, b and c parameters.
This isn't a lambda specific thing. Its a "closure" and can be done with a regular function also. In fact, a lambda is just an anonymous function. Its it restricted to implementing an expression instead of full python statements, but that's only the case because of python parsing issues. So, this is the same thing
def build_quadratic_function(a,b,c):
def inner(x):
return a*x**2 + b*x+c
return inner
inner uses variables from the enclosing function. When build_quadratic_function returns inner, the current objects in a, b and c are bound to inner. Later, when inner(someval) is called, those bound objects to a, b and c are used. x, which is a parameter to inner needs to be supplied on each call.
You can get the inner function once and use it many times with the same values.
func = build_quadratic_function(1,2,3)
for i in range(10):
print(func(i))
A lambda function is a small anonymous function. (function with no name)
f = build_quadratic_function(2,3,-5)
Till this point, f is equal to the return value of build_quadratic_function, which is another function(lambda in this case)!
f(0) calls the lambda which is waiting

Control Structures and Functions inside lambda

Create a lambda function greater, which takes two arguments x and y and return x if x>y otherwise y. input value is (9,3)
greater= lambda a,b:a>b
if a>b:
print(a)
else:
return b
print(greater(a,b))
File "/code/source.py3", line 11
return b
^
SyntaxError: 'return' outside function
Even I am getting error in return statement.
I have to only get the output as value but I am getting value with True.
Use if - else in lambda:
greater = lambda a, b: a if a > b else b
and call it as:
greater(9, 13)
Problems with your code:
Your lambda function just compares two variables and returns a True / False.
You used return outside a function which is not allowed. (Btw, there is no need of explicit if - else outside lambda when you can do within).
You don't return from a lambda function.
greater = lambda a,b: a if a > b else b
print(greater(3,4))
You can use ternary operators (a if a > b else c) in lambdas but control structures require the def keyword
Also, there is no return in a lambda function
Use a ternary if in your lambda:
greater = lambda x,y: x if x>y else y
greater(1,3) # 3
greater(4,3) # 4
Small anonymous functions can be created with the lambda keyword. Lambda functions can be used wherever function objects are required. They are syntactically restricted to a single expression.
Read more.
Solution without using ternary expression:
greater = lambda a, b: (a, b)[a<b]
a<b returns the boolean value False if a is greater than, or equal to, b, and True if a is smaller than b. We use the boolean value (basically representing 0 or 1) as an index to the tuple (a, b) to return our desired result.

if and else in python lambda expression

Please help me to understand how this works. Output is 4
a=4
b=7
x=lambda: a if 1 else b
lambda x: 'big' if x > 100 else 'small'
print(x())
First, let's remove this line as it doesn't do anything:
lambda x: 'big' if x > 100 else 'small'
This lambda expression is defined but never called. The fact that it's argument is also called x has nothing to do with the rest of the code.
Let's look at what remains:
a = 4
b = 7
x = lambda: a if 1 else b
print(x())
Here x becomes a function as it contains code. The lambda form can only contain expressions, not statements, so it has to use the expression form of if which is backward looking:
true-result if condition else false-result
In this case the condition is 1, which is always true, so the result of the function x() is always the value of a, assigned to 4 earlier in the code. Effectively, x() acts like:
def x():
return a
Understanding the differences between expressions and statements is key to understanding code like this.
Your x is always equals to 4, as it takes no arguments and if 1 is always True.
Then you have lambda expression that's not assigned to any variable, neither used elsewhere.
Eventualy, you print out x, which is always 4 as I said above.
P.S. I strongly suggest you to read Using lambda Functions from Dive into Python
Let me translate that for you.
You assign to x a lambda function with no arguments. Because 1 always evaluates as true, you always return the externally defined variable a, which evaluates as 4.
Then, you create a lambda function with one argument x, which you don't assign to a variable/access name, so it is lost forever.
Then, you call function x, which always returns a. Output is 4.

Python: Understanding unfamiliar function syntax (from UC Berkeley CS61A)

I can't do most parts of this question without peeking at the answer key, so I figured I could ask it here. Frankly, I've always had a problem understanding functions with no parameters, and whenever I see one, I think, "OH! they must mean "print" function!" When I'm actually overcomplicating things.
As for Exercise 5, I'm not understanding how to even evaluate the expressions. I feel like it's a simple question, but I can't compute an answer to any of them.
Exercise 4: A Fistful of Functions
For each of the following expressions, what must f be in order for the evaluation of the expression to succeed, without causing an error? Give a definition of f for each expression such that evaluating the expression will not cause an error.
f
f()
f(3)
f()()
f()(3)()
Solution
f = 3
f = lambda: 3
f = lambda x: x
f = lambda: lambda: 3
f = lambda: lambda x: lambda: x
Exercise 5: For A Few Lambdas More
Find the value of the following three expressions, using the given values of t and s.
t = lambda f: lambda x: f(f(f(x)))
s = lambda x: x + 1
t(s)(0) # 1
t(t(s))(0) # 2
t(t)(s)(0) # 3
Solution
1.) 3
2.) 9
3.) 27
For Exercise 4, you are given the following questions and answers.
Q: f
A: f = 3
This is essentially variable assignment.
Q: f()
A: f = lambda: 3
This is similar to a function that takes in no arguments and returns the value 3.
Q: f(3)
A: f = lambda x: x
This is similar to a function that takes in the argument x and returns the value x. So you are given the value 3 and a value of 3 is returned.
Q: f()()
A: f = lambda: lambda: 3
This is similar to a function that takes in no arguments and returns another function that again takes no arguments which will return the value 3.
Q: f()(3)()
A: f = lambda: lambda x: lambda: x
Like the previous example, this will return 3. You have function that takes in no arguments but returns another function that takes in the value x and returns another function that takes in no arguments but returns the value x.
By following the examples above, you can solve Exercise 5 in a similar fashion.
Additionally, Exercise 5 has been explained pretty well in the comments by ChrisP.

recursive lambda-expressions possible?

I'm trying to write a lambda-expression that calls itself, but i can't seem to find any syntax for that, or even if it's possible.
Essentially what I wanted to transfer the following function into the following lambda expression: (I realize it's a silly application, it just adds, but I'm exploring what I can do with lambda-expressions in python)
def add(a, b):
if a <= 0:
return b
else:
return 1 + add(a - 1, b)
add = lambda a, b: [1 + add(a-1, b), b][a <= 0]
but calling the lambda form of add results in a runtime error because the maximum recursion depth is reached. Is it even possible to do this in python? Or am I just making some stupid mistake? Oh, I'm using python3.0, but I don't think that should matter?
Maybe you need a Y combinator?
Edit - make that a Z combinator (I hadn't realized that Y combinators are more for call-by-name)
Using the definition of the Z combinator from Wikipedia
>>> Z = lambda f: (lambda x: f(lambda *args: x(x)(*args)))(lambda x: f(lambda *args: x(x)(*args)))
Using this, you can then define add as a completely anonymous function (ie. no reference to its name in its definition)
>>> add = Z(lambda f: lambda a, b: b if a <= 0 else 1 + f(a - 1, b))
>>> add(1, 1)
2
>>> add(1, 5)
6
Perhaps you should try the Z combinator, where this example is from:
>>> Z = lambda f: (lambda x: f(lambda *args: x(x)(*args)))(lambda x: f(lambda *args: x(x)(*args)))
>>> fact = lambda f: lambda x: 1 if x == 0 else x * f(x-1)
>>> Z(fact)(5)
120
First of all recursive lambda expressions are completely unnecessary. As you yourself point out, for the lambda expression to call itself, it needs to have a name. But lambda expressions is nothing else than anonymous functions. So if you give the lambda expression a name, it's no longer a lambda expression, but a function.
Hence, using a lambda expression is useless, and will only confuse people. So create it with a def instead.
But yes, as you yourself discovered, lambda expressions can be recursive. Your own example is. It's in fact so fantastically recursive that you exceed the maximum recursion depth. So it's recursive alright. Your problem is that you always call add in the expression, so the recursion never stops. Don't do that. Your expression can be expressed like this instead:
add = lambda a, b: a > 0 and (1 + add(a-1, b)) or b
Which takes care of that problem. However, your first def is the correct way of doing it.
add = lambda a, b: b if a <= 0 else 1 + add(a - 1, b)
You want the Y combinator, or some other fixed point combinator.
Here's an example implementation as a Python lambda expression:
Y = lambda g: (lambda f: g(lambda arg: f(f)(arg))) (lambda f: g(lambda arg: f(f)(arg)))
Use it like so:
factorial = Y(lambda f: (lambda num: num and num * f(num - 1) or 1))
That is, you pass into Y() a single-argument function (or lambda), which receives as its argument a recursive version of itself. So the function doesn't need to know its own name, since it gets a reference to itself instead.
Note that this does get tricky for your add() function because the Y combinator only supports passing a single argument. You can get more arguments by currying -- but I'll leave that as an exercise for the reader. :-)
a little late ... but I just found this gem # http://metapython.blogspot.com/2010/11/recursive-lambda-functions.html
def myself (*args, **kw):
caller_frame = currentframe(1)
code = caller_frame.f_code
return FunctionType(code, caller_frame.f_globals)(*args,**kw)
print "5! = "
print (lambda x:1 if n <= 1 else myself(n-1)*n)(5)

Categories