Producing combinations of lambda functions compositions - python

I am facing a challenging issue in order to make my Python3 code more elegant.
Suppose I have a number function with variable number of different inputs, for example something like this:
def fun1(a,b):
return a+b
def fun2(c,d,e):
return c*d + e
def fun3(x):
return x*x
These functions needs to be agglomerated in a single function that needs to be used as the optimization function of a numerical solver.
However I need to create different combinations of various operations with these functions, like for example multiplying the output of the first two functions and summing by the third.
The manual solution is to create a specific lambda function:
fun = lambda x : fun1(x[0],x[1])*fun2(x[2],x[3],x[4]) + fun3(x[4])
but the number of functions I have is large and I need to produce all the possibile combinations of them.
I would like to systematically be able to compose these functions and always knowing the mapping from the arguments of higher level function fun to the lower level arguments of each single function.
In this case I manually specified that x[0] corresponds to the argument a of fun1, x[1] corresponds to argument b of fun1 etcetera.
Any idea?

It sounds like you are trying to do what is known as symbolic regression. This problem is often solved via some variation on genetic algorithms which encode the functional relationships in the genes and then optimise based on a fitness function which includes the prediction error as well as a term which penalises more complicated relationships.
Here are two libraries which solve this problem for you:
GPLearn
dcgpy
The following classes provide a rudimentary way of composing functions and keeping track of the number of arguments each one requires, which appears to be the main problem you have:
class Wrapper:
def __init__(self, f):
self.f = f
self.n = f.__code__.co_argcount
def __call__(self, x):
return self.f(*x)
def __add__(self, other):
return Add(self, other)
def __mul__(self, other):
return Mul(self, other)
class Operator:
def __init__(self, left, right):
self.left = left
self.right = right
self.n = left.n + right.n
class Mul(Operator):
def __call__(self, x):
return self.left(x[:self.left.n]) * self.right(x[self.left.n:])
class Add(Operator):
def __call__(self, x):
return self.left(x[:self.left.n]) + self.right(x[self.left.n:])
To use them, you first create wrappers for each of your functions:
w1 = Wrapper(fun1)
w2 = Wrapper(fun2)
w3 = Wrapper(fun3)
Then you can add and multiply the wrappers to get a new function-like object:
(w1 + w2*w3)([1, 2, 3, 4, 5, 6])

This could be a solution:
def fun1(a,b):
return a+b
def fun2(c,d,e):
return c+d+e
def compose(f1,f2):
n1 = len(f1.__code__.co_varnames)
n2 = len(f2.__code__.co_varnames)
F1 = lambda x : f1(*[x[i] for i in range(0,n1)])*f2(*[x[i] for i in range(n1,n1+n2)])
return F1
print(compose(fun1,fun2)([1,2,3,4,5]))

Related

Ways to define and use partially bound functions

The two ways I'm aware of to have a partially-bound function that can be later called is:
apply_twice = lambda f: lambda x: f(f(x))
square2x = apply_twice(lambda x: x*x)
square2x(2)
# 16
And
def apply_twice(f):
def apply(x):
return f(f(x))
return apply
square_2x=apply_twice(lambda x: x*x)
square_2x(4)
# 256
Are there any other common ways to pass around or use partially-bound functions?
functools.partial can be used to partially apply an ordinary Python function. This is especially useful if you already have a regular function and want to apply only some of the arguments.
from functools import partial
def apply_twice(f, x):
return f(f(x))
square2x = partial(apply_twice, lambda x: x*x)
print(square2x(4))
It's also important to remember that functions are only one type of callable in Python, and we're free to define callables ourselves as ordinary user-defined classes. So if you have some complex operation that you want to behave like a function, you can always write a class, which lets you document in more detail what it is and what the different parts mean.
class MyApplyTwice:
def __init__(self, f):
self.f = f
def __call__(self, x):
return self.f(self.f(x))
square2x = MyApplyTwice(lambda x: x*x)
print(square2x(4))
While overly verbose in this example, it can be helpful to write your function out as a class if it's going to be storing state long-term or might be doing confusing mutable things with its state. It's also useful to keep in mind for learning purposes, as it's a healthy reminder that closures and objects are two sides of the same coin. They're really the same thing, viewed in a different light.
You can also do this with functools.partial():
def apply_twice(f, x):
return f(f(x))
square_2x = functools.partial(apply_twice, lambda x: x*x)
This isn't really partial binding, assuming you mean partial application.
Partial application is when you create a function that does the same thing as another function by fixing some number of its arguments, producing a function of smaller arity (the arity of a function is the number of arugments it takes).
So, for example,
def foo(a, b, c):
return a + b + c
A partially applied version of foo would be something like:
def partial_foo(a, b):
return foo(a, b, 42)
Or, with a lambda expression:
partial_foo = lambda a, b: foo(a, b, 42)
However, note, the above goes against the official style guidelines, in PEP8, you shouldn't assign the result of lambda expressions to a name, if you are going to do that just use a full function defintion.
The module, functools, has a helper for partial application:
import functools
partial_foo = functools.partial(foo, c=42)
Note, you may have heard about "currying", which sometimes gets confused for partial application. Currying is when you decompose a n-arity function into N, 1-arity functions. So, more concretely, for foo:
curried_foo = lambda a: lambda b: lambda c: a + b + c
Or in long form:
def curried_foo(a):
def _curr0(b):
def _curr1(c):
return a + b + c
return _curr1
return _curr0
And the important part, curried_foo(1)(2)(3) == foo(1, 2, 3)

