Related
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))
I was able to find several implementations of Newton's methods, for example, this link or maybe this one.
However, most of the time the examples are with simple functions such as:
x^2−9=0 or x^3-x^2-1=0. I am looking for something that would work for:
My question for that I am lost in how to use this code to solve my problem. For example, I am not sure how I would apply the derivative (dfdx) on my F(x) that contain matrices. Also, if I should direct input the matrices on my "def f(x)"
The code that I am using:
def Newton(f, dfdx, x, eps):
f_value = f(x)
iteration_counter = 0
while abs(f_value) > eps and iteration_counter < 100:
try:
x = x - float(f_value)/dfdx(x)
except ZeroDivisionError:
print "Error! - derivative zero for x = ", x
sys.exit(1) # Abort with error
f_value = f(x)
iteration_counter += 1
# Here, either a solution is found, or too many iterations
if abs(f_value) > eps:
iteration_counter = -1
return x, iteration_counter
def f(x):
return x**2 - 9
def dfdx(x):
return 2*x
solution, no_iterations = Newton(f, dfdx, x=1000, eps=1.0e-6)
if no_iterations > 0: # Solution found
print "Number of function calls: %d" % (1 + 2*no_iterations)
print "A solution is: %f" % (solution)
else:
print "Solution not found!"
There aren't any special rules for deriving matrices - the derivative is just calculated for each element separately. I would suggest evaluating the $[x1,x2]' * M * [x1,x2]$ expression on paper to get a matrix of polynomials, and then calculating the derivative of each one.
I have to return the second smallest number in a python list using recursion, and no loops. What I have done is created a helper function that returns a tuple of the (smallest, second smallest) values in the list, and then I just take the tuple[1] in my second_smallest func.
def s_smallest(L):
if(len(L) == 2):
if (L[0] >= L[1]):
return (L[1],L[0])
else:
return (L[0],L[1])
else:
first_smallest,second_smallest = s_smallest(L[1:])
if L[0] >= first_smallest and L[0] <= second_smallest:
return (first_smallest, L[0])
elif L[0] <= first_smallest:
return (L[0], first_smallest)
else:
return (first_smallest, second_smallest)
This works, but now I need to handle nested lists, so s_smallest([1,2,[3,0]]) should return (0,1). I tried doing this:
if isinstance(L[0],list):
first_smallest,second_smallest = s_smallest(L[0])
else:
first_smallest,second_smallest = s_smallest(L[1:])
to get the first smallest and second smallest values if it is a list, but I get an error saying builtins.TypeError: unorderable types: int() >= list(). How can I fix this problem to deal with nested lists?
I might suggest separating the list unnesting and the min reducing into two separate, well-defined tasks
deepReduce will reduce a list of lists using the specified reducing function
deepMin performs a deepReduce using min
import math # used for math.inf
def min (x,y):
return x if x < y else y
def deepReduce (f, y, xs):
if not xs:
return y
elif isinstance(xs[0], list):
return deepReduce(f, deepReduce(f, y, xs[0]), xs[1:])
else:
return deepReduce(f, f(y, xs[0]), xs[1:])
def deepMin (xs):
return deepReduce (min, math.inf, xs)
data = [1,2,[7,[6,1,3,[0,4,3]],3,4],2,1]
print(deepMin(data))
# 0
Oh, but you said you want the second smallest number. Let's rework that code a little bit. Of course I knew that all along, but answering this question twice allows me to demonstrate the versatility of this specific implementation – Changes in bold
def min2 (xs, y):
# x1 is the smallest, x2 is second smallest
x1, x2 = xs
if (y < x1) and (y < x2):
return (y, x2)
elif y < x2:
return (x1, y)
else:
return (x1, x2)
def deepMin2 (xs):
# notice we change to use tuple of math.inf now
x1, x2 = deepReduce (min2, (math.inf, math.inf), xs)
return x2
data = [1,2,[7,[6,1,3,[0,4,3]],3,4],2,1]
print(deepMin2(data))
# 1
I should point out that we didn't have to touch deepReduce at all, which is the point – we should be able to do any arbitrary deep operation on our nested list without having to statically code that behaviour into our function.
Now you can write whatever deep reducer you want and call it with deepReduce
Full solution
Using nothing but functools.reduce, no loops, to handle lists of arbitrary nesting:
import functools
def helper(acc, x):
if type(x) is list:
return functools.reduce(lambda acc, x: helper(acc, x), x, acc)
else:
if x < acc[0]:
return (x, acc[0])
elif x < acc[1]:
return (acc[0], x)
else:
return (acc[0], acc[1])
def second_smallest(l):
if len(l) < 2:
return None
else:
if l[0] <= l[1]:
return functools.reduce(lambda acc, x: helper(acc, x), l[2:], (l[0], l[1]))
else:
return functools.reduce(lambda acc, x: helper(acc, x), l[2:], (l[1], l[0]))
>>> second_smallest([1,2,[0,3,[-1,-2]]])
(-2, -1)
I am trying to revamp a function that uses the Pollard Rho method to factor an integer but my attempt at using memoize has had no improvement in being able to factor a specific number (N=7331117) that this function should be able to facotr.
Before attempt:
import fractions
def pollard_Rho(n):
def f(xn):
if xn == 0:
return 2
return f(xn - 1) ** 2 + 1
i = 0
x = f(i)
y = f(f(i))
d = fractions.gcd(abs(x - y), n)
while d == 1:
i = i + 1
d = fractions.gcd(abs(x - y), n)
root1 = d
root2 = n / d
print i + 1
return (root1, root2)
memoize attempt:
def pollard_Rho(n):
class memoize:
def __init__(self, function):
self.function = function
self.memoized = {}
def __call__(self, *args):
try:
return self.memoized[args]
except KeyError:
self.memoized[args] = self.function(*args)
return self.memoized[args]
#memoize
def f(xn):
if xn == 0:
return 2
return f(xn - 1) ** 2 + 1
i = 0
x = f(i)
y = f(f(i))
d = fractions.gcd(abs(x - y), n)
while d == 1:
i = i + 1
d = fractions.gcd(abs(x - y), n)
root1 = d
root2 = n / d
print i + 1
return (root1, root2)
Now neither code produces any errors but both codes also do produce any results.
The output of
print pollard_Rho(7331117)
should be (641, 11437) (I know this because of another factorization function I have written) but what actually happens is the code runs through 3 iterations of the while loop and nothing happens afterwards. Does anyone have any suggestions?
Sorry for the vague question, does anyone have any suggestions on improving the the codes ability to factor in general? Maybe by a method more efficient than a recursive function? 7331116 and 7331118 factor perfectly fine and only 7331117 seems to be a tough nut to crack so far using this method.
Its possible I didn't use memoize right because even with looking at at on of stackoverflow examples I don't really understand how to use it. It seems every single instance of it I came across was drastically different.
It seems like your algorithm does not work for some reason. In order to see what is going on I went to wikipedia site of the algorithm and implemented regular version from there and it worked without a problem. Than I replaced my g function with your recursive version and I got following error
File "rho.py", line 25, in f_fun
return 2 if xn == 0 else f_fun(xn - 1) ** 2 + 1
RecursionError: maximum recursion depth exceeded
It seems like you cannot implement this with a regular recursion. I would suggest to convert your recursion to a fold or a generator.
Here is the code I tried:
https://gist.github.com/huseyinyilmaz/73c1ac42b2a20d24d3b5
UPDATE:
Here is your version with cache, it still have maximum depth problem. (python 2 implementation)
https://gist.github.com/huseyinyilmaz/bb26ac172fbec4c655d3
I'm trying to write a function that takes as input a list of coefficients (a0, a1, a2, a3.....a n) of a polynomial p(x) and the value x. The function will return p(x), which is the value of the polynomial when evaluated at x.
A polynomial of degree n with coefficient a0, a1, a2, a3........an is the function
p(x)= a0+a1*x+a2*x^2+a3*x^3+.....+an*x^n
So I'm not sure how to attack the problem. I'm thinking that I will need a range but how can I make it so that it can handle any numerical input for x? I'm not expecting you guys to give the answer, I'm just in need of a little kick start. Do I need a for loop, while loop or could recursive be an option here?
def poly(lst, x)
I need to iterate over the items in the list, do I use the indices for that, but how can I make it iterate over an unknown number of items?
I'm thinking I can use recursion here:
def poly(lst, x):
n = len(lst)
If n==4:
return lst[o]+lst[1]*x+lst[2]*x**2+lst[3]*x**3
elif n==3:
return lst[o]+lst[1]*x+lst[2]*x**2
elif n==2:
return lst[o]+lst[1]*x
elif n==1:
return lst[o]
else:
return lst[o]+lst[1]*x+lst[2]*x**2+lst[3]*x**3+lst[n]*x**n
This works for n<=4 but I get a index error: list index out of range for n>4, can't see why though.
The most efficient way is to evaluate the polynomial backwards using Horner's Rule. Very easy to do in Python:
# Evaluate a polynomial in reverse order using Horner's Rule,
# for example: a3*x^3+a2*x^2+a1*x+a0 = ((a3*x+a2)x+a1)x+a0
def poly(lst, x):
total = 0
for a in reversed(lst):
total = total*x+a
return total
simple:
def poly(lst, x):
n, tmp = 0, 0
for a in lst:
tmp = tmp + (a * (x**n))
n += 1
return tmp
print poly([1,2,3], 2)
simple recursion:
def poly(lst, x, i = 0):
try:
tmp = lst.pop(0)
except IndexError:
return 0
return tmp * (x ** (i)) + poly(lst, x, i+1)
print poly([1,2,3], 2)
def evalPoly(lst, x):
total = 0
for power, coeff in enumerate(lst): # starts at 0 by default
total += (x**power) * coeff
return total
Alternatively, you can use a list and then use sum:
def evalPoly(lst, x):
total = []
for power, coeff in enumerate(lst):
total.append((x**power) * coeff)
return sum(total)
Without enumerate:
def evalPoly(lst, x):
total, power = 0, 0
for coeff in lst:
total += (x**power) * coeff
power += 1
return total
Alternative to non-enumerate method:
def evalPoly(lst, x):
total = 0
for power in range(len(lst)):
total += (x**power) * lst[power] # lst[power] is the coefficient
return total
Also #DSM stated, you can put this together in a single line:
def evalPoly(lst, x):
return sum((x**power) * coeff for power, coeff in enumerate(lst))
Or, using lambda:
evalPoly = lambda lst, x: sum((x**power) * coeff for power, coeff in enumerate(lst))
Recursive solution:
def evalPoly(lst, x, power = 0):
if power == len(lst): return (x**power) * lst[power]
return ((x**power) * lst[power]) + evalPoly(lst, x, power + 1)
enumerate(iterable, start) is a generator expression (so it uses yield instead of return that yields a number and then an element of the iterable. The number is equivalent to the index of the element + start.
From the Python docs, it is also the same as:
def enumerate(sequence, start=0):
n = start
for elem in sequence:
yield n, elem
n += 1
Either with recursion, or without, the essence of the solution is to create a loop on "n", because the polynomial starts at x^0 and goes up to a_n.x^n and that's the variable you should also consider as an input. Besides that, use a trick called multiply and accumulate to be able to calculate partial results on each loop iteration.
def evalPoly(lst, x, power):
if power == 0:
return lst[power]
return ((x**power) * lst[power]) + evalPoly(lst, x, power - 1)
lst = [7, 1, 2, 3]
x = 5
print(evalPoly(lst, x, 3))
Equation to evaluate is - 3x^3 + 2x^2 + x + 7
when x = 5, result is - 437