Why does my function with complex numbers return as a NoneType? - python-3.x

I've been trying to code something to draw the mandelbrot-set, but my function doesnt seem to work.
the 'point' in my code is a complex number that is defined somewhere else in the code.
def mandelbrot(point, gen):
z = point
if gen > 0:
mandelbrot(z**2 + c, gen-1)
else:
return (z.real**2 + z.imag**2)**(1/2)
I got a grid of points that get colored in based on the result of this function. It would start with a complex number that i define in a loop later, and the 'gen' is just an integer that determines how often the function is used so i can do quicker tests in case it works. I thought it should have returned the length of the vector, but it gave an error that it was a NoneType.
For context, here is the full code:
import turtle
import cmath
Pen = turtle.Turtle()
Pen.speed(0)
Pen.penup()
size = 800
resolution = 16
accuracy = 3
c = complex(0,0)
z = complex(0,0)
Pen.goto(-size/2, -size/2)
def mandelbrot(point, gen):
z = point
if gen > 0:
mandelbrot(z**2 + c, gen-1)
else:
return (z.real**2 + z.imag**2)**(1/2)
def pixel(point):
if mandelbrot(point, accuracy) > 2:
Pen.fillcolor(1,1,1)
else:
Pen.fillcolor(0,0,0)
Pen.begin_fill()
for i in range (0, 4):
Pen.forward(size/resolution)
Pen.left(90)
Pen.end_fill()
for i in range(0, resolution):
Pen.goto(-size/2, -size/2 + i*size/resolution)
for j in range(0, resolution):
c = complex((-size/2 + j*size/resolution)/size*4,
(-size/2 + i*size/resolution)/size*4)
pixel(c)
Pen.forward(size/resolution)

Related

Converting Python iterative function to recursive function

Please consider 2 crossed suites:
U0 = 1
V0 = 2
Un = 2U(n-1) + 3 V(n-1)
Vn = U(n-1) + V(n-1)
I want to resolve it with this Python iterative function:
def myfunction(n=5):
u = 1
v = 2
for i in range(n):
w = u
u = 2*u + 3*v
v = w + v
return(u,v)
I would prefer a recursive function but I have no idea to convert my function.
Do you have any idea?
Thanks.
As simple as:
def u(n):
if n == 0:
return 1
else:
return 2*u(n-1) + 3*v(n-1)
def v(n):
if n == 0:
return 2
else:
return u(n-1) + v(n-1)
print((u(5), v(5))) # -> (905, 393)
This is possible due to the nature of Python being an interpreted dynamic programing language.
Edit:
def myfunction(n):
def u(n):
if n == 0:
return 1
else:
return 2*u(n-1) + 3*v(n-1)
def v(n):
if n == 0:
return 2
else:
return u(n-1) + v(n-1)
return u(n), v(n)
print(myfunction(5)) # -> (905, 393)
Just to conform with your exact problem/function.
The naive recursive implementation proposed by #moctarjallo is very slow because the same values have to be calculated over and over again. For example, calculating u(22) takes the ridiculous 0.8 sec:
from timeit import timeit
timeit('u(22)', globals=globals(), number=10)
# 8.138428802136332
Consider using an lru_cache decorator that saves the previously computed values in an invisible table and actually calls the functions only when they have not been called with the same parameters before:
from functools import lru_cache
#lru_cache(None) # decorate with a cache
def fast_u(n):
return 1 if not n else 2 * fast_u(n-1) + 3 * fast_v(n-1)
#lru_cache(None) # decorate with a cache
def fast_v(n):
return 2 if not n else fast_u(n-1) + fast_v(n-1)
timeit('fast_u(22)',globals=globals(), number=10)
#9.34056006371975e-05
I also made the functions code a little more idiomatic. Enjoy the difference!
P.S. If you are looking for a one-function implementation:
def uv(n):
if n == 0: return 1, 2
u, v = uv(n-1)
return 2 * u + 3 * v, u + v
uv(5)
#(905, 393)
Caching still improves its performance by orders of magnitude.

Knapsack algorithm, weird behavior (python3)

