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
Related
I have a function that needs to give a specific value to an other function depending on the current iteration in a for loop. the get_change_vector returns a tuple of 4 elements depending on the iteration a want to get a specific value from it.
def get_change_vector(x, r,):
Xp = r*x + x**3 - x**5
Xp2 = r*x + x**2 - x**3
Xp3 = r*x -x/(1+x**2)
Xp4 = x-r+(2-x)/(1+x**2)
return (Xp, Xp2, Xp3, Xp4)
def main ():
for n in range (4):
Xs = [i for i in np.arange(-2, 2, 0.001)]
rs = [funcR(x)[n] for x in Xs]
i1, i2 = 0 if n < 2 else 1, 0 if n % 2 ==0 else 1
ax = axes[i1] [i2]
for x, r in zip (Xs, rs):
clr = 'g' if is_stable(get_change_vector,x, r) else 'r'
ax.plot(r, x, 'o', color=clr, markersize=0.1)
I tried to give a specific index to get_change_vector but it returns an error saying function is not subcriptable.
I tried making a variable of the needed function
function = get_change_vector(x,r)[n]
but this returned an error this is because of the what the is_stable when it reaches func(*args)
'numpy.float64' object is not callable
def get_derivative(func, n, i):
'''
Wrapper around our change_vector function
so derivative can handle multiple parameters
'''
def wraps(n):
args = i, n
return func(*args)
return derivative(wraps, n, dx=1e-6)
def is_stable(func, n , i ):
return get_derivative(func, n, i) < 0
I have to write a function which takes a list of numbers of length ≥2, and returns a tuple containing the arithmetic mean and the unbiased sample variance of those numbers. i.e. given a list of items [𝑥1,𝑥2,…,𝑥𝑁], return a tuple (𝑚,𝑠2) where:
I'm not allowed to use inbuilt functions like sum, any math functions, etc. I'm not sure how to proceed without using those functions.
My code:
def mean_variance(numbers):
m = sum(numbers) / len(numbers)
var = sum((xi - m) ** 2 for xi in numbers) / len(numbers)
return m, var
What I'm testing on:
assert(mean_variance([1, 2, 3]) == (2, 1))
I dont know why you arent allowed to use inbuilt functions, but I guess you can do it without inbuilt functions like this:
def mean_variance(numbers):
meanSum = 0
for num in numbers:
meanSum += num
mean = meanSum / len(numbers)
varSum = 0
for num in numbers:
varSum += (num - mean) ** 2
var = varSum / (len(numbers) - 1)
return mean, var
I replaced the sum function with reduce and corrected an error in the formula.
Here is the code:
from functools import reduce
def mean_variance(numbers):
m = reduce(lambda x, y: x+y, numbers) / len(numbers)
var = reduce(lambda x, y: x+y, ((xi - m) ** 2 for xi in numbers)) / (len(numbers)-1)
return m, var
Without using any inbuilt methods
Mean and variance can come as floats.
so returning int or float will be automatically handled by assert
def mean_variance(inputList):
sum = 0
lenList = 0
for val in inputList:
sum = int(val) + sum
lenList = lenList + 1
mean = sum/lenList
sum_sq = 0
for val in inputList:
sq = (int(val) - int(mean)) ** 2
sum_sq = sum_sq + sq
variance = sum_sq/(lenList-1)
return (float(mean), float(variance))
print(mean_variance([1, 2, 3]))
assert mean_variance([1, 2, 3]) == (2, 1)
def fib(a, b, f):
fib must generate (using yield) the generalized Fibonacci
sequence, a and b is first and second element. f is function to get the third element instead of a+b as normal Fibonacci sequence. Use take function(which show below) to test it.
my code is below
def fib(a, b, f):
x = a
y = b
yield x
x, y = y, f(x,y)
fib(x,y,f)
I don't know what is wrong of my code, when I try to test it, it show
"TypeError: 'generator' object is not subscriptable"
the test case is:
take(5, fib(0, 1, lambda x, y: x - y))
It should out put:
[0, 1, -1, 2, -3]
and take function as i write is :
def take(n, iterable):
x = []
if n <= 0:
return x
else:
for i in range (0,n):
x.append(iterable[i])
return x
The message means that generators do not support indexing, so iterable[i] fails. Instead, use the next() function to get the next item from the iterator.
def take(n, iterable):
x = []
if n > 0
itr = iter(iterable) # Convert the iterable to an iterator
for _ in range(n): # Repeat n times
x.append(next(itr)) # Append the next item from the iterator
return x
Also, your fib() function will not work. You should not recurse at the end of the function; instead write a loop that yields a value each iteration.
def fib(a, b, f):
x = a
y = b
while True:
yield x
x, y = y, f(x,y)
You can't index into the results coming from a generator function like fib(). This following avoids that by using zip() with a range() argument. zip() stops automatically when one of its arguments reaches then end.
def fib(a, b, f):
x, y = a, b
while True:
yield x
x, y = y, f(x, y)
def take(n, iterable):
return [] if n <= 0 else [v for _, v in zip(range(n), iterable)]
print( take(5, fib(0, 1, lambda x, y: x-y)) )
Output:
[0, 1, -1, 2, -3]
Fibonacci simplest method you'll ever come across:
a , b =0 , 1
for n in range(100):#any number
print(a)
a = a + b
print (b)
b = b + a
def fibo(n):
if n == 0:
return 0
elif n == 1:
return 1
else:
return fibo(n - 1) + fibo(n - 2)
n = int(input("enter the number: "))
for i in range(n):
print(fibo(i))
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
When working with generators you can only pull out items on a single pass. An alternative is to load the generator into an list and do multiple passes but this involves a hit on performance and memory allocation.
Can anyone think of a better way of computing the following metrics from a generator in a single pass. Ideally the code computes the count, sum, average, sd, max, min and any other stats you can think of.
UPDATE
Initial horrid code in this gist.
See the gist here: https://gist.github.com/3038746
Using the great suggestions from #larsmans here is the final solution I went with. Using the named tuple really helped.
import random
from math import sqrt
from collections import namedtuple
def stat(gen):
"""Returns the namedtuple Stat as below."""
Stat = namedtuple('Stat', 'total, sum, avg, sd, max, min')
it = iter(gen)
x0 = next(it)
mx = mn = s = x0
s2 = x0*x0
n = 1
for x in it:
mx = max(mx, x)
mn = min(mn, x)
s += x
s2 += x*x
n += 1
return Stat(n, s, s/n, sqrt(s2/n - s*s/n/n), mx, mn)
def random_int_list(size=100, start=0, end=1000):
return (random.randrange(start,end,1) for x in xrange(size))
if __name__ == '__main__':
r = stat(random_int_list())
print r #Stat(total=100, sum=56295, avg=562, sd=294.82537204250247, max=994, min=10)
def statistics(it):
"""Returns number of elements, sum, max, min"""
it = iter(it)
x0 = next(it)
maximum = minimum = total = x0
n = 1
for x in it:
maximum = max(maximum, x)
minimum = min(minimum, x)
total += x
n += 1
return n, total, maximum, minimum
Add other statistics as you please. Consider using a namedtuple when the number of statistics to compute grows large.
If you want to get really fancy, you can build an OO hierarchy of statistics collectors (untested):
class Summer(object):
def __init__(self, x0=0):
self.value = x0
def add(self, x):
self.value += x
class SquareSummer(Summer):
def add(self, x):
super(SquareSummer, self).add(x ** 2)
class Maxer(object):
def __init__(self, x0):
self.value = x0
def add(self, x):
self.value = max(self.value, x)
# example usage: collect([Maxer, Summer], iterable)
def collect(collectors, it):
it = iter(it)
x0 = next(it)
collectors = [c(x0) for c in collectors]
for x in it:
for c in collectors:
c.add(x)
return [c.value for c in collectors]