Análisis de la curva de Hilbert

I'm just starting to learn Python and I don't understand the ability of calling the same function inside itself?

Aquí hay un ejemplo:

import turtle
from turtle import left, right, forward

size = 10

def hilbert(level, angle):
    if level == 0:
        return

    turtle.color("Blue")
    turtle.speed("Fastest")

    right(angle)
    hilbert(level - 1, -angle)
    forward(size)
    left(angle)
    hilbert(level - 1, angle)
    forward(size)
    hilbert(level - 1, angle)
    left(angle)
    forward(size)
    hilbert(level - 1, -angle)
    right(angle)

¿Cómo funciona nuestro servicio exactamente?

Gracias.

preguntado el 28 de agosto de 11 a las 00:08

+1 Cool program! Where'd you get the idea? -

I'm studying fractals because I have to generate them in a open source software called 4NEC2. The Python code I found was online. -

Care to provide a link? I'd love to test it out myself, and people looking at this post in the future might find it relevant. -

@machine yearning: It appears to come from esta página de wikipedia. I doubt it actually works -- the size is never changed. -

@machine yearning: LOL -- I just found out -- turtle is part of the standard library. And it comes with demo scripts. The hilbert curve is one of the demos that comes with the module. (On my system, implemented in /usr/share/doc/python2.6/examples/Demo/turtle/tdemo_fractalcurves.py.) -

6 Respuestas

I couldn't accept that the beauty of recursion was not understanding it, nor could I accept the fact that I might not be able to understand it myself! So after consulting a friend, I finally became aware of how the stack works. Here is my equivalent code for the Space Filling Hilbert Curve if level = 2 and angle = 90°:

import turtle
from turtle import left, right, forward

size = 10
angle = 90

turtle.hideturtle()
turtle.color("Blue")
turtle.speed("Fastest")

''' Assume we have two levels. '''

right(angle)

# 1st hilbert call
right(-angle)
forward(size)
left(-angle)
forward(size)
left(-angle)
forward(size)
right(-angle)

# Continue from first call of hilbert
forward(size)
left(angle)

# 2nd hilbert call
right(angle)
forward(size)
left(angle)
forward(size)
left(angle)
forward(size)
right(angle)

# Continue from second call of hilbert
forward(size)

# 3rd hilbert call
right(angle)
forward(size)
left(angle)
forward(size)
left(angle)
forward(size)
right(angle)

# Continue from third call of hilbert
left(angle)
forward(size)

# 4th call of hilbert
right(-angle)
forward(size)
left(-angle)
forward(size)
left(-angle)
forward(size)
right(-angle)

# Continue from fourth call of hilbert
right(angle)

¡Eureka!

Respondido 29 ago 11, 18:08

Cuando te level es igual a 0, hilbert(level,angle) just returns, that is, does nothing.

Now consider what happens when level equals 1: Calling hilbert(1,angle) executes these statements:

turtle.color("Blue")
turtle.speed("Fastest")
right(angle)
forward(size)
left(angle)
forward(size)
left(angle)
forward(size)
right(angle)

It looks to me that this probably draws three sides of a square.

Al hilbert(level-1,...) statements have been removed since level-1 equals 0 and we already determined that hilbert(0,...) no hace nada.

Ahora, considere lo que sucede cuando llama hilbert(1,-angle). Next, think about what happens when level equals 2. I hope this gives you an idea of how to proceed.

PS. Lovely thing about Python -- you can run programs interactively to visualize what calling hilbert(1,angle) hace, entonces hilbert(2,angle) does, etc...

Respondido 28 ago 11, 04:08

BTW, I see it is more efficient to have the turtle.color("Blue") and turtle.speed("Fastest") outside the function. - ElectroNerd

I don't understand the sequence for a level = 2. Here's the statements I have: right(angle) right(-angle) forward(size) left(-angle) forward(size) left(-angle) forward(size) right(-angle) forward(size) left(-angle) forward(size) left(-angle) forward(size) right(-angle) - ElectroNerd

@ElectroNerd: Haha you rarely will understand every level of a recursive process, that's the beauty of it! A simple problem quickly cascades into an increasingly complex mess of uniform and fractal-looking logic; the main thing is to understand your problem, and understand from a given level, how to get to the next level. - anhelo de máquina

This is a powerful programming technique called recursividad, where a problem is solved by breaking it down into similar but smaller problems, until you reach a point where the problem is small enough to solve easily.

Respondido 28 ago 11, 04:08

Thanks Tom, I will be sure to research that term specifically. - ElectroNerd

As @Tom Zych and others mentioned, this is a problem called recursion that can be hard to wrap your mind around at first (sometimes requires thinking about problems in a totally different way than usual).

The most classic and easily understood (but not necessarily useful or powerful) example of recursion is the factorial generator. Given a positive integer n, the factorial of n is equal to the product of all the positive integers less than or equal to n. We write the factorial of n as n!:

n! = n * (n-1) * (n-2) * ... * 3 * 2 * 1

Now with recursion we want to see, "what is the pattern here that repeats and gets simpler as I try to solve the larger problem?" Let's try 5! por ejemplo:

5! = 5 * 4 * 3 * 2 * 1

What is the first thing we do when solving this equation? We take 5 and multiply it by something. This is perfect, because if we had a factorial function fact(n), we would probably take n as its parameter:

def fact(n):
    return n * #something

All that remains is to figure out what that #something is. But we just wrote it above:

5! = 5 * (4 * 3 * 2 * 1)

But how is out new #something just a smaller problem that is essentially identical to our original problem? Watch, this is the magic of recursion:

5! = 5 * 4 * 3 * 2 * 1
   = 5 * 4!
4! = 4 * 3 * 2 * 1
   = 4 * 3!
3! = 3 * 2 * 1
   = 3 * 2!
2! = 2 * 1
   = 2 * 1!
1! = ???

As you can see, for most any given n,

n! = n * (n-1)!

We're almost there, now that we've discovered our pattern, we need to worry about the exception case, the simplest case, (when n = 1, there's nothing else to multiply by). In recursion, we call this the caso base, and fortunately we know exactly what to do in this base case: 1! = 1. So in summarizing our logic, we can write our recursive factorial function:

def fact(n):
    # Take care of the base case first
    if n == 1:
        return 1
    # Then break down the larger case into its recursive sub-problems
    else:
        return n * fact(n-1)

Your Hilburtle program is a tad bit more intricate, but if you know some of what Hilbert curve analysis is about, and you're beginning to understand recursive program logic, you should be able to figure out how it works. Good luck!

Respondido 28 ago 11, 06:08

Esto se conoce como recursividad. A recursive function usually solves a small problem but also has the ability to break larger problems into smaller ones that it can more easily solve.

In your example, it looks like the program may be some path-exhausting program.

Respondido 28 ago 11, 04:08

It's pretty simple actually. Speaking generally, and leaving out a few (important, but not to this discussion) exceptions:

  • A function is a list of instructions, that operate on data.
  • Part of that data is the "stack" - a block of memory
  • Functions keep track of which PART of the stack is in use with a "stack pointer"
  • When a function is called, the stack pointer is moved, and instructions act on the current stack pointer (perhaps moving it further)
  • When a function finishes (returns), the pointer moves back.
  • When a function calls another function, it moves the stack pointer, just as before.
  • So, when a function calls itself, it's no different: the function pointer moves, then the function is executed.

In other words, the computer doesn't really care if you call different functions, or call the same function recursively. In fact, it can optimise the recursive function a little, because it knows the same things will happen each time, like a for loop.

Respondido 01 Oct 13, 02:10

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.