How to take arbitrary number of parentheses from user for add function

add(5)(10)(20)
How can I to supply an arbitrary number of parentheses to add numbers?
You could create a class like so:
class add(object):
def __init__(self, value):
self.value= value
def __call__(self, value):
self.value+= value
return self
def __repr__(self):
return str(self.value)
print add(5)(10)(20)
# output: 35
It's impossible, or at least it should be if the language you're using is worth anything. You're asking for a function to return two different types, which is inviting a a disaster.
sometimes it should return a function that takes the next number to add
other times it should return the sum of the previous inputs.
What? Take a step back and ask yourself what kind of design that is. You would need need some way to notify the function that you're done giving inputs and now you want the computed value.
Think about it, the function might look like this
def add (sum):
print(sum)
return lambda x: add(sum + x)
add(1)(3)(4)(5)(10)(20)
# 1
# 4
# 8
# 13
# 23
# 43
# => None
But there's no way to let the function know to return a final value unless you change the api somehow.
You could change the api to return the computed value when the users enters a 0 or something. Great idea right? Very clever.
def add (x):
def loop(sum, x):
if x == 0:
return sum
else:
return lambda x: loop(sum + x, x)
return loop(0, x)
print(add(1)(3)(4)(5)(10)(20)(0))
# 42
Hey look, it works where #Rawling's clever code fails. All without adding a bunch of tricks to a class
print(add(5)(10)(20)(0) + add(5)(10)(20)(0))
# 70
But still, this is garbage code. No well-designed function should ever behave like this.
Or if your content with being insane, create a class like #Rawing's answer suggests.
What you could do is this:
class add(object):
def __init__(self, val):
self.val= val
def __call__(self, val=None):
if not val:
return self.val
self.val += val
return self
add(5)(10)()
>>> 15

Represent a function by a mathematical function

Is it possible to output a mathematical function directly from the function implementation ?
class MyFunction:
def __init__(self, func):
self.func = func
def math_representation(self):
# returns a string representation of self.func
f = lambda x: 3*x**2
myFunc = MyFunction(f)
print(myFunc.math_reprentation()) #prints something like 3*x**2
Of course constructing the object with the representation as a parameter is possible, and is a trivial solution. But the idea is to generate this representation.
I could also build the function with objects representing the math operations, but the idea is to do it on a regular (lambda) function.
I really don't see a way for this to happen, but I'm curious.
Thanks for any help and suggestion
As I said, you can use SymPy if you want this to be more complex, but for simple functions (and trusted inputs), you could do something like this:
class MathFunction(object):
def __init__(self, code):
self.code = code
self._func = eval("lambda x: " + code)
def __call__(self, arg):
return self._func(arg)
def __repr__(self):
return "f(x) = " + self.code
You can use it like this:
>>> sq = MathFunction("x**2")
>>> sq
f(x) = x**2
>>> sq(7)
49
This is a bit restricted, of course (only using the variable called "x", and only one parameter), but it can be, of course, expanded.

python class Vector, change from 3dimension to ndimension

