I am trying to make a program that solves the following with permutations and lambda:
You pick 5 numbers and a random number is generated, the aim is to use those 5 numbers to reach the target number. You are allowed to use each number once with as many operators as you want (+-*/). I want the program to print() all of the solutions
this is the code i have created so far
from itertools import permutations
import operator
num1=3
num2=5
num3=7
num4=2
num5=10
class Infix:
def __init__(self, function):
self.function = function
def __ror__(self, other):
return Infix(lambda x, self=self, other=other: self.function(other, x))
def __or__(self, other):
return self.function(other)
def __rlshift__(self, other):
return Infix(lambda x, self=self, other=other: self.function(other, x))
def __rshift__(self, other):
return self.function(other)
def __call__(self, value1, value2):
return self.function(value1, value2)
"""what the class infix does is it allows me to substitute operators such as +-*/ to functions as follows:"""
multiply=Infix(lambda x,y: x*y) #this is a way of telling it that whenever i call x multiply y is the same as x*y
add=Infix(lambda x,y: x+y) #same here just for adding
minus=Infix(lambda x,y: x-y)
divide=Infix(lambda x,y: x/y)
"""the way infix can be called is if i say 3 |add| 4, which allows me to substitute
variables as the operators"""
target = 50
for w,x,y,z in permutations((|multiply|,|add|,|minus|,|divide|), 4): #telling it to substitute operators to the variables
for a,b,c,d,e in permutations(num1,num2,num3,num4,num5), 5):
if a(w)b(x)c(y)d(z)e == target: #works out the sum
print(a(w)b(x)c(y)d(z)e) #prints it if it equals my target
The only error in this code is the for loops because i don't know how to substitute both operators and numbers at the same time, all the other parts of the code are absolutely fine.
The expected output is all answers that work e.g. 3*2+5-7=4 if target==4.
What i asked this to do is run through all of the numbers with all of the operators again and again to find answers that match the target, and then print them out, but i am having difficulties trying to substitute the number together with the operator.
I thought that a(X)b(y)... would work because if you substitute it, it is a(|add|)b(|multiply|)d... and so on, but it turns out that it doesn't.
None of these work but i am trying to find a solution that does. It needs to loop through the numbers and the operators at the same time and i don't know how to do it!
Error when running:
Infix working correctly:
Finally, I think we get to the bottom of it. You are expecting the "bitwise OR" operators | to somehow modify the Infix objects, so that when you do
permutations((|multiply|,|add|,|minus|,|divide|), 4)
they "stay with" the objects. That can't happen; for example, you wouldn't do:
x, y = 1, 2
a = x+
print(ay)
and expect 3. Instead, you need to do:
permutations((multiply, add, minus, divide), 4)
i.e. actually shuffle the Infix instances, then apply the operators later, when calculating the comparison with target:
if a |w| b |x| c |y| d |z| e == target:
There are a few other minor errors, but that should allow you to move forwards.
Related
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]))
I am given a list of functions and asked to define plus(x,y) with add1 and repeated. plus is a function that takes in two numbers and returns the total. However, I cannot get any output with my definition. It just gives the name of the function. Any help is appreciated!
add1 = lambda x: x + 1
def compose(f, g):
return lambda x: f(g(x))
def repeated(f, n):
if n == 0:
return lambda x: x
else:
return compose(f, repeated(f, n - 1))
def plus(x, y):
return repeated(add1, y)
That is an interesting way to do addition. It works quite well, you just missed one thing. Repeated returns a function which will give the sum, not the sum itself. So you just have to call repeated(add1, y) on x like this
def plus(x, y):
return repeated(add1, y)(x)
The rest of the code works fine.
The detail is that plus returns a function and that's why you see the name of the function instead of a numeric value. I think that's why there is the x parameter in plus. Just change this line of code to
return repeated(add1, y)(x)
This will evaluate the return function of repeated with the value in x.
So using
plus(5, 1)
>> 6
I have a class that represents a polynomial as a collection of terms where each term has a coefficient and an exponent. I am working on the __add__ method of the class and I am wondering what the most effective way to do something like:
def __add__(self, other):
new_terms = []
for term in self.terms:
if there is a term in other with an exponent == term.exponent
new_terms.append(Term(term.coef + other_term.coef, term.exponent))
It strikes me that I'm looking for something such as:
if x in y where x.attr == val
Or in my specific case:
if x in other where x.exponent == term.exponent
Does such a thing exist?
You need to filter your list before doing your contains check. As tobias_k suggested, you can either build a new list, e.g.
[x for x in other if x.exponent == term.exponent]
This works directly in an if statement, because an empty list is False:
if [x for x in other if x.exponent == term.exponent]:
But this does some wasteful work, since it a) has to construct a new list and b) doesn't short-circuit once a result is found. Better is to use the same syntax in a generator expression:
(True for x in other if x.exponent == term.exponent)
Which you can then similarly use in an if statement, but no wasteful work is done:
if next((True for x in other if x.exponent == term.exponent), False):
I think you want [x for x in y if x.attr == val], or use next with the same expression for just the first such value.
In your case, it could look something like this:
def __add__(self, other):
for term in self.terms:
for other_term in (x for x in other.terms
if x.exponent == term.exponent):
term.coefficient += other_term.coefficient
However, this will not work too well. First, __add__ should not modify neither self nor other but instead create a new polynomial. Also, this will ignore any values from other that have a different exponent that any of the terms in self. And third, the performance is pretty lousy, as it loops the list of terms in other for each term in self, giving it quadratic complexity.
Instead, I suggest using a dictionary, mapping exponents in the term to their coefficient. In fact, you could probably just use a collections.Counter for that; it already implements __add__ in the right way. Something like this:
class Poly:
def __init__(self, counts):
self.terms = collections.Counter(counts)
def __add__(self, other):
return Poly(self.terms + other.terms)
def __str__(self):
return " + ".join("%dx^%d" % (c, x) for x, c in self.terms.items())
Example:
>>> Poly({2: 1, 1: 3, 0: 5}) + Poly({3: 1, 1: 2, 0: 3})
8x^0 + 5x^1 + 1x^2 + 1x^3
Is there any way to use infix operators (like +,-,*,/) as higher order functions in python without creating "wrapper" functions?
def apply(f,a,b):
return f(a,b)
def plus(a,b):
return a + b
# This will work fine
apply(plus,1,1)
# Is there any way to get this working?
apply(+,1,1)
You can use the operator module, which has the "wrapper" functions written for you already.
import operator
def apply(f,a,b):
return f(a,b)
print apply(operator.add,1,1)
Result:
2
You can also define the wrapper using lambda functions, which saves you the trouble of a standalone def:
print apply(lamba a,b: a+b, 1, 1)
Use operator module and a dictionary:
>>> from operator import add, mul, sub, div, mod
>>> dic = {'+':add, '*':mul, '/':div, '%': mod, '-':sub}
>>> def apply(op, x, y):
return dic[op](x,y)
...
>>> apply('+',1,5)
6
>>> apply('-',1,5)
-4
>>> apply('%',1,5)
1
>>> apply('*',1,5)
5
Note that you can't use +, -, etc directly as they are not valid identifiers in python.
You can use the operator module this way:
import operator
def apply(op, a, b):
return op(a, b)
print(apply(operator.add, 1, 2))
print(apply(operator.lt, 1, 2))
Output:
3
True
The other solution is to use a lambda function, but "there should be one -- and preferably only one -- obvious way to do it", so I prefer to use the operator module
you can use anonymous function : apply(lambda x,y : x + y, 1,1)
# Is there any way to get this working?
apply(+,1,1)
No. As others have already mentioned, there are function forms of all of the operators in the operator module. But, you can't use the operators themselves as that is a SyntaxError and there is no way to dynamically change python's core syntax. You can get close though using dictionaries and passing strings:
_mapping = {'+':operator.add}
def apply(op,*args):
return _mapping[op](*args)
apply('+',1,1)
It is possible to give the operators +, -, *, and / special behavior for a class using magic methods, you can read about this here: http://www.rafekettler.com/magicmethods.html
This isn't exactly what you were asking for because this still requires the creation of a method for each operator, but it does allow you to use the operators by symbol in your code. Note that I don't think this is better than the other methods, it is just an illustration of how you can define behavior for operators:
class Prefix(object):
def __add__(self, other):
""" Prefix() + (a, b) == a + b """
return other[0] + other[1]
def __sub__(self, other):
""" Prefix() - (a, b) == a - b """
return other[0] - other[1]
def __mul__(self, other):
""" Prefix() * (a, b) == a * b """
return other[0] * other[1]
def __div__(self, other):
""" Prefix() / (a, b) == a / b """
return other[0] / other[1]
And examples:
>>> prefix = Prefix()
>>> prefix + (12, 3)
15
>>> prefix - (12, 3)
9
>>> prefix * (12, 3)
36
>>> prefix / (12, 3)
4
Of course this method can't be used for a more complex prefix equation like * / 6 2 5 because there is no way to define behavior for adjacent operators, which will always give a SyntaxError (except for a few special cases where + or - are interpreted as making the next element positive or negative).
I'm revisiting some scheme excercises in python (if that makes sense) to find out what python can do in terms of FP. My problem concerns lambda in python :
Can i define a general function in python with an operator as one of the arguments?
Think this :
def f (op,x,y):
#return some lambda function that combines x and y in the appropriate way
#i.e if op is +, then return x+y, if op is -, then return x-y etc
#Edit : added usage
#this should be called like this:
f(+, 1,2) #should return 3
I know this is possible in scheme, but is there something equivalent in python? I've gotten the impression that lambda in python is just a shorter way of defining a method, and I've not found any way to define a general combiner function in python.
I can see some points in your question, lets go through them in order:
1. Can I pass a function as a parameter to someone?
Yes:
def f(op, x, y):
return op(x, y)
def add(x, y):
return x + y
f(add, 10, 7) #gives 17
2. What about operators then?
Unlike scheme, Python operators are not functions so you can't pass them directly as parameters. You can either create the wrapper functions yourself or you can import the operator module from the standard library.
import operator
operator.add(1, 2)
(lambda x,y : x+y)(1, 2)
Operators not being real functions is a little sad in most cases but at least Python gives us chained comparisons like 10 <= x < 100 in exchange...
3. So what is the difference between Python and Scheme then?
In the general sense, functions in Python are as powerful as functions in Scheme, however there are some things to note:
The lambda keyword is limited
You can only have a single expression as the function body
f = lambda x, y: x + y
Since there are a bunch of things in Python that are statements and not expressions (assignments, the 2.x print, ...), you often need to fall back to named functions instead.
There are closures
def make_printer(msg):
def printer():
print msg
return printer
printer('a message')()
But mutating variables in them is a pain
This doesn't work. It tries to bind a new n for the inner function instead of using the outer one
def make_counter(n):
def inc():
n = n + 1
return n
return inc
new 3.x nonlocal keyword
def make_counter(n):
def inc():
nonlocal n
n = n + 1
return n
return inc
workaround w/ mutable objects
def make_counter(n):
nw = [n]
def inc():
nw[0] = nw[0] + 1
return nw[0]
return inc
Objects instead of closures. Uses the magic __call__ method to pretend its a function
class Counter:
def __init__(self, n):
self.n = n
def __call__(self):
self.n += 1
return self.n
Operators aren't really function in python, more like methods -- x + y is short for x.__add__(y), or y.__radd__(x). You can use the functions in the operator module to emulate the behavior you want.
I think your best bet is to make a function that does the operator, and pass that:
def f(op, x, y):
return op(x, y)
f(lambda x, y: x + y, 1, 2)
Looks a little redundant though when you can do:
f = lambda x, y: x + y
f(1, 2)
You cannot syntactically pass an operator in python. E.g. f(+) is a syntax error. However, if you consider op to be any function, you can use def or lambda:
def f(op, x, y):
def op_func():
return op(x, y)
return op_func
or
def f(op, x, y):
op_func = lambda: op(x, y)
return op_func
In your case, you wish to evaluate the function:
def f(op, x, y):
return op(x, y)
Remember that Python is interpreted, so even def statements are evaluated at runtime.
[ If for some reason you need to, you can access the built-in operators as functions using the operator module: http://docs.python.org/library/operator.html ]
Check operator module. All python operators are available there in the form of functions.
example:
import operator
operate = lambda op, x, y: op(x, y)
operate(operator.add, 1, 2)