I have been working on recursion and tried to solve the Knapsack problem [https://en.wikipedia.org/wiki/Knapsack_problem]. I came up with the algorithm below which works just fine:
cost_array = [2,3,4,5,9]
value_array = [3,4,8,8,10]
def KP(Weight, C, V):
if Weight < 2:
return 0
q = 0
for i in range(len(C)):
q = max(q, (KP(Weight-C[i], [x for j,x in enumerate(C) if j!=i], \
[x for j,x in enumerate(V) if j!=i]) + V[i]*(Weight-C[i] >= 0)))
return q
print(KP(25,cost_array,value_array))
However when I change the value of q to q < 0 and call print(KP(25,cost_array,value_array)) the result I get is 33 - q. With 33 being the max value the knapsack can have.
What is weird here is that I only get this behavior if I call the initial function with a Weight > 23 and here 23=2+3+4+5+9.
I can't figure out at what point the negative q gets added to my result for me this line never performs such an operation, can you guys enlighten me ?
q = max(q, (KP(W-C[i], [x for j,x in enumerate(C) if j!=i], [x for j,x in enumerate(V) if j!=i]) + V[i]*(W-C[i] >= 0)))
Thanks,
d_darric
Suppose q=-2 (a negative value)
Therefore you are filling your base cases with -2 . That is -2 is returned for base cases of your function which is then getting added to the answer on each step in recursion. Try a bottom up approach with a 2D array. You can look at that here https://www.youtube.com/watch?v=8LusJS5-AGo . In your case you are filling matrix base cases with -2.
def knapSack(W, wt, val, n):
K = [[0 for x in range(W+1)] for x in range(n+1)]
q=-2 #Make it zero for correct answer
# Build table K[][] in bottom up manner
for i in range(n+1):
for w in range(W+1):
if i==0 or w==0:
K[i][w] = q #Here you are assigning negative value
elif wt[i-1] <= w:
K[i][w] = max(val[i-1] + K[i-1][w-wt[i-1]], K[i-1][w])
else:
K[i][w] = K[i-1][w]
return K[n][W]
# Driver program to test above function
value_array = [3,4,8,8,10]
cost_array = [2,3,4,5,9]
Weight = 25
n = len(val)
print(knapSack(Weight, cost_array, value_array, n))

simpson integration on python

I am trying to integrate numerically using simpson integration rule for f(x) = 2x from 0 to 1, but keep getting a large error. The desired output is 1 but, the output from python is 1.334. Can someone help me find a solution to this problem?
thank you.
import numpy as np
def f(x):
return 2*x
def simpson(f,a,b,n):
x = np.linspace(a,b,n)
dx = (b-a)/n
for i in np.arange(1,n):
if i % 2 != 0:
y = 4*f(x)
elif i % 2 == 0:
y = 2*f(x)
return (f(a)+sum(y)+f(x)[-1])*dx/3
a = 0
b = 1
n = 1000
ans = simpson(f,a,b,n)
print(ans)
There is everything wrong. x is an array, everytime you call f(x), you are evaluating the function over the whole array. As n is even and n-1 odd, the y in the last loop is 4*f(x) and from its sum something is computed
Then n is the number of segments. The number of points is n+1. A correct implementation is
def simpson(f,a,b,n):
x = np.linspace(a,b,n+1)
y = f(x)
dx = x[1]-x[0]
return (y[0]+4*sum(y[1::2])+2*sum(y[2:-1:2])+y[-1])*dx/3
simpson(lambda x:2*x, 0, 1, 1000)
which then correctly returns 1.000. You might want to add a test if n is even, and increase it by one if that is not the case.
If you really want to keep the loop, you need to actually accumulate the sum inside the loop.
def simpson(f,a,b,n):
dx = (b-a)/n;
res = 0;
for i in range(1,n): res += f(a+i*dx)*(2 if i%2==0 else 4);
return (f(a)+f(b) + res)*dx/3;
simpson(lambda x:2*x, 0, 1, 1000)
But loops are generally slower than vectorized operations, so if you use numpy, use vectorized operations. Or just use directly scipy.integrate.simps.

Smoothing values (neighbors between 1-9)

Instructions: Compute and store R=1000 random values from 0-1 as x. moving_window_average(x, n_neighbors) is pre-loaded into memory from 3a. Compute the moving window average for x for the range of n_neighbors 1-9. Store x as well as each of these averages as consecutive lists in a list called Y.
My solution:
R = 1000
n_neighbors = 9
x = [random.uniform(0,1) for i in range(R)]
Y = [moving_window_average(x, n_neighbors) for n_neighbors in range(1,n_neighbors)]
where moving_window_average(x, n_neighbors) is a function as follows:
def moving_window_average(x, n_neighbors=1):
n = len(x)
width = n_neighbors*2 + 1
x = [x[0]]*n_neighbors + x + [x[-1]]*n_neighbors
# To complete the function,
# return a list of the mean of values from i to i+width for all values i from 0 to n-1.
mean_values=[]
for i in range(1,n+1):
mean_values.append((x[i-1] + x[i] + x[i+1])/width)
return (mean_values)
This gives me an error, Check your usage of Y again. Even though I've tested for a few values, I did not get yet why there is a problem with this exercise. Did I just misunderstand something?
The instruction tells you to compute moving averages for all neighbors ranging from 1 to 9. So the below code should work:
import random
random.seed(1)
R = 1000
x = []
for i in range(R):
num = random.uniform(0,1)
x.append(num)
Y = []
Y.append(x)
for i in range(1,10):
mov_avg = moving_window_average(x, n_neighbors=i)
Y.append(mov_avg)
Actually your moving_window_average(list, n_neighbors) function is not going to work with a n_neighbors bigger than one, I mean, the interpreter won't say a thing, but you're not delivering correctness on what you have been asked.
I suggest you to use something like:
def moving_window_average(x, n_neighbors=1):
n = len(x)
width = n_neighbors*2 + 1
x = [x[0]]*n_neighbors + x + [x[-1]]*n_neighbors
mean_values = []
for i in range(n):
temp = x[i: i+width]
sum_= 0
for elm in temp:
sum_+= elm
mean_values.append(sum_ / width)
return mean_values
My solution for +100XP
import random
random.seed(1)
R=1000
Y = list()
x = [random.uniform(0, 1) for num in range(R)]
for n_neighbors in range(10):
Y.append(moving_window_average(x, n_neighbors))

TypeError: unsupported operand type(s) for +=: 'float' and 'NoneType' in Python 3

Does anyone know why I keep getting this error? I'm really new and I'd appreciate someone's help. This is my code:
import turtle as t
import math as m
import random as r
raindrops = int(input("Enter the number of raindrops: "))
def drawSquare():
t.up()
t.goto(-300,-300)
t.down()
t.fd(600)
t.lt(90)
t.fd(600)
t.lt(90)
t.fd(600)
t.lt(90)
t.fd(600)
t.lt(90)
def location():
x = (r.randint(-300, 300))
y = (r.randint(-300, 300))
t.up()
t.goto(x, y)
return x, y
def drawRaindrops(x, y):
t.fillcolor(r.random(), r.random(), r.random())
circles = (r.randint(3, 8))
radius = (r.randint(1, 20))
newradius = radius
area = 0
t.up()
t.rt(90)
t.fd(newradius)
t.lt(90)
t.down()
t.begin_fill()
t.circle(newradius)
t.end_fill()
t.up()
t.lt(90)
t.fd(newradius)
t.rt(90)
while circles > 0:
if x + newradius < 300 and x - newradius > -300 and y + newradius < 300 and y - newradius > -300:
t.up()
t.rt(90)
t.fd(newradius)
t.lt(90)
t.down()
t.circle(newradius)
t.up()
t.lt(90)
t.fd(newradius)
t.rt(90)
newradius += radius
circles -= 1
area += m.pi * radius * radius
else:
circles -= 1
return area
def promptRaindrops(raindrops):
if raindrops < 1 or raindrops > 100:
print ("Raindrops must be between 1 and 100 inclusive.")
if raindrops >= 1 and raindrops <= 100:
x, y = location()
area = drawRaindrops(x, y)
area += promptRaindrops(raindrops - 1)
return x, y, area
def main():
t.speed(0)
drawSquare()
x, y, area = promptRaindrops(raindrops)
print('The area is:', area, 'square units.')
main()
t.done()
I'm assuming something is wrong with the "+=" but I have no idea what. I'm fairly certain that the area is correctly being returned. Help please. :)
Two things I noticed:
1. promptRaindrops returns a tuple
I am sure you didn't intend this, but when you say area += promptRaindrops(raindrops - 1), you are adding a tuple to area, which is an integer. To fix this, you should say area += promptRaindrops(raindrops - 1)[2] to get the area returned. However, your error is generated by
2. Your base case doesn't return a value
In promptRaindrops, you return a recursive call of the function whenever 1 <= raindrops <= 100. But, when it is outside that range, it returns nothing, only prints a message. Your function will always be outside of that range, because if you keep decreasing the value passed in to promptRaindrops, it will eventually go below 1. When it does, you return None (since you didn't return anything). That None bubbles up through every single recursion call made to that point, and you will inevitably be adding None to area. Add a return statement returning a tuple, and your error should vanish.
In promptRaindrops() you perform a += operation with a recursive call to promptRaindrops() which will not return anything (NoneType) if raindrops is outside the given range.
Depending on how the program should behave, either something should be returned there or it should not be called with values outside the given range.

Resources