I made this class that computes some operations for 3d vectors, is there anyway I can change the code so that it computes the same operations but for vectors of any dimension n?
import sys
class Vector:
def __init__(self,x,y,z):
self.x= x
self.y= y
self.z= z
def __repr__(self):
return "(%f,%f,%f)"%(self.x,self.y,self.z)
def __add__(self,other):
return (self.x+other.x,self.y+other.y,self.z+other.z)
def __sub__(self,other):
return (self.x-other.x,self.y-other.y,self.z-other.z)
def __norm__(self):
return (self.x**2+self.y**2+self.z**2)**0.5
def escalar(self,other):
return (self.x*other.x+self.y*other.y+self.z*other.z)
def __mod__(self,other):
return (self.x%other.x,self.y%other.y,self.z%other.z)
def __neg__(self):
return (-self.x,-self.y,-self.z)
As an example, for a n dimensional vector, something like
class Vector:
def __init__(self, components):
self.components = components # components should be a list
def __add__(self, other):
assert len(other.components) == len(self.components)
added_components = []
for i in range(len(self.components)):
added_components.append(self.components[i] + other.components[i])
return Vector(added_components)
def dimensions(self):
return len(self.components)
would be possible. Note that the __add__ override returns a new Vector instance, not a tuple as in your case. Then adapt your other methods likewise.
There are more 'clever' ways of adding elements from two lists, into a third. You should really not do it this way if performance is an issue though (or in any other case but an exercise, IMO). Look into numpy.
Use a list to store the coefficients rather than explicit variables. For negating, adding, subtracting etc. you just iterate over the lists.
In terms of initialisation, you need to use *args for the input. Have a look at this post for an explanation of how it works: https://stackoverflow.com/a/3394898/1178052

product of two functions

I have two functions, f and g. Both have the same signature: (x). I want to create a new function, z, with the same signature:
def z(x):
return f(x) * g(x)
except that I'd like to be able to write
z = f * g instead of the above code. Is it possible?
Something close is possible:
z = lambda x: f(x) * g(x)
Personally, I find this way more intuitive than z = f * g, because mathematically, multiplying functions doesn't mean anything. Depending on the interpretation of the * operator, it may mean composition so z(x) = f(g(x)), but definitely not multiplication of the results of invocation. On the other hand, the lambda above is very explicit, and frankly requires just a bit more characters to write.
Update: Kudos to JBernardo for hacking it together. I was imagining it would be much more hacky than in turned out. Still, I would advise against using this in real code.
The funny thing is that it is quite possible. I made a project some days ago to do things like that.
Here it is: FuncBuilder
By now you can only define variables, but you can use my metaclass with the help of some other functions to build a class to what you want.
Problems:
It's slow
It's really slow
You think you want that but describing functions the way they meant to be described is the right way.
You should use your first code.
Just as a proof of concept:
from funcbuilder import OperatorMachinery
class FuncOperations(metaclass=OperatorMachinery):
def __init__(self, function):
self.func = function
def __call__(self, *args, **kwargs):
return self.func(*args, **kwargs)
def func(self, *n, oper=None):
if not n:
return type(self)(lambda x: oper(self.func(x)))
return type(self)(lambda x: oper(self.func(x), n[0](x)))
FuncOperations.apply_operators([func, func])
Now you can code like that:
#FuncOperations
def f(x):
return x + 1
#FuncOperations
def g(x):
return x + 2
And the desired behavior is:
>>> z = f * g
>>> z(3)
20
I added a better version of it on the FuncBuilder project. It works with any operation between a FuncOperation object and another callable. Also works on unary operations. :D
You can play with it to make functions like:
z = -f + g * h
I can be done with the exact syntax you intended (though using lambda might be better), by using a decorator. As stated, functions don't have operators defined for them, but objects can be made to be callable just like functions in Python --
So the decorator bellow just wraps the function in an object for which the multiplication for another function is defined:
class multipliable(object):
def __init__(self, func):
self.func = func
def __call__(self, *args, **kw):
return self.func(*args, **kw)
def __mul__(self, other):
#multipliable
def new_func(*args, **kw):
return self.func(*args, **kw) * other(*args, **kw)
return new_func
#multipliable
def x():
return 2
(tested in Python 2 and Python 3)
def y():
return 3
z = x * y
z()

Categories

Resources