Planning
So, according to wikipedia, if you have n points around a circle and you connect every point p to 2*p (mod n), you will create an envelope of a cardioid. (somewhat off topic, but if you switch it to 3*p or m*p, you get m-1 cusps in your curve. More info below). I figured this would make some good string art, but I didn't want to use a different piece of string for every chord. I wanted to use a couple pieces and get as many chords in sequence as I could. I ended up writing a python script (included at bottom of post) using turtle draw to create pictures on n points generating cycles rather than just knowing which two points to connect.For example, if you have 10 points, you would want the first cycle to be (1, 2, 4, 8, 6, 2) since 8*2 = 16 = 6 mod 10. it ends at 2 since you would continue in a cycle from there. As you see though, we have a problem. Some points are not covered. What about 3? What about 10 (though we will call this 0). We should go back and start again at 3. The next grouping would be (3, 6) We end here since 6 was already covered and we would just loop back into the original cycle. Next we start at 5 since it is the smallest point not yet hit. We get the next grouping to be (5, 0) since 5*2 = 10 = 0 mod 10. If you continue in this manner you get the following groupings and picture:
(1, 2, 4, 8, 6, 2), (3, 6), (5, 0), (7, 4), (9, 8)
Cardioid on 10 points |
On 10 points, you don't get enough detail to see the envelope. The pictures get more detailed the more points you add. With 50 points you get the following groupings and resulting picture:
[[1, 2, 4, 8, 16, 32, 14, 28, 6, 12, 24, 48, 46, 42, 34, 18, 36, 22, 44, 38, 26, 2], [3, 6], [5, 10, 20, 40, 30, 10], [7, 14], [9, 18], [11, 22], [13, 26], [15, 30], [17, 34], [19, 38], [21, 42], [23, 46], [25, 0, 0], [27, 4], [29, 8], [31, 12], [33, 16], [35, 20], [37, 24], [39, 28], [41, 32], [43, 36], [45, 40], [47, 44], [49, 48], [50, 0]]
Much better! However, if you see the groupings you will notice that there are a lot of groupings of just two points, meaning they define only one chord. I wanted to lengthen the groupings. Either have just one large cycle or lots of medium sized ones. After testing out a few numbers I arrived at 75 points. You get the following groupings and resulting picture:
[[1, 2, 4, 8, 16, 32, 64, 55, 37, 1], [3, 6, 12, 24, 48, 23, 46, 19, 38, 3], [5, 10, 20, 40, 7, 14, 28, 56, 39, 5], [9, 18, 36, 72, 71, 69, 65, 57, 41, 9], [11, 22, 44, 15, 30, 60, 47, 21, 42, 11], [13, 26, 52, 31, 62, 51, 29, 58, 43, 13], [17, 34, 68, 63, 53, 33, 66, 59, 45, 17], [25, 50, 27, 54, 35, 70, 67, 61, 49, 25], [73, 0, 0]]
I decided on this one since the groupings are all equally sized. There are 8 groupings, enough for each color of the rainbow (ROYGBIV) and one silver. Now that I had the plan, it was on to making this thing!
Making
I wanted something large and I did NOT want to spend a lot of time cutting down and finishing wood, either as a board with a circle of nails or a wooden hoop. So I decided to buy a hula hoop and put nails in around the outside. I wasn't 100% sure this would work since I have never hammered nails into a hula hoop before, but it was worth a shot!It did end up working out. I measured the circumference of the hoop and divided it by 73. I think I should have been more careful about how I measured the circumference or how I marked out the nails because I ended up with 74 nails in there somehow. It didn't really matter in the end, but if I were to do it again, I would be more careful. Anyway, I marked out my points and began hammering.
As you can see, the hoop I got was not a perfect torus. It was whatever Target had. I liked the metallic color and thought it would go well with the rainbow theme. I also ended up angling the nails so they would disappear a bit when the hoop was hanging up. It also made it easier to loop the string.
Here are some pics of the process:
All ready for the string! |
First grouping in red, am I doing this wrong? |
Four groupings and you can start to see it |
One more to go! |
All done! |
What happens if you multiply by something other than 2?
When I was writing my program, I was wondering why multiplying by 2 would give you this cardioid and what happens if you multiply by something else? Well here are images on 100 points of different multipliers.
p -> 2p mod n |
p -> 3p mod n |
p -> 4p mod n |
p -> 5p mod n |
But why does this work?
Ah, that is the question...
The proof for the Cardioid requires a bit of unit circle trig, but its definitely worth working through on your own. Can you generalize to the other multipliers?
How does this relate to Group Theory?
Also a good question. You are probably thinking, are these subgroups? Why do some numbers generate long strings of groupings and others short ones? Are these orbits under a group action?
Probably orbits, definitely not always subgroups. Might have some quotients in relatively prime situations. I would have to go back to Dummit & Foote to answer for sure. It has been too long...
If you know enough math to even be asking this question, you know enough to answer it for yourself.
If you know enough math to even be asking this question, you know enough to answer it for yourself.
Python Code
import turtle
import math
RADIUS = 300
num_points = int(input("How many points?"))
factor = int(input("What factor?"))
#generate points list
points = []
theta = 2 * math.pi / (num_points)
for i in range(num_points):
points.append((RADIUS * math.cos(i * theta), RADIUS * math.sin(i * theta)))
#generate drawing sequences
sequences = [[1]]
finished = False
while not finished:
# do the appending
sequences[-1].append((sequences[-1][-1] * factor) % (num_points))
# check if current value is redundant
redundant = False
for sequence in sequences[:(len(sequences) - 1)]:
if sequences[-1][-1] in sequence:
redundant = True
break
if sequences[-1][-1] in sequences[-1][:(len(sequences[-1]) - 1)]:
redundant = True
if redundant:
finished = True
for i in range(1, num_points + 1):
new_num = True
for sequence in sequences:
if i in sequence:
new_num = False
if new_num:
sequences.append([i])
finished = False
break
print(sequences)
sheldon = turtle.Turtle()
sheldon.speed(0)
win = turtle.Screen()
for sequence in sequences:
sheldon.pu()
sheldon.goto(points[sequence[0] - 1])
sheldon.pd()
for index in sequence:
sheldon.goto(points[index - 1])
sheldon.pu()
win.exitonclick()