13131: The B-Heptomino/Glider Spaceship Thread
Re: 13131: The B-Heptomino/Glider Spaceship Thread
I found this old post by dvgrn made in 2013 that has a list of lots of still lifes that the 13131 b-heptomino could climb on:
https://conwaylife.com/forums/viewtopic ... 1065#p7750
I'm not sure how useful these reactions are or might be but I'll post it here just in case.
https://conwaylife.com/forums/viewtopic ... 1065#p7750
I'm not sure how useful these reactions are or might be but I'll post it here just in case.
Puffer Suppressor
Would we be able to know when we know everything there is to know?
How would we know what we don’t know that we don’t know?
The (34,7)c/156 caterpillar is finished!!! You can download it here.
Would we be able to know when we know everything there is to know?
How would we know what we don’t know that we don’t know?
The (34,7)c/156 caterpillar is finished!!! You can download it here.
-
Jormungant
- Posts: 853
- Joined: May 27th, 2016, 1:01 am
Re: 13131: The B-Heptomino/Glider Spaceship Thread
I was starting to have some doubts, but it seems it is possible to shoot these mwss pair even on the harder side (which is what my previous construction needs)
Sadly, this these not work at p496, so it seem to hint one should aim toward using a p992 construction instead (or something >650, if an helix can be found). Still, would be great if there was a faster reaction to turn that glider, which is mandatory for most mwss constructions.
Code: Select all
x = 158, y = 121, rule = LifeHistory
10$48.A$47.A.A$47.A.A$48.A14$137.A$136.A.A$136.A.A$137.A14$16.A2.A$
20.A$16.A3.A$17.4A11$29.2A$13.4A13.2A$12.A3.A12.A$16.A88.A2.A$15.A93.
A$105.A3.A$27.3A76.4A$29.A$28.A9$20.2A96.2A$19.A.A6.2A72.4A13.2A$21.A
7.2A70.A3.A12.A$28.A76.A$104.A2$116.3A$118.A$117.A$132.2A$130.2A.2A$
130.4A$131.2A$43.2A3.A$41.2A.2A2.2A84.3A$41.4A2.A.A86.A$42.2A91.A$
109.2A$44.2A62.A.A6.2A$43.A.A64.A7.2A13.A$45.A71.A15.2A$132.A.A$127.
2A$126.4A$126.2A.2A$128.2A6$30.2A93.2A$29.A.A94.2A5.3A$31.A93.A9.A$
134.A!
-
Mathemagician314
- Posts: 154
- Joined: November 15th, 2023, 3:15 pm
- Location: Toroidal Universe MKA-84
Re: 13131: The B-Heptomino/Glider Spaceship Thread
This thread has been dead for three years -- can we maybe revive it? I don't have any contributions to make within this post, but I think that we have enough tools to finish this project, more tools than we had three years ago.
So this post has some academic content in it, is the next step using rakes made from climbers to synthesize Jormungant's frontend? If so, would we need to do that manually or is there a way we can create a program to do that if we feed it the rakes and the required syntheses? (I assume manually, but you never know. Also it seems like doing it manually would take a really long time...) In addition, we already have a possible backend by PC101.
Here are some things that I think might be helpful, from earlier in the thread.
By C28, this makes a long boat, which is a one-time turner in multiple ways:
Again by C28, this cleanly generates blocks, which is very helpful since a B-heptomino can climb on blocks:
By Jormungant, generates blocks and gliders:
In addition, there's a lot of useful stuff scattered throughout this thread. So what do we have to do next?
So this post has some academic content in it, is the next step using rakes made from climbers to synthesize Jormungant's frontend? If so, would we need to do that manually or is there a way we can create a program to do that if we feed it the rakes and the required syntheses? (I assume manually, but you never know. Also it seems like doing it manually would take a really long time...) In addition, we already have a possible backend by PC101.
Here are some things that I think might be helpful, from earlier in the thread.
By C28, this makes a long boat, which is a one-time turner in multiple ways:
Code: Select all
x = 57, y = 131, rule = B3/S23
2bo$obo$b2o19$7bobo$8b2o$8bo18$15bo$16bo$14b3o7$54b2o$54b2o11$21bo$22b
2o29b2o$21b2o30b2o12$52b2o$52b2o6$29bo$27bobo$28b2o4$51b2o$51b2o12$50b
2o$50b2o$34bobo$35b2o$35bo9$49b2o$49b2o$43bo$42b3o$41bo2b2o$41b4o7b3o
$44bobo5bo2bo$44bo2bo3bo3bo$44b3o4b4o$43bobo6bo$43bobo$43b3o3$52b2ob2o
$52bob3o!
Code: Select all
x = 77, y = 190, rule = B3/S23
bo$2bo$3o4$16bo$17bo$15b3o13$7bo$8b2o$7b2o4$22bo$23b2o$22b2o13$15bo$13b
obo$14b2o4$30bo$28bobo$29b2o13$20bobo$21b2o$21bo4$35bobo$36b2o$36bo12$
28bo$29bo$27b3o4$43bo$44bo$42b3o13$34bo$35b2o$34b2o4$49bo$50b2o$49b2o
13$42bo$40bobo$41b2o4$57bo$55bobo$56b2o13$47bobo$48b2o$48bo4$62bobo$63b
2o$63bo12$55bo$56bo$54b3o3$73bo$72b3o$72bob2o$73bo2bo$74b2o$74bo2$61b
3o7b2o$60bo2bo6bo$60bo2bo$59bo2bo6bobo2bo$59bo2bo6bob3obo$63b2o3b3ob2o
bo$63b2o4bobo$61bo3bo3b3o$64b2o4bo$66bo$61bo3bo$62b3o!
Code: Select all
x = 181, y = 566, rule = B3/S23
bo$2bo$3o4$16bo$17bo$15b3o13$7bo$8b2o$7b2o4$22bo$23b2o$22b2o13$15bo$
13bobo$14b2o4$30bo$28bobo$29b2o13$20bobo$21b2o$21bo4$35bobo$36b2o$36bo
12$28bo$29bo$27b3o4$43bo$44bo$42b3o13$34bo$35b2o$34b2o4$49bo$50b2o$49b
2o13$42bo$40bobo$41b2o4$57bo$55bobo$56b2o13$47bobo$48b2o$48bo4$62bobo$
63b2o$63bo12$55bo$56bo$54b3o4$70bo$71bo$69b3o13$61bo$62b2o$61b2o4$76bo
$77b2o$76b2o13$69bo$67bobo$68b2o4$84bo$82bobo$83b2o13$74bobo$75b2o$75b
o4$89bobo$90b2o$90bo12$82bo$83bo$81b3o4$97bo$98bo$96b3o13$88bo$89b2o$
88b2o4$103bo$104b2o$103b2o7$110bo$109b3o$108b2o2bo4$96b2o10b2o$94bo4b
2o8b3o$95bo5bo10bo$100b2o8b3o$110b2o$96bo2bo$97b2o$100b2o8bobo$99b3o9b
2o$100bo10bo$97bo2bo$98b2o6bo$105bobo$101bo3bo2bo$100bobo3b2o$97bo4b2o
$97bo4bo$97bo2b2o$97b2o$98bobo$99bo$103bo$104bo$102b3o3$100b2o$100b2o
16bo$119bo$117b3o10$99b2o$99b2o2$109bo$110b2o$109b2o4$124bo$125b2o$
124b2o2$98b2o$98b2o10$117bo$115bobo$97b2o17b2o$97b2o3$132bo$130bobo$
131b2o7$96b2o$96b2o5$122bobo$123b2o$123bo4$137bobo$95b2o41b2o$95b2o41b
o12$94b2o34bo$94b2o35bo$129b3o4$145bo$146bo$144b3o$148b3o$147bo2bo$
151bo$147b2o$93b2o52b2o3bo$93b2o57bo$150bo$148b3o$148b2o$138b3o7bo$
137bo2bo8b2o$137bo4bo6bobo$142bo5bo3bo$142b2o5b2o$139bob2o$140bo2$92b
2o$92b2o$153bo$137b2o12bobo$152b2o$137bo2bo$141bo$138bo2bo$139bo5$91b
2o$91b2o3$143bobo$144b2o$139b2o3bo$139b2o3$158bobo$159b2o$159bo$90b2o$
90b2o5$138b2o$138b2o4$151bo$152bo$89b2o59b3o$89b2o$92b3o$91bo2bo$95bo
70bo$91b2o74bo$91b2o3bo40b2o26b3o$96bo40b2o$94bo$92b3o$92b2o$92bo$93b
2o$93bobo$92bo3bo$93b2o4$136b2o19bo$136b2o20b2o$97bo59b2o$95bobo$96b2o
2$172bo$173b2o$172b2o5$135b2o$135b2o7$165bo$163bobo$102bobo59b2o$103b
2o$103bo$134b2o$134b2o44bo$178bobo$179b2o10$133b2o$133b2o3$110bo$111bo
$109b3o7$132b2o$132b2o11$116bo$117b2o12b2o$116b2o13b2o12$130b2o$125bo
4b2o$124b3o$123b2o2bo2$127b2o$127b2o$126bo2bo$125b3o!
Can we make a (28,3)c/84 spaceship??
[currently inactive]
Code: Select all
x = 3, y = 4, rule = B3-e4i5-a/S2-i3-a4cr5e6c
o$obo$b2o$2o!
[[ THEME PCA ]]
Code: Select all
x = 6, y = 5, rule = 2-ak34/2kn3-r4aijnr5c/5
.3A$.ABA$DAD2A$.ABADC$.3A2B!
[[ THEME BLUES ]]
-
Jormungant
- Posts: 853
- Joined: May 27th, 2016, 1:01 am
Re: 13131: The B-Heptomino/Glider Spaceship Thread
Might as well put this thing I had in the freezer in here, since I think there might be an issue with making MWSSes on one side of the catterpillar, which is required by the current frontend I made. I had an idea to multiply gliders on the side with the helix, I found some glider/xwss reaction that somehow produce the right shift between multiplied gliders, but the issue remaining is to translate this to a block (or whatever legal life can be burned) trail. I have someting that is close to managing this, but not quite:
Code: Select all
x = 3286, y = 3238, rule = LifeHistory
10.3A$10.A2.A4.A5.3A$4.2A4.A6.3A4.A2.A4.A5.3A$5.2A3.A5.2A.A4.A6.3A4.A
2.A4.A5.3A$4.2A5.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A$A.2A.A10.3A6.A.
A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A$2.3A11.3A11.3A6.A.A2.3A5.A5.2A.A4.
A6.3A4.A2.A4.A5.3A$2.2A13.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A
4.A5.3A$31.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A$45.2A
11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A$59.2A11.3A11.3A6.A.A2.3A
5.A5.2A.A4.A6.3A9.A$73.2A11.3A11.3A6.A.A2.3A5.A5.2A.A8.3A$87.2A11.3A
11.3A6.A.A2.3A9.A.2A$101.2A11.3A11.3A10.3A$115.2A11.3A10.3A$129.2A10.
3A$141.2A4$126.3A$112.3A5.A4.A2.A$98.3A5.A4.A2.A4.3A6.A5.3A$84.3A5.A
4.A2.A4.3A6.A4.A.2A5.A5.A2.A$70.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A
6.A$56.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.A3.A4.3A$42.3A5.A4.
A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.A3.A3.A2.A$28.3A5.A4.A2.A4.
3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.2A12.A10.A$22.A4.A2.A4.3A6.A4.A.2A
5.A5.3A2.A.A6.3A11.3A11.2A27.A.A7.A$21.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.
3A11.2A48.A.A$21.A.2A5.A5.3A2.A.A6.3A11.3A11.2A$22.3A2.A.A6.3A11.3A
11.2A$22.3A11.3A11.2A88.A$15.A6.3A11.2A101.3A$14.3A5.2A114.2A.A$14.A.
2A120.3A$15.3A121.2A$15.2A3$26.3A$26.A2.A4.A5.3A144.A$17.A8.A6.3A4.A
2.A4.A5.3A130.2A$16.3A7.A5.2A.A4.A6.3A4.A2.A4.A5.3A115.A.A$16.A.2A7.A
.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A$17.3A12.3A6.A.A2.3A5.A5.2A.A4.A6.
3A4.A2.A4.A5.3A$17.2A13.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A
$33.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A$47.2A11.3A11.
3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A$61.2A11.3A11.3A6.A.A2.3A5.A
5.2A.A4.A6.3A4.A2.A4.A$75.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A9.A$
89.2A11.3A11.3A6.A.A2.3A5.A5.2A.A8.3A$103.2A11.3A11.3A6.A.A2.3A9.A.2A
$117.2A11.3A11.3A10.3A$131.2A11.3A10.3A$145.2A10.3A$157.2A4$142.3A$
128.3A5.A4.A2.A$114.3A5.A4.A2.A4.3A6.A5.3A$100.3A5.A4.A2.A4.3A6.A4.A.
2A5.A5.A2.A$86.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.A$72.3A5.A4.A2.A
4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.A3.A4.3A$58.3A5.A4.A2.A4.3A6.A4.A.2A
5.A5.3A2.A.A6.3A11.3A11.A3.A3.A2.A$44.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A
2.A.A6.3A11.3A11.2A12.A10.A$38.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A
11.3A11.2A27.A.A7.A$37.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.2A48.A.A$
37.A.2A5.A5.3A2.A.A6.3A11.3A11.2A$38.3A2.A.A6.3A11.3A11.2A$38.3A11.3A
11.2A88.A$31.A6.3A11.2A101.3A$30.3A5.2A114.2A.A$30.A.2A120.3A$31.3A
121.2A$31.2A3$42.3A$42.A2.A4.A5.3A$33.A8.A6.3A4.A2.A4.A5.3A$32.3A7.A
5.2A.A4.A6.3A4.A2.A4.A5.3A$32.A.2A7.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A
5.3A$33.3A12.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A$33.2A13.3A11.3A
6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A$49.2A11.3A11.3A6.A.A2.3A5.A5.
2A.A4.A6.3A4.A2.A4.A5.3A$63.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A
2.A4.A5.3A$77.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A$91.2A11.
3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A9.A$105.2A11.3A11.3A6.A.A2.3A5.A5.2A.
A8.3A$119.2A11.3A11.3A6.A.A2.3A9.A.2A$133.2A11.3A11.3A10.3A$147.2A11.
3A10.3A$161.2A10.3A$173.2A4$158.3A$144.3A5.A4.A2.A$130.3A5.A4.A2.A4.
3A6.A5.3A$116.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.A2.A$102.3A5.A4.A2.A4.3A6.
A4.A.2A5.A5.3A2.A.A6.A$88.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.
A3.A4.3A$74.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.A3.A3.A2.
A$60.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.2A12.A10.A$54.A
4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.2A27.A.A7.A$53.3A6.A4.A.2A
5.A5.3A2.A.A6.3A11.3A11.2A48.A.A$53.A.2A5.A5.3A2.A.A6.3A11.3A11.2A$
54.3A2.A.A6.3A11.3A11.2A$54.3A11.3A11.2A88.A$47.A6.3A11.2A101.3A$46.
3A5.2A114.2A.A$46.A.2A120.3A$47.3A121.2A$47.2A3$58.3A$58.A2.A4.A5.3A$
49.A8.A6.3A4.A2.A4.A5.3A$48.3A7.A5.2A.A4.A6.3A4.A2.A4.A5.3A$48.A.2A7.
A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A$49.3A12.3A6.A.A2.3A5.A5.2A.A4.A
6.3A4.A2.A4.A5.3A164.A$49.2A13.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A
4.A5.3A150.2A$65.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A
135.A.A$79.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A$93.2A
11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A$107.2A11.3A11.3A6.A.A2.
3A5.A5.2A.A4.A6.3A9.A$121.2A11.3A11.3A6.A.A2.3A5.A5.2A.A8.3A$135.2A
11.3A11.3A6.A.A2.3A9.A.2A$149.2A11.3A11.3A10.3A$163.2A11.3A10.3A$177.
2A10.3A$189.2A4$174.3A$160.3A5.A4.A2.A$146.3A5.A4.A2.A4.3A6.A5.3A$
132.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.A2.A$118.3A5.A4.A2.A4.3A6.A4.A.2A5.A
5.3A2.A.A6.A$104.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.A3.A4.3A$
90.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.A3.A3.A2.A$76.3A5.
A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.2A12.A10.A$70.A4.A2.A4.3A
6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.2A27.A.A7.A$69.3A6.A4.A.2A5.A5.3A2.A
.A6.3A11.3A11.2A48.A.A$69.A.2A5.A5.3A2.A.A6.3A11.3A11.2A$70.3A2.A.A6.
3A11.3A11.2A$70.3A11.3A11.2A88.A$63.A6.3A11.2A101.3A$62.3A5.2A114.2A.
A$62.A.2A120.3A$63.3A121.2A$63.2A3$74.3A$74.A2.A4.A5.3A$65.A8.A6.3A4.
A2.A4.A5.3A$64.3A7.A5.2A.A4.A6.3A4.A2.A4.A5.3A$64.A.2A7.A.A2.3A5.A5.
2A.A4.A6.3A4.A2.A4.A5.3A$65.3A12.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A
5.3A$65.2A13.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A$81.2A11.3A
11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A$95.2A11.3A11.3A6.A.A2.3A
5.A5.2A.A4.A6.3A4.A2.A4.A5.3A$109.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.
3A4.A2.A4.A$123.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A9.A$137.2A11.3A
11.3A6.A.A2.3A5.A5.2A.A8.3A$151.2A11.3A11.3A6.A.A2.3A9.A.2A$165.2A11.
3A11.3A10.3A$179.2A11.3A10.3A$193.2A10.3A$205.2A4$190.3A$176.3A5.A4.A
2.A$162.3A5.A4.A2.A4.3A6.A5.3A$148.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.A2.A$
134.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.A$120.3A5.A4.A2.A4.3A6.A4.A
.2A5.A5.3A2.A.A6.3A11.A3.A4.3A$106.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A
.A6.3A11.3A11.A3.A3.A2.A$92.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A
11.3A11.2A12.A10.A$86.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.2A
27.A.A7.A$85.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.2A48.A.A$85.A.2A5.A5.
3A2.A.A6.3A11.3A11.2A$86.3A2.A.A6.3A11.3A11.2A$86.3A11.3A11.2A88.A$
79.A6.3A11.2A101.3A$78.3A5.2A114.2A.A$78.A.2A120.3A$79.3A121.2A$79.2A
3$90.3A$90.A2.A4.A5.3A$81.A8.A6.3A4.A2.A4.A5.3A$80.3A7.A5.2A.A4.A6.3A
4.A2.A4.A5.3A$80.A.2A7.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A$81.3A12.
3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A$81.2A13.3A11.3A6.A.A2.3A5.A
5.2A.A4.A6.3A4.A2.A4.A5.3A$97.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.
A2.A4.A5.3A$111.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A$
125.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A192.A$139.2A11.3A
11.3A6.A.A2.3A5.A5.2A.A4.A6.3A9.A181.2A$153.2A11.3A11.3A6.A.A2.3A5.A
5.2A.A8.3A179.A.A$167.2A11.3A11.3A6.A.A2.3A9.A.2A$181.2A11.3A11.3A10.
3A$195.2A11.3A10.3A$209.2A10.3A$221.2A4$206.3A$192.3A5.A4.A2.A$178.3A
5.A4.A2.A4.3A6.A5.3A$164.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.A2.A$150.3A5.A
4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.A$136.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.
3A2.A.A6.3A11.A3.A4.3A$122.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A
11.3A11.A3.A3.A2.A$108.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A
11.2A12.A10.A$102.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.2A27.A.
A7.A$101.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.2A48.A.A$101.A.2A5.A5.3A
2.A.A6.3A11.3A11.2A$102.3A2.A.A6.3A11.3A11.2A$102.3A11.3A11.2A88.A$
95.A6.3A11.2A101.3A$94.3A5.2A114.2A.A$94.A.2A120.3A$95.3A121.2A$95.2A
3$106.3A$106.A2.A4.A5.3A$97.A8.A6.3A4.A2.A4.A5.3A$96.3A7.A5.2A.A4.A6.
3A4.A2.A4.A5.3A$96.A.2A7.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A$97.3A
12.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A$97.2A13.3A11.3A6.A.A2.3A
5.A5.2A.A4.A6.3A4.A2.A4.A5.3A$113.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.
3A4.A2.A4.A5.3A$127.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.
3A$141.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A$155.2A11.3A11.
3A6.A.A2.3A5.A5.2A.A4.A6.3A9.A$169.2A11.3A11.3A6.A.A2.3A5.A5.2A.A8.3A
$183.2A11.3A11.3A6.A.A2.3A9.A.2A$197.2A11.3A11.3A10.3A$211.2A11.3A10.
3A$225.2A10.3A$237.2A4$222.3A$208.3A5.A4.A2.A$194.3A5.A4.A2.A4.3A6.A
5.3A$180.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.A2.A$166.3A5.A4.A2.A4.3A6.A4.A.
2A5.A5.3A2.A.A6.A$152.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.A3.A
4.3A$138.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.A3.A3.A2.A$
124.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.2A12.A10.A$118.A
4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.2A27.A.A7.A$117.3A6.A4.A.
2A5.A5.3A2.A.A6.3A11.3A11.2A48.A.A$117.A.2A5.A5.3A2.A.A6.3A11.3A11.2A
$118.3A2.A.A6.3A11.3A11.2A$118.3A11.3A11.2A88.A$111.A6.3A11.2A101.3A$
110.3A5.2A114.2A.A$110.A.2A120.3A$111.3A121.2A$111.2A3$122.3A$122.A2.
A4.A5.3A$113.A8.A6.3A4.A2.A4.A5.3A$112.3A7.A5.2A.A4.A6.3A4.A2.A4.A5.
3A$112.A.2A7.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A$113.3A12.3A6.A.A2.
3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A$113.2A13.3A11.3A6.A.A2.3A5.A5.2A.A4.A
6.3A4.A2.A4.A5.3A$129.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A
5.3A$143.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A$157.2A11.
3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A$171.2A11.3A11.3A6.A.A2.3A5.
A5.2A.A4.A6.3A9.A$185.2A11.3A11.3A6.A.A2.3A5.A5.2A.A8.3A$199.2A11.3A
11.3A6.A.A2.3A9.A.2A$213.2A11.3A11.3A10.3A255.A$227.2A11.3A10.3A255.
2A$241.2A10.3A254.A.A$253.2A4$238.3A$224.3A5.A4.A2.A$210.3A5.A4.A2.A
4.3A6.A5.3A$196.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.A2.A$182.3A5.A4.A2.A4.3A
6.A4.A.2A5.A5.3A2.A.A6.A$168.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A
11.A3.A4.3A$154.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.A3.A
3.A2.A$140.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.2A12.A10.A
$134.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.2A27.A.A7.A$133.3A6.
A4.A.2A5.A5.3A2.A.A6.3A11.3A11.2A48.A.A$133.A.2A5.A5.3A2.A.A6.3A11.3A
11.2A$134.3A2.A.A6.3A11.3A11.2A$134.3A11.3A11.2A88.A$127.A6.3A11.2A
101.3A$126.3A5.2A114.2A.A$126.A.2A120.3A$127.3A121.2A$127.2A3$138.3A$
138.A2.A4.A5.3A$129.A8.A6.3A4.A2.A4.A5.3A$128.3A7.A5.2A.A4.A6.3A4.A2.
A4.A5.3A$128.A.2A7.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A$129.3A12.3A6.
A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A$129.2A13.3A11.3A6.A.A2.3A5.A5.2A
.A4.A6.3A4.A2.A4.A5.3A$145.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.
A4.A5.3A$159.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A$173.
2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A$187.2A11.3A11.3A6.A.A
2.3A5.A5.2A.A4.A6.3A9.A$201.2A11.3A11.3A6.A.A2.3A5.A5.2A.A8.3A$215.2A
11.3A11.3A6.A.A2.3A9.A.2A$229.2A11.3A11.3A10.3A$243.2A11.3A10.3A$257.
2A10.3A$269.2A4$254.3A$240.3A5.A4.A2.A$226.3A5.A4.A2.A4.3A6.A5.3A$
212.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.A2.A$198.3A5.A4.A2.A4.3A6.A4.A.2A5.A
5.3A2.A.A6.A$184.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.A3.A4.3A$
170.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.A3.A3.A2.A$156.3A
5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.2A12.A10.A$150.A4.A2.A
4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.2A27.A.A7.A$149.3A6.A4.A.2A5.A5.
3A2.A.A6.3A11.3A11.2A48.A.A$149.A.2A5.A5.3A2.A.A6.3A11.3A11.2A$150.3A
2.A.A6.3A11.3A11.2A$150.3A11.3A11.2A88.A$143.A6.3A11.2A101.3A$142.3A
5.2A114.2A.A$142.A.2A120.3A$143.3A121.2A$143.2A3$154.3A$154.A2.A4.A5.
3A$145.A8.A6.3A4.A2.A4.A5.3A$144.3A7.A5.2A.A4.A6.3A4.A2.A4.A5.3A$144.
A.2A7.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A$145.3A12.3A6.A.A2.3A5.A5.
2A.A4.A6.3A4.A2.A4.A5.3A$145.2A13.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A
2.A4.A5.3A$161.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A$
175.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A$189.2A11.3A11.
3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A$203.2A11.3A11.3A6.A.A2.3A5.A5.2A
.A4.A6.3A9.A$217.2A11.3A11.3A6.A.A2.3A5.A5.2A.A8.3A$231.2A11.3A11.3A
6.A.A2.3A9.A.2A$245.2A11.3A11.3A10.3A$259.2A11.3A10.3A$273.2A10.3A$
285.2A$619.A$619.2A$618.A.A$270.3A$256.3A5.A4.A2.A$242.3A5.A4.A2.A4.
3A6.A5.3A$228.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.A2.A$214.3A5.A4.A2.A4.3A6.
A4.A.2A5.A5.3A2.A.A6.A$200.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A
11.A3.A4.3A$186.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.A3.A
3.A2.A$172.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.2A12.A10.A
$166.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.2A27.A.A7.A$165.3A6.
A4.A.2A5.A5.3A2.A.A6.3A11.3A11.2A48.A.A$165.A.2A5.A5.3A2.A.A6.3A11.3A
11.2A$166.3A2.A.A6.3A11.3A11.2A$166.3A11.3A11.2A88.A$159.A6.3A11.2A
101.3A$158.3A5.2A114.2A.A$158.A.2A120.3A$159.3A121.2A$159.2A3$170.3A$
170.A2.A4.A5.3A$161.A8.A6.3A4.A2.A4.A5.3A$160.3A7.A5.2A.A4.A6.3A4.A2.
A4.A5.3A$160.A.2A7.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A$161.3A12.3A6.
A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A$161.2A13.3A11.3A6.A.A2.3A5.A5.2A
.A4.A6.3A4.A2.A4.A5.3A$177.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.
A4.A5.3A$191.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A$205.
2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A$219.2A11.3A11.3A6.A.A
2.3A5.A5.2A.A4.A6.3A9.A$233.2A11.3A11.3A6.A.A2.3A5.A5.2A.A8.3A$247.2A
11.3A11.3A6.A.A2.3A9.A.2A$261.2A11.3A11.3A10.3A$275.2A11.3A10.3A$289.
2A10.3A$301.2A4$286.3A$272.3A5.A4.A2.A$258.3A5.A4.A2.A4.3A6.A5.3A$
244.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.A2.A$230.3A5.A4.A2.A4.3A6.A4.A.2A5.A
5.3A2.A.A6.A$216.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.A3.A4.3A$
202.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.A3.A3.A2.A$188.3A
5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.2A12.A10.A$182.A4.A2.A
4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.2A27.A.A7.A$181.3A6.A4.A.2A5.A5.
3A2.A.A6.3A11.3A11.2A48.A.A$181.A.2A5.A5.3A2.A.A6.3A11.3A11.2A$182.3A
2.A.A6.3A11.3A11.2A$182.3A11.3A11.2A88.A$175.A6.3A11.2A101.3A$174.3A
5.2A114.2A.A$174.A.2A120.3A$175.3A121.2A$175.2A3$186.3A$186.A2.A4.A5.
3A$177.A8.A6.3A4.A2.A4.A5.3A$176.3A7.A5.2A.A4.A6.3A4.A2.A4.A5.3A$176.
A.2A7.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A$177.3A12.3A6.A.A2.3A5.A5.
2A.A4.A6.3A4.A2.A4.A5.3A$177.2A13.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A
2.A4.A5.3A$193.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A$
207.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A$221.2A11.3A11.
3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A$235.2A11.3A11.3A6.A.A2.3A5.A5.2A
.A4.A6.3A9.A$249.2A11.3A11.3A6.A.A2.3A5.A5.2A.A8.3A$263.2A11.3A11.3A
6.A.A2.3A9.A.2A$277.2A11.3A11.3A10.3A$291.2A11.3A10.3A$305.2A10.3A$
317.2A4$302.3A$288.3A5.A4.A2.A422.A$274.3A5.A4.A2.A4.3A6.A5.3A414.2A$
260.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.A2.A412.A.A$246.3A5.A4.A2.A4.3A6.A4.
A.2A5.A5.3A2.A.A6.A$232.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.A
3.A4.3A$218.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.A3.A3.A2.
A$204.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.2A12.A10.A$198.
A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.2A27.A.A7.A421.3A$197.3A
6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.2A48.A.A421.A2.A$197.A.2A5.A5.3A2.A.
A6.3A11.3A11.2A489.A$198.3A2.A.A6.3A11.3A11.2A499.A3.A$198.3A11.3A11.
2A88.A428.A$191.A6.3A11.2A101.3A424.A.A7.A$190.3A5.2A114.2A.A433.3A$
190.A.2A120.3A433.2A.A$191.3A121.2A433.3A$191.2A558.2A3$202.3A$202.A
2.A4.A5.3A$193.A8.A6.3A4.A2.A4.A5.3A$192.3A7.A5.2A.A4.A6.3A4.A2.A4.A
5.3A$192.A.2A7.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A489.A$193.3A12.3A
6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A474.3A$193.2A13.3A11.3A6.A.A2.
3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A459.2A.A$209.2A11.3A11.3A6.A.A2.3A5.A
5.2A.A4.A6.3A4.A2.A4.A5.3A445.3A$223.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.
A6.3A4.A2.A4.A5.3A432.2A$237.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A
2.A4.A$251.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A9.A$265.2A11.3A11.3A
6.A.A2.3A5.A5.2A.A8.3A$279.2A11.3A11.3A6.A.A2.3A9.A.2A$293.2A11.3A11.
3A10.3A$307.2A11.3A10.3A$321.2A10.3A$333.2A4$318.3A$304.3A5.A4.A2.A$
290.3A5.A4.A2.A4.3A6.A5.3A418.A$276.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.A2.A
416.3A$262.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.A419.A.2A$248.3A5.A
4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.A3.A4.3A409.3A$234.3A5.A4.A2.A
4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.A3.A3.A2.A409.3A$220.3A5.A4.A2.A
4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.2A12.A10.A409.2A$214.A4.A2.A4.3A
6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.2A27.A.A7.A421.3A$213.3A6.A4.A.2A5.A
5.3A2.A.A6.3A11.3A11.2A48.A.A421.A2.A$213.A.2A5.A5.3A2.A.A6.3A11.3A
11.2A489.A$214.3A2.A.A6.3A11.3A11.2A499.A3.A$214.3A11.3A11.2A88.A428.
A16.3A$207.A6.3A11.2A101.3A424.A.A7.A8.A2.A$206.3A5.2A114.2A.A433.3A
10.A$206.A.2A120.3A433.2A.A10.A$207.3A121.2A433.3A8.A.A$207.2A558.2A
3$218.3A552.A$218.A2.A4.A5.3A537.3A$209.A8.A6.3A4.A2.A4.A5.3A522.2A.A
$208.3A7.A5.2A.A4.A6.3A4.A2.A4.A5.3A508.3A$208.A.2A7.A.A2.3A5.A5.2A.A
4.A6.3A4.A2.A4.A5.3A489.A4.3A$209.3A12.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A
2.A4.A5.3A474.3A4.2A6.A$209.2A13.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A
2.A4.A5.3A459.2A.A11.3A$225.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A
2.A4.A5.3A445.3A12.A.2A$239.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A
2.A4.A5.3A432.2A13.3A$253.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A
4.A441.2A$267.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A9.A$281.2A11.3A11.
3A6.A.A2.3A5.A5.2A.A8.3A$295.2A11.3A11.3A6.A.A2.3A9.A.2A$309.2A11.3A
11.3A10.3A$323.2A11.3A10.3A$337.2A10.3A$349.2A$837.A$837.2A$836.A.A$
334.3A$320.3A5.A4.A2.A467.3A$306.3A5.A4.A2.A4.3A6.A5.3A418.A39.A2.A$
292.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.A2.A416.3A41.A$278.3A5.A4.A2.A4.3A6.
A4.A.2A5.A5.3A2.A.A6.A419.A.2A36.A3.A$264.3A5.A4.A2.A4.3A6.A4.A.2A5.A
5.3A2.A.A6.3A11.A3.A4.3A409.3A40.A$250.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.
3A2.A.A6.3A11.3A11.A3.A3.A2.A409.3A37.A.A7.A20.A$236.3A5.A4.A2.A4.3A
6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.2A12.A10.A409.2A47.3A19.2A$230.A4.A
2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.2A27.A.A7.A421.3A33.2A.A18.A.
A$229.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.2A48.A.A421.A2.A33.3A$229.A.
2A5.A5.3A2.A.A6.3A11.3A11.2A489.A34.2A$230.3A2.A.A6.3A11.3A11.2A499.A
3.A$230.3A11.3A11.2A88.A428.A16.3A$223.A6.3A11.2A101.3A424.A.A7.A8.A
2.A$222.3A5.2A114.2A.A433.3A10.A$222.A.2A120.3A433.2A.A10.A$223.3A
121.2A433.3A8.A.A$223.2A558.2A26.A$810.3A$809.2A.A$234.3A552.A19.3A$
234.A2.A4.A5.3A537.3A19.2A$225.A8.A6.3A4.A2.A4.A5.3A522.2A.A$224.3A7.
A5.2A.A4.A6.3A4.A2.A4.A5.3A508.3A39.A$224.A.2A7.A.A2.3A5.A5.2A.A4.A6.
3A4.A2.A4.A5.3A489.A4.3A39.2A$225.3A12.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A
2.A4.A5.3A474.3A4.2A6.A31.A.A$225.2A13.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.
3A4.A2.A4.A5.3A459.2A.A11.3A$241.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.
3A4.A2.A4.A5.3A445.3A12.A.2A$255.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.
3A4.A2.A4.A5.3A432.2A13.3A$269.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A
4.A2.A4.A441.2A$283.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A9.A$297.2A
11.3A11.3A6.A.A2.3A5.A5.2A.A8.3A$311.2A11.3A11.3A6.A.A2.3A9.A.2A$325.
2A11.3A11.3A10.3A$339.2A11.3A10.3A481.3A$353.2A10.3A440.A39.A2.A$365.
2A440.3A41.A$807.A.2A36.A3.A$808.3A40.A$808.3A37.A.A7.A$350.3A455.2A
47.3A$336.3A5.A4.A2.A467.3A33.2A.A$322.3A5.A4.A2.A4.3A6.A5.3A418.A39.
A2.A33.3A$308.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.A2.A416.3A41.A34.2A$294.3A
5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.A419.A.2A36.A3.A$280.3A5.A4.A2.A
4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.A3.A4.3A409.3A40.A16.3A$266.3A5.A4.A
2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.A3.A3.A2.A409.3A37.A.A7.A8.A
2.A$252.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.2A12.A10.A
409.2A47.3A10.A$246.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.2A27.
A.A7.A421.3A33.2A.A10.A$245.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.2A48.A
.A421.A2.A33.3A8.A.A$245.A.2A5.A5.3A2.A.A6.3A11.3A11.2A489.A34.2A26.A
$246.3A2.A.A6.3A11.3A11.2A499.A3.A61.3A$246.3A11.3A11.2A88.A428.A16.
3A41.2A.A$239.A6.3A11.2A101.3A424.A.A7.A8.A2.A21.A19.3A$238.3A5.2A
114.2A.A433.3A10.A20.3A19.2A$238.A.2A120.3A433.2A.A10.A19.2A.A$239.3A
121.2A433.3A8.A.A20.3A$239.2A558.2A26.A4.3A$826.3A4.2A6.A$825.2A.A11.
3A$250.3A552.A19.3A12.A.2A$250.A2.A4.A5.3A537.3A19.2A13.3A$241.A8.A6.
3A4.A2.A4.A5.3A522.2A.A34.2A$240.3A7.A5.2A.A4.A6.3A4.A2.A4.A5.3A508.
3A$240.A.2A7.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A489.A4.3A$241.3A12.
3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A474.3A4.2A6.A$241.2A13.3A11.
3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A459.2A.A11.3A$257.2A11.3A11.
3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A445.3A12.A.2A$271.2A11.3A11.
3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A432.2A13.3A38.A$285.2A11.3A
11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A441.2A38.3A$299.2A11.3A11.3A6.
A.A2.3A5.A5.2A.A4.A6.3A9.A470.A.2A$313.2A11.3A11.3A6.A.A2.3A5.A5.2A.A
8.3A470.3A$327.2A11.3A11.3A6.A.A2.3A9.A.2A469.3A$341.2A11.3A11.3A10.
3A469.2A$355.2A11.3A10.3A481.3A$369.2A10.3A440.A39.A2.A$381.2A440.3A
41.A$823.A.2A36.A3.A$824.3A40.A16.3A$824.3A37.A.A7.A8.A2.A$366.3A455.
2A47.3A10.A$352.3A5.A4.A2.A467.3A33.2A.A10.A58.A$338.3A5.A4.A2.A4.3A
6.A5.3A418.A39.A2.A33.3A8.A.A59.2A$324.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.A
2.A416.3A41.A34.2A69.A.A$310.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.A
419.A.2A36.A3.A$296.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.A3.A4.
3A409.3A40.A16.3A$282.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A
11.A3.A3.A2.A409.3A37.A.A7.A8.A2.A21.A$268.3A5.A4.A2.A4.3A6.A4.A.2A5.
A5.3A2.A.A6.3A11.3A11.2A12.A10.A409.2A47.3A10.A20.3A$262.A4.A2.A4.3A
6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.2A27.A.A7.A421.3A33.2A.A10.A19.2A.A$
261.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.2A48.A.A421.A2.A33.3A8.A.A20.
3A$261.A.2A5.A5.3A2.A.A6.3A11.3A11.2A489.A34.2A26.A4.3A62.A$262.3A2.A
.A6.3A11.3A11.2A499.A3.A61.3A4.2A6.A55.2A$262.3A11.3A11.2A88.A428.A
16.3A41.2A.A11.3A53.A.A$255.A6.3A11.2A101.3A424.A.A7.A8.A2.A21.A19.3A
12.A.2A$254.3A5.2A114.2A.A433.3A10.A20.3A19.2A13.3A$254.A.2A120.3A
433.2A.A10.A19.2A.A34.2A$255.3A121.2A433.3A8.A.A20.3A$255.2A558.2A26.
A4.3A$842.3A4.2A6.A$841.2A.A11.3A80.A$266.3A552.A19.3A12.A.2A79.2A$
266.A2.A4.A5.3A537.3A19.2A13.3A78.A.A$257.A8.A6.3A4.A2.A4.A5.3A522.2A
.A34.2A$256.3A7.A5.2A.A4.A6.3A4.A2.A4.A5.3A508.3A$256.A.2A7.A.A2.3A5.
A5.2A.A4.A6.3A4.A2.A4.A5.3A489.A4.3A$257.3A12.3A6.A.A2.3A5.A5.2A.A4.A
6.3A4.A2.A4.A5.3A474.3A4.2A6.A$257.2A13.3A11.3A6.A.A2.3A5.A5.2A.A4.A
6.3A4.A2.A4.A5.3A459.2A.A11.3A$273.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A
6.3A4.A2.A4.A5.3A445.3A12.A.2A79.3A$287.2A11.3A11.3A6.A.A2.3A5.A5.2A.
A4.A6.3A4.A2.A4.A5.3A432.2A13.3A38.A39.A2.A23.A$301.2A11.3A11.3A6.A.A
2.3A5.A5.2A.A4.A6.3A4.A2.A4.A441.2A38.3A41.A23.2A$315.2A11.3A11.3A6.A
.A2.3A5.A5.2A.A4.A6.3A9.A470.A.2A36.A3.A22.A.A$329.2A11.3A11.3A6.A.A
2.3A5.A5.2A.A8.3A470.3A40.A$343.2A11.3A11.3A6.A.A2.3A9.A.2A469.3A37.A
.A7.A$357.2A11.3A11.3A10.3A469.2A47.3A$371.2A11.3A10.3A481.3A33.2A.A$
385.2A10.3A440.A39.A2.A33.3A$397.2A440.3A41.A34.2A$839.A.2A36.A3.A$
840.3A40.A16.3A$840.3A37.A.A7.A8.A2.A$382.3A455.2A47.3A10.A$368.3A5.A
4.A2.A467.3A33.2A.A10.A$354.3A5.A4.A2.A4.3A6.A5.3A418.A39.A2.A33.3A8.
A.A$340.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.A2.A416.3A41.A34.2A26.A$326.3A5.
A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.A419.A.2A36.A3.A61.3A$312.3A5.A4.A
2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.A3.A4.3A409.3A40.A16.3A41.2A.A12.A
$298.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.A3.A3.A2.A409.3A
37.A.A7.A8.A2.A21.A19.3A13.2A$284.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.
A6.3A11.3A11.2A12.A10.A409.2A47.3A10.A20.3A19.2A12.A.A$278.A4.A2.A4.
3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.2A27.A.A7.A421.3A33.2A.A10.A19.2A.
A$277.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.2A48.A.A421.A2.A33.3A8.A.A
20.3A$277.A.2A5.A5.3A2.A.A6.3A11.3A11.2A489.A34.2A26.A4.3A$278.3A2.A.
A6.3A11.3A11.2A499.A3.A61.3A4.2A6.A$278.3A11.3A11.2A88.A428.A16.3A41.
2A.A11.3A$271.A6.3A11.2A101.3A424.A.A7.A8.A2.A21.A19.3A12.A.2A$270.3A
5.2A114.2A.A433.3A10.A20.3A19.2A13.3A$270.A.2A120.3A433.2A.A10.A19.2A
.A34.2A$271.3A121.2A433.3A8.A.A20.3A$271.2A558.2A26.A4.3A$858.3A4.2A
6.A$857.2A.A11.3A$282.3A552.A19.3A12.A.2A79.3A$282.A2.A4.A5.3A537.3A
19.2A13.3A38.A39.A2.A$273.A8.A6.3A4.A2.A4.A5.3A522.2A.A34.2A38.3A41.A
$272.3A7.A5.2A.A4.A6.3A4.A2.A4.A5.3A508.3A75.A.2A36.A3.A$272.A.2A7.A.
A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A489.A4.3A76.3A40.A$273.3A12.3A6.A.A
2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A474.3A4.2A6.A69.3A37.A.A7.A$273.2A
13.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A459.2A.A11.3A68.2A47.
3A$289.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A445.3A12.A.
2A79.3A33.2A.A$303.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A
432.2A13.3A38.A39.A2.A33.3A$317.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A
4.A2.A4.A441.2A38.3A41.A34.2A$331.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.
3A9.A470.A.2A36.A3.A$345.2A11.3A11.3A6.A.A2.3A5.A5.2A.A8.3A470.3A40.A
16.3A$359.2A11.3A11.3A6.A.A2.3A9.A.2A469.3A37.A.A7.A8.A2.A$373.2A11.
3A11.3A10.3A469.2A47.3A10.A$387.2A11.3A10.3A481.3A33.2A.A10.A$401.2A
10.3A440.A39.A2.A33.3A8.A.A$413.2A440.3A41.A34.2A26.A$855.A.2A36.A3.A
61.3A$856.3A40.A16.3A41.2A.A$856.3A37.A.A7.A8.A2.A21.A19.3A$398.3A
455.2A47.3A10.A20.3A19.2A$384.3A5.A4.A2.A467.3A33.2A.A10.A19.2A.A$
370.3A5.A4.A2.A4.3A6.A5.3A418.A39.A2.A33.3A8.A.A20.3A$356.3A5.A4.A2.A
4.3A6.A4.A.2A5.A5.A2.A416.3A41.A34.2A26.A4.3A$342.3A5.A4.A2.A4.3A6.A
4.A.2A5.A5.3A2.A.A6.A419.A.2A36.A3.A61.3A4.2A6.A$328.3A5.A4.A2.A4.3A
6.A4.A.2A5.A5.3A2.A.A6.3A11.A3.A4.3A409.3A40.A16.3A41.2A.A11.3A104.A$
314.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.A3.A3.A2.A409.3A
37.A.A7.A8.A2.A21.A19.3A12.A.2A103.2A$300.3A5.A4.A2.A4.3A6.A4.A.2A5.A
5.3A2.A.A6.3A11.3A11.2A12.A10.A409.2A47.3A10.A20.3A19.2A13.3A102.A.A$
294.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.2A27.A.A7.A421.3A33.
2A.A10.A19.2A.A34.2A$293.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.2A48.A.A
421.A2.A33.3A8.A.A20.3A$293.A.2A5.A5.3A2.A.A6.3A11.3A11.2A489.A34.2A
26.A4.3A$294.3A2.A.A6.3A11.3A11.2A499.A3.A61.3A4.2A6.A$294.3A11.3A11.
2A88.A428.A16.3A41.2A.A11.3A$287.A6.3A11.2A101.3A424.A.A7.A8.A2.A21.A
19.3A12.A.2A$286.3A5.2A114.2A.A433.3A10.A20.3A19.2A13.3A38.A90.A$286.
A.2A120.3A433.2A.A10.A19.2A.A34.2A38.3A89.2A$287.3A121.2A433.3A8.A.A
20.3A75.A.2A87.A.A$287.2A558.2A26.A4.3A76.3A$874.3A4.2A6.A69.3A$873.
2A.A11.3A68.2A$298.3A552.A19.3A12.A.2A79.3A$298.A2.A4.A5.3A537.3A19.
2A13.3A38.A39.A2.A$289.A8.A6.3A4.A2.A4.A5.3A522.2A.A34.2A38.3A41.A$
288.3A7.A5.2A.A4.A6.3A4.A2.A4.A5.3A508.3A75.A.2A36.A3.A73.A$288.A.2A
7.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A489.A4.3A76.3A40.A16.3A54.2A$
289.3A12.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A474.3A4.2A6.A69.3A
37.A.A7.A8.A2.A53.A.A$289.2A13.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A
4.A5.3A459.2A.A11.3A68.2A47.3A10.A$305.2A11.3A11.3A6.A.A2.3A5.A5.2A.A
4.A6.3A4.A2.A4.A5.3A445.3A12.A.2A79.3A33.2A.A10.A$319.2A11.3A11.3A6.A
.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A432.2A13.3A38.A39.A2.A33.3A8.A.A$
333.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A441.2A38.3A41.A34.
2A$347.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A9.A470.A.2A36.A3.A$361.2A
11.3A11.3A6.A.A2.3A5.A5.2A.A8.3A470.3A40.A16.3A$375.2A11.3A11.3A6.A.A
2.3A9.A.2A469.3A37.A.A7.A8.A2.A21.A58.A$389.2A11.3A11.3A10.3A469.2A
47.3A10.A20.3A57.2A$403.2A11.3A10.3A481.3A33.2A.A10.A19.2A.A56.A.A$
417.2A10.3A440.A39.A2.A33.3A8.A.A20.3A$429.2A440.3A41.A34.2A26.A4.3A$
871.A.2A36.A3.A61.3A4.2A6.A$872.3A40.A16.3A41.2A.A11.3A$872.3A37.A.A
7.A8.A2.A21.A19.3A12.A.2A$414.3A455.2A47.3A10.A20.3A19.2A13.3A$400.3A
5.A4.A2.A467.3A33.2A.A10.A19.2A.A34.2A47.A$386.3A5.A4.A2.A4.3A6.A5.3A
418.A39.A2.A33.3A8.A.A20.3A84.2A$372.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.A2.
A416.3A41.A34.2A26.A4.3A83.A.A$358.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A
.A6.A419.A.2A36.A3.A61.3A4.2A6.A$344.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A
2.A.A6.3A11.A3.A4.3A409.3A40.A16.3A41.2A.A11.3A$330.3A5.A4.A2.A4.3A6.
A4.A.2A5.A5.3A2.A.A6.3A11.3A11.A3.A3.A2.A409.3A37.A.A7.A8.A2.A21.A19.
3A12.A.2A$316.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.2A12.A
10.A409.2A47.3A10.A20.3A19.2A13.3A$310.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A
.A6.3A11.3A11.2A27.A.A7.A457.2A.A10.A19.2A.A34.2A$309.3A6.A4.A.2A5.A
5.3A2.A.A6.3A11.3A11.2A48.A.A458.3A8.A.A20.3A$309.A.2A5.A5.3A2.A.A6.
3A11.3A11.2A524.2A26.A4.3A110.A$310.3A2.A.A6.3A11.3A11.2A565.3A4.2A6.
A103.2A$310.3A11.3A11.2A88.A445.3A41.2A.A11.3A101.A.A$303.A6.3A11.2A
101.3A443.A2.A21.A19.3A12.A.2A79.3A$302.3A5.2A114.2A.A446.A20.3A19.2A
13.3A38.A39.A2.A$302.A.2A120.3A447.A19.2A.A34.2A38.3A41.A$303.3A121.
2A444.A.A20.3A75.A.2A36.A3.A$303.2A586.A4.3A76.3A40.A$890.3A4.2A6.A
69.3A37.A.A7.A$889.2A.A11.3A68.2A47.3A$314.3A552.A19.3A12.A.2A79.3A
33.2A.A$314.A2.A4.A5.3A537.3A19.2A13.3A38.A39.A2.A33.3A$305.A8.A6.3A
4.A2.A4.A5.3A522.2A.A34.2A38.3A41.A34.2A$304.3A7.A5.2A.A4.A6.3A4.A2.A
4.A5.3A508.3A75.A.2A36.A3.A$304.A.2A7.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.
A5.3A494.3A76.3A40.A16.3A$305.3A12.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A
4.A5.3A481.2A6.A69.3A37.A.A7.A8.A2.A$305.2A13.3A11.3A6.A.A2.3A5.A5.2A
.A4.A6.3A4.A2.A4.A5.3A474.3A68.2A47.3A10.A$321.2A11.3A11.3A6.A.A2.3A
5.A5.2A.A4.A6.3A4.A2.A4.A5.3A460.A.2A79.3A33.2A.A10.A24.A$335.2A11.3A
11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A447.3A38.A39.A2.A33.3A8.A.
A25.2A$349.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A441.2A38.3A
41.A34.2A26.A8.A.A3.A$363.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A9.A
470.A.2A36.A3.A61.3A12.A2.A$377.2A11.3A11.3A6.A.A2.3A5.A5.2A.A8.3A
470.3A40.A16.3A41.2A.A11.A3.A$391.2A11.3A11.3A6.A.A2.3A9.A.2A469.3A
37.A.A7.A8.A2.A21.A19.3A12.2A$405.2A11.3A11.3A10.3A469.2A47.3A10.A20.
3A19.2A11.A$419.2A11.3A10.3A481.3A33.2A.A10.A19.2A.A33.2A$433.2A10.3A
440.A39.A2.A33.3A8.A.A20.3A28.A5.A$445.2A440.3A41.A34.2A26.A4.3A27.A$
887.A.2A36.A3.A61.3A4.2A6.A21.A$888.3A40.A16.3A41.2A.A11.3A$888.3A37.
A.A7.A8.A2.A21.A19.3A12.A.2A$430.3A455.2A47.3A10.A20.3A19.2A13.3A$
416.3A5.A4.A2.A467.3A33.2A.A10.A19.2A.A34.2A$402.3A5.A4.A2.A4.3A6.A5.
3A458.A2.A33.3A8.A.A20.3A$388.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.A2.A460.A
34.2A26.A4.3A$374.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.A459.A3.A61.
3A4.2A6.A$360.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.A3.A4.3A452.
A16.3A41.2A.A11.3A$346.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A
11.A3.A3.A2.A449.A.A7.A8.A2.A21.A19.3A12.A.2A79.3A$332.3A5.A4.A2.A4.
3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.2A12.A10.A458.3A10.A20.3A19.2A13.
3A38.A39.A2.A$326.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.2A27.A.
A7.A457.2A.A10.A19.2A.A34.2A38.3A41.A$325.3A6.A4.A.2A5.A5.3A2.A.A6.3A
11.3A11.2A48.A.A458.3A8.A.A20.3A75.A.2A36.A3.A97.A$325.A.2A5.A5.3A2.A
.A6.3A11.3A11.2A524.2A26.A4.3A76.3A40.A97.2A$326.3A2.A.A6.3A11.3A11.
2A565.3A4.2A6.A69.3A37.A.A7.A89.A.A$326.3A11.3A11.2A88.A489.2A.A11.3A
68.2A47.3A$319.A6.3A11.2A101.3A468.A19.3A12.A.2A79.3A33.2A.A$318.3A5.
2A114.2A.A467.3A19.2A13.3A38.A39.A2.A33.3A$318.A.2A120.3A467.2A.A34.
2A38.3A41.A34.2A$319.3A121.2A467.3A75.A.2A36.A3.A$319.2A586.A4.3A76.
3A40.A16.3A$906.3A4.2A6.A69.3A37.A.A7.A8.A2.A104.A$905.2A.A11.3A68.2A
47.3A10.A104.2A$330.3A572.3A12.A.2A79.3A33.2A.A10.A103.A.A$330.A2.A4.
A5.3A559.2A13.3A38.A39.A2.A33.3A8.A.A$321.A8.A6.3A4.A2.A4.A5.3A560.2A
38.3A41.A34.2A26.A$320.3A7.A5.2A.A4.A6.3A4.A2.A4.A5.3A586.A.2A36.A3.A
61.3A$320.A.2A7.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A573.3A40.A16.3A
41.2A.A$321.3A12.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A559.3A37.A.A
7.A8.A2.A21.A19.3A$321.2A13.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A
5.3A545.2A47.3A10.A20.3A19.2A$337.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.
3A4.A2.A4.A5.3A543.3A33.2A.A10.A19.2A.A107.A$351.2A11.3A11.3A6.A.A2.
3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A488.A39.A2.A33.3A8.A.A20.3A108.2A$365.
2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A481.3A41.A34.2A26.A4.3A
107.A.A$379.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A9.A470.A.2A36.A3.A
61.3A4.2A6.A$393.2A11.3A11.3A6.A.A2.3A5.A5.2A.A8.3A470.3A40.A16.3A41.
2A.A11.3A$407.2A11.3A11.3A6.A.A2.3A9.A.2A469.3A37.A.A7.A8.A2.A21.A19.
3A12.A.2A$421.2A11.3A11.3A10.3A469.2A47.3A10.A20.3A19.2A13.3A$435.2A
11.3A10.3A481.3A33.2A.A10.A19.2A.A34.2A$449.2A10.3A440.A39.A2.A33.3A
8.A.A20.3A$461.2A440.3A41.A34.2A26.A4.3A134.A$903.A.2A36.A3.A61.3A4.
2A6.A127.2A$904.3A40.A16.3A41.2A.A11.3A125.A.A$904.3A37.A.A7.A8.A2.A
21.A19.3A12.A.2A$446.3A455.2A47.3A10.A20.3A19.2A13.3A38.A$432.3A5.A4.
A2.A503.2A.A10.A19.2A.A34.2A38.3A$418.3A5.A4.A2.A4.3A6.A5.3A495.3A8.A
.A20.3A75.A.2A$404.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.A2.A495.2A26.A4.3A76.
3A$390.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.A525.3A4.2A6.A69.3A$376.
3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.A3.A4.3A469.3A41.2A.A11.3A
68.2A82.A$362.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.A3.A3.A
2.A468.A2.A21.A19.3A12.A.2A79.3A69.2A$348.3A5.A4.A2.A4.3A6.A4.A.2A5.A
5.3A2.A.A6.3A11.3A11.2A12.A10.A471.A20.3A19.2A13.3A38.A39.A2.A68.A.A$
342.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.2A27.A.A7.A471.A19.2A
.A34.2A38.3A41.A$341.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.2A48.A.A469.A
.A20.3A75.A.2A36.A3.A$341.A.2A5.A5.3A2.A.A6.3A11.3A11.2A552.A4.3A76.
3A40.A16.3A$342.3A2.A.A6.3A11.3A11.2A565.3A4.2A6.A69.3A37.A.A7.A8.A2.
A$342.3A11.3A11.2A88.A489.2A.A11.3A68.2A47.3A10.A$335.A6.3A11.2A101.
3A468.A19.3A12.A.2A79.3A33.2A.A10.A$334.3A5.2A114.2A.A467.3A19.2A13.
3A38.A39.A2.A33.3A8.A.A48.A$334.A.2A120.3A467.2A.A34.2A38.3A41.A34.2A
59.2A$335.3A121.2A467.3A75.A.2A36.A3.A94.A.A$335.2A591.3A76.3A40.A16.
3A$929.2A6.A69.3A37.A.A7.A8.A2.A21.A$936.3A68.2A47.3A10.A20.3A$346.3A
587.A.2A79.3A33.2A.A10.A19.2A.A$346.A2.A4.A5.3A574.3A38.A39.A2.A33.3A
8.A.A20.3A$337.A8.A6.3A4.A2.A4.A5.3A560.2A38.3A41.A34.2A26.A4.3A$336.
3A7.A5.2A.A4.A6.3A4.A2.A4.A5.3A586.A.2A36.A3.A61.3A4.2A6.A44.A$336.A.
2A7.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A573.3A40.A16.3A41.2A.A11.3A
43.2A$337.3A12.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A559.3A37.A.A7.
A8.A2.A21.A19.3A12.A.2A41.A.A$337.2A13.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.
3A4.A2.A4.A5.3A545.2A47.3A10.A20.3A19.2A13.3A$353.2A11.3A11.3A6.A.A2.
3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A543.3A33.2A.A10.A19.2A.A34.2A$367.2A
11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A488.A39.A2.A33.3A8.A.
A20.3A$381.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A481.3A41.A
34.2A26.A4.3A$395.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A9.A470.A.2A36.
A3.A61.3A4.2A6.A$409.2A11.3A11.3A6.A.A2.3A5.A5.2A.A8.3A470.3A40.A16.
3A41.2A.A11.3A$423.2A11.3A11.3A6.A.A2.3A9.A.2A469.3A37.A.A7.A8.A2.A
21.A19.3A12.A.2A68.A$437.2A11.3A11.3A10.3A469.2A47.3A10.A20.3A19.2A
13.3A68.2A$451.2A11.3A10.3A481.3A33.2A.A10.A19.2A.A34.2A68.A.A$465.2A
10.3A480.A2.A33.3A8.A.A20.3A$477.2A484.A34.2A26.A4.3A$959.A3.A61.3A4.
2A6.A$963.A16.3A41.2A.A11.3A$960.A.A7.A8.A2.A21.A19.3A12.A.2A79.3A$
462.3A504.3A10.A20.3A19.2A13.3A38.A39.A2.A$448.3A5.A4.A2.A503.2A.A10.
A19.2A.A34.2A38.3A41.A$434.3A5.A4.A2.A4.3A6.A5.3A495.3A8.A.A20.3A75.A
.2A36.A3.A$420.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.A2.A495.2A26.A4.3A76.3A
40.A$406.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.A525.3A4.2A6.A69.3A37.
A.A7.A$392.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.A3.A4.3A513.2A.
A11.3A68.2A47.3A$378.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.
A3.A3.A2.A493.A19.3A12.A.2A79.3A33.2A.A$364.3A5.A4.A2.A4.3A6.A4.A.2A
5.A5.3A2.A.A6.3A11.3A11.2A12.A10.A492.3A19.2A13.3A38.A39.A2.A33.3A4.
2A5.2A$358.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.2A27.A.A7.A
491.2A.A34.2A38.3A41.A34.2A4.2A4.A2.A$357.3A6.A4.A.2A5.A5.3A2.A.A6.3A
11.3A11.2A48.A.A492.3A75.A.2A36.A3.A46.A$357.A.2A5.A5.3A2.A.A6.3A11.
3A11.2A552.A4.3A76.3A40.A16.3A30.A$358.3A2.A.A6.3A11.3A11.2A565.3A4.
2A6.A69.3A37.A.A7.A8.A2.A21.A5.A$358.3A11.3A11.2A88.A489.2A.A11.3A68.
2A47.3A10.A20.3A4.A$351.A6.3A11.2A101.3A488.3A12.A.2A79.3A33.2A.A10.A
19.2A.A131.A$350.3A5.2A114.2A.A489.2A13.3A38.A39.A2.A33.3A8.A.A20.3A
132.2A$350.A.2A120.3A505.2A38.3A41.A34.2A26.A4.3A131.A.A$351.3A121.2A
545.A.2A36.A3.A61.3A4.2A6.A$351.2A670.3A40.A16.3A41.2A.A11.3A$1023.3A
37.A.A7.A8.A2.A21.A19.3A12.A.2A$1023.2A47.3A10.A20.3A19.2A13.3A$362.
3A670.3A33.2A.A10.A19.2A.A34.2A$362.A2.A4.A5.3A615.A39.A2.A33.3A8.A.A
20.3A$353.A8.A6.3A4.A2.A4.A5.3A600.3A41.A34.2A26.A4.3A158.A$352.3A7.A
5.2A.A4.A6.3A4.A2.A4.A5.3A586.A.2A36.A3.A61.3A4.2A6.A151.2A$352.A.2A
7.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A573.3A40.A16.3A41.2A.A11.3A149.
A.A$353.3A12.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A559.3A37.A.A7.A
8.A2.A21.A19.3A12.A.2A$353.2A13.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.
A4.A5.3A545.2A47.3A10.A20.3A19.2A13.3A$369.2A11.3A11.3A6.A.A2.3A5.A5.
2A.A4.A6.3A4.A2.A4.A5.3A543.3A33.2A.A10.A19.2A.A34.2A$383.2A11.3A11.
3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A488.A39.A2.A33.3A8.A.A20.3A$
397.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A481.3A41.A34.2A26.A
4.3A$411.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A9.A470.A.2A36.A3.A61.3A
4.2A6.A$425.2A11.3A11.3A6.A.A2.3A5.A5.2A.A8.3A470.3A40.A16.3A41.2A.A
11.3A176.A$439.2A11.3A11.3A6.A.A2.3A9.A.2A469.3A37.A.A7.A8.A2.A21.A
19.3A12.A.2A79.3A93.2A$453.2A11.3A11.3A10.3A469.2A47.3A10.A20.3A19.2A
13.3A38.A39.A2.A92.A.A$467.2A11.3A10.3A517.2A.A10.A19.2A.A34.2A38.3A
41.A$481.2A10.3A517.3A8.A.A20.3A75.A.2A36.A3.A$493.2A519.2A26.A4.3A
76.3A40.A$1041.3A4.2A6.A69.3A37.A.A7.A$996.3A41.2A.A11.3A68.2A47.3A$
995.A2.A21.A19.3A12.A.2A79.3A33.2A.A$478.3A517.A20.3A19.2A13.3A38.A
39.A2.A33.3A83.A$464.3A5.A4.A2.A517.A19.2A.A34.2A38.3A41.A34.2A83.2A$
450.3A5.A4.A2.A4.3A6.A5.3A506.A.A20.3A75.A.2A36.A3.A118.A.A$436.3A5.A
4.A2.A4.3A6.A4.A.2A5.A5.A2.A523.A4.3A76.3A40.A16.3A$422.3A5.A4.A2.A4.
3A6.A4.A.2A5.A5.3A2.A.A6.A525.3A4.2A6.A69.3A37.A.A7.A8.A2.A$408.3A5.A
4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.A3.A4.3A513.2A.A11.3A68.2A47.3A
10.A$394.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.A3.A3.A2.A
493.A19.3A12.A.2A79.3A33.2A.A10.A$380.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A
2.A.A6.3A11.3A11.2A12.A10.A492.3A19.2A13.3A38.A39.A2.A33.3A8.A.A$374.
A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.2A27.A.A7.A491.2A.A34.2A
38.3A41.A34.2A26.A$373.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.2A48.A.A
492.3A75.A.2A36.A3.A61.3A81.A$373.A.2A5.A5.3A2.A.A6.3A11.3A11.2A557.
3A76.3A40.A16.3A41.2A.A81.2A$374.3A2.A.A6.3A11.3A11.2A572.2A6.A69.3A
37.A.A7.A8.A2.A21.A19.3A81.A.A$374.3A11.3A11.2A88.A504.3A68.2A47.3A
10.A20.3A19.2A$367.A6.3A11.2A101.3A503.A.2A79.3A33.2A.A10.A19.2A.A$
366.3A5.2A114.2A.A504.3A38.A39.A2.A33.3A8.A.A20.3A$366.A.2A120.3A505.
2A38.3A41.A34.2A26.A4.3A$367.3A121.2A545.A.2A36.A3.A61.3A4.2A6.A$367.
2A670.3A40.A16.3A41.2A.A11.3A$1039.3A37.A.A7.A8.A2.A21.A19.3A12.A.2A
92.A$1039.2A47.3A10.A20.3A19.2A13.3A92.2A$378.3A670.3A33.2A.A10.A19.
2A.A34.2A92.A.A$378.A2.A4.A5.3A615.A39.A2.A33.3A8.A.A20.3A$369.A8.A6.
3A4.A2.A4.A5.3A600.3A41.A34.2A26.A4.3A$368.3A7.A5.2A.A4.A6.3A4.A2.A4.
A5.3A586.A.2A36.A3.A61.3A4.2A6.A$368.A.2A7.A.A2.3A5.A5.2A.A4.A6.3A4.A
2.A4.A5.3A573.3A40.A16.3A41.2A.A11.3A$369.3A12.3A6.A.A2.3A5.A5.2A.A4.
A6.3A4.A2.A4.A5.3A559.3A37.A.A7.A8.A2.A21.A19.3A12.A.2A$369.2A13.3A
11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A545.2A47.3A10.A20.3A19.2A
13.3A38.A$385.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A543.
3A33.2A.A10.A19.2A.A34.2A38.3A78.A$399.2A11.3A11.3A6.A.A2.3A5.A5.2A.A
4.A6.3A4.A2.A4.A5.3A528.A2.A33.3A8.A.A20.3A75.A.2A77.2A$413.2A11.3A
11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A525.A34.2A26.A4.3A76.3A76.A.A$
427.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A9.A510.A3.A61.3A4.2A6.A69.3A
$441.2A11.3A11.3A6.A.A2.3A5.A5.2A.A8.3A513.A16.3A41.2A.A11.3A68.2A$
455.2A11.3A11.3A6.A.A2.3A9.A.2A509.A.A7.A8.A2.A21.A19.3A12.A.2A79.3A$
469.2A11.3A11.3A10.3A518.3A10.A20.3A19.2A13.3A38.A39.A2.A$483.2A11.3A
10.3A517.2A.A10.A19.2A.A34.2A38.3A41.A$497.2A10.3A517.3A8.A.A20.3A75.
A.2A36.A3.A$509.2A519.2A26.A4.3A76.3A40.A16.3A43.A$1057.3A4.2A6.A69.
3A37.A.A7.A8.A2.A43.2A$1056.2A.A11.3A68.2A47.3A10.A42.A.A$1036.A19.3A
12.A.2A79.3A33.2A.A10.A$494.3A538.3A19.2A13.3A38.A39.A2.A33.3A8.A.A$
480.3A5.A4.A2.A537.2A.A34.2A38.3A41.A34.2A$466.3A5.A4.A2.A4.3A6.A5.3A
529.3A75.A.2A36.A3.A$452.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.A2.A523.A4.3A
76.3A40.A16.3A$438.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.A525.3A4.2A
6.A69.3A37.A.A7.A8.A2.A21.A$424.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A
6.3A11.A3.A4.3A513.2A.A11.3A68.2A47.3A10.A20.3A46.A$410.3A5.A4.A2.A4.
3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.A3.A3.A2.A513.3A12.A.2A79.3A33.2A.
A10.A19.2A.A46.2A$396.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A
11.2A12.A10.A514.2A13.3A38.A39.A2.A33.3A8.A.A20.3A46.A.A$390.A4.A2.A
4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.2A27.A.A7.A529.2A38.3A41.A34.2A
26.A4.3A$389.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.2A48.A.A570.A.2A36.A
3.A61.3A4.2A6.A$389.A.2A5.A5.3A2.A.A6.3A11.3A11.2A636.3A40.A16.3A41.
2A.A11.3A$390.3A2.A.A6.3A11.3A11.2A650.3A37.A.A7.A8.A2.A21.A19.3A12.A
.2A$390.3A11.3A11.2A88.A575.2A47.3A10.A20.3A19.2A13.3A$383.A6.3A11.2A
101.3A586.3A33.2A.A10.A19.2A.A34.2A$382.3A5.2A114.2A.A545.A39.A2.A33.
3A8.A.A20.3A73.A$382.A.2A120.3A545.3A41.A34.2A26.A4.3A73.2A$383.3A
121.2A545.A.2A36.A3.A61.3A4.2A6.A65.A.A$383.2A670.3A40.A16.3A41.2A.A
11.3A200.A$1055.3A37.A.A7.A8.A2.A21.A19.3A12.A.2A199.2A$1055.2A47.3A
10.A20.3A19.2A13.3A198.A.A$394.3A670.3A33.2A.A10.A19.2A.A34.2A$394.A
2.A4.A5.3A615.A39.A2.A33.3A8.A.A20.3A$385.A8.A6.3A4.A2.A4.A5.3A600.3A
41.A34.2A26.A4.3A$384.3A7.A5.2A.A4.A6.3A4.A2.A4.A5.3A586.A.2A36.A3.A
61.3A4.2A6.A$384.A.2A7.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A573.3A40.A
16.3A41.2A.A11.3A$385.3A12.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A
559.3A37.A.A7.A8.A2.A21.A19.3A12.A.2A79.3A$385.2A13.3A11.3A6.A.A2.3A
5.A5.2A.A4.A6.3A4.A2.A4.A5.3A545.2A47.3A10.A20.3A19.2A13.3A38.A39.A2.
A11.2A130.A$401.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A
579.2A.A10.A19.2A.A34.2A38.3A41.A10.A.A130.2A$415.2A11.3A11.3A6.A.A2.
3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A565.3A8.A.A20.3A75.A.2A36.A3.A12.A129.
A.A$429.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A560.2A26.A4.3A
76.3A40.A16.3A$443.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A9.A576.3A4.2A
6.A69.3A37.A.A7.A8.A2.A$457.2A11.3A11.3A6.A.A2.3A5.A5.2A.A8.3A530.3A
41.2A.A11.3A68.2A47.3A10.A$471.2A11.3A11.3A6.A.A2.3A9.A.2A528.A2.A21.
A19.3A12.A.2A79.3A33.2A.A10.A$485.2A11.3A11.3A10.3A531.A20.3A19.2A13.
3A38.A39.A2.A33.3A8.A.A$499.2A11.3A10.3A531.A19.2A.A34.2A38.3A41.A34.
2A$513.2A10.3A528.A.A20.3A75.A.2A36.A3.A169.A$525.2A547.A4.3A76.3A40.
A16.3A150.2A$1073.3A4.2A6.A69.3A37.A.A7.A8.A2.A21.A127.A.A$1072.2A.A
11.3A68.2A47.3A10.A20.3A$1052.A19.3A12.A.2A79.3A33.2A.A10.A19.2A.A$
510.3A538.3A19.2A13.3A38.A39.A2.A33.3A8.A.A20.3A$496.3A5.A4.A2.A537.
2A.A34.2A38.3A41.A34.2A26.A4.3A$482.3A5.A4.A2.A4.3A6.A5.3A529.3A75.A.
2A36.A3.A61.3A4.2A6.A$468.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.A2.A528.3A76.
3A40.A16.3A41.2A.A11.3A$454.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.A
532.2A6.A69.3A37.A.A7.A8.A2.A21.A19.3A12.A.2A116.A$440.3A5.A4.A2.A4.
3A6.A4.A.2A5.A5.3A2.A.A6.3A11.A3.A4.3A528.3A68.2A47.3A10.A20.3A19.2A
13.3A116.2A$426.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.A3.A
3.A2.A528.A.2A79.3A33.2A.A10.A19.2A.A34.2A116.A.A$412.3A5.A4.A2.A4.3A
6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.2A12.A10.A529.3A38.A39.A2.A33.3A8.A.
A20.3A$406.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.2A27.A.A7.A
529.2A38.3A41.A34.2A26.A4.3A$405.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.
2A48.A.A570.A.2A36.A3.A61.3A4.2A6.A$405.A.2A5.A5.3A2.A.A6.3A11.3A11.
2A636.3A40.A16.3A41.2A.A11.3A$406.3A2.A.A6.3A11.3A11.2A650.3A37.A.A7.
A8.A2.A21.A19.3A12.A.2A$406.3A11.3A11.2A88.A575.2A47.3A10.A20.3A19.2A
13.3A$399.A6.3A11.2A101.3A586.3A33.2A.A10.A19.2A.A34.2A143.A$398.3A5.
2A114.2A.A545.A39.A2.A33.3A8.A.A20.3A180.2A$398.A.2A120.3A545.3A41.A
34.2A26.A4.3A179.A.A$399.3A121.2A545.A.2A36.A3.A61.3A4.2A6.A$399.2A
670.3A40.A16.3A41.2A.A11.3A$1071.3A37.A.A7.A8.A2.A21.A19.3A12.A.2A79.
3A$1071.2A47.3A10.A20.3A19.2A13.3A38.A39.A2.A$410.3A670.3A33.2A.A10.A
19.2A.A34.2A38.3A41.A$410.A2.A4.A5.3A655.A2.A33.3A8.A.A20.3A75.A.2A
36.A3.A$401.A8.A6.3A4.A2.A4.A5.3A644.A34.2A26.A4.3A76.3A40.A86.A$400.
3A7.A5.2A.A4.A6.3A4.A2.A4.A5.3A626.A3.A61.3A4.2A6.A69.3A37.A.A7.A79.
2A$400.A.2A7.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A616.A16.3A41.2A.A11.
3A68.2A47.3A77.A.A$401.3A12.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A
599.A.A7.A8.A2.A21.A19.3A12.A.2A79.3A33.2A.A$401.2A13.3A11.3A6.A.A2.
3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A594.3A10.A20.3A19.2A13.3A38.A39.A2.A
33.3A$417.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A579.2A.A
10.A19.2A.A34.2A38.3A41.A34.2A$431.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A
6.3A4.A2.A4.A5.3A565.3A8.A.A20.3A75.A.2A36.A3.A$445.2A11.3A11.3A6.A.A
2.3A5.A5.2A.A4.A6.3A4.A2.A4.A560.2A26.A4.3A76.3A40.A16.3A$459.2A11.3A
11.3A6.A.A2.3A5.A5.2A.A4.A6.3A9.A576.3A4.2A6.A69.3A37.A.A7.A8.A2.A$
473.2A11.3A11.3A6.A.A2.3A5.A5.2A.A8.3A574.2A.A11.3A68.2A47.3A10.A93.A
$487.2A11.3A11.3A6.A.A2.3A9.A.2A553.A19.3A12.A.2A79.3A33.2A.A10.A93.
2A$501.2A11.3A11.3A10.3A552.3A19.2A13.3A38.A39.A2.A33.3A8.A.A93.A.A$
515.2A11.3A10.3A551.2A.A34.2A38.3A41.A34.2A26.A$529.2A10.3A551.3A75.A
.2A36.A3.A61.3A$541.2A547.A4.3A76.3A40.A16.3A41.2A.A$1089.3A4.2A6.A
69.3A37.A.A7.A8.A2.A21.A19.3A$1088.2A.A11.3A68.2A47.3A10.A20.3A19.2A$
1088.3A12.A.2A79.3A33.2A.A10.A19.2A.A$526.3A560.2A13.3A38.A39.A2.A33.
3A8.A.A20.3A97.A$512.3A5.A4.A2.A575.2A38.3A41.A34.2A26.A4.3A97.2A$
498.3A5.A4.A2.A4.3A6.A5.3A607.A.2A36.A3.A61.3A4.2A6.A89.A.A$484.3A5.A
4.A2.A4.3A6.A4.A.2A5.A5.A2.A607.3A40.A16.3A41.2A.A11.3A$470.3A5.A4.A
2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.A610.3A37.A.A7.A8.A2.A21.A19.3A12.A.2A$
456.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.A3.A4.3A599.2A47.3A10.
A20.3A19.2A13.3A$442.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.
A3.A3.A2.A611.3A33.2A.A10.A19.2A.A34.2A$428.3A5.A4.A2.A4.3A6.A4.A.2A
5.A5.3A2.A.A6.3A11.3A11.2A12.A10.A570.A39.A2.A33.3A8.A.A20.3A$422.A4.
A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.2A27.A.A7.A569.3A41.A34.2A
26.A4.3A$421.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.2A48.A.A570.A.2A36.A
3.A61.3A4.2A6.A116.A$421.A.2A5.A5.3A2.A.A6.3A11.3A11.2A636.3A40.A16.
3A41.2A.A11.3A115.2A$422.3A2.A.A6.3A11.3A11.2A650.3A37.A.A7.A8.A2.A
21.A19.3A12.A.2A113.A.A$422.3A11.3A11.2A88.A575.2A47.3A10.A20.3A19.2A
13.3A38.A$415.A6.3A11.2A101.3A586.3A33.2A.A10.A19.2A.A34.2A38.3A$414.
3A5.2A114.2A.A545.A39.A2.A33.3A8.A.A20.3A75.A.2A$414.A.2A120.3A545.3A
41.A34.2A26.A4.3A76.3A$415.3A121.2A545.A.2A36.A3.A61.3A4.2A6.A69.3A$
415.2A670.3A40.A16.3A41.2A.A11.3A68.2A$1087.3A37.A.A7.A8.A2.A21.A19.
3A12.A.2A79.3A58.A$1087.2A47.3A10.A20.3A19.2A13.3A38.A39.A2.A58.2A$
426.3A706.2A.A10.A19.2A.A34.2A38.3A41.A57.A.A$426.A2.A4.A5.3A692.3A8.
A.A20.3A75.A.2A36.A3.A193.A$417.A8.A6.3A4.A2.A4.A5.3A679.2A26.A4.3A
76.3A40.A16.3A174.2A$416.3A7.A5.2A.A4.A6.3A4.A2.A4.A5.3A692.3A4.2A6.A
69.3A37.A.A7.A8.A2.A173.A.A$416.A.2A7.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.
A5.3A633.3A41.2A.A11.3A68.2A47.3A10.A$417.3A12.3A6.A.A2.3A5.A5.2A.A4.
A6.3A4.A2.A4.A5.3A618.A2.A21.A19.3A12.A.2A79.3A33.2A.A10.A$417.2A13.
3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A607.A20.3A19.2A13.3A38.A
39.A2.A33.3A8.A.A$433.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A
5.3A593.A19.2A.A34.2A38.3A41.A34.2A48.A$447.2A11.3A11.3A6.A.A2.3A5.A
5.2A.A4.A6.3A4.A2.A4.A5.3A576.A.A20.3A75.A.2A36.A3.A84.2A$461.2A11.3A
11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A588.A4.3A76.3A40.A16.3A64.A.A$
475.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A9.A576.3A4.2A6.A69.3A37.A.A
7.A8.A2.A21.A178.A$489.2A11.3A11.3A6.A.A2.3A5.A5.2A.A8.3A574.2A.A11.
3A68.2A47.3A10.A20.3A177.2A$503.2A11.3A11.3A6.A.A2.3A9.A.2A553.A19.3A
12.A.2A79.3A33.2A.A10.A19.2A.A176.A.A$517.2A11.3A11.3A10.3A552.3A19.
2A13.3A38.A39.A2.A33.3A8.A.A20.3A$531.2A11.3A10.3A551.2A.A34.2A38.3A
41.A34.2A26.A4.3A$545.2A10.3A551.3A75.A.2A36.A3.A61.3A4.2A6.A$557.2A
552.3A76.3A40.A16.3A41.2A.A11.3A32.A$1112.2A6.A69.3A37.A.A7.A8.A2.A
21.A19.3A12.A.2A31.2A$1119.3A68.2A47.3A10.A20.3A19.2A13.3A30.A.A$
1119.A.2A79.3A33.2A.A10.A19.2A.A34.2A167.A$542.3A575.3A38.A39.A2.A33.
3A8.A.A20.3A204.2A$528.3A5.A4.A2.A575.2A38.3A41.A34.2A26.A4.3A203.A.A
$514.3A5.A4.A2.A4.3A6.A5.3A607.A.2A36.A3.A61.3A4.2A6.A$500.3A5.A4.A2.
A4.3A6.A4.A.2A5.A5.A2.A607.3A40.A16.3A41.2A.A11.3A$486.3A5.A4.A2.A4.
3A6.A4.A.2A5.A5.3A2.A.A6.A610.3A37.A.A7.A8.A2.A21.A19.3A12.A.2A$472.
3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.A3.A4.3A599.2A47.3A10.A20.
3A19.2A13.3A$458.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.A3.A
3.A2.A611.3A33.2A.A10.A19.2A.A34.2A$444.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.
3A2.A.A6.3A11.3A11.2A12.A10.A570.A39.A2.A33.3A8.A.A20.3A$438.A4.A2.A
4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.2A27.A.A7.A569.3A41.A34.2A26.A4.
3A98.2A130.A$437.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.2A48.A.A570.A.2A
36.A3.A61.3A4.2A6.A90.A.A130.2A$437.A.2A5.A5.3A2.A.A6.3A11.3A11.2A
636.3A40.A16.3A41.2A.A11.3A91.A129.A.A$438.3A2.A.A6.3A11.3A11.2A650.
3A37.A.A7.A8.A2.A21.A19.3A12.A.2A79.3A$438.3A11.3A11.2A88.A575.2A47.
3A10.A20.3A19.2A13.3A38.A39.A2.A$431.A6.3A11.2A101.3A586.3A33.2A.A10.
A19.2A.A34.2A38.3A41.A$430.3A5.2A114.2A.A585.A2.A33.3A8.A.A20.3A75.A.
2A36.A3.A$430.A.2A120.3A589.A34.2A26.A4.3A76.3A40.A16.3A$431.3A121.2A
585.A3.A61.3A4.2A6.A69.3A37.A.A7.A8.A2.A$431.2A713.A16.3A41.2A.A11.3A
68.2A47.3A10.A117.A$1143.A.A7.A8.A2.A21.A19.3A12.A.2A79.3A33.2A.A10.A
117.2A$1152.3A10.A20.3A19.2A13.3A38.A39.A2.A33.3A8.A.A117.A.A$442.3A
706.2A.A10.A19.2A.A34.2A38.3A41.A34.2A$442.A2.A4.A5.3A692.3A8.A.A20.
3A75.A.2A36.A3.A$433.A8.A6.3A4.A2.A4.A5.3A679.2A26.A4.3A76.3A40.A16.
3A$432.3A7.A5.2A.A4.A6.3A4.A2.A4.A5.3A692.3A4.2A6.A69.3A37.A.A7.A8.A
2.A21.A$432.A.2A7.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A677.2A.A11.3A
68.2A47.3A10.A20.3A$433.3A12.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A
643.A19.3A12.A.2A79.3A33.2A.A10.A19.2A.A$433.2A13.3A11.3A6.A.A2.3A5.A
5.2A.A4.A6.3A4.A2.A4.A5.3A628.3A19.2A13.3A38.A39.A2.A33.3A8.A.A20.3A
121.A$449.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A613.2A.A
34.2A38.3A41.A34.2A26.A4.3A121.2A$463.2A11.3A11.3A6.A.A2.3A5.A5.2A.A
4.A6.3A4.A2.A4.A5.3A599.3A75.A.2A36.A3.A61.3A4.2A6.A113.A.A$477.2A11.
3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A588.A4.3A76.3A40.A16.3A41.2A
.A11.3A$491.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A9.A576.3A4.2A6.A69.
3A37.A.A7.A8.A2.A21.A19.3A12.A.2A$505.2A11.3A11.3A6.A.A2.3A5.A5.2A.A
8.3A574.2A.A11.3A68.2A47.3A10.A20.3A19.2A13.3A$519.2A11.3A11.3A6.A.A
2.3A9.A.2A573.3A12.A.2A79.3A33.2A.A10.A19.2A.A34.2A$533.2A11.3A11.3A
10.3A574.2A13.3A38.A39.A2.A33.3A8.A.A20.3A$547.2A11.3A10.3A589.2A38.
3A41.A34.2A26.A4.3A$561.2A10.3A629.A.2A36.A3.A61.3A4.2A6.A140.A$573.
2A631.3A40.A16.3A41.2A.A11.3A139.2A$1206.3A37.A.A7.A8.A2.A21.A19.3A
12.A.2A137.A.A$1206.2A47.3A10.A20.3A19.2A13.3A$1218.3A33.2A.A10.A19.
2A.A34.2A$558.3A616.A39.A2.A33.3A8.A.A20.3A$544.3A5.A4.A2.A615.3A41.A
34.2A26.A4.3A$530.3A5.A4.A2.A4.3A6.A5.3A607.A.2A36.A3.A61.3A4.2A6.A$
516.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.A2.A607.3A40.A16.3A41.2A.A11.3A$502.
3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.A610.3A37.A.A7.A8.A2.A21.A19.3A
12.A.2A79.3A82.A$488.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.A3.A
4.3A599.2A47.3A10.A20.3A19.2A13.3A38.A39.A2.A82.2A$474.3A5.A4.A2.A4.
3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.A3.A3.A2.A611.3A33.2A.A10.A19.2A.A
34.2A38.3A41.A81.A.A$460.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.
3A11.2A12.A10.A570.A39.A2.A33.3A8.A.A20.3A75.A.2A36.A3.A$454.A4.A2.A
4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.2A27.A.A7.A569.3A41.A34.2A26.A4.
3A76.3A40.A$453.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.2A48.A.A570.A.2A
36.A3.A61.3A4.2A6.A69.3A37.A.A7.A$453.A.2A5.A5.3A2.A.A6.3A11.3A11.2A
636.3A40.A16.3A41.2A.A11.3A68.2A47.3A$454.3A2.A.A6.3A11.3A11.2A650.3A
37.A.A7.A8.A2.A21.A19.3A12.A.2A79.3A33.2A.A$454.3A11.3A11.2A88.A575.
2A47.3A10.A20.3A19.2A13.3A38.A39.A2.A33.3A$447.A6.3A11.2A101.3A622.2A
.A10.A19.2A.A34.2A38.3A41.A34.2A72.A$446.3A5.2A114.2A.A622.3A8.A.A20.
3A75.A.2A36.A3.A108.2A$446.A.2A120.3A624.2A26.A4.3A76.3A40.A16.3A88.A
.A$447.3A121.2A651.3A4.2A6.A69.3A37.A.A7.A8.A2.A$447.2A730.3A41.2A.A
11.3A68.2A47.3A10.A$1178.A2.A21.A19.3A12.A.2A79.3A33.2A.A10.A$1181.A
20.3A19.2A13.3A38.A39.A2.A33.3A8.A.A$458.3A720.A19.2A.A34.2A38.3A41.A
34.2A26.A$458.A2.A4.A5.3A703.A.A20.3A75.A.2A36.A3.A61.3A$449.A8.A6.3A
4.A2.A4.A5.3A707.A4.3A76.3A40.A16.3A41.2A.A70.A$448.3A7.A5.2A.A4.A6.
3A4.A2.A4.A5.3A692.3A4.2A6.A69.3A37.A.A7.A8.A2.A21.A19.3A71.2A$448.A.
2A7.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A677.2A.A11.3A68.2A47.3A10.A
20.3A19.2A70.A.A$449.3A12.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A
643.A19.3A12.A.2A79.3A33.2A.A10.A19.2A.A227.A$449.2A13.3A11.3A6.A.A2.
3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A628.3A19.2A13.3A38.A39.A2.A33.3A8.A.A
20.3A228.2A$465.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A
613.2A.A34.2A38.3A41.A34.2A26.A4.3A227.A.A$479.2A11.3A11.3A6.A.A2.3A
5.A5.2A.A4.A6.3A4.A2.A4.A5.3A599.3A75.A.2A36.A3.A61.3A4.2A6.A$493.2A
11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A593.3A76.3A40.A16.3A41.2A
.A11.3A$507.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A9.A583.2A6.A69.3A37.
A.A7.A8.A2.A21.A19.3A12.A.2A$521.2A11.3A11.3A6.A.A2.3A5.A5.2A.A8.3A
589.3A68.2A47.3A10.A20.3A19.2A13.3A81.A$535.2A11.3A11.3A6.A.A2.3A9.A.
2A588.A.2A79.3A33.2A.A10.A19.2A.A34.2A82.2A$549.2A11.3A11.3A10.3A589.
3A38.A39.A2.A33.3A8.A.A20.3A118.A.A$563.2A11.3A10.3A589.2A38.3A41.A
34.2A26.A4.3A254.A$577.2A10.3A629.A.2A36.A3.A61.3A4.2A6.A247.2A$589.
2A631.3A40.A16.3A41.2A.A11.3A245.A.A$1222.3A37.A.A7.A8.A2.A21.A19.3A
12.A.2A$1222.2A47.3A10.A20.3A19.2A13.3A38.A$1234.3A33.2A.A10.A19.2A.A
34.2A38.3A$574.3A616.A39.A2.A33.3A8.A.A20.3A75.A.2A66.A$560.3A5.A4.A
2.A615.3A41.A34.2A26.A4.3A76.3A66.2A$546.3A5.A4.A2.A4.3A6.A5.3A607.A.
2A36.A3.A61.3A4.2A6.A69.3A65.A.A$532.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.A2.
A607.3A40.A16.3A41.2A.A11.3A68.2A202.A$518.3A5.A4.A2.A4.3A6.A4.A.2A5.
A5.3A2.A.A6.A610.3A37.A.A7.A8.A2.A21.A19.3A12.A.2A79.3A189.2A$504.3A
5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.A3.A4.3A599.2A47.3A10.A20.3A
19.2A13.3A38.A39.A2.A188.A.A$490.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A
6.3A11.3A11.A3.A3.A2.A611.3A33.2A.A10.A19.2A.A34.2A38.3A41.A$476.3A5.
A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.2A12.A10.A610.A2.A33.3A8.
A.A20.3A75.A.2A36.A3.A$470.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A
11.2A27.A.A7.A613.A34.2A26.A4.3A76.3A40.A16.3A$469.3A6.A4.A.2A5.A5.3A
2.A.A6.3A11.3A11.2A48.A.A610.A3.A61.3A4.2A6.A69.3A37.A.A7.A8.A2.A32.A
$469.A.2A5.A5.3A2.A.A6.3A11.3A11.2A679.A16.3A41.2A.A11.3A68.2A47.3A
10.A32.2A$470.3A2.A.A6.3A11.3A11.2A690.A.A7.A8.A2.A21.A19.3A12.A.2A
79.3A33.2A.A10.A31.A.A$470.3A11.3A11.2A88.A624.3A10.A20.3A19.2A13.3A
38.A39.A2.A33.3A8.A.A168.A$463.A6.3A11.2A101.3A622.2A.A10.A19.2A.A34.
2A38.3A41.A34.2A179.2A$462.3A5.2A114.2A.A622.3A8.A.A20.3A75.A.2A36.A
3.A214.A.A$462.A.2A120.3A624.2A26.A4.3A76.3A40.A16.3A$463.3A121.2A
651.3A4.2A6.A69.3A37.A.A7.A8.A2.A21.A$463.2A774.2A.A11.3A68.2A47.3A
10.A20.3A$1219.A19.3A12.A.2A79.3A33.2A.A10.A19.2A.A35.A$1218.3A19.2A
13.3A38.A39.A2.A33.3A8.A.A20.3A36.2A$474.3A740.2A.A34.2A38.3A41.A34.
2A26.A4.3A35.A.A$474.A2.A4.A5.3A726.3A75.A.2A36.A3.A61.3A4.2A6.A164.A
$465.A8.A6.3A4.A2.A4.A5.3A707.A4.3A76.3A40.A16.3A41.2A.A11.3A163.2A$
464.3A7.A5.2A.A4.A6.3A4.A2.A4.A5.3A692.3A4.2A6.A69.3A37.A.A7.A8.A2.A
21.A19.3A12.A.2A161.A.A$464.A.2A7.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.
3A677.2A.A11.3A68.2A47.3A10.A20.3A19.2A13.3A$465.3A12.3A6.A.A2.3A5.A
5.2A.A4.A6.3A4.A2.A4.A5.3A663.3A12.A.2A79.3A33.2A.A10.A19.2A.A34.2A$
465.2A13.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A650.2A13.3A38.A
39.A2.A33.3A8.A.A20.3A$481.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.
A4.A5.3A651.2A38.3A41.A34.2A26.A4.3A$495.2A11.3A11.3A6.A.A2.3A5.A5.2A
.A4.A6.3A4.A2.A4.A5.3A677.A.2A36.A3.A61.3A4.2A6.A$509.2A11.3A11.3A6.A
.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A672.3A40.A16.3A41.2A.A11.3A$523.2A11.
3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A9.A661.3A37.A.A7.A8.A2.A21.A19.3A12.A
.2A56.2A130.A$537.2A11.3A11.3A6.A.A2.3A5.A5.2A.A8.3A660.2A47.3A10.A
20.3A19.2A13.3A55.A.A130.2A$551.2A11.3A11.3A6.A.A2.3A9.A.2A671.3A33.
2A.A10.A19.2A.A34.2A58.A129.A.A$565.2A11.3A11.3A10.3A630.A39.A2.A33.
3A8.A.A20.3A$579.2A11.3A10.3A629.3A41.A34.2A26.A4.3A$593.2A10.3A629.A
.2A36.A3.A61.3A4.2A6.A$605.2A631.3A40.A16.3A41.2A.A11.3A$1238.3A37.A.
A7.A8.A2.A21.A19.3A12.A.2A79.3A$1238.2A47.3A10.A20.3A19.2A13.3A38.A
39.A2.A$1250.3A33.2A.A10.A19.2A.A34.2A38.3A41.A132.A$590.3A616.A39.A
2.A33.3A8.A.A20.3A75.A.2A36.A3.A132.2A$576.3A5.A4.A2.A615.3A41.A34.2A
26.A4.3A76.3A40.A16.3A112.A.A$562.3A5.A4.A2.A4.3A6.A5.3A607.A.2A36.A
3.A61.3A4.2A6.A69.3A37.A.A7.A8.A2.A$548.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.
A2.A607.3A40.A16.3A41.2A.A11.3A68.2A47.3A10.A$534.3A5.A4.A2.A4.3A6.A
4.A.2A5.A5.3A2.A.A6.A610.3A37.A.A7.A8.A2.A21.A19.3A12.A.2A79.3A33.2A.
A10.A$520.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.A3.A4.3A599.2A
47.3A10.A20.3A19.2A13.3A38.A39.A2.A33.3A8.A.A$506.3A5.A4.A2.A4.3A6.A
4.A.2A5.A5.3A2.A.A6.3A11.3A11.A3.A3.A2.A647.2A.A10.A19.2A.A34.2A38.3A
41.A34.2A$492.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.2A12.A
10.A647.3A8.A.A20.3A75.A.2A36.A3.A$486.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A
.A6.3A11.3A11.2A27.A.A7.A648.2A26.A4.3A76.3A40.A16.3A139.A$485.3A6.A
4.A.2A5.A5.3A2.A.A6.3A11.3A11.2A48.A.A676.3A4.2A6.A69.3A37.A.A7.A8.A
2.A21.A117.2A$485.A.2A5.A5.3A2.A.A6.3A11.3A11.2A696.3A41.2A.A11.3A68.
2A47.3A10.A20.3A115.A.A$486.3A2.A.A6.3A11.3A11.2A709.A2.A21.A19.3A12.
A.2A79.3A33.2A.A10.A19.2A.A$486.3A11.3A11.2A88.A637.A20.3A19.2A13.3A
38.A39.A2.A33.3A8.A.A20.3A$479.A6.3A11.2A101.3A636.A19.2A.A34.2A38.3A
41.A34.2A26.A4.3A$478.3A5.2A114.2A.A633.A.A20.3A75.A.2A36.A3.A61.3A4.
2A6.A$478.A.2A120.3A652.A4.3A76.3A40.A16.3A41.2A.A11.3A$479.3A121.2A
651.3A4.2A6.A69.3A37.A.A7.A8.A2.A21.A19.3A12.A.2A$479.2A774.2A.A11.3A
68.2A47.3A10.A20.3A19.2A13.3A105.A$1235.A19.3A12.A.2A79.3A33.2A.A10.A
19.2A.A34.2A106.2A$1234.3A19.2A13.3A38.A39.A2.A33.3A8.A.A20.3A142.A.A
$490.3A740.2A.A34.2A38.3A41.A34.2A26.A4.3A$490.A2.A4.A5.3A726.3A75.A.
2A36.A3.A61.3A4.2A6.A$481.A8.A6.3A4.A2.A4.A5.3A712.3A76.3A40.A16.3A
41.2A.A11.3A$480.3A7.A5.2A.A4.A6.3A4.A2.A4.A5.3A699.2A6.A69.3A37.A.A
7.A8.A2.A21.A19.3A12.A.2A$480.A.2A7.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A
5.3A692.3A68.2A47.3A10.A20.3A19.2A13.3A$481.3A12.3A6.A.A2.3A5.A5.2A.A
4.A6.3A4.A2.A4.A5.3A678.A.2A79.3A33.2A.A10.A19.2A.A34.2A$481.2A13.3A
11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A665.3A38.A39.A2.A33.3A8.A.
A20.3A169.A$497.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A
651.2A38.3A41.A34.2A26.A4.3A169.2A$511.2A11.3A11.3A6.A.A2.3A5.A5.2A.A
4.A6.3A4.A2.A4.A5.3A677.A.2A36.A3.A61.3A4.2A6.A161.A.A$525.2A11.3A11.
3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A672.3A40.A16.3A41.2A.A11.3A296.A$
539.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A9.A661.3A37.A.A7.A8.A2.A21.A
19.3A12.A.2A79.3A213.2A$553.2A11.3A11.3A6.A.A2.3A5.A5.2A.A8.3A660.2A
47.3A10.A20.3A19.2A13.3A38.A39.A2.A212.A.A$567.2A11.3A11.3A6.A.A2.3A
9.A.2A671.3A33.2A.A10.A19.2A.A34.2A38.3A41.A$581.2A11.3A11.3A10.3A
630.A39.A2.A33.3A8.A.A20.3A75.A.2A36.A3.A$595.2A11.3A10.3A629.3A41.A
34.2A26.A4.3A76.3A40.A$609.2A10.3A629.A.2A36.A3.A61.3A4.2A6.A69.3A37.
A.A7.A68.A$621.2A631.3A40.A16.3A41.2A.A11.3A68.2A47.3A67.2A$1254.3A
37.A.A7.A8.A2.A21.A19.3A12.A.2A79.3A33.2A.A66.A.A$1254.2A47.3A10.A20.
3A19.2A13.3A38.A39.A2.A33.3A203.A$1266.3A33.2A.A10.A19.2A.A34.2A38.3A
41.A34.2A203.2A$606.3A656.A2.A33.3A8.A.A20.3A75.A.2A36.A3.A238.A.A$
592.3A5.A4.A2.A659.A34.2A26.A4.3A76.3A40.A16.3A$578.3A5.A4.A2.A4.3A6.
A5.3A647.A3.A61.3A4.2A6.A69.3A37.A.A7.A8.A2.A$564.3A5.A4.A2.A4.3A6.A
4.A.2A5.A5.A2.A650.A16.3A41.2A.A11.3A68.2A47.3A10.A$550.3A5.A4.A2.A4.
3A6.A4.A.2A5.A5.3A2.A.A6.A650.A.A7.A8.A2.A21.A19.3A12.A.2A79.3A33.2A.
A10.A82.A$536.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.A3.A4.3A648.
3A10.A20.3A19.2A13.3A38.A39.A2.A33.3A8.A.A83.2A$522.3A5.A4.A2.A4.3A6.
A4.A.2A5.A5.3A2.A.A6.3A11.3A11.A3.A3.A2.A647.2A.A10.A19.2A.A34.2A38.
3A41.A34.2A26.A66.A.A$508.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.
3A11.2A12.A10.A647.3A8.A.A20.3A75.A.2A36.A3.A61.3A201.A$502.A4.A2.A4.
3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.2A27.A.A7.A648.2A26.A4.3A76.3A40.A
16.3A41.2A.A201.2A$501.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.2A48.A.A
676.3A4.2A6.A69.3A37.A.A7.A8.A2.A21.A19.3A201.A.A$501.A.2A5.A5.3A2.A.
A6.3A11.3A11.2A740.2A.A11.3A68.2A47.3A10.A20.3A19.2A$502.3A2.A.A6.3A
11.3A11.2A734.A19.3A12.A.2A79.3A33.2A.A10.A19.2A.A$502.3A11.3A11.2A
88.A658.3A19.2A13.3A38.A39.A2.A33.3A8.A.A20.3A$495.A6.3A11.2A101.3A
656.2A.A34.2A38.3A41.A34.2A26.A4.3A86.A$494.3A5.2A114.2A.A656.3A75.A.
2A36.A3.A61.3A4.2A6.A79.2A$494.A.2A120.3A652.A4.3A76.3A40.A16.3A41.2A
.A11.3A77.A.A$495.3A121.2A651.3A4.2A6.A69.3A37.A.A7.A8.A2.A21.A19.3A
12.A.2A212.A$495.2A774.2A.A11.3A68.2A47.3A10.A20.3A19.2A13.3A212.2A$
1271.3A12.A.2A79.3A33.2A.A10.A19.2A.A34.2A212.A.A$1272.2A13.3A38.A39.
A2.A33.3A8.A.A20.3A$506.3A778.2A38.3A41.A34.2A26.A4.3A$506.A2.A4.A5.
3A804.A.2A36.A3.A61.3A4.2A6.A$497.A8.A6.3A4.A2.A4.A5.3A791.3A40.A16.
3A41.2A.A11.3A104.A$496.3A7.A5.2A.A4.A6.3A4.A2.A4.A5.3A777.3A37.A.A7.
A8.A2.A21.A19.3A12.A.2A103.2A$496.A.2A7.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A
4.A5.3A763.2A47.3A10.A20.3A19.2A13.3A38.A63.A.A$497.3A12.3A6.A.A2.3A
5.A5.2A.A4.A6.3A4.A2.A4.A5.3A761.3A33.2A.A10.A19.2A.A34.2A38.3A198.A$
497.2A13.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A706.A39.A2.A33.
3A8.A.A20.3A75.A.2A197.2A$513.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.
A2.A4.A5.3A691.3A41.A34.2A26.A4.3A76.3A196.A.A$527.2A11.3A11.3A6.A.A
2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A677.A.2A36.A3.A61.3A4.2A6.A69.3A$
541.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A672.3A40.A16.3A41.
2A.A11.3A68.2A$555.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A9.A661.3A37.A
.A7.A8.A2.A21.A19.3A12.A.2A79.3A$569.2A11.3A11.3A6.A.A2.3A5.A5.2A.A8.
3A660.2A47.3A10.A20.3A19.2A13.3A38.A39.A2.A47.A$583.2A11.3A11.3A6.A.A
2.3A9.A.2A671.3A33.2A.A10.A19.2A.A34.2A38.3A41.A47.2A$597.2A11.3A11.
3A10.3A630.A39.A2.A33.3A8.A.A20.3A75.A.2A36.A3.A46.A.A$611.2A11.3A10.
3A629.3A41.A34.2A26.A4.3A76.3A40.A16.3A163.A$625.2A10.3A629.A.2A36.A
3.A61.3A4.2A6.A69.3A37.A.A7.A8.A2.A163.2A$637.2A631.3A40.A16.3A41.2A.
A11.3A68.2A47.3A10.A162.A.A$1270.3A37.A.A7.A8.A2.A21.A19.3A12.A.2A79.
3A33.2A.A10.A$1270.2A47.3A10.A20.3A19.2A13.3A38.A39.A2.A33.3A8.A.A$
1318.2A.A10.A19.2A.A34.2A38.3A41.A34.2A$622.3A693.3A8.A.A20.3A75.A.2A
36.A3.A73.A$608.3A5.A4.A2.A694.2A26.A4.3A76.3A40.A16.3A54.2A$594.3A5.
A4.A2.A4.3A6.A5.3A713.3A4.2A6.A69.3A37.A.A7.A8.A2.A21.A31.A.A$580.3A
5.A4.A2.A4.3A6.A4.A.2A5.A5.A2.A667.3A41.2A.A11.3A68.2A47.3A10.A20.3A
166.A$566.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.A669.A2.A21.A19.3A12.
A.2A79.3A33.2A.A10.A19.2A.A166.2A$552.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A
2.A.A6.3A11.A3.A4.3A661.A20.3A19.2A13.3A38.A39.A2.A33.3A8.A.A20.3A
166.A.A$538.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.A3.A3.A2.
A661.A19.2A.A34.2A38.3A41.A34.2A26.A4.3A$524.3A5.A4.A2.A4.3A6.A4.A.2A
5.A5.3A2.A.A6.3A11.3A11.2A12.A10.A658.A.A20.3A75.A.2A36.A3.A61.3A4.2A
6.A$518.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.2A27.A.A7.A676.A
4.3A76.3A40.A16.3A41.2A.A11.3A$517.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A
11.2A48.A.A676.3A4.2A6.A69.3A37.A.A7.A8.A2.A21.A19.3A12.A.2A$517.A.2A
5.A5.3A2.A.A6.3A11.3A11.2A740.2A.A11.3A68.2A47.3A10.A20.3A19.2A13.3A$
518.3A2.A.A6.3A11.3A11.2A734.A19.3A12.A.2A79.3A33.2A.A10.A19.2A.A34.
2A$518.3A11.3A11.2A88.A658.3A19.2A13.3A38.A39.A2.A33.3A8.A.A20.3A61.
2A130.A$511.A6.3A11.2A101.3A656.2A.A34.2A38.3A41.A34.2A26.A4.3A60.A.A
130.2A$510.3A5.2A114.2A.A656.3A75.A.2A36.A3.A61.3A4.2A6.A55.A129.A.A$
510.A.2A120.3A657.3A76.3A40.A16.3A41.2A.A11.3A$511.3A121.2A658.2A6.A
69.3A37.A.A7.A8.A2.A21.A19.3A12.A.2A$511.2A789.3A68.2A47.3A10.A20.3A
19.2A13.3A$1302.A.2A79.3A33.2A.A10.A19.2A.A34.2A$1303.3A38.A39.A2.A
33.3A8.A.A20.3A$522.3A778.2A38.3A41.A34.2A26.A4.3A$522.A2.A4.A5.3A
804.A.2A36.A3.A61.3A4.2A6.A212.A$513.A8.A6.3A4.A2.A4.A5.3A791.3A40.A
16.3A41.2A.A11.3A211.2A$512.3A7.A5.2A.A4.A6.3A4.A2.A4.A5.3A777.3A37.A
.A7.A8.A2.A21.A19.3A12.A.2A79.3A127.A.A$512.A.2A7.A.A2.3A5.A5.2A.A4.A
6.3A4.A2.A4.A5.3A763.2A47.3A10.A20.3A19.2A13.3A38.A39.A2.A$513.3A12.
3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A761.3A33.2A.A10.A19.2A.A34.2A
38.3A41.A$513.2A13.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A706.A
39.A2.A33.3A8.A.A20.3A75.A.2A36.A3.A$529.2A11.3A11.3A6.A.A2.3A5.A5.2A
.A4.A6.3A4.A2.A4.A5.3A691.3A41.A34.2A26.A4.3A76.3A31.A8.A16.3A$543.2A
11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A677.A.2A36.A3.A61.3A
4.2A6.A69.3A30.A6.A.A7.A8.A2.A$557.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A
6.3A4.A2.A4.A672.3A40.A16.3A41.2A.A11.3A68.2A31.A15.3A10.A$571.2A11.
3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A9.A661.3A37.A.A7.A8.A2.A21.A19.3A12.A
.2A79.3A33.2A.A10.A106.A$585.2A11.3A11.3A6.A.A2.3A5.A5.2A.A8.3A660.2A
47.3A10.A20.3A19.2A13.3A38.A39.A2.A33.3A8.A.A107.2A$599.2A11.3A11.3A
6.A.A2.3A9.A.2A671.3A33.2A.A10.A19.2A.A34.2A38.3A41.A34.2A117.A.A$
613.2A11.3A11.3A10.3A670.A2.A33.3A8.A.A20.3A75.A.2A36.A3.A289.A$627.
2A11.3A10.3A673.A34.2A26.A4.3A76.3A40.A16.3A270.2A$641.2A10.3A669.A3.
A61.3A4.2A6.A69.3A37.A.A7.A8.A2.A21.A247.A.A$653.2A674.A16.3A41.2A.A
11.3A68.2A47.3A10.A20.3A$1326.A.A7.A8.A2.A21.A19.3A12.A.2A79.3A33.2A.
A10.A19.2A.A$1335.3A10.A20.3A19.2A13.3A38.A39.A2.A33.3A8.A.A20.3A$
1334.2A.A10.A19.2A.A34.2A38.3A41.A34.2A26.A4.3A110.A$638.3A693.3A8.A.
A20.3A75.A.2A36.A3.A61.3A4.2A6.A103.2A$624.3A5.A4.A2.A694.2A26.A4.3A
76.3A40.A16.3A41.2A.A11.3A101.A.A$610.3A5.A4.A2.A4.3A6.A5.3A713.3A4.
2A6.A69.3A37.A.A7.A8.A2.A21.A19.3A12.A.2A236.A$596.3A5.A4.A2.A4.3A6.A
4.A.2A5.A5.A2.A711.2A.A11.3A68.2A47.3A10.A20.3A19.2A13.3A236.2A$582.
3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.A694.A19.3A12.A.2A79.3A33.2A.A
10.A19.2A.A34.2A236.A.A$568.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A
11.A3.A4.3A682.3A19.2A13.3A38.A39.A2.A33.3A8.A.A20.3A$554.3A5.A4.A2.A
4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.A3.A3.A2.A681.2A.A34.2A38.3A41.A
34.2A26.A4.3A$540.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.2A
12.A10.A681.3A75.A.2A36.A3.A61.3A4.2A6.A$534.A4.A2.A4.3A6.A4.A.2A5.A
5.3A2.A.A6.3A11.3A11.2A27.A.A7.A676.A4.3A76.3A40.A16.3A41.2A.A11.3A
128.A$533.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.2A48.A.A676.3A4.2A6.A69.
3A37.A.A7.A8.A2.A21.A19.3A12.A.2A127.2A$533.A.2A5.A5.3A2.A.A6.3A11.3A
11.2A740.2A.A11.3A68.2A47.3A10.A20.3A19.2A13.3A126.A.A$534.3A2.A.A6.
3A11.3A11.2A754.3A12.A.2A79.3A33.2A.A10.A19.2A.A34.2A263.A$534.3A11.
3A11.2A88.A680.2A13.3A38.A39.A2.A33.3A8.A.A20.3A300.2A$527.A6.3A11.2A
101.3A694.2A38.3A41.A34.2A26.A4.3A299.A.A$526.3A5.2A114.2A.A734.A.2A
36.A3.A61.3A4.2A6.A$526.A.2A120.3A736.3A40.A16.3A41.2A.A11.3A$527.3A
121.2A736.3A37.A.A7.A8.A2.A21.A19.3A12.A.2A79.3A$527.2A860.2A47.3A10.
A20.3A19.2A13.3A38.A39.A2.A71.A$1401.3A33.2A.A10.A19.2A.A34.2A38.3A
41.A71.2A$1360.A39.A2.A33.3A8.A.A20.3A75.A.2A36.A3.A70.A.A$538.3A818.
3A41.A34.2A26.A4.3A76.3A40.A206.A$538.A2.A4.A5.3A804.A.2A36.A3.A61.3A
4.2A6.A69.3A37.A.A7.A199.2A$529.A8.A6.3A4.A2.A4.A5.3A791.3A40.A16.3A
41.2A.A11.3A68.2A47.3A197.A.A$528.3A7.A5.2A.A4.A6.3A4.A2.A4.A5.3A777.
3A37.A.A7.A8.A2.A21.A19.3A12.A.2A79.3A33.2A.A$528.A.2A7.A.A2.3A5.A5.
2A.A4.A6.3A4.A2.A4.A5.3A763.2A47.3A10.A20.3A19.2A13.3A38.A39.A2.A33.
3A$529.3A12.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A761.3A33.2A.A10.A
19.2A.A34.2A38.3A41.A34.2A$529.2A13.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A
4.A2.A4.A5.3A706.A39.A2.A33.3A8.A.A20.3A75.A.2A36.A3.A97.A$545.2A11.
3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A691.3A41.A34.2A26.A4.3A
76.3A40.A16.3A78.2A$559.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.
A5.3A677.A.2A36.A3.A61.3A4.2A6.A69.3A37.A.A7.A8.A2.A77.A.A$573.2A11.
3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A672.3A40.A16.3A41.2A.A11.3A
68.2A47.3A10.A213.A$587.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A9.A661.
3A37.A.A7.A8.A2.A21.A19.3A12.A.2A79.3A33.2A.A10.A213.2A$601.2A11.3A
11.3A6.A.A2.3A5.A5.2A.A8.3A660.2A47.3A10.A20.3A19.2A13.3A38.A39.A2.A
33.3A8.A.A213.A.A$615.2A11.3A11.3A6.A.A2.3A9.A.2A707.2A.A10.A19.2A.A
34.2A38.3A41.A34.2A26.A$629.2A11.3A11.3A10.3A707.3A8.A.A20.3A75.A.2A
36.A3.A61.3A$643.2A11.3A10.3A708.2A26.A4.3A76.3A40.A16.3A41.2A.A$657.
2A10.3A735.3A4.2A6.A69.3A37.A.A7.A8.A2.A21.A19.3A60.A$669.2A691.3A41.
2A.A11.3A68.2A47.3A10.A20.3A19.2A60.2A$1361.A2.A21.A19.3A12.A.2A79.3A
33.2A.A10.A19.2A.A80.A.A$1364.A20.3A19.2A13.3A38.A39.A2.A33.3A8.A.A
20.3A217.A$1364.A19.2A.A34.2A38.3A41.A34.2A26.A4.3A217.2A$654.3A704.A
.A20.3A75.A.2A36.A3.A61.3A4.2A6.A209.A.A$640.3A5.A4.A2.A722.A4.3A76.
3A40.A16.3A41.2A.A11.3A$626.3A5.A4.A2.A4.3A6.A5.3A713.3A4.2A6.A69.3A
37.A.A7.A8.A2.A21.A19.3A12.A.2A$612.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.A2.A
711.2A.A11.3A68.2A47.3A10.A20.3A19.2A13.3A$598.3A5.A4.A2.A4.3A6.A4.A.
2A5.A5.3A2.A.A6.A694.A19.3A12.A.2A79.3A33.2A.A10.A19.2A.A34.2A71.A$
584.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.A3.A4.3A682.3A19.2A13.
3A38.A39.A2.A33.3A8.A.A20.3A108.2A$570.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.
3A2.A.A6.3A11.3A11.A3.A3.A2.A681.2A.A34.2A38.3A41.A34.2A26.A4.3A107.A
.A$556.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.2A12.A10.A681.
3A75.A.2A36.A3.A61.3A4.2A6.A236.A$550.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.
A6.3A11.3A11.2A27.A.A7.A681.3A76.3A40.A16.3A41.2A.A11.3A235.2A$549.3A
6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.2A48.A.A683.2A6.A69.3A37.A.A7.A8.A2.
A21.A19.3A12.A.2A233.A.A$549.A.2A5.A5.3A2.A.A6.3A11.3A11.2A755.3A68.
2A47.3A10.A20.3A19.2A13.3A38.A$550.3A2.A.A6.3A11.3A11.2A769.A.2A79.3A
33.2A.A10.A19.2A.A34.2A38.3A$550.3A11.3A11.2A88.A695.3A38.A39.A2.A33.
3A8.A.A20.3A75.A.2A$543.A6.3A11.2A101.3A694.2A38.3A41.A34.2A26.A4.3A
76.3A55.A$542.3A5.2A114.2A.A734.A.2A36.A3.A61.3A4.2A6.A69.3A55.2A$
542.A.2A120.3A736.3A40.A16.3A41.2A.A11.3A68.2A55.A.A$543.3A121.2A736.
3A37.A.A7.A8.A2.A21.A19.3A12.A.2A79.3A178.A$543.2A860.2A47.3A10.A20.
3A19.2A13.3A38.A39.A2.A178.2A$1417.3A33.2A.A10.A19.2A.A34.2A38.3A41.A
177.A.A$1376.A39.A2.A33.3A8.A.A20.3A75.A.2A36.A3.A$554.3A818.3A41.A
34.2A26.A4.3A76.3A40.A16.3A$554.A2.A4.A5.3A804.A.2A36.A3.A61.3A4.2A6.
A69.3A37.A.A7.A8.A2.A$545.A8.A6.3A4.A2.A4.A5.3A791.3A40.A16.3A41.2A.A
11.3A68.2A47.3A10.A21.A$544.3A7.A5.2A.A4.A6.3A4.A2.A4.A5.3A777.3A37.A
.A7.A8.A2.A21.A19.3A12.A.2A79.3A33.2A.A10.A21.2A$544.A.2A7.A.A2.3A5.A
5.2A.A4.A6.3A4.A2.A4.A5.3A763.2A47.3A10.A20.3A19.2A13.3A38.A39.A2.A
33.3A8.A.A21.A.A$545.3A12.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A
761.3A33.2A.A10.A19.2A.A34.2A38.3A41.A34.2A168.A$545.2A13.3A11.3A6.A.
A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A746.A2.A33.3A8.A.A20.3A75.A.2A36.A
3.A204.2A$561.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A735.A
34.2A26.A4.3A76.3A40.A16.3A184.A.A$575.2A11.3A11.3A6.A.A2.3A5.A5.2A.A
4.A6.3A4.A2.A4.A5.3A717.A3.A61.3A4.2A6.A69.3A37.A.A7.A8.A2.A21.A$589.
2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A715.A16.3A41.2A.A11.3A
68.2A47.3A10.A20.3A$603.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A9.A701.A
.A7.A8.A2.A21.A19.3A12.A.2A79.3A33.2A.A10.A19.2A.A$617.2A11.3A11.3A6.
A.A2.3A5.A5.2A.A8.3A709.3A10.A20.3A19.2A13.3A38.A39.A2.A33.3A8.A.A20.
3A$631.2A11.3A11.3A6.A.A2.3A9.A.2A707.2A.A10.A19.2A.A34.2A38.3A41.A
34.2A26.A4.3A$645.2A11.3A11.3A10.3A707.3A8.A.A20.3A75.A.2A36.A3.A61.
3A4.2A6.A$659.2A11.3A10.3A708.2A26.A4.3A76.3A40.A16.3A41.2A.A11.3A20.
2A130.A$673.2A10.3A735.3A4.2A6.A69.3A37.A.A7.A8.A2.A21.A19.3A12.A.2A
8.2A.A6.A.A130.2A$685.2A735.2A.A11.3A68.2A47.3A10.A20.3A19.2A13.3A8.A
3.A7.A129.A.A$1402.A19.3A12.A.2A79.3A33.2A.A10.A19.2A.A34.2A10.A.A
274.A$1401.3A19.2A13.3A38.A39.A2.A33.3A8.A.A20.3A324.2A$1400.2A.A34.
2A38.3A41.A34.2A26.A4.3A323.A.A$670.3A727.3A75.A.2A36.A3.A61.3A4.2A6.
A38.3A$656.3A5.A4.A2.A722.A4.3A76.3A40.A16.3A41.2A.A11.3A38.A.A$642.
3A5.A4.A2.A4.3A6.A5.3A713.3A4.2A6.A69.3A37.A.A7.A8.A2.A21.A19.3A12.A.
2A37.A2.A$628.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.A2.A711.2A.A11.3A68.2A47.
3A10.A20.3A19.2A13.3A40.A136.A$614.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A
.A6.A714.3A12.A.2A79.3A33.2A.A10.A19.2A.A34.2A37.A140.2A$600.3A5.A4.A
2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.A3.A4.3A704.2A13.3A38.A39.A2.A33.
3A8.A.A20.3A74.A5.A133.A.A$586.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.
3A11.3A11.A3.A3.A2.A719.2A38.3A41.A34.2A26.A4.3A76.4A270.A$572.3A5.A
4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.2A12.A10.A759.A.2A36.A3.A
61.3A4.2A6.A72.A270.2A$566.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A
11.2A27.A.A7.A760.3A40.A16.3A41.2A.A11.3A341.A.A$565.3A6.A4.A.2A5.A5.
3A2.A.A6.3A11.3A11.2A48.A.A761.3A37.A.A7.A8.A2.A21.A19.3A12.A.2A79.3A
$565.A.2A5.A5.3A2.A.A6.3A11.3A11.2A826.2A47.3A10.A20.3A19.2A13.3A38.A
39.A2.A$566.3A2.A.A6.3A11.3A11.2A852.3A33.2A.A10.A19.2A.A34.2A38.3A
41.A$566.3A11.3A11.2A88.A736.A39.A2.A33.3A8.A.A20.3A75.A.2A36.A3.A
121.A$559.A6.3A11.2A101.3A734.3A41.A34.2A26.A4.3A76.3A40.A16.3A102.2A
$558.3A5.2A114.2A.A734.A.2A36.A3.A61.3A4.2A6.A69.3A37.A.A7.A8.A2.A
101.A.A$558.A.2A120.3A736.3A40.A16.3A41.2A.A11.3A68.2A47.3A10.A237.A$
559.3A121.2A736.3A37.A.A7.A8.A2.A21.A19.3A12.A.2A79.3A33.2A.A10.A237.
2A$559.2A860.2A47.3A10.A20.3A19.2A13.3A38.A39.A2.A33.3A8.A.A237.A.A$
1433.3A33.2A.A10.A19.2A.A34.2A38.3A41.A34.2A$1392.A39.A2.A33.3A8.A.A
20.3A75.A.2A36.A3.A$570.3A818.3A41.A34.2A26.A4.3A76.3A40.A16.3A$570.A
2.A4.A5.3A804.A.2A36.A3.A61.3A4.2A6.A69.3A37.A.A7.A8.A2.A21.A106.A$
561.A8.A6.3A4.A2.A4.A5.3A791.3A40.A16.3A41.2A.A11.3A68.2A47.3A10.A20.
3A105.2A$560.3A7.A5.2A.A4.A6.3A4.A2.A4.A5.3A777.3A37.A.A7.A8.A2.A21.A
19.3A12.A.2A79.3A33.2A.A10.A19.2A.A104.A.A$560.A.2A7.A.A2.3A5.A5.2A.A
4.A6.3A4.A2.A4.A5.3A763.2A47.3A10.A20.3A19.2A13.3A38.A39.A2.A33.3A8.A
.A20.3A241.A$561.3A12.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A797.2A.
A10.A19.2A.A34.2A38.3A41.A34.2A26.A4.3A241.2A$561.2A13.3A11.3A6.A.A2.
3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A783.3A8.A.A20.3A75.A.2A36.A3.A61.3A4.
2A6.A233.A.A$577.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A
770.2A26.A4.3A76.3A40.A16.3A41.2A.A11.3A$591.2A11.3A11.3A6.A.A2.3A5.A
5.2A.A4.A6.3A4.A2.A4.A5.3A783.3A4.2A6.A69.3A37.A.A7.A8.A2.A21.A19.3A
12.A.2A$605.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A732.3A41.2A
.A11.3A68.2A47.3A10.A20.3A19.2A13.3A$619.2A11.3A11.3A6.A.A2.3A5.A5.2A
.A4.A6.3A9.A720.A2.A21.A19.3A12.A.2A79.3A33.2A.A10.A19.2A.A34.2A95.A$
633.2A11.3A11.3A6.A.A2.3A5.A5.2A.A8.3A722.A20.3A19.2A13.3A38.A39.A2.A
33.3A8.A.A20.3A132.2A$647.2A11.3A11.3A6.A.A2.3A9.A.2A721.A19.2A.A34.
2A38.3A41.A34.2A26.A4.3A131.A.A$661.2A11.3A11.3A10.3A718.A.A20.3A75.A
.2A36.A3.A61.3A4.2A6.A260.A$675.2A11.3A10.3A736.A4.3A76.3A40.A16.3A
41.2A.A11.3A259.2A$689.2A10.3A735.3A4.2A6.A69.3A37.A.A7.A8.A2.A21.A
19.3A12.A.2A257.A.A$701.2A735.2A.A11.3A68.2A47.3A10.A20.3A19.2A13.3A$
1418.A19.3A12.A.2A79.3A33.2A.A10.A19.2A.A34.2A$1417.3A19.2A13.3A38.A
39.A2.A33.3A8.A.A20.3A$1416.2A.A34.2A38.3A41.A34.2A26.A4.3A158.A$686.
3A727.3A75.A.2A36.A3.A61.3A4.2A6.A151.2A$672.3A5.A4.A2.A727.3A76.3A
40.A16.3A41.2A.A11.3A149.A.A$658.3A5.A4.A2.A4.3A6.A5.3A720.2A6.A69.3A
37.A.A7.A8.A2.A21.A19.3A12.A.2A79.3A202.A$644.3A5.A4.A2.A4.3A6.A4.A.
2A5.A5.A2.A726.3A68.2A47.3A10.A20.3A19.2A13.3A38.A39.A2.A202.2A$630.
3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.A729.A.2A79.3A33.2A.A10.A19.2A.
A34.2A38.3A41.A201.A.A$616.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A
11.A3.A4.3A719.3A38.A39.A2.A33.3A8.A.A20.3A75.A.2A36.A3.A$602.3A5.A4.
A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.A3.A3.A2.A719.2A38.3A41.A34.
2A26.A4.3A76.3A40.A$588.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A
11.2A12.A10.A759.A.2A36.A3.A61.3A4.2A6.A69.3A37.A.A7.A$582.A4.A2.A4.
3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.2A27.A.A7.A760.3A40.A16.3A41.2A.A
11.3A68.2A47.3A56.A$581.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.2A48.A.A
761.3A37.A.A7.A8.A2.A21.A19.3A12.A.2A79.3A33.2A.A56.2A$581.A.2A5.A5.
3A2.A.A6.3A11.3A11.2A826.2A47.3A10.A20.3A19.2A13.3A38.A39.A2.A33.3A
56.A.A$582.3A2.A.A6.3A11.3A11.2A852.3A33.2A.A10.A19.2A.A34.2A38.3A41.
A34.2A192.A$582.3A11.3A11.2A88.A736.A39.A2.A33.3A8.A.A20.3A75.A.2A36.
A3.A228.2A$575.A6.3A11.2A101.3A734.3A41.A34.2A26.A4.3A76.3A40.A16.3A
208.A.A$574.3A5.2A114.2A.A734.A.2A36.A3.A61.3A4.2A6.A69.3A37.A.A7.A8.
A2.A$574.A.2A120.3A736.3A40.A16.3A41.2A.A11.3A68.2A47.3A10.A$575.3A
121.2A736.3A37.A.A7.A8.A2.A21.A19.3A12.A.2A79.3A33.2A.A10.A$575.2A
860.2A47.3A10.A20.3A19.2A13.3A38.A39.A2.A33.3A8.A.A72.A$1449.3A33.2A.
A10.A19.2A.A34.2A38.3A41.A34.2A26.A56.2A$1448.A2.A33.3A8.A.A20.3A75.A
.2A36.A3.A61.3A54.A.A$586.3A862.A34.2A26.A4.3A76.3A40.A16.3A41.2A.A
190.A$586.A2.A4.A5.3A844.A3.A61.3A4.2A6.A69.3A37.A.A7.A8.A2.A21.A19.
3A191.2A$577.A8.A6.3A4.A2.A4.A5.3A834.A16.3A41.2A.A11.3A68.2A47.3A10.
A20.3A19.2A190.A.A$576.3A7.A5.2A.A4.A6.3A4.A2.A4.A5.3A817.A.A7.A8.A2.
A21.A19.3A12.A.2A79.3A33.2A.A10.A19.2A.A$576.A.2A7.A.A2.3A5.A5.2A.A4.
A6.3A4.A2.A4.A5.3A812.3A10.A20.3A19.2A13.3A38.A39.A2.A33.3A8.A.A20.3A
$577.3A12.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A797.2A.A10.A19.2A.A
34.2A38.3A41.A34.2A26.A4.3A$577.2A13.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A
4.A2.A4.A5.3A783.3A8.A.A20.3A75.A.2A36.A3.A61.3A4.2A6.A68.A$593.2A11.
3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A770.2A26.A4.3A76.3A40.A
16.3A41.2A.A11.3A67.2A$607.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.
A4.A5.3A783.3A4.2A6.A69.3A37.A.A7.A8.A2.A21.A19.3A12.A.2A65.A.A$621.
2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A776.2A.A11.3A68.2A47.3A
10.A20.3A19.2A13.3A201.A$635.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A9.A
745.A19.3A12.A.2A79.3A33.2A.A10.A19.2A.A34.2A202.2A$649.2A11.3A11.3A
6.A.A2.3A5.A5.2A.A8.3A743.3A19.2A13.3A38.A39.A2.A33.3A8.A.A20.3A238.A
.A$663.2A11.3A11.3A6.A.A2.3A9.A.2A741.2A.A34.2A38.3A41.A34.2A26.A4.3A
$677.2A11.3A11.3A10.3A741.3A75.A.2A36.A3.A61.3A4.2A6.A$691.2A11.3A10.
3A736.A4.3A76.3A40.A16.3A41.2A.A11.3A$705.2A10.3A735.3A4.2A6.A69.3A
37.A.A7.A8.A2.A21.A19.3A12.A.2A92.A$717.2A735.2A.A11.3A68.2A47.3A10.A
20.3A19.2A13.3A38.A53.2A$1454.3A12.A.2A79.3A33.2A.A10.A19.2A.A34.2A
38.3A51.A.A$1455.2A13.3A38.A39.A2.A33.3A8.A.A20.3A75.A.2A186.A$1470.
2A38.3A41.A34.2A26.A4.3A76.3A186.2A$702.3A805.A.2A36.A3.A61.3A4.2A6.A
69.3A185.A.A$688.3A5.A4.A2.A806.3A40.A16.3A41.2A.A11.3A68.2A322.A$
674.3A5.A4.A2.A4.3A6.A5.3A798.3A37.A.A7.A8.A2.A21.A19.3A12.A.2A79.3A
309.2A$660.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.A2.A797.2A47.3A10.A20.3A19.2A
13.3A38.A39.A2.A308.A.A$646.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.A
812.3A33.2A.A10.A19.2A.A34.2A38.3A41.A36.A$632.3A5.A4.A2.A4.3A6.A4.A.
2A5.A5.3A2.A.A6.3A11.A3.A4.3A760.A39.A2.A33.3A8.A.A20.3A75.A.2A36.A3.
A36.2A$618.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.A3.A3.A2.A
759.3A41.A34.2A26.A4.3A76.3A40.A16.3A16.A.A$604.3A5.A4.A2.A4.3A6.A4.A
.2A5.A5.3A2.A.A6.3A11.3A11.2A12.A10.A759.A.2A36.A3.A61.3A4.2A6.A69.3A
37.A.A7.A8.A2.A152.A$598.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.
2A27.A.A7.A760.3A40.A16.3A41.2A.A11.3A68.2A47.3A10.A4.2A146.2A$597.3A
6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.2A48.A.A761.3A37.A.A7.A8.A2.A21.A19.
3A12.A.2A79.3A33.2A.A10.A4.2A.2A142.A.A$597.A.2A5.A5.3A2.A.A6.3A11.3A
11.2A826.2A47.3A10.A20.3A19.2A13.3A38.A39.A2.A33.3A8.A.A5.2A.2A2.2A
274.A$598.3A2.A.A6.3A11.3A11.2A852.3A33.2A.A10.A19.2A.A34.2A38.3A41.A
34.2A17.A.A.2A.A274.2A$598.3A11.3A11.2A88.A736.A39.A2.A33.3A8.A.A20.
3A75.A.2A36.A3.A54.A2.A2.A273.A.A$591.A6.3A11.2A101.3A734.3A41.A34.2A
26.A4.3A76.3A40.A16.3A38.A2.A$590.3A5.2A114.2A.A734.A.2A36.A3.A61.3A
4.2A6.A69.3A37.A.A7.A8.A2.A21.A19.A$590.A.2A120.3A736.3A40.A16.3A41.
2A.A11.3A68.2A47.3A10.A20.3A15.A2.A$591.3A121.2A736.3A37.A.A7.A8.A2.A
21.A19.3A12.A.2A79.3A33.2A.A10.A19.2A.A14.2A2.A4.2A130.A$591.2A860.2A
47.3A10.A20.3A19.2A13.3A38.A39.A2.A33.3A8.A.A20.3A15.2A2.A3.A.A130.2A
$1501.2A.A10.A19.2A.A34.2A38.3A41.A34.2A26.A4.3A14.2A9.A129.A.A$1501.
3A8.A.A20.3A75.A.2A36.A3.A61.3A4.2A6.A9.A2.2A270.A$602.3A897.2A26.A4.
3A76.3A40.A16.3A41.2A.A11.3A283.2A$602.A2.A4.A5.3A910.3A4.2A6.A69.3A
37.A.A7.A8.A2.A21.A19.3A12.A.2A281.A.A$593.A8.A6.3A4.A2.A4.A5.3A851.
3A41.2A.A11.3A68.2A47.3A10.A20.3A19.2A13.3A$592.3A7.A5.2A.A4.A6.3A4.A
2.A4.A5.3A836.A2.A21.A19.3A12.A.2A79.3A33.2A.A10.A19.2A.A34.2A10.3A$
592.A.2A7.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A825.A20.3A19.2A13.3A38.
A39.A2.A33.3A8.A.A20.3A46.A3.A$593.3A12.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.
A2.A4.A5.3A811.A19.2A.A34.2A38.3A41.A34.2A26.A4.3A47.A.A132.A$593.2A
13.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A794.A.A20.3A75.A.2A
36.A3.A61.3A4.2A6.A41.A133.2A$609.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.
3A4.A2.A4.A5.3A798.A4.3A76.3A40.A16.3A41.2A.A11.3A173.A.A$623.2A11.3A
11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A783.3A4.2A6.A69.3A37.A.A7.
A8.A2.A21.A19.3A12.A.2A308.A$637.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.
3A4.A2.A4.A776.2A.A11.3A68.2A47.3A10.A20.3A19.2A13.3A38.A269.2A$651.
2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A9.A745.A19.3A12.A.2A79.3A33.2A.A
10.A19.2A.A34.2A38.3A267.A.A$665.2A11.3A11.3A6.A.A2.3A5.A5.2A.A8.3A
743.3A19.2A13.3A38.A39.A2.A33.3A8.A.A20.3A75.A.2A$679.2A11.3A11.3A6.A
.A2.3A9.A.2A741.2A.A34.2A38.3A41.A34.2A26.A4.3A76.3A$693.2A11.3A11.3A
10.3A741.3A75.A.2A36.A3.A61.3A4.2A6.A69.3A$707.2A11.3A10.3A741.3A76.
3A40.A16.3A41.2A.A11.3A68.2A130.A$721.2A10.3A742.2A6.A69.3A37.A.A7.A
8.A2.A21.A19.3A12.A.2A79.3A117.2A$733.2A750.3A68.2A47.3A10.A20.3A19.
2A13.3A38.A39.A2.A116.A.A$1485.A.2A79.3A33.2A.A10.A19.2A.A34.2A38.3A
41.A252.A$1486.3A38.A39.A2.A33.3A8.A.A20.3A75.A.2A36.A3.A252.2A$1486.
2A38.3A41.A34.2A26.A4.3A76.3A40.A16.3A232.A.A$718.3A805.A.2A36.A3.A
61.3A4.2A6.A69.3A37.A.A7.A8.A2.A$704.3A5.A4.A2.A806.3A40.A16.3A41.2A.
A11.3A68.2A47.3A10.A$690.3A5.A4.A2.A4.3A6.A5.3A798.3A37.A.A7.A8.A2.A
21.A19.3A12.A.2A79.3A33.2A.A10.A$676.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.A2.
A797.2A47.3A10.A20.3A19.2A13.3A38.A39.A2.A33.3A8.A.A96.A$662.3A5.A4.A
2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.A812.3A33.2A.A10.A19.2A.A34.2A38.3A41.A
34.2A107.2A$648.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.A3.A4.3A
760.A39.A2.A33.3A8.A.A20.3A75.A.2A36.A3.A142.A.A$634.3A5.A4.A2.A4.3A
6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.A3.A3.A2.A759.3A41.A34.2A26.A4.3A76.
3A40.A16.3A259.A$620.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.
2A12.A10.A759.A.2A36.A3.A61.3A4.2A6.A69.3A37.A.A7.A8.A2.A21.A237.2A$
614.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.2A27.A.A7.A760.3A40.A
16.3A41.2A.A11.3A68.2A47.3A10.A20.3A235.A.A$613.3A6.A4.A.2A5.A5.3A2.A
.A6.3A11.3A11.2A48.A.A761.3A37.A.A7.A8.A2.A21.A19.3A12.A.2A79.3A33.2A
.A10.A19.2A.A$613.A.2A5.A5.3A2.A.A6.3A11.3A11.2A826.2A47.3A10.A20.3A
19.2A13.3A38.A39.A2.A33.3A8.A.A20.3A$614.3A2.A.A6.3A11.3A11.2A852.3A
33.2A.A10.A19.2A.A34.2A38.3A41.A34.2A26.A4.3A$614.3A11.3A11.2A88.A
776.A2.A33.3A8.A.A20.3A75.A.2A36.A3.A61.3A4.2A6.A92.A$607.A6.3A11.2A
101.3A778.A34.2A26.A4.3A76.3A40.A16.3A41.2A.A11.3A91.2A$606.3A5.2A
114.2A.A774.A3.A61.3A4.2A6.A69.3A37.A.A7.A8.A2.A21.A19.3A12.A.2A89.A.
A$606.A.2A120.3A779.A16.3A41.2A.A11.3A68.2A47.3A10.A20.3A19.2A13.3A
225.A$607.3A121.2A776.A.A7.A8.A2.A21.A19.3A12.A.2A79.3A33.2A.A10.A19.
2A.A34.2A226.2A$607.2A909.3A10.A20.3A19.2A13.3A38.A39.A2.A33.3A8.A.A
20.3A262.A.A$1517.2A.A10.A19.2A.A34.2A38.3A41.A34.2A26.A4.3A$1517.3A
8.A.A20.3A75.A.2A36.A3.A61.3A4.2A6.A$618.3A897.2A26.A4.3A76.3A40.A16.
3A41.2A.A11.3A$618.A2.A4.A5.3A910.3A4.2A6.A69.3A37.A.A7.A8.A2.A21.A
19.3A12.A.2A116.A$609.A8.A6.3A4.A2.A4.A5.3A895.2A.A11.3A68.2A47.3A10.
A20.3A19.2A13.3A116.2A$608.3A7.A5.2A.A4.A6.3A4.A2.A4.A5.3A861.A19.3A
12.A.2A79.3A33.2A.A10.A19.2A.A34.2A116.A.A$608.A.2A7.A.A2.3A5.A5.2A.A
4.A6.3A4.A2.A4.A5.3A846.3A19.2A13.3A38.A39.A2.A33.3A8.A.A20.3A289.A$
609.3A12.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A831.2A.A34.2A38.3A
41.A34.2A26.A4.3A289.2A$609.2A13.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A
2.A4.A5.3A817.3A75.A.2A36.A3.A61.3A4.2A6.A281.A.A$625.2A11.3A11.3A6.A
.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A798.A4.3A76.3A40.A16.3A41.2A.A11.
3A$639.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A783.3A4.2A6.
A69.3A37.A.A7.A8.A2.A21.A19.3A12.A.2A79.3A$653.2A11.3A11.3A6.A.A2.3A
5.A5.2A.A4.A6.3A4.A2.A4.A776.2A.A11.3A68.2A47.3A10.A20.3A19.2A13.3A
38.A39.A2.A$667.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A9.A765.3A12.A.2A
79.3A33.2A.A10.A19.2A.A34.2A38.3A41.A60.A$681.2A11.3A11.3A6.A.A2.3A5.
A5.2A.A8.3A765.2A13.3A38.A39.A2.A33.3A8.A.A20.3A75.A.2A36.A3.A60.2A$
695.2A11.3A11.3A6.A.A2.3A9.A.2A779.2A38.3A41.A34.2A26.A4.3A76.3A40.A
59.A.A$709.2A11.3A11.3A10.3A819.A.2A36.A3.A61.3A4.2A6.A69.3A37.A.A7.A
188.A$723.2A11.3A10.3A820.3A40.A16.3A41.2A.A11.3A68.2A47.3A187.2A$
737.2A10.3A820.3A37.A.A7.A8.A2.A21.A19.3A12.A.2A79.3A33.2A.A186.A.A$
749.2A821.2A47.3A10.A20.3A19.2A13.3A38.A39.A2.A33.3A$1584.3A33.2A.A
10.A19.2A.A34.2A38.3A41.A34.2A$1543.A39.A2.A33.3A8.A.A20.3A75.A.2A36.
A3.A$1542.3A41.A34.2A26.A4.3A76.3A40.A16.3A67.A$734.3A805.A.2A36.A3.A
61.3A4.2A6.A69.3A37.A.A7.A8.A2.A67.2A$720.3A5.A4.A2.A806.3A40.A16.3A
41.2A.A11.3A68.2A47.3A10.A66.A.A$706.3A5.A4.A2.A4.3A6.A5.3A798.3A37.A
.A7.A8.A2.A21.A19.3A12.A.2A79.3A33.2A.A10.A202.A$692.3A5.A4.A2.A4.3A
6.A4.A.2A5.A5.A2.A797.2A47.3A10.A20.3A19.2A13.3A38.A39.A2.A33.3A8.A.A
203.2A$678.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.A812.3A33.2A.A10.A
19.2A.A34.2A38.3A41.A34.2A26.A186.A.A$664.3A5.A4.A2.A4.3A6.A4.A.2A5.A
5.3A2.A.A6.3A11.A3.A4.3A760.A39.A2.A33.3A8.A.A20.3A75.A.2A36.A3.A61.
3A321.A$650.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.A3.A3.A2.
A759.3A41.A34.2A26.A4.3A76.3A40.A16.3A41.2A.A321.2A$636.3A5.A4.A2.A4.
3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.2A12.A10.A759.A.2A36.A3.A61.3A4.2A
6.A69.3A37.A.A7.A8.A2.A21.A19.3A321.A.A$630.A4.A2.A4.3A6.A4.A.2A5.A5.
3A2.A.A6.3A11.3A11.2A27.A.A7.A760.3A40.A16.3A41.2A.A11.3A68.2A47.3A
10.A20.3A19.2A49.A$629.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.2A48.A.A
761.3A37.A.A7.A8.A2.A21.A19.3A12.A.2A79.3A33.2A.A10.A19.2A.A70.2A$
629.A.2A5.A5.3A2.A.A6.3A11.3A11.2A826.2A47.3A10.A20.3A19.2A13.3A38.A
39.A2.A33.3A8.A.A20.3A70.A.A$630.3A2.A.A6.3A11.3A11.2A888.2A.A10.A19.
2A.A34.2A38.3A41.A34.2A26.A4.3A206.A$630.3A11.3A11.2A88.A813.3A8.A.A
20.3A75.A.2A36.A3.A61.3A4.2A6.A199.2A$623.A6.3A11.2A101.3A813.2A26.A
4.3A76.3A40.A16.3A41.2A.A11.3A197.A.A$622.3A5.2A114.2A.A840.3A4.2A6.A
69.3A37.A.A7.A8.A2.A21.A19.3A12.A.2A332.A$622.A.2A120.3A796.3A41.2A.A
11.3A68.2A47.3A10.A20.3A19.2A13.3A332.2A$623.3A121.2A795.A2.A21.A19.
3A12.A.2A79.3A33.2A.A10.A19.2A.A34.2A332.A.A$623.2A922.A20.3A19.2A13.
3A38.A39.A2.A33.3A8.A.A20.3A97.A$1547.A19.2A.A34.2A38.3A41.A34.2A26.A
4.3A97.2A$1544.A.A20.3A75.A.2A36.A3.A61.3A4.2A6.A89.A.A$634.3A925.A4.
3A76.3A40.A16.3A41.2A.A11.3A224.A$634.A2.A4.A5.3A910.3A4.2A6.A69.3A
37.A.A7.A8.A2.A21.A19.3A12.A.2A223.2A$625.A8.A6.3A4.A2.A4.A5.3A895.2A
.A11.3A68.2A47.3A10.A20.3A19.2A13.3A38.A183.A.A$624.3A7.A5.2A.A4.A6.
3A4.A2.A4.A5.3A861.A19.3A12.A.2A79.3A33.2A.A10.A19.2A.A34.2A38.3A318.
A$624.A.2A7.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A846.3A19.2A13.3A38.A
39.A2.A33.3A8.A.A20.3A75.A.2A317.2A$625.3A12.3A6.A.A2.3A5.A5.2A.A4.A
6.3A4.A2.A4.A5.3A831.2A.A34.2A38.3A41.A34.2A26.A4.3A76.3A42.A273.A.A$
625.2A13.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A817.3A75.A.2A
36.A3.A61.3A4.2A6.A69.3A36.A.A2.A.A3.A$641.2A11.3A11.3A6.A.A2.3A5.A5.
2A.A4.A6.3A4.A2.A4.A5.3A803.3A76.3A40.A16.3A41.2A.A11.3A68.2A37.A6.A
2.3A$655.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A790.2A6.A
69.3A37.A.A7.A8.A2.A21.A19.3A12.A.2A79.3A24.3A2.A.A.2A.A$669.2A11.3A
11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A791.3A68.2A47.3A10.A20.3A19.2A
13.3A38.A39.A2.A29.2A2.3A131.A$683.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A
6.3A9.A780.A.2A79.3A33.2A.A10.A19.2A.A34.2A38.3A41.A34.2A131.2A$697.
2A11.3A11.3A6.A.A2.3A5.A5.2A.A8.3A780.3A38.A39.A2.A33.3A8.A.A20.3A75.
A.2A36.A3.A166.A.A$711.2A11.3A11.3A6.A.A2.3A9.A.2A779.2A38.3A41.A34.
2A26.A4.3A76.3A40.A16.3A283.A$725.2A11.3A11.3A10.3A819.A.2A36.A3.A61.
3A4.2A6.A69.3A37.A.A7.A8.A2.A283.2A$739.2A11.3A10.3A820.3A40.A16.3A
41.2A.A11.3A68.2A47.3A10.A282.A.A$753.2A10.3A820.3A37.A.A7.A8.A2.A21.
A19.3A12.A.2A79.3A33.2A.A10.A$765.2A821.2A47.3A10.A20.3A19.2A13.3A38.
A39.A2.A33.3A8.A.A7.7A$1600.3A33.2A.A10.A19.2A.A34.2A38.3A41.A34.2A
16.A2.3A.4A$1559.A39.A2.A33.3A8.A.A20.3A75.A.2A36.A3.A52.A2.A.A.A.3A
129.A$1558.3A41.A34.2A26.A4.3A76.3A40.A16.3A33.A6.A3.A129.2A$750.3A
805.A.2A36.A3.A61.3A4.2A6.A69.3A37.A.A7.A8.A2.A21.A13.2A2.2A.2A129.A.
A$736.3A5.A4.A2.A806.3A40.A16.3A41.2A.A11.3A68.2A47.3A10.A20.3A16.A.
3A265.A$722.3A5.A4.A2.A4.3A6.A5.3A798.3A37.A.A7.A8.A2.A21.A19.3A12.A.
2A79.3A33.2A.A10.A19.2A.A286.2A$708.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.A2.A
797.2A47.3A10.A20.3A19.2A13.3A38.A39.A2.A33.3A8.A.A20.3A286.A.A$694.
3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.A812.3A33.2A.A10.A19.2A.A34.2A
38.3A41.A34.2A26.A4.3A$680.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A
11.A3.A4.3A800.A2.A33.3A8.A.A20.3A75.A.2A36.A3.A61.3A4.2A6.A$666.3A5.
A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.A3.A3.A2.A803.A34.2A26.A
4.3A76.3A40.A16.3A41.2A.A11.3A$652.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A
.A6.3A11.3A11.2A12.A10.A799.A3.A61.3A4.2A6.A69.3A37.A.A7.A8.A2.A21.A
19.3A12.A.2A140.A$646.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.2A
27.A.A7.A803.A16.3A41.2A.A11.3A68.2A47.3A10.A20.3A19.2A13.3A140.2A$
645.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.2A48.A.A801.A.A7.A8.A2.A21.A
19.3A12.A.2A79.3A33.2A.A10.A19.2A.A34.2A140.A.A$645.A.2A5.A5.3A2.A.A
6.3A11.3A11.2A875.3A10.A20.3A19.2A13.3A38.A39.A2.A33.3A8.A.A20.3A313.
A$646.3A2.A.A6.3A11.3A11.2A888.2A.A10.A19.2A.A34.2A38.3A41.A34.2A26.A
4.3A313.2A$646.3A11.3A11.2A88.A813.3A8.A.A20.3A75.A.2A36.A3.A61.3A4.
2A6.A305.A.A$639.A6.3A11.2A101.3A813.2A26.A4.3A76.3A40.A16.3A41.2A.A
11.3A$638.3A5.2A114.2A.A840.3A4.2A6.A69.3A37.A.A7.A8.A2.A21.A19.3A12.
A.2A$638.A.2A120.3A840.2A.A11.3A68.2A47.3A10.A20.3A19.2A13.3A38.A$
639.3A121.2A820.A19.3A12.A.2A79.3A33.2A.A10.A19.2A.A34.2A38.3A126.A$
639.2A943.3A19.2A13.3A38.A39.A2.A33.3A8.A.A20.3A75.A.2A125.2A$1583.2A
.A34.2A38.3A41.A34.2A26.A4.3A76.3A124.A.A$1583.3A75.A.2A36.A3.A61.3A
4.2A6.A69.3A260.A$650.3A925.A4.3A76.3A40.A16.3A41.2A.A11.3A68.2A261.
2A$650.A2.A4.A5.3A910.3A4.2A6.A69.3A37.A.A7.A8.A2.A21.A19.3A12.A.2A
79.3A247.A.A$641.A8.A6.3A4.A2.A4.A5.3A895.2A.A11.3A68.2A47.3A10.A20.
3A19.2A13.3A38.A39.A2.A$640.3A7.A5.2A.A4.A6.3A4.A2.A4.A5.3A881.3A12.A
.2A79.3A33.2A.A10.A19.2A.A34.2A38.3A41.A$640.A.2A7.A.A2.3A5.A5.2A.A4.
A6.3A4.A2.A4.A5.3A868.2A13.3A38.A39.A2.A33.3A8.A.A20.3A75.A.2A36.A3.A
$641.3A12.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A869.2A38.3A41.A34.
2A26.A4.3A76.3A40.A16.3A91.A$641.2A13.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.
3A4.A2.A4.A5.3A895.A.2A36.A3.A61.3A4.2A6.A69.3A37.A.A7.A8.A2.A91.2A$
657.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A882.3A40.A16.3A
41.2A.A11.3A68.2A47.3A10.A90.A.A$671.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.
A6.3A4.A2.A4.A5.3A868.3A37.A.A7.A8.A2.A21.A19.3A12.A.2A79.3A33.2A.A
10.A226.A$685.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A862.2A47.
3A10.A20.3A19.2A13.3A38.A39.A2.A33.3A8.A.A227.2A$699.2A11.3A11.3A6.A.
A2.3A5.A5.2A.A4.A6.3A9.A863.3A33.2A.A10.A19.2A.A34.2A38.3A41.A34.2A
237.A.A$713.2A11.3A11.3A6.A.A2.3A5.A5.2A.A8.3A821.A39.A2.A33.3A8.A.A
20.3A75.A.2A36.A3.A$727.2A11.3A11.3A6.A.A2.3A9.A.2A819.3A41.A34.2A26.
A4.3A76.3A40.A16.3A$741.2A11.3A11.3A10.3A819.A.2A36.A3.A61.3A4.2A6.A
69.3A37.A.A7.A8.A2.A21.A$755.2A11.3A10.3A820.3A40.A16.3A41.2A.A11.3A
68.2A47.3A10.A20.3A94.A$769.2A10.3A820.3A37.A.A7.A8.A2.A21.A19.3A12.A
.2A79.3A33.2A.A10.A19.2A.A94.2A$781.2A821.2A47.3A10.A20.3A19.2A13.3A
38.A39.A2.A33.3A8.A.A20.3A94.A.A$1616.3A33.2A.A10.A19.2A.A34.2A38.3A
41.A34.2A26.A4.3A230.A$1575.A39.A2.A33.3A8.A.A20.3A75.A.2A36.A3.A61.
3A4.2A6.A223.2A$1574.3A41.A34.2A26.A4.3A76.3A40.A16.3A41.2A.A11.3A
221.A.A$766.3A805.A.2A36.A3.A61.3A4.2A6.A69.3A37.A.A7.A8.A2.A21.A19.
3A12.A.2A$752.3A5.A4.A2.A806.3A40.A16.3A41.2A.A11.3A68.2A47.3A10.A20.
3A19.2A13.3A$738.3A5.A4.A2.A4.3A6.A5.3A798.3A37.A.A7.A8.A2.A21.A19.3A
12.A.2A79.3A33.2A.A10.A19.2A.A34.2A$724.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.
A2.A797.2A47.3A10.A20.3A19.2A13.3A38.A39.A2.A33.3A8.A.A20.3A121.A$
710.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.A848.2A.A10.A19.2A.A34.2A
38.3A41.A34.2A26.A4.3A121.2A$696.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A
6.3A11.A3.A4.3A837.3A8.A.A20.3A75.A.2A36.A3.A61.3A4.2A6.A113.A.A$682.
3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.A3.A3.A2.A838.2A26.A
4.3A76.3A40.A16.3A41.2A.A11.3A248.A$668.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.
3A2.A.A6.3A11.3A11.2A12.A10.A865.3A4.2A6.A69.3A37.A.A7.A8.A2.A21.A19.
3A12.A.2A247.2A$662.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.2A27.
A.A7.A820.3A41.2A.A11.3A68.2A47.3A10.A20.3A19.2A13.3A246.A.A$661.3A6.
A4.A.2A5.A5.3A2.A.A6.3A11.3A11.2A48.A.A820.A2.A21.A19.3A12.A.2A79.3A
33.2A.A10.A19.2A.A34.2A383.A$661.A.2A5.A5.3A2.A.A6.3A11.3A11.2A888.A
20.3A19.2A13.3A38.A39.A2.A33.3A8.A.A20.3A420.2A$662.3A2.A.A6.3A11.3A
11.2A902.A19.2A.A34.2A38.3A41.A34.2A26.A4.3A419.A.A$662.3A11.3A11.2A
88.A824.A.A20.3A75.A.2A36.A3.A61.3A4.2A6.A140.A$655.A6.3A11.2A101.3A
841.A4.3A76.3A40.A16.3A41.2A.A11.3A139.2A$654.3A5.2A114.2A.A840.3A4.
2A6.A69.3A37.A.A7.A8.A2.A21.A19.3A12.A.2A79.3A55.A.A$654.A.2A120.3A
840.2A.A11.3A68.2A47.3A10.A20.3A19.2A13.3A38.A39.A2.A191.A$655.3A121.
2A820.A19.3A12.A.2A79.3A33.2A.A10.A19.2A.A34.2A38.3A41.A191.2A$655.2A
943.3A19.2A13.3A38.A39.A2.A33.3A8.A.A20.3A75.A.2A36.A3.A190.A.A$1599.
2A.A34.2A38.3A41.A34.2A26.A4.3A76.3A40.A326.A$1599.3A75.A.2A36.A3.A
61.3A4.2A6.A69.3A37.A.A7.A319.2A$666.3A930.3A76.3A40.A16.3A41.2A.A11.
3A68.2A47.3A317.A.A$666.A2.A4.A5.3A917.2A6.A69.3A37.A.A7.A8.A2.A21.A
19.3A12.A.2A79.3A33.2A.A45.A$657.A8.A6.3A4.A2.A4.A5.3A910.3A68.2A47.
3A10.A20.3A19.2A13.3A38.A39.A2.A33.3A46.2A$656.3A7.A5.2A.A4.A6.3A4.A
2.A4.A5.3A896.A.2A79.3A33.2A.A10.A19.2A.A34.2A38.3A41.A34.2A45.A.A$
656.A.2A7.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A883.3A38.A39.A2.A33.3A
8.A.A20.3A75.A.2A36.A3.A217.A$657.3A12.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A
2.A4.A5.3A869.2A38.3A41.A34.2A26.A4.3A76.3A40.A16.3A198.2A$657.2A13.
3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A895.A.2A36.A3.A61.3A4.2A
6.A69.3A37.A.A7.A8.A2.A197.A.A$673.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A
6.3A4.A2.A4.A5.3A882.3A40.A16.3A41.2A.A11.3A68.2A47.3A10.A333.A$687.
2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A868.3A37.A.A7.A8.A
2.A21.A19.3A12.A.2A79.3A33.2A.A10.A333.2A$701.2A11.3A11.3A6.A.A2.3A5.
A5.2A.A4.A6.3A4.A2.A4.A862.2A47.3A10.A20.3A19.2A13.3A38.A39.A2.A33.3A
8.A.A333.A.A$715.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A9.A863.3A33.2A.
A10.A19.2A.A34.2A38.3A41.A34.2A26.A45.A$729.2A11.3A11.3A6.A.A2.3A5.A
5.2A.A8.3A821.A39.A2.A33.3A8.A.A20.3A75.A.2A36.A3.A61.3A44.2A$743.2A
11.3A11.3A6.A.A2.3A9.A.2A819.3A41.A34.2A26.A4.3A76.3A40.A16.3A41.2A.A
43.A.A$757.2A11.3A11.3A10.3A819.A.2A36.A3.A61.3A4.2A6.A69.3A37.A.A7.A
8.A2.A21.A19.3A180.A$771.2A11.3A10.3A820.3A40.A16.3A41.2A.A11.3A68.2A
47.3A10.A20.3A19.2A180.2A$785.2A10.3A820.3A37.A.A7.A8.A2.A21.A19.3A
12.A.2A79.3A33.2A.A10.A19.2A.A200.A.A$797.2A821.2A47.3A10.A20.3A19.2A
13.3A38.A39.A2.A33.3A8.A.A20.3A337.A$1632.3A33.2A.A10.A19.2A.A34.2A
38.3A41.A34.2A26.A4.3A337.2A$1631.A2.A33.3A8.A.A20.3A75.A.2A36.A3.A
61.3A4.2A6.A329.A.A$1634.A34.2A26.A4.3A76.3A40.A16.3A41.2A.A11.3A56.A
$782.3A845.A3.A61.3A4.2A6.A69.3A37.A.A7.A8.A2.A21.A19.3A12.A.2A55.2A$
768.3A5.A4.A2.A849.A16.3A41.2A.A11.3A68.2A47.3A10.A20.3A19.2A13.3A54.
A.A$754.3A5.A4.A2.A4.3A6.A5.3A838.A.A7.A8.A2.A21.A19.3A12.A.2A79.3A
33.2A.A10.A19.2A.A34.2A191.A$740.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.A2.A
846.3A10.A20.3A19.2A13.3A38.A39.A2.A33.3A8.A.A20.3A228.2A$726.3A5.A4.
A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.A848.2A.A10.A19.2A.A34.2A38.3A41.A34.
2A26.A4.3A227.A.A$712.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.A3.A
4.3A837.3A8.A.A20.3A75.A.2A36.A3.A61.3A4.2A6.A356.A$698.3A5.A4.A2.A4.
3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.A3.A3.A2.A838.2A26.A4.3A76.3A40.A
16.3A41.2A.A11.3A355.2A$684.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A
11.3A11.2A12.A10.A865.3A4.2A6.A69.3A37.A.A7.A8.A2.A21.A19.3A12.A.2A
79.3A271.A.A$678.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.2A27.A.A
7.A864.2A.A11.3A68.2A47.3A10.A20.3A19.2A13.3A38.A39.A2.A$677.3A6.A4.A
.2A5.A5.3A2.A.A6.3A11.3A11.2A48.A.A845.A19.3A12.A.2A79.3A33.2A.A10.A
19.2A.A34.2A38.3A41.A$677.A.2A5.A5.3A2.A.A6.3A11.3A11.2A909.3A19.2A
13.3A38.A39.A2.A33.3A8.A.A20.3A75.A.2A40.A$678.3A2.A.A6.3A11.3A11.2A
922.2A.A34.2A38.3A41.A34.2A26.A4.3A76.3A175.A$678.3A11.3A11.2A88.A
847.3A75.A.2A36.A3.A61.3A4.2A6.A69.3A38.A.A6.A127.2A$671.A6.3A11.2A
101.3A841.A4.3A76.3A40.A16.3A41.2A.A11.3A68.2A39.A.2A4.3A125.A.A$670.
3A5.2A114.2A.A840.3A4.2A6.A69.3A37.A.A7.A8.A2.A21.A19.3A12.A.2A79.3A
28.A4.2A.A261.A$670.A.2A120.3A840.2A.A11.3A68.2A47.3A10.A20.3A19.2A
13.3A38.A39.A2.A26.3A4.3A262.2A$671.3A121.2A840.3A12.A.2A79.3A33.2A.A
10.A19.2A.A34.2A38.3A41.A34.2A261.A.A$671.2A965.2A13.3A38.A39.A2.A33.
3A8.A.A20.3A75.A.2A36.A3.A$1653.2A38.3A41.A34.2A26.A4.3A76.3A40.A16.
3A$1693.A.2A36.A3.A61.3A4.2A6.A69.3A37.A.A7.A8.A2.A$682.3A1009.3A40.A
16.3A41.2A.A11.3A68.2A47.3A10.A141.A$682.A2.A4.A5.3A995.3A37.A.A7.A8.
A2.A21.A19.3A12.A.2A79.3A33.2A.A10.A141.2A$673.A8.A6.3A4.A2.A4.A5.3A
981.2A47.3A10.A20.3A19.2A13.3A38.A39.A2.A33.3A8.A.A141.A.A$672.3A7.A
5.2A.A4.A6.3A4.A2.A4.A5.3A979.3A33.2A.A10.A19.2A.A34.2A38.3A41.A34.2A
26.A261.A$672.A.2A7.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A924.A39.A2.A
33.3A8.A.A20.3A75.A.2A36.A3.A61.3A260.2A$673.3A12.3A6.A.A2.3A5.A5.2A.
A4.A6.3A4.A2.A4.A5.3A909.3A41.A34.2A26.A4.3A76.3A40.A16.3A41.2A.A259.
A.A$673.2A13.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A895.A.2A36.
A3.A61.3A4.2A6.A69.3A37.A.A7.A8.A2.A21.A19.3A$689.2A11.3A11.3A6.A.A2.
3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A882.3A40.A16.3A41.2A.A11.3A68.2A47.3A
10.A20.3A19.2A$703.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A
868.3A37.A.A7.A8.A2.A21.A19.3A12.A.2A79.3A33.2A.A10.A19.2A.A$717.2A
11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A862.2A47.3A10.A20.3A19.2A
13.3A38.A39.A2.A33.3A8.A.A20.3A145.A$731.2A11.3A11.3A6.A.A2.3A5.A5.2A
.A4.A6.3A9.A863.3A33.2A.A10.A19.2A.A34.2A38.3A41.A34.2A26.A4.3A145.2A
$745.2A11.3A11.3A6.A.A2.3A5.A5.2A.A8.3A821.A39.A2.A33.3A8.A.A20.3A75.
A.2A36.A3.A61.3A4.2A6.A137.A.A$759.2A11.3A11.3A6.A.A2.3A9.A.2A819.3A
41.A34.2A26.A4.3A76.3A40.A16.3A41.2A.A11.3A272.A$773.2A11.3A11.3A10.
3A819.A.2A36.A3.A61.3A4.2A6.A69.3A37.A.A7.A8.A2.A21.A19.3A12.A.2A271.
2A$787.2A11.3A10.3A820.3A40.A16.3A41.2A.A11.3A68.2A47.3A10.A20.3A19.
2A13.3A270.A.A$801.2A10.3A820.3A37.A.A7.A8.A2.A21.A19.3A12.A.2A79.3A
33.2A.A10.A19.2A.A34.2A$813.2A821.2A47.3A10.A20.3A19.2A13.3A38.A39.A
2.A33.3A8.A.A20.3A$1684.2A.A10.A19.2A.A34.2A38.3A41.A34.2A26.A4.3A$
1684.3A8.A.A20.3A75.A.2A36.A3.A61.3A4.2A6.A164.A$1685.2A26.A4.3A76.3A
40.A16.3A41.2A.A11.3A163.2A$798.3A911.3A4.2A6.A69.3A37.A.A7.A8.A2.A
21.A19.3A12.A.2A161.A.A$784.3A5.A4.A2.A866.3A41.2A.A11.3A68.2A47.3A
10.A20.3A19.2A13.3A38.A258.A$770.3A5.A4.A2.A4.3A6.A5.3A857.A2.A21.A
19.3A12.A.2A79.3A33.2A.A10.A19.2A.A34.2A38.3A257.2A$756.3A5.A4.A2.A4.
3A6.A4.A.2A5.A5.A2.A859.A20.3A19.2A13.3A38.A39.A2.A33.3A8.A.A20.3A75.
A.2A255.A.A$742.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.A862.A19.2A.A
34.2A38.3A41.A34.2A26.A4.3A76.3A$728.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A
2.A.A6.3A11.A3.A4.3A848.A.A20.3A75.A.2A36.A3.A61.3A4.2A6.A69.3A$714.
3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.A3.A3.A2.A866.A4.3A
76.3A40.A16.3A41.2A.A11.3A68.2A$700.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.
A.A6.3A11.3A11.2A12.A10.A865.3A4.2A6.A69.3A37.A.A7.A8.A2.A21.A19.3A
12.A.2A79.3A106.A$694.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.2A
27.A.A7.A864.2A.A11.3A68.2A47.3A10.A20.3A19.2A13.3A38.A39.A2.A106.2A$
693.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.2A48.A.A845.A19.3A12.A.2A79.3A
33.2A.A10.A19.2A.A34.2A38.3A41.A105.A.A$693.A.2A5.A5.3A2.A.A6.3A11.3A
11.2A909.3A19.2A13.3A38.A39.A2.A33.3A8.A.A20.3A75.A.2A36.A3.A241.A$
694.3A2.A.A6.3A11.3A11.2A922.2A.A34.2A38.3A41.A34.2A26.A4.3A76.3A40.A
16.3A222.2A$694.3A11.3A11.2A88.A847.3A75.A.2A36.A3.A61.3A4.2A6.A69.3A
37.A.A7.A8.A2.A221.A.A$687.A6.3A11.2A101.3A846.3A76.3A40.A16.3A41.2A.
A11.3A68.2A47.3A10.A357.A$686.3A5.2A114.2A.A847.2A6.A69.3A37.A.A7.A8.
A2.A21.A19.3A12.A.2A79.3A33.2A.A10.A357.2A$686.A.2A120.3A855.3A68.2A
47.3A10.A20.3A19.2A13.3A38.A39.A2.A33.3A8.A.A357.A.A$687.3A121.2A855.
A.2A79.3A33.2A.A10.A19.2A.A34.2A38.3A41.A34.2A96.A$687.2A980.3A38.A
39.A2.A33.3A8.A.A20.3A75.A.2A36.A3.A132.2A$1669.2A38.3A41.A34.2A26.A
4.3A76.3A40.A16.3A112.A.A$1709.A.2A36.A3.A61.3A4.2A6.A69.3A37.A.A7.A
8.A2.A21.A226.A$698.3A1009.3A40.A16.3A41.2A.A11.3A68.2A47.3A10.A20.3A
225.2A$698.A2.A4.A5.3A995.3A37.A.A7.A8.A2.A21.A19.3A12.A.2A79.3A33.2A
.A10.A19.2A.A224.A.A$689.A8.A6.3A4.A2.A4.A5.3A981.2A47.3A10.A20.3A19.
2A13.3A38.A39.A2.A33.3A8.A.A20.3A361.A$688.3A7.A5.2A.A4.A6.3A4.A2.A4.
A5.3A979.3A33.2A.A10.A19.2A.A34.2A38.3A41.A34.2A26.A4.3A361.2A$688.A.
2A7.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A924.A39.A2.A33.3A8.A.A20.3A
75.A.2A36.A3.A61.3A4.2A6.A353.A.A$689.3A12.3A6.A.A2.3A5.A5.2A.A4.A6.
3A4.A2.A4.A5.3A909.3A41.A34.2A26.A4.3A76.3A40.A16.3A41.2A.A11.3A80.A$
689.2A13.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A895.A.2A36.A3.A
61.3A4.2A6.A69.3A37.A.A7.A8.A2.A21.A19.3A12.A.2A79.2A$705.2A11.3A11.
3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A882.3A40.A16.3A41.2A.A11.3A
68.2A47.3A10.A20.3A19.2A13.3A78.A.A$719.2A11.3A11.3A6.A.A2.3A5.A5.2A.
A4.A6.3A4.A2.A4.A5.3A868.3A37.A.A7.A8.A2.A21.A19.3A12.A.2A79.3A33.2A.
A10.A19.2A.A34.2A215.A$733.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.
A4.A862.2A47.3A10.A20.3A19.2A13.3A38.A39.A2.A33.3A8.A.A20.3A252.2A$
747.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A9.A863.3A33.2A.A10.A19.2A.A
34.2A38.3A41.A34.2A26.A4.3A251.A.A$761.2A11.3A11.3A6.A.A2.3A5.A5.2A.A
8.3A861.A2.A33.3A8.A.A20.3A75.A.2A36.A3.A61.3A4.2A6.A380.A$775.2A11.
3A11.3A6.A.A2.3A9.A.2A863.A34.2A26.A4.3A76.3A40.A16.3A41.2A.A11.3A
379.2A$789.2A11.3A11.3A10.3A859.A3.A61.3A4.2A6.A69.3A37.A.A7.A8.A2.A
21.A19.3A12.A.2A377.A.A$803.2A11.3A10.3A863.A16.3A41.2A.A11.3A68.2A
47.3A10.A20.3A19.2A13.3A105.A$817.2A10.3A860.A.A7.A8.A2.A21.A19.3A12.
A.2A79.3A33.2A.A10.A19.2A.A34.2A106.2A$829.2A870.3A10.A20.3A19.2A13.
3A38.A39.A2.A33.3A8.A.A20.3A142.A.A$1700.2A.A10.A19.2A.A34.2A38.3A41.
A34.2A26.A4.3A278.A$1700.3A8.A.A20.3A75.A.2A36.A3.A61.3A4.2A6.A271.2A
$1701.2A26.A4.3A76.3A40.A16.3A41.2A.A11.3A269.A.A$814.3A911.3A4.2A6.A
69.3A37.A.A7.A8.A2.A21.A19.3A12.A.2A79.3A322.A$800.3A5.A4.A2.A910.2A.
A11.3A68.2A47.3A10.A20.3A19.2A13.3A38.A39.A2.A322.2A$786.3A5.A4.A2.A
4.3A6.A5.3A882.A19.3A12.A.2A79.3A33.2A.A10.A19.2A.A34.2A38.3A41.A321.
A.A$772.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.A2.A880.3A19.2A13.3A38.A39.A2.A
33.3A8.A.A20.3A75.A.2A36.A3.A49.A$758.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A
2.A.A6.A882.2A.A34.2A38.3A41.A34.2A26.A4.3A76.3A40.A49.2A$744.3A5.A4.
A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.A3.A4.3A871.3A75.A.2A36.A3.A61.3A
4.2A6.A69.3A37.A.A7.A41.A.A$730.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A
6.3A11.3A11.A3.A3.A2.A866.A4.3A76.3A40.A16.3A41.2A.A11.3A68.2A47.3A
176.A$716.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.2A12.A10.A
865.3A4.2A6.A69.3A37.A.A7.A8.A2.A21.A19.3A12.A.2A79.3A33.2A.A176.2A$
710.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.2A27.A.A7.A864.2A.A
11.3A68.2A47.3A10.A20.3A19.2A13.3A38.A39.A2.A33.3A176.A.A$709.3A6.A4.
A.2A5.A5.3A2.A.A6.3A11.3A11.2A48.A.A865.3A12.A.2A79.3A33.2A.A10.A19.
2A.A34.2A38.3A41.A34.2A312.A$709.A.2A5.A5.3A2.A.A6.3A11.3A11.2A931.2A
13.3A38.A39.A2.A33.3A8.A.A20.3A75.A.2A36.A3.A348.2A$710.3A2.A.A6.3A
11.3A11.2A960.2A38.3A41.A34.2A26.A4.3A76.3A40.A16.3A328.A.A$710.3A11.
3A11.2A88.A925.A.2A36.A3.A61.3A4.2A6.A69.3A37.A.A7.A8.A2.A56.A$703.A
6.3A11.2A101.3A925.3A40.A16.3A41.2A.A11.3A68.2A47.3A10.A56.2A$702.3A
5.2A114.2A.A925.3A37.A.A7.A8.A2.A21.A19.3A12.A.2A79.3A33.2A.A10.A55.A
.A$702.A.2A120.3A926.2A47.3A10.A20.3A19.2A13.3A38.A39.A2.A33.3A8.A.A
192.A$703.3A121.2A938.3A33.2A.A10.A19.2A.A34.2A38.3A41.A34.2A26.A176.
2A$703.2A1021.A39.A2.A33.3A8.A.A20.3A75.A.2A36.A3.A61.3A174.A.A$1725.
3A41.A34.2A26.A4.3A76.3A40.A16.3A41.2A.A310.A$1725.A.2A36.A3.A61.3A4.
2A6.A69.3A37.A.A7.A8.A2.A21.A19.3A311.2A$714.3A1009.3A40.A16.3A41.2A.
A11.3A68.2A47.3A10.A20.3A19.2A310.A.A$714.A2.A4.A5.3A995.3A37.A.A7.A
8.A2.A21.A19.3A12.A.2A79.3A33.2A.A10.A19.2A.A59.A$705.A8.A6.3A4.A2.A
4.A5.3A981.2A47.3A10.A20.3A19.2A13.3A38.A39.A2.A33.3A8.A.A20.3A60.2A$
704.3A7.A5.2A.A4.A6.3A4.A2.A4.A5.3A979.3A33.2A.A10.A19.2A.A34.2A38.3A
41.A34.2A26.A4.3A59.A.A$704.A.2A7.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.
3A924.A39.A2.A33.3A8.A.A20.3A75.A.2A36.A3.A61.3A4.2A6.A188.A$705.3A
12.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A909.3A41.A34.2A26.A4.3A76.
3A40.A16.3A41.2A.A11.3A187.2A$705.2A13.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.
3A4.A2.A4.A5.3A895.A.2A36.A3.A61.3A4.2A6.A69.3A37.A.A7.A8.A2.A21.A19.
3A12.A.2A185.A.A$721.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.
3A882.3A40.A16.3A41.2A.A11.3A68.2A47.3A10.A20.3A19.2A13.3A321.A$735.
2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A868.3A37.A.A7.A8.A
2.A21.A19.3A12.A.2A79.3A33.2A.A10.A19.2A.A34.2A322.2A$749.2A11.3A11.
3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A862.2A47.3A10.A20.3A19.2A13.3A38.
A39.A2.A33.3A8.A.A20.3A358.A.A$763.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A
6.3A9.A899.2A.A10.A19.2A.A34.2A38.3A41.A34.2A26.A4.3A$777.2A11.3A11.
3A6.A.A2.3A5.A5.2A.A8.3A898.3A8.A.A20.3A75.A.2A36.A3.A61.3A4.2A6.A$
791.2A11.3A11.3A6.A.A2.3A9.A.2A898.2A26.A4.3A76.3A40.A16.3A41.2A.A11.
3A$805.2A11.3A11.3A10.3A925.3A4.2A6.A69.3A37.A.A7.A8.A2.A21.A19.3A12.
A.2A212.A$819.2A11.3A10.3A880.3A41.2A.A11.3A68.2A47.3A10.A20.3A19.2A
13.3A38.A173.2A$833.2A10.3A879.A2.A21.A19.3A12.A.2A79.3A33.2A.A10.A
19.2A.A34.2A38.3A171.A.A$845.2A883.A20.3A19.2A13.3A38.A39.A2.A33.3A8.
A.A20.3A75.A.2A306.A$1730.A19.2A.A34.2A38.3A41.A34.2A26.A4.3A76.3A
306.2A$1727.A.A20.3A75.A.2A36.A3.A61.3A4.2A6.A69.3A34.A270.A.A$1745.A
4.3A76.3A40.A16.3A41.2A.A11.3A68.2A35.2A$830.3A911.3A4.2A6.A69.3A37.A
.A7.A8.A2.A21.A19.3A12.A.2A79.3A21.A.A$816.3A5.A4.A2.A910.2A.A11.3A
68.2A47.3A10.A20.3A19.2A13.3A38.A39.A2.A$802.3A5.A4.A2.A4.3A6.A5.3A
882.A19.3A12.A.2A79.3A33.2A.A10.A19.2A.A34.2A38.3A41.A156.A$788.3A5.A
4.A2.A4.3A6.A4.A.2A5.A5.A2.A880.3A19.2A13.3A38.A39.A2.A33.3A8.A.A20.
3A75.A.2A36.A3.A156.2A$774.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.A
882.2A.A34.2A38.3A41.A34.2A26.A4.3A76.3A40.A16.3A136.A.A$760.3A5.A4.A
2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.A3.A4.3A871.3A75.A.2A36.A3.A61.3A
4.2A6.A69.3A37.A.A7.A8.A2.A272.A$746.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A
2.A.A6.3A11.3A11.A3.A3.A2.A871.3A76.3A40.A16.3A41.2A.A11.3A68.2A47.3A
10.A272.2A$732.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.2A12.A
10.A872.2A6.A69.3A37.A.A7.A8.A2.A21.A19.3A12.A.2A79.3A33.2A.A10.A271.
A.A$726.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.2A27.A.A7.A879.3A
68.2A47.3A10.A20.3A19.2A13.3A38.A39.A2.A33.3A8.A.A$725.3A6.A4.A.2A5.A
5.3A2.A.A6.3A11.3A11.2A48.A.A880.A.2A79.3A33.2A.A10.A19.2A.A34.2A38.
3A41.A34.2A$725.A.2A5.A5.3A2.A.A6.3A11.3A11.2A946.3A38.A39.A2.A33.3A
8.A.A20.3A75.A.2A36.A3.A$726.3A2.A.A6.3A11.3A11.2A960.2A38.3A41.A34.
2A26.A4.3A76.3A40.A16.3A163.A$726.3A11.3A11.2A88.A925.A.2A36.A3.A61.
3A4.2A6.A69.3A37.A.A7.A8.A2.A21.A141.2A$719.A6.3A11.2A101.3A925.3A40.
A16.3A41.2A.A11.3A68.2A47.3A10.A20.3A139.A.A$718.3A5.2A114.2A.A925.3A
37.A.A7.A8.A2.A21.A19.3A12.A.2A79.3A33.2A.A10.A19.2A.A275.A$718.A.2A
120.3A926.2A47.3A10.A20.3A19.2A13.3A38.A39.A2.A33.3A8.A.A20.3A276.2A$
719.3A121.2A938.3A33.2A.A10.A19.2A.A34.2A38.3A41.A34.2A26.A4.3A275.A.
A$719.2A1021.A39.A2.A33.3A8.A.A20.3A75.A.2A36.A3.A61.3A4.2A6.A404.A$
1741.3A41.A34.2A26.A4.3A76.3A40.A16.3A41.2A.A11.3A403.2A$1741.A.2A36.
A3.A61.3A4.2A6.A69.3A37.A.A7.A8.A2.A21.A19.3A12.A.2A401.A.A$730.3A
1009.3A40.A16.3A41.2A.A11.3A68.2A47.3A10.A20.3A19.2A13.3A129.A$730.A
2.A4.A5.3A995.3A37.A.A7.A8.A2.A21.A19.3A12.A.2A79.3A33.2A.A10.A19.2A.
A34.2A130.2A$721.A8.A6.3A4.A2.A4.A5.3A981.2A47.3A10.A20.3A19.2A13.3A
38.A39.A2.A33.3A8.A.A20.3A166.A.A$720.3A7.A5.2A.A4.A6.3A4.A2.A4.A5.3A
979.3A33.2A.A10.A19.2A.A34.2A38.3A41.A34.2A26.A4.3A302.A$720.A.2A7.A.
A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A964.A2.A33.3A8.A.A20.3A75.A.2A36.A
3.A61.3A4.2A6.A295.2A$721.3A12.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.
3A953.A34.2A26.A4.3A76.3A40.A16.3A41.2A.A11.3A293.A.A$721.2A13.3A11.
3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A935.A3.A61.3A4.2A6.A69.3A37.A
.A7.A8.A2.A21.A19.3A12.A.2A428.A$737.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.
A6.3A4.A2.A4.A5.3A925.A16.3A41.2A.A11.3A68.2A47.3A10.A20.3A19.2A13.3A
428.2A$751.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A908.A.A
7.A8.A2.A21.A19.3A12.A.2A79.3A33.2A.A10.A19.2A.A34.2A428.A.A$765.2A
11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A911.3A10.A20.3A19.2A13.3A
38.A39.A2.A33.3A8.A.A20.3A193.A$779.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A
6.3A9.A899.2A.A10.A19.2A.A34.2A38.3A41.A34.2A26.A4.3A193.2A$793.2A11.
3A11.3A6.A.A2.3A5.A5.2A.A8.3A898.3A8.A.A20.3A75.A.2A36.A3.A61.3A4.2A
6.A185.A.A$807.2A11.3A11.3A6.A.A2.3A9.A.2A898.2A26.A4.3A76.3A40.A16.
3A41.2A.A11.3A320.A$821.2A11.3A11.3A10.3A925.3A4.2A6.A69.3A37.A.A7.A
8.A2.A21.A19.3A12.A.2A319.2A$835.2A11.3A10.3A924.2A.A11.3A68.2A47.3A
10.A20.3A19.2A13.3A38.A279.A.A$849.2A10.3A904.A19.3A12.A.2A79.3A33.2A
.A10.A19.2A.A34.2A38.3A414.A$861.2A904.3A19.2A13.3A38.A39.A2.A33.3A8.
A.A20.3A75.A.2A413.2A$1766.2A.A34.2A38.3A41.A34.2A26.A4.3A76.3A412.A.
A$1766.3A75.A.2A36.A3.A61.3A4.2A6.A69.3A140.A$1761.A4.3A76.3A40.A16.
3A41.2A.A11.3A68.2A141.2A$846.3A911.3A4.2A6.A69.3A37.A.A7.A8.A2.A21.A
19.3A12.A.2A79.3A127.A.A$832.3A5.A4.A2.A910.2A.A11.3A68.2A47.3A10.A
20.3A19.2A13.3A38.A39.A2.A263.A$818.3A5.A4.A2.A4.3A6.A5.3A902.3A12.A.
2A79.3A33.2A.A10.A19.2A.A34.2A38.3A41.A263.2A$804.3A5.A4.A2.A4.3A6.A
4.A.2A5.A5.A2.A902.2A13.3A38.A39.A2.A33.3A8.A.A20.3A75.A.2A36.A3.A
262.A.A$790.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.A920.2A38.3A41.A34.
2A26.A4.3A76.3A40.A16.3A379.A$776.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.
A6.3A11.A3.A4.3A949.A.2A36.A3.A61.3A4.2A6.A69.3A37.A.A7.A8.A2.A379.2A
$762.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.A3.A3.A2.A950.3A
40.A16.3A41.2A.A11.3A68.2A47.3A10.A378.A.A$748.3A5.A4.A2.A4.3A6.A4.A.
2A5.A5.3A2.A.A6.3A11.3A11.2A12.A10.A950.3A37.A.A7.A8.A2.A21.A19.3A12.
A.2A79.3A33.2A.A10.A106.A$742.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.
3A11.2A27.A.A7.A950.2A47.3A10.A20.3A19.2A13.3A38.A39.A2.A33.3A8.A.A
107.2A$741.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.2A48.A.A963.3A33.2A.A
10.A19.2A.A34.2A38.3A41.A34.2A117.A.A$741.A.2A5.A5.3A2.A.A6.3A11.3A
11.2A987.A39.A2.A33.3A8.A.A20.3A75.A.2A36.A3.A289.A$742.3A2.A.A6.3A
11.3A11.2A1000.3A41.A34.2A26.A4.3A76.3A40.A16.3A270.2A$742.3A11.3A11.
2A88.A925.A.2A36.A3.A61.3A4.2A6.A69.3A37.A.A7.A8.A2.A21.A247.A.A$735.
A6.3A11.2A101.3A925.3A40.A16.3A41.2A.A11.3A68.2A47.3A10.A20.3A382.A$
734.3A5.2A114.2A.A925.3A37.A.A7.A8.A2.A21.A19.3A12.A.2A79.3A33.2A.A
10.A19.2A.A382.2A$734.A.2A120.3A926.2A47.3A10.A20.3A19.2A13.3A38.A39.
A2.A33.3A8.A.A20.3A382.A.A$735.3A121.2A938.3A33.2A.A10.A19.2A.A34.2A
38.3A41.A34.2A26.A4.3A110.A$735.2A1021.A39.A2.A33.3A8.A.A20.3A75.A.2A
36.A3.A61.3A4.2A6.A103.2A$1757.3A41.A34.2A26.A4.3A76.3A40.A16.3A41.2A
.A11.3A101.A.A$1757.A.2A36.A3.A61.3A4.2A6.A69.3A37.A.A7.A8.A2.A21.A
19.3A12.A.2A236.A$746.3A1009.3A40.A16.3A41.2A.A11.3A68.2A47.3A10.A20.
3A19.2A13.3A236.2A$746.A2.A4.A5.3A995.3A37.A.A7.A8.A2.A21.A19.3A12.A.
2A79.3A33.2A.A10.A19.2A.A34.2A236.A.A$737.A8.A6.3A4.A2.A4.A5.3A981.2A
47.3A10.A20.3A19.2A13.3A38.A39.A2.A33.3A8.A.A20.3A409.A$736.3A7.A5.2A
.A4.A6.3A4.A2.A4.A5.3A1015.2A.A10.A19.2A.A34.2A38.3A41.A34.2A26.A4.3A
409.2A$736.A.2A7.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A1001.3A8.A.A20.
3A75.A.2A36.A3.A61.3A4.2A6.A401.A.A$737.3A12.3A6.A.A2.3A5.A5.2A.A4.A
6.3A4.A2.A4.A5.3A988.2A26.A4.3A76.3A40.A16.3A41.2A.A11.3A128.A$737.2A
13.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A1001.3A4.2A6.A69.3A
37.A.A7.A8.A2.A21.A19.3A12.A.2A127.2A$753.2A11.3A11.3A6.A.A2.3A5.A5.
2A.A4.A6.3A4.A2.A4.A5.3A942.3A41.2A.A11.3A68.2A47.3A10.A20.3A19.2A13.
3A126.A.A$767.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A927.A
2.A21.A19.3A12.A.2A79.3A33.2A.A10.A19.2A.A34.2A263.A$781.2A11.3A11.3A
6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A924.A20.3A19.2A13.3A38.A39.A2.A33.
3A8.A.A20.3A300.2A$795.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A9.A913.A
19.2A.A34.2A38.3A41.A34.2A26.A4.3A299.A.A$809.2A11.3A11.3A6.A.A2.3A5.
A5.2A.A8.3A909.A.A20.3A75.A.2A36.A3.A61.3A4.2A6.A428.A$823.2A11.3A11.
3A6.A.A2.3A9.A.2A926.A4.3A76.3A40.A16.3A41.2A.A11.3A427.2A$837.2A11.
3A11.3A10.3A925.3A4.2A6.A69.3A37.A.A7.A8.A2.A21.A19.3A12.A.2A425.A.A$
851.2A11.3A10.3A924.2A.A11.3A68.2A47.3A10.A20.3A19.2A13.3A38.A$865.2A
10.3A904.A19.3A12.A.2A79.3A33.2A.A10.A19.2A.A34.2A38.3A$877.2A904.3A
19.2A13.3A38.A39.A2.A33.3A8.A.A20.3A75.A.2A$1782.2A.A34.2A38.3A41.A
34.2A26.A4.3A76.3A247.A$1782.3A75.A.2A36.A3.A61.3A4.2A6.A69.3A247.2A$
1782.3A76.3A40.A16.3A41.2A.A11.3A68.2A247.A.A$862.3A918.2A6.A69.3A37.
A.A7.A8.A2.A21.A19.3A12.A.2A79.3A370.A$848.3A5.A4.A2.A925.3A68.2A47.
3A10.A20.3A19.2A13.3A38.A39.A2.A370.2A$834.3A5.A4.A2.A4.3A6.A5.3A917.
A.2A79.3A33.2A.A10.A19.2A.A34.2A38.3A41.A98.A270.A.A$820.3A5.A4.A2.A
4.3A6.A4.A.2A5.A5.A2.A917.3A38.A39.A2.A33.3A8.A.A20.3A75.A.2A36.A3.A
98.2A$806.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.A920.2A38.3A41.A34.2A
26.A4.3A76.3A40.A16.3A78.A.A$792.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A
6.3A11.A3.A4.3A949.A.2A36.A3.A61.3A4.2A6.A69.3A37.A.A7.A8.A2.A$778.3A
5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.A3.A3.A2.A950.3A40.A16.
3A41.2A.A11.3A68.2A47.3A10.A213.A$764.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A
2.A.A6.3A11.3A11.2A12.A10.A950.3A37.A.A7.A8.A2.A21.A19.3A12.A.2A79.3A
33.2A.A10.A213.2A$758.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.2A
27.A.A7.A950.2A47.3A10.A20.3A19.2A13.3A38.A39.A2.A33.3A8.A.A213.A.A$
757.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.2A48.A.A963.3A33.2A.A10.A19.2A
.A34.2A38.3A41.A34.2A360.A$757.A.2A5.A5.3A2.A.A6.3A11.3A11.2A987.A39.
A2.A33.3A8.A.A20.3A75.A.2A36.A3.A396.2A$758.3A2.A.A6.3A11.3A11.2A
1000.3A41.A34.2A26.A4.3A76.3A40.A16.3A376.A.A$758.3A11.3A11.2A88.A
925.A.2A36.A3.A61.3A4.2A6.A69.3A37.A.A7.A8.A2.A21.A$751.A6.3A11.2A
101.3A925.3A40.A16.3A41.2A.A11.3A68.2A47.3A10.A20.3A$750.3A5.2A114.2A
.A925.3A37.A.A7.A8.A2.A21.A19.3A12.A.2A79.3A33.2A.A10.A19.2A.A$750.A.
2A120.3A926.2A47.3A10.A20.3A19.2A13.3A38.A39.A2.A33.3A8.A.A20.3A217.A
$751.3A121.2A938.3A33.2A.A10.A19.2A.A34.2A38.3A41.A34.2A26.A4.3A217.
2A$751.2A1061.A2.A33.3A8.A.A20.3A75.A.2A36.A3.A61.3A4.2A6.A209.A.A$
1817.A34.2A26.A4.3A76.3A40.A16.3A41.2A.A11.3A344.A$1813.A3.A61.3A4.2A
6.A69.3A37.A.A7.A8.A2.A21.A19.3A12.A.2A343.2A$762.3A1052.A16.3A41.2A.
A11.3A68.2A47.3A10.A20.3A19.2A13.3A342.A.A$762.A2.A4.A5.3A1035.A.A7.A
8.A2.A21.A19.3A12.A.2A79.3A33.2A.A10.A19.2A.A34.2A479.A$753.A8.A6.3A
4.A2.A4.A5.3A1030.3A10.A20.3A19.2A13.3A38.A39.A2.A33.3A8.A.A20.3A516.
2A$752.3A7.A5.2A.A4.A6.3A4.A2.A4.A5.3A1015.2A.A10.A19.2A.A34.2A38.3A
41.A34.2A26.A4.3A515.A.A$752.A.2A7.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.
3A1001.3A8.A.A20.3A75.A.2A36.A3.A61.3A4.2A6.A236.A$753.3A12.3A6.A.A2.
3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A988.2A26.A4.3A76.3A40.A16.3A41.2A.A11.
3A235.2A$753.2A13.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A1001.
3A4.2A6.A69.3A37.A.A7.A8.A2.A21.A19.3A12.A.2A233.A.A$769.2A11.3A11.3A
6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A986.2A.A11.3A68.2A47.3A10.A20.
3A19.2A13.3A369.A$783.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A
5.3A952.A19.3A12.A.2A79.3A33.2A.A10.A19.2A.A34.2A370.2A$797.2A11.3A
11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A945.3A19.2A13.3A38.A39.A2.A33.
3A8.A.A20.3A406.A.A$811.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A9.A933.
2A.A34.2A38.3A41.A34.2A26.A4.3A542.A$825.2A11.3A11.3A6.A.A2.3A5.A5.2A
.A8.3A932.3A75.A.2A36.A3.A61.3A4.2A6.A535.2A$839.2A11.3A11.3A6.A.A2.
3A9.A.2A926.A4.3A76.3A40.A16.3A41.2A.A11.3A533.A.A$853.2A11.3A11.3A
10.3A925.3A4.2A6.A69.3A37.A.A7.A8.A2.A21.A19.3A12.A.2A260.A$867.2A11.
3A10.3A924.2A.A11.3A68.2A47.3A10.A20.3A19.2A13.3A38.A221.2A$881.2A10.
3A924.3A12.A.2A79.3A33.2A.A10.A19.2A.A34.2A38.3A219.A.A$893.2A926.2A
13.3A38.A39.A2.A33.3A8.A.A20.3A75.A.2A354.A$1836.2A38.3A41.A34.2A26.A
4.3A76.3A354.2A$1876.A.2A36.A3.A61.3A4.2A6.A69.3A353.A.A$1877.3A40.A
16.3A41.2A.A11.3A68.2A490.A$878.3A996.3A37.A.A7.A8.A2.A21.A19.3A12.A.
2A79.3A477.2A$864.3A5.A4.A2.A996.2A47.3A10.A20.3A19.2A13.3A38.A39.A2.
A476.A.A$850.3A5.A4.A2.A4.3A6.A5.3A1000.3A33.2A.A10.A19.2A.A34.2A38.
3A41.A204.A$836.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.A2.A958.A39.A2.A33.3A8.A
.A20.3A75.A.2A36.A3.A204.2A$822.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A
6.A960.3A41.A34.2A26.A4.3A76.3A40.A16.3A184.A.A$808.3A5.A4.A2.A4.3A6.
A4.A.2A5.A5.3A2.A.A6.3A11.A3.A4.3A949.A.2A36.A3.A61.3A4.2A6.A69.3A37.
A.A7.A8.A2.A320.A$794.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A
11.A3.A3.A2.A950.3A40.A16.3A41.2A.A11.3A68.2A47.3A10.A320.2A$780.3A5.
A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.2A12.A10.A950.3A37.A.A7.A
8.A2.A21.A19.3A12.A.2A79.3A33.2A.A10.A319.A.A$774.A4.A2.A4.3A6.A4.A.
2A5.A5.3A2.A.A6.3A11.3A11.2A27.A.A7.A950.2A47.3A10.A20.3A19.2A13.3A
38.A39.A2.A33.3A8.A.A456.A$773.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.2A
48.A.A963.3A33.2A.A10.A19.2A.A34.2A38.3A41.A34.2A467.2A$773.A.2A5.A5.
3A2.A.A6.3A11.3A11.2A987.A39.A2.A33.3A8.A.A20.3A75.A.2A36.A3.A502.A.A
$774.3A2.A.A6.3A11.3A11.2A1000.3A41.A34.2A26.A4.3A76.3A40.A16.3A211.A
$774.3A11.3A11.2A88.A925.A.2A36.A3.A61.3A4.2A6.A69.3A37.A.A7.A8.A2.A
21.A189.2A$767.A6.3A11.2A101.3A925.3A40.A16.3A41.2A.A11.3A68.2A47.3A
10.A20.3A187.A.A$766.3A5.2A114.2A.A925.3A37.A.A7.A8.A2.A21.A19.3A12.A
.2A79.3A33.2A.A10.A19.2A.A323.A$766.A.2A120.3A926.2A47.3A10.A20.3A19.
2A13.3A38.A39.A2.A33.3A8.A.A20.3A324.2A$767.3A121.2A974.2A.A10.A19.2A
.A34.2A38.3A41.A34.2A26.A4.3A323.A.A$767.2A1098.3A8.A.A20.3A75.A.2A
36.A3.A61.3A4.2A6.A452.A$1868.2A26.A4.3A76.3A40.A16.3A41.2A.A11.3A
451.2A$1895.3A4.2A6.A69.3A37.A.A7.A8.A2.A21.A19.3A12.A.2A449.A.A$778.
3A1069.3A41.2A.A11.3A68.2A47.3A10.A20.3A19.2A13.3A177.A$778.A2.A4.A5.
3A1054.A2.A21.A19.3A12.A.2A79.3A33.2A.A10.A19.2A.A34.2A178.2A$769.A8.
A6.3A4.A2.A4.A5.3A1043.A20.3A19.2A13.3A38.A39.A2.A33.3A8.A.A20.3A214.
A.A$768.3A7.A5.2A.A4.A6.3A4.A2.A4.A5.3A1029.A19.2A.A34.2A38.3A41.A34.
2A26.A4.3A350.A$768.A.2A7.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A1012.A.
A20.3A75.A.2A36.A3.A61.3A4.2A6.A343.2A$769.3A12.3A6.A.A2.3A5.A5.2A.A
4.A6.3A4.A2.A4.A5.3A1016.A4.3A76.3A40.A16.3A41.2A.A11.3A341.A.A$769.
2A13.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A1001.3A4.2A6.A69.3A
37.A.A7.A8.A2.A21.A19.3A12.A.2A476.A$785.2A11.3A11.3A6.A.A2.3A5.A5.2A
.A4.A6.3A4.A2.A4.A5.3A986.2A.A11.3A68.2A47.3A10.A20.3A19.2A13.3A476.
2A$799.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A952.A19.3A
12.A.2A79.3A33.2A.A10.A19.2A.A34.2A476.A.A$813.2A11.3A11.3A6.A.A2.3A
5.A5.2A.A4.A6.3A4.A2.A4.A945.3A19.2A13.3A38.A39.A2.A33.3A8.A.A20.3A
241.A$827.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A9.A933.2A.A34.2A38.3A
41.A34.2A26.A4.3A241.2A$841.2A11.3A11.3A6.A.A2.3A5.A5.2A.A8.3A932.3A
75.A.2A36.A3.A61.3A4.2A6.A233.A.A$855.2A11.3A11.3A6.A.A2.3A9.A.2A931.
3A76.3A40.A16.3A41.2A.A11.3A368.A$869.2A11.3A11.3A10.3A932.2A6.A69.3A
37.A.A7.A8.A2.A21.A19.3A12.A.2A367.2A$883.2A11.3A10.3A939.3A68.2A47.
3A10.A20.3A19.2A13.3A38.A327.A.A$897.2A10.3A939.A.2A79.3A33.2A.A10.A
19.2A.A34.2A38.3A462.A$909.2A941.3A38.A39.A2.A33.3A8.A.A20.3A75.A.2A
461.2A$1852.2A38.3A41.A34.2A26.A4.3A76.3A460.A.A$1892.A.2A36.A3.A61.
3A4.2A6.A69.3A$1893.3A40.A16.3A41.2A.A11.3A68.2A$894.3A996.3A37.A.A7.
A8.A2.A21.A19.3A12.A.2A79.3A$880.3A5.A4.A2.A996.2A47.3A10.A20.3A19.2A
13.3A38.A39.A2.A311.A$866.3A5.A4.A2.A4.3A6.A5.3A1000.3A33.2A.A10.A19.
2A.A34.2A38.3A41.A311.2A$852.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.A2.A958.A
39.A2.A33.3A8.A.A20.3A75.A.2A36.A3.A310.A.A$838.3A5.A4.A2.A4.3A6.A4.A
.2A5.A5.3A2.A.A6.A960.3A41.A34.2A26.A4.3A76.3A40.A16.3A427.A$824.3A5.
A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.A3.A4.3A949.A.2A36.A3.A61.3A4.
2A6.A69.3A37.A.A7.A8.A2.A427.2A$810.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.
A.A6.3A11.3A11.A3.A3.A2.A950.3A40.A16.3A41.2A.A11.3A68.2A47.3A10.A
155.A270.A.A$796.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.2A
12.A10.A950.3A37.A.A7.A8.A2.A21.A19.3A12.A.2A79.3A33.2A.A10.A155.2A$
790.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.2A27.A.A7.A950.2A47.
3A10.A20.3A19.2A13.3A38.A39.A2.A33.3A8.A.A155.A.A$789.3A6.A4.A.2A5.A
5.3A2.A.A6.3A11.3A11.2A48.A.A963.3A33.2A.A10.A19.2A.A34.2A38.3A41.A
34.2A$789.A.2A5.A5.3A2.A.A6.3A11.3A11.2A1027.A2.A33.3A8.A.A20.3A75.A.
2A36.A3.A337.A$790.3A2.A.A6.3A11.3A11.2A1044.A34.2A26.A4.3A76.3A40.A
16.3A318.2A$790.3A11.3A11.2A88.A965.A3.A61.3A4.2A6.A69.3A37.A.A7.A8.A
2.A21.A295.A.A$783.A6.3A11.2A101.3A968.A16.3A41.2A.A11.3A68.2A47.3A
10.A20.3A430.A$782.3A5.2A114.2A.A965.A.A7.A8.A2.A21.A19.3A12.A.2A79.
3A33.2A.A10.A19.2A.A430.2A$782.A.2A120.3A975.3A10.A20.3A19.2A13.3A38.
A39.A2.A33.3A8.A.A20.3A430.A.A$783.3A121.2A974.2A.A10.A19.2A.A34.2A
38.3A41.A34.2A26.A4.3A$783.2A1098.3A8.A.A20.3A75.A.2A36.A3.A61.3A4.2A
6.A$1884.2A26.A4.3A76.3A40.A16.3A41.2A.A11.3A$1911.3A4.2A6.A69.3A37.A
.A7.A8.A2.A21.A19.3A12.A.2A284.A$794.3A1113.2A.A11.3A68.2A47.3A10.A
20.3A19.2A13.3A284.2A$794.A2.A4.A5.3A1079.A19.3A12.A.2A79.3A33.2A.A
10.A19.2A.A34.2A284.A.A$785.A8.A6.3A4.A2.A4.A5.3A1064.3A19.2A13.3A38.
A39.A2.A33.3A8.A.A20.3A457.A$784.3A7.A5.2A.A4.A6.3A4.A2.A4.A5.3A1049.
2A.A34.2A38.3A41.A34.2A26.A4.3A457.2A$784.A.2A7.A.A2.3A5.A5.2A.A4.A6.
3A4.A2.A4.A5.3A1035.3A75.A.2A36.A3.A61.3A4.2A6.A449.A.A$785.3A12.3A6.
A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A1016.A4.3A76.3A40.A16.3A41.2A.A
11.3A584.A$785.2A13.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A
1001.3A4.2A6.A69.3A37.A.A7.A8.A2.A21.A19.3A12.A.2A583.2A$801.2A11.3A
11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A986.2A.A11.3A68.2A47.3A10.
A20.3A19.2A13.3A582.A.A$815.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A
2.A4.A5.3A972.3A12.A.2A79.3A33.2A.A10.A19.2A.A34.2A311.A$829.2A11.3A
11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A967.2A13.3A38.A39.A2.A33.3A8.A
.A20.3A348.2A$843.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A9.A971.2A38.3A
41.A34.2A26.A4.3A347.A.A$857.2A11.3A11.3A6.A.A2.3A5.A5.2A.A8.3A1010.A
.2A36.A3.A61.3A4.2A6.A476.A$871.2A11.3A11.3A6.A.A2.3A9.A.2A1010.3A40.
A16.3A41.2A.A11.3A475.2A$885.2A11.3A11.3A10.3A1010.3A37.A.A7.A8.A2.A
21.A19.3A12.A.2A473.A.A$899.2A11.3A10.3A1010.2A47.3A10.A20.3A19.2A13.
3A38.A570.A$913.2A10.3A1022.3A33.2A.A10.A19.2A.A34.2A38.3A569.2A$925.
2A982.A39.A2.A33.3A8.A.A20.3A75.A.2A567.A.A$1908.3A41.A34.2A26.A4.3A
76.3A295.A$1908.A.2A36.A3.A61.3A4.2A6.A69.3A295.2A$1909.3A40.A16.3A
41.2A.A11.3A68.2A295.A.A$910.3A996.3A37.A.A7.A8.A2.A21.A19.3A12.A.2A
79.3A418.A$896.3A5.A4.A2.A996.2A47.3A10.A20.3A19.2A13.3A38.A39.A2.A
418.2A$882.3A5.A4.A2.A4.3A6.A5.3A1000.3A33.2A.A10.A19.2A.A34.2A38.3A
41.A417.A.A$868.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.A2.A958.A39.A2.A33.3A8.A
.A20.3A75.A.2A36.A3.A553.A$854.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.
A960.3A41.A34.2A26.A4.3A76.3A40.A16.3A534.2A$840.3A5.A4.A2.A4.3A6.A4.
A.2A5.A5.3A2.A.A6.3A11.A3.A4.3A949.A.2A36.A3.A61.3A4.2A6.A69.3A37.A.A
7.A8.A2.A533.A.A$826.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.
A3.A3.A2.A950.3A40.A16.3A41.2A.A11.3A68.2A47.3A10.A261.A$812.3A5.A4.A
2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.2A12.A10.A950.3A37.A.A7.A8.A
2.A21.A19.3A12.A.2A79.3A33.2A.A10.A261.2A$806.A4.A2.A4.3A6.A4.A.2A5.A
5.3A2.A.A6.3A11.3A11.2A27.A.A7.A950.2A47.3A10.A20.3A19.2A13.3A38.A39.
A2.A33.3A8.A.A261.A.A$805.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.2A48.A.A
999.2A.A10.A19.2A.A34.2A38.3A41.A34.2A408.A$805.A.2A5.A5.3A2.A.A6.3A
11.3A11.2A1064.3A8.A.A20.3A75.A.2A36.A3.A444.2A$806.3A2.A.A6.3A11.3A
11.2A1079.2A26.A4.3A76.3A40.A16.3A424.A.A$806.3A11.3A11.2A88.A1031.3A
4.2A6.A69.3A37.A.A7.A8.A2.A21.A538.A$799.A6.3A11.2A101.3A985.3A41.2A.
A11.3A68.2A47.3A10.A20.3A537.2A$798.3A5.2A114.2A.A984.A2.A21.A19.3A
12.A.2A79.3A33.2A.A10.A19.2A.A536.A.A$798.A.2A120.3A988.A20.3A19.2A
13.3A38.A39.A2.A33.3A8.A.A20.3A265.A$799.3A121.2A988.A19.2A.A34.2A38.
3A41.A34.2A26.A4.3A265.2A$799.2A1109.A.A20.3A75.A.2A36.A3.A61.3A4.2A
6.A257.A.A$1928.A4.3A76.3A40.A16.3A41.2A.A11.3A392.A$1927.3A4.2A6.A
69.3A37.A.A7.A8.A2.A21.A19.3A12.A.2A391.2A$810.3A1113.2A.A11.3A68.2A
47.3A10.A20.3A19.2A13.3A390.A.A$810.A2.A4.A5.3A1079.A19.3A12.A.2A79.
3A33.2A.A10.A19.2A.A34.2A527.A$801.A8.A6.3A4.A2.A4.A5.3A1064.3A19.2A
13.3A38.A39.A2.A33.3A8.A.A20.3A564.2A$800.3A7.A5.2A.A4.A6.3A4.A2.A4.A
5.3A1049.2A.A34.2A38.3A41.A34.2A26.A4.3A563.A.A$800.A.2A7.A.A2.3A5.A
5.2A.A4.A6.3A4.A2.A4.A5.3A1035.3A75.A.2A36.A3.A61.3A4.2A6.A284.A$801.
3A12.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A1021.3A76.3A40.A16.3A41.
2A.A11.3A283.2A$801.2A13.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.
3A1008.2A6.A69.3A37.A.A7.A8.A2.A21.A19.3A12.A.2A281.A.A$817.2A11.3A
11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A1001.3A68.2A47.3A10.A20.3A
19.2A13.3A417.A$831.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.
3A987.A.2A79.3A33.2A.A10.A19.2A.A34.2A418.2A$845.2A11.3A11.3A6.A.A2.
3A5.A5.2A.A4.A6.3A4.A2.A4.A982.3A38.A39.A2.A33.3A8.A.A20.3A454.A.A$
859.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A9.A971.2A38.3A41.A34.2A26.A
4.3A590.A$873.2A11.3A11.3A6.A.A2.3A5.A5.2A.A8.3A1010.A.2A36.A3.A61.3A
4.2A6.A583.2A$887.2A11.3A11.3A6.A.A2.3A9.A.2A1010.3A40.A16.3A41.2A.A
11.3A581.A.A$901.2A11.3A11.3A10.3A1010.3A37.A.A7.A8.A2.A21.A19.3A12.A
.2A308.A$915.2A11.3A10.3A1010.2A47.3A10.A20.3A19.2A13.3A38.A269.2A$
929.2A10.3A1022.3A33.2A.A10.A19.2A.A34.2A38.3A267.A.A$941.2A982.A39.A
2.A33.3A8.A.A20.3A75.A.2A402.A$1924.3A41.A34.2A26.A4.3A76.3A402.2A$
1924.A.2A36.A3.A61.3A4.2A6.A69.3A401.A.A$1925.3A40.A16.3A41.2A.A11.3A
68.2A538.A$926.3A996.3A37.A.A7.A8.A2.A21.A19.3A12.A.2A79.3A525.2A$
912.3A5.A4.A2.A996.2A47.3A10.A20.3A19.2A13.3A38.A39.A2.A524.A.A$898.
3A5.A4.A2.A4.3A6.A5.3A1000.3A33.2A.A10.A19.2A.A34.2A38.3A41.A$884.3A
5.A4.A2.A4.3A6.A4.A.2A5.A5.A2.A998.A2.A33.3A8.A.A20.3A75.A.2A36.A3.A$
870.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.A1004.A34.2A26.A4.3A76.3A
40.A16.3A$856.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.A3.A4.3A989.
A3.A61.3A4.2A6.A69.3A37.A.A7.A8.A2.A368.A$842.3A5.A4.A2.A4.3A6.A4.A.
2A5.A5.3A2.A.A6.3A11.3A11.A3.A3.A2.A993.A16.3A41.2A.A11.3A68.2A47.3A
10.A368.2A$828.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.2A12.A
10.A990.A.A7.A8.A2.A21.A19.3A12.A.2A79.3A33.2A.A10.A367.A.A$822.A4.A
2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.2A27.A.A7.A999.3A10.A20.3A19.
2A13.3A38.A39.A2.A33.3A8.A.A504.A$821.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.
3A11.2A48.A.A999.2A.A10.A19.2A.A34.2A38.3A41.A34.2A515.2A$821.A.2A5.A
5.3A2.A.A6.3A11.3A11.2A1064.3A8.A.A20.3A75.A.2A36.A3.A279.A270.A.A$
822.3A2.A.A6.3A11.3A11.2A1079.2A26.A4.3A76.3A40.A16.3A260.2A$822.3A
11.3A11.2A88.A1031.3A4.2A6.A69.3A37.A.A7.A8.A2.A21.A237.A.A$815.A6.3A
11.2A101.3A1029.2A.A11.3A68.2A47.3A10.A20.3A$814.3A5.2A114.2A.A1009.A
19.3A12.A.2A79.3A33.2A.A10.A19.2A.A371.A$814.A.2A120.3A1009.3A19.2A
13.3A38.A39.A2.A33.3A8.A.A20.3A372.2A$815.3A121.2A1008.2A.A34.2A38.3A
41.A34.2A26.A4.3A371.A.A$815.2A1132.3A75.A.2A36.A3.A61.3A4.2A6.A500.A
$1944.A4.3A76.3A40.A16.3A41.2A.A11.3A499.2A$1943.3A4.2A6.A69.3A37.A.A
7.A8.A2.A21.A19.3A12.A.2A497.A.A$826.3A1113.2A.A11.3A68.2A47.3A10.A
20.3A19.2A13.3A$826.A2.A4.A5.3A1099.3A12.A.2A79.3A33.2A.A10.A19.2A.A
34.2A$817.A8.A6.3A4.A2.A4.A5.3A1086.2A13.3A38.A39.A2.A33.3A8.A.A20.3A
$816.3A7.A5.2A.A4.A6.3A4.A2.A4.A5.3A1087.2A38.3A41.A34.2A26.A4.3A398.
A$816.A.2A7.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A1113.A.2A36.A3.A61.3A
4.2A6.A391.2A$817.3A12.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A1100.
3A40.A16.3A41.2A.A11.3A389.A.A$817.2A13.3A11.3A6.A.A2.3A5.A5.2A.A4.A
6.3A4.A2.A4.A5.3A1086.3A37.A.A7.A8.A2.A21.A19.3A12.A.2A524.A$833.2A
11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A1072.2A47.3A10.A20.3A
19.2A13.3A524.2A$847.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.
3A1070.3A33.2A.A10.A19.2A.A34.2A524.A.A$861.2A11.3A11.3A6.A.A2.3A5.A
5.2A.A4.A6.3A4.A2.A4.A1023.A39.A2.A33.3A8.A.A20.3A697.A$875.2A11.3A
11.3A6.A.A2.3A5.A5.2A.A4.A6.3A9.A1011.3A41.A34.2A26.A4.3A697.2A$889.
2A11.3A11.3A6.A.A2.3A5.A5.2A.A8.3A1010.A.2A36.A3.A61.3A4.2A6.A689.A.A
$903.2A11.3A11.3A6.A.A2.3A9.A.2A1010.3A40.A16.3A41.2A.A11.3A416.A$
917.2A11.3A11.3A10.3A1010.3A37.A.A7.A8.A2.A21.A19.3A12.A.2A415.2A$
931.2A11.3A10.3A1010.2A47.3A10.A20.3A19.2A13.3A38.A375.A.A$945.2A10.
3A1022.3A33.2A.A10.A19.2A.A34.2A38.3A510.A$957.2A982.A39.A2.A33.3A8.A
.A20.3A75.A.2A509.2A$1940.3A41.A34.2A26.A4.3A76.3A508.A.A$1940.A.2A
36.A3.A61.3A4.2A6.A69.3A644.A$1941.3A40.A16.3A41.2A.A11.3A68.2A645.2A
$942.3A996.3A37.A.A7.A8.A2.A21.A19.3A12.A.2A79.3A631.A.A$928.3A5.A4.A
2.A996.2A47.3A10.A20.3A19.2A13.3A38.A39.A2.A359.A$914.3A5.A4.A2.A4.3A
6.A5.3A1036.2A.A10.A19.2A.A34.2A38.3A41.A359.2A$900.3A5.A4.A2.A4.3A6.
A4.A.2A5.A5.A2.A1035.3A8.A.A20.3A75.A.2A36.A3.A358.A.A$886.3A5.A4.A2.
A4.3A6.A4.A.2A5.A5.3A2.A.A6.A1039.2A26.A4.3A76.3A40.A16.3A475.A$872.
3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.A3.A4.3A1055.3A4.2A6.A69.
3A37.A.A7.A8.A2.A475.2A$858.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A
11.3A11.A3.A3.A2.A1010.3A41.2A.A11.3A68.2A47.3A10.A474.A.A$844.3A5.A
4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.2A12.A10.A1009.A2.A21.A19.
3A12.A.2A79.3A33.2A.A10.A610.A$838.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.
3A11.3A11.2A27.A.A7.A1012.A20.3A19.2A13.3A38.A39.A2.A33.3A8.A.A611.2A
$837.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.2A48.A.A1013.A19.2A.A34.2A38.
3A41.A34.2A621.A.A$837.A.2A5.A5.3A2.A.A6.3A11.3A11.2A1075.A.A20.3A75.
A.2A36.A3.A385.A$838.3A2.A.A6.3A11.3A11.2A1107.A4.3A76.3A40.A16.3A
366.2A$838.3A11.3A11.2A88.A1031.3A4.2A6.A69.3A37.A.A7.A8.A2.A21.A343.
A.A$831.A6.3A11.2A101.3A1029.2A.A11.3A68.2A47.3A10.A20.3A478.A$830.3A
5.2A114.2A.A1009.A19.3A12.A.2A79.3A33.2A.A10.A19.2A.A478.2A$830.A.2A
120.3A1009.3A19.2A13.3A38.A39.A2.A33.3A8.A.A20.3A478.A.A$831.3A121.2A
1008.2A.A34.2A38.3A41.A34.2A26.A4.3A614.A$831.2A1132.3A75.A.2A36.A3.A
61.3A4.2A6.A607.2A$1965.3A76.3A40.A16.3A41.2A.A11.3A605.A.A$1966.2A6.
A69.3A37.A.A7.A8.A2.A21.A19.3A12.A.2A332.A$842.3A1128.3A68.2A47.3A10.
A20.3A19.2A13.3A332.2A$842.A2.A4.A5.3A1114.A.2A79.3A33.2A.A10.A19.2A.
A34.2A332.A.A$833.A8.A6.3A4.A2.A4.A5.3A1101.3A38.A39.A2.A33.3A8.A.A
20.3A505.A$832.3A7.A5.2A.A4.A6.3A4.A2.A4.A5.3A1087.2A38.3A41.A34.2A
26.A4.3A505.2A$832.A.2A7.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A1113.A.
2A36.A3.A61.3A4.2A6.A497.A.A$833.3A12.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A
2.A4.A5.3A1100.3A40.A16.3A41.2A.A11.3A632.A$833.2A13.3A11.3A6.A.A2.3A
5.A5.2A.A4.A6.3A4.A2.A4.A5.3A1086.3A37.A.A7.A8.A2.A21.A19.3A12.A.2A
631.2A$849.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A1072.2A
47.3A10.A20.3A19.2A13.3A630.A.A$863.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A
6.3A4.A2.A4.A5.3A1070.3A33.2A.A10.A19.2A.A34.2A359.A$877.2A11.3A11.3A
6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A1023.A39.A2.A33.3A8.A.A20.3A396.2A$
891.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A9.A1011.3A41.A34.2A26.A4.3A
395.A.A$905.2A11.3A11.3A6.A.A2.3A5.A5.2A.A8.3A1010.A.2A36.A3.A61.3A4.
2A6.A524.A$919.2A11.3A11.3A6.A.A2.3A9.A.2A1010.3A40.A16.3A41.2A.A11.
3A523.2A$933.2A11.3A11.3A10.3A1010.3A37.A.A7.A8.A2.A21.A19.3A12.A.2A
521.A.A$947.2A11.3A10.3A1010.2A47.3A10.A20.3A19.2A13.3A38.A618.A$961.
2A10.3A1022.3A33.2A.A10.A19.2A.A34.2A38.3A617.2A$973.2A1022.A2.A33.3A
8.A.A20.3A75.A.2A615.A.A$2000.A34.2A26.A4.3A76.3A343.A$1996.A3.A61.3A
4.2A6.A69.3A343.2A$2000.A16.3A41.2A.A11.3A68.2A343.A.A$958.3A1036.A.A
7.A8.A2.A21.A19.3A12.A.2A79.3A466.A$944.3A5.A4.A2.A1045.3A10.A20.3A
19.2A13.3A38.A39.A2.A466.2A$930.3A5.A4.A2.A4.3A6.A5.3A1036.2A.A10.A
19.2A.A34.2A38.3A41.A465.A.A$916.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.A2.A
1035.3A8.A.A20.3A75.A.2A36.A3.A601.A$902.3A5.A4.A2.A4.3A6.A4.A.2A5.A
5.3A2.A.A6.A1039.2A26.A4.3A76.3A40.A16.3A582.2A$888.3A5.A4.A2.A4.3A6.
A4.A.2A5.A5.3A2.A.A6.3A11.A3.A4.3A1055.3A4.2A6.A69.3A37.A.A7.A8.A2.A
581.A.A$874.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.A3.A3.A2.
A1054.2A.A11.3A68.2A47.3A10.A$860.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.
A6.3A11.3A11.2A12.A10.A1034.A19.3A12.A.2A79.3A33.2A.A10.A$854.A4.A2.A
4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.2A27.A.A7.A1033.3A19.2A13.3A38.A
39.A2.A33.3A8.A.A$853.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.2A48.A.A
1033.2A.A34.2A38.3A41.A34.2A456.A$853.A.2A5.A5.3A2.A.A6.3A11.3A11.2A
1098.3A75.A.2A36.A3.A492.2A$854.3A2.A.A6.3A11.3A11.2A1107.A4.3A76.3A
40.A16.3A472.A.A$854.3A11.3A11.2A88.A1031.3A4.2A6.A69.3A37.A.A7.A8.A
2.A21.A586.A$847.A6.3A11.2A101.3A1029.2A.A11.3A68.2A47.3A10.A20.3A
585.2A$846.3A5.2A114.2A.A1029.3A12.A.2A79.3A33.2A.A10.A19.2A.A313.A
270.A.A$846.A.2A120.3A1031.2A13.3A38.A39.A2.A33.3A8.A.A20.3A314.2A$
847.3A121.2A1046.2A38.3A41.A34.2A26.A4.3A313.A.A$847.2A1210.A.2A36.A
3.A61.3A4.2A6.A$2060.3A40.A16.3A41.2A.A11.3A440.A$2060.3A37.A.A7.A8.A
2.A21.A19.3A12.A.2A439.2A$858.3A1199.2A47.3A10.A20.3A19.2A13.3A438.A.
A$858.A2.A4.A5.3A1197.3A33.2A.A10.A19.2A.A34.2A575.A$849.A8.A6.3A4.A
2.A4.A5.3A1142.A39.A2.A33.3A8.A.A20.3A612.2A$848.3A7.A5.2A.A4.A6.3A4.
A2.A4.A5.3A1127.3A41.A34.2A26.A4.3A611.A.A$848.A.2A7.A.A2.3A5.A5.2A.A
4.A6.3A4.A2.A4.A5.3A1113.A.2A36.A3.A61.3A4.2A6.A$849.3A12.3A6.A.A2.3A
5.A5.2A.A4.A6.3A4.A2.A4.A5.3A1100.3A40.A16.3A41.2A.A11.3A$849.2A13.3A
11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A1086.3A37.A.A7.A8.A2.A21.A
19.3A12.A.2A$865.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A
1072.2A47.3A10.A20.3A19.2A13.3A465.A$879.2A11.3A11.3A6.A.A2.3A5.A5.2A
.A4.A6.3A4.A2.A4.A5.3A1070.3A33.2A.A10.A19.2A.A34.2A466.2A$893.2A11.
3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A1023.A39.A2.A33.3A8.A.A20.3A
502.A.A$907.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A9.A1011.3A41.A34.2A
26.A4.3A638.A$921.2A11.3A11.3A6.A.A2.3A5.A5.2A.A8.3A1010.A.2A36.A3.A
61.3A4.2A6.A631.2A$935.2A11.3A11.3A6.A.A2.3A9.A.2A1010.3A40.A16.3A41.
2A.A11.3A629.A.A$949.2A11.3A11.3A10.3A1010.3A37.A.A7.A8.A2.A21.A19.3A
12.A.2A764.A$963.2A11.3A10.3A1010.2A47.3A10.A20.3A19.2A13.3A38.A725.
2A$977.2A10.3A1058.2A.A10.A19.2A.A34.2A38.3A723.A.A$989.2A1059.3A8.A.
A20.3A75.A.2A450.A$2051.2A26.A4.3A76.3A450.2A$2078.3A4.2A6.A69.3A449.
A.A$2033.3A41.2A.A11.3A68.2A586.A$974.3A1055.A2.A21.A19.3A12.A.2A79.
3A573.2A$960.3A5.A4.A2.A1058.A20.3A19.2A13.3A38.A39.A2.A572.A.A$946.
3A5.A4.A2.A4.3A6.A5.3A1050.A19.2A.A34.2A38.3A41.A708.A$932.3A5.A4.A2.
A4.3A6.A4.A.2A5.A5.A2.A1046.A.A20.3A75.A.2A36.A3.A708.2A$918.3A5.A4.A
2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.A1067.A4.3A76.3A40.A16.3A688.A.A$904.3A
5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.A3.A4.3A1055.3A4.2A6.A69.3A
37.A.A7.A8.A2.A416.A$890.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.
3A11.A3.A3.A2.A1054.2A.A11.3A68.2A47.3A10.A416.2A$876.3A5.A4.A2.A4.3A
6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.2A12.A10.A1034.A19.3A12.A.2A79.3A33.
2A.A10.A415.A.A$870.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.2A27.
A.A7.A1033.3A19.2A13.3A38.A39.A2.A33.3A8.A.A552.A$869.3A6.A4.A.2A5.A
5.3A2.A.A6.3A11.3A11.2A48.A.A1033.2A.A34.2A38.3A41.A34.2A563.2A$869.A
.2A5.A5.3A2.A.A6.3A11.3A11.2A1098.3A75.A.2A36.A3.A598.A.A$870.3A2.A.A
6.3A11.3A11.2A1112.3A76.3A40.A16.3A715.A$870.3A11.3A11.2A88.A1038.2A
6.A69.3A37.A.A7.A8.A2.A21.A693.2A$863.A6.3A11.2A101.3A1044.3A68.2A47.
3A10.A20.3A691.A.A$862.3A5.2A114.2A.A1044.A.2A79.3A33.2A.A10.A19.2A.A
419.A$862.A.2A120.3A1046.3A38.A39.A2.A33.3A8.A.A20.3A420.2A$863.3A
121.2A1046.2A38.3A41.A34.2A26.A4.3A419.A.A$863.2A1210.A.2A36.A3.A61.
3A4.2A6.A548.A$2076.3A40.A16.3A41.2A.A11.3A547.2A$2076.3A37.A.A7.A8.A
2.A21.A19.3A12.A.2A545.A.A$874.3A1199.2A47.3A10.A20.3A19.2A13.3A681.A
$874.A2.A4.A5.3A1197.3A33.2A.A10.A19.2A.A34.2A682.2A$865.A8.A6.3A4.A
2.A4.A5.3A1142.A39.A2.A33.3A8.A.A20.3A718.A.A$864.3A7.A5.2A.A4.A6.3A
4.A2.A4.A5.3A1127.3A41.A34.2A26.A4.3A446.A$864.A.2A7.A.A2.3A5.A5.2A.A
4.A6.3A4.A2.A4.A5.3A1113.A.2A36.A3.A61.3A4.2A6.A439.2A$865.3A12.3A6.A
.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A1100.3A40.A16.3A41.2A.A11.3A437.A.
A$865.2A13.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A1086.3A37.A.A
7.A8.A2.A21.A19.3A12.A.2A572.A$881.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A
6.3A4.A2.A4.A5.3A1072.2A47.3A10.A20.3A19.2A13.3A572.2A$895.2A11.3A11.
3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A1070.3A33.2A.A10.A19.2A.A34.
2A572.A.A$909.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A1063.A2.A
33.3A8.A.A20.3A745.A$923.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A9.A
1055.A34.2A26.A4.3A745.2A$937.2A11.3A11.3A6.A.A2.3A5.A5.2A.A8.3A1050.
A3.A61.3A4.2A6.A737.A.A$951.2A11.3A11.3A6.A.A2.3A9.A.2A1053.A16.3A41.
2A.A11.3A464.A$965.2A11.3A11.3A10.3A1050.A.A7.A8.A2.A21.A19.3A12.A.2A
463.2A$979.2A11.3A10.3A1059.3A10.A20.3A19.2A13.3A38.A423.A.A$993.2A
10.3A1058.2A.A10.A19.2A.A34.2A38.3A558.A$1005.2A1059.3A8.A.A20.3A75.A
.2A557.2A$2067.2A26.A4.3A76.3A556.A.A$2094.3A4.2A6.A69.3A692.A$2093.
2A.A11.3A68.2A693.2A$990.3A1080.A19.3A12.A.2A79.3A679.A.A$976.3A5.A4.
A2.A1079.3A19.2A13.3A38.A39.A2.A407.A$962.3A5.A4.A2.A4.3A6.A5.3A1070.
2A.A34.2A38.3A41.A407.2A$948.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.A2.A1069.3A
75.A.2A36.A3.A406.A.A$934.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.A
1067.A4.3A76.3A40.A16.3A523.A$920.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.
A6.3A11.A3.A4.3A1055.3A4.2A6.A69.3A37.A.A7.A8.A2.A523.2A$906.3A5.A4.A
2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.A3.A3.A2.A1054.2A.A11.3A68.2A
47.3A10.A522.A.A$892.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.
2A12.A10.A1054.3A12.A.2A79.3A33.2A.A10.A658.A$886.A4.A2.A4.3A6.A4.A.
2A5.A5.3A2.A.A6.3A11.3A11.2A27.A.A7.A1055.2A13.3A38.A39.A2.A33.3A8.A.
A659.2A$885.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.2A48.A.A1071.2A38.3A
41.A34.2A669.A.A$885.A.2A5.A5.3A2.A.A6.3A11.3A11.2A1176.A.2A36.A3.A$
886.3A2.A.A6.3A11.3A11.2A1191.3A40.A16.3A$886.3A11.3A11.2A88.A1116.3A
37.A.A7.A8.A2.A21.A$879.A6.3A11.2A101.3A1115.2A47.3A10.A20.3A526.A$
878.3A5.2A114.2A.A1127.3A33.2A.A10.A19.2A.A526.2A$878.A.2A120.3A1087.
A39.A2.A33.3A8.A.A20.3A526.A.A$879.3A121.2A1086.3A41.A34.2A26.A4.3A
662.A$879.2A1210.A.2A36.A3.A61.3A4.2A6.A655.2A$2092.3A40.A16.3A41.2A.
A11.3A382.A270.A.A$2092.3A37.A.A7.A8.A2.A21.A19.3A12.A.2A381.2A$890.
3A1199.2A47.3A10.A20.3A19.2A13.3A380.A.A$890.A2.A4.A5.3A1197.3A33.2A.
A10.A19.2A.A34.2A$881.A8.A6.3A4.A2.A4.A5.3A1142.A39.A2.A33.3A8.A.A20.
3A553.A$880.3A7.A5.2A.A4.A6.3A4.A2.A4.A5.3A1127.3A41.A34.2A26.A4.3A
553.2A$880.A.2A7.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A1113.A.2A36.A3.A
61.3A4.2A6.A545.A.A$881.3A12.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A
1100.3A40.A16.3A41.2A.A11.3A680.A$881.2A13.3A11.3A6.A.A2.3A5.A5.2A.A
4.A6.3A4.A2.A4.A5.3A1086.3A37.A.A7.A8.A2.A21.A19.3A12.A.2A679.2A$897.
2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A1072.2A47.3A10.A20.
3A19.2A13.3A678.A.A$911.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.
A5.3A1106.2A.A10.A19.2A.A34.2A$925.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A
6.3A4.A2.A4.A1100.3A8.A.A20.3A$939.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A
6.3A9.A1090.2A26.A4.3A$953.2A11.3A11.3A6.A.A2.3A5.A5.2A.A8.3A1116.3A
4.2A6.A572.A$967.2A11.3A11.3A6.A.A2.3A9.A.2A1070.3A41.2A.A11.3A571.2A
$981.2A11.3A11.3A10.3A1069.A2.A21.A19.3A12.A.2A569.A.A$995.2A11.3A10.
3A1072.A20.3A19.2A13.3A38.A666.A$1009.2A10.3A1072.A19.2A.A34.2A38.3A
665.2A$1021.2A1070.A.A20.3A75.A.2A663.A.A$2111.A4.3A76.3A799.A$2110.
3A4.2A6.A69.3A799.2A$2109.2A.A11.3A68.2A799.A.A$1006.3A1080.A19.3A12.
A.2A79.3A514.A$992.3A5.A4.A2.A1079.3A19.2A13.3A38.A39.A2.A514.2A$978.
3A5.A4.A2.A4.3A6.A5.3A1070.2A.A34.2A38.3A41.A513.A.A279.A$964.3A5.A4.
A2.A4.3A6.A4.A.2A5.A5.A2.A1069.3A75.A.2A36.A3.A649.A144.3A$950.3A5.A
4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.A1072.3A76.3A40.A16.3A630.2A142.2A.A
$936.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.A3.A4.3A1062.2A6.A69.
3A37.A.A7.A8.A2.A629.A.A142.3A$922.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A
.A6.3A11.3A11.A3.A3.A2.A1069.3A68.2A47.3A10.A765.A9.2A$908.3A5.A4.A2.
A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.2A12.A10.A1069.A.2A79.3A33.2A.A
10.A765.2A$902.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.2A27.A.A7.
A1070.3A38.A39.A2.A33.3A8.A.A765.A.A$901.3A6.A4.A.2A5.A5.3A2.A.A6.3A
11.3A11.2A48.A.A1071.2A38.3A41.A34.2A504.A289.A$901.A.2A5.A5.3A2.A.A
6.3A11.3A11.2A1176.A.2A36.A3.A540.2A287.3A$902.3A2.A.A6.3A11.3A11.2A
1191.3A40.A16.3A520.A.A287.A.2A$902.3A11.3A11.2A88.A1116.3A37.A.A7.A
8.A2.A21.A634.A154.3A$895.A6.3A11.2A101.3A1115.2A47.3A10.A20.3A633.2A
153.2A$894.3A5.2A114.2A.A1127.3A33.2A.A10.A19.2A.A632.A.A$894.A.2A
120.3A1087.A39.A2.A33.3A8.A.A20.3A769.A$895.3A121.2A1086.3A41.A34.2A
26.A4.3A769.2A$895.2A1210.A.2A36.A3.A61.3A4.2A6.A761.A.A$2108.3A40.A
16.3A41.2A.A11.3A488.A$2108.3A37.A.A7.A8.A2.A21.A19.3A12.A.2A487.2A$
906.3A1199.2A47.3A10.A20.3A19.2A13.3A486.A.A$906.A2.A4.A5.3A1197.3A
33.2A.A10.A19.2A.A34.2A623.A$897.A8.A6.3A4.A2.A4.A5.3A1182.A2.A33.3A
8.A.A20.3A660.2A$896.3A7.A5.2A.A4.A6.3A4.A2.A4.A5.3A1171.A34.2A26.A4.
3A659.A.A$896.A.2A7.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A1153.A3.A61.
3A4.2A6.A788.A$897.3A12.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A1143.
A16.3A41.2A.A11.3A787.2A14.A$897.2A13.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.
3A4.A2.A4.A5.3A1126.A.A7.A8.A2.A21.A19.3A12.A.2A785.A.A13.3A$913.2A
11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A1121.3A10.A20.3A19.2A
13.3A513.A286.2A.A$927.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A
5.3A1106.2A.A10.A19.2A.A34.2A514.2A285.3A$941.2A11.3A11.3A6.A.A2.3A5.
A5.2A.A4.A6.3A4.A2.A4.A1100.3A8.A.A20.3A550.A.A286.2A$955.2A11.3A11.
3A6.A.A2.3A5.A5.2A.A4.A6.3A9.A1090.2A26.A4.3A686.A$969.2A11.3A11.3A6.
A.A2.3A5.A5.2A.A8.3A1116.3A4.2A6.A679.2A$983.2A11.3A11.3A6.A.A2.3A9.A
.2A1114.2A.A11.3A677.A.A158.A$997.2A11.3A11.3A10.3A1094.A19.3A12.A.2A
812.A23.3A$1011.2A11.3A10.3A1093.3A19.2A13.3A38.A773.2A22.A.2A$1025.
2A10.3A1092.2A.A34.2A38.3A771.A.A23.3A$1037.2A1093.3A75.A.2A498.A297.
2A$2127.A4.3A76.3A498.2A$2126.3A4.2A6.A69.3A497.A.A$2125.2A.A11.3A68.
2A634.A$1022.3A1100.3A12.A.2A79.3A621.2A$1008.3A5.A4.A2.A1101.2A13.3A
38.A39.A2.A620.A.A$994.3A5.A4.A2.A4.3A6.A5.3A1108.2A38.3A41.A756.A38.
A$980.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.A2.A1147.A.2A36.A3.A756.2A36.3A$
966.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.A1151.3A40.A16.3A736.A.A35.
2A.A$952.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.A3.A4.3A1140.3A
37.A.A7.A8.A2.A464.A309.3A$938.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.
3A11.3A11.A3.A3.A2.A1140.2A47.3A10.A464.2A309.2A$924.3A5.A4.A2.A4.3A
6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.2A12.A10.A1152.3A33.2A.A10.A463.A.A$
918.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.2A27.A.A7.A1111.A39.A
2.A33.3A8.A.A600.A158.A$917.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.2A48.A
.A1111.3A41.A34.2A611.2A156.3A22.A$917.A.2A5.A5.3A2.A.A6.3A11.3A11.2A
1176.A.2A36.A3.A646.A.A155.2A.A21.3A$918.3A2.A.A6.3A11.3A11.2A1191.3A
40.A16.3A763.A21.3A22.A.2A$918.3A11.3A11.2A88.A1116.3A37.A.A7.A8.A2.A
21.A741.2A21.2A23.3A$911.A6.3A11.2A101.3A1115.2A47.3A10.A20.3A739.A.A
46.2A$910.3A5.2A114.2A.A1127.3A33.2A.A10.A19.2A.A$910.A.2A120.3A1087.
A39.A2.A33.3A8.A.A20.3A771.A$911.3A121.2A1086.3A41.A34.2A26.A4.3A770.
3A$911.2A1210.A.2A36.A3.A61.3A4.2A6.A596.A166.A.2A$2124.3A40.A16.3A
41.2A.A11.3A595.2A166.3A$2124.3A37.A.A7.A8.A2.A21.A19.3A12.A.2A593.A.
A166.2A$922.3A1199.2A47.3A10.A20.3A19.2A13.3A729.A$922.A2.A4.A5.3A
1233.2A.A10.A19.2A.A34.2A730.2A$913.A8.A6.3A4.A2.A4.A5.3A1219.3A8.A.A
20.3A495.A270.A.A$912.3A7.A5.2A.A4.A6.3A4.A2.A4.A5.3A1206.2A26.A4.3A
495.2A$912.A.2A7.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A1219.3A4.2A6.A
487.A.A$913.3A12.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A1160.3A41.2A
.A11.3A803.A$913.2A13.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A
1145.A2.A21.A19.3A12.A.2A620.A180.3A$929.2A11.3A11.3A6.A.A2.3A5.A5.2A
.A4.A6.3A4.A2.A4.A5.3A1134.A20.3A19.2A13.3A620.2A178.2A.A$943.2A11.3A
11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A1120.A19.2A.A34.2A620.A.A
178.3A$957.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A1111.A.A20.
3A793.A45.2A$971.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A9.A1118.A4.3A
793.2A$985.2A11.3A11.3A6.A.A2.3A5.A5.2A.A8.3A1116.3A4.2A6.A785.A.A27.
A$999.2A11.3A11.3A6.A.A2.3A9.A.2A1114.2A.A11.3A813.3A22.A$1013.2A11.
3A11.3A10.3A1094.A19.3A12.A.2A811.2A.A21.3A$1027.2A11.3A10.3A1093.3A
19.2A13.3A38.A772.3A22.A.2A$1041.2A10.3A1092.2A.A34.2A38.3A606.A165.
2A23.3A$1053.2A1093.3A75.A.2A605.2A189.2A$2148.3A76.3A604.A.A$2149.2A
6.A69.3A740.A37.A$2156.3A68.2A741.2A35.3A$1038.3A1115.A.2A79.3A727.A.
A35.A.2A$1024.3A5.A4.A2.A1116.3A38.A39.A2.A766.3A$1010.3A5.A4.A2.A4.
3A6.A5.3A1108.2A38.3A41.A766.2A27.A$996.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.
A2.A1147.A.2A36.A3.A794.3A$982.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.
A1151.3A40.A16.3A571.A202.2A.A$968.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A
.A6.3A11.A3.A4.3A1140.3A37.A.A7.A8.A2.A571.2A201.3A$954.3A5.A4.A2.A4.
3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.A3.A3.A2.A1140.2A47.3A10.A570.A.A
202.2A$940.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.2A12.A10.A
1152.3A33.2A.A10.A706.A$934.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A
11.2A27.A.A7.A1111.A39.A2.A33.3A8.A.A707.2A50.A$933.3A6.A4.A.2A5.A5.
3A2.A.A6.3A11.3A11.2A48.A.A1111.3A41.A34.2A717.A.A49.3A22.A$933.A.2A
5.A5.3A2.A.A6.3A11.3A11.2A1176.A.2A36.A3.A804.2A.A21.3A$934.3A2.A.A6.
3A11.3A11.2A1191.3A40.A16.3A785.3A22.A.2A$934.3A11.3A11.2A88.A1116.3A
37.A.A7.A8.A2.A21.A764.2A23.3A$927.A6.3A11.2A101.3A1115.2A47.3A10.A
20.3A574.A213.2A$926.3A5.2A114.2A.A1127.3A33.2A.A10.A19.2A.A574.2A
170.A$926.A.2A120.3A1127.A2.A33.3A8.A.A20.3A574.A.A169.3A22.A$927.3A
121.2A1130.A34.2A26.A4.3A710.A34.2A.A21.3A$927.2A1250.A3.A61.3A4.2A6.
A703.2A33.3A22.A.2A$2183.A16.3A41.2A.A11.3A701.A.A34.2A23.3A$2180.A.A
7.A8.A2.A21.A19.3A12.A.2A762.2A$938.3A1248.3A10.A20.3A19.2A13.3A$938.
A2.A4.A5.3A1233.2A.A10.A19.2A.A34.2A745.A$929.A8.A6.3A4.A2.A4.A5.3A
1219.3A8.A.A20.3A601.A179.3A$928.3A7.A5.2A.A4.A6.3A4.A2.A4.A5.3A1206.
2A26.A4.3A601.2A178.A.2A$928.A.2A7.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.
3A1219.3A4.2A6.A593.A.A179.3A$929.3A12.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A
2.A4.A5.3A1204.2A.A11.3A728.A45.2A27.A$929.2A13.3A11.3A6.A.A2.3A5.A5.
2A.A4.A6.3A4.A2.A4.A5.3A1170.A19.3A12.A.2A727.2A72.3A$945.2A11.3A11.
3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A1155.3A19.2A13.3A726.A.A71.2A
.A$959.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A1140.2A.A34.
2A801.3A$973.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A1134.3A
839.2A$987.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A9.A1118.A4.3A$1001.2A
11.3A11.3A6.A.A2.3A5.A5.2A.A8.3A1116.3A4.2A6.A620.A194.A$1015.2A11.3A
11.3A6.A.A2.3A9.A.2A1114.2A.A11.3A619.2A192.3A22.A$1029.2A11.3A11.3A
10.3A1114.3A12.A.2A617.A.A191.2A.A21.3A$1043.2A11.3A10.3A1115.2A13.3A
38.A714.A57.3A22.A.2A$1057.2A10.3A1130.2A38.3A713.2A57.2A23.3A$1069.
2A1171.A.2A711.A.A82.2A$2243.3A754.A$2243.3A753.3A22.A$2243.2A753.2A.
A21.3A$1054.3A1198.3A562.A177.3A22.A.2A$1040.3A5.A4.A2.A1157.A39.A2.A
562.2A177.2A23.3A$1026.3A5.A4.A2.A4.3A6.A5.3A1148.3A41.A561.A.A202.2A
27.A$1012.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.A2.A1147.A.2A36.A3.A697.A96.3A
$998.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.A1151.3A40.A16.3A678.2A49.
A44.2A.A$984.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.A3.A4.3A1140.
3A37.A.A7.A8.A2.A677.A.A48.3A43.3A$970.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.
3A2.A.A6.3A11.3A11.A3.A3.A2.A1140.2A47.3A10.A728.A.2A43.2A$956.3A5.A
4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.2A12.A10.A1152.3A33.2A.A
10.A729.3A$950.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.2A27.A.A7.
A1111.A39.A2.A33.3A8.A.A730.2A27.A$949.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.
3A11.2A48.A.A1111.3A41.A34.2A552.A216.3A22.A$949.A.2A5.A5.3A2.A.A6.3A
11.3A11.2A1176.A.2A36.A3.A588.2A214.2A.A21.3A$950.3A2.A.A6.3A11.3A11.
2A1191.3A40.A16.3A568.A.A214.3A22.A.2A$950.3A11.3A11.2A88.A1116.3A37.
A.A7.A8.A2.A21.A682.A81.2A23.3A$943.A6.3A11.2A101.3A1115.2A47.3A10.A
20.3A681.2A105.2A$942.3A5.2A114.2A.A1163.2A.A10.A19.2A.A680.A.A63.A$
942.A.2A120.3A1164.3A8.A.A20.3A746.3A22.A$943.3A121.2A1165.2A26.A4.3A
745.2A.A21.3A$943.2A1316.3A4.2A6.A738.3A22.A.2A$2216.3A41.2A.A11.3A
738.2A23.3A$2215.A2.A21.A19.3A12.A.2A762.2A$954.3A1261.A20.3A19.2A13.
3A720.A$954.A2.A4.A5.3A1247.A19.2A.A34.2A671.A48.3A22.A$945.A8.A6.3A
4.A2.A4.A5.3A1230.A.A20.3A708.2A46.2A.A21.3A$944.3A7.A5.2A.A4.A6.3A4.
A2.A4.A5.3A1234.A4.3A707.A.A46.3A22.A.2A$944.A.2A7.A.A2.3A5.A5.2A.A4.
A6.3A4.A2.A4.A5.3A1219.3A4.2A6.A750.2A23.3A$945.3A12.3A6.A.A2.3A5.A5.
2A.A4.A6.3A4.A2.A4.A5.3A1204.2A.A11.3A774.2A27.A$945.2A13.3A11.3A6.A.
A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A1170.A19.3A12.A.2A562.A238.3A$961.
2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A1155.3A19.2A13.3A
562.2A191.A44.2A.A$975.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A
5.3A1140.2A.A34.2A562.A.A190.3A43.3A$989.2A11.3A11.3A6.A.A2.3A5.A5.2A
.A4.A6.3A4.A2.A4.A1134.3A792.A.2A43.2A$1003.2A11.3A11.3A6.A.A2.3A5.A
5.2A.A4.A6.3A9.A1123.3A734.A58.3A$1017.2A11.3A11.3A6.A.A2.3A5.A5.2A.A
8.3A1123.2A6.A727.2A57.2A27.A$1031.2A11.3A11.3A6.A.A2.3A9.A.2A1129.3A
725.A.A85.3A22.A$1045.2A11.3A11.3A10.3A1129.A.2A811.2A.A21.3A$1059.2A
11.3A10.3A1130.3A38.A772.3A22.A.2A$1073.2A10.3A1130.2A38.3A772.2A23.
3A$1085.2A1171.A.2A796.2A$2259.3A754.A$2259.3A753.3A22.A$2259.2A682.A
70.2A.A21.3A$1070.3A1198.3A669.2A69.3A22.A.2A$1056.3A5.A4.A2.A1157.A
39.A2.A668.A.A70.2A23.3A$1042.3A5.A4.A2.A4.3A6.A5.3A1148.3A41.A766.2A
27.A$1028.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.A2.A1147.A.2A36.A3.A724.A69.3A
$1014.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.A1151.3A40.A16.3A704.3A
22.A44.2A.A$1000.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.A3.A4.3A
1140.3A37.A.A7.A8.A2.A703.2A.A21.3A43.3A$986.3A5.A4.A2.A4.3A6.A4.A.2A
5.A5.3A2.A.A6.3A11.3A11.A3.A3.A2.A1140.2A47.3A10.A703.3A22.A.2A43.2A$
972.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.2A12.A10.A1152.3A
33.2A.A10.A704.2A23.3A$966.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A
11.2A27.A.A7.A1151.A2.A33.3A8.A.A648.A81.2A27.A$965.3A6.A4.A.2A5.A5.
3A2.A.A6.3A11.3A11.2A48.A.A1155.A34.2A659.2A108.3A22.A$965.A.2A5.A5.
3A2.A.A6.3A11.3A11.2A1216.A3.A694.A.A62.A44.2A.A21.3A$966.3A2.A.A6.3A
11.3A11.2A1234.A16.3A739.3A43.3A22.A.2A$966.3A11.3A11.2A88.A1156.A.A
7.A8.A2.A21.A717.A.2A43.2A23.3A$959.A6.3A11.2A101.3A1164.3A10.A20.3A
717.3A68.2A$958.3A5.2A114.2A.A1163.2A.A10.A19.2A.A717.2A27.A$958.A.2A
120.3A1164.3A8.A.A20.3A746.3A22.A$959.3A121.2A1165.2A26.A4.3A745.2A.A
21.3A$959.2A1316.3A4.2A6.A644.A93.3A22.A.2A$2276.2A.A11.3A643.2A93.2A
23.3A$2256.A19.3A12.A.2A641.A.A118.2A$970.3A1282.3A19.2A13.3A720.A$
970.A2.A4.A5.3A1267.2A.A34.2A720.3A22.A$961.A8.A6.3A4.A2.A4.A5.3A
1253.3A756.2A.A21.3A$960.3A7.A5.2A.A4.A6.3A4.A2.A4.A5.3A1234.A4.3A
756.3A22.A.2A$960.A.2A7.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A1219.3A4.
2A6.A750.2A23.3A$961.3A12.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A
1204.2A.A11.3A774.2A27.A$961.2A13.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A
2.A4.A5.3A1190.3A12.A.2A668.A62.A69.3A$977.2A11.3A11.3A6.A.A2.3A5.A5.
2A.A4.A6.3A4.A2.A4.A5.3A1177.2A13.3A668.2A60.3A22.A44.2A.A$991.2A11.
3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A1178.2A668.A.A59.2A.A21.
3A43.3A$1005.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A1904.3A22.
A.2A43.2A$1019.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A9.A1894.2A23.3A$
1033.2A11.3A11.3A6.A.A2.3A5.A5.2A.A8.3A1918.2A27.A$1047.2A11.3A11.3A
6.A.A2.3A9.A.2A1945.3A22.A$1061.2A11.3A11.3A10.3A1899.A44.2A.A21.3A$
1075.2A11.3A10.3A1171.A726.3A43.3A22.A.2A$1089.2A10.3A1170.3A654.A70.
A.2A43.2A23.3A$1101.2A1171.A.2A653.2A70.3A68.2A$2275.3A652.A.A70.2A
27.A$2275.3A753.3A22.A$2275.2A753.2A.A21.3A$1086.3A1198.3A740.3A22.A.
2A$1072.3A5.A4.A2.A1157.A39.A2.A741.2A23.3A$1058.3A5.A4.A2.A4.3A6.A5.
3A1148.3A41.A766.2A27.A$1044.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.A2.A1147.A.
2A36.A3.A724.A69.3A$1030.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.A1151.
3A40.A16.3A619.A84.3A22.A44.2A.A$1016.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A
2.A.A6.3A11.A3.A4.3A1140.3A37.A.A7.A8.A2.A619.2A82.2A.A21.3A43.3A$
1002.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.A3.A3.A2.A1140.
2A47.3A10.A618.A.A82.3A22.A.2A43.2A$988.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.
3A2.A.A6.3A11.3A11.2A12.A10.A1188.2A.A10.A704.2A23.3A$982.A4.A2.A4.3A
6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.2A27.A.A7.A1188.3A8.A.A730.2A27.A$
981.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.2A48.A.A1190.2A699.A69.3A22.A$
981.A.2A5.A5.3A2.A.A6.3A11.3A11.2A1955.3A22.A44.2A.A21.3A$982.3A2.A.A
6.3A11.3A11.2A1251.3A714.2A.A21.3A43.3A22.A.2A$982.3A11.3A11.2A88.A
1175.A2.A21.A692.3A22.A.2A43.2A23.3A$975.A6.3A11.2A101.3A1177.A20.3A
622.A69.2A23.3A68.2A$974.3A5.2A114.2A.A1177.A19.2A.A622.2A93.2A27.A$
974.A.2A120.3A1175.A.A20.3A622.A.A121.3A22.A$975.3A121.2A1193.A4.3A
700.A44.2A.A21.3A$975.2A1316.3A4.2A6.A692.3A43.3A22.A.2A$2292.2A.A11.
3A691.A.2A43.2A23.3A$2272.A19.3A12.A.2A691.3A68.2A$986.3A1282.3A19.2A
13.3A691.2A27.A$986.A2.A4.A5.3A1267.2A.A34.2A720.3A22.A$977.A8.A6.3A
4.A2.A4.A5.3A1253.3A756.2A.A21.3A$976.3A7.A5.2A.A4.A6.3A4.A2.A4.A5.3A
1239.3A756.3A22.A.2A$976.A.2A7.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A
1226.2A6.A750.2A23.3A$977.3A12.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.
3A1219.3A774.2A27.A$977.2A13.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.
A5.3A1205.A.2A731.A69.3A$993.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A
2.A4.A5.3A1192.3A730.3A22.A44.2A.A$1007.2A11.3A11.3A6.A.A2.3A5.A5.2A.
A4.A6.3A4.A2.A4.A5.3A1178.2A730.2A.A21.3A43.3A$1021.2A11.3A11.3A6.A.A
2.3A5.A5.2A.A4.A6.3A4.A2.A4.A1904.3A22.A.2A43.2A$1035.2A11.3A11.3A6.A
.A2.3A5.A5.2A.A4.A6.3A9.A1802.A91.2A23.3A$1049.2A11.3A11.3A6.A.A2.3A
5.A5.2A.A8.3A1801.2A115.2A27.A$1063.2A11.3A11.3A6.A.A2.3A9.A.2A1799.A
.A73.A69.3A22.A$1077.2A11.3A11.3A10.3A1874.3A22.A44.2A.A21.3A$1091.2A
11.3A10.3A1171.A701.2A.A21.3A43.3A22.A.2A$1105.2A10.3A1170.3A700.3A
22.A.2A43.2A23.3A$1117.2A1171.A.2A700.2A23.3A68.2A$2291.3A725.2A27.A$
2291.3A753.3A22.A$2291.2A708.A44.2A.A21.3A$1102.3A1198.3A694.3A43.3A
22.A.2A$1088.3A5.A4.A2.A1197.A2.A694.A.2A43.2A23.3A$1074.3A5.A4.A2.A
4.3A6.A5.3A1192.A695.3A68.2A27.A$1060.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.A
2.A1187.A3.A695.2A27.A69.3A$1046.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A
6.A1194.A16.3A704.3A22.A44.2A.A$1032.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A
2.A.A6.3A11.A3.A4.3A1180.A.A7.A8.A2.A703.2A.A21.3A43.3A$1018.3A5.A4.A
2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.A3.A3.A2.A1189.3A10.A703.3A
22.A.2A43.2A$1004.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.2A
12.A10.A1188.2A.A10.A704.2A23.3A$998.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A
6.3A11.3A11.2A27.A.A7.A1188.3A10.A730.2A27.A$997.3A6.A4.A.2A5.A5.3A2.
A.A6.3A11.3A11.2A48.A.A1190.2A699.A69.3A22.A$997.A.2A5.A5.3A2.A.A6.3A
11.3A11.2A1955.3A22.A44.2A.A21.3A$998.3A2.A.A6.3A11.3A11.2A1968.2A.A
21.3A43.3A22.A.2A$998.3A11.3A11.2A88.A1200.A692.3A22.A.2A43.2A23.3A$
991.A6.3A11.2A101.3A1198.3A692.2A23.3A68.2A$990.3A5.2A114.2A.A1197.2A
.A717.2A27.A$990.A.2A120.3A1198.3A676.A69.3A22.A$991.3A121.2A1193.A4.
3A675.3A22.A44.2A.A21.3A$991.2A1316.3A4.2A6.A667.2A.A21.3A43.3A22.A.
2A$2308.2A.A11.3A666.3A22.A.2A43.2A23.3A$2308.3A12.A.2A666.2A23.3A68.
2A$1002.3A1304.2A13.3A691.2A27.A$1002.A2.A4.A5.3A1305.2A720.3A22.A$
993.A8.A6.3A4.A2.A4.A5.3A1967.A44.2A.A21.3A$992.3A7.A5.2A.A4.A6.3A4.A
2.A4.A5.3A1952.3A43.3A22.A.2A$992.A.2A7.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A
4.A5.3A1938.A.2A43.2A23.3A$993.3A12.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A
4.A5.3A1925.3A68.2A27.A$993.2A13.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A
2.A4.A5.3A1911.2A27.A69.3A$1009.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A
4.A2.A4.A5.3A1925.3A22.A44.2A.A$1023.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.
A6.3A4.A2.A4.A5.3A1910.2A.A21.3A43.3A$1037.2A11.3A11.3A6.A.A2.3A5.A5.
2A.A4.A6.3A4.A2.A4.A1904.3A22.A.2A43.2A$1051.2A11.3A11.3A6.A.A2.3A5.A
5.2A.A4.A6.3A9.A1894.2A23.3A$1065.2A11.3A11.3A6.A.A2.3A5.A5.2A.A8.3A
1918.2A27.A$1079.2A11.3A11.3A6.A.A2.3A9.A.2A1875.A69.3A22.A$1093.2A
11.3A11.3A10.3A1874.3A22.A44.2A.A21.3A$1107.2A11.3A10.3A1171.A701.2A.
A21.3A43.3A22.A.2A$1121.2A10.3A1170.3A700.3A22.A.2A43.2A23.3A$1133.2A
1171.A.2A700.2A23.3A68.2A$2307.3A725.2A27.A$2307.3A683.A69.3A22.A$
2307.2A683.3A22.A44.2A.A21.3A$1118.3A1870.2A.A21.3A43.3A22.A.2A$1104.
3A5.A4.A2.A1870.3A22.A.2A43.2A23.3A$1090.3A5.A4.A2.A4.3A6.A5.3A1863.
2A23.3A68.2A27.A$1076.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.A2.A1887.2A27.A69.
3A$1062.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.A1918.3A22.A44.2A.A$
1048.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.A3.A4.3A1861.A44.2A.A
21.3A43.3A$1034.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.A3.A
3.A2.A1860.3A43.3A22.A.2A43.2A$1020.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.
A.A6.3A11.3A11.2A12.A10.A1860.A.2A43.2A23.3A$1014.A4.A2.A4.3A6.A4.A.
2A5.A5.3A2.A.A6.3A11.3A11.2A27.A.A7.A1861.3A68.2A27.A$1013.3A6.A4.A.
2A5.A5.3A2.A.A6.3A11.3A11.2A48.A.A1862.2A27.A69.3A22.A$1013.A.2A5.A5.
3A2.A.A6.3A11.3A11.2A1955.3A22.A44.2A.A21.3A$1014.3A2.A.A6.3A11.3A11.
2A1968.2A.A21.3A43.3A22.A.2A$1014.3A11.3A11.2A88.A1893.3A22.A.2A43.2A
23.3A$1007.A6.3A11.2A101.3A1893.2A23.3A68.2A$1006.3A5.2A114.2A.A1918.
2A27.A$1006.A.2A120.3A1877.A69.3A22.A$1007.3A121.2A1876.3A22.A44.2A.A
21.3A$1007.2A1999.2A.A21.3A43.3A22.A.2A$3008.3A22.A.2A43.2A23.3A$
3009.2A23.3A68.2A$1018.3A2013.2A27.A$1018.A2.A4.A5.3A1957.A69.3A22.A$
1009.A8.A6.3A4.A2.A4.A5.3A1942.3A22.A44.2A.A21.3A$1008.3A7.A5.2A.A4.A
6.3A4.A2.A4.A5.3A1927.2A.A21.3A43.3A22.A.2A$1008.A.2A7.A.A2.3A5.A5.2A
.A4.A6.3A4.A2.A4.A5.3A1913.3A22.A.2A43.2A23.3A$1009.3A12.3A6.A.A2.3A
5.A5.2A.A4.A6.3A4.A2.A4.A5.3A1900.2A23.3A68.2A27.A$1009.2A13.3A11.3A
6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A1911.2A27.A69.3A$1025.2A11.3A
11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A1925.3A22.A44.2A.A$1039.2A
11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A1910.2A.A21.3A43.3A$
1053.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A1904.3A22.A.2A43.
2A$1067.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A9.A1894.2A23.3A$1081.2A
11.3A11.3A6.A.A2.3A5.A5.2A.A8.3A1918.2A27.A$1095.2A11.3A11.3A6.A.A2.
3A9.A.2A1875.A69.3A22.A$1109.2A11.3A11.3A10.3A1874.3A22.A44.2A.A21.3A
$1123.2A11.3A10.3A1873.2A.A21.3A43.3A22.A.2A$1137.2A10.3A1873.3A22.A.
2A43.2A23.3A$1149.2A1875.2A23.3A68.2A$3051.2A27.A$3009.A69.3A22.A$
3008.3A22.A44.2A.A21.3A$1134.3A1870.2A.A21.3A43.3A22.A.2A$1120.3A5.A
4.A2.A1870.3A22.A.2A43.2A23.3A$1106.3A5.A4.A2.A4.3A6.A5.3A1863.2A23.
3A68.2A27.A$1092.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.A2.A1887.2A27.A69.3A$
1078.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.A1918.3A22.A44.2A.A$1064.
3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.A3.A4.3A1861.A44.2A.A21.3A
43.3A$1050.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.A3.A3.A2.A
1860.3A43.3A22.A.2A43.2A$1036.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.
3A11.3A11.2A12.A10.A1860.A.2A43.2A23.3A$1030.A4.A2.A4.3A6.A4.A.2A5.A
5.3A2.A.A6.3A11.3A11.2A27.A.A7.A1861.3A68.2A27.A$1029.3A6.A4.A.2A5.A
5.3A2.A.A6.3A11.3A11.2A48.A.A1862.2A27.A69.3A22.A$1029.A.2A5.A5.3A2.A
.A6.3A11.3A11.2A1955.3A22.A44.2A.A21.3A$1030.3A2.A.A6.3A11.3A11.2A
1968.2A.A21.3A43.3A22.A.2A$1030.3A11.3A11.2A88.A1893.3A22.A.2A43.2A
23.3A$1023.A6.3A11.2A101.3A1893.2A23.3A68.2A$1022.3A5.2A114.2A.A1918.
2A27.A$1022.A.2A120.3A1877.A69.3A22.A$1023.3A121.2A1876.3A22.A44.2A.A
21.3A$1023.2A1999.2A.A21.3A43.3A22.A.2A$3024.3A22.A.2A43.2A23.3A$
3025.2A23.3A68.2A$1034.3A2013.2A27.A$1034.A2.A4.A5.3A1957.A69.3A22.A$
1025.A8.A6.3A4.A2.A4.A5.3A1942.3A22.A44.2A.A21.3A$1024.3A7.A5.2A.A4.A
6.3A4.A2.A4.A5.3A1927.2A.A21.3A43.3A22.A.2A$1024.A.2A7.A.A2.3A5.A5.2A
.A4.A6.3A4.A2.A4.A5.3A1913.3A22.A.2A43.2A23.3A$1025.3A12.3A6.A.A2.3A
5.A5.2A.A4.A6.3A4.A2.A4.A5.3A1900.2A23.3A68.2A27.A$1025.2A13.3A11.3A
6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A1911.2A27.A69.3A$1041.2A11.3A
11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A1925.3A22.A44.2A.A$1055.2A
11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A1910.2A.A21.3A43.3A$
1069.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A1904.3A22.A.2A43.
2A$1083.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A9.A1894.2A23.3A$1097.2A
11.3A11.3A6.A.A2.3A5.A5.2A.A8.3A1918.2A27.A$1111.2A11.3A11.3A6.A.A2.
3A9.A.2A1875.A69.3A22.A$1125.2A11.3A11.3A10.3A1874.3A22.A44.2A.A21.3A
$1139.2A11.3A10.3A1873.2A.A21.3A43.3A22.A.2A$1153.2A10.3A1873.3A22.A.
2A43.2A23.3A$1165.2A1875.2A23.3A68.2A$3067.2A27.A$3025.A69.3A22.A$
3024.3A22.A44.2A.A21.3A$1150.3A1870.2A.A21.3A43.3A22.A.2A$1136.3A5.A
4.A2.A1870.3A22.A.2A43.2A23.3A$1122.3A5.A4.A2.A4.3A6.A5.3A1863.2A23.
3A68.2A27.A$1108.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.A2.A1887.2A27.A69.3A$
1094.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.A1918.3A22.A44.2A.A$1080.
3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.A3.A4.3A1861.A44.2A.A21.3A
43.3A$1066.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.A3.A3.A2.A
1860.3A43.3A22.A.2A43.2A$1052.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.
3A11.3A11.2A12.A10.A1860.A.2A43.2A23.3A$1046.A4.A2.A4.3A6.A4.A.2A5.A
5.3A2.A.A6.3A11.3A11.2A27.A.A7.A1861.3A68.2A27.A$1045.3A6.A4.A.2A5.A
5.3A2.A.A6.3A11.3A11.2A48.A.A1862.2A27.A69.3A22.A$1045.A.2A5.A5.3A2.A
.A6.3A11.3A11.2A1955.3A22.A44.2A.A21.3A$1046.3A2.A.A6.3A11.3A11.2A
1968.2A.A21.3A43.3A22.A.2A$1046.3A11.3A11.2A88.A1893.3A22.A.2A43.2A
23.3A$1039.A6.3A11.2A101.3A1893.2A23.3A68.2A$1038.3A5.2A114.2A.A1918.
2A27.A$1038.A.2A120.3A1877.A69.3A22.A$1039.3A121.2A1876.3A22.A44.2A.A
21.3A$1039.2A1999.2A.A21.3A43.3A22.A.2A$3040.3A22.A.2A43.2A23.3A$
3041.2A23.3A68.2A$1050.3A2013.2A27.A$1050.A2.A4.A5.3A1957.A69.3A22.A$
1041.A8.A6.3A4.A2.A4.A5.3A1942.3A22.A44.2A.A21.3A$1040.3A7.A5.2A.A4.A
6.3A4.A2.A4.A5.3A1927.2A.A21.3A43.3A22.A.2A$1040.A.2A7.A.A2.3A5.A5.2A
.A4.A6.3A4.A2.A4.A5.3A1913.3A22.A.2A43.2A23.3A$1041.3A12.3A6.A.A2.3A
5.A5.2A.A4.A6.3A4.A2.A4.A5.3A1900.2A23.3A68.2A27.A$1041.2A13.3A11.3A
6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A1911.2A27.A69.3A$1057.2A11.3A
11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A1925.3A22.A44.2A.A$1071.2A
11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A1910.2A.A21.3A43.3A$
1085.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A1904.3A22.A.2A43.
2A$1099.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A9.A1894.2A23.3A$1113.2A
11.3A11.3A6.A.A2.3A5.A5.2A.A8.3A1918.2A27.A$1127.2A11.3A11.3A6.A.A2.
3A9.A.2A1875.A69.3A22.A$1141.2A11.3A11.3A10.3A1874.3A22.A44.2A.A21.3A
$1155.2A11.3A10.3A1873.2A.A21.3A43.3A22.A.2A$1169.2A10.3A1873.3A22.A.
2A43.2A23.3A$1181.2A1875.2A23.3A68.2A$3083.2A27.A$3041.A69.3A22.A$
3040.3A22.A44.2A.A21.3A$1166.3A1870.2A.A21.3A43.3A22.A.2A$1152.3A5.A
4.A2.A1870.3A22.A.2A43.2A23.3A$1138.3A5.A4.A2.A4.3A6.A5.3A1863.2A23.
3A68.2A27.A$1124.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.A2.A1887.2A27.A69.3A$
1110.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.A1918.3A22.A44.2A.A$1096.
3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.A3.A4.3A1861.A44.2A.A21.3A
43.3A$1082.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.A3.A3.A2.A
1860.3A43.3A22.A.2A43.2A$1068.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.
3A11.3A11.2A12.A10.A1860.A.2A43.2A23.3A$1062.A4.A2.A4.3A6.A4.A.2A5.A
5.3A2.A.A6.3A11.3A11.2A27.A.A7.A1861.3A68.2A27.A$1061.3A6.A4.A.2A5.A
5.3A2.A.A6.3A11.3A11.2A48.A.A1862.2A27.A69.3A22.A$1061.A.2A5.A5.3A2.A
.A6.3A11.3A11.2A1955.3A22.A44.2A.A21.3A$1062.3A2.A.A6.3A11.3A11.2A
1968.2A.A21.3A43.3A22.A.2A$1062.3A11.3A11.2A88.A1893.3A22.A.2A43.2A
23.3A$1055.A6.3A11.2A101.3A1893.2A23.3A68.2A$1054.3A5.2A114.2A.A1918.
2A27.A$1054.A.2A120.3A1877.A69.3A22.A$1055.3A121.2A1876.3A22.A44.2A.A
21.3A$1055.2A1999.2A.A21.3A43.3A22.A.2A$3056.3A22.A.2A43.2A23.3A$
3057.2A23.3A68.2A$1066.3A2013.2A27.A$1066.A2.A4.A5.3A1957.A69.3A22.A$
1057.A8.A6.3A4.A2.A4.A5.3A1942.3A22.A44.2A.A21.3A$1056.3A7.A5.2A.A4.A
6.3A4.A2.A4.A5.3A1927.2A.A21.3A43.3A22.A.2A$1056.A.2A7.A.A2.3A5.A5.2A
.A4.A6.3A4.A2.A4.A5.3A1913.3A22.A.2A43.2A23.3A$1057.3A12.3A6.A.A2.3A
5.A5.2A.A4.A6.3A4.A2.A4.A5.3A1900.2A23.3A68.2A27.A$1057.2A13.3A11.3A
6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A1911.2A27.A69.3A$1073.2A11.3A
11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A1925.3A22.A44.2A.A$1087.2A
11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A1910.2A.A21.3A43.3A$
1101.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A1904.3A22.A.2A43.
2A$1115.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A9.A1894.2A23.3A$1129.2A
11.3A11.3A6.A.A2.3A5.A5.2A.A8.3A1918.2A27.A$1143.2A11.3A11.3A6.A.A2.
3A9.A.2A1875.A69.3A22.A$1157.2A11.3A11.3A10.3A1874.3A22.A44.2A.A21.3A
$1171.2A11.3A10.3A1873.2A.A21.3A43.3A22.A.2A$1185.2A10.3A1873.3A22.A.
2A43.2A23.3A$1197.2A1875.2A23.3A68.2A$3099.2A27.A$3057.A69.3A22.A$
3056.3A22.A44.2A.A21.3A$1182.3A1870.2A.A21.3A43.3A22.A.2A$1168.3A5.A
4.A2.A1870.3A22.A.2A43.2A23.3A$1154.3A5.A4.A2.A4.3A6.A5.3A1863.2A23.
3A68.2A27.A$1140.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.A2.A1887.2A27.A69.3A$
1126.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.A1918.3A22.A44.2A.A$1112.
3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.A3.A4.3A1861.A44.2A.A21.3A
43.3A$1098.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.A3.A3.A2.A
1860.3A43.3A22.A.2A43.2A$1084.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.
3A11.3A11.2A12.A10.A1860.A.2A43.2A23.3A$1078.A4.A2.A4.3A6.A4.A.2A5.A
5.3A2.A.A6.3A11.3A11.2A27.A.A7.A1861.3A68.2A27.A$1077.3A6.A4.A.2A5.A
5.3A2.A.A6.3A11.3A11.2A48.A.A1862.2A27.A69.3A22.A$1077.A.2A5.A5.3A2.A
.A6.3A11.3A11.2A1955.3A22.A44.2A.A21.3A$1078.3A2.A.A6.3A11.3A11.2A
1968.2A.A21.3A43.3A22.A.2A$1078.3A11.3A11.2A88.A1893.3A22.A.2A43.2A
23.3A$1071.A6.3A11.2A101.3A1893.2A23.3A68.2A$1070.3A5.2A114.2A.A1918.
2A27.A$1070.A.2A120.3A1877.A69.3A22.A$1071.3A121.2A1876.3A22.A44.2A.A
21.3A$1071.2A1999.2A.A21.3A43.3A22.A.2A$3072.3A22.A.2A43.2A23.3A$
3073.2A23.3A68.2A$1082.3A2013.2A27.A$1082.A2.A4.A5.3A1957.A69.3A22.A$
1073.A8.A6.3A4.A2.A4.A5.3A1942.3A22.A44.2A.A21.3A$1072.3A7.A5.2A.A4.A
6.3A4.A2.A4.A5.3A1927.2A.A21.3A43.3A22.A.2A$1072.A.2A7.A.A2.3A5.A5.2A
.A4.A6.3A4.A2.A4.A5.3A1913.3A22.A.2A43.2A23.3A$1073.3A12.3A6.A.A2.3A
5.A5.2A.A4.A6.3A4.A2.A4.A5.3A1900.2A23.3A68.2A27.A$1073.2A13.3A11.3A
6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A1911.2A27.A69.3A$1089.2A11.3A
11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A1925.3A22.A44.2A.A$1103.2A
11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A1910.2A.A21.3A43.3A$
1117.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A1904.3A22.A.2A43.
2A$1131.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A9.A1894.2A23.3A$1145.2A
11.3A11.3A6.A.A2.3A5.A5.2A.A8.3A1918.2A27.A$1159.2A11.3A11.3A6.A.A2.
3A9.A.2A1875.A69.3A22.A$1173.2A11.3A11.3A10.3A1874.3A22.A44.2A.A21.3A
$1187.2A11.3A10.3A1873.2A.A21.3A43.3A22.A.2A$1201.2A10.3A1873.3A22.A.
2A43.2A23.3A$1213.2A1875.2A23.3A68.2A$3115.2A27.A$3073.A69.3A22.A$
3072.3A22.A44.2A.A21.3A$1198.3A1870.2A.A21.3A43.3A22.A.2A$1184.3A5.A
4.A2.A1870.3A22.A.2A43.2A23.3A$1170.3A5.A4.A2.A4.3A6.A5.3A1863.2A23.
3A68.2A27.A$1156.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.A2.A1887.2A27.A69.3A$
1142.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.A1918.3A22.A44.2A.A$1128.
3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.A3.A4.3A1861.A44.2A.A21.3A
43.3A$1114.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.A3.A3.A2.A
1860.3A43.3A22.A.2A43.2A$1100.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.
3A11.3A11.2A12.A10.A1860.A.2A43.2A23.3A$1094.A4.A2.A4.3A6.A4.A.2A5.A
5.3A2.A.A6.3A11.3A11.2A27.A.A7.A1861.3A68.2A27.A$1093.3A6.A4.A.2A5.A
5.3A2.A.A6.3A11.3A11.2A48.A.A1862.2A27.A69.3A22.A$1093.A.2A5.A5.3A2.A
.A6.3A11.3A11.2A1955.3A22.A44.2A.A21.3A$1094.3A2.A.A6.3A11.3A11.2A
1968.2A.A21.3A43.3A22.A.2A$1094.3A11.3A11.2A88.A1893.3A22.A.2A43.2A
23.3A$1087.A6.3A11.2A101.3A1893.2A23.3A68.2A$1086.3A5.2A114.2A.A1918.
2A27.A$1086.A.2A120.3A1877.A69.3A22.A$1087.3A121.2A1876.3A22.A44.2A.A
21.3A$1087.2A1999.2A.A21.3A43.3A22.A.2A$3088.3A22.A.2A43.2A23.3A$
3089.2A23.3A68.2A$1098.3A2013.2A27.A$1098.A2.A4.A5.3A1957.A69.3A22.A$
1089.A8.A6.3A4.A2.A4.A5.3A1942.3A22.A44.2A.A21.3A$1088.3A7.A5.2A.A4.A
6.3A4.A2.A4.A5.3A1927.2A.A21.3A43.3A22.A.2A$1088.A.2A7.A.A2.3A5.A5.2A
.A4.A6.3A4.A2.A4.A5.3A1913.3A22.A.2A43.2A23.3A$1089.3A12.3A6.A.A2.3A
5.A5.2A.A4.A6.3A4.A2.A4.A5.3A1900.2A23.3A68.2A27.A$1089.2A13.3A11.3A
6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A1911.2A27.A69.3A$1105.2A11.3A
11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A1925.3A22.A44.2A.A$1119.2A
11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A1910.2A.A21.3A43.3A$
1133.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A1904.3A22.A.2A43.
2A$1147.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A9.A1894.2A23.3A$1161.2A
11.3A11.3A6.A.A2.3A5.A5.2A.A8.3A1918.2A27.A$1175.2A11.3A11.3A6.A.A2.
3A9.A.2A1875.A69.3A22.A$1189.2A11.3A11.3A10.3A1874.3A22.A44.2A.A21.3A
$1203.2A11.3A10.3A1873.2A.A21.3A43.3A22.A.2A$1217.2A10.3A1873.3A22.A.
2A43.2A23.3A$1229.2A1875.2A23.3A68.2A$3131.2A27.A$3089.A69.3A22.A$
3088.3A22.A44.2A.A21.3A$1214.3A1870.2A.A21.3A43.3A22.A.2A$1200.3A5.A
4.A2.A1870.3A22.A.2A43.2A23.3A$1186.3A5.A4.A2.A4.3A6.A5.3A1863.2A23.
3A68.2A27.A$1172.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.A2.A1887.2A27.A69.3A$
1158.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.A1918.3A22.A44.2A.A$1144.
3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.A3.A4.3A1861.A44.2A.A21.3A
43.3A$1130.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.A3.A3.A2.A
1860.3A43.3A22.A.2A43.2A$1116.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.
3A11.3A11.2A12.A10.A1860.A.2A43.2A23.3A$1110.A4.A2.A4.3A6.A4.A.2A5.A
5.3A2.A.A6.3A11.3A11.2A27.A.A7.A1861.3A68.2A27.A$1109.3A6.A4.A.2A5.A
5.3A2.A.A6.3A11.3A11.2A48.A.A1862.2A27.A69.3A22.A$1109.A.2A5.A5.3A2.A
.A6.3A11.3A11.2A1955.3A22.A44.2A.A21.3A$1110.3A2.A.A6.3A11.3A11.2A
1968.2A.A21.3A43.3A22.A.2A$1110.3A11.3A11.2A88.A1893.3A22.A.2A43.2A
23.3A$1103.A6.3A11.2A101.3A1893.2A23.3A68.2A$1102.3A5.2A114.2A.A1918.
2A27.A$1102.A.2A120.3A1877.A69.3A22.A$1103.3A121.2A1876.3A22.A44.2A.A
21.3A$1103.2A1999.2A.A21.3A43.3A22.A.2A$3104.3A22.A.2A43.2A23.3A$
3105.2A23.3A68.2A$1114.3A2013.2A27.A$1114.A2.A4.A5.3A1957.A69.3A22.A$
1105.A8.A6.3A4.A2.A4.A5.3A1942.3A22.A44.2A.A21.3A$1104.3A7.A5.2A.A4.A
6.3A4.A2.A4.A5.3A1927.2A.A21.3A43.3A22.A.2A$1104.A.2A7.A.A2.3A5.A5.2A
.A4.A6.3A4.A2.A4.A5.3A1913.3A22.A.2A43.2A23.3A$1105.3A12.3A6.A.A2.3A
5.A5.2A.A4.A6.3A4.A2.A4.A5.3A1900.2A23.3A68.2A27.A$1105.2A13.3A11.3A
6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A1911.2A27.A69.3A$1121.2A11.3A
11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A1925.3A22.A44.2A.A$1135.2A
11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A1910.2A.A21.3A43.3A$
1149.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A1904.3A22.A.2A43.
2A$1163.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A9.A1894.2A23.3A$1177.2A
11.3A11.3A6.A.A2.3A5.A5.2A.A8.3A1918.2A27.A$1191.2A11.3A11.3A6.A.A2.
3A9.A.2A1875.A69.3A22.A$1205.2A11.3A11.3A10.3A1874.3A22.A44.2A.A21.3A
$1219.2A11.3A10.3A1873.2A.A21.3A43.3A22.A.2A$1233.2A10.3A1873.3A22.A.
2A43.2A23.3A$1245.2A1875.2A23.3A68.2A$3147.2A27.A$3105.A69.3A22.A$
3104.3A22.A44.2A.A21.3A$1230.3A1870.2A.A21.3A43.3A22.A.2A$1216.3A5.A
4.A2.A1870.3A22.A.2A43.2A23.3A$1202.3A5.A4.A2.A4.3A6.A5.3A1863.2A23.
3A68.2A27.A$1188.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.A2.A1887.2A27.A69.3A$
1174.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.A1918.3A22.A44.2A.A$1160.
3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.A3.A4.3A1861.A44.2A.A21.3A
43.3A$1146.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.A3.A3.A2.A
1860.3A43.3A22.A.2A43.2A$1132.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.
3A11.3A11.2A12.A10.A1860.A.2A43.2A23.3A$1126.A4.A2.A4.3A6.A4.A.2A5.A
5.3A2.A.A6.3A11.3A11.2A27.A.A7.A1861.3A68.2A27.A$1125.3A6.A4.A.2A5.A
5.3A2.A.A6.3A11.3A11.2A48.A.A1862.2A27.A69.3A22.A$1125.A.2A5.A5.3A2.A
.A6.3A11.3A11.2A1955.3A22.A44.2A.A21.3A$1126.3A2.A.A6.3A11.3A11.2A
1968.2A.A21.3A43.3A22.A.2A$1126.3A11.3A11.2A88.A1893.3A22.A.2A43.2A
23.3A$1119.A6.3A11.2A101.3A1893.2A23.3A68.2A$1118.3A5.2A114.2A.A1918.
2A27.A$1118.A.2A120.3A1877.A69.3A22.A$1119.3A121.2A1876.3A22.A44.2A.A
21.3A$1119.2A1999.2A.A21.3A43.3A22.A.2A$3120.3A22.A.2A43.2A23.3A$
3121.2A23.3A68.2A$1130.3A2013.2A27.A$1130.A2.A4.A5.3A1957.A69.3A22.A$
1121.A8.A6.3A4.A2.A4.A5.3A1942.3A22.A44.2A.A21.3A$1120.3A7.A5.2A.A4.A
6.3A4.A2.A4.A5.3A1927.2A.A21.3A43.3A22.A.2A$1120.A.2A7.A.A2.3A5.A5.2A
.A4.A6.3A4.A2.A4.A5.3A1913.3A22.A.2A43.2A23.3A$1121.3A12.3A6.A.A2.3A
5.A5.2A.A4.A6.3A4.A2.A4.A5.3A1900.2A23.3A68.2A27.A$1121.2A13.3A11.3A
6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A1911.2A27.A69.3A$1137.2A11.3A
11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A1925.3A22.A44.2A.A$1151.2A
11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A1910.2A.A21.3A43.3A$
1165.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A1904.3A22.A.2A43.
2A$1179.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A9.A1894.2A23.3A$1193.2A
11.3A11.3A6.A.A2.3A5.A5.2A.A8.3A1918.2A27.A$1207.2A11.3A11.3A6.A.A2.
3A9.A.2A1875.A69.3A22.A$1221.2A11.3A11.3A10.3A1874.3A22.A44.2A.A21.3A
$1235.2A11.3A10.3A1873.2A.A21.3A43.3A22.A.2A$1249.2A10.3A1873.3A22.A.
2A43.2A23.3A$1261.2A1875.2A23.3A68.2A$3163.2A27.A$3121.A69.3A22.A$
3120.3A22.A44.2A.A21.3A$1246.3A1870.2A.A21.3A43.3A22.A.2A$1232.3A5.A
4.A2.A1870.3A22.A.2A43.2A23.3A$1218.3A5.A4.A2.A4.3A6.A5.3A1863.2A23.
3A68.2A27.A$1204.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.A2.A1887.2A27.A69.3A$
1190.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.A1918.3A22.A44.2A.A$1176.
3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.A3.A4.3A1861.A44.2A.A21.3A
43.3A$1162.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.A3.A3.A2.A
1860.3A43.3A22.A.2A43.2A$1148.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.
3A11.3A11.2A12.A10.A1860.A.2A43.2A23.3A$1142.A4.A2.A4.3A6.A4.A.2A5.A
5.3A2.A.A6.3A11.3A11.2A27.A.A7.A1861.3A68.2A27.A$1141.3A6.A4.A.2A5.A
5.3A2.A.A6.3A11.3A11.2A48.A.A1862.2A27.A69.3A22.A$1141.A.2A5.A5.3A2.A
.A6.3A11.3A11.2A1955.3A22.A44.2A.A21.3A$1142.3A2.A.A6.3A11.3A11.2A
1968.2A.A21.3A43.3A22.A.2A$1142.3A11.3A11.2A88.A1893.3A22.A.2A43.2A
23.3A$1135.A6.3A11.2A101.3A1893.2A23.3A68.2A$1134.3A5.2A114.2A.A1918.
2A27.A$1134.A.2A120.3A1877.A69.3A22.A$1135.3A121.2A1876.3A22.A44.2A.A
21.3A$1135.2A1999.2A.A21.3A43.3A22.A.2A$3136.3A22.A.2A43.2A23.3A$
3137.2A23.3A68.2A$1146.3A2013.2A27.A$1146.A2.A4.A5.3A1957.A69.3A22.A$
1137.A8.A6.3A4.A2.A4.A5.3A1942.3A22.A44.2A.A21.3A$1136.3A7.A5.2A.A4.A
6.3A4.A2.A4.A5.3A1927.2A.A21.3A43.3A22.A.2A$1136.A.2A7.A.A2.3A5.A5.2A
.A4.A6.3A4.A2.A4.A5.3A1913.3A22.A.2A43.2A23.3A$1137.3A12.3A6.A.A2.3A
5.A5.2A.A4.A6.3A4.A2.A4.A5.3A1900.2A23.3A68.2A27.A$1137.2A13.3A11.3A
6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A1911.2A27.A69.3A$1153.2A11.3A
11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A1925.3A22.A44.2A.A$1167.2A
11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A1910.2A.A21.3A43.3A$
1181.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A1904.3A22.A.2A43.
2A$1195.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A9.A1894.2A23.3A$1209.2A
11.3A11.3A6.A.A2.3A5.A5.2A.A8.3A1918.2A27.A$1223.2A11.3A11.3A6.A.A2.
3A9.A.2A1875.A69.3A22.A$1237.2A11.3A11.3A10.3A1874.3A22.A44.2A.A21.3A
$1251.2A11.3A10.3A1873.2A.A21.3A43.3A22.A.2A$1265.2A10.3A1873.3A22.A.
2A43.2A23.3A$1277.2A1875.2A23.3A68.2A$3179.2A27.A$3137.A69.3A22.A$
3136.3A22.A44.2A.A21.3A$1262.3A1870.2A.A21.3A43.3A22.A.2A$1248.3A5.A
4.A2.A1870.3A22.A.2A43.2A23.3A$1234.3A5.A4.A2.A4.3A6.A5.3A1863.2A23.
3A68.2A27.A$1220.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.A2.A1887.2A27.A69.3A$
1206.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.A1918.3A22.A44.2A.A$1192.
3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.A3.A4.3A1861.A44.2A.A21.3A
43.3A$1178.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.A3.A3.A2.A
1860.3A43.3A22.A.2A43.2A$1164.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.
3A11.3A11.2A12.A10.A1860.A.2A43.2A23.3A$1158.A4.A2.A4.3A6.A4.A.2A5.A
5.3A2.A.A6.3A11.3A11.2A27.A.A7.A1861.3A68.2A27.A$1157.3A6.A4.A.2A5.A
5.3A2.A.A6.3A11.3A11.2A48.A.A1862.2A27.A69.3A22.A$1157.A.2A5.A5.3A2.A
.A6.3A11.3A11.2A1955.3A22.A44.2A.A21.3A$1158.3A2.A.A6.3A11.3A11.2A
1968.2A.A21.3A43.3A22.A.2A$1158.3A11.3A11.2A88.A1893.3A22.A.2A43.2A
23.3A$1151.A6.3A11.2A101.3A1893.2A23.3A68.2A$1150.3A5.2A114.2A.A1918.
2A27.A$1150.A.2A120.3A1877.A69.3A22.A$1151.3A121.2A1876.3A22.A44.2A.A
21.3A$1151.2A1999.2A.A21.3A43.3A22.A.2A$3152.3A22.A.2A43.2A23.3A$
3153.2A23.3A68.2A$1162.3A2013.2A27.A$1162.A2.A4.A5.3A1957.A69.3A22.A$
1153.A8.A6.3A4.A2.A4.A5.3A1942.3A22.A44.2A.A21.3A$1152.3A7.A5.2A.A4.A
6.3A4.A2.A4.A5.3A1927.2A.A21.3A43.3A22.A.2A$1152.A.2A7.A.A2.3A5.A5.2A
.A4.A6.3A4.A2.A4.A5.3A1913.3A22.A.2A43.2A23.3A$1153.3A12.3A6.A.A2.3A
5.A5.2A.A4.A6.3A4.A2.A4.A5.3A1900.2A23.3A68.2A27.A$1153.2A13.3A11.3A
6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A1911.2A27.A69.3A$1169.2A11.3A
11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A1925.3A22.A44.2A.A$1183.2A
11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A1910.2A.A21.3A43.3A$
1197.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A1904.3A22.A.2A43.
2A$1211.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A9.A1894.2A23.3A$1225.2A
11.3A11.3A6.A.A2.3A5.A5.2A.A8.3A1918.2A27.A$1239.2A11.3A11.3A6.A.A2.
3A9.A.2A1875.A69.3A22.A$1253.2A11.3A11.3A10.3A1874.3A22.A44.2A.A21.3A
$1267.2A11.3A10.3A1873.2A.A21.3A43.3A22.A.2A$1281.2A10.3A1873.3A22.A.
2A43.2A23.3A$1293.2A1875.2A23.3A68.2A$3195.2A27.A$3153.A69.3A22.A$
3152.3A22.A44.2A.A21.3A$1278.3A1870.2A.A21.3A43.3A22.A.2A$1264.3A5.A
4.A2.A1870.3A22.A.2A43.2A23.3A$1250.3A5.A4.A2.A4.3A6.A5.3A1863.2A23.
3A68.2A27.A$1236.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.A2.A1887.2A27.A69.3A$
1222.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.A1918.3A22.A44.2A.A$1208.
3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.A3.A4.3A1861.A44.2A.A21.3A
43.3A$1194.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.A3.A3.A2.A
1860.3A43.3A22.A.2A43.2A$1180.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.
3A11.3A11.2A12.A10.A1860.A.2A43.2A23.3A$1174.A4.A2.A4.3A6.A4.A.2A5.A
5.3A2.A.A6.3A11.3A11.2A27.A.A7.A1861.3A68.2A27.A$1173.3A6.A4.A.2A5.A
5.3A2.A.A6.3A11.3A11.2A48.A.A1862.2A27.A69.3A22.A$1173.A.2A5.A5.3A2.A
.A6.3A11.3A11.2A1955.3A22.A44.2A.A21.3A$1174.3A2.A.A6.3A11.3A11.2A
1968.2A.A21.3A43.3A22.A.2A$1174.3A11.3A11.2A88.A1893.3A22.A.2A43.2A
23.3A$1167.A6.3A11.2A101.3A1893.2A23.3A68.2A$1166.3A5.2A114.2A.A1918.
2A27.A$1166.A.2A120.3A1877.A69.3A22.A$1167.3A121.2A1876.3A22.A44.2A.A
21.3A$1167.2A1999.2A.A21.3A43.3A22.A.2A$3168.3A22.A.2A43.2A23.3A$
3169.2A23.3A68.2A$1178.3A2013.2A27.A$1178.A2.A4.A5.3A1957.A69.3A22.A$
1169.A8.A6.3A4.A2.A4.A5.3A1942.3A22.A44.2A.A21.3A$1168.3A7.A5.2A.A4.A
6.3A4.A2.A4.A5.3A1927.2A.A21.3A43.3A22.A.2A$1168.A.2A7.A.A2.3A5.A5.2A
.A4.A6.3A4.A2.A4.A5.3A1913.3A22.A.2A43.2A23.3A$1169.3A12.3A6.A.A2.3A
5.A5.2A.A4.A6.3A4.A2.A4.A5.3A1900.2A23.3A68.2A27.A$1169.2A13.3A11.3A
6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A1911.2A27.A69.3A$1185.2A11.3A
11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A1925.3A22.A44.2A.A$1199.2A
11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A1910.2A.A21.3A43.3A$
1213.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A1904.3A22.A.2A43.
2A$1227.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A9.A1894.2A23.3A$1241.2A
11.3A11.3A6.A.A2.3A5.A5.2A.A8.3A1918.2A27.A$1255.2A11.3A11.3A6.A.A2.
3A9.A.2A1875.A69.3A22.A$1269.2A11.3A11.3A10.3A1874.3A22.A44.2A.A21.3A
$1283.2A11.3A10.3A1873.2A.A21.3A43.3A22.A.2A$1297.2A10.3A1873.3A22.A.
2A43.2A23.3A$1309.2A1875.2A23.3A68.2A$3211.2A27.A$3169.A69.3A22.A$
3168.3A22.A44.2A.A21.3A$1294.3A1870.2A.A21.3A43.3A22.A.2A$1280.3A5.A
4.A2.A1870.3A22.A.2A43.2A23.3A$1266.3A5.A4.A2.A4.3A6.A5.3A1863.2A23.
3A68.2A$1252.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.A2.A1887.2A27.A$1238.3A5.A
4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.A1918.3A22.A$1224.3A5.A4.A2.A4.3A6.A
4.A.2A5.A5.3A2.A.A6.3A11.A3.A4.3A1861.A44.2A.A21.3A$1210.3A5.A4.A2.A
4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.A3.A3.A2.A1860.3A43.3A22.A.2A$
1196.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.2A12.A10.A1860.A
.2A43.2A23.3A$1190.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.2A27.A
.A7.A1861.3A68.2A27.A$1189.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.2A48.A.
A1862.2A27.A69.3A$1189.A.2A5.A5.3A2.A.A6.3A11.3A11.2A1955.3A22.A44.2A
.A$1190.3A2.A.A6.3A11.3A11.2A1968.2A.A21.3A43.3A$1190.3A11.3A11.2A88.
A1893.3A22.A.2A43.2A$1183.A6.3A11.2A101.3A1893.2A23.3A$1182.3A5.2A
114.2A.A1918.2A27.A$1182.A.2A120.3A1877.A69.3A22.A$1183.3A121.2A1876.
3A22.A44.2A.A21.3A$1183.2A1999.2A.A21.3A43.3A22.A.2A$3184.3A22.A.2A
43.2A23.3A$3185.2A23.3A68.2A$1194.3A2013.2A27.A$1194.A2.A4.A5.3A1957.
A69.3A22.A$1185.A8.A6.3A4.A2.A4.A5.3A1942.3A22.A44.2A.A21.3A$1184.3A
7.A5.2A.A4.A6.3A4.A2.A4.A5.3A1927.2A.A21.3A43.3A22.A.2A$1184.A.2A7.A.
A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A1913.3A22.A.2A43.2A23.3A$1185.3A12.
3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A1900.2A23.3A68.2A$1185.2A13.
3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A1911.2A27.A$1201.2A11.3A
11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A1925.3A22.A$1215.2A11.3A
11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A1910.2A.A21.3A$1229.2A11.
3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A1904.3A22.A.2A$1243.2A11.3A
11.3A6.A.A2.3A5.A5.2A.A4.A6.3A9.A1894.2A23.3A$1257.2A11.3A11.3A6.A.A
2.3A5.A5.2A.A8.3A1918.2A27.A$1271.2A11.3A11.3A6.A.A2.3A9.A.2A1875.A
69.3A$1285.2A11.3A11.3A10.3A1874.3A22.A44.2A.A$1299.2A11.3A10.3A1873.
2A.A21.3A43.3A$1313.2A10.3A1873.3A22.A.2A43.2A$1325.2A1875.2A23.3A$
3227.2A27.A$3185.A69.3A22.A$3184.3A22.A44.2A.A21.3A$1310.3A1870.2A.A
21.3A43.3A22.A.2A$1296.3A5.A4.A2.A1870.3A22.A.2A43.2A23.3A$1282.3A5.A
4.A2.A4.3A6.A5.3A1863.2A23.3A68.2A$1268.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.
A2.A1887.2A27.A$1254.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.A1918.3A
22.A$1240.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.A3.A4.3A1861.A
44.2A.A21.3A$1226.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.A3.
A3.A2.A1860.3A43.3A22.A.2A$1212.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A
6.3A11.3A11.2A12.A10.A1860.A.2A43.2A23.3A$1206.A4.A2.A4.3A6.A4.A.2A5.
A5.3A2.A.A6.3A11.3A11.2A27.A.A7.A1861.3A68.2A$1205.3A6.A4.A.2A5.A5.3A
2.A.A6.3A11.3A11.2A48.A.A1862.2A27.A$1205.A.2A5.A5.3A2.A.A6.3A11.3A
11.2A1955.3A22.A$1206.3A2.A.A6.3A11.3A11.2A1968.2A.A21.3A$1206.3A11.
3A11.2A88.A1893.3A22.A.2A$1199.A6.3A11.2A101.3A1893.2A23.3A$1198.3A5.
2A114.2A.A1918.2A27.A$1198.A.2A120.3A1877.A69.3A$1199.3A121.2A1876.3A
22.A44.2A.A$1199.2A1999.2A.A21.3A43.3A$3200.3A22.A.2A43.2A$3201.2A23.
3A$1210.3A2013.2A27.A$1210.A2.A4.A5.3A1957.A69.3A22.A$1201.A8.A6.3A4.
A2.A4.A5.3A1942.3A22.A44.2A.A21.3A$1200.3A7.A5.2A.A4.A6.3A4.A2.A4.A5.
3A1927.2A.A21.3A43.3A22.A.2A$1200.A.2A7.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A
4.A5.3A1913.3A22.A.2A43.2A23.3A$1201.3A12.3A6.A.A2.3A5.A5.2A.A4.A6.3A
4.A2.A4.A5.3A1900.2A23.3A68.2A$1201.2A13.3A11.3A6.A.A2.3A5.A5.2A.A4.A
6.3A4.A2.A4.A5.3A1911.2A27.A$1217.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.
3A4.A2.A4.A5.3A1925.3A22.A$1231.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A
4.A2.A4.A5.3A1910.2A.A21.3A$1245.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.
3A4.A2.A4.A1904.3A22.A.2A$1259.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A
9.A1894.2A23.3A$1273.2A11.3A11.3A6.A.A2.3A5.A5.2A.A8.3A1918.2A$1287.
2A11.3A11.3A6.A.A2.3A9.A.2A1875.A$1301.2A11.3A11.3A10.3A1874.3A22.A$
1315.2A11.3A10.3A1873.2A.A21.3A$1329.2A10.3A1873.3A22.A.2A$1341.2A
1875.2A23.3A$3243.2A27.A$3201.A69.3A$3200.3A22.A44.2A.A$1326.3A1870.
2A.A21.3A43.3A$1312.3A5.A4.A2.A1870.3A22.A.2A43.2A$1298.3A5.A4.A2.A4.
3A6.A5.3A1863.2A23.3A$1284.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.A2.A1887.2A
27.A$1270.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.A1918.3A22.A$1256.3A
5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.A3.A4.3A1861.A44.2A.A21.3A$
1242.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.A3.A3.A2.A1860.
3A43.3A22.A.2A$1228.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.
2A12.A10.A1860.A.2A43.2A23.3A$1222.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.
3A11.3A11.2A27.A.A7.A1861.3A68.2A$1221.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.
3A11.2A48.A.A1862.2A27.A$1221.A.2A5.A5.3A2.A.A6.3A11.3A11.2A1955.3A
22.A$1222.3A2.A.A6.3A11.3A11.2A1968.2A.A21.3A$1222.3A11.3A11.2A88.A
1893.3A22.A.2A$1215.A6.3A11.2A101.3A1893.2A23.3A$1214.3A5.2A114.2A.A
1918.2A$1214.A.2A120.3A1877.A$1215.3A121.2A1876.3A22.A$1215.2A1999.2A
.A21.3A$3216.3A22.A.2A$3217.2A23.3A$1226.3A2013.2A27.A$1226.A2.A4.A5.
3A1957.A69.3A$1217.A8.A6.3A4.A2.A4.A5.3A1942.3A22.A44.2A.A$1216.3A7.A
5.2A.A4.A6.3A4.A2.A4.A5.3A1927.2A.A21.3A43.3A$1216.A.2A7.A.A2.3A5.A5.
2A.A4.A6.3A4.A2.A4.A5.3A1913.3A22.A.2A43.2A$1217.3A12.3A6.A.A2.3A5.A
5.2A.A4.A6.3A4.A2.A4.A5.3A1900.2A23.3A$1217.2A13.3A11.3A6.A.A2.3A5.A
5.2A.A4.A6.3A4.A2.A4.A5.3A1911.2A27.A$1233.2A11.3A11.3A6.A.A2.3A5.A5.
2A.A4.A6.3A4.A2.A4.A5.3A1925.3A22.A$1247.2A11.3A11.3A6.A.A2.3A5.A5.2A
.A4.A6.3A4.A2.A4.A5.3A1910.2A.A21.3A$1261.2A11.3A11.3A6.A.A2.3A5.A5.
2A.A4.A6.3A4.A2.A4.A1904.3A22.A.2A$1275.2A11.3A11.3A6.A.A2.3A5.A5.2A.
A4.A6.3A9.A1894.2A23.3A$1289.2A11.3A11.3A6.A.A2.3A5.A5.2A.A8.3A1918.
2A$1303.2A11.3A11.3A6.A.A2.3A9.A.2A1875.A$1317.2A11.3A11.3A10.3A1874.
3A22.A$1331.2A11.3A10.3A1873.2A.A21.3A$1345.2A10.3A1873.3A22.A.2A$
1357.2A1875.2A23.3A$3259.2A$3217.A$3216.3A22.A$1342.3A1870.2A.A21.3A$
1328.3A5.A4.A2.A1870.3A22.A.2A$1314.3A5.A4.A2.A4.3A6.A5.3A1863.2A23.
3A$1300.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.A2.A1887.2A27.A$1286.3A5.A4.A2.A
4.3A6.A4.A.2A5.A5.3A2.A.A6.A1918.3A$1272.3A5.A4.A2.A4.3A6.A4.A.2A5.A
5.3A2.A.A6.3A11.A3.A4.3A1861.A44.2A.A$1258.3A5.A4.A2.A4.3A6.A4.A.2A5.
A5.3A2.A.A6.3A11.3A11.A3.A3.A2.A1860.3A43.3A$1244.3A5.A4.A2.A4.3A6.A
4.A.2A5.A5.3A2.A.A6.3A11.3A11.2A12.A10.A1860.A.2A43.2A$1238.A4.A2.A4.
3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.2A27.A.A7.A1861.3A$1237.3A6.A4.A.
2A5.A5.3A2.A.A6.3A11.3A11.2A48.A.A1862.2A27.A$1237.A.2A5.A5.3A2.A.A6.
3A11.3A11.2A1955.3A22.A$1238.3A2.A.A6.3A11.3A11.2A1968.2A.A21.3A$
1238.3A11.3A11.2A88.A1893.3A22.A.2A$1231.A6.3A11.2A101.3A1893.2A23.3A
$1230.3A5.2A114.2A.A1918.2A$1230.A.2A120.3A1877.A$1231.3A121.2A1876.
3A22.A$1231.2A1999.2A.A21.3A$3232.3A22.A.2A$3233.2A23.3A$1242.3A2013.
2A$1242.A2.A4.A5.3A1957.A$1233.A8.A6.3A4.A2.A4.A5.3A1942.3A22.A$1232.
3A7.A5.2A.A4.A6.3A4.A2.A4.A5.3A1927.2A.A21.3A$1232.A.2A7.A.A2.3A5.A5.
2A.A4.A6.3A4.A2.A4.A5.3A1913.3A22.A.2A$1233.3A12.3A6.A.A2.3A5.A5.2A.A
4.A6.3A4.A2.A4.A5.3A1900.2A23.3A$1233.2A13.3A11.3A6.A.A2.3A5.A5.2A.A
4.A6.3A4.A2.A4.A5.3A1911.2A27.A$1249.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.
A6.3A4.A2.A4.A5.3A1925.3A$1263.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A
4.A2.A4.A5.3A1910.2A.A$1277.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A
2.A4.A1904.3A$1291.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A9.A1894.2A$
1305.2A11.3A11.3A6.A.A2.3A5.A5.2A.A8.3A$1319.2A11.3A11.3A6.A.A2.3A9.A
.2A1875.A$1333.2A11.3A11.3A10.3A1874.3A22.A$1347.2A11.3A10.3A1873.2A.
A21.3A$1361.2A10.3A1873.3A22.A.2A$1373.2A1875.2A23.3A$3275.2A$3233.A$
3232.3A22.A$1358.3A1870.2A.A21.3A$1344.3A5.A4.A2.A1870.3A22.A.2A$
1330.3A5.A4.A2.A4.3A6.A5.3A1863.2A23.3A$1316.3A5.A4.A2.A4.3A6.A4.A.2A
5.A5.A2.A1887.2A$1302.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.A$1288.3A
5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.A3.A4.3A1861.A$1274.3A5.A4.A
2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.A3.A3.A2.A1860.3A$1260.3A5.A
4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.2A12.A10.A1860.A.2A$1254.A
4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.2A27.A.A7.A1861.3A$1253.3A
6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.2A48.A.A1862.2A27.A$1253.A.2A5.A5.3A
2.A.A6.3A11.3A11.2A1955.3A$1254.3A2.A.A6.3A11.3A11.2A1968.2A.A$1254.
3A11.3A11.2A88.A1893.3A$1247.A6.3A11.2A101.3A1893.2A$1246.3A5.2A114.
2A.A$1246.A.2A120.3A1877.A$1247.3A121.2A1876.3A22.A$1247.2A1999.2A.A
21.3A$3248.3A22.A.2A$3249.2A23.3A$1258.3A2013.2A$1258.A2.A4.A5.3A
1957.A$1249.A8.A6.3A4.A2.A4.A5.3A1942.3A22.A$1248.3A7.A5.2A.A4.A6.3A
4.A2.A4.A5.3A1927.2A.A21.3A$1248.A.2A7.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A
4.A5.3A1913.3A22.A.2A$1249.3A12.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A
5.3A1900.2A23.3A$1249.2A13.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A
5.3A1911.2A$1265.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A$
1279.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A$1293.2A11.3A
11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A$1307.2A11.3A11.3A6.A.A2.3A5.A
5.2A.A4.A6.3A9.A$1321.2A11.3A11.3A6.A.A2.3A5.A5.2A.A8.3A$1335.2A11.3A
11.3A6.A.A2.3A9.A.2A1875.A$1349.2A11.3A11.3A10.3A1874.3A$1363.2A11.3A
10.3A1873.2A.A$1377.2A10.3A1873.3A$1389.2A1875.2A2$3249.A$3248.3A22.A
$1374.3A1870.2A.A21.3A$1360.3A5.A4.A2.A1870.3A22.A.2A$1346.3A5.A4.A2.
A4.3A6.A5.3A1863.2A23.3A$1332.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.A2.A1887.
2A$1318.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.A$1304.3A5.A4.A2.A4.3A
6.A4.A.2A5.A5.3A2.A.A6.3A11.A3.A4.3A1861.A$1290.3A5.A4.A2.A4.3A6.A4.A
.2A5.A5.3A2.A.A6.3A11.3A11.A3.A3.A2.A1860.3A$1276.3A5.A4.A2.A4.3A6.A
4.A.2A5.A5.3A2.A.A6.3A11.3A11.2A12.A10.A1860.A.2A$1270.A4.A2.A4.3A6.A
4.A.2A5.A5.3A2.A.A6.3A11.3A11.2A27.A.A7.A1861.3A$1269.3A6.A4.A.2A5.A
5.3A2.A.A6.3A11.3A11.2A48.A.A1862.2A$1269.A.2A5.A5.3A2.A.A6.3A11.3A
11.2A$1270.3A2.A.A6.3A11.3A11.2A$1270.3A11.3A11.2A88.A$1263.A6.3A11.
2A101.3A$1262.3A5.2A114.2A.A$1262.A.2A120.3A1877.A$1263.3A121.2A1876.
3A$1263.2A1999.2A.A$3264.3A$3265.2A$1274.3A$1274.A2.A4.A5.3A1957.A$
1265.A8.A6.3A4.A2.A4.A5.3A1942.3A22.A$1264.3A7.A5.2A.A4.A6.3A4.A2.A4.
A5.3A1927.2A.A21.3A$1264.A.2A7.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A
1913.3A22.A.2A$1265.3A12.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A
1900.2A23.3A$1265.2A13.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A
1911.2A$1281.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A$1295.
2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A$1309.2A11.3A11.3A
6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A$1323.2A11.3A11.3A6.A.A2.3A5.A5.2A.
A4.A6.3A9.A$1337.2A11.3A11.3A6.A.A2.3A5.A5.2A.A8.3A$1351.2A11.3A11.3A
6.A.A2.3A9.A.2A$1365.2A11.3A11.3A10.3A$1379.2A11.3A10.3A$1393.2A10.3A
$1405.2A2$3265.A$3264.3A$1390.3A1870.2A.A$1376.3A5.A4.A2.A1870.3A$
1362.3A5.A4.A2.A4.3A6.A5.3A1863.2A$1348.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.
A2.A$1334.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.A$1320.3A5.A4.A2.A4.
3A6.A4.A.2A5.A5.3A2.A.A6.3A11.A3.A4.3A1861.A$1306.3A5.A4.A2.A4.3A6.A
4.A.2A5.A5.3A2.A.A6.3A11.3A11.A3.A3.A2.A1860.3A$1292.3A5.A4.A2.A4.3A
6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.2A12.A10.A1860.A.2A$1286.A4.A2.A4.3A
6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.2A27.A.A7.A1861.3A$1285.3A6.A4.A.2A
5.A5.3A2.A.A6.3A11.3A11.2A48.A.A1862.2A$1285.A.2A5.A5.3A2.A.A6.3A11.
3A11.2A$1286.3A2.A.A6.3A11.3A11.2A$1286.3A11.3A11.2A88.A$1279.A6.3A
11.2A101.3A$1278.3A5.2A114.2A.A$1278.A.2A120.3A$1279.3A121.2A$1279.2A
3$1290.3A$1290.A2.A4.A5.3A1957.A$1281.A8.A6.3A4.A2.A4.A5.3A1942.3A$
1280.3A7.A5.2A.A4.A6.3A4.A2.A4.A5.3A1927.2A.A$1280.A.2A7.A.A2.3A5.A5.
2A.A4.A6.3A4.A2.A4.A5.3A1913.3A$1281.3A12.3A6.A.A2.3A5.A5.2A.A4.A6.3A
4.A2.A4.A5.3A1900.2A$1281.2A13.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A
4.A5.3A$1297.2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A$1311.
2A11.3A11.3A6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A5.3A$1325.2A11.3A11.3A
6.A.A2.3A5.A5.2A.A4.A6.3A4.A2.A4.A$1339.2A11.3A11.3A6.A.A2.3A5.A5.2A.
A4.A6.3A9.A$1353.2A11.3A11.3A6.A.A2.3A5.A5.2A.A8.3A$1367.2A11.3A11.3A
6.A.A2.3A9.A.2A$1381.2A11.3A11.3A10.3A$1395.2A11.3A10.3A$1409.2A10.3A
$1421.2A4$1406.3A$1392.3A5.A4.A2.A$1378.3A5.A4.A2.A4.3A6.A5.3A$1364.
3A5.A4.A2.A4.3A6.A4.A.2A5.A5.A2.A$1350.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.
3A2.A.A6.A$1336.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.A3.A4.3A$
1322.3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.A3.A3.A2.A$1308.
3A5.A4.A2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.2A12.A10.A$1302.A4.A
2.A4.3A6.A4.A.2A5.A5.3A2.A.A6.3A11.3A11.2A27.A.A7.A$1301.3A6.A4.A.2A
5.A5.3A2.A.A6.3A11.3A11.2A48.A.A$1301.A.2A5.A5.3A2.A.A6.3A11.3A11.2A$
1302.3A2.A.A6.3A11.3A11.2A$1302.3A11.3A11.2A88.A$1295.A6.3A11.2A101.
3A$1294.3A5.2A114.2A.A$1294.A.2A120.3A$1295.3A121.2A$1295.2A!
[[ TRACK 1/31 -13/31 ]]
Re: 13131: The B-Heptomino/Glider Spaceship Thread
(31,15)c/211 climber (needs some blocks to remove):
Code: Select all
x = 528, y = 405, rule = B3/S23
2bo$obo$b2o7$527bo$525b2o$526b2o73$38bobo$39b2o$39bo7$458bo$458bobo$
458b2o72$77bo$78bo$76b3o8$390bobo$390b2o$391bo72$114bo156b2o$115b2o
154b2o$114b2o7$323bo$322bo$322b3o20$256b2o$256b2o30$241b2o$241b2o21$
153bo$151bobo$152b2o7$226b2o28bo$226b2o26b2o$255b2o29$211b2o$211b2o26$
194bo$193b3o$192b2o2bo!
-
Haycat2009
- Posts: 1053
- Joined: April 26th, 2023, 5:47 am
- Location: Bahar Junction, Zumaland
Re: 13131: The B-Heptomino/Glider Spaceship Thread
MWSS and 1 extra glider are produced. Gives me the idea to redirect the MWSS to the frontend, then use it to build the fuse.C_R_116 wrote: May 4th, 2024, 11:33 pm (31,15)c/211 climber (needs some blocks to remove):Code: Select all
x = 528, y = 405, rule = B3/S23 2bo$obo$b2o7$527bo$525b2o$526b2o73$38bobo$39b2o$39bo7$458bo$458bobo$ 458b2o72$77bo$78bo$76b3o8$390bobo$390b2o$391bo72$114bo156b2o$115b2o 154b2o$114b2o7$323bo$322bo$322b3o20$256b2o$256b2o30$241b2o$241b2o21$ 153bo$151bobo$152b2o7$226b2o28bo$226b2o26b2o$255b2o29$211b2o$211b2o26$ 194bo$193b3o$192b2o2bo!
~ Haycat Durnak, a hard-working editor
Also, support Conway and Friends story mode!
I mean no harm to those who have tested me. But do not take this for granted.
Also, support Conway and Friends story mode!
I mean no harm to those who have tested me. But do not take this for granted.
- glider_rider
- Posts: 197
- Joined: February 20th, 2013, 5:41 pm
- Location: CA
Re: 13131: The B-Heptomino/Glider Spaceship Thread
A prototype fanout mechanism:
The design builds a track pair, plus an extra glider that can presumably be used for the 16x period multiplier (that part will probably be subject to some modification depending on how exactly that ends up working). It consists of 16 subunits that look essentially like this:
Here's the script that was used to generate it:
It still has a few bugs which meant I had to do some hand-patching to make a working pattern: Hopefully those will be fixed soon.
Code: Select all
x = 6358, y = 5577, rule = B3/S23
6356b2o$6355b2o$6357bo82$6248b2o$6247b2o$6249bo82$6140b2o$6139b2o$
6141bo82$6032b2o$6031b2o$6033bo82$5924b2o$5923b2o$5925bo82$5816b2o$
5815b2o$5817bo82$5708b2o$5707b2o$5709bo82$5600b2o$5599b2o$5601bo82$
5492b2o$5491b2o$5493bo82$5384b2o$5383b2o$5385bo82$5276b2o$5275b2o$
5277bo82$5168b2o$5167b2o$5169bo82$5060b2o$5059b2o$5061bo82$4952b2o$
4951b2o$4953bo82$4844b2o$4843b2o$4845bo82$4736b2o$4735b2o$4737bo82$
4628b2o$4627b2o$4629bo82$4520b2o$4519b2o$4521bo82$4412b2o$4411b2o$
4413bo82$4304b2o$4303b2o$4305bo82$4196b2o$4195b2o$4197bo82$4088b2o$
4087b2o$4089bo82$3980b2o$3979b2o$3981bo82$3872b2o$3871b2o$3873bo82$
3764b2o$3763b2o$3765bo82$3656b2o$3655b2o$3657bo82$3548b2o$3547b2o$
3549bo82$3440b2o$3439b2o$3441bo82$3332b2o$3331b2o$3333bo82$3224b2o$
3223b2o$3225bo82$3116b2o$3115b2o$3117bo82$3008b2o$3007b2o$3009bo82$
2900b2o$2899b2o$2901bo82$2792b2o$2791b2o$2793bo82$2684b2o$2683b2o$
2685bo82$2576b2o$2575b2o$2577bo82$2468b2o$2467b2o$2469bo82$2360b2o$
2359b2o$2361bo82$2252b2o$2251b2o$2253bo82$2144b2o$2143b2o$2145bo82$
2036b2o$2035b2o$2037bo72$1955bo$1954b3o$1954bob2o$1955b3o$1955b2o9$
1965b3o$1959b3o2bo2bo$1958bo2bo5bo$1961bo5bo$1961bo2bobo$1958bobo22$
1939bo$1938b3o$1938bob2o$1939b3o$1939b2o9$1949b3o$1943b3o2bo2bo$1942bo
2bo5bo$1887b4o54bo5bo$1887bo3bo53bo2bobo$1887bo54bobo$1888bo2bo6$1978b
3o15$1923bo$1922b3o$1922bob2o$1923b3o$1923b2o9$1933b3o$1927b3o2bo2bo$
1926bo2bo5bo$1929bo5bo$1929bo2bobo$1926bobo22$1907bo$1906b3o$1906bob2o
$1907b3o$1907b2o9$1917b3o$1911b3o2bo2bo$1910bo2bo5bo$1913bo5bo$1913bo
2bobo$1910bobo22$1891bo$1890b3o$1890bob2o$1891b3o$1891b2o9$1901b3o$
1895b3o2bo2bo$1894bo2bo5bo$1897bo5bo$1897bo2bobo$1894bobo22$1875bo$
1874b3o$1874bob2o$1875b3o$1875b2o9$1885b3o$1879b3o2bo2bo$1878bo2bo5bo$
1881bo5bo$1881bo2bobo$1878bobo9$1979b3o$1978bo2bo$1952b3o26bo$1952bo
28bo$1953bo24bobo5$1977b3o$1977bo2bo$1977bo$1977bo$1859bo118bobo$1858b
3o$1858bob2o$1859b3o$1859b2o9$1869b3o$1863b3o2bo2bo$1862bo2bo5bo$1865b
o5bo$1865bo2bobo$1862bobo6$1655b4o$1655bo3bo$1655bo$1656bo2bo303b3o$
1962bo2bo$1965bo$1965bo$1962bobo5$1961b3o$1961bo2bo$1961bo$1961bo$
1843bo118bobo$1842b3o$1842bob2o$1843b3o$1843b2o9$1853b3o$1847b3o2bo2bo
$1846bo2bo5bo$1849bo5bo$1849bo2bobo$1846bobo9$1947b3o$1946bo2bo$1949bo
$1949bo$1946bobo2$1844b3o$1844bo$1845bo$1945b3o$1945bo2bo$1945bo$1945b
o$1827bo118bobo$1826b3o$1826bob2o$1827b3o$1827b2o9$1837b3o$1831b3o2bo
2bo$1830bo2bo5bo$1833bo5bo$1833bo2bobo$1830bobo9$1931b3o$1930bo2bo$
1933bo$1933bo$1930bobo$1794b3o$1794bo2bo$1794bo$1794bo3bo$1794bo3bo
130b3o$1794bo134bo2bo$1795bobo131bo$1929bo$1811bo118bobo$1810b3o$1810b
ob2o$1811b3o$1811b2o$1803b3o$1803bo2bo$1803bo$1803bo3bo$1803bo$1804bob
o3$1821b3o$1815b3o2bo2bo$1814bo2bo5bo$1817bo5bo$1817bo2bobo$1814bobo9$
1915b3o$1914bo2bo$1917bo$1917bo$1914bobo$1778b3o$1778bo2bo$1778bo$
1778bo3bo$1778bo3bo130b3o$1778bo134bo2bo$1779bobo131bo$1913bo$1795bo
118bobo$1794b3o$1740bo53bob2o$1739b2o54b3o$1739bobo53b2o$1787b3o$1787b
o2bo$1787bo$1787bo3bo$1787bo$1788bobo2$1750b3o$1750bo2bo51b3o$1750bo
48b3o2bo2bo$1750bo10b3o34bo2bo5bo$1751bobo7bo39bo5bo$1762bo38bo2bobo$
1798bobo3$1745bo$1744b3o$1744bob2o$1745b3o$1745b2o2$1899b3o$1898bo2bo$
1901bo$1901bo$1898bobo$1762b3o$1755bo6bo2bo$1754b3o5bo$1754bob2o4bo3bo
$1755b3o4bo3bo130b3o$1755b2o5bo134bo2bo$1763bobo131bo$1897bo$1759bo19b
o118bobo$1758b3o17b3o$1757b2obo17bob2o$1757b3o19b3o$1758b2o19b2o$1771b
3o$1771bo2bo$1771bo$1771bo3bo$1771bo$1772bobo2$1734b3o$1734bo2bo51b3o$
1734bo48b3o2bo2bo$1734bo47bo2bo5bo$1735bobo47bo5bo$1785bo2bobo$1782bob
o3$1729bo$1728b3o$1728bob2o$1729b3o$1729b2o2$1883b3o$1882bo2bo$1885bo$
1885bo$1882bobo$1423b4o319b3o$1423bo3bo311bo6bo2bo$1423bo314b3o5bo$
1424bo2bo310bob2o4bo3bo$1739b3o4bo3bo130b3o$1739b2o5bo134bo2bo$1747bob
o131bo$1881bo$1743bo19bo118bobo$1742b3o17b3o$1741b2obo17bob2o$1741b3o
19b3o$1742b2o19b2o$1755b3o$1632bo122bo2bo$1631b2o122bo$1631bobo121bo3b
o$1755bo$1756bobo2$1718b3o$1718bo2bo51b3o$1718bo48b3o2bo2bo$1718bo47bo
2bo5bo$1719bobo47bo5bo$1769bo2bobo$1766bobo3$1713bo$1680b3o29b3o$1680b
o2bo28bob2o$1680bo32b3o$1680bo32b2o$1681bobo$1655bo211b3o$1654b2o210bo
2bo$1654bobo212bo$1869bo$1675bo190bobo$1674b3o53b3o$1674bob2o45bo6bo2b
o$1675b3o44b3o5bo$1675b2o45bob2o4bo3bo$1723b3o4bo3bo130b3o$1680bo42b2o
5bo134bo2bo$1679b2o50bobo131bo$1679bobo183bo$1686b3o38bo19bo118bobo$
1686bo2bo36b3o17b3o$1686bo38b2obo17bob2o$1686bo38b3o19b3o$1687bobo36b
2o19b2o$1739b3o$1739bo2bo$1739bo$1739bo3bo$1739bo$1740bobo2$1702b3o$
1691bo10bo2bo51b3o$1690b3o9bo48b3o2bo2bo$1689b2obo9bo47bo2bo5bo$1689b
3o11bobo47bo5bo$1689b3o61bo2bobo$1690b2o58bobo3$1697bo$1664b3o29b3o$
1664bo2bo28bob2o$1664bo32b3o$1664bo32b2o$1665bobo$1851b3o$1850bo2bo$
1853bo$1853bo$1659bo190bobo$1658b3o53b3o$1658bob2o45bo6bo2bo$1659b3o
44b3o5bo$1659b2o45bob2o4bo3bo$1707b3o4bo3bo130b3o$1707b2o5bo134bo2bo$
1715bobo131bo$1849bo$1670b3o38bo19bo118bobo$1670bo2bo36b3o17b3o$1670bo
38b2obo17bob2o$1670bo38b3o19b3o$1671bobo36b2o19b2o$1723b3o$1723bo2bo$
1723bo$1723bo3bo$1723bo$1524bo199bobo$1523b2o$1523bobo160b3o$1675bo10b
o2bo51b3o$1674b3o9bo48b3o2bo2bo$1673b2obo9bo47bo2bo5bo$1673b3o11bobo
47bo5bo$1673b3o61bo2bobo$1674b2o58bobo3$1681bo$1648b3o29b3o$1648bo2bo
28bob2o$1648bo32b3o$1648bo32b2o$1649bobo$1835b3o$1834bo2bo$1837bo$
1837bo$1547bo95bo190bobo$1546b2o94b3o53b3o$1546bobo93bob2o45bo6bo2bo$
1643b3o44b3o5bo$1643b2o45bob2o4bo3bo$1691b3o4bo3bo130b3o$1691b2o5bo
134bo2bo$1699bobo131bo$1833bo$1654b3o38bo19bo118bobo$1572bo81bo2bo36b
3o17b3o$1571b2o81bo38b2obo17bob2o$1571bobo80bo38b3o19b3o$1655bobo36b2o
19b2o$1707b3o$1707bo2bo$1707bo$1707bo3bo$1707bo$1708bobo2$1670b3o$
1659bo10bo2bo51b3o$1658b3o9bo48b3o2bo2bo$1657b2obo9bo47bo2bo5bo$1657b
3o11bobo47bo5bo$1657b3o61bo2bobo$1658b2o58bobo3$1665bo$1632b3o29b3o$
1632bo2bo28bob2o$1632bo32b3o$1632bo32b2o$1633bobo$1819b3o$1818bo2bo$
1821bo$1821bo$1627bo190bobo$1626b3o53b3o$1626bob2o45bo6bo2bo$1627b3o
44b3o5bo$1627b2o45bob2o4bo3bo$1675b3o4bo3bo130b3o$1675b2o5bo134bo2bo$
1683bobo131bo$1817bo$1638b3o38bo19bo118bobo$1638bo2bo36b3o17b3o$1638bo
38b2obo17bob2o$1638bo38b3o19b3o$1639bobo36b2o19b2o$1691b3o$1691bo2bo$
1691bo$1691bo3bo$1691bo$1692bobo2$1654b3o$1643bo10bo2bo51b3o$1416bo
225b3o9bo48b3o2bo2bo$1415b2o224b2obo9bo47bo2bo5bo$1415bobo223b3o11bobo
47bo5bo$1641b3o61bo2bobo$1642b2o58bobo3$1649bo$1616b3o29b3o$1616bo2bo
28bob2o$1616bo32b3o$1616bo32b2o$1617bobo$1803b3o$1802bo2bo$1805bo$
1805bo$1611bo190bobo$1610b3o53b3o$1610bob2o45bo6bo2bo$1611b3o44b3o5bo$
1439bo171b2o45bob2o4bo3bo$1438b2o219b3o4bo3bo130b3o$1438bobo218b2o5bo
134bo2bo$1667bobo131bo$1801bo$1191b4o427b3o38bo19bo118bobo$1191bo3bo
426bo2bo36b3o17b3o$1191bo430bo38b2obo17bob2o$1192bo2bo426bo38b3o19b3o$
1623bobo36b2o19b2o$1675b3o$1675bo2bo$1675bo$1675bo3bo$1675bo$1676bobo
2$1638b3o$1627bo10bo2bo51b3o$1626b3o9bo48b3o2bo2bo$1625b2obo9bo47bo2bo
5bo$1625b3o11bobo47bo5bo$1625b3o61bo2bobo$1626b2o58bobo3$1633bo$1600b
3o29b3o$1600bo2bo28bob2o$1600bo32b3o$1600bo32b2o$1601bobo$1787b3o$
1786bo2bo$1789bo$1789bo$1595bo190bobo$1594b3o53b3o$1594bob2o45bo6bo2bo
$1595b3o44b3o5bo$1595b2o45bob2o4bo3bo$1643b3o4bo3bo130b3o$1643b2o5bo
134bo2bo$1651bobo131bo$1785bo$1606b3o38bo19bo118bobo$1606bo2bo36b3o17b
3o$1606bo38b2obo17bob2o$1606bo38b3o19b3o$1607bobo36b2o19b2o$1659b3o$
1659bo2bo$1659bo$1659bo3bo$1659bo$1660bobo2$1622b3o$1611bo10bo2bo51b3o
$1610b3o9bo48b3o2bo2bo$1609b2obo9bo47bo2bo5bo$1609b3o11bobo47bo5bo$
1609b3o61bo2bobo$1308bo301b2o58bobo$1307b2o$1307bobo$1617bo$1584b3o29b
3o$1584bo2bo28bob2o$1584bo32b3o$1584bo32b2o$1585bobo$1771b3o$1770bo2bo
$1773bo$1773bo$1579bo190bobo$1578b3o53b3o$1578bob2o45bo6bo2bo$1579b3o
44b3o5bo$1579b2o45bob2o4bo3bo$1627b3o4bo3bo130b3o$1627b2o5bo134bo2bo$
1635bobo131bo$1331bo437bo$1330b2o258b3o38bo19bo118bobo$1330bobo257bo2b
o36b3o17b3o$1590bo38b2obo17bob2o$1590bo38b3o19b3o$1591bobo36b2o19b2o$
1643b3o$1643bo2bo$1643bo$1643bo3bo$1643bo$1644bobo2$1606b3o$1595bo10bo
2bo51b3o$1594b3o9bo48b3o2bo2bo$1593b2obo9bo47bo2bo5bo$1593b3o11bobo47b
o5bo$1593b3o61bo2bobo$1594b2o58bobo3$1601bo$1568b3o29b3o$1568bo2bo28bo
b2o$1568bo32b3o$1568bo32b2o$1569bobo$1755b3o$1754bo2bo$1757bo$1757bo$
1563bo190bobo$1562b3o53b3o$1562bob2o45bo6bo2bo$1563b3o44b3o5bo$1563b2o
45bob2o4bo3bo$1611b3o4bo3bo130b3o$1611b2o5bo134bo2bo$1619bobo131bo$
1753bo$1574b3o38bo19bo118bobo$1574bo2bo36b3o17b3o$1574bo38b2obo17bob2o
$1574bo38b3o19b3o$1575bobo36b2o19b2o$1627b3o$1627bo2bo$1627bo$1627bo3b
o$1627bo$1628bobo2$1590b3o$1579bo10bo2bo51b3o$1578b3o9bo48b3o2bo2bo$
1577b2obo9bo47bo2bo5bo$1577b3o11bobo47bo5bo$1577b3o61bo2bobo$1578b2o
58bobo3$1585bo$1200bo351b3o29b3o$1199b2o351bo2bo28bob2o$1199bobo350bo
32b3o$1552bo32b2o$1553bobo$1739b3o$1738bo2bo$1741bo$1741bo$1547bo190bo
bo$1546b3o53b3o$1546bob2o45bo6bo2bo$1547b3o44b3o5bo$1547b2o45bob2o4bo
3bo$1595b3o4bo3bo130b3o$1595b2o5bo134bo2bo$1603bobo131bo$1737bo$1558b
3o38bo19bo118bobo$1558bo2bo36b3o17b3o$1558bo38b2obo17bob2o$1223bo334bo
38b3o19b3o$1222b2o335bobo36b2o19b2o$1222bobo386b3o$1611bo2bo$1611bo$
1611bo3bo$1611bo$1612bobo2$1574b3o$1563bo10bo2bo51b3o$1562b3o9bo48b3o
2bo2bo$1561b2obo9bo47bo2bo5bo$1561b3o11bobo47bo5bo$1561b3o61bo2bobo$
1562b2o58bobo3$1569bo$1536b3o29b3o$1536bo2bo28bob2o$1536bo32b3o$1536bo
32b2o$1537bobo$1723b3o$1722bo2bo$1725bo$1725bo$1531bo190bobo$1530b3o
53b3o$1530bob2o45bo6bo2bo$1531b3o44b3o5bo$1531b2o45bob2o4bo3bo$1579b3o
4bo3bo130b3o$1579b2o5bo134bo2bo$1587bobo131bo$1721bo$1542b3o38bo19bo
118bobo$1542bo2bo36b3o17b3o$1542bo38b2obo17bob2o$1542bo38b3o19b3o$
1543bobo36b2o19b2o$1595b3o$1595bo2bo$1595bo$959b4o632bo3bo$959bo3bo
631bo$959bo636bobo$960bo2bo$1558b3o$1547bo10bo2bo51b3o$1546b3o9bo48b3o
2bo2bo$1545b2obo9bo47bo2bo5bo$1545b3o11bobo47bo5bo$1545b3o61bo2bobo$
1546b2o58bobo3$1553bo$1520b3o29b3o$1520bo2bo28bob2o$1520bo32b3o$1520bo
32b2o$1092bo428bobo$1091b2o614b3o$1091bobo612bo2bo$1709bo$1709bo$1515b
o190bobo$1514b3o53b3o$1514bob2o45bo6bo2bo$1515b3o44b3o5bo$1515b2o45bob
2o4bo3bo$1563b3o4bo3bo130b3o$1563b2o5bo134bo2bo$1571bobo131bo$1705bo$
1526b3o38bo19bo118bobo$1526bo2bo36b3o17b3o$1526bo38b2obo17bob2o$1526bo
38b3o19b3o$1527bobo36b2o19b2o$1579b3o$1579bo2bo$1115bo463bo$1114b2o
463bo3bo$1114bobo462bo$1580bobo2$1542b3o$1531bo10bo2bo51b3o$1530b3o9bo
48b3o2bo2bo$1529b2obo9bo47bo2bo5bo$1529b3o11bobo47bo5bo$1529b3o61bo2bo
bo$1530b2o58bobo3$1537bo$1504b3o29b3o$1504bo2bo28bob2o$1504bo32b3o$
1504bo32b2o$1505bobo$1691b3o$1690bo2bo$1693bo$1693bo$1499bo190bobo$
1498b3o53b3o$1498bob2o45bo6bo2bo$1499b3o44b3o5bo$1499b2o45bob2o4bo3bo$
1547b3o4bo3bo130b3o$1547b2o5bo134bo2bo$1555bobo131bo$1689bo$1510b3o38b
o19bo118bobo$1510bo2bo36b3o17b3o$1510bo38b2obo17bob2o$1510bo38b3o19b3o
$1511bobo36b2o19b2o$1563b3o$1563bo2bo$1563bo$1563bo3bo$1563bo$1564bobo
2$1526b3o$1515bo10bo2bo51b3o$1514b3o9bo48b3o2bo2bo$1513b2obo9bo47bo2bo
5bo$1513b3o11bobo47bo5bo$1513b3o61bo2bobo$1514b2o58bobo3$1521bo$1488b
3o29b3o$1488bo2bo28bob2o$1488bo32b3o$1488bo32b2o$1489bobo$1675b3o$
1674bo2bo$1677bo$984bo692bo$983b2o498bo190bobo$983bobo496b3o53b3o$
1482bob2o45bo6bo2bo$1483b3o44b3o5bo$1483b2o45bob2o4bo3bo$1531b3o4bo3bo
130b3o$1531b2o5bo134bo2bo$1539bobo131bo$1673bo$1494b3o38bo19bo118bobo$
1494bo2bo36b3o17b3o$1494bo38b2obo17bob2o$1494bo38b3o19b3o$1495bobo36b
2o19b2o$1547b3o$1547bo2bo$1547bo$1547bo3bo$1547bo$1548bobo$1007bo$
1006b2o502b3o$1006bobo490bo10bo2bo51b3o$1498b3o9bo48b3o2bo2bo$1497b2ob
o9bo47bo2bo5bo$1497b3o11bobo47bo5bo$1497b3o61bo2bobo$1498b2o58bobo3$
1505bo$1472b3o29b3o$1472bo2bo28bob2o$1472bo32b3o$1472bo32b2o$1473bobo$
1659b3o$1658bo2bo$1661bo$1661bo$1467bo190bobo$1466b3o53b3o$1466bob2o
45bo6bo2bo$1467b3o44b3o5bo$1467b2o45bob2o4bo3bo$1515b3o4bo3bo130b3o$
1515b2o5bo134bo2bo$1523bobo131bo$1657bo$1478b3o38bo19bo118bobo$1478bo
2bo36b3o17b3o$1478bo38b2obo17bob2o$1478bo38b3o19b3o$1479bobo36b2o19b2o
$1531b3o$1531bo2bo$1531bo$1531bo3bo$1531bo$1532bobo2$1494b3o$1483bo10b
o2bo51b3o$1482b3o9bo48b3o2bo2bo$1481b2obo9bo47bo2bo5bo$1481b3o11bobo
47bo5bo$1481b3o61bo2bobo$1482b2o58bobo3$1489bo$1456b3o29b3o$1456bo2bo
28bob2o$1456bo32b3o$1456bo32b2o$1457bobo$1643b3o$1642bo2bo$1645bo$
1645bo$1451bo190bobo$1450b3o53b3o$1450bob2o45bo6bo2bo$876bo574b3o44b3o
5bo$875b2o574b2o45bob2o4bo3bo$875bobo621b3o4bo3bo130b3o$1499b2o5bo134b
o2bo$1507bobo131bo$1641bo$1462b3o38bo19bo118bobo$1462bo2bo36b3o17b3o$
1462bo38b2obo17bob2o$1462bo38b3o19b3o$1463bobo36b2o19b2o$1515b3o$1515b
o2bo$1515bo$1515bo3bo$1515bo$1516bobo2$1478b3o$1467bo10bo2bo51b3o$
1466b3o9bo48b3o2bo2bo$899bo565b2obo9bo47bo2bo5bo$727b4o167b2o565b3o11b
obo47bo5bo$727bo3bo166bobo564b3o61bo2bobo$727bo738b2o58bobo$728bo2bo2$
1473bo$1440b3o29b3o$1440bo2bo28bob2o$1440bo32b3o$1440bo32b2o$1441bobo$
1627b3o$1626bo2bo$1629bo$1629bo$1435bo190bobo$1434b3o53b3o$1434bob2o
45bo6bo2bo$1435b3o44b3o5bo$1435b2o45bob2o4bo3bo$1483b3o4bo3bo130b3o$
1483b2o5bo134bo2bo$1491bobo131bo$1625bo$1446b3o38bo19bo118bobo$1446bo
2bo36b3o17b3o$1446bo38b2obo17bob2o$1446bo38b3o19b3o$1447bobo36b2o19b2o
$1499b3o$1499bo2bo$1499bo$1499bo3bo$1499bo$1500bobo2$1462b3o$1451bo10b
o2bo51b3o$1450b3o9bo48b3o2bo2bo$1449b2obo9bo47bo2bo5bo$1449b3o11bobo
47bo5bo$1449b3o61bo2bobo$1450b2o58bobo3$1457bo$1424b3o29b3o$1424bo2bo
28bob2o$1424bo32b3o$1424bo32b2o$1425bobo$1611b3o$1610bo2bo$1613bo$
1613bo$1419bo190bobo$1418b3o53b3o$1418bob2o45bo6bo2bo$1419b3o44b3o5bo$
1419b2o45bob2o4bo3bo$1467b3o4bo3bo130b3o$1467b2o5bo134bo2bo$768bo706bo
bo131bo$767b2o840bo$767bobo660b3o38bo19bo118bobo$1430bo2bo36b3o17b3o$
1430bo38b2obo17bob2o$1430bo38b3o19b3o$1431bobo36b2o19b2o$1483b3o$1483b
o2bo$1483bo$1483bo3bo$1483bo$1484bobo2$1446b3o$1435bo10bo2bo51b3o$
1434b3o9bo48b3o2bo2bo$1433b2obo9bo47bo2bo5bo$1433b3o11bobo47bo5bo$
1433b3o61bo2bobo$1434b2o58bobo$791bo$790b2o$790bobo648bo$1408b3o29b3o$
1408bo2bo28bob2o$1408bo32b3o$1408bo32b2o$1409bobo$1595b3o$1594bo2bo$
1597bo$1597bo$1403bo190bobo$1402b3o53b3o$1402bob2o45bo6bo2bo$1403b3o
44b3o5bo$1403b2o45bob2o4bo3bo$1451b3o4bo3bo130b3o$1451b2o5bo134bo2bo$
1459bobo131bo$1593bo$1414b3o38bo19bo118bobo$1414bo2bo36b3o17b3o$1414bo
38b2obo17bob2o$1414bo38b3o19b3o$1415bobo36b2o19b2o$1467b3o$1467bo2bo$
1467bo$1467bo3bo$1467bo$1468bobo2$1430b3o$1419bo10bo2bo51b3o$1418b3o9b
o48b3o2bo2bo$1417b2obo9bo47bo2bo5bo$1417b3o11bobo47bo5bo$1417b3o61bo2b
obo$1418b2o58bobo3$1425bo$1392b3o29b3o$1392bo2bo28bob2o$1392bo32b3o$
1392bo32b2o$1393bobo$1579b3o$1578bo2bo$1581bo$1581bo$1387bo190bobo$
1386b3o53b3o$1386bob2o45bo6bo2bo$1387b3o44b3o5bo$1387b2o45bob2o4bo3bo$
1435b3o4bo3bo130b3o$1435b2o5bo134bo2bo$1443bobo131bo$1577bo$1398b3o38b
o19bo118bobo$1398bo2bo36b3o17b3o$660bo737bo38b2obo17bob2o$659b2o737bo
38b3o19b3o$659bobo737bobo36b2o19b2o$1451b3o$1451bo2bo$1451bo$1451bo3bo
$1451bo$1452bobo2$1414b3o$1403bo10bo2bo51b3o$1402b3o9bo48b3o2bo2bo$
1401b2obo9bo47bo2bo5bo$1401b3o11bobo47bo5bo$1401b3o61bo2bobo$1402b2o
58bobo3$1409bo$1376b3o29b3o$683bo692bo2bo28bob2o$682b2o692bo32b3o$682b
obo691bo32b2o$1377bobo$1563b3o$1562bo2bo$1565bo$1565bo$1371bo190bobo$
1370b3o53b3o$1370bob2o45bo6bo2bo$1371b3o44b3o5bo$1371b2o45bob2o4bo3bo$
1419b3o4bo3bo130b3o$1419b2o5bo134bo2bo$1427bobo131bo$1561bo$1382b3o38b
o19bo118bobo$1382bo2bo36b3o17b3o$1382bo38b2obo17bob2o$1382bo38b3o19b3o
$1383bobo36b2o19b2o$1435b3o$1435bo2bo$1435bo$1435bo3bo$1435bo$1436bobo
2$1398b3o$1387bo10bo2bo51b3o$1386b3o9bo48b3o2bo2bo$1385b2obo9bo47bo2bo
5bo$1385b3o11bobo47bo5bo$1385b3o61bo2bobo$1386b2o58bobo3$1393bo$1360b
3o29b3o$1360bo2bo28bob2o$495b4o861bo32b3o$495bo3bo860bo32b2o$495bo865b
obo$496bo2bo1047b3o$1546bo2bo$1549bo$1549bo$1355bo190bobo$1354b3o53b3o
$1354bob2o45bo6bo2bo$1355b3o44b3o5bo$1355b2o45bob2o4bo3bo$1403b3o4bo3b
o130b3o$1403b2o5bo134bo2bo$1411bobo131bo$1545bo$1366b3o38bo19bo118bobo
$1366bo2bo36b3o17b3o$1366bo38b2obo17bob2o$1366bo38b3o19b3o$1367bobo36b
2o19b2o$1419b3o$552bo866bo2bo$551b2o866bo$551bobo865bo3bo$1419bo$1420b
obo2$1382b3o$1371bo10bo2bo51b3o$1370b3o9bo48b3o2bo2bo$1369b2obo9bo47bo
2bo5bo$1369b3o11bobo47bo5bo$1369b3o61bo2bobo$1370b2o58bobo3$1377bo$
1344b3o29b3o$1344bo2bo28bob2o$1344bo32b3o$1344bo32b2o$1345bobo$575bo
955b3o$574b2o954bo2bo$574bobo956bo$1533bo$1339bo190bobo$1338b3o53b3o$
1338bob2o45bo6bo2bo$1339b3o44b3o5bo$1339b2o45bob2o4bo3bo$1387b3o4bo3bo
130b3o$1387b2o5bo134bo2bo$1395bobo131bo$1529bo$1350b3o38bo19bo118bobo$
1350bo2bo36b3o17b3o$1350bo38b2obo17bob2o$1350bo38b3o19b3o$1351bobo36b
2o19b2o$1403b3o$1403bo2bo$1403bo$1403bo3bo$1403bo$1404bobo2$1366b3o$
1355bo10bo2bo51b3o$1354b3o9bo48b3o2bo2bo$1353b2obo9bo47bo2bo5bo$1353b
3o11bobo47bo5bo$1353b3o61bo2bobo$1354b2o58bobo3$1361bo$1328b3o29b3o$
1328bo2bo28bob2o$1328bo32b3o$1328bo32b2o$1329bobo$1515b3o$1514bo2bo$
1517bo$1517bo$1323bo190bobo$1322b3o53b3o$1322bob2o45bo6bo2bo$1323b3o
44b3o5bo$1323b2o45bob2o4bo3bo$1371b3o4bo3bo130b3o$1371b2o5bo134bo2bo$
1379bobo131bo$1513bo$1334b3o38bo19bo118bobo$1334bo2bo36b3o17b3o$1334bo
38b2obo17bob2o$1334bo38b3o19b3o$1335bobo36b2o19b2o$1387b3o$1387bo2bo$
1387bo$1387bo3bo$1387bo$444bo943bobo$443b2o$443bobo904b3o$1339bo10bo2b
o51b3o$1338b3o9bo48b3o2bo2bo$1337b2obo9bo47bo2bo5bo$1337b3o11bobo47bo
5bo$1337b3o61bo2bobo$1338b2o58bobo3$1345bo$1312b3o29b3o$1312bo2bo28bob
2o$1312bo32b3o$1312bo32b2o$1313bobo$1499b3o$1498bo2bo$1501bo$1501bo$
467bo839bo190bobo$466b2o838b3o53b3o$466bobo837bob2o45bo6bo2bo$1307b3o
44b3o5bo$1307b2o45bob2o4bo3bo$1355b3o4bo3bo130b3o$1355b2o5bo134bo2bo$
1363bobo131bo$1497bo$1318b3o38bo19bo118bobo$1318bo2bo36b3o17b3o$1318bo
38b2obo17bob2o$1318bo38b3o19b3o$1319bobo36b2o19b2o$1371b3o$1371bo2bo$
1371bo$1371bo3bo$1371bo$1372bobo2$1334b3o$1323bo10bo2bo51b3o$1322b3o9b
o48b3o2bo2bo$1321b2obo9bo47bo2bo5bo$1321b3o11bobo47bo5bo$1321b3o61bo2b
obo$1322b2o58bobo3$1329bo$1296b3o29b3o$1296bo2bo28bob2o$1296bo32b3o$
1296bo32b2o$1297bobo$1483b3o$1482bo2bo$1485bo$1485bo$1291bo190bobo$
1290b3o53b3o$1290bob2o45bo6bo2bo$1291b3o44b3o5bo$1291b2o45bob2o4bo3bo$
1339b3o4bo3bo130b3o$1339b2o5bo134bo2bo$1347bobo131bo$1481bo$1302b3o38b
o19bo118bobo$1302bo2bo36b3o17b3o$1302bo38b2obo17bob2o$1302bo38b3o19b3o
$1303bobo36b2o19b2o$1355b3o$1355bo2bo$1355bo$1355bo3bo$1355bo$1356bobo
2$1318b3o$1307bo10bo2bo51b3o$336bo969b3o9bo48b3o2bo2bo$335b2o968b2obo
9bo47bo2bo5bo$335bobo967b3o11bobo47bo5bo$1305b3o61bo2bobo$1306b2o58bob
o3$1313bo$1280b3o29b3o$1280bo2bo28bob2o$1280bo32b3o$1280bo32b2o$1281bo
bo$1467b3o$1466bo2bo$1469bo$1469bo$1275bo190bobo$263b4o1007b3o53b3o$
263bo3bo1006bob2o45bo6bo2bo$263bo1011b3o44b3o5bo$264bo2bo91bo915b2o45b
ob2o4bo3bo$358b2o963b3o4bo3bo130b3o$358bobo962b2o5bo134bo2bo$1331bobo
131bo$1465bo$1286b3o38bo19bo118bobo$1286bo2bo36b3o17b3o$1286bo38b2obo
17bob2o$1286bo38b3o19b3o$1287bobo36b2o19b2o$1339b3o$1339bo2bo$1339bo$
1339bo3bo$1339bo$1340bobo2$1302b3o$1291bo10bo2bo51b3o$1290b3o9bo48b3o
2bo2bo$1289b2obo9bo47bo2bo5bo$1289b3o11bobo47bo5bo$1289b3o61bo2bobo$
1290b2o58bobo3$1297bo$1264b3o29b3o$1264bo2bo28bob2o$1264bo32b3o$1264bo
32b2o$1265bobo$1451b3o$1450bo2bo$1453bo$1453bo$1259bo190bobo$1258b3o
53b3o$1258bob2o45bo6bo2bo$1259b3o44b3o5bo$1259b2o45bob2o4bo3bo$1307b3o
4bo3bo130b3o$1307b2o5bo134bo2bo$1315bobo131bo$1449bo$1270b3o38bo19bo
118bobo$1270bo2bo36b3o17b3o$1270bo38b2obo17bob2o$1270bo38b3o19b3o$
1271bobo36b2o19b2o$1323b3o$1323bo2bo$1323bo$1323bo3bo$1323bo$1324bobo
2$1286b3o$1275bo10bo2bo51b3o$1274b3o9bo48b3o2bo2bo$1273b2obo9bo47bo2bo
5bo$1273b3o11bobo47bo5bo$1273b3o61bo2bobo$228bo1045b2o58bobo$227b2o$
227bobo$1281bo$1248b3o29b3o$1248bo2bo28bob2o$1248bo32b3o$1248bo32b2o$
1249bobo$1435b3o$1434bo2bo$1437bo$1437bo$1243bo190bobo$1242b3o53b3o$
1242bob2o45bo6bo2bo$1243b3o44b3o5bo$1243b2o45bob2o4bo3bo$1291b3o4bo3bo
130b3o$1291b2o5bo134bo2bo$1299bobo131bo$251bo1181bo$250b2o1002b3o38bo
19bo118bobo$250bobo1001bo2bo36b3o17b3o$1254bo38b2obo17bob2o$1254bo38b
3o19b3o$1255bobo36b2o19b2o$1307b3o$1307bo2bo$1307bo$1307bo3bo$1307bo$
1308bobo2$1270b3o$1259bo10bo2bo51b3o$1258b3o9bo48b3o2bo2bo$1257b2obo9b
o47bo2bo5bo$1257b3o11bobo47bo5bo$1257b3o61bo2bobo$1258b2o58bobo3$1265b
o$1232b3o29b3o$1232bo2bo28bob2o$1232bo32b3o$1232bo32b2o$1233bobo$1419b
3o$1418bo2bo$1421bo$1421bo$1227bo190bobo$1226b3o53b3o$1226bob2o45bo6bo
2bo$1227b3o44b3o5bo$1227b2o45bob2o4bo3bo$1275b3o4bo3bo130b3o$1275b2o5b
o134bo2bo$1283bobo131bo$1417bo$1238b3o38bo138bobo$1238bo2bo36b3o$1238b
o38b2obo$1238bo38b3o$1239bobo36b2o$1291b3o$1291bo2bo$1291bo$1291bo3bo$
1291bo$1292bobo2$1254b3o$1243bo10bo2bo$1242b3o9bo$1241b2obo9bo$1241b3o
11bobo$1241b3o$1242b2o3$1249bo$120bo1095b3o29b3o$119b2o1095bo2bo28bob
2o$119bobo1094bo32b3o$1216bo32b2o$1217bobo$1403b3o$1402bo2bo$1405bo$
1405bo$1211bo190bobo$1210b3o53b3o$1210bob2o45bo6bo2bo$1211b3o44b3o5bo$
1211b2o45bob2o4bo3bo$1259b3o4bo3bo130b3o$1259b2o5bo134bo2bo$1267bobo
131bo$1401bo$1222b3o38bo138bobo$1222bo2bo36b3o$1222bo38b2obo$143bo
1078bo38b3o$142b2o1079bobo36b2o$142bobo1130b3o$1275bo2bo$1275bo$1275bo
3bo$1275bo$1276bobo2$1238b3o$1227bo10bo2bo$1226b3o9bo$1225b2obo9bo$
1225b3o11bobo$1225b3o$1226b2o3$1233bo$1200b3o29b3o$1200bo2bo28bob2o$
1200bo32b3o$1200bo32b2o$1201bobo$1387b3o$1386bo2bo$1389bo$1389bo$1195b
o190bobo$1194b3o53b3o$1194bob2o45bo6bo2bo$1195b3o44b3o5bo$1195b2o45bob
2o4bo3bo$1243b3o4bo3bo130b3o$1243b2o5bo134bo2bo$1251bobo131bo$1385bo$
31b4o1171b3o38bo138bobo$31bo3bo1170bo2bo36b3o$31bo1174bo38b2obo$32bo2b
o1170bo38b3o$1207bobo36b2o$1259b3o$1259bo2bo$1259bo$1259bo3bo$1259bo$
1260bobo2$1222b3o$1211bo10bo2bo$1210b3o9bo$1209b2obo9bo$1209b3o11bobo$
1209b3o$1210b2o3$1217bo$1184b3o29b3o$1184bo2bo28bob2o$1184bo32b3o$
1184bo32b2o$12bo1172bobo$11b2o1358b3o$11bobo1356bo2bo$1373bo$1373bo$
1179bo190bobo$1178b3o53b3o$1178bob2o45bo6bo2bo$1179b3o44b3o5bo$1179b2o
45bob2o4bo3bo$1227b3o4bo3bo130b3o$1227b2o5bo134bo2bo$1235bobo131bo$
1369bo$1190b3o38bo138bobo$1190bo2bo36b3o$1190bo38b2obo$1190bo38b3o$
1191bobo36b2o$1243b3o$1243bo2bo$35bo1207bo$34b2o1207bo3bo$34bobo1206bo
$1244bobo2$1206b3o$1195bo10bo2bo$1194b3o9bo$1193b2obo9bo$1193b3o11bobo
$1193b3o$1194b2o3$1201bo$1168b3o29b3o$1168bo2bo28bob2o$1168bo32b3o$
1168bo32b2o$1169bobo$1355b3o$1354bo2bo$1357bo$1357bo$1163bo190bobo$
1162b3o53b3o$1162bob2o45bo6bo2bo$1163b3o44b3o5bo$1163b2o45bob2o4bo3bo$
1211b3o4bo3bo130b3o$1211b2o5bo134bo2bo$1219bobo131bo$1353bo$1174b3o38b
o138bobo$1174bo2bo36b3o$1174bo38b2obo$1174bo38b3o$1175bobo36b2o$1227b
3o$1227bo2bo$1227bo$1227bo3bo$1227bo$1228bobo2$1190b3o$1179bo10bo2bo$
1178b3o9bo$1177b2obo9bo$1177b3o11bobo$1177b3o$1178b2o3$1185bo$1152b3o
29b3o$1152bo2bo28bob2o$1152bo32b3o$1152bo32b2o$1153bobo$1339b3o$1338bo
2bo$1341bo$1341bo$1147bo190bobo$1146b3o53b3o$1146bob2o45bo6bo2bo$1147b
3o44b3o5bo$1147b2o45bob2o4bo3bo$1195b3o4bo3bo130b3o$1195b2o5bo134bo2bo
$1203bobo131bo$1337bo$1158b3o38bo138bobo$1158bo2bo36b3o$1158bo38b2obo$
1158bo38b3o$1159bobo36b2o$1211b3o$1211bo2bo$1211bo$1211bo3bo$1211bo$
1212bobo2$1174b3o$1163bo10bo2bo$1162b3o9bo$1161b2obo9bo$1161b3o11bobo$
1161b3o$1162b2o3$1169bo$1136b3o29b3o$1136bo2bo28bob2o$1136bo32b3o$
1136bo32b2o$1137bobo5$1131bo$1130b3o53b3o$1130bob2o45bo6bo2bo$1131b3o
44b3o5bo$1131b2o45bob2o4bo3bo$1179b3o4bo3bo$1179b2o5bo$1187bobo2$1142b
3o38bo$1142bo2bo36b3o$1142bo38b2obo$1142bo38b3o$1143bobo36b2o$1195b3o$
1195bo2bo$1195bo$1195bo3bo$1195bo$1196bobo2$1158b3o$1147bo10bo2bo$
1146b3o9bo$1145b2obo9bo$1145b3o11bobo$1145b3o$1146b2o3$1153bo$1120b3o
29b3o$1120bo2bo28bob2o$1120bo32b3o$1120bo32b2o$1121bobo5$1115bo$1114b
3o53b3o$1114bob2o45bo6bo2bo$1115b3o44b3o5bo$1115b2o45bob2o4bo3bo$1163b
3o4bo3bo$1163b2o5bo$1171bobo2$1126b3o38bo$1126bo2bo36b3o$1126bo38b2obo
$1126bo38b3o$1127bobo36b2o$1179b3o$1179bo2bo$1179bo$2o1177bo3bo$2o
1177bo$1180bobo2$1142b3o$5b2o1124bo10bo2bo$5b2o1123b3o9bo$1129b2obo9bo
$1129b3o11bobo$1129b3o$1130b2o3$1137bo$1104b3o29b3o$1104bo2bo28bob2o$
1104bo32b3o$1104bo32b2o$1105bobo5$1099bo$1098b3o53b3o$1098bob2o45bo6bo
2bo$1099b3o44b3o5bo$1099b2o45bob2o4bo3bo$1147b3o4bo3bo$1147b2o5bo$
1155bobo2$1110b3o38bo$1110bo2bo36b3o$1110bo38b2obo$1110bo38b3o$1111bob
o36b2o$1163b3o$1163bo2bo$1163bo$1163bo3bo$1163bo$1164bobo2$1126b3o$
1115bo10bo2bo$1114b3o9bo$1113b2obo9bo$1113b3o11bobo$1113b3o$1114b2o3$
1121bo$1088b3o29b3o$1088bo2bo28bob2o$1088bo32b3o$1088bo32b2o$1089bobo
5$1083bo$1082b3o53b3o$1082bob2o45bo6bo2bo$1083b3o44b3o5bo$1083b2o45bob
2o4bo3bo$1131b3o4bo3bo$1131b2o5bo$1139bobo2$1094b3o38bo$1094bo2bo36b3o
$1094bo38b2obo$1094bo38b3o$1095bobo36b2o$1147b3o$1147bo2bo$1147bo$
1147bo3bo$1147bo$1148bobo2$1110b3o$1099bo10bo2bo$1098b3o9bo$1097b2obo
9bo$1097b3o11bobo$1097b3o$1098b2o3$1105bo$1072b3o29b3o$1072bo2bo28bob
2o$1072bo32b3o$1072bo32b2o$1073bobo5$1067bo$1066b3o$1066bob2o45bo$
1067b3o44b3o$1067b2o45bob2o$1115b3o$1115b2o3$1078b3o38bo$1078bo2bo36b
3o$1078bo38b2obo$1078bo38b3o$1079bobo36b2o9$1083bo$1082b3o$1081b2obo$
1081b3o$1081b3o$1082b2o4$1056b3o$1056bo2bo$1056bo$1056bo$1057bobo5$
1051bo$1050b3o$1050bob2o$1051b3o$1051b2o5$1062b3o$1062bo2bo$1062bo$
1062bo$1063bobo9$1067bo$1066b3o$1065b2obo$1065b3o$1065b3o$1066b2o4$
1040b3o$1040bo2bo$1040bo$1040bo$1041bobo5$1035bo$1034b3o$1034bob2o$
1035b3o$1035b2o5$1046b3o$1046bo2bo$1046bo$1046bo$1047bobo9$1051bo$
1050b3o$1049b2obo$16b2o1031b3o$16b2o1031b3o$1050b2o3$21b2o$21b2o!
Code: Select all
import golly as g
from glife import *
import math
import cmath
import os
from scipy import signal
def mod(x,m):
return ((x%m)+m)%m
#Linear algebra stuff
#Wanted to do this myself rather than using a library
#Whether or not this was smart is debatable
#I ended up using scipy instead because it's much faster
#A rational number
class Rational:
#Constructor
def __init__(self, num: int, den: int = 1):
a = math.gcd(num, den)
self.num = (1, -1)[den < 0] * num // a
self.den = abs(den // a)
#Hashing
def __eq__(self, other)->bool:
if isinstance(other, int):
return self.num == other and self.den == 1
elif isinstance(other, Rational):
return self.num == other.num and self.den == other.den
def __hash__(self) -> int:
return hash((self.num,self.den))
#Comparison
def __ne__(self, other)->bool:
if isinstance(other, int):
return self.num != other or self.den != 1
elif isinstance(other, Rational):
return self.num != other.num or self.den != other.den
def __lt__(self, other) -> bool:
if isinstance(other, int | float):
return self.num < other*self.den
elif isinstance(other, Rational):
return self.num*other.den < other.num*self.den
def __le__(self, other) -> bool:
if isinstance(other, int | float):
return self.num <= other*self.den
elif isinstance(other, Rational):
return self.num*other.den <= other.num*self.den
def __gt__(self, other) -> bool:
if isinstance(other, int | float):
return self.num > other*self.den
elif isinstance(other, Rational):
return self.num*other.den > other.num*self.den
def __ge__(self, other) -> bool:
if isinstance(other, int | float):
return self.num >= other*self.den
elif isinstance(other, Rational):
return self.num*other.den >= other.num*self.den
#Arithmetic
def __add__(self, other):
if isinstance(other, int):
return Rational(self.num+other*self.den, self.den)
elif isinstance(other, Rational):
return Rational(self.num*other.den+other.num*self.den, self.den*other.den)
def __sub__(self, other):
if isinstance(other, int):
return Rational(self.num-other*self.den, self.den)
elif isinstance(other, Rational):
return Rational(self.num*other.den-other.num*self.den, self.den*other.den)
def __mul__(self, other):
if isinstance(other, int):
return Rational(self.num*other, self.den)
elif isinstance(other, Rational):
return Rational(self.num*other.num, self.den*other.den)
def __truediv__(self, other):
if isinstance(other, int):
return Rational(self.num, self.den*other)
elif isinstance(other, Rational):
return Rational(self.num*other.den, self.den*other.num)
def __floordiv__(self, other):
return Rational(int(self / other), 1)
def __mod__(self, other):
return (self / other) - (self // other)
def __neg__(self):
return Rational(-self.num, self.den)
def __abs__(self):
return Rational(abs(self.num), self.den)
#Casting
def __int__(self) -> int:
return self.num // self.den
def __float__(self) -> float:
return self.num / self.den
def __str__(self) -> str:
return str(self.num) + "/" + str(self.den)
#Other math
def gcd(*args):
output = abs(args[0])
for i in range(1,len(args)):
output = Rational(math.gcd(output.num, args[i].num), math.lcm(output.den, args[i].den))
return output
#A matrix of rational numbers
class Matrix:
#Constructor
def __init__(self, terms):
#Automatically convert ints to Rationals
self.terms = [[Rational(1) * term for term in row] for row in terms]
self.height = len(terms)
self.width = 0
if self.height > 0:
self.width = len(terms[0])
#Get terms
def sliceRange(s):
if isinstance(s, int):
return range(s,s+1)
elif isinstance(s, slice):
return range(s.start, s.stop)
def __getitem__(self, key: list[int] | list[slice]):
if isinstance(key[0], int) and isinstance(key[1], int):
return self.terms[key[0]][key[1]]
else:
return Matrix([[self.terms[row][col] for col in Matrix.sliceRange(key[1])] for row in Matrix.sliceRange(key[0])])
#Hashing
def __eq__(self, other)->bool:
return self.terms == other.terms
def __hash__(self) -> int:
return hash(tuple(tuple(row) for row in self.terms))
#Arithmetic
def __add__(self, other):
return Matrix([[term1 + term2 for term1, term2 in zip(row1,row2)] for row1, row2 in zip(self.terms,other.terms)])
def __sub__(self, other):
return Matrix([[term1 - term2 for term1, term2 in zip(row1,row2)] for row1, row2 in zip(self.terms,other.terms)])
#Scalar or matrix multiplication
def __mul__(self, other):
if isinstance(other, int | Rational):
return Matrix([[term * other for term in row] for row in self.terms])
elif isinstance(other, Matrix):
return Matrix([[sum([self[rowIndex,sharedIndex]*other[sharedIndex,colIndex] for sharedIndex in range(self.width)], Rational(0)) for colIndex in range(other.width)] for rowIndex in range(self.height)])
elif isinstance(other, CosetMatrix):
return CosetMatrix(self*other.rep, other.lattice)
def __div__(self, other):
return Matrix([[term / other for term in row] for row in self.terms])
def __neg__(self):
return Matrix([[-term for term in row] for row in self.terms])
def transpose(self):
return Matrix([[self[rowIndex,colIndex] for rowIndex in range(self.height)] for colIndex in range(self.width)])
def copy(self):
return Matrix([[term for term in row] for row in self.terms])
def row(self, row: int):
return self[row, 0:self.width]
def col(self, col: int):
return self[0:self.height, col]
def rows(self):
return [self.row(n) for n in range(self.height)]
def cols(self):
return [self.col(n) for n in range(self.width)]
def __str__(self):
output = ""
for row in range(self.height):
output += "["
for col in range(self.width):
output += str(self[row,col])
if col < self.width-1:
output += ","
output += "]"
if row < self.height-1:
output += "\n"
return output
def isZero(self):
return all(all(term == 0 for term in row) for row in self.terms)
#Tools for making block matrices
def blockHorizontal(self, other):
return Matrix([row1+row2 for row1,row2 in zip(self.terms, other.terms)])
def blockVertical(self, other):
return Matrix(self.terms+other.terms)
#Row reduction
def rowReduce(self):
output = self.copy()
rowIndex = 0
colIndex = 0
while rowIndex < output.height and colIndex < output.width:
#Check if this column is zero below rowIndex, if so goto next column
nonzeroRowIndex = next((rowCheckIndex for rowCheckIndex in range(rowIndex, output.height) if output[rowCheckIndex,colIndex] != 0), -1)
if nonzeroRowIndex == -1:
colIndex += 1
else:
#Otherwise, do a row-reduction step
#Swap rows rowIndex and nonzeroRowIndex if needed
if nonzeroRowIndex != rowIndex:
output.swapRowsInPlace(rowIndex, nonzeroRowIndex)
#Normalize to 1
divideByVal = output[rowIndex, colIndex]
output.terms[rowIndex] = [term / divideByVal for term in output.terms[rowIndex]]
for otherRowIndex in range(output.height):
if otherRowIndex != rowIndex:
output.terms[otherRowIndex] = [otherRowTerm - rowTerm * output[otherRowIndex, colIndex] for rowTerm, otherRowTerm in zip(output.terms[rowIndex], output.terms[otherRowIndex])]
rowIndex += 1
return output
def swapRowsInPlace(self, row1: int, row2: int):
self.terms[row1], self.terms[row2] = self.terms[row2], self.terms[row1]
def removeZeroRows(self):
return Matrix([row for row in self.terms if not all(term == 0 for term in row)])
def det(self):
rowReducedForm = self.rowReduce()
return math.prod([rowReducedForm[i,i] for i in range(rowReducedForm.width)])
def rank(self):
return len([row for row in self.terms if not all(term == 0 for term in row)])
def id(n: int):
return Matrix([[Rational(int(row == col)) for col in range(n)] for row in range(n)])
def zero(height: int, width: int):
return Matrix([[Rational(0) for col in range(width)] for row in range(height)])
#Gives the inverse of an invertible square matrix
def inverse(self):
return self.blockHorizontal(Matrix.id(self.width)).rowReduce()[0:self.height,self.width:self.width*2]
#Gives a right inverse
def rightInverse(self):
transpose = self.transpose()
return transpose * (self * transpose).inverse()
#Row reduction but we can only use integer multiples
def integerRowReduce(self):
output = self.copy()
rowIndex = 0
colIndex = 0
while rowIndex < output.height and colIndex < output.width:
#Check if this column is zero below rowIndex, if so goto next column
existsANonzeroEntry = False
rowToTest = rowIndex
while rowToTest < output.height:
if output[rowToTest, colIndex] > 0:
#Found a nonzero entry
existsANonzeroEntry = True
if rowToTest == rowIndex:
#On the starting row, so we don't do much
rowToTest += 1
else:
if output[rowIndex, colIndex] < output[rowToTest, colIndex]:
#swap rows
output.swapRowsInPlace(rowIndex, rowToTest)
else:
#subtract as many terms[rowToTest] from terms[rowIndex] as possible
mult = output[rowIndex, colIndex] // output[rowToTest, colIndex]
output.terms[rowIndex] = [term - testTerm * mult for term, testTerm in zip(output.terms[rowIndex],output.terms[rowToTest])]
elif output[rowToTest, colIndex] < 0:
#Switch sign of this row
output.terms[rowToTest] = [-term for term in output.terms[rowToTest]]
else:
#Entry cleared, move to next row
rowToTest += 1
if existsANonzeroEntry and rowIndex < output.height and colIndex < output.width and output[rowIndex, colIndex] != 0:
#Subtract as much from the rows < rowIndex as possible while leaving the term positive
for rowToModify in range(rowIndex):
mult = output[rowToModify, colIndex] // output[rowIndex, colIndex]
output.terms[rowToModify] = [termToModify - term * mult for term, termToModify in zip(output.terms[rowIndex],output.terms[rowToModify])]
rowIndex += 1
else:
colIndex += 1
return output
#A lattice of rational points
class Lattice:
#Constructor
def __init__(self, basis: Matrix, rowReduceBasis: bool = True):
#Do integer row reduction for our basis by default
if rowReduceBasis:
self.basis = basis.integerRowReduce().removeZeroRows()
else:
self.basis = basis.copy()
self.dimension = self.basis.width
self.rank = self.basis.height
#Find pivot columns
#The index of the first nonzero column in each row
self.pivots = [[x != 0 for x in row].index(True) for row in self.basis.terms]
#Find inverse of the generator matrix
self.changeOfBasis = self.basis.rightInverse()
#Gets canonical coset representative for a matrix
def getCosetRepresentative(self, matrix: Matrix) -> Matrix:
output = matrix.copy()
for matrixRowIndex in range(matrix.height):
for rowIndex in range(len(self.pivots)):
colIndex = self.pivots[rowIndex]
generatorValue = self.basis[rowIndex,colIndex]
matrixValue = output[matrixRowIndex,colIndex]
output.terms[matrixRowIndex] = [output[matrixRowIndex,termIndex] - self.basis[rowIndex,termIndex] * (matrixValue // generatorValue) for termIndex in range(matrix.width)]
return output
#Does this lattice group contain a given row vector
def __contains__(self, vector: Matrix) -> bool:
return self.getCosetRepresentative(vector).isZero()
#Sum of two lattices
def __add__(self, other):
return Lattice(self.basis.blockVertical(other.basis))
def addGenerators(self, basisVectors: Matrix):
return Lattice(self.basis.blockVertical(basisVectors))
#Gets coordinates of the row vectors in a matrix where all row vectors are in this lattice
def getCoordinates(self, matrix: Matrix) -> Matrix:
return matrix * self.changeOfBasis
#Whether or not this lattice contains a multiple of the row vector for each row of a given matrix
def containsMultiple(self, matrix: Matrix) -> bool:
return self.getCoordinates(matrix) * self.basis == matrix
#The intersection of self with the plane other lies in
def intersectWithPlane(self,other):
#add in extra coordinates that don't lie in this plane
otherExtraBasis = other.basis
n = 0
while otherExtraBasis.height < otherExtraBasis.width:
testVector = Matrix([[Rational(int(a==n)) for a in range(otherExtraBasis.width)]])
n += 1
if not Lattice(otherExtraBasis).containsMultiple(testVector):
otherExtraBasis = testVector.blockVertical(otherExtraBasis)
otherExtraBasisInverse = otherExtraBasis.inverse()
basisInOtherCoordsReduced = (self.basis * otherExtraBasisInverse).integerRowReduce()
#Isolate only the rows that don't rely on the first few terms
basisInPlaneInOtherCoords = Matrix([row for row in basisInOtherCoordsReduced.terms if all(row[i]==0 for i in range(other.basis.width - other.basis.height))])
#Convert from coordinates
basisInPlane = basisInPlaneInOtherCoords * otherExtraBasis
return Lattice(basisInPlane)
#The dual of a lattice
def dual(self):
return Lattice(self.changeOfBasis.transpose(), False)
#The intersection of two lattices
def __and__(self, other):
return (self.dual() + other.dual()).dual().intersectWithPlane(self).intersectWithPlane(other)
#The lattice of integer divisors of a given lattice
def divisorLattice(self):
return LatticeGroup(Matrix.id(self.dimension)).intersectWithPlane(self)
#A basis for the torsion-free part of G/H
#Output as a matrix with rows v s.t. v+H form our basis
def quotientTorsionFreeBasis(self, sublattice):
divisorLattice = self.intersectWithPlane(sublattice)
divisorLatticeBasisExtended = divisorLattice.basis
nonPivots = [x for x in range(divisorLattice.dimension) if x not in divisorLattice.pivots]
for nonPivot in nonPivots:
divisorLatticeBasisExtended = self.basis.row(nonPivot).blockVertical(divisorLatticeBasisExtended)
divisorLatticeBasisExtendedInverse = divisorLatticeBasisExtended.inverse()
basisVectorsInDivisorLatticeExtendedCoordsReduced = (self.basis * divisorLatticeBasisExtendedInverse).integerRowReduce()
nonPivotBasisVectorsToCoords = basisVectorsInDivisorLatticeExtendedCoordsReduced[0:(divisorLattice.dimension-divisorLattice.rank),0:divisorLattice.dimension]
return CosetMatrix((nonPivotBasisVectorsToCoords * divisorLatticeBasisExtended).integerRowReduce(), sublattice)
#The torsion elements of G/H
def quotientTorsionElements(self, sublattice):
#We know these are all in divisorLattice
divisorLattice = self.intersectWithPlane(sublattice)
intermediateLattice = sublattice
#Find torsion of all basis elements
generators = Matrix([])
torsions = []
for basisElt in divisorLattice.basis.rows():
#Find the torsion of this basis element in the intermediate lattice
basisEltCoords = basisElt * intermediateLattice.changeOfBasis
#Torsion is the gcd of the elements of basisEltCoords
torsion = Rational.gcd(*basisEltCoords.terms[0]).den
torsions.append(torsion)
generators = generators.blockVertical(basisElt)
intermediateLattice = intermediateLattice.addGenerators(basisElt)
#Output as an iterator
def outputGenerator(basisElts, torsions):
multiplicities = [0 for torsion in torsions]
while True:
yield CosetMatrix(Matrix([multiplicities]) * basisElts, sublattice)
#Increment
index = 0
multiplicities[0]+=1
while index < len(multiplicities) and multiplicities[index] == torsions[index]:
multiplicities[index] = 0
index += 1
if index < len(multiplicities):
multiplicities[index]+=1
if index == len(multiplicities):
break
return outputGenerator(basisElts, torsions)
#Generators for G/H, with torsions (0 if torsion-free)
def quotientGeneratorsWithTorsions(self, sublattice):
#We know these are all in divisorLattice
divisorLattice = self.intersectWithPlane(sublattice)
intermediateLattice = sublattice
#Find torsion of all basis elements
generators = Matrix([])
torsions = []
for basisElt in divisorLattice.basis.rows():
#Find the torsion of this basis element in the intermediate lattice
basisEltCoords = basisElt * intermediateLattice.changeOfBasis
#Torsion is the gcd of the elements of basisEltCoords
torsion = Rational.gcd(*basisEltCoords.terms[0]).den
#if torsion != 1:
torsions.append(torsion)
generators = generators.blockVertical(basisElt)
intermediateLattice = intermediateLattice.addGenerators(basisElt)
#Add in the torsion-free basis
#return list(zip([CosetMatrix(row, sublattice) for row in generators.rows()], torsions)) + [(row,0) for row in self.quotientTorsionFreeBasis(sublattice).rows()]
return list(zip(generators.rows(), torsions)) + [(row.rep,0) for row in self.quotientTorsionFreeBasis(sublattice).rows()]
#Divides an envelope into a dictionary of cosets by a lattice
def divideIntoCosets(self, envelope):
output = dict()
for v in envelope:
key = CosetMatrix(v, self)
if key in output:
output[key].append(v)
else:
output[key] = [v]
#g.warn("".join(str(k.rep)+": "+str([str(x) for x in v])+"\n\n" for k,v in output.items()))
return output
#A matrix of lattice cosets of the form v+H
class CosetMatrix:
#Constructor
def __init__(self, rep: Matrix, lattice: Lattice):
self.lattice = lattice
self.rep = lattice.getCosetRepresentative(rep)
self.width = self.rep.width
self.height = self.rep.height
#Hashing
def __hash__(self) -> int:
return hash((self.rep))
def __eq__(self, other) -> bool:
return self.rep == other.rep
def __ne__(self, other) -> bool:
return self.rep != other.rep
#Arithmetic
def __add__(self, other) -> bool:
if isinstance(other, CosetMatrix):
return CosetMatrix(self.rep+other.rep, self.lattice)
elif isinstance(other, Matrix):
return CosetMatrix(self.rep+other, self.lattice)
def __sub__(self, other) -> bool:
if isinstance(other, CosetMatrix):
return CosetMatrix(self.rep-other.rep, self.lattice)
elif isinstance(other, Matrix):
return CosetMatrix(self.rep-other, self.lattice)
def __neg__(self) -> bool:
return CosetMatrix(-self.rep, self.lattice)
#Matrix multiplication
#Note: We also multiply the lattice basis
def __mul__(self, other):
return CosetMatrix(self.rep * other, Lattice(self.lattice.basis * other))
def rows(self):
return [CosetMatrix(row, self.lattice) for row in self.rep.rows()]
#A function from Z^n -> int
class LatticeFunction:
def __init__(self, data, dimension):
self.data = data
self.dimension = dimension
self.minCoords = [min(int(key[0,i]) for key,value in self.data.items()) for i in range(self.dimension)]
self.maxCoords = [max(int(key[0,i]) for key,value in self.data.items()) for i in range(self.dimension)]
self.coordDiffs = [x-y for x,y in zip(self.maxCoords, self.minCoords)]
#Convolve using Fourier transform
def convolve(self, other):
#Find amounts to wrap around
#These must be wrapArounds[i] a power of 2 satisfying wrapArounds[i] > self.coordDiffs[i] + other.coordDiffs[i]
#wrapArounds = [1<<(x+y).bit_length() for x,y in zip(self.coordDiffs, other.coordDiffs)]
wrapArounds = [x+y+1 for x,y in zip(self.coordDiffs, other.coordDiffs)]
#return LatticeFunction.unwrapData(LatticeFunction.fft([x*y for x,y in zip(LatticeFunction.fft(self.wrapData(wrapArounds), 1, 1), LatticeFunction.fft(other.wrapData(wrapArounds), 1, 1))], -1, 0.5), wrapArounds, Matrix([self.minCoords])+Matrix([other.minCoords]))
selfData = self.wrapData(wrapArounds)
otherData = other.wrapData(wrapArounds)
g.show("Convolving with length " + str(math.prod(wrapArounds)) + " " + str(tuple(wrapArounds)) + "...")
return LatticeFunction.unwrapData(signal.fftconvolve(selfData, otherData), wrapArounds, Matrix([self.minCoords])+Matrix([other.minCoords]))
#Wraps data to a list, where wrapArounds[i] are our sufficiently large powers of 2
def wrapData(self, wrapArounds):
g.show("Wrapping...")
wrapAroundsCumulative = [math.prod(wrapArounds[0:i]) for i in range(len(wrapArounds)+1)]
output = [0 for x in range(math.prod(wrapArounds))]
#Edit output.data
for key, value in self.data.items():
#Offset by self.minCoords so that indices are all positive
keyIndex = sum(mod(int(key[0,i] - self.minCoords[i]), wrapArounds[i])*wrapAroundsCumulative[i] for i in range(self.dimension))
output[keyIndex] = value
return output
#1-dimensional fast Fourier transform of an array of length 2^n
#Using the Cooley-Tukey algorithm
#I don't actually use this because signal.fftconvolve is faster but it was fun to implement
numFFTs = 0
def fft(data, sign: int = 1, scalePerStep = 1):
outputData = data.copy()
dataSize = len(outputData).bit_length() - 1
#Precompute twiddle factors
g.show("FFT " + str(LatticeFunction.numFFTs+1) + "/12: Computing twiddle factors...")
twiddleFactors = [cmath.exp(-sign * 2j * math.pi * k / (1 << dataSize)) for k in range(1 << dataSize)]
for step in range(0,dataSize):
g.show("FFT " + str(LatticeFunction.numFFTs+1) + "/12: " + str(step) + "/" + str(dataSize))
nextData = []
splitPos = dataSize - step - 1
splitPosMaskBit = 1 << splitPos
belowSplitPosMask = splitPosMaskBit - 1
aboveSplitPosMask = ((1 << (dataSize-1)) - 1) & ~belowSplitPosMask
for i in range(len(outputData)):
#Input indices
#How this works: Take i, split into before and after parts at data-step-1, bitshift after part up 1, insert a 0 or 1 bit
lowerInputIndex = (i & belowSplitPosMask) | ((i & aboveSplitPosMask) << 1)
upperInputIndex = lowerInputIndex | splitPosMaskBit
#Parity
paritySign = 1 - ((i >> (dataSize - 1)) << 1)
#Twiddle factor index
k = i & aboveSplitPosMask
#print(str(step) + ", " + str(i) + ": " + str(lowerInputIndex) + ", " + str(upperInputIndex) + str(" ") + str(k) + ", " + str(twiddleFactor))
nextData.append((outputData[lowerInputIndex] + paritySign * twiddleFactors[k] * outputData[upperInputIndex]) * scalePerStep)
#Progress bar for my sanity
outputData = nextData
g.show("FFT " + str(LatticeFunction.numFFTs) + "/6: " + str(dataSize) + "/" + str(dataSize))
LatticeFunction.numFFTs += 1
return outputData
#Unwrap a list to a LatticeFunction (rounding to ints)
def unwrapData(data, wrapArounds, offset):
g.show("Unwrapping...")
wrapAroundsCumulative = [math.prod(wrapArounds[0:i]) for i in range(len(wrapArounds)+1)]
outputData = {}
for keyIndex in range(len(data)):
if not cmath.isclose(data[keyIndex], 0, rel_tol=1e-09, abs_tol=1e-09):
#Nonzero entry
key = Matrix([[mod(keyIndex // wrapAroundsCumulative[i], wrapArounds[i]) for i in range(len(wrapArounds))]]) + offset
outputData[key] = round(data[keyIndex].real)
return LatticeFunction(outputData, len(wrapArounds))
#Wraps data to a function on a quotient group
def wrapToQuotientFunction(self, group, sign: int = 1):
outputData = {}
for key,value in self.data.items():
quotientKey = CosetMatrix(key * group.optimalLatticeBasis * sign, group.sublattice)
if quotientKey in outputData:
outputData[quotientKey] += value
else:
outputData[quotientKey] = value
return QuotientGroupFunction(group, outputData)
#A quotient of lattices
class QuotientGroup:
def __init__(self, lattice: Lattice, sublattice: Lattice):
#On initialization, organize
self.lattice = lattice
self.sublattice = sublattice
self.generatorsWithTorsions = lattice.quotientGeneratorsWithTorsions(sublattice)
#Find optimal basis for compact unwrapping
# I'm pretty sure this is actually pretty optimal for our purposes
self.optimalLatticeBasis = self.lattice.basis
self.optimalChangeOfBasis = self.optimalLatticeBasis.rightInverse()
#Other thing I considered, seems worse though
#self.optimalLatticeBasis = Matrix([generator.terms[0] for generator, torsion in self.generatorsWithTorsions])
#g.warn(str(self.lattice.basis) + "\n\n" + str(self.sublattice.basis) + "\n\n" + str(self.optimalLatticeBasis))
#A function from G/H -> int
class QuotientGroupFunction:
def __init__(self, group: QuotientGroup, data):
self.group = group
#A dictionary from cosets v+group.sublattice to ints
self.data = data
#Unwraps to a LatticeFunction
def unwrap(self):
return LatticeFunction({key.rep * self.group.optimalChangeOfBasis: self.data[key] for key in self.data}, self.group.optimalChangeOfBasis.width)
#Wraps to a further quotient
def wrapToQuotientFunction(self, group, sign: int = 1):
outputData = {}
for key,value in self.data.items():
quotientKey = CosetMatrix(key.rep * group.optimalLatticeBasis * sign, group.sublattice)
if quotientKey in outputData:
outputData[quotientKey] += value
else:
outputData[quotientKey] = value
return QuotientGroupFunction(group, outputData)
#Function convolution
def convolve(self, other):
return self.unwrap().convolve(other.unwrap()).wrapToQuotientFunction(self.group)
#Golly misc help stuff
#Helpful conversions
def toCellSet(cellList):
return {(cellList[i],cellList[i+1]) for i in range(0,len(cellList),2)}
def toCellList(cellSet):
return [num for x,y in cellSet for num in [x,y]]
#nonempty getrect
def getrect():
if g.empty():
return [0,0,1,1]
return g.getrect()
#This is just convenient
def gethash():
return g.hash(getrect())
def getcells():
return g.getcells(getrect())
#Does the pattern contain a given cell list
def patternContains(cellList, x=0, y=0):
return toCellSet(g.transform(cellList,x,y)).issubset(toCellSet(getcells()))
#Tools for pattern decomposition into components
#For a decomposition of Child(p) = DisjointUnion(q_i)
# Returns a decomposition of this pattern as p = DisjointUnion(p_j) such that Child(p_j) = DisjointUnion(q_{i_{j,k}})
# All inputs and outputs are given as cell sets
nbhd = {(x,y) for x in range(-1,2) for y in range(-1,2)}
def findSubpatterns(patternState, childDecomposition):
#Start by decomposing into connected components
#output = findConnectedComponents(patternState, {(x,y) for x in range(-1,2) for y in range(-1,2)})
output = set()
for cell in patternState:
nbhdOfCell = {(cell[0]+x,cell[1]+y) for x,y in nbhd}
#Check against all children in childDecomposition
requiredCells = {cell}
for childCellSet in childDecomposition:
if not nbhdOfCell.isdisjoint(childCellSet):
#This child's component must contain patternState intersect nbhd(childCellSet)
requiredCells |= patternState & set().union(*[{(a[0]+b[0],a[1]+b[1]) for a in nbhd} for b in childCellSet])
#We require all these cells in our component
componentsToUnionWith = {component for component in output if not requiredCells.isdisjoint(component)}
output -= componentsToUnionWith
output.add(frozenset({cell}.union(*componentsToUnionWith)))
#Additionally, unionize any components around cells that don't match
evolvedState = set().union(*childDecomposition)
evolvedComponentStatesUnion = set().union(*[toCellSet(g.evolve(toCellList(component),1)) for component in output])
error = evolvedState ^ evolvedComponentStatesUnion
for errorCell in error:
nbhdOfCell = {(errorCell[0]+x,errorCell[1]+y) for x,y in nbhd}
#Unionize all components intersecting nbhdOfCell
componentsToUnionWith = {component for component in output if not nbhdOfCell.isdisjoint(component)}
output -= componentsToUnionWith
output.add(frozenset().union(*componentsToUnionWith))
return output
#Removes unneccessary cells from the evolution of this pattern (requiring patFinalState in the final result)
def removeAshCells(patEvolution, patFinalState):
#Find the indepdenent subpatterns of this at each stage
patFinalStateCellSet = frozenset(toCellSet(patFinalState))
patFinalStateCellSetWithExtra = frozenset(toCellSet(g.evolve(patEvolution[len(patEvolution)-1], 1)))
patFinalDecomposition = {patFinalStateCellSet} | {frozenset({cell}) for cell in patFinalStateCellSetWithExtra - patFinalStateCellSet}
patDecompositions = [patFinalDecomposition]
for i in reversed(range(len(patEvolution))):
#Find the prior decomposition
prevDecomposition = findSubpatterns(toCellSet(patEvolution[i]), patDecompositions[0])
patDecompositions.insert(0, prevDecomposition)
#Construct list of only the minimal decompositions leading to patFinalState
minComponents = [patFinalStateCellSet]
for i in reversed(range(len(patEvolution))):
#Need component intersects nbhd(minComponents[0])
try:
prevMinComponent = next(component for component in patDecompositions[i] if not component.isdisjoint(set().union(*[{(a[0]+b[0],a[1]+b[1]) for a in nbhd} for b in minComponents[0]])))
minComponents.insert(0, prevMinComponent)
except StopIteration:
#This only happens when our cell has no predecessors
#This isn't common, but can occur when we add in components mid-evolution
continue
#Convert back to cell lists, remove the last component
return [toCellList(component) for component in minComponents[0:len(minComponents)-1]]
cellLattice = Lattice(Matrix.id(3))
#A periodic pattern with inputs and outputs
class PeriodicPattern:
def __init__(self, cellList, dT, dX, dY, inputs = [], outputs = [], computeExtras = False):
self.dX = dX
self.dY = dY
self.dT = dT
self.inputs = inputs
self.outputs = outputs
self.periodVector = Matrix([[self.dT, -self.dX, -self.dY]])
self.periodLattice = Lattice(self.periodVector)
self.positionGroup = QuotientGroup(cellLattice, self.periodLattice)
#Find states
currentState = cellList.copy()
self.state = []
g.setrule("B3/S23")
for t in range(self.dT):
#Remove all outputs on this generation from currentState
#TODO: Could be nice to add a way for outputs to be removed 'late'/after a full cycle
# Or generally for the pattern to 'fill in' over multiple cycles, so that sparks are covered too
for outputTimeToRemove, outputPattern, outputPosition in outputs:
if outputTimeToRemove == t:
currentState = outputPattern.joinInto(currentState, outputPosition, "andnot")
self.state.append(currentState)
#Join all inputs on this generation to currentState
for inputTimeToAdd, inputPattern, inputPosition in inputs:
if inputTimeToAdd == t:
currentState = inputPattern.joinInto(currentState, inputPosition, "or")
currentState = g.evolve(currentState, 1)
if computeExtras:
#Precompute some envelopes for collision purposes
g.setrule("B12345678/S012345678")
self.envelopeA = LatticeFunction(dict.fromkeys({Matrix([[t,-x,-y]]) for t in range(self.dT) for x,y in toCellSet(g.evolve(self.state[t],1))}, 1), 3)
g.setrule("B3/S012345678")
self.envelopeB = LatticeFunction(dict.fromkeys({Matrix([[t,-x,-y]]) for t in range(self.dT) for x,y in toCellSet(g.evolve(self.state[t],1))}, 1), 3)
g.setrule("B1/S")
self.envelopeC = LatticeFunction(dict.fromkeys({Matrix([[t,-x,-y]]) for t in range(self.dT) for x,y in toCellSet(g.evolve(self.state[t],1))}, 1), 3)
g.setrule("B2/S")
self.envelopeD = LatticeFunction(dict.fromkeys({Matrix([[t,-x,-y]]) for t in range(self.dT) for x,y in toCellSet(g.evolve(self.state[t],1))}, 1), 3)
g.setrule("B3/S23")
#Find states required for pattern to be restored
#TODO: Also find states required for outputs
# Approach we take: Remove any unnecessary cells (parts that permanently have no influence on the rest of the crawler)
#Fill in crawlerStates
#We iterate twice to prevent pruning ash near the end of the cycle that would collide with the crawler later
#TODO: Most of this is just copy-pasted, I could definitely do this better
extendedState = self.state.copy()
for t in range(self.dT):
#Remove all outputs on this generation from currentState
for outputTimeToRemove, outputPattern, outputPosition in outputs:
if outputTimeToRemove == t:
currentState = outputPattern.joinInto(currentState, outputPosition + Matrix([[0,self.dX,self.dY]]), "andnot")
extendedState.append(currentState)
#Join all inputs on this generation to currentState
for inputTimeToAdd, inputPattern, inputPosition in inputs:
if inputTimeToAdd == t:
currentState = inputPattern.joinInto(currentState, inputPosition + Matrix([[0,self.dX,self.dY]]), "or")
currentState = g.evolve(currentState, 1)
#TODO: This is *probably* too strict, since some of the pi-crawler pairs I expected don't show up
self.requiredState = removeAshCells(extendedState, g.transform(self.state[0], self.dX*2, self.dY*2))[0:self.dT]
def getStatePosition(self, position, onlyRequired = False):
if onlyRequired:
return g.transform(self.requiredState[int(position.rep[0,0])], int(position.rep[0,1]), int(position.rep[0,2]))
else:
return g.transform(self.state[int(position.rep[0,0])], int(position.rep[0,1]), int(position.rep[0,2]))
def joinInto(self, cellList, position, mode):
if mode == "or":
return g.join(cellList, self.getStatePosition(position))
elif mode == "andnot":
return toCellList(toCellSet(cellList) - toCellSet(self.getStatePosition(position)))
def place(self, position, mode = "or", onlyRequired = False):
g.putcells(self.getStatePosition(position, onlyRequired),0,0,1,0,0,1, mode)
def placeInput(self, position, index, mode = "or"):
stateT = int(position.rep[0,0])
for inputTimeToAdd, inputPattern, inputPosition in self.inputs:
indexToUse = index + (1,0)[inputTimeToAdd >= stateT]
inputPattern.place(inputPosition + (position.rep + Matrix([[-inputTimeToAdd, 0, 0]]) - Matrix([[self.dT, -self.dX, -self.dY]]) * indexToUse), mode)
def placeOutput(self, position, index, mode = "or"):
stateT = int(position.rep[0,0])
for outputTimeToRemove, outputPattern, outputPosition in self.outputs:
indexToUse = index + (1,0)[outputTimeToRemove <= stateT]
outputPattern.place(outputPosition + (position.rep + Matrix([[-outputTimeToRemove, 0, 0]]) + Matrix([[self.dT, -self.dX, -self.dY]]) * indexToUse), mode)
#Place with inputs (and outputs)
def placeWithInputs(self, position, numInputs = 0, numOutputs = 0, mode = "or", onlyRequired = False):
self.place(position, mode, onlyRequired)
for i in range(0,numInputs):
self.placeInput(position, i, mode)
for i in range(0,numOutputs):
self.placeOutput(position, i, mode)
#Test this pattern with inputs (and outputs)
# We only want to test against the minimum envelope required to sustain the component
#TODO: Allow more customizability in input/output testing
def test(self, position, onlyRequired = True):
return patternContains(self.getStatePosition(position, onlyRequired))
def testInput(self, position, index):
stateT = int(position.rep[0,0])
for inputTimeToAdd, inputPattern, inputPosition in self.inputs:
indexToUse = index + (1,0)[inputTimeToAdd >= stateT]
if not inputPattern.test(inputPosition + (position.rep + Matrix([[-inputTimeToAdd, 0, 0]]) - Matrix([[self.dT, -self.dX, -self.dY]]) * indexToUse)):
return False
return True
def testOutput(self, position, index):
stateT = int(position.rep[0,0])
for outputTimeToRemove, outputPattern, outputPosition in self.outputs:
indexToUse = index + (1,0)[outputTimeToRemove <= stateT]
if not outputPattern.test(outputPosition + (position.rep + Matrix([[-outputTimeToRemove, 0, 0]]) + Matrix([[self.dT, -self.dX, -self.dY]]) * indexToUse)):
return False
return True
def testWithInputs(self, position, numInputs = 0, numOutputs = 0):
return self.test(position) and all(self.testInput(position,i) for i in range(0, numInputs)) and all(self.testOutput(position,i) for i in range(0, numOutputs))
#Enumerate all possible collisions/interaction separations between two objects
#NOTE: This is optimized for the case where self is small
#TODO: Would probably like to make a version optimized for where self is not small
# I'm not entirely sure how best to do that
def enumerateCollisionSeparations(self, other):
separationLattice = self.periodLattice + other.periodLattice
separationGroup = QuotientGroup(cellLattice, separationLattice)
#Wrapping our envelopes first is probably more efficient
prewrapSelfA = self.envelopeA.wrapToQuotientFunction(separationGroup, -1)
prewrapSelfB = self.envelopeB.wrapToQuotientFunction(separationGroup, -1)
prewrapSelfC = self.envelopeC.wrapToQuotientFunction(separationGroup, -1)
prewrapSelfD = self.envelopeD.wrapToQuotientFunction(separationGroup, -1)
prewrapOtherA = other.envelopeA.wrapToQuotientFunction(separationGroup, 1)
prewrapOtherB = other.envelopeB.wrapToQuotientFunction(separationGroup, 1)
prewrapOtherC = other.envelopeC.wrapToQuotientFunction(separationGroup, 1)
prewrapOtherD = other.envelopeD.wrapToQuotientFunction(separationGroup, 1)
collisionSeparationCosets = set(prewrapSelfA.convolve(prewrapOtherB).data) | set(prewrapSelfB.convolve(prewrapOtherA).data) | set(prewrapSelfC.convolve(prewrapOtherD).data) | set(prewrapSelfD.convolve(prewrapOtherC).data)
#Want to find the first possible absolute separations
#This means, for each separationCoset in collisionSeparationCosets, we want to find the first time resulting in an interaction
#Divide our envelopes into cosets
selfCosetsA = separationLattice.divideIntoCosets(self.envelopeA.data)
selfCosetsB = separationLattice.divideIntoCosets(self.envelopeB.data)
selfCosetsC = separationLattice.divideIntoCosets(self.envelopeC.data)
selfCosetsD = separationLattice.divideIntoCosets(self.envelopeD.data)
otherCosetsA = separationLattice.divideIntoCosets(other.envelopeA.data)
otherCosetsB = separationLattice.divideIntoCosets(other.envelopeB.data)
otherCosetsC = separationLattice.divideIntoCosets(other.envelopeC.data)
otherCosetsD = separationLattice.divideIntoCosets(other.envelopeD.data)
#Find earliest interatction cells for each coset
#Idea:
# Want to understand the space of vectors v such that CosetMatrix(v, self.periodLattice) in selfEnvelope, and CosetMatrix(v + separation, other.periodLattice) in otherEnvelope
# That is, exist m,n such that v + m*self.periodVector in selfEnvelope.reps, v + separation + n*other.periodVector in otherEnvelope.reps
# Have x in selfEnvelope.reps, y in otherEnvelope.reps such that v + m*self.periodVector = x, v + separation + n*other.periodVector = y
# Then x+separation-y = m*self.periodVector - n*other.periodVector
# So [m,-n] = (x+separation-y) * changeOfCoords
# In particular, m = (x+separation-y) * changeOfCoords.col(0)
# Then v = x - self.periodVector * ((x+separation-y) * changeOfCoords.col(0))[0,0]
# Specifically, v[0,0] = x[0,0] - self.periodVector[0,0] * ((x+separation-y) * changeOfCoords.col(0))[0,0]
# = x[0,0] - self.periodVector[0,0] * (x * changeOfCoords.col(0))[0,0] + self.periodVector[0,0] * ((y-separation) * changeOfCoords.col(0))[0,0]
# = x * ([[1],[0],[0]] - changeOfCoords.col(0) * self.periodVector[0,0]) + (y-separation) * changeOfCoords.col(0) * self.periodVector[0,0]
cMulOther = self.periodVector.blockVertical(other.periodVector).rightInverse().col(0) * self.periodVector[0,0]
cMulSelf = Matrix([[1],[0],[0]]) - cMulOther
def findContribs(cosetReps, multiplier):
return {coset: min((rep * multiplier)[0,0] for rep in cosetReps[coset]) for coset in cosetReps}
selfContribsA = findContribs(selfCosetsA, cMulSelf)
selfContribsB = findContribs(selfCosetsB, cMulSelf)
selfContribsC = findContribs(selfCosetsC, cMulSelf)
selfContribsD = findContribs(selfCosetsD, cMulSelf)
otherContribsA = findContribs(otherCosetsA, cMulOther)
otherContribsB = findContribs(otherCosetsB, cMulOther)
otherContribsC = findContribs(otherCosetsC, cMulOther)
otherContribsD = findContribs(otherCosetsD, cMulOther)
#Remark: This is rather slow when self is large
#TODO: Would like a better approach to this
def minContrib(separation, selfContribs, otherContribs):
return min((selfContribs[coset] + otherContribs[coset + separation] for coset in selfContribs if coset + separation in otherContribs), default = math.inf)
for separationCoset in collisionSeparationCosets:
minT = min(minContrib(separationCoset.rep, selfContribsA, otherContribsB),
minContrib(separationCoset.rep, selfContribsB, otherContribsA),
minContrib(separationCoset.rep, selfContribsC, otherContribsD),
minContrib(separationCoset.rep, selfContribsD, otherContribsC)) - (separationCoset.rep * cMulOther)[0,0]
yield [CosetMatrix(Matrix([[minT,0,0]]), self.periodLattice), CosetMatrix(Matrix([[minT,0,0]]) + separationCoset.rep, other.periodLattice)]
#Enumerate interactions between two objects with the same velocity
#NOTE: This is less size-dependent
def enumerateInteractionSeparations(self, other):
separationLattice = self.periodLattice + other.periodLattice
separationGroup = QuotientGroup(cellLattice, separationLattice)
#Wrapping our envelopes first is probably more efficient
prewrapSelfA = self.envelopeA.wrapToQuotientFunction(separationGroup, -1)
prewrapSelfB = self.envelopeB.wrapToQuotientFunction(separationGroup, -1)
prewrapSelfC = self.envelopeC.wrapToQuotientFunction(separationGroup, -1)
prewrapSelfD = self.envelopeD.wrapToQuotientFunction(separationGroup, -1)
prewrapOtherA = other.envelopeA.wrapToQuotientFunction(separationGroup, 1)
prewrapOtherB = other.envelopeB.wrapToQuotientFunction(separationGroup, 1)
prewrapOtherC = other.envelopeC.wrapToQuotientFunction(separationGroup, 1)
prewrapOtherD = other.envelopeD.wrapToQuotientFunction(separationGroup, 1)
collisionSeparationCosets = set(prewrapSelfA.convolve(prewrapOtherB).data) | set(prewrapSelfB.convolve(prewrapOtherA).data) | set(prewrapSelfC.convolve(prewrapOtherD).data) | set(prewrapSelfD.convolve(prewrapOtherC).data)
return [[CosetMatrix(Matrix([[0,0,0]]), self.periodLattice), CosetMatrix(coset.rep, other.periodLattice)] for coset in collisionSeparationCosets]
#TODO: Could make a faster method for self-interactions, since half of the convolutions aren't really required
#Multiple patterns with the same period, with compatible inputs and outputs linked
class CompoundPattern:
def __init__(self, componentsWithPositions):
#Members are of the form (component, position)
self.componentsWithPositions = componentsWithPositions
self.periodVector = componentsWithPositions[0][0].periodVector
self.periodLattice = componentsWithPositions[0][0].periodLattice
self.dT = int(self.periodVector[0,0])
self.dX = -int(self.periodVector[0,1])
self.dY = -int(self.periodVector[0,2])
#Figure out all inputs and outputs
self.inputDict = {}
for inputComponent, inputComponentPosition in self.componentsWithPositions:
for inputTime, inputPattern, inputPosition in inputComponent.inputs:
if not inputPattern in self.inputDict:
self.inputDict[inputPattern] = {}
combinedLattice = inputPattern.periodLattice + self.periodLattice
#What lane is our input on
inputPositionInCompound = inputPosition + inputComponentPosition.rep - Matrix([[inputTime,0,0]])
inputLane = CosetMatrix(inputPositionInCompound.rep, combinedLattice)
if not inputLane in self.inputDict[inputPattern]:
self.inputDict[inputPattern][inputLane] = []
#Our input time and position in the larger compound pattern
inputTimeInCompoundPattern = mod(inputTime - int(inputComponentPosition.rep[0,0]), self.dT)
inputSpacing = ((inputTime - int(inputComponentPosition.rep[0,0])) - inputTimeInCompoundPattern) // self.dT
inputPositionInCompoundPattern = inputPosition.rep + inputComponentPosition.rep + Matrix([[inputTimeInCompoundPattern - inputTime,0,0]]) + self.periodVector * inputSpacing
self.inputDict[inputPattern][inputLane].append((inputTimeInCompoundPattern, inputPositionInCompoundPattern))
self.outputDict = {}
for outputComponent, outputComponentPosition in self.componentsWithPositions:
for outputTime, outputPattern, outputPosition in outputComponent.outputs:
if not outputPattern in self.outputDict:
self.outputDict[outputPattern] = {}
combinedLattice = outputPattern.periodLattice + self.periodLattice
#What lane is our output on
outputPositionInCompound = outputPosition + outputComponentPosition.rep - Matrix([[outputTime,0,0]])
outputLane = CosetMatrix(outputPositionInCompound.rep, combinedLattice)
if not outputLane in self.outputDict[outputPattern]:
self.outputDict[outputPattern][outputLane] = []
#Our output time and position in the larger compound pattern
outputTimeInCompoundPattern = mod(outputTime - int(outputComponentPosition.rep[0,0]), self.dT)
outputSpacing = ((outputTime - int(outputComponentPosition.rep[0,0])) - outputTimeInCompoundPattern) // self.dT
outputPositionInCompoundPattern = outputPosition.rep + outputComponentPosition.rep + Matrix([[outputTimeInCompoundPattern - outputTime,0,0]]) + self.periodVector * outputSpacing
self.outputDict[outputPattern][outputLane].append((outputTimeInCompoundPattern, outputPositionInCompoundPattern))
#Whole pattern's inputs and outputs
#In same format as PeriodicPattern, to allow for nesting
self.inputs = []
self.outputs = []
self.linkages = []
#TODO: Need to register those with no compatible lanes
#Figure out compatible input-output pairs and combine 'em
for pattern in self.inputDict:
if pattern in self.outputDict:
combinedLatticeChangeOfBasis = self.periodVector.blockVertical(pattern.periodVector).rightInverse()
for lane in self.inputDict[pattern]:
if lane in self.outputDict[pattern]:
#Positivity/spacing checks on pairs in the same lane
inputsMinPositiveDisplacements = [(math.inf, -1) for i in range(len(self.inputDict[pattern][lane]))]
outputsMinPositiveDisplacements = [(math.inf, -1) for j in range(len(self.outputDict[pattern][lane]))]
for i in range(len(self.inputDict[pattern][lane])):
inputTimeInCompoundPattern, inputPositionInCompoundPattern = self.inputDict[pattern][lane][i]
for j in range(len(self.outputDict[pattern][lane])):
outputTimeInCompoundPattern, outputPositionInCompoundPattern = self.outputDict[pattern][lane][j]
inputPos = inputPositionInCompoundPattern + Matrix([[inputTimeInCompoundPattern,0,0]])
outputPos = outputPositionInCompoundPattern + Matrix([[outputTimeInCompoundPattern,0,0]])
#This is incredibly scuffed and probably incorrect
#TODO: Yeah this is definitely incorrect
displacement = int((inputPos - outputPos)[0,0]) + int(((inputPos - outputPos) * combinedLatticeChangeOfBasis)[0,0]) * self.dT
if displacement >= 0 or True:
#Link up if these are an improvement
if displacement < inputsMinPositiveDisplacements[i][0]:
inputsMinPositiveDisplacements[i] = (displacement, j)
if displacement < outputsMinPositiveDisplacements[j][0]:
outputsMinPositiveDisplacements[j] = (displacement, i)
unboundInputs = set(range(len(self.inputDict[pattern][lane])))
unboundOutputs = set(range(len(self.outputDict[pattern][lane])))
#Register linkages for closest compatible pairs
for i in range(len(self.inputDict[pattern][lane])):
j = inputsMinPositiveDisplacements[i][1]
if j != -1 and outputsMinPositiveDisplacements[j][1] == i:
#i,j is a closest compatible pair
unboundInputs.remove(i)
unboundOutputs.remove(j)
inputTimeInCompoundPattern, inputPositionInCompoundPattern = self.inputDict[pattern][lane][i]
outputTimeInCompoundPattern, outputPositionInCompoundPattern = self.outputDict[pattern][lane][j]
self.linkages.append((pattern, inputTimeInCompoundPattern, inputPositionInCompoundPattern, outputTimeInCompoundPattern, outputPositionInCompoundPattern))
#Register unbound inputs and outputs
for i in unboundInputs:
inputTimeInCompoundPattern, inputPositionInCompoundPattern = self.inputDict[pattern][lane][i]
self.inputs.append((inputTimeInCompoundPattern, pattern, CosetMatrix(inputPositionInCompoundPattern, pattern.periodLattice)))
for j in unboundOutputs:
outputTimeInCompoundPattern, outputPositionInCompoundPattern = self.outputDict[pattern][lane][j]
self.outputs.append((outputTimeInCompoundPattern, pattern, CosetMatrix(outputPositionInCompoundPattern, pattern.periodLattice)))
else:
for inputTimeInCompoundPattern, inputPositionInCompoundPattern in self.inputDict[pattern][lane]:
self.inputs.append((inputTimeInCompoundPattern, pattern, CosetMatrix(inputPositionInCompoundPattern, pattern.periodLattice)))
for lane in self.outputDict[pattern]:
if not lane in self.inputDict[pattern]:
for outputTimeInCompoundPattern, outputPositionInCompoundPattern in self.outputDict[pattern][lane]:
self.outputs.append((outputTimeInCompoundPattern, pattern, CosetMatrix(outputPositionInCompoundPattern, pattern.periodLattice)))
else:
for lane in self.inputDict[pattern]:
for inputTimeInCompoundPattern, inputPositionInCompoundPattern in self.inputDict[pattern][lane]:
self.inputs.append((inputTimeInCompoundPattern, pattern, CosetMatrix(inputPositionInCompoundPattern, pattern.periodLattice)))
for pattern in self.outputDict:
if not pattern in self.inputDict:
for lane in self.outputDict[pattern]:
for outputTimeInCompoundPattern, outputPositionInCompoundPattern in self.outputDict[pattern][lane]:
self.outputs.append((outputTimeInCompoundPattern, pattern, CosetMatrix(outputPositionInCompoundPattern, pattern.periodLattice)))
def place(self, position, mode = "or"):
#Place in all components
for component, componentPosition in self.componentsWithPositions:
component.place(position + componentPosition, mode)
#Place in all linkages
stateT = int(position.rep[0,0])
for pattern, inputTimeInCompoundPattern, inputPositionInCompoundPattern, outputTimeInCompoundPattern, outputPositionInCompoundPattern in self.linkages:
#TODO: There appears to be a slight bug here of some sort in cases where we're placing on that generation
# ALSO: We don't use stateT at all when clearly this is required
inputBasePos = inputPositionInCompoundPattern + position.rep - Matrix([[inputTimeInCompoundPattern, 0, 0]])
outputBasePos = outputPositionInCompoundPattern + position.rep - Matrix([[outputTimeInCompoundPattern, 0, 0]])
combinedLatticeChangeOfBasis = self.periodVector.blockVertical(pattern.periodVector).rightInverse()
for index in range(int(((inputBasePos - outputBasePos) * combinedLatticeChangeOfBasis)[0,0])):
pattern.place(CosetMatrix(inputBasePos - Matrix([[self.dT, -self.dX, -self.dY]]) * index, pattern.periodLattice), mode)
def placeInput(self, position, index, mode = "or"):
stateT = int(position.rep[0,0])
for inputTimeToAdd, inputPattern, inputPosition in self.inputs:
indexToUse = index + (1,0)[inputTimeToAdd >= stateT]
inputPattern.place(inputPosition + (position.rep + Matrix([[-inputTimeToAdd, 0, 0]]) - Matrix([[self.dT, -self.dX, -self.dY]]) * indexToUse), mode)
def placeOutput(self, position, index, mode = "or"):
stateT = int(position.rep[0,0])
for outputTimeToRemove, outputPattern, outputPosition in self.outputs:
indexToUse = index + (1,0)[outputTimeToRemove <= stateT]
outputPattern.place(outputPosition + (position.rep + Matrix([[-outputTimeToRemove, 0, 0]]) + Matrix([[self.dT, -self.dX, -self.dY]]) * indexToUse), mode)
#Place with inputs (and outputs)
def placeWithInputs(self, position, numInputs = 0, numOutputs = 0, mode = "or"):
self.place(position, mode)
for i in range(0,numInputs):
self.placeInput(position, i, mode)
for i in range(0,numOutputs):
self.placeOutput(position, i, mode)
#Find the minimal offset displacement of pat2 linking an output in one PeriodicPattern (or CompoundPattern) to an input in another
# Plus extraSpacing steps worth of space
def findOffset(pat1, pat1OutputIndex, pat2, pat2InputIndex, extraSpacing = 0):
outputTimeToRemove, outputPattern, outputPosition = pat1.outputs[pat1OutputIndex]
inputTimeToAdd, inputPattern, inputPosition = pat2.inputs[pat2InputIndex]
#Want to add and remove in the same generation
return CosetMatrix(Matrix([[inputTimeToAdd - outputTimeToRemove,0,0]]) + outputPosition.rep - inputPosition.rep - outputPattern.periodVector * extraSpacing, pat1.periodLattice)
#A chain with certain spacings
def chain(patternInputOutputSpacingInfo):
periodLattice = patternInputOutputSpacingInfo[0][0].periodLattice
cumulativeOffset = CosetMatrix(Matrix.zero(1,3), periodLattice)
componentsWithPositions = [(patternInputOutputSpacingInfo[0][0], cumulativeOffset)]
for i in range(len(patternInputOutputSpacingInfo) - 1):
outputComponent, _, outputComponentOutputIndex, _ = patternInputOutputSpacingInfo[i]
inputComponent, inputComponentInputIndex, _, extraSpacing = patternInputOutputSpacingInfo[i+1]
addedOffset = CompoundPattern.findOffset(outputComponent, outputComponentOutputIndex, inputComponent, inputComponentInputIndex, extraSpacing)
cumulativeOffset += addedOffset
componentsWithPositions.append((inputComponent, cumulativeOffset))
return CompoundPattern(componentsWithPositions)
#Settings
g.new("13131")
g.setrule("B3/S23")
g.setalgo("HashLife")
#Basic objects
block = PeriodicPattern(g.parse("2o$2o!",0,0), 1, 0, 0)
blinker = PeriodicPattern(g.parse("3o!",-1,0), 2, 0, 0)
SWGlider = PeriodicPattern(g.parse("bo$o$3o!",0,0), 4, -1, 1)
NWGlider = PeriodicPattern(g.parse("2o$obo$o!",0,0), 4, -1, -1)
NLWSS = PeriodicPattern(g.parse("3o$o2bo$o$o$bobo!",0,0), 4, 0, -2)
NMWSS = PeriodicPattern(g.parse("3o$o2bo$o$o3bo$o$bobo!",0,0), 4, 0, -2)
NHWSS = PeriodicPattern(g.parse("3o$o2bo$o$o3bo$o3bo$o$bobo!",0,0), 4, 0, -2)
WLWSS = PeriodicPattern(g.parse("bo2bo$o$o3bo$4o!",0,0), 4, -2, 0)
#Fanout components
#TODO: Would be nice to figure these out automatically
fanoutComponent1 = PeriodicPattern([],31*16,-1*16,-13*16,
[(0,NWGlider,CosetMatrix(Matrix([[1,1,0]]), NWGlider.periodLattice)),
(0,NLWSS,CosetMatrix(Matrix([[3,-5,0]]), NLWSS.periodLattice)),
(15,NLWSS,CosetMatrix(Matrix([[1,0,5]]), NLWSS.periodLattice)),
(16,NLWSS,CosetMatrix(Matrix([[2,6,4]]), NLWSS.periodLattice))],
[(28,blinker,CosetMatrix(Matrix([[0,4,7]]), blinker.periodLattice)),
(29,WLWSS,CosetMatrix(Matrix([[-1,-7,-3]]), WLWSS.periodLattice))])
fanoutComponent2 = PeriodicPattern([],31*16,-1*16,-13*16,
[(0,blinker,CosetMatrix(Matrix([[1,2,1]]), blinker.periodLattice)),
(0,NLWSS,CosetMatrix(Matrix([[1,2,4]]), NLWSS.periodLattice)),
(13,NLWSS,CosetMatrix(Matrix([[0,0,6]]), NLWSS.periodLattice))],
[(10,NWGlider,CosetMatrix(Matrix([[-1,1,-2]]), NWGlider.periodLattice))])
fanoutComponent3 = PeriodicPattern([],31*16,-1*16,-13*16,
[(0,NWGlider,CosetMatrix(Matrix([[2,7,5]]), NWGlider.periodLattice)),
(0,NHWSS,CosetMatrix(Matrix([[0,0,0]]), NHWSS.periodLattice)),
(10,NMWSS,CosetMatrix(Matrix([[2,9,9]]), NMWSS.periodLattice))],
[(26,NWGlider,CosetMatrix(Matrix([[0,2,-5]]), NWGlider.periodLattice))])
fanoutComponent4 = PeriodicPattern([],31*16,-1*16,-13*16,
[(0,NWGlider,CosetMatrix(Matrix([[2,5,0]]), NWGlider.periodLattice)),
(0,NLWSS,CosetMatrix(Matrix([[0,6,4]]), NLWSS.periodLattice)),
(16,NLWSS,CosetMatrix(Matrix([[3,0,7]]), NLWSS.periodLattice))],
[(18,blinker,CosetMatrix(Matrix([[1,8,5]]), blinker.periodLattice)),
(20,NWGlider,CosetMatrix(Matrix([[3,1,4]]), NWGlider.periodLattice))])
fanoutComponent5 = PeriodicPattern([],31*16,-1*16,-13*16,
[(0,blinker,CosetMatrix(Matrix([[0,1,0]]), blinker.periodLattice)),
(0,NLWSS,CosetMatrix(Matrix([[0,3,2]]), NLWSS.periodLattice)),
(9,NLWSS,CosetMatrix(Matrix([[3,7,6]]), NLWSS.periodLattice))],
[(23,NWGlider,CosetMatrix(Matrix([[2,6,1]]), NWGlider.periodLattice))])
fanoutComponent6 = fanoutComponent4
fanoutComponent7 = PeriodicPattern([],31*16,-1*16,-13*16,
[(0,blinker,CosetMatrix(Matrix([[0,1,2]]), blinker.periodLattice)),
(0,NLWSS,CosetMatrix(Matrix([[1,5,1]]), NLWSS.periodLattice)),
(25,NMWSS,CosetMatrix(Matrix([[3,9,3]]), NMWSS.periodLattice))],
[(37,NWGlider,CosetMatrix(Matrix([[1,5,-3]]), NWGlider.periodLattice))])
trackPairBuilderCollision1 = PeriodicPattern([],31*16,-1*16,-13*16,
[(0,WLWSS,CosetMatrix(Matrix([[1,1,-1]]), WLWSS.periodLattice)),
(0,NWGlider,CosetMatrix(Matrix([[2,3,5]]), NWGlider.periodLattice)),
(79,NWGlider,CosetMatrix(Matrix([[1,6,6]]), NWGlider.periodLattice))],
[(8,block,CosetMatrix(Matrix([[0,-3,0]]), block.periodLattice)),
(85,block,CosetMatrix(Matrix([[0,2,5]]), block.periodLattice))])
#TODO: Want to be able to 'complete a cycle with available components' when possible
def testPatSpacingInfo(n,dn):
return [
(fanoutComponent1,0,0,207 + (dn-2)*192 - n * 16),
(fanoutComponent2,0,0,1 + n*24),
(fanoutComponent3,0,0,50 + n*16),
(fanoutComponent4,0,0,47),
(fanoutComponent5,0,0,10),
(fanoutComponent6,0,0,94),
(fanoutComponent7,0,0,10),
]
nList = [10]
for i in range(16-1):
#15/12 is probably not the exact optimal value but it's fine
newN = int(math.ceil(nList[0] * 7 / 6 + 15/12))
nList.insert(0,newN)
g.show(str(nList))
testPatSpacings = []
for i in range(len(nList)):
if i == 0:
testPatSpacings += testPatSpacingInfo(nList[i], 0)
else:
testPatSpacings += testPatSpacingInfo(nList[i], nList[i-1] - nList[i])
testPat = CompoundPattern.chain(testPatSpacings)
testPat.placeWithInputs(CosetMatrix(Matrix([[0,0,0]]), testPat.periodLattice), 320, 320)
#fanoutComponent3.placeWithInputs(CosetMatrix(Matrix([[0,0,0]]), fanoutComponent3.periodLattice), 320, 320)
#Crawlers on various objects
crawlerSWGliders1 = PeriodicPattern(g.parse(
"2b3o$bo2bo$o$b3o3$4b2o$4b2o$5bo$5b2o$b3obob2o$b2o$5bo2bo$5b3o!"
,0,0), 31, -1, -13,
[(24,SWGlider,CosetMatrix(Matrix([[0,6,-14]]), SWGlider.periodLattice))],
[(15,SWGlider,CosetMatrix(Matrix([[1,1,4]]), SWGlider.periodLattice))])
crawlerSWGliders2 = PeriodicPattern(g.parse(
"2b3o$bo2bo$o$b3o3$4b2o$4b2o$5bo$5b2o$b3obob2o$b2o$5bo2bo$5b3o!"
,0,0), 31, -1, -13,
[(24,SWGlider,CosetMatrix(Matrix([[0,6,-15]]), SWGlider.periodLattice))],
[(15,SWGlider,CosetMatrix(Matrix([[1,1,4]]), SWGlider.periodLattice))])
crawlerSWGliders3 = PeriodicPattern(g.parse(
"2b3o$bo2bo$o$b3o3$4b2o$4b2o$5bo$5b2o$b3obob2o$b2o$5bo2bo$5b3o!"
,0,0), 31, -1, -13,
[(24,SWGlider,CosetMatrix(Matrix([[1,6,-15]]), SWGlider.periodLattice))],
[(15,SWGlider,CosetMatrix(Matrix([[1,1,4]]), SWGlider.periodLattice))])
crawlerNWGliders = PeriodicPattern(g.parse(
"2b3o$bo2bo$o$b3o3$4b2o$4b2o$5bo$5b2o$b3obob2o$b2o$5bo2bo$5b3o!"
,0,0), 31, -1, -13,
[(24,NWGlider,CosetMatrix(Matrix([[1,7,-14]]), NWGlider.periodLattice))],
[(15,SWGlider,CosetMatrix(Matrix([[1,1,4]]), SWGlider.periodLattice))])
crawlerBlocks = PeriodicPattern(g.parse(
"2b3o$bo2bo$o$b3o3$4b2o$4b2o$5bo$5b2o$b3obob2o$b2o$5bo2bo$5b3o!"
,0,0), 31, -1, -13,
[(24,block,CosetMatrix(Matrix([[0,6,-14]]), block.periodLattice))],
[(15,SWGlider,CosetMatrix(Matrix([[1,1,4]]), SWGlider.periodLattice))])
#The lane shift a SW glider -> SW glider crawler shifts a glider trail by
crawlerGliderLattice = SWGlider.periodLattice + crawlerSWGliders1.periodLattice
def getGliderShift(pattern, inputIndex = 0, outputIndex = 0):
inputLane = CosetMatrix((pattern.inputs[inputIndex][2] - Matrix([[pattern.inputs[inputIndex][0],0,0]])).rep, crawlerGliderLattice)
outputLane = CosetMatrix((pattern.outputs[inputIndex][2] - Matrix([[pattern.outputs[inputIndex][0],0,0]])).rep, crawlerGliderLattice)
return outputLane - inputLane
gliderShift1 = getGliderShift(crawlerSWGliders1).rep
gliderShift2 = getGliderShift(crawlerSWGliders2).rep
gliderShift3 = getGliderShift(crawlerSWGliders3).rep
Nora Brown
- I6_I6
- Posts: 1040
- Joined: July 26th, 2025, 8:44 pm
- Location: Here, there, somewhere, anywhere, everywhere.
- Contact:
Re: 13131: The B-Heptomino/Glider Spaceship Thread
It's great to see an old project starting up again!glider_rider wrote: February 11th, 2026, 2:16 am A prototype fanout mechanism:
FanoutDevicePrototype.mc
But given the number of XWSSs in the helices, this thing would probably be larger than the Caterpillar.
Code: Select all
#C [[ THEME Golly ]]
x = 27, y = 15, rule = LifeHistory
8.A$A6.A.A$3A4.BA2B.B2D$3.A4.2B.2B2DB$2.2A2.3B.6B2.3B$2.20B$4.19B$4.2B
C10BD4B$4.2B2C10BD4B$4.B2C11B2D3B$4.13B2D4B$5.12BD3B.B2A$6.13B3.BA.A$
6.3B.B3.B10.A$25.2A!
Re: 13131: The B-Heptomino/Glider Spaceship Thread
I believe the number of xWSS in the helix doesn't mean as much as the number of xWSS in fanout devices. And since the input of the (13,1)c/31 crawler is way more versatile than 17c/45 (it can accept a block, 3 orientations of a boat, and - most importantly - 4 orientations of a glider) I hope it is possible to build simpler fanout devices akin to the fanout device of the waterbear. By the way, there is an x15 helix, based on the Coe ship. There are probably more that work (however I couldn't find any that work at x14)
Code: Select all
x = 260, y = 387, rule = B3/S23
b2o$obo$2bo$13bo$12b3o12bo$12bob2o3b3o4b3o12bo$13b3o3bo2bo3bob2o3b3o4b
3o12bo$13b2o4bo7b3o3bo2bo3bob2o3b3o4b3o12bo43bo$19bo3bo3b2o4bo7b3o3bo
2bo3bob2o3b3o4b3o12bo28b3o3b3o$19bo3bo9bo3bo3b2o4bo7b3o3bo2bo3bob2o3b
3o4b3o12bo13b2obo2bo2bo$19bo13bo3bo9bo3bo3b2o4bo7b3o3bo2bo3bob2o3b3o4b
3o12b3o6bo$20bobo10bo13bo3bo9bo3bo3b2o4bo7b3o3bo2bo3bob2o3b3o5b3o2bo3b
o$34bobo10bo13bo3bo9bo3bo3b2o4bo7b3o3bo2bo4b3o2bo2bo$48bobo10bo13bo3bo
9bo3bo3b2o4bo8bobo$62bobo10bo13bo3bo9bo3bo4b3o$76bobo10bo13bo3bo4bo2bo
$90bobo10bo8bo2bo$104bobo6bobo$114bo4$90bo30bo$76bo12b3o28b3o$62bo12b
3o4b3o4bob2o26b2obo$48bo12b3o4b3o4bob2o3bo2bo4b3o26b3o$34bo12b3o4b3o4b
ob2o3bo2bo4b3o3bo7b2o27b3o$33b3o4b3o4bob2o3bo2bo4b3o3bo7b2o4bo3bo22b3o
8b2o$26b3o4bob2o3bo2bo4b3o3bo7b2o4bo3bo9bo3bo22bo2bo$26bo2bo4b3o3bo7b
2o4bo3bo9bo3bo9bo26bo$26bo7b2o4bo3bo9bo3bo9bo14bobo23bo$26bo3bo9bo3bo
9bo14bobo38bobo$26bo3bo9bo14bobo$26bo14bobo$27bobo$16b3o$16bo2bo$16bo$
16bo$17bobo2$27b3o$26bo2bo5bo5b3o$29bo4b3o3bo2bo5bo5b3o$29bo4bob2o5bo
4b3o3bo2bo5bo5b3o$13b3o10bobo6b3o5bo4bob2o5bo4b3o3bo2bo5bo5b3o41b3o4bo
$12bo2bo19b3o2bobo6b3o5bo4bob2o5bo4b3o3bo2bo5bo5b3o27bo2bo2b3o$15bo19b
3o11b3o2bobo6b3o5bo4bob2o5bo4b3o3bo2bo5bo5b3o13bo4b2obo$15bo19b2o12b3o
11b3o2bobo6b3o5bo4bob2o5bo4b3o3bo2bo5bo7bo3b4o$12bobo34b2o12b3o11b3o2b
obo6b3o5bo4bob2o5bo4b3o6bo5b2o$63b2o12b3o11b3o2bobo6b3o5bo4bob2o5bo2bo
$77b2o12b3o11b3o2bobo6b3o6b2o$91b2o12b3o11b3o6bo$105b2o12b3o6b3o$119b
2o7b3o6$104b3o28b3o$90b3o5bo4bo2bo28bo2bo$76b3o5bo4bo2bo4b3o6bo28bo$
62b3o5bo4bo2bo4b3o6bo4bob2o5bo28bo3bo$48b3o5bo4bo2bo4b3o6bo4bob2o5bo5b
3o2bobo19bo9bo$42bo4bo2bo4b3o6bo4bob2o5bo5b3o2bobo6b3o23b3o9bobo$41b3o
6bo4bob2o5bo5b3o2bobo6b3o11b3o23bob2o$41bob2o5bo5b3o2bobo6b3o11b3o11b
2o25b3o$42b3o2bobo6b3o11b3o11b2o39b2o$42b3o11b3o11b2o$42b3o11b2o$42b2o
$32bo$31b3o$31bob2o$32b3o$32b2o2$43bo$42b3o12bo$41b2obo4b3o4b3o12bo$
41b3o4bo2bo3b2obo4b3o4b3o12bo$29bo12b2o7bo3b3o4bo2bo3b2obo4b3o4b3o12bo
43bo$28b3o16bo3bo4b2o7bo3b3o4bo2bo3b2obo4b3o4b3o12bo28b3o3b3o$27b2obo
16bo3bo9bo3bo4b2o7bo3b3o4bo2bo3b2obo4b3o4b3o12bo14bob2o2bo2bo$27b3o21b
o9bo3bo9bo3bo4b2o7bo3b3o4bo2bo3b2obo4b3o4b3o14b3o2bo$28b2o18bobo14bo9b
o3bo9bo3bo4b2o7bo3b3o4bo2bo3b2obo4b3o7b3o2bo$62bobo14bo9bo3bo9bo3bo4b
2o7bo3b3o4bo2bo7b2o4bobo$76bobo14bo9bo3bo9bo3bo4b2o7bo7bo$90bobo14bo9b
o3bo9bo3bo$104bobo14bo9bo3bo7b3o$118bobo14bo8bo$132bobo5$120bo30bo$
106bo12b3o28b3o$92bo12b3o4b3o3b2obo28bob2o$78bo12b3o4b3o3b2obo3bo2bo3b
3o30b3o$64bo12b3o4b3o3b2obo3bo2bo3b3o7bo4b2o30b3o$63b3o4b3o3b2obo3bo2b
o3b3o7bo4b2o3bo3bo24b3o9b2o$56b3o3b2obo3bo2bo3b3o7bo4b2o3bo3bo9bo3bo
23bo2bo$55bo2bo3b3o7bo4b2o3bo3bo9bo3bo13bo26bo$58bo4b2o3bo3bo9bo3bo13b
o10bobo27bo$54bo3bo9bo3bo13bo10bobo38bobo$54bo3bo13bo10bobo$58bo10bobo
$55bobo$46b3o$45bo2bo$48bo$48bo$45bobo2$57b3o$57bo2bo4bo5b3o$57bo6b3o
4bo2bo4bo5b3o$57bo5b2obo4bo6b3o4bo2bo4bo5b3o$43b3o12bobo2b3o5bo5b2obo
4bo6b3o4bo2bo4bo5b3o41b3o4bo$43bo2bo16b3o6bobo2b3o5bo5b2obo4bo6b3o4bo
2bo4bo5b3o26bo2bo3b3o$43bo19b3o11b3o6bobo2b3o5bo5b2obo4bo6b3o4bo2bo4bo
5b3o15bo3bob2o$43bo20b2o11b3o11b3o6bobo2b3o5bo5b2obo4bo6b3o4bo2bo4bo5b
o3bo4b3o$44bobo31b2o11b3o11b3o6bobo2b3o5bo5b2obo4bo6b3o4bo3bo4b2o$92b
2o11b3o11b3o6bobo2b3o5bo5b2obo8b2o$106b2o11b3o11b3o6bobo2b3o9b2o$120b
2o11b3o11b3o7bobo$134b2o11b3o$148b2o8b2o6$134b3o28b3o$120b3o5bo5bo2bo
26bo2bo$106b3o5bo5bo2bo3b3o4bo32bo$92b3o5bo5bo2bo3b3o4bo5b2obo4bo28bo
3bo$78b3o5bo5bo2bo3b3o4bo5b2obo4bo5b3o6bobo17bo11bo$72bo5bo2bo3b3o4bo
5b2obo4bo5b3o6bobo2b3o25b3o7bobo$71b3o4bo5b2obo4bo5b3o6bobo2b3o11b3o
24b2obo$70b2obo4bo5b3o6bobo2b3o11b3o12b2o24b3o$70b3o6bobo2b3o11b3o12b
2o39b2o$70b3o11b3o12b2o$70b3o12b2o$71b2o$62bo$61b3o$60b2obo$60b3o$61b
2o2$73bo$72b3o12bo$72bob2o3b3o4b3o12bo$73b3o3bo2bo3bob2o3b3o4b3o12bo$
59bo13b2o4bo7b3o3bo2bo3bob2o3b3o4b3o12bo43bo$58b3o18bo3bo3b2o4bo7b3o3b
o2bo3bob2o3b3o4b3o12bo28b3o3b3o$58bob2o17bo3bo9bo3bo3b2o4bo7b3o3bo2bo
3bob2o3b3o4b3o12bo13b2obo2bo2bo$59b3o17bo13bo3bo9bo3bo3b2o4bo7b3o3bo2b
o3bob2o3b3o4b3o12b3o6bo$59b2o19bobo10bo13bo3bo9bo3bo3b2o4bo7b3o3bo2bo
3bob2o3b3o5b3o2bo3bo$94bobo10bo13bo3bo9bo3bo3b2o4bo7b3o3bo2bo4b3o2bo2b
o$108bobo10bo13bo3bo9bo3bo3b2o4bo8bobo$122bobo10bo13bo3bo9bo3bo4b3o$
136bobo10bo13bo3bo5bo$150bobo10bo9b2o$164bobo5$150bo30bo$136bo12b3o28b
3o$122bo12b3o4b3o4bob2o26b2obo$108bo12b3o4b3o4bob2o3bo2bo4b3o26b3o$94b
o12b3o4b3o4bob2o3bo2bo4b3o3bo7b2o27b3o$93b3o4b3o4bob2o3bo2bo4b3o3bo7b
2o4bo3bo22b3o8b2o$86b3o4bob2o3bo2bo4b3o3bo7b2o4bo3bo9bo3bo22bo2bo$86bo
2bo4b3o3bo7b2o4bo3bo9bo3bo9bo26bo$86bo7b2o4bo3bo9bo3bo9bo14bobo23bo$
86bo3bo9bo3bo9bo14bobo38bobo$86bo3bo9bo14bobo$86bo14bobo$87bobo$76b3o$
76bo2bo$76bo$76bo$77bobo2$87b3o$86bo2bo5bo5b3o$89bo4b3o3bo2bo5bo5b3o$
89bo4bob2o5bo4b3o3bo2bo5bo5b3o$73b3o10bobo6b3o5bo4bob2o5bo4b3o3bo2bo5b
o5b3o41b3o4bo$72bo2bo19b3o2bobo6b3o5bo4bob2o5bo4b3o3bo2bo5bo5b3o27bo2b
o2b3o$75bo19b3o11b3o2bobo6b3o5bo4bob2o5bo4b3o3bo2bo5bo5b3o13bo4b2obo$
75bo19b2o12b3o11b3o2bobo6b3o5bo4bob2o5bo4b3o3bo2bo5bo7bo3b4o$72bobo34b
2o12b3o11b3o2bobo6b3o5bo4bob2o5bo4b3o6bo5b2o$123b2o12b3o11b3o2bobo6b3o
5bo4bob2o5bo2bo$137b2o12b3o11b3o2bobo6b3o6b2o$151b2o12b3o11b3o6bo$165b
2o12b3o7bo$179b2o8bo6$164b3o28b3o$150b3o5bo4bo2bo28bo2bo$136b3o5bo4bo
2bo4b3o6bo28bo$122b3o5bo4bo2bo4b3o6bo4bob2o5bo28bo3bo$108b3o5bo4bo2bo
4b3o6bo4bob2o5bo5b3o2bobo19bo9bo$102bo4bo2bo4b3o6bo4bob2o5bo5b3o2bobo
6b3o23b3o9bobo$101b3o6bo4bob2o5bo5b3o2bobo6b3o11b3o23bob2o$101bob2o5bo
5b3o2bobo6b3o11b3o11b2o25b3o$102b3o2bobo6b3o11b3o11b2o39b2o$102b3o11b
3o11b2o$102b3o11b2o$102b2o$92bo$91b3o$91bob2o$92b3o$92b2o2$103bo$102b
3o12bo$101b2obo4b3o4b3o12bo$101b3o4bo2bo3b2obo4b3o4b3o12bo$89bo12b2o7b
o3b3o4bo2bo3b2obo4b3o4b3o12bo43bo$88b3o16bo3bo4b2o7bo3b3o4bo2bo3b2obo
4b3o4b3o12bo28b3o3b3o$87b2obo16bo3bo9bo3bo4b2o7bo3b3o4bo2bo3b2obo4b3o
4b3o12bo14bob2o2bo2bo$87b3o21bo9bo3bo9bo3bo4b2o7bo3b3o4bo2bo3b2obo4b3o
4b3o14b3o2bo$88b2o18bobo14bo9bo3bo9bo3bo4b2o7bo3b3o4bo2bo3b2obo4b3o7b
3o2bo$122bobo14bo9bo3bo9bo3bo4b2o7bo3b3o4bo2bo7b2o4bobo$136bobo14bo9bo
3bo9bo3bo4b2o7bo7bo$150bobo14bo9bo3bo9bo3bo$164bobo14bo9bo3bo7b3o$178b
obo14bo$192bobo4$206b2o$180bo30bo$166bo12b3o21b2o5b3o$152bo12b3o4b3o3b
2obo28bob2o$138bo12b3o4b3o3b2obo3bo2bo3b3o30b3o$124bo12b3o4b3o3b2obo3b
o2bo3b3o7bo4b2o30b3o$123b3o4b3o3b2obo3bo2bo3b3o7bo4b2o3bo3bo24b3o9b2o$
116b3o3b2obo3bo2bo3b3o7bo4b2o3bo3bo9bo3bo23bo2bo$115bo2bo3b3o7bo4b2o3b
o3bo9bo3bo13bo26bo$118bo4b2o3bo3bo9bo3bo13bo10bobo27bo$114bo3bo9bo3bo
13bo10bobo38bobo$114bo3bo13bo10bobo$118bo10bobo$115bobo$106b3o$105bo2b
o$108bo$108bo$105bobo2$117b3o$117bo2bo4bo5b3o$117bo6b3o4bo2bo4bo5b3o$
117bo5b2obo4bo6b3o4bo2bo4bo5b3o$103b3o12bobo2b3o5bo5b2obo4bo6b3o4bo2bo
4bo5b3o41b3o4bo$103bo2bo16b3o6bobo2b3o5bo5b2obo4bo6b3o4bo2bo4bo5b3o26b
o2bo3b3o$103bo19b3o11b3o6bobo2b3o5bo5b2obo4bo6b3o4bo2bo4bo5b3o15bo3bob
2o$103bo20b2o11b3o11b3o6bobo2b3o5bo5b2obo4bo6b3o4bo2bo4bo5bo3bo4b3o$
104bobo31b2o11b3o11b3o6bobo2b3o5bo5b2obo4bo6b3o4bo3bo4b2o$152b2o11b3o
11b3o6bobo2b3o5bo5b2obo8b2o$166b2o11b3o11b3o6bobo2b3o6bo2b2o$180b2o11b
3o11b3o8b2o$194b2o11b3o$208b2o3$221b2o2$218bo3bo$194b3o21bo2bo3b3o$
180b3o5bo5bo2bo21bo4bo2bo$166b3o5bo5bo2bo3b3o4bo32bo$152b3o5bo5bo2bo3b
3o4bo5b2obo4bo28bo3bo$138b3o5bo5bo2bo3b3o4bo5b2obo4bo5b3o6bobo17bo11bo
$132bo5bo2bo3b3o4bo5b2obo4bo5b3o6bobo2b3o25b3o7bobo$131b3o4bo5b2obo4bo
5b3o6bobo2b3o11b3o24b2obo$130b2obo4bo5b3o6bobo2b3o11b3o12b2o24b3o$130b
3o6bobo2b3o11b3o12b2o39b2o$130b3o11b3o12b2o$130b3o12b2o$131b2o$122bo$
121b3o$120b2obo$120b3o$121b2o2$133bo$132b3o12bo$132bob2o3b3o4b3o12bo$
133b3o3bo2bo3bob2o3b3o4b3o12bo$119bo13b2o4bo7b3o3bo2bo3bob2o3b3o4b3o
12bo43bo$118b3o18bo3bo3b2o4bo7b3o3bo2bo3bob2o3b3o4b3o12bo28b3o3b3o$
118bob2o17bo3bo9bo3bo3b2o4bo7b3o3bo2bo3bob2o3b3o4b3o12bo13b2obo2bo2bo$
119b3o17bo13bo3bo9bo3bo3b2o4bo7b3o3bo2bo3bob2o3b3o4b3o12b3o6bo$119b2o
19bobo10bo13bo3bo9bo3bo3b2o4bo7b3o3bo2bo3bob2o3b3o5b3o2bo3bo$154bobo
10bo13bo3bo9bo3bo3b2o4bo7b3o3bo2bo4b3o2bo2bo$168bobo10bo13bo3bo9bo3bo
3b2o4bo8bobo$182bobo10bo13bo3bo9bo3bo5b2o$196bobo10bo13bo3bo$210bobo
10bo$224bobo2$236b2o$236b2o$234b3o$210bo22b3o5bo$196bo12b3o28b3o$182bo
12b3o4b3o4bob2o26b2obo$168bo12b3o4b3o4bob2o3bo2bo4b3o26b3o$154bo12b3o
4b3o4bob2o3bo2bo4b3o3bo7b2o27b3o$153b3o4b3o4bob2o3bo2bo4b3o3bo7b2o4bo
3bo22b3o8b2o$146b3o4bob2o3bo2bo4b3o3bo7b2o4bo3bo9bo3bo22bo2bo$146bo2bo
4b3o3bo7b2o4bo3bo9bo3bo9bo26bo$146bo7b2o4bo3bo9bo3bo9bo14bobo23bo$146b
o3bo9bo3bo9bo14bobo38bobo$146bo3bo9bo14bobo$146bo14bobo$147bobo$136b3o
$136bo2bo$136bo$136bo$137bobo2$147b3o$146bo2bo5bo5b3o$149bo4b3o3bo2bo
5bo5b3o$149bo4bob2o5bo4b3o3bo2bo5bo5b3o$133b3o10bobo6b3o5bo4bob2o5bo4b
3o3bo2bo5bo5b3o41b3o4bo$132bo2bo19b3o2bobo6b3o5bo4bob2o5bo4b3o3bo2bo5b
o5b3o27bo2bo2b3o$135bo19b3o11b3o2bobo6b3o5bo4bob2o5bo4b3o3bo2bo5bo5b3o
13bo4b2obo$135bo19b2o12b3o11b3o2bobo6b3o5bo4bob2o5bo4b3o3bo2bo5bo7bo3b
4o$132bobo34b2o12b3o11b3o2bobo6b3o5bo4bob2o5bo4b3o6bo5b2o$183b2o12b3o
11b3o2bobo6b3o5bo4bob2o5bo2bo$197b2o12b3o11b3o2bobo6b3o6b2o$211b2o12b
3o11b3o$225b2o12b3o$239b2o2$251b2o$251b2o2$248b3o$224b3o22bo5b3o$210b
3o5bo4bo2bo22bo5bo2bo$196b3o5bo4bo2bo4b3o6bo28bo$182b3o5bo4bo2bo4b3o6b
o4bob2o5bo28bo3bo$168b3o5bo4bo2bo4b3o6bo4bob2o5bo5b3o2bobo19bo9bo$162b
o4bo2bo4b3o6bo4bob2o5bo5b3o2bobo6b3o23b3o9bobo$161b3o6bo4bob2o5bo5b3o
2bobo6b3o11b3o23bob2o$161bob2o5bo5b3o2bobo6b3o11b3o11b2o25b3o$162b3o2b
obo6b3o11b3o11b2o39b2o$162b3o11b3o11b2o$162b3o11b2o$162b2o$152bo$151b
3o$151bob2o$152b3o$152b2o6$149bo$148b3o$147b2obo$147b3o$148b2o!
Ivan Fomichev
- glider_rider
- Posts: 197
- Joined: February 20th, 2013, 5:41 pm
- Location: CA
Re: 13131: The B-Heptomino/Glider Spaceship Thread
It is possible to use a NW glider for one crawler input, meaning we can get away with one fewer track construction unit, leading to a 269-xWSS helix+fanout (as opposed to 280 previously). This will presumably become 270 since we'll need one more xWSS for period multiplication. Here's an updated script (this also has several other improvements and bugfixes).
With this approach to the fanout, I don't know if using x15 is actually helpful, since it relies on passing NW gliders through parts of the fanout in several places, and a lot of those are already pretty tight squeezes. (It also means I don't need to think about making Coe ships.)
EDIT: Pair track reset mechanism completed:
I'm anticipating we'll need a lot more of these than the waterbear. Here's the generation script:
I suppose I now need to think about how the period multiplication is actually going to work.
EDIT: NE and SE rakes.
Code: Select all
import golly as g
from glife import *
import math
import cmath
import os
from scipy import signal
def mod(x,m):
return ((x%m)+m)%m
#Linear algebra stuff
#Wanted to do this myself rather than using a library
#Whether or not this was smart is debatable
#I ended up using scipy instead because it's much faster
#A rational number
class Rational:
#Constructor
def __init__(self, num: int, den: int = 1):
a = math.gcd(num, den)
self.num = (1, -1)[den < 0] * num // a
self.den = abs(den // a)
#Hashing
def __eq__(self, other)->bool:
if isinstance(other, int):
return self.num == other and self.den == 1
elif isinstance(other, Rational):
return self.num == other.num and self.den == other.den
def __hash__(self) -> int:
return hash((self.num,self.den))
#Comparison
def __ne__(self, other)->bool:
if isinstance(other, int):
return self.num != other or self.den != 1
elif isinstance(other, Rational):
return self.num != other.num or self.den != other.den
def __lt__(self, other) -> bool:
if isinstance(other, int | float):
return self.num < other*self.den
elif isinstance(other, Rational):
return self.num*other.den < other.num*self.den
def __le__(self, other) -> bool:
if isinstance(other, int | float):
return self.num <= other*self.den
elif isinstance(other, Rational):
return self.num*other.den <= other.num*self.den
def __gt__(self, other) -> bool:
if isinstance(other, int | float):
return self.num > other*self.den
elif isinstance(other, Rational):
return self.num*other.den > other.num*self.den
def __ge__(self, other) -> bool:
if isinstance(other, int | float):
return self.num >= other*self.den
elif isinstance(other, Rational):
return self.num*other.den >= other.num*self.den
#Arithmetic
def __add__(self, other):
if isinstance(other, int):
return Rational(self.num+other*self.den, self.den)
elif isinstance(other, Rational):
return Rational(self.num*other.den+other.num*self.den, self.den*other.den)
def __sub__(self, other):
if isinstance(other, int):
return Rational(self.num-other*self.den, self.den)
elif isinstance(other, Rational):
return Rational(self.num*other.den-other.num*self.den, self.den*other.den)
def __mul__(self, other):
if isinstance(other, int):
return Rational(self.num*other, self.den)
elif isinstance(other, Rational):
return Rational(self.num*other.num, self.den*other.den)
def __truediv__(self, other):
if isinstance(other, int):
return Rational(self.num, self.den*other)
elif isinstance(other, Rational):
return Rational(self.num*other.den, self.den*other.num)
def __floordiv__(self, other):
return Rational(int(self / other), 1)
def __mod__(self, other):
return (self / other) - (self // other)
def __neg__(self):
return Rational(-self.num, self.den)
def __abs__(self):
return Rational(abs(self.num), self.den)
#Casting
def __int__(self) -> int:
return self.num // self.den
def __float__(self) -> float:
return self.num / self.den
def __str__(self) -> str:
return str(self.num) + "/" + str(self.den)
#Other math
def gcd(*args):
output = abs(args[0])
for i in range(1,len(args)):
output = Rational(math.gcd(output.num, args[i].num), math.lcm(output.den, args[i].den))
return output
#A matrix of rational numbers
class Matrix:
#Constructor
def __init__(self, terms):
#Automatically convert ints to Rationals
self.terms = [[Rational(1) * term for term in row] for row in terms]
self.height = len(terms)
self.width = 0
if self.height > 0:
self.width = len(terms[0])
#Get terms
def sliceRange(s):
if isinstance(s, int):
return range(s,s+1)
elif isinstance(s, slice):
return range(s.start, s.stop)
def __getitem__(self, key: list[int] | list[slice]):
if isinstance(key[0], int) and isinstance(key[1], int):
return self.terms[key[0]][key[1]]
else:
return Matrix([[self.terms[row][col] for col in Matrix.sliceRange(key[1])] for row in Matrix.sliceRange(key[0])])
#Hashing
def __eq__(self, other)->bool:
return self.terms == other.terms
def __hash__(self) -> int:
return hash(tuple(tuple(row) for row in self.terms))
#Arithmetic
def __add__(self, other):
return Matrix([[term1 + term2 for term1, term2 in zip(row1,row2)] for row1, row2 in zip(self.terms,other.terms)])
def __sub__(self, other):
return Matrix([[term1 - term2 for term1, term2 in zip(row1,row2)] for row1, row2 in zip(self.terms,other.terms)])
#Scalar or matrix multiplication
def __mul__(self, other):
if isinstance(other, int | Rational):
return Matrix([[term * other for term in row] for row in self.terms])
elif isinstance(other, Matrix):
return Matrix([[sum([self[rowIndex,sharedIndex]*other[sharedIndex,colIndex] for sharedIndex in range(self.width)], Rational(0)) for colIndex in range(other.width)] for rowIndex in range(self.height)])
elif isinstance(other, CosetMatrix):
return CosetMatrix(self*other.rep, other.lattice)
def __div__(self, other):
return Matrix([[term / other for term in row] for row in self.terms])
def __neg__(self):
return Matrix([[-term for term in row] for row in self.terms])
def transpose(self):
return Matrix([[self[rowIndex,colIndex] for rowIndex in range(self.height)] for colIndex in range(self.width)])
def copy(self):
return Matrix([[term for term in row] for row in self.terms])
def row(self, row: int):
return self[row, 0:self.width]
def col(self, col: int):
return self[0:self.height, col]
def rows(self):
return [self.row(n) for n in range(self.height)]
def cols(self):
return [self.col(n) for n in range(self.width)]
def __str__(self):
output = ""
for row in range(self.height):
output += "["
for col in range(self.width):
output += str(self[row,col])
if col < self.width-1:
output += ","
output += "]"
if row < self.height-1:
output += "\n"
return output
def isZero(self):
return all(all(term == 0 for term in row) for row in self.terms)
#Tools for making block matrices
def blockHorizontal(self, other):
return Matrix([row1+row2 for row1,row2 in zip(self.terms, other.terms)])
def blockVertical(self, other):
return Matrix(self.terms+other.terms)
#Row reduction
def rowReduce(self):
output = self.copy()
rowIndex = 0
colIndex = 0
while rowIndex < output.height and colIndex < output.width:
#Check if this column is zero below rowIndex, if so goto next column
nonzeroRowIndex = next((rowCheckIndex for rowCheckIndex in range(rowIndex, output.height) if output[rowCheckIndex,colIndex] != 0), -1)
if nonzeroRowIndex == -1:
colIndex += 1
else:
#Otherwise, do a row-reduction step
#Swap rows rowIndex and nonzeroRowIndex if needed
if nonzeroRowIndex != rowIndex:
output.swapRowsInPlace(rowIndex, nonzeroRowIndex)
#Normalize to 1
divideByVal = output[rowIndex, colIndex]
output.terms[rowIndex] = [term / divideByVal for term in output.terms[rowIndex]]
for otherRowIndex in range(output.height):
if otherRowIndex != rowIndex:
output.terms[otherRowIndex] = [otherRowTerm - rowTerm * output[otherRowIndex, colIndex] for rowTerm, otherRowTerm in zip(output.terms[rowIndex], output.terms[otherRowIndex])]
rowIndex += 1
return output
def swapRowsInPlace(self, row1: int, row2: int):
self.terms[row1], self.terms[row2] = self.terms[row2], self.terms[row1]
def removeZeroRows(self):
return Matrix([row for row in self.terms if not all(term == 0 for term in row)])
def det(self):
rowReducedForm = self.rowReduce()
return math.prod([rowReducedForm[i,i] for i in range(rowReducedForm.width)])
def rank(self):
return len([row for row in self.terms if not all(term == 0 for term in row)])
def id(n: int):
return Matrix([[Rational(int(row == col)) for col in range(n)] for row in range(n)])
def zero(height: int, width: int):
return Matrix([[Rational(0) for col in range(width)] for row in range(height)])
#Gives the inverse of an invertible square matrix
def inverse(self):
return self.blockHorizontal(Matrix.id(self.width)).rowReduce()[0:self.height,self.width:self.width*2]
#Gives a right inverse
def rightInverse(self):
transpose = self.transpose()
return transpose * (self * transpose).inverse()
#Row reduction but we can only use integer multiples
def integerRowReduce(self):
output = self.copy()
rowIndex = 0
colIndex = 0
while rowIndex < output.height and colIndex < output.width:
#Check if this column is zero below rowIndex, if so goto next column
existsANonzeroEntry = False
rowToTest = rowIndex
while rowToTest < output.height:
if output[rowToTest, colIndex] > 0:
#Found a nonzero entry
existsANonzeroEntry = True
if rowToTest == rowIndex:
#On the starting row, so we don't do much
rowToTest += 1
else:
if output[rowIndex, colIndex] < output[rowToTest, colIndex]:
#swap rows
output.swapRowsInPlace(rowIndex, rowToTest)
else:
#subtract as many terms[rowToTest] from terms[rowIndex] as possible
mult = output[rowIndex, colIndex] // output[rowToTest, colIndex]
output.terms[rowIndex] = [term - testTerm * mult for term, testTerm in zip(output.terms[rowIndex],output.terms[rowToTest])]
elif output[rowToTest, colIndex] < 0:
#Switch sign of this row
output.terms[rowToTest] = [-term for term in output.terms[rowToTest]]
else:
#Entry cleared, move to next row
rowToTest += 1
if existsANonzeroEntry and rowIndex < output.height and colIndex < output.width and output[rowIndex, colIndex] != 0:
#Subtract as much from the rows < rowIndex as possible while leaving the term positive
for rowToModify in range(rowIndex):
mult = output[rowToModify, colIndex] // output[rowIndex, colIndex]
output.terms[rowToModify] = [termToModify - term * mult for term, termToModify in zip(output.terms[rowIndex],output.terms[rowToModify])]
rowIndex += 1
else:
colIndex += 1
return output
#A lattice of rational points
class Lattice:
#Constructor
def __init__(self, basis: Matrix, rowReduceBasis: bool = True):
#Do integer row reduction for our basis by default
if rowReduceBasis:
self.basis = basis.integerRowReduce().removeZeroRows()
else:
self.basis = basis.copy()
self.dimension = self.basis.width
self.rank = self.basis.height
#Find pivot columns
#The index of the first nonzero column in each row
self.pivots = [[x != 0 for x in row].index(True) for row in self.basis.terms]
#Find inverse of the generator matrix
self.changeOfBasis = self.basis.rightInverse()
#Gets canonical coset representative for a matrix
def getCosetRepresentative(self, matrix: Matrix) -> Matrix:
output = matrix.copy()
for matrixRowIndex in range(matrix.height):
for rowIndex in range(len(self.pivots)):
colIndex = self.pivots[rowIndex]
generatorValue = self.basis[rowIndex,colIndex]
matrixValue = output[matrixRowIndex,colIndex]
output.terms[matrixRowIndex] = [output[matrixRowIndex,termIndex] - self.basis[rowIndex,termIndex] * (matrixValue // generatorValue) for termIndex in range(matrix.width)]
return output
#Does this lattice group contain a given row vector
def __contains__(self, vector: Matrix) -> bool:
return self.getCosetRepresentative(vector).isZero()
#Sum of two lattices
def __add__(self, other):
return Lattice(self.basis.blockVertical(other.basis))
def addGenerators(self, basisVectors: Matrix):
return Lattice(self.basis.blockVertical(basisVectors))
#Gets coordinates of the row vectors in a matrix where all row vectors are in this lattice
def getCoordinates(self, matrix: Matrix) -> Matrix:
return matrix * self.changeOfBasis
#Whether or not this lattice contains a multiple of the row vector for each row of a given matrix
def containsMultiple(self, matrix: Matrix) -> bool:
return self.getCoordinates(matrix) * self.basis == matrix
#The intersection of self with the plane other lies in
def intersectWithPlane(self,other):
#add in extra coordinates that don't lie in this plane
otherExtraBasis = other.basis
n = 0
while otherExtraBasis.height < otherExtraBasis.width:
testVector = Matrix([[Rational(int(a==n)) for a in range(otherExtraBasis.width)]])
n += 1
if not Lattice(otherExtraBasis).containsMultiple(testVector):
otherExtraBasis = testVector.blockVertical(otherExtraBasis)
otherExtraBasisInverse = otherExtraBasis.inverse()
basisInOtherCoordsReduced = (self.basis * otherExtraBasisInverse).integerRowReduce()
#Isolate only the rows that don't rely on the first few terms
basisInPlaneInOtherCoords = Matrix([row for row in basisInOtherCoordsReduced.terms if all(row[i]==0 for i in range(other.basis.width - other.basis.height))])
#Convert from coordinates
basisInPlane = basisInPlaneInOtherCoords * otherExtraBasis
return Lattice(basisInPlane)
#The dual of a lattice
def dual(self):
return Lattice(self.changeOfBasis.transpose(), False)
#The intersection of two lattices
def __and__(self, other):
return (self.dual() + other.dual()).dual().intersectWithPlane(self).intersectWithPlane(other)
#The lattice of integer divisors of a given lattice
def divisorLattice(self):
return LatticeGroup(Matrix.id(self.dimension)).intersectWithPlane(self)
#A basis for the torsion-free part of G/H
#Output as a matrix with rows v s.t. v+H form our basis
def quotientTorsionFreeBasis(self, sublattice):
divisorLattice = self.intersectWithPlane(sublattice)
divisorLatticeBasisExtended = divisorLattice.basis
nonPivots = [x for x in range(divisorLattice.dimension) if x not in divisorLattice.pivots]
for nonPivot in nonPivots:
divisorLatticeBasisExtended = self.basis.row(nonPivot).blockVertical(divisorLatticeBasisExtended)
divisorLatticeBasisExtendedInverse = divisorLatticeBasisExtended.inverse()
basisVectorsInDivisorLatticeExtendedCoordsReduced = (self.basis * divisorLatticeBasisExtendedInverse).integerRowReduce()
nonPivotBasisVectorsToCoords = basisVectorsInDivisorLatticeExtendedCoordsReduced[0:(divisorLattice.dimension-divisorLattice.rank),0:divisorLattice.dimension]
return CosetMatrix((nonPivotBasisVectorsToCoords * divisorLatticeBasisExtended).integerRowReduce(), sublattice)
#The torsion elements of G/H
def quotientTorsionElements(self, sublattice):
#We know these are all in divisorLattice
divisorLattice = self.intersectWithPlane(sublattice)
intermediateLattice = sublattice
#Find torsion of all basis elements
generators = Matrix([])
torsions = []
for basisElt in divisorLattice.basis.rows():
#Find the torsion of this basis element in the intermediate lattice
basisEltCoords = basisElt * intermediateLattice.changeOfBasis
#Torsion is the gcd of the elements of basisEltCoords
torsion = Rational.gcd(*basisEltCoords.terms[0]).den
torsions.append(torsion)
generators = generators.blockVertical(basisElt)
intermediateLattice = intermediateLattice.addGenerators(basisElt)
#Output as an iterator
def outputGenerator(basisElts, torsions):
multiplicities = [0 for torsion in torsions]
while True:
yield CosetMatrix(Matrix([multiplicities]) * basisElts, sublattice)
#Increment
index = 0
multiplicities[0]+=1
while index < len(multiplicities) and multiplicities[index] == torsions[index]:
multiplicities[index] = 0
index += 1
if index < len(multiplicities):
multiplicities[index]+=1
if index == len(multiplicities):
break
return outputGenerator(basisElts, torsions)
#Generators for G/H, with torsions (0 if torsion-free)
def quotientGeneratorsWithTorsions(self, sublattice):
#We know these are all in divisorLattice
divisorLattice = self.intersectWithPlane(sublattice)
intermediateLattice = sublattice
#Find torsion of all basis elements
generators = Matrix([])
torsions = []
for basisElt in divisorLattice.basis.rows():
#Find the torsion of this basis element in the intermediate lattice
basisEltCoords = basisElt * intermediateLattice.changeOfBasis
#Torsion is the gcd of the elements of basisEltCoords
torsion = Rational.gcd(*basisEltCoords.terms[0]).den
#if torsion != 1:
torsions.append(torsion)
generators = generators.blockVertical(basisElt)
intermediateLattice = intermediateLattice.addGenerators(basisElt)
#Add in the torsion-free basis
#return list(zip([CosetMatrix(row, sublattice) for row in generators.rows()], torsions)) + [(row,0) for row in self.quotientTorsionFreeBasis(sublattice).rows()]
return list(zip(generators.rows(), torsions)) + [(row.rep,0) for row in self.quotientTorsionFreeBasis(sublattice).rows()]
#Divides an envelope into a dictionary of cosets by a lattice
def divideIntoCosets(self, envelope):
output = dict()
for v in envelope:
key = CosetMatrix(v, self)
if key in output:
output[key].append(v)
else:
output[key] = [v]
#g.warn("".join(str(k.rep)+": "+str([str(x) for x in v])+"\n\n" for k,v in output.items()))
return output
#A matrix of lattice cosets of the form v+H
class CosetMatrix:
#Constructor
def __init__(self, rep: Matrix, lattice: Lattice):
self.lattice = lattice
self.rep = lattice.getCosetRepresentative(rep)
self.width = self.rep.width
self.height = self.rep.height
#Hashing
def __hash__(self) -> int:
return hash((self.rep))
def __eq__(self, other) -> bool:
return self.rep == other.rep
def __ne__(self, other) -> bool:
return self.rep != other.rep
#Arithmetic
def __add__(self, other) -> bool:
if isinstance(other, CosetMatrix):
return CosetMatrix(self.rep+other.rep, self.lattice)
elif isinstance(other, Matrix):
return CosetMatrix(self.rep+other, self.lattice)
def __sub__(self, other) -> bool:
if isinstance(other, CosetMatrix):
return CosetMatrix(self.rep-other.rep, self.lattice)
elif isinstance(other, Matrix):
return CosetMatrix(self.rep-other, self.lattice)
def __neg__(self) -> bool:
return CosetMatrix(-self.rep, self.lattice)
#Matrix multiplication
#Note: We also multiply the lattice basis
def __mul__(self, other):
return CosetMatrix(self.rep * other, Lattice(self.lattice.basis * other))
def rows(self):
return [CosetMatrix(row, self.lattice) for row in self.rep.rows()]
#A function from Z^n -> int
class LatticeFunction:
def __init__(self, data, dimension):
self.data = data
self.dimension = dimension
self.minCoords = [min(int(key[0,i]) for key,value in self.data.items()) for i in range(self.dimension)]
self.maxCoords = [max(int(key[0,i]) for key,value in self.data.items()) for i in range(self.dimension)]
self.coordDiffs = [x-y for x,y in zip(self.maxCoords, self.minCoords)]
#Convolve using Fourier transform
def convolve(self, other):
#Find amounts to wrap around
#These must be wrapArounds[i] a power of 2 satisfying wrapArounds[i] > self.coordDiffs[i] + other.coordDiffs[i]
#wrapArounds = [1<<(x+y).bit_length() for x,y in zip(self.coordDiffs, other.coordDiffs)]
wrapArounds = [x+y+1 for x,y in zip(self.coordDiffs, other.coordDiffs)]
#return LatticeFunction.unwrapData(LatticeFunction.fft([x*y for x,y in zip(LatticeFunction.fft(self.wrapData(wrapArounds), 1, 1), LatticeFunction.fft(other.wrapData(wrapArounds), 1, 1))], -1, 0.5), wrapArounds, Matrix([self.minCoords])+Matrix([other.minCoords]))
selfData = self.wrapData(wrapArounds)
otherData = other.wrapData(wrapArounds)
g.show("Convolving with length " + str(math.prod(wrapArounds)) + " " + str(tuple(wrapArounds)) + "...")
return LatticeFunction.unwrapData(signal.fftconvolve(selfData, otherData), wrapArounds, Matrix([self.minCoords])+Matrix([other.minCoords]))
#Wraps data to a list, where wrapArounds[i] are our sufficiently large powers of 2
def wrapData(self, wrapArounds):
g.show("Wrapping...")
wrapAroundsCumulative = [math.prod(wrapArounds[0:i]) for i in range(len(wrapArounds)+1)]
output = [0 for x in range(math.prod(wrapArounds))]
#Edit output.data
for key, value in self.data.items():
#Offset by self.minCoords so that indices are all positive
keyIndex = sum(mod(int(key[0,i] - self.minCoords[i]), wrapArounds[i])*wrapAroundsCumulative[i] for i in range(self.dimension))
output[keyIndex] = value
return output
#1-dimensional fast Fourier transform of an array of length 2^n
#Using the Cooley-Tukey algorithm
#I don't actually use this because signal.fftconvolve is faster but it was fun to implement
numFFTs = 0
def fft(data, sign: int = 1, scalePerStep = 1):
outputData = data.copy()
dataSize = len(outputData).bit_length() - 1
#Precompute twiddle factors
g.show("FFT " + str(LatticeFunction.numFFTs+1) + "/12: Computing twiddle factors...")
twiddleFactors = [cmath.exp(-sign * 2j * math.pi * k / (1 << dataSize)) for k in range(1 << dataSize)]
for step in range(0,dataSize):
g.show("FFT " + str(LatticeFunction.numFFTs+1) + "/12: " + str(step) + "/" + str(dataSize))
nextData = []
splitPos = dataSize - step - 1
splitPosMaskBit = 1 << splitPos
belowSplitPosMask = splitPosMaskBit - 1
aboveSplitPosMask = ((1 << (dataSize-1)) - 1) & ~belowSplitPosMask
for i in range(len(outputData)):
#Input indices
#How this works: Take i, split into before and after parts at data-step-1, bitshift after part up 1, insert a 0 or 1 bit
lowerInputIndex = (i & belowSplitPosMask) | ((i & aboveSplitPosMask) << 1)
upperInputIndex = lowerInputIndex | splitPosMaskBit
#Parity
paritySign = 1 - ((i >> (dataSize - 1)) << 1)
#Twiddle factor index
k = i & aboveSplitPosMask
#print(str(step) + ", " + str(i) + ": " + str(lowerInputIndex) + ", " + str(upperInputIndex) + str(" ") + str(k) + ", " + str(twiddleFactor))
nextData.append((outputData[lowerInputIndex] + paritySign * twiddleFactors[k] * outputData[upperInputIndex]) * scalePerStep)
#Progress bar for my sanity
outputData = nextData
g.show("FFT " + str(LatticeFunction.numFFTs) + "/6: " + str(dataSize) + "/" + str(dataSize))
LatticeFunction.numFFTs += 1
return outputData
#Unwrap a list to a LatticeFunction (rounding to ints)
def unwrapData(data, wrapArounds, offset):
g.show("Unwrapping...")
wrapAroundsCumulative = [math.prod(wrapArounds[0:i]) for i in range(len(wrapArounds)+1)]
outputData = {}
for keyIndex in range(len(data)):
if not cmath.isclose(data[keyIndex], 0, rel_tol=1e-09, abs_tol=1e-09):
#Nonzero entry
key = Matrix([[mod(keyIndex // wrapAroundsCumulative[i], wrapArounds[i]) for i in range(len(wrapArounds))]]) + offset
outputData[key] = round(data[keyIndex].real)
return LatticeFunction(outputData, len(wrapArounds))
#Wraps data to a function on a quotient group
def wrapToQuotientFunction(self, group, sign: int = 1):
outputData = {}
for key,value in self.data.items():
quotientKey = CosetMatrix(key * group.optimalLatticeBasis * sign, group.sublattice)
if quotientKey in outputData:
outputData[quotientKey] += value
else:
outputData[quotientKey] = value
return QuotientGroupFunction(group, outputData)
#A quotient of lattices
class QuotientGroup:
def __init__(self, lattice: Lattice, sublattice: Lattice):
#On initialization, organize
self.lattice = lattice
self.sublattice = sublattice
self.generatorsWithTorsions = lattice.quotientGeneratorsWithTorsions(sublattice)
#Find optimal basis for compact unwrapping
# I'm pretty sure this is actually pretty optimal for our purposes
self.optimalLatticeBasis = self.lattice.basis
self.optimalChangeOfBasis = self.optimalLatticeBasis.rightInverse()
#Other thing I considered, seems worse though
#self.optimalLatticeBasis = Matrix([generator.terms[0] for generator, torsion in self.generatorsWithTorsions])
#g.warn(str(self.lattice.basis) + "\n\n" + str(self.sublattice.basis) + "\n\n" + str(self.optimalLatticeBasis))
#A function from G/H -> int
class QuotientGroupFunction:
def __init__(self, group: QuotientGroup, data):
self.group = group
#A dictionary from cosets v+group.sublattice to ints
self.data = data
#Unwraps to a LatticeFunction
def unwrap(self):
return LatticeFunction({key.rep * self.group.optimalChangeOfBasis: self.data[key] for key in self.data}, self.group.optimalChangeOfBasis.width)
#Wraps to a further quotient
def wrapToQuotientFunction(self, group, sign: int = 1):
outputData = {}
for key,value in self.data.items():
quotientKey = CosetMatrix(key.rep * group.optimalLatticeBasis * sign, group.sublattice)
if quotientKey in outputData:
outputData[quotientKey] += value
else:
outputData[quotientKey] = value
return QuotientGroupFunction(group, outputData)
#Function convolution
def convolve(self, other):
return self.unwrap().convolve(other.unwrap()).wrapToQuotientFunction(self.group)
#Golly misc help stuff
#Helpful conversions
def toCellSet(cellList):
return {(cellList[i],cellList[i+1]) for i in range(0,len(cellList),2)}
def toCellList(cellSet):
return [num for x,y in cellSet for num in [x,y]]
#nonempty getrect
def getrect():
if g.empty():
return [0,0,1,1]
return g.getrect()
#This is just convenient
def gethash():
return g.hash(getrect())
def getcells():
return g.getcells(getrect())
#Does the pattern contain a given cell list
def patternContains(cellList, x=0, y=0):
return toCellSet(g.transform(cellList,x,y)).issubset(toCellSet(getcells()))
#Tools for pattern decomposition into components
#For a decomposition of Child(p) = DisjointUnion(q_i)
# Returns a decomposition of this pattern as p = DisjointUnion(p_j) such that Child(p_j) = DisjointUnion(q_{i_{j,k}})
# All inputs and outputs are given as cell sets
nbhd = {(x,y) for x in range(-1,2) for y in range(-1,2)}
def findSubpatterns(patternState, childDecomposition):
#Start by decomposing into connected components
#output = findConnectedComponents(patternState, {(x,y) for x in range(-1,2) for y in range(-1,2)})
output = set()
for cell in patternState:
nbhdOfCell = {(cell[0]+x,cell[1]+y) for x,y in nbhd}
#Check against all children in childDecomposition
requiredCells = {cell}
for childCellSet in childDecomposition:
if not nbhdOfCell.isdisjoint(childCellSet):
#This child's component must contain patternState intersect nbhd(childCellSet)
requiredCells |= patternState & set().union(*[{(a[0]+b[0],a[1]+b[1]) for a in nbhd} for b in childCellSet])
#We require all these cells in our component
componentsToUnionWith = {component for component in output if not requiredCells.isdisjoint(component)}
output -= componentsToUnionWith
output.add(frozenset({cell}.union(*componentsToUnionWith)))
#Additionally, unionize any components around cells that don't match
evolvedState = set().union(*childDecomposition)
evolvedComponentStatesUnion = set().union(*[toCellSet(g.evolve(toCellList(component),1)) for component in output])
error = evolvedState ^ evolvedComponentStatesUnion
for errorCell in error:
nbhdOfCell = {(errorCell[0]+x,errorCell[1]+y) for x,y in nbhd}
#Unionize all components intersecting nbhdOfCell
componentsToUnionWith = {component for component in output if not nbhdOfCell.isdisjoint(component)}
output -= componentsToUnionWith
output.add(frozenset().union(*componentsToUnionWith))
return output
#Removes unneccessary cells from the evolution of this pattern (requiring patFinalState in the final result)
def removeAshCells(patEvolution, patFinalState):
#Find the indepdenent subpatterns of this at each stage
patFinalStateCellSet = frozenset(toCellSet(patFinalState))
patFinalStateCellSetWithExtra = frozenset(toCellSet(g.evolve(patEvolution[len(patEvolution)-1], 1)))
patFinalDecomposition = {patFinalStateCellSet} | {frozenset({cell}) for cell in patFinalStateCellSetWithExtra - patFinalStateCellSet}
patDecompositions = [patFinalDecomposition]
for i in reversed(range(len(patEvolution))):
#Find the prior decomposition
prevDecomposition = findSubpatterns(toCellSet(patEvolution[i]), patDecompositions[0])
patDecompositions.insert(0, prevDecomposition)
#Construct list of only the minimal decompositions leading to patFinalState
minComponents = [patFinalStateCellSet]
for i in reversed(range(len(patEvolution))):
#Need component intersects nbhd(minComponents[0])
try:
prevMinComponent = next(component for component in patDecompositions[i] if not component.isdisjoint(set().union(*[{(a[0]+b[0],a[1]+b[1]) for a in nbhd} for b in minComponents[0]])))
minComponents.insert(0, prevMinComponent)
except StopIteration:
#This only happens when our cell has no predecessors
#This isn't common, but can occur when we add in components mid-evolution
continue
#Convert back to cell lists, remove the last component
return [toCellList(component) for component in minComponents[0:len(minComponents)-1]]
cellLattice = Lattice(Matrix.id(3))
#A periodic pattern with inputs and outputs
class PeriodicPattern:
def __init__(self, cellList, dT, dX, dY, inputs = [], outputs = [], computeExtras = False):
self.dX = dX
self.dY = dY
self.dT = dT
self.inputs = inputs
self.outputs = outputs
self.inputNamesToIndexes = {inputs[i][1]:i for i in range(len(inputs))}
self.outputNamesToIndexes = {outputs[i][1]:i for i in range(len(outputs))}
self.periodVector = Matrix([[self.dT, -self.dX, -self.dY]])
self.periodLattice = Lattice(self.periodVector)
self.positionGroup = QuotientGroup(cellLattice, self.periodLattice)
#Find states
currentState = cellList.copy()
self.state = []
g.setrule("B3/S23")
for t in range(self.dT):
#Remove all outputs on this generation from currentState
#TODO: Could be nice to add a way for outputs to be removed 'late'/after a full cycle
# Or generally for the pattern to 'fill in' over multiple cycles, so that sparks are covered too
for outputPattern, outputName, outputTimeToRemove, outputPosition in outputs:
if outputTimeToRemove == t:
currentState = outputPattern.joinInto(currentState, outputPosition, "andnot")
self.state.append(currentState)
#Join all inputs on this generation to currentState
for inputPattern, inputName, inputTimeToAdd, inputPosition in inputs:
if inputTimeToAdd == t:
currentState = inputPattern.joinInto(currentState, inputPosition, "or")
currentState = g.evolve(currentState, 1)
if computeExtras:
#Precompute some envelopes for collision purposes
g.setrule("B12345678/S012345678")
self.envelopeA = LatticeFunction(dict.fromkeys({Matrix([[t,-x,-y]]) for t in range(self.dT) for x,y in toCellSet(g.evolve(self.state[t],1))}, 1), 3)
g.setrule("B3/S012345678")
self.envelopeB = LatticeFunction(dict.fromkeys({Matrix([[t,-x,-y]]) for t in range(self.dT) for x,y in toCellSet(g.evolve(self.state[t],1))}, 1), 3)
g.setrule("B1/S")
self.envelopeC = LatticeFunction(dict.fromkeys({Matrix([[t,-x,-y]]) for t in range(self.dT) for x,y in toCellSet(g.evolve(self.state[t],1))}, 1), 3)
g.setrule("B2/S")
self.envelopeD = LatticeFunction(dict.fromkeys({Matrix([[t,-x,-y]]) for t in range(self.dT) for x,y in toCellSet(g.evolve(self.state[t],1))}, 1), 3)
g.setrule("B3/S23")
#Find states required for pattern to be restored
#TODO: Also find states required for outputs
# Approach we take: Remove any unnecessary cells (parts that permanently have no influence on the rest of the crawler)
#Fill in crawlerStates
#We iterate twice to prevent pruning ash near the end of the cycle that would collide with the crawler later
#TODO: Most of this is just copy-pasted, I could definitely do this better
extendedState = self.state.copy()
for t in range(self.dT):
#Remove all outputs on this generation from currentState
for outputPattern, outputName, outputTimeToRemove, outputPosition in outputs:
if outputTimeToRemove == t:
currentState = outputPattern.joinInto(currentState, outputPosition + Matrix([[0,self.dX,self.dY]]), "andnot")
extendedState.append(currentState)
#Join all inputs on this generation to currentState
for inputPattern, inputName, inputTimeToAdd, inputPosition in inputs:
if inputTimeToAdd == t:
currentState = inputPattern.joinInto(currentState, inputPosition + Matrix([[0,self.dX,self.dY]]), "or")
currentState = g.evolve(currentState, 1)
#TODO: This is *probably* too strict, since some of the pi-crawler pairs I expected don't show up
self.requiredState = removeAshCells(extendedState, g.transform(self.state[0], self.dX*2, self.dY*2))[0:self.dT]
def getStatePosition(self, position, onlyRequired = False):
if onlyRequired:
return g.transform(self.requiredState[int(position.rep[0,0])], int(position.rep[0,1]), int(position.rep[0,2]))
else:
return g.transform(self.state[int(position.rep[0,0])], int(position.rep[0,1]), int(position.rep[0,2]))
def joinInto(self, cellList, position, mode):
if mode == "or":
return g.join(cellList, self.getStatePosition(position))
elif mode == "andnot":
return toCellList(toCellSet(cellList) - toCellSet(self.getStatePosition(position)))
def place(self, position, mode = "or", onlyRequired = False):
g.putcells(self.getStatePosition(position, onlyRequired),0,0,1,0,0,1, mode)
def placeInput(self, position, index, mode = "or"):
stateT = int(position.rep[0,0])
for inputPattern, inputName, inputTimeToAdd, inputPosition in self.inputs:
indexToUse = index + (1,0)[inputTimeToAdd >= stateT]
inputPattern.place(inputPosition + (position.rep + Matrix([[-inputTimeToAdd, 0, 0]]) - Matrix([[self.dT, -self.dX, -self.dY]]) * indexToUse), mode)
def placeOutput(self, position, index, mode = "or"):
stateT = int(position.rep[0,0])
for outputPattern, outputName, outputTimeToRemove, outputPosition in self.outputs:
indexToUse = index + (1,0)[outputTimeToRemove <= stateT]
outputPattern.place(outputPosition + (position.rep + Matrix([[-outputTimeToRemove, 0, 0]]) + Matrix([[self.dT, -self.dX, -self.dY]]) * indexToUse), mode)
#Place with inputs (and outputs)
def placeWithInputs(self, position, numInputs = 0, numOutputs = 0, mode = "or", onlyRequired = False):
self.place(position, mode, onlyRequired)
for i in range(0,numInputs):
self.placeInput(position, i, mode)
for i in range(0,numOutputs):
self.placeOutput(position, i, mode)
#Test this pattern with inputs (and outputs)
# We only want to test against the minimum envelope required to sustain the component
#TODO: Allow more customizability in input/output testing
def test(self, position, onlyRequired = True):
return patternContains(self.getStatePosition(position, onlyRequired))
def testInput(self, position, index):
stateT = int(position.rep[0,0])
for inputPattern, inputName, inputTimeToAdd, inputPosition in self.inputs:
indexToUse = index + (1,0)[inputTimeToAdd >= stateT]
if not inputPattern.test(inputPosition + (position.rep + Matrix([[-inputTimeToAdd, 0, 0]]) - Matrix([[self.dT, -self.dX, -self.dY]]) * indexToUse)):
return False
return True
def testOutput(self, position, index):
stateT = int(position.rep[0,0])
for outputPattern, outputName, outputTimeToRemove, outputPosition in self.outputs:
indexToUse = index + (1,0)[outputTimeToRemove <= stateT]
if not outputPattern.test(outputPosition + (position.rep + Matrix([[-outputTimeToRemove, 0, 0]]) + Matrix([[self.dT, -self.dX, -self.dY]]) * indexToUse)):
return False
return True
def testWithInputs(self, position, numInputs = 0, numOutputs = 0):
return self.test(position) and all(self.testInput(position,i) for i in range(0, numInputs)) and all(self.testOutput(position,i) for i in range(0, numOutputs))
#Enumerate all possible collisions/interaction separations between two objects
#NOTE: This is optimized for the case where self is small
#TODO: Would probably like to make a version optimized for where self is not small
# I'm not entirely sure how best to do that
def enumerateCollisionSeparations(self, other):
separationLattice = self.periodLattice + other.periodLattice
separationGroup = QuotientGroup(cellLattice, separationLattice)
#Wrapping our envelopes first is probably more efficient
prewrapSelfA = self.envelopeA.wrapToQuotientFunction(separationGroup, -1)
prewrapSelfB = self.envelopeB.wrapToQuotientFunction(separationGroup, -1)
prewrapSelfC = self.envelopeC.wrapToQuotientFunction(separationGroup, -1)
prewrapSelfD = self.envelopeD.wrapToQuotientFunction(separationGroup, -1)
prewrapOtherA = other.envelopeA.wrapToQuotientFunction(separationGroup, 1)
prewrapOtherB = other.envelopeB.wrapToQuotientFunction(separationGroup, 1)
prewrapOtherC = other.envelopeC.wrapToQuotientFunction(separationGroup, 1)
prewrapOtherD = other.envelopeD.wrapToQuotientFunction(separationGroup, 1)
collisionSeparationCosets = set(prewrapSelfA.convolve(prewrapOtherB).data) | set(prewrapSelfB.convolve(prewrapOtherA).data) | set(prewrapSelfC.convolve(prewrapOtherD).data) | set(prewrapSelfD.convolve(prewrapOtherC).data)
#Want to find the first possible absolute separations
#This means, for each separationCoset in collisionSeparationCosets, we want to find the first time resulting in an interaction
#Divide our envelopes into cosets
selfCosetsA = separationLattice.divideIntoCosets(self.envelopeA.data)
selfCosetsB = separationLattice.divideIntoCosets(self.envelopeB.data)
selfCosetsC = separationLattice.divideIntoCosets(self.envelopeC.data)
selfCosetsD = separationLattice.divideIntoCosets(self.envelopeD.data)
otherCosetsA = separationLattice.divideIntoCosets(other.envelopeA.data)
otherCosetsB = separationLattice.divideIntoCosets(other.envelopeB.data)
otherCosetsC = separationLattice.divideIntoCosets(other.envelopeC.data)
otherCosetsD = separationLattice.divideIntoCosets(other.envelopeD.data)
#Find earliest interatction cells for each coset
#Idea:
# Want to understand the space of vectors v such that CosetMatrix(v, self.periodLattice) in selfEnvelope, and CosetMatrix(v + separation, other.periodLattice) in otherEnvelope
# That is, exist m,n such that v + m*self.periodVector in selfEnvelope.reps, v + separation + n*other.periodVector in otherEnvelope.reps
# Have x in selfEnvelope.reps, y in otherEnvelope.reps such that v + m*self.periodVector = x, v + separation + n*other.periodVector = y
# Then x+separation-y = m*self.periodVector - n*other.periodVector
# So [m,-n] = (x+separation-y) * changeOfCoords
# In particular, m = (x+separation-y) * changeOfCoords.col(0)
# Then v = x - self.periodVector * ((x+separation-y) * changeOfCoords.col(0))[0,0]
# Specifically, v[0,0] = x[0,0] - self.periodVector[0,0] * ((x+separation-y) * changeOfCoords.col(0))[0,0]
# = x[0,0] - self.periodVector[0,0] * (x * changeOfCoords.col(0))[0,0] + self.periodVector[0,0] * ((y-separation) * changeOfCoords.col(0))[0,0]
# = x * ([[1],[0],[0]] - changeOfCoords.col(0) * self.periodVector[0,0]) + (y-separation) * changeOfCoords.col(0) * self.periodVector[0,0]
cMulOther = self.periodVector.blockVertical(other.periodVector).rightInverse().col(0) * self.periodVector[0,0]
cMulSelf = Matrix([[1],[0],[0]]) - cMulOther
def findContribs(cosetReps, multiplier):
return {coset: min((rep * multiplier)[0,0] for rep in cosetReps[coset]) for coset in cosetReps}
selfContribsA = findContribs(selfCosetsA, cMulSelf)
selfContribsB = findContribs(selfCosetsB, cMulSelf)
selfContribsC = findContribs(selfCosetsC, cMulSelf)
selfContribsD = findContribs(selfCosetsD, cMulSelf)
otherContribsA = findContribs(otherCosetsA, cMulOther)
otherContribsB = findContribs(otherCosetsB, cMulOther)
otherContribsC = findContribs(otherCosetsC, cMulOther)
otherContribsD = findContribs(otherCosetsD, cMulOther)
#Remark: This is rather slow when self is large
#TODO: Would like a better approach to this
def minContrib(separation, selfContribs, otherContribs):
return min((selfContribs[coset] + otherContribs[coset + separation] for coset in selfContribs if coset + separation in otherContribs), default = math.inf)
for separationCoset in collisionSeparationCosets:
minT = min(minContrib(separationCoset.rep, selfContribsA, otherContribsB),
minContrib(separationCoset.rep, selfContribsB, otherContribsA),
minContrib(separationCoset.rep, selfContribsC, otherContribsD),
minContrib(separationCoset.rep, selfContribsD, otherContribsC)) - (separationCoset.rep * cMulOther)[0,0]
yield [CosetMatrix(Matrix([[minT,0,0]]), self.periodLattice), CosetMatrix(Matrix([[minT,0,0]]) + separationCoset.rep, other.periodLattice)]
#Enumerate interactions between two objects with the same velocity
#NOTE: This is less size-dependent
def enumerateInteractionSeparations(self, other):
separationLattice = self.periodLattice + other.periodLattice
separationGroup = QuotientGroup(cellLattice, separationLattice)
#Wrapping our envelopes first is probably more efficient
prewrapSelfA = self.envelopeA.wrapToQuotientFunction(separationGroup, -1)
prewrapSelfB = self.envelopeB.wrapToQuotientFunction(separationGroup, -1)
prewrapSelfC = self.envelopeC.wrapToQuotientFunction(separationGroup, -1)
prewrapSelfD = self.envelopeD.wrapToQuotientFunction(separationGroup, -1)
prewrapOtherA = other.envelopeA.wrapToQuotientFunction(separationGroup, 1)
prewrapOtherB = other.envelopeB.wrapToQuotientFunction(separationGroup, 1)
prewrapOtherC = other.envelopeC.wrapToQuotientFunction(separationGroup, 1)
prewrapOtherD = other.envelopeD.wrapToQuotientFunction(separationGroup, 1)
collisionSeparationCosets = set(prewrapSelfA.convolve(prewrapOtherB).data) | set(prewrapSelfB.convolve(prewrapOtherA).data) | set(prewrapSelfC.convolve(prewrapOtherD).data) | set(prewrapSelfD.convolve(prewrapOtherC).data)
return [[CosetMatrix(Matrix([[0,0,0]]), self.periodLattice), CosetMatrix(coset.rep, other.periodLattice)] for coset in collisionSeparationCosets]
#TODO: Could make a faster method for self-interactions, since half of the convolutions aren't really required
#Multiple patterns with the same period, with compatible inputs and outputs linked
class CompoundPattern:
def __init__(self, componentsWithPositions, name = ""):
#Members are of the form (component, position)
self.componentsWithPositions = componentsWithPositions
self.periodVector = componentsWithPositions[0][0].periodVector
self.periodLattice = componentsWithPositions[0][0].periodLattice
self.dT = int(self.periodVector[0,0])
self.dX = -int(self.periodVector[0,1])
self.dY = -int(self.periodVector[0,2])
#Figure out all inputs and outputs
self.inputDict = {}
for inputComponent, inputComponentName, inputComponentPosition in self.componentsWithPositions:
for inputPattern, inputName, inputTime, inputPosition in inputComponent.inputs:
if not inputPattern in self.inputDict:
self.inputDict[inputPattern] = {}
combinedLattice = inputPattern.periodLattice + self.periodLattice
#What lane is our input on
inputPositionInCompound = inputPosition + inputComponentPosition.rep - Matrix([[inputTime,0,0]])
inputLane = CosetMatrix(inputPositionInCompound.rep, combinedLattice)
if not inputLane in self.inputDict[inputPattern]:
self.inputDict[inputPattern][inputLane] = []
#Our input time and position in the larger compound pattern
inputTimeInCompoundPattern = mod(inputTime - int(inputComponentPosition.rep[0,0]), self.dT)
inputSpacing = ((inputTime - int(inputComponentPosition.rep[0,0])) - inputTimeInCompoundPattern) // self.dT
inputPositionInCompoundPattern = inputPosition.rep + inputComponentPosition.rep + Matrix([[inputTimeInCompoundPattern - inputTime,0,0]]) + self.periodVector * inputSpacing
self.inputDict[inputPattern][inputLane].append((inputTimeInCompoundPattern, inputPositionInCompoundPattern, inputComponentName+"."+inputName))
self.outputDict = {}
for outputComponent, outputComponentName, outputComponentPosition in self.componentsWithPositions:
for outputPattern, outputName, outputTime, outputPosition in outputComponent.outputs:
if not outputPattern in self.outputDict:
self.outputDict[outputPattern] = {}
combinedLattice = outputPattern.periodLattice + self.periodLattice
#What lane is our output on
outputPositionInCompound = outputPosition + outputComponentPosition.rep - Matrix([[outputTime,0,0]])
outputLane = CosetMatrix(outputPositionInCompound.rep, combinedLattice)
if not outputLane in self.outputDict[outputPattern]:
self.outputDict[outputPattern][outputLane] = []
#Our output time and position in the larger compound pattern
outputTimeInCompoundPattern = mod(outputTime - int(outputComponentPosition.rep[0,0]), self.dT)
outputSpacing = ((outputTime - int(outputComponentPosition.rep[0,0])) - outputTimeInCompoundPattern) // self.dT
outputPositionInCompoundPattern = outputPosition.rep + outputComponentPosition.rep + Matrix([[outputTimeInCompoundPattern - outputTime,0,0]]) + self.periodVector * outputSpacing
self.outputDict[outputPattern][outputLane].append((outputTimeInCompoundPattern, outputPositionInCompoundPattern, outputComponentName+"."+outputName))
#Whole pattern's inputs and outputs
#In same format as PeriodicPattern, to allow for nesting
self.inputs = []
self.outputs = []
self.linkages = []
#Input/output index registration with names
self.name = name
self.inputNamesToIndexes = {}
self.outputNamesToIndexes = {}
def registerInput(inputTimeInCompoundPattern, pattern, inputPositionInCompoundPattern, inputName):
self.inputNamesToIndexes[inputName] = len(self.inputs)
self.inputs.append((pattern, inputName, inputTimeInCompoundPattern, CosetMatrix(inputPositionInCompoundPattern, pattern.periodLattice)))
def registerOutput(outputTimeInCompoundPattern, pattern, outputPositionInCompoundPattern, outputName):
self.outputNamesToIndexes[outputName] = len(self.outputs)
self.outputs.append((pattern, outputName, outputTimeInCompoundPattern, CosetMatrix(outputPositionInCompoundPattern, pattern.periodLattice)))
#Figure out compatible input-output pairs and combine 'em
for pattern in self.inputDict:
if pattern in self.outputDict:
combinedLatticeChangeOfBasis = self.periodVector.blockVertical(pattern.periodVector).rightInverse()
for lane in self.inputDict[pattern]:
if lane in self.outputDict[pattern]:
#Positivity/spacing checks on pairs in the same lane
inputsMinPositiveDisplacements = [(math.inf, -1) for i in range(len(self.inputDict[pattern][lane]))]
outputsMinPositiveDisplacements = [(math.inf, -1) for j in range(len(self.outputDict[pattern][lane]))]
for i in range(len(self.inputDict[pattern][lane])):
inputTimeInCompoundPattern, inputPositionInCompoundPattern, inputName = self.inputDict[pattern][lane][i]
for j in range(len(self.outputDict[pattern][lane])):
outputTimeInCompoundPattern, outputPositionInCompoundPattern, outputName = self.outputDict[pattern][lane][j]
inputPos = inputPositionInCompoundPattern + Matrix([[inputTimeInCompoundPattern,0,0]])
outputPos = outputPositionInCompoundPattern + Matrix([[outputTimeInCompoundPattern,0,0]])
#This is incredibly scuffed and probably incorrect
#TODO: Yeah this is definitely incorrect
displacement = int((inputPos - outputPos)[0,0]) + int(((inputPos - outputPos) * combinedLatticeChangeOfBasis)[0,0]) * self.dT
if displacement >= 0 or True:
#Link up if these are an improvement
if displacement < inputsMinPositiveDisplacements[i][0]:
inputsMinPositiveDisplacements[i] = (displacement, j)
if displacement < outputsMinPositiveDisplacements[j][0]:
outputsMinPositiveDisplacements[j] = (displacement, i)
unboundInputs = set(range(len(self.inputDict[pattern][lane])))
unboundOutputs = set(range(len(self.outputDict[pattern][lane])))
#Register linkages for closest compatible pairs
for i in range(len(self.inputDict[pattern][lane])):
j = inputsMinPositiveDisplacements[i][1]
if j != -1 and outputsMinPositiveDisplacements[j][1] == i:
#i,j is a closest compatible pair
unboundInputs.remove(i)
unboundOutputs.remove(j)
inputTimeInCompoundPattern, inputPositionInCompoundPattern, inputName = self.inputDict[pattern][lane][i]
outputTimeInCompoundPattern, outputPositionInCompoundPattern, outputName = self.outputDict[pattern][lane][j]
self.linkages.append((pattern, inputTimeInCompoundPattern, inputPositionInCompoundPattern, outputTimeInCompoundPattern, outputPositionInCompoundPattern))
#Register unbound inputs and outputs
for i in unboundInputs:
inputTimeInCompoundPattern, inputPositionInCompoundPattern, inputName = self.inputDict[pattern][lane][i]
registerInput(inputTimeInCompoundPattern, pattern, inputPositionInCompoundPattern, inputName)
for j in unboundOutputs:
outputTimeInCompoundPattern, outputPositionInCompoundPattern, outputName = self.outputDict[pattern][lane][j]
registerOutput(outputTimeInCompoundPattern, pattern, outputPositionInCompoundPattern, outputName)
else:
for inputTimeInCompoundPattern, inputPositionInCompoundPattern, inputName in self.inputDict[pattern][lane]:
registerInput(inputTimeInCompoundPattern, pattern, inputPositionInCompoundPattern, inputName)
for lane in self.outputDict[pattern]:
if not lane in self.inputDict[pattern]:
for outputTimeInCompoundPattern, outputPositionInCompoundPattern, outputName in self.outputDict[pattern][lane]:
registerOutput(outputTimeInCompoundPattern, pattern, outputPositionInCompoundPattern, outputName)
else:
for lane in self.inputDict[pattern]:
for inputTimeInCompoundPattern, inputPositionInCompoundPattern, inputName in self.inputDict[pattern][lane]:
registerInput(inputTimeInCompoundPattern, pattern, inputPositionInCompoundPattern, inputName)
for pattern in self.outputDict:
if not pattern in self.inputDict:
for lane in self.outputDict[pattern]:
for outputTimeInCompoundPattern, outputPositionInCompoundPattern, outputName in self.outputDict[pattern][lane]:
registerOutput(outputTimeInCompoundPattern, pattern, outputPositionInCompoundPattern, outputName)
def place(self, position, mode = "or"):
#Place in all components
for component, componentName, componentPosition in self.componentsWithPositions:
component.place(position + componentPosition, mode)
#Place in all linkages
stateT = int(position.rep[0,0])
for pattern, inputTimeInCompoundPattern, inputPositionInCompoundPattern, outputTimeInCompoundPattern, outputPositionInCompoundPattern in self.linkages:
#TODO: These are wrong
inputIndexOffset = (1,0)[inputTimeInCompoundPattern >= stateT]
outputIndexOffset = (0,1)[outputTimeInCompoundPattern <= stateT]
#g.warn(str(inputTimeInCompoundPattern) +", "+str(outputTimeInCompoundPattern) +", "+str(stateT)+"\n\n"+str(inputIndexOffset) + ", "+str(outputIndexOffset))
inputBasePos = inputPositionInCompoundPattern + position.rep - Matrix([[inputTimeInCompoundPattern, 0, 0]])
outputBasePos = outputPositionInCompoundPattern + position.rep - Matrix([[outputTimeInCompoundPattern, 0, 0]])
combinedLatticeChangeOfBasis = self.periodVector.blockVertical(pattern.periodVector).rightInverse()
for index in range(inputIndexOffset, outputIndexOffset + int(((inputBasePos - outputBasePos) * combinedLatticeChangeOfBasis)[0,0])):
pattern.place(CosetMatrix(inputBasePos - Matrix([[self.dT, -self.dX, -self.dY]]) * index, pattern.periodLattice), mode)
def placeInput(self, position, index, mode = "or"):
stateT = int(position.rep[0,0])
for inputPattern, inputName, inputTimeToAdd, inputPosition in self.inputs:
indexToUse = index + (1,0)[inputTimeToAdd >= stateT]
inputPattern.place(inputPosition + (position.rep + Matrix([[-inputTimeToAdd, 0, 0]]) - Matrix([[self.dT, -self.dX, -self.dY]]) * indexToUse), mode)
def placeOutput(self, position, index, mode = "or"):
stateT = int(position.rep[0,0])
for outputPattern, outputName, outputTimeToRemove, outputPosition in self.outputs:
indexToUse = index + (1,0)[outputTimeToRemove <= stateT]
outputPattern.place(outputPosition + (position.rep + Matrix([[-outputTimeToRemove, 0, 0]]) + Matrix([[self.dT, -self.dX, -self.dY]]) * indexToUse), mode)
#Place with inputs (and outputs)
def placeWithInputs(self, position, numInputs = 0, numOutputs = 0, mode = "or"):
self.place(position, mode)
for i in range(0,numInputs):
self.placeInput(position, i, mode)
for i in range(0,numOutputs):
self.placeOutput(position, i, mode)
#Find the minimal offset displacement of pat2 linking an output in one PeriodicPattern (or CompoundPattern) to an input in another
# Plus extraSpacing steps worth of space
def findOffset(pat1, pat1OutputIndex, pat2, pat2InputIndex, extraSpacing = 0):
outputPattern, outputName, outputTimeToRemove, outputPosition = pat1.outputs[pat1OutputIndex]
inputPattern, inputName, inputTimeToAdd, inputPosition = pat2.inputs[pat2InputIndex]
if outputPattern != inputPattern:
g.warn("Pattern mismatch!")
#Want to add and remove in the same generation
return CosetMatrix(Matrix([[inputTimeToAdd - outputTimeToRemove,0,0]]) + outputPosition.rep - inputPosition.rep - outputPattern.periodVector * extraSpacing, pat1.periodLattice)
#A chain with certain spacings
def chain(patternInputOutputSpacingInfo):
periodLattice = patternInputOutputSpacingInfo[0][0].periodLattice
cumulativeOffset = CosetMatrix(Matrix.zero(1,3), periodLattice)
componentsWithPositions = [(patternInputOutputSpacingInfo[0][0], patternInputOutputSpacingInfo[0][1], cumulativeOffset)]
for i in range(len(patternInputOutputSpacingInfo) - 1):
outputComponent, _, _, outputComponentOutputName, _ = patternInputOutputSpacingInfo[i]
inputComponent, inputComponentName, inputComponentInputName, _, extraSpacing = patternInputOutputSpacingInfo[i+1]
outputComponentOutputIndex = outputComponent.outputNamesToIndexes[outputComponentOutputName]
inputComponentInputIndex = inputComponent.inputNamesToIndexes[inputComponentInputName]
addedOffset = CompoundPattern.findOffset(outputComponent, outputComponentOutputIndex, inputComponent, inputComponentInputIndex, extraSpacing)
cumulativeOffset += addedOffset
componentsWithPositions.append((inputComponent, inputComponentName, cumulativeOffset))
return CompoundPattern(componentsWithPositions)
#Automatically add in a collection of components with compatible spacings with certain inputs/outputs to form a loop
def addCompatibleComponents(self, componentsToAddData, selfName = "Main"):
newCompoundPatternComponents = [(self, selfName, CosetMatrix(Matrix.zero(1,3), self.periodLattice))]
for component, componentName, componentInputIndicesToSelfOutputIndices, componentOutputIndicesToSelfInputIndices in componentsToAddData:
#Get constraints
baseOffsets = []
stepDisplacements = []
#We expect exactly 2 of these constraints in total
for componentInputName, selfOutputName in componentInputIndicesToSelfOutputIndices.items():
componentInputIndex = component.inputNamesToIndexes[componentInputName]
selfOutputIndex = self.outputNamesToIndexes[selfOutputName]
baseOffsets.append(CompoundPattern.findOffset(self, selfOutputIndex, component, componentInputIndex).rep)
stepDisplacements.append(component.inputs[componentInputIndex][0].periodVector)
for componentOutputName, selfInputName in componentOutputIndicesToSelfInputIndices.items():
componentOutputIndex = component.outputNamesToIndexes[componentOutputName]
selfInputIndex = self.inputNamesToIndexes[selfInputName]
baseOffsets.append(-CompoundPattern.findOffset(component, componentOutputIndex, self, selfInputIndex).rep)
stepDisplacements.append(component.outputs[componentOutputIndex][0].periodVector)
#Our position must be, for all i, of the form v = baseOffsets[i] + n_i * stepDisplacements[i] + m_i * self.periodVector
# In particular, have 0 = baseOffsets[0] - baseOffsets[1] + n_0 * stepDisplacements[0] - n_1 * stepDisplacements[1] + (m_0-m_1)*self.periodVector
# baseOffsets[1] - baseOffsets[0] = Matrix([[n_0,-n_1,m_0-m_1]]) * BlockVertical(stepDisplacements[0], stepDisplacements[1], self.periodVector)
# (baseOffsets[1] - baseOffsets[0]) * blockMatrixInverse = Matrix([[n_0,-n_1,m_0-m_1]])
# ((baseOffsets[1] - baseOffsets[0]) * blockMatrixInverse.col(0))[0,0] = n_0
n0 = ((baseOffsets[1] - baseOffsets[0]) * stepDisplacements[0].blockVertical(stepDisplacements[1]).blockVertical(self.periodVector).inverse().col(0))[0,0]
v = baseOffsets[0] + stepDisplacements[0] * n0
newCompoundPatternComponents.append((component, componentName, CosetMatrix(v, component.periodLattice)))
return CompoundPattern(newCompoundPatternComponents)
#Settings
g.new("13131")
g.setrule("B3/S23")
g.setalgo("HashLife")
#Basic objects
block = PeriodicPattern(g.parse("2o$2o!",0,0), 1, 0, 0)
blinker = PeriodicPattern(g.parse("3o!",-1,0), 2, 0, 0)
SWGlider = PeriodicPattern(g.parse("bo$o$3o!",0,0), 4, -1, 1)
NWGlider = PeriodicPattern(g.parse("2o$obo$o!",0,0), 4, -1, -1)
NEGlider = PeriodicPattern(g.parse("3o$2bo$bo!",0,0), 4, 1, -1)
NLWSS = PeriodicPattern(g.parse("3o$o2bo$o$o$bobo!",0,0), 4, 0, -2)
NMWSS = PeriodicPattern(g.parse("3o$o2bo$o$o3bo$o$bobo!",0,0), 4, 0, -2)
NHWSS = PeriodicPattern(g.parse("3o$o2bo$o$o3bo$o3bo$o$bobo!",0,0), 4, 0, -2)
WLWSS = PeriodicPattern(g.parse("bo2bo$o$o3bo$4o!",0,0), 4, -2, 0)
#Helix components
helixComponent1 = PeriodicPattern([],31*16,-1*16,-13*16,
[(NEGlider,"NEGlider0",0,CosetMatrix(Matrix([[0,0,4]]), NEGlider.periodLattice)),
(NLWSS,"NLWSS0",0,CosetMatrix(Matrix([[1,5,1]]), NLWSS.periodLattice)),
(NHWSS,"NHWSS0",8,CosetMatrix(Matrix([[2,12,-1]]), NHWSS.periodLattice))],
[(NEGlider,"NEGlider1",17,CosetMatrix(Matrix([[1,12,-5]]), NEGlider.periodLattice))])
helixComponent2 = PeriodicPattern([],31*16,-1*16,-13*16,
[(NEGlider,"NEGlider0",0,CosetMatrix(Matrix([[3,-1,1]]), NEGlider.periodLattice)),
(NLWSS,"NLWSS0",0,CosetMatrix(Matrix([[1,4,2]]), NLWSS.periodLattice)),
(NLWSS,"NLWSS1",10,CosetMatrix(Matrix([[3,2,7]]), NLWSS.periodLattice))],
[(NWGlider,"NWGlider0",19,CosetMatrix(Matrix([[0,-2,1]]), NWGlider.periodLattice))])
helixComponent3 = PeriodicPattern([],31*16,-1*16,-13*16,
[(NWGlider,"NWGlider0",0,CosetMatrix(Matrix([[2,13,4]]), NWGlider.periodLattice)),
(NLWSS,"NLWSS0",0,CosetMatrix(Matrix([[3,7,2]]), NLWSS.periodLattice)),
(NHWSS,"NHWSS0",8,CosetMatrix(Matrix([[0,0,-2]]), NHWSS.periodLattice))],
[(NWGlider,"NWGlider1",17,CosetMatrix(Matrix([[3,1,-5]]), NWGlider.periodLattice))])
helixComponent4 = PeriodicPattern([],31*16,-1*16,-13*16,
[(NWGlider,"NWGlider0",0,CosetMatrix(Matrix([[0,9,5]]), NWGlider.periodLattice)),
(NHWSS,"NHWSS0",0,CosetMatrix(Matrix([[0,3,0]]), NHWSS.periodLattice)),
(NHWSS,"NHWSS1",7,CosetMatrix(Matrix([[0,9,8]]), NHWSS.periodLattice)),
(NLWSS,"NLWSS0",23,CosetMatrix(Matrix([[2,0,4]]), NLWSS.periodLattice)),
(NLWSS,"NLWSS1",40,CosetMatrix(Matrix([[2,4,3]]), NLWSS.periodLattice))],
[(NEGlider,"NEGlider0",29,CosetMatrix(Matrix([[3,6,-6]]), NEGlider.periodLattice)),
(NWGlider,"NWGlider1",39,CosetMatrix(Matrix([[1,-3,-4]]), NWGlider.periodLattice))])
#TODO: Replace indices with names
helixSpacings = [
(helixComponent1,"H0","","NEGlider1",2),
(helixComponent1,"H1","NEGlider0","NEGlider1",2),
(helixComponent1,"H2","NEGlider0","NEGlider1",2),
(helixComponent1,"H3","NEGlider0","NEGlider1",2),
(helixComponent1,"H4","NEGlider0","NEGlider1",2),
(helixComponent1,"H5","NEGlider0","NEGlider1",2),
(helixComponent1,"H6","NEGlider0","NEGlider1",2),
(helixComponent1,"H7","NEGlider0","NEGlider1",2),
(helixComponent2,"H8","NEGlider0","NWGlider0",2),
(helixComponent3,"H9","NWGlider0","NWGlider1",0),
(helixComponent3,"H10","NWGlider0","NWGlider1",2),
(helixComponent3,"H11","NWGlider0","NWGlider1",2),
(helixComponent3,"H12","NWGlider0","NWGlider1",2),
(helixComponent3,"H13","NWGlider0","NWGlider1",2),
(helixComponent3,"H14","NWGlider0","NWGlider1",2),
(helixComponent3,"H15","NWGlider0","NWGlider1",2),
(helixComponent3,"H16","NWGlider0","NWGlider1",2),
(helixComponent3,"H17","NWGlider0","NWGlider1",2),
(helixComponent4,"H18","NWGlider0","NEGlider0",6),
]
helix = CompoundPattern.chain(helixSpacings)
#helix.placeWithInputs(CosetMatrix(Matrix([[0,0,0]]), helix.periodLattice), 20, 20)
#Fanout components
#TODO: Would be nice to figure these input/output values automatically
fanoutComponent1 = PeriodicPattern([],31*16,-1*16,-13*16,
[(NWGlider,"NWGlider0",0,CosetMatrix(Matrix([[1,1,0]]), NWGlider.periodLattice)),
(NLWSS,"NLWSS0",0,CosetMatrix(Matrix([[3,-5,0]]), NLWSS.periodLattice)),
(NLWSS,"NLWSS1",15,CosetMatrix(Matrix([[1,0,5]]), NLWSS.periodLattice)),
(NLWSS,"NLWSS2",16,CosetMatrix(Matrix([[2,6,4]]), NLWSS.periodLattice))],
[(blinker,"Blinker0",28,CosetMatrix(Matrix([[0,4,7]]), blinker.periodLattice)),
(WLWSS,"WLWSS0",29,CosetMatrix(Matrix([[-1,-7,-3]]), WLWSS.periodLattice))])
fanoutComponent2 = PeriodicPattern([],31*16,-1*16,-13*16,
[(blinker,"Blinker0",0,CosetMatrix(Matrix([[1,2,1]]), blinker.periodLattice)),
(NLWSS,"NLWSS0",0,CosetMatrix(Matrix([[1,2,4]]), NLWSS.periodLattice)),
(NLWSS,"NLWSS1",13,CosetMatrix(Matrix([[0,0,6]]), NLWSS.periodLattice))],
[(NWGlider,"NWGlider0",10,CosetMatrix(Matrix([[-1,1,-2]]), NWGlider.periodLattice))])
fanoutComponent3 = PeriodicPattern([],31*16,-1*16,-13*16,
[(NWGlider,"NWGlider0",0,CosetMatrix(Matrix([[2,7,5]]), NWGlider.periodLattice)),
(NHWSS,"NHWSS0",0,CosetMatrix(Matrix([[0,0,0]]), NHWSS.periodLattice)),
(NMWSS,"NMWSS0",10,CosetMatrix(Matrix([[2,9,9]]), NMWSS.periodLattice))],
[(NWGlider,"NWGlider1",26,CosetMatrix(Matrix([[0,2,-5]]), NWGlider.periodLattice))])
fanoutComponent4 = PeriodicPattern([],31*16,-1*16,-13*16,
[(NWGlider,"NWGlider0",0,CosetMatrix(Matrix([[2,5,0]]), NWGlider.periodLattice)),
(NLWSS,"NLWSS0",0,CosetMatrix(Matrix([[0,6,4]]), NLWSS.periodLattice)),
(NLWSS,"NLWSS1",16,CosetMatrix(Matrix([[3,0,7]]), NLWSS.periodLattice))],
[(blinker,"Blinker0",18,CosetMatrix(Matrix([[1,8,5]]), blinker.periodLattice)),
(NWGlider,"NWGlider1",20,CosetMatrix(Matrix([[3,1,4]]), NWGlider.periodLattice))])
fanoutComponent5 = PeriodicPattern([],31*16,-1*16,-13*16,
[(blinker,"Blinker0",0,CosetMatrix(Matrix([[0,1,0]]), blinker.periodLattice)),
(NLWSS,"NLWSS0",0,CosetMatrix(Matrix([[0,3,2]]), NLWSS.periodLattice)),
(NLWSS,"NLWSS0",9,CosetMatrix(Matrix([[3,7,6]]), NLWSS.periodLattice))],
[(NWGlider,"NWGlider0",23,CosetMatrix(Matrix([[2,6,1]]), NWGlider.periodLattice))])
fanoutComponent6 = PeriodicPattern([],31*16,-1*16,-13*16,
[(blinker,"Blinker0",0,CosetMatrix(Matrix([[0,1,2]]), blinker.periodLattice)),
(NLWSS,"NLWSS0",0,CosetMatrix(Matrix([[1,5,1]]), NLWSS.periodLattice)),
(NMWSS,"NMWSS0",25,CosetMatrix(Matrix([[3,9,3]]), NMWSS.periodLattice))],
[(NWGlider,"NWGlider0",37,CosetMatrix(Matrix([[1,5,-3]]), NWGlider.periodLattice))])
#Extra fanout components for the last track builder (slightly cheaper)
fanoutComponent7 = PeriodicPattern([],31*16,-1*16,-13*16,
[(NWGlider,"NWGlider0",0,CosetMatrix(Matrix([[1,4,0]]), NWGlider.periodLattice)),
(NLWSS,"NLWSS0",0,CosetMatrix(Matrix([[2,6,5]]), NLWSS.periodLattice)),
(NLWSS,"NLWSS1",2,CosetMatrix(Matrix([[2,0,4]]), NLWSS.periodLattice))],
[(blinker,"Blinker0",16,CosetMatrix(Matrix([[1,4,1]]), blinker.periodLattice)),
(NWGlider,"NWGlider1",17,CosetMatrix(Matrix([[1,-1,0]]), NWGlider.periodLattice))])
fanoutComponent8 = PeriodicPattern([],31*16,-1*16,-13*16,
[(blinker,"Blinker0",0,CosetMatrix(Matrix([[0,5,0]]), blinker.periodLattice)),
(NLWSS,"NLWSS0",0,CosetMatrix(Matrix([[2,8,2]]), NLWSS.periodLattice)),
(NLWSS,"NLWSS1",7,CosetMatrix(Matrix([[2,0,3]]), NLWSS.periodLattice))],
[(NWGlider,"NWGlider0",14,CosetMatrix(Matrix([[2,3,2]]), NWGlider.periodLattice))])
trackPairBuilderCollision1 = PeriodicPattern([],31*16,-1*16,-13*16,
[(WLWSS,"WLWSS0",0,CosetMatrix(Matrix([[1,1,-1]]), WLWSS.periodLattice)),
(NWGlider,"NWGlider0",0,CosetMatrix(Matrix([[2,3,5]]), NWGlider.periodLattice)),
(NWGlider,"NWGlider1",79,CosetMatrix(Matrix([[1,6,6]]), NWGlider.periodLattice))],
[(block,"Block0",8,CosetMatrix(Matrix([[0,-3,0]]), block.periodLattice)),
(block,"Block1",85,CosetMatrix(Matrix([[0,2,5]]), block.periodLattice))])
#TODO: Want to be able to 'complete a cycle with available components' when possible
#TODO: Want a slightly different last fanout
# First fanout should have different starting displacement, connect to helix
# Last fanout should not produce 'fanout continuation glider': It's cheaper to use an extra LWSS for period multiplication instead
# In fact, could potentially be even cheaper if we instead fan out into two gliders which support our climbers directly!
def fanoutPatSpacingInfo(n,dn, i, isFirstFanout = False, isLastFanout = False):
startSpacing = 207 + (dn-2)*192 - n * 16
if isFirstFanout:
startSpacing = 38 + n * 16
return [
(fanoutComponent1,"F1,"+str(i),"NWGlider0","Blinker0",startSpacing),
(fanoutComponent2,"F2,"+str(i),"Blinker0","NWGlider0",1 + n*24),
(fanoutComponent3,"F3,"+str(i),"NWGlider0","NWGlider1",50 + n*16),
(fanoutComponent4,"F4,"+str(i),"NWGlider0","Blinker0",47),
(fanoutComponent5,"F5,"+str(i),"Blinker0","NWGlider0",10),
(fanoutComponent4,"F6,"+str(i),"NWGlider0","Blinker0",94),
(fanoutComponent6,"F7,"+str(i),"Blinker0","NWGlider0",10),
]
fanoutDeviceSpacingsList = [3]
for i in range(15-1):
#15/12 is probably not the exact optimal value but it's fine
newN = int(math.ceil(fanoutDeviceSpacingsList[0] * 7 / 6 + 15/12))
fanoutDeviceSpacingsList.insert(0,newN)
fanoutPatSpacings = [(helix,"Helix","","H18.NWGlider1",0)]
for i in range(len(fanoutDeviceSpacingsList)):
if i == 0:
fanoutPatSpacings += fanoutPatSpacingInfo(fanoutDeviceSpacingsList[i], 0, i, True)
else:
fanoutPatSpacings += fanoutPatSpacingInfo(fanoutDeviceSpacingsList[i], fanoutDeviceSpacingsList[i-1] - fanoutDeviceSpacingsList[i], i, False)
#Cheaper last fanout
fanoutPatSpacings += [(fanoutComponent7,"F1,16","NWGlider0","Blinker0",68),(fanoutComponent8,"F2,16","Blinker0","NWGlider0",26)]
fanoutTrackPairBuilderConnections = [(trackPairBuilderCollision1, "T"+str(i), {"WLWSS0":"F1,"+str(i)+".WLWSS0", "NWGlider0":"F4,"+str(i)+".NWGlider1"}, {}) for i in range(15)]
periodDemultiplierCrawlerBlockInputs = [(block, "Block"+str(i), 31*i, CosetMatrix(Matrix([[0,6,-2]]) + Matrix([[0,-1,-13]])*i, block.periodLattice)) for i in range(15)]
periodDemultiplierCrawlerGliderOutputs = [(SWGlider, "SWGlider"+str(i), 22+31*i, CosetMatrix(Matrix([[1,0,3]]) + Matrix([[0,-1,-13]])*i, SWGlider.periodLattice)) for i in range(16)]
periodDemultiplierCrawler = PeriodicPattern(g.parse("2b3o$2bo2bo$bo$4b2o$o3b2o$o$2bo$2b3o$3b2o$4bo$2b2o$bobo$o3bo$2b2o!"),31*16,-1*16,-13*16,
periodDemultiplierCrawlerBlockInputs + [(NWGlider, "NWGlider0", 31*15, CosetMatrix(Matrix([[1,7,-2]]) + Matrix([[0,-1,-13]])*15, NWGlider.periodLattice))],
periodDemultiplierCrawlerGliderOutputs)
periodDemultiplierConnections = [(periodDemultiplierCrawler, "Demultiplier0", {"NWGlider0":"Main.F1,16.NWGlider1","Block0":"T0.Block0"}, {}),
(periodDemultiplierCrawler, "Demultiplier1", {"NWGlider0":"Main.F2,16.NWGlider0","Block0":"T0.Block1"}, {})]
fanoutDevice = CompoundPattern.chain(fanoutPatSpacings).addCompatibleComponents(fanoutTrackPairBuilderConnections).addCompatibleComponents(periodDemultiplierConnections)
#g.warn(str(set(fanoutDevice.outputNamesToIndexes)))
fanoutDevice.placeWithInputs(CosetMatrix(Matrix([[0,0,0]]), fanoutDevice.periodLattice), 320, 3)EDIT: Pair track reset mechanism completed:
Code: Select all
x = 979, y = 2204, rule = B3/S23
978bo$976b2o$977b2o4$963bo$961b2o$962b2o13$970bo$970bobo$970b2o4$955bo
$955bobo$955b2o13$963bobo$963b2o$964bo4$948bobo$948b2o$949bo12$957bo$
956bo$956b3o4$942bo$941bo$941b3o13$951bo$949b2o$950b2o4$936bo$934b2o$
935b2o13$943bo$943bobo$943b2o4$928bo$928bobo$928b2o13$936bobo$936b2o$
937bo4$921bobo$921b2o$922bo12$930bo$929bo$929b3o4$915bo$914bo$914b3o
13$924bo$922b2o$923b2o4$909bo$907b2o$908b2o13$916bo$916bobo$916b2o4$
901bo$901bobo$901b2o13$909bobo$909b2o$910bo4$894bobo$894b2o$895bo12$
903bo$902bo$902b3o4$888bo$887bo$887b3o13$897bo$895b2o$896b2o4$882bo$
880b2o$881b2o13$889bo$889bobo$889b2o4$874bo$874bobo$874b2o13$882bobo$
882b2o$883bo4$867bobo$867b2o$868bo12$876bo$875bo$875b3o4$861bo$860bo$
860b3o13$870bo$868b2o$869b2o4$855bo$853b2o$854b2o13$862bo$862bobo$862b
2o4$847bo$847bobo$847b2o13$855bobo$855b2o$856bo4$840bobo$840b2o$841bo
12$849bo$848bo$848b3o4$834bo$833bo$833b3o13$843bo$841b2o$842b2o4$828bo
$826b2o$827b2o13$835bo$835bobo$835b2o4$820bo$820bobo$820b2o13$828bobo$
828b2o$829bo4$813bobo$813b2o$814bo12$822bo$821bo$821b3o4$807bo$806bo$
806b3o13$816bo$814b2o$815b2o4$801bo$799b2o$800b2o13$808bo$808bobo$808b
2o4$793bo$793bobo$793b2o13$801bobo$801b2o$802bo4$786bobo$786b2o$787bo
12$795bo$794bo$794b3o4$780bo$779bo$779b3o13$789bo$787b2o$788b2o4$774bo
$772b2o$773b2o13$781bo$781bobo$781b2o4$766bo$766bobo$766b2o13$774bobo$
774b2o$775bo4$759bobo$759b2o$760bo12$768bo$767bo$767b3o4$753bo$752bo$
748b3ob3o$748bo2bo$747bo$750b2o$746bo3b2o$746bo$748bo$748b3o$749b2o$
750bo7b3o$748b2o8bo2bo$747bobo6bo4bo$746bo3bo5bo$748b2o5b2o$756b2obo$
758bo4$745bo$745bobo12b2o$745b2o$758bo2bo$757bo$757bo2bo$739b3o17bo$
738bo2bo$738bo3bo$739b4o$741bo2$750b3o$749bo2bo$749bo2bo$737b2ob2o6bo
2bo$737b3obo7b3o$749b2o7b2o$758b2o$753bo$738bo14bo$737bo16bo$733b3ob3o
10b2obo$733bo2bo12bo$732bo18bo4bo$735b2o$731bo3b2o16bobo$731bo21b3o$
733bo10b3o$733b3o8bo2bo$734b2o8bob2o11b2o$735bo6b2o15b2o$733b2o7b2o$
732bobo6bo2bo$731bo3bo9bo$733b2o8b3o$744bo4$727bo$725b2ob2o$725b2o$
725b2ob2o30b2o$738b3o19b2o$737bo2bo$728b2o7bo4bo$728b2o$742bo$730bo10b
o$725b2ob2obo5bob2o$725b2o4b2o3bo2bo$728b2ob2o5b2o$730bo4bo2bo$735bo$
739bo$721bo14bo24b2o$720b3o14b3o21b2o$719b2o2bo$719bo$718b2o12b3o$717b
o14bo2bo$717b4o10bo3bo$719b2o10bobob2o$732b2ob2o$733b3o4$762b2o$731bob
2o27b2o$730bobobo$715bo15bo$714b3o7bo$713bo2b2o6bo$717bo$715b3o8b2ob2o
$714bob2o7bo6bo$713b2obo8b2o4bo$715b2o$712b2obo11bo2bo$712b2ob2o11b2o$
712b2ob2o8b2o36b2o$714bo10b3o35b2o$726bo$725b2ob2o$725b2ob2o$725bo3bo$
709bo15bo3bo$708b3o17bo$707b2o2bo$709b3o4$711bo52b2o$708bo10bo44b2o$
707bo3bo6bobo$706b2ob2o7bobo$718b3o$719bo2bo$719bo$708bo13bo$706b2o$
707b2o11bo$721bo$713bo6b2o$712bobo$711bo2b2obo47b2o$712b2ob2obo46b2o$
715bo2bo3bo$716bobo2bobo$718b3o$700bo17b3o$699b3o17bo2bo$698bo2b2o18bo
$702bo$700b3o12bo$699bob2o12bobo$698b2obo13b2o$700b2o8b3o$697b2obo8bo
2bo5b2o46b2o$697b2ob2o7bo3bo4b2o46b2o$697b2ob2o6b2o2bo$699bo10bo$711b
2o$711b3o$711b3o$704b2o$703bo2bo$704bo3bo$704b5o$706b2ob2o$709bo2b2o$
710b3o6b2o46b2o$711bo7b2o46b2o$692bo$691b3o14bo$690b2o2bo12bo$691b4o
12b3o$689bobo$688bo2bo$689b3o$690bobo9b3o4b2o$690bobo9bo2bo3b2o$690b3o
8bo3bo$701bobob2o$702b2ob2o13b2o46b2o$703b3o14b2o46b2o2$696b2o$696bo2b
o$697bo2bo$697b2obo3bo$701b2o2bo$702b3o$703bo6b2o$710b2o2$700bo$700bob
o18b2o46b2o$683bo16b2o19b2o46b2o$682b3o$681bo2b2o$680b5o$680bo2b2o9b3o
4b2o$680bo2bo9bo2bo4b2o$681bobo9bo3bo$694b4o$696bo14b2o$685b2o24b2o$
684b3o$682bo$683b2o37b2o46b2o$692b2ob2o25b2o46b2o$692b3obo$685bobo$
677bo7bobo$676b3o7bo15b2o$675b2o2bo13bo8b2o$676b4o12bo$674bobo11b3ob3o
$673bo2bo11bo2bo20b2o$674b3o10bo24b2o$675bobo12b2o$675bobo8bo3b2o$675b
3o8bo36b2o46b2o$688bo34b2o46b2o$688b3o$689b2o$690bo$688b2o13b2o$687bob
o13b2o$671bo14bo3bo$670b3o15b2o$669bo2b2o39b2o$713b2o3$672b2o8bo41b2o
46b2o$670b3o7b2ob2o39b2o46b2o$669bo10b2o$669b3o8b2ob2o$670b2o$704b2o$
683b2o19b2o$669bobo11b2o$669b2o$670bo14bo28b2o$665bo14b2ob2obo27b2o$
664b3o13b2o4b2o$663b2o2bo15b2ob2o$663bo3bo17bo39b2o46b2o$663bobo59b2o
46b2o2$664b2ob2o7bo$666bo8b3o$674b2o2bo26b2o$674bo30b2o$673b2o$663b4o
5bo$662bobobo5b4o39b2o$663bo10b2o39b2o3$726b2o46b2o$658bo67b2o46b2o$
657bobo2b2o$657b2o$658bo$660b2o44b2o$658b4o8bo35b2o$657bo2bo8b3o7bo$
659bo8bo2b2o6bo$660bo11bo43b2o$660b2o8b3o43b2o$656bo5bo6bob2o$656b2o3b
2o5b2obo$660b2o8b2o55b2o46b2o$667b2obo56b2o46b2o$667b2ob2o$667b2ob2o$
669bo$707b2o$651b3o53b2o$650bo2bo$650bo2bo$649bo2bo64b2o$650b3o64b2o$
650b2o$663bo$654bo7b3o63b2o46b2o$654bo6b2o2bo62b2o46b2o$655bo6b5o$651b
2obob2o4b5o$650bo12bo$652bo5bo2bobo44b2o$658b3ob2o44b2o$654bo3b3obo$
654b2o3b3o$659bobo56b2o$660b4o54b2o$661b3o$662bo$729b2o46b2o$729b2o46b
2o2$643bo$642bobo2b2o$642b2o17b2o46b2o$643bo17b2o46b2o$645b2o$643b4o$
642bo2bo73b2o$644bo74b2o$645bo8bo$645b2o6b3o$641bo5bo4bo2b2o73b2o46b2o
$641b2o3b2o82b2o46b2o$645b2o4b2o$651b2o$650bo2bo$652b3o7b2o46b2o$662b
2o46b2o3$720b2o$720b2o$636bob2obo$635b3ob2o$634b2ob4o90b2o46b2o$637b2o
13b2o77b2o46b2o$637b2o13b2o$637b2o$634bo$634b2o27b2o46b2o63bo$635bobo
25b2o46b2o62b3o$635bo2bo7bo127b2o2bo$635bobo7b3o128b3o$635b3o6b2o2bo
72b2o$634bob2o6bo76b2o$634bo2bo5b2o$636bo5bo135bo$642b4o86b2o41bo$644b
2o7b2o77b2o40bo3bo$653b2o118b2ob2o3$633bo30b2o46b2o$631b2o31b2o46b2o
61bo$632b2o13b2o124b2o$774b2o$644b2o76b2o$627bo17bo76b2o$626b3o$625bo
2b2o$625bo3bo103b2o$626b2obo24b2o77b2o$628b2o24b2o$638bo$637b3o$636bo
2b2o24b2o$635b5o25b2o42bo$624bo2b2o6bo2b2o68bobo$624bobobo6bo2bo68b2ob
2o$625bo10bobo6b2o61bob2o11b2o$645b2o76b2o2$640b2o68b2o$621bob2obo12b
3o68bo23b2o$620b3ob2o11bo17b2o77b2o31bo$619b2ob4o12b2o15b2o56bo53bobo$
622b2o83b2ob2obo53b2o$622b2o83b2ob2ob2o$622b2o16bobo23b2o43bobo$619bo
12bo7bobo23b2o44bo$619b2o10b3o7bo$620bobo7b2o2bo$620bo2bo7b4o11b2o76b
2o$620bobo6bobo14b2o76b2o$620b3o5bo2bo$619bob2o6b3o$619bo2bo7bobo102b
2o$621bo8bobo23b2o48bo28b2o$630b3o23b2o46b2o$705b2o2$667b2o$613b3o51b
2o$612bo2bo$611bo$612b3o11bo16bo81b2o33bobo$625b3o14b3o80b2o33b2o$624b
o2b2o12b2obo116bo$615b2o23bo2bo$615b2o24b2o93b2o$616bo25bo14b2o77b2o$
616b2o9b2o28b2o$612b3obob2o5b3o16b2o$612b2o10bo21bo$616bo2bo4b3o41b2o$
616b3o6b2o15bo2bobo20b2o$641bob3obo$641bob2ob3o$607b3o14bobo18bobo50bo
27b2o$606bo2bo14b2o19b3o50bobo25b2o$606bo2bo15bo20bo51b2o$620bo$605b2o
12b3o115b2o$604bo2bo10b2o2bo35b2o77b2o$604bo2bo10bo3bo35b2o$607bo10bob
o133bo$753bo$619b2ob2o45b2o82b3o$621bo16bo30b2o$638bobo$638b2o$727b2o$
618b4o105b2o$617bobobo$601b3o14bo$601bo2bo133b2o$601bo2bo54b2o77b2o$
602bo2bo53b2o$602bo2bo7bo$600b2o10bobo2b2o72bobo$600b2o10b2o56b2o19b2o
$599bo3bo9bo56b2o20bo$599b2o14b2o$598bo14b4o$599bo3bo8bo2bo112b2o$600b
3o11bo113b2o$615bo132bo$615b2o129b2o$611bo5bo121b2o6b2o$611b2o3b2o13bo
bo26b2o77b2o$595b3o17b2o14b2o27b2o$594bo2bo34bo$594bo3bo$595b4o72b2o$
597bo73b2o3$729b2o$606bo122b2o$593b2ob2o7bobo77bo$593b3obo6b2ob2o75bo$
605bob2o75b3o53b2o$661b2o77b2o$661b2o$594bo$593bo$593b3o76b2o$608bo63b
2o66bo$600bo6b2o131bobo$599bob2o22bo114b2o$598bo5bo19bo105b2o$599b2o4b
o18b3o103b2o$601b2o2b2o2bo$605bob3o$608bo132b2o$586b3o19bo53b2o77b2o$
586bo2bo15b2obo53b2o$586bo2bo$587bo2bo$587bo2bo12bo69b2o$585b2o14b2o
70b2o4bo$585b2o11bo3b2o73b2o$584bo3bo8b3o78b2o$584b2o10bo2b2o4b2o120bo
$583bo12b2ob2o4b2o119b3o$584bo3bo6b3o127b2obo$585b3o8b2obo124bo2bo$
597bo2bo124b2o15b2o$597bo65b2o61bo6bobo6b2o$598bobo62b2o68b2o$591b2o6b
o19bo108b2o4bo$590bo26b2o111bo$590b2o3bo22b2o54b2o$591bo82b2o50bo2bobo
$596b2o127bob3obo$595b2o2b2o124bob2ob3o$597bo2bo5b2o121bobo$597b3o6b2o
121b3o$730bo2$594bobo146b2o$594b2o68b2o5bo71b2o$595bo68b2o5bobo$590bo
80b2o64b2o$589b3o144b2obo$588b2o2bo3b2o77b2o58b2o2b2o$579bobo6bo3bo3b
2o77b2o58b2ob2o$579b2o7bobo143bo2b2o$580bo80bo71bob2o$589b2ob2o13b2o
51b3o69b2obo$591bo15b2o50b2o2bo68bo$611bo48b5o67b3o$611bobo46b5o$611b
2o48bo$588b4o67bobo$587bobobo66bob2o$588bo69bobo$657b3o65b2o$597b2o58b
obo5b2o9b2o46b2o$597b2o59b3o6bo8b2o48bo$583bo75b2o4bo2bo$582bobo2b2o
71bo3bo2bo73b2o$582b2o24b2o54b3o51b2o$583bo24b2o108bobo19b2o$585b2o
131bo$583b4o$573bo8bo2bo$572bo11bo127bo$572b3o10bo125b2o$585b2o124bobo
$581bo5bo$581b2o3b2o10b2o$585b2o11b2o4bobo$604b2o98b3o$605bo98bo$609b
2o60bo4bo28bo$609b2o59bob2o3bo$594b3o72bo3bob2o$576b3o15bo2bo72b2o26b
2o$575bo2bo15bob2o74b3o22b2o$575bo2bo83b3o9b2o23bo$574bo2bo84bo8b2obo$
575b3o85bo5b5o$575b2o19b2o71b4o18b2o$594b4o71bo21bobo$579bo13bo2bo59b
2o33bo$579bo13bobo59b2o$567bo12bo12bobo61bo$565b2o9b2obo30b2o73bo$566b
2o7bo23b3o8b2o72b2o$577bo4bo10b2o3b2ob3o45b2o33bobo$593b2o3bo2bo47bobo
$579bobo15b2ob2o47bo$579b3o16bobo$570b3o26bo77b3o$570bo2bo69bo33bo$
570bob2o68b2o34bo$568b2o72bobo$568b2o$567bo2bo100b2o$571bo98b2o$569b3o
63b3o34bo$570bo64bo$636bo$664b2o$609bo54bobo$603b2o4b2o18b2o33bo$603bo
bo4b2o16b2o$559bo44bo5b2o18bo$559bobo34b2o6b3o2b3o46bo$559b2o3b3o28b2o
13bo46b2o$563bo2bo30bo10b2o12b2o33bobo$555bo7bo4bo34bo4b2o12bobo$554b
3o46bo18bo$553b2o2bo10bo20b2o12bo$553bo3bo9bo21bobo58b3o$553bobo7bob2o
22bo26bo33bo$562bo2bo49b2o34bo$554b2ob2o5b2o49bobo$556bo4bo2bo18bo$
561bo20b2o60b2o$565bo16bobo58b2o$562bo45b3o34bo$553b4o6b3o42bo$552bobo
bo52bo$553bo21b3o59b2o$575bo61bobo$576bo25b2o33bo$601b2o$553bo49bo$
551b2o16b2o60bo$552b2o14b2o60b2o$570bo24b2o33bobo$595bobo$595bo$562b2o
$562bobo58b3o$562bo26bo33bo$588b2o34bo$588bobo$556bo$555b2o60b2o$555bo
bo58b2o$581b3o34bo$581bo$582bo$610b2o$610bobo$575b2o33bo$574b2o$576bo$
604bo$603b2o$568b2o33bobo$568bobo$568bo2$596b3o$562bo33bo$561b2o34bo$
561bobo2$590b2o$589b2o$554b3o34bo$554bo$555bo$583b2o$583bobo$548b2o33b
o$547b2o$549bo$577bo$576b2o$541b2o33bobo$541bobo$541bo2$569b3o$535bo
33bo$534b2o34bo$534bobo2$563b2o$562b2o$527b3o34bo$527bo$528bo$556b2o$
556bobo$521b2o33bo$520b2o$522bo$550bo$549b2o$514b2o33bobo$514bobo$514b
o2$542b3o$508bo33bo$507b2o34bo$507bobo2$536b2o$535b2o$500b3o34bo$500bo
$501bo$529b2o$529bobo$494b2o33bo$493b2o$495bo$523bo$522b2o$487b2o33bob
o$487bobo$487bo2$515b3o$481bo33bo$480b2o34bo$480bobo2$509b2o$508b2o$
473b3o34bo$473bo$474bo$502b2o$502bobo$467b2o33bo$466b2o$468bo$496bo$
495b2o$460b2o33bobo$460bobo$460bo2$488b3o$454bo33bo$453b2o34bo$453bobo
2$482b2o$481b2o$446b3o34bo$446bo$447bo$475b2o$475bobo$440b2o33bo$439b
2o$441bo$469bo$468b2o$433b2o33bobo$433bobo$433bo2$461b3o$427bo33bo$
426b2o34bo$426bobo2$455b2o$454b2o$419b3o34bo$419bo$420bo$448b2o$448bob
o$413b2o33bo$412b2o$414bo$442bo$441b2o$406b2o33bobo$406bobo$406bo2$
434b3o$400bo33bo$399b2o34bo$399bobo2$428b2o$427b2o$392b3o34bo$392bo$
393bo$421b2o$421bobo$386b2o33bo$385b2o$387bo$415bo$414b2o$379b2o33bobo
$379bobo$379bo2$407b3o$373bo33bo$372b2o34bo$372bobo2$401b2o$400b2o$
365b3o34bo$365bo$366bo$394b2o$394bobo$359b2o33bo$358b2o$360bo$388bo$
387b2o$352b2o33bobo$352bobo$352bo2$380b3o$346bo33bo$345b2o34bo$345bobo
2$374b2o$373b2o$338b3o34bo$338bo$339bo$367b2o$367bobo$332b2o33bo$331b
2o$333bo$361bo$360b2o$325b2o33bobo$325bobo$325bo2$353b3o$319bo33bo$
318b2o34bo$318bobo2$347b2o$346b2o$311b3o34bo$311bo$312bo$340b2o$340bob
o$305b2o33bo$304b2o$306bo$334bo$333b2o$298b2o33bobo$298bobo$298bo2$
326b3o$292bo33bo$291b2o34bo$291bobo2$320b2o$319b2o$284b3o34bo$284bo$
285bo$313b2o$313bobo$278b2o33bo$277b2o$279bo$307bo$306b2o$271b2o33bobo
$271bobo$271bo2$299b3o$265bo33bo$264b2o34bo$264bobo2$293b2o$292b2o$
257b3o34bo$257bo$258bo$286b2o$286bobo$251b2o33bo$250b2o$252bo$280bo$
279b2o$244b2o33bobo$244bobo$244bo2$272b3o$238bo33bo$237b2o34bo$237bobo
2$266b2o$265b2o$230b3o34bo$230bo$231bo$259b2o$259bobo$224b2o33bo$223b
2o$225bo$253bo$252b2o$217b2o33bobo$217bobo$213bo3bo$212b3o$211bo2b2o
29b3o$211b2ob2o29bo$210b3o33bo$211b2obo$212bo2bo$212bo26b2o$213bobo22b
2o$214bo25bo2$211b3o$211b2obo17b2o$210bob2o18bobo$232bo3$226bo$225b2o$
209bobo13bobo$209b2o$210bo$218b3o$217bo2bo$217bo4bo2$222bo$221bo$217bo
b2o$216bo2bo$218b2o$215bo2bo$215bo$219bo$216bo$217b3o4$203bo$202bo$
202b3o13$212bo$210b2o$211b2o4$197bo$195b2o$196b2o13$204bo$204bobo$204b
2o4$189bo$189bobo$189b2o13$197bobo$197b2o$198bo4$182bobo$182b2o$183bo
12$191bo$190bo$190b3o4$176bo$175bo$175b3o13$185bo$183b2o$184b2o4$170bo
$168b2o$169b2o13$177bo$177bobo$177b2o4$162bo$162bobo$162b2o13$170bobo$
170b2o$171bo4$155bobo$155b2o$156bo12$164bo$163bo$163b3o4$149bo$148bo$
148b3o13$158bo$156b2o$157b2o4$143bo$141b2o$142b2o13$150bo$150bobo$150b
2o4$135bo$135bobo$135b2o13$143bobo$143b2o$144bo4$128bobo$128b2o$129bo
12$137bo$136bo$136b3o4$122bo$121bo$121b3o13$131bo$129b2o$130b2o4$116bo
$114b2o$115b2o13$123bo$123bobo$123b2o4$108bo$108bobo$108b2o13$116bobo$
116b2o$117bo4$101bobo$101b2o$102bo12$110bo$109bo$109b3o4$95bo$94bo$94b
3o13$104bo$102b2o$103b2o4$89bo$87b2o$88b2o13$96bo$96bobo$96b2o4$81bo$
81bobo$81b2o13$89bobo$89b2o$90bo4$74bobo$74b2o$75bo12$83bo$82bo$82b3o
4$68bo$67bo$67b3o13$77bo$75b2o$76b2o4$62bo$60b2o$61b2o13$69bo$69bobo$
69b2o4$54bo$54bobo$54b2o13$62bobo$62b2o$63bo4$47bobo$47b2o$48bo12$56bo
$55bo$55b3o4$41bo$40bo$40b3o13$50bo$48b2o$49b2o4$35bo$33b2o$34b2o13$
42bo$42bobo$42b2o4$27bo$27bobo$27b2o13$35bobo$35b2o$36bo4$20bobo$20b2o
$21bo12$29bo$28bo$28b3o4$14bo$13bo$13b3o13$23bo$21b2o$22b2o4$8bo$6b2o$
7b2o13$15bo$15bobo$15b2o4$o$obo$2o13$8bobo$8b2o$9bo18$2bo$bo$b3o!
Code: Select all
import golly as g
from glife import *
import math
import cmath
import os
from scipy import signal
def mod(x,m):
return ((x%m)+m)%m
#Linear algebra stuff
#Wanted to do this myself rather than using a library
#Whether or not this was smart is debatable
#I ended up using scipy instead because it's much faster
#A rational number
class Rational:
#Constructor
def __init__(self, num: int, den: int = 1):
a = math.gcd(num, den)
self.num = (1, -1)[den < 0] * num // a
self.den = abs(den // a)
#Hashing
def __eq__(self, other)->bool:
if isinstance(other, int):
return self.num == other and self.den == 1
elif isinstance(other, Rational):
return self.num == other.num and self.den == other.den
def __hash__(self) -> int:
return hash((self.num,self.den))
#Comparison
def __ne__(self, other)->bool:
if isinstance(other, int):
return self.num != other or self.den != 1
elif isinstance(other, Rational):
return self.num != other.num or self.den != other.den
def __lt__(self, other) -> bool:
if isinstance(other, int | float):
return self.num < other*self.den
elif isinstance(other, Rational):
return self.num*other.den < other.num*self.den
def __le__(self, other) -> bool:
if isinstance(other, int | float):
return self.num <= other*self.den
elif isinstance(other, Rational):
return self.num*other.den <= other.num*self.den
def __gt__(self, other) -> bool:
if isinstance(other, int | float):
return self.num > other*self.den
elif isinstance(other, Rational):
return self.num*other.den > other.num*self.den
def __ge__(self, other) -> bool:
if isinstance(other, int | float):
return self.num >= other*self.den
elif isinstance(other, Rational):
return self.num*other.den >= other.num*self.den
#Arithmetic
def __add__(self, other):
if isinstance(other, int):
return Rational(self.num+other*self.den, self.den)
elif isinstance(other, Rational):
return Rational(self.num*other.den+other.num*self.den, self.den*other.den)
def __sub__(self, other):
if isinstance(other, int):
return Rational(self.num-other*self.den, self.den)
elif isinstance(other, Rational):
return Rational(self.num*other.den-other.num*self.den, self.den*other.den)
def __mul__(self, other):
if isinstance(other, int):
return Rational(self.num*other, self.den)
elif isinstance(other, Rational):
return Rational(self.num*other.num, self.den*other.den)
def __truediv__(self, other):
if isinstance(other, int):
return Rational(self.num, self.den*other)
elif isinstance(other, Rational):
return Rational(self.num*other.den, self.den*other.num)
def __floordiv__(self, other):
return Rational(int(self / other), 1)
def __mod__(self, other):
return (self / other) - (self // other)
def __neg__(self):
return Rational(-self.num, self.den)
def __abs__(self):
return Rational(abs(self.num), self.den)
#Casting
def __int__(self) -> int:
return self.num // self.den
def __float__(self) -> float:
return self.num / self.den
def __str__(self) -> str:
return str(self.num) + "/" + str(self.den)
#Other math
def gcd(*args):
output = abs(args[0])
for i in range(1,len(args)):
output = Rational(math.gcd(output.num, args[i].num), math.lcm(output.den, args[i].den))
return output
#A matrix of rational numbers
class Matrix:
#Constructor
def __init__(self, terms):
#Automatically convert ints to Rationals
self.terms = [[Rational(1) * term for term in row] for row in terms]
self.height = len(terms)
self.width = 0
if self.height > 0:
self.width = len(terms[0])
#Get terms
def sliceRange(s):
if isinstance(s, int):
return range(s,s+1)
elif isinstance(s, slice):
return range(s.start, s.stop)
def __getitem__(self, key: list[int] | list[slice]):
if isinstance(key[0], int) and isinstance(key[1], int):
return self.terms[key[0]][key[1]]
else:
return Matrix([[self.terms[row][col] for col in Matrix.sliceRange(key[1])] for row in Matrix.sliceRange(key[0])])
#Hashing
def __eq__(self, other)->bool:
return self.terms == other.terms
def __hash__(self) -> int:
return hash(tuple(tuple(row) for row in self.terms))
#Arithmetic
def __add__(self, other):
return Matrix([[term1 + term2 for term1, term2 in zip(row1,row2)] for row1, row2 in zip(self.terms,other.terms)])
def __sub__(self, other):
return Matrix([[term1 - term2 for term1, term2 in zip(row1,row2)] for row1, row2 in zip(self.terms,other.terms)])
#Scalar or matrix multiplication
def __mul__(self, other):
if isinstance(other, int | Rational):
return Matrix([[term * other for term in row] for row in self.terms])
elif isinstance(other, Matrix):
return Matrix([[sum([self[rowIndex,sharedIndex]*other[sharedIndex,colIndex] for sharedIndex in range(self.width)], Rational(0)) for colIndex in range(other.width)] for rowIndex in range(self.height)])
elif isinstance(other, CosetMatrix):
return CosetMatrix(self*other.rep, other.lattice)
def __div__(self, other):
return Matrix([[term / other for term in row] for row in self.terms])
def __neg__(self):
return Matrix([[-term for term in row] for row in self.terms])
def transpose(self):
return Matrix([[self[rowIndex,colIndex] for rowIndex in range(self.height)] for colIndex in range(self.width)])
def copy(self):
return Matrix([[term for term in row] for row in self.terms])
def row(self, row: int):
return self[row, 0:self.width]
def col(self, col: int):
return self[0:self.height, col]
def rows(self):
return [self.row(n) for n in range(self.height)]
def cols(self):
return [self.col(n) for n in range(self.width)]
def __str__(self):
output = ""
for row in range(self.height):
output += "["
for col in range(self.width):
output += str(self[row,col])
if col < self.width-1:
output += ","
output += "]"
if row < self.height-1:
output += "\n"
return output
def isZero(self):
return all(all(term == 0 for term in row) for row in self.terms)
#Tools for making block matrices
def blockHorizontal(self, other):
return Matrix([row1+row2 for row1,row2 in zip(self.terms, other.terms)])
def blockVertical(self, other):
return Matrix(self.terms+other.terms)
#Row reduction
def rowReduce(self):
output = self.copy()
rowIndex = 0
colIndex = 0
while rowIndex < output.height and colIndex < output.width:
#Check if this column is zero below rowIndex, if so goto next column
nonzeroRowIndex = next((rowCheckIndex for rowCheckIndex in range(rowIndex, output.height) if output[rowCheckIndex,colIndex] != 0), -1)
if nonzeroRowIndex == -1:
colIndex += 1
else:
#Otherwise, do a row-reduction step
#Swap rows rowIndex and nonzeroRowIndex if needed
if nonzeroRowIndex != rowIndex:
output.swapRowsInPlace(rowIndex, nonzeroRowIndex)
#Normalize to 1
divideByVal = output[rowIndex, colIndex]
output.terms[rowIndex] = [term / divideByVal for term in output.terms[rowIndex]]
for otherRowIndex in range(output.height):
if otherRowIndex != rowIndex:
output.terms[otherRowIndex] = [otherRowTerm - rowTerm * output[otherRowIndex, colIndex] for rowTerm, otherRowTerm in zip(output.terms[rowIndex], output.terms[otherRowIndex])]
rowIndex += 1
return output
def swapRowsInPlace(self, row1: int, row2: int):
self.terms[row1], self.terms[row2] = self.terms[row2], self.terms[row1]
def removeZeroRows(self):
return Matrix([row for row in self.terms if not all(term == 0 for term in row)])
def det(self):
rowReducedForm = self.rowReduce()
return math.prod([rowReducedForm[i,i] for i in range(rowReducedForm.width)])
def rank(self):
return len([row for row in self.terms if not all(term == 0 for term in row)])
def id(n: int):
return Matrix([[Rational(int(row == col)) for col in range(n)] for row in range(n)])
def zero(height: int, width: int):
return Matrix([[Rational(0) for col in range(width)] for row in range(height)])
#Gives the inverse of an invertible square matrix
def inverse(self):
return self.blockHorizontal(Matrix.id(self.width)).rowReduce()[0:self.height,self.width:self.width*2]
#Gives a right inverse
def rightInverse(self):
transpose = self.transpose()
return transpose * (self * transpose).inverse()
#Row reduction but we can only use integer multiples
def integerRowReduce(self):
output = self.copy()
rowIndex = 0
colIndex = 0
while rowIndex < output.height and colIndex < output.width:
#Check if this column is zero below rowIndex, if so goto next column
existsANonzeroEntry = False
rowToTest = rowIndex
while rowToTest < output.height:
if output[rowToTest, colIndex] > 0:
#Found a nonzero entry
existsANonzeroEntry = True
if rowToTest == rowIndex:
#On the starting row, so we don't do much
rowToTest += 1
else:
if output[rowIndex, colIndex] < output[rowToTest, colIndex]:
#swap rows
output.swapRowsInPlace(rowIndex, rowToTest)
else:
#subtract as many terms[rowToTest] from terms[rowIndex] as possible
mult = output[rowIndex, colIndex] // output[rowToTest, colIndex]
output.terms[rowIndex] = [term - testTerm * mult for term, testTerm in zip(output.terms[rowIndex],output.terms[rowToTest])]
elif output[rowToTest, colIndex] < 0:
#Switch sign of this row
output.terms[rowToTest] = [-term for term in output.terms[rowToTest]]
else:
#Entry cleared, move to next row
rowToTest += 1
if existsANonzeroEntry and rowIndex < output.height and colIndex < output.width and output[rowIndex, colIndex] != 0:
#Subtract as much from the rows < rowIndex as possible while leaving the term positive
for rowToModify in range(rowIndex):
mult = output[rowToModify, colIndex] // output[rowIndex, colIndex]
output.terms[rowToModify] = [termToModify - term * mult for term, termToModify in zip(output.terms[rowIndex],output.terms[rowToModify])]
rowIndex += 1
else:
colIndex += 1
return output
#A lattice of rational points
class Lattice:
#Constructor
def __init__(self, basis: Matrix, rowReduceBasis: bool = True):
#Do integer row reduction for our basis by default
if rowReduceBasis:
self.basis = basis.integerRowReduce().removeZeroRows()
else:
self.basis = basis.copy()
self.dimension = self.basis.width
self.rank = self.basis.height
#Find pivot columns
#The index of the first nonzero column in each row
self.pivots = [[x != 0 for x in row].index(True) for row in self.basis.terms]
#Find inverse of the generator matrix
self.changeOfBasis = self.basis.rightInverse()
#Gets canonical coset representative for a matrix
def getCosetRepresentative(self, matrix: Matrix) -> Matrix:
output = matrix.copy()
for matrixRowIndex in range(matrix.height):
for rowIndex in range(len(self.pivots)):
colIndex = self.pivots[rowIndex]
generatorValue = self.basis[rowIndex,colIndex]
matrixValue = output[matrixRowIndex,colIndex]
output.terms[matrixRowIndex] = [output[matrixRowIndex,termIndex] - self.basis[rowIndex,termIndex] * (matrixValue // generatorValue) for termIndex in range(matrix.width)]
return output
#Does this lattice group contain a given row vector
def __contains__(self, vector: Matrix) -> bool:
return self.getCosetRepresentative(vector).isZero()
#Sum of two lattices
def __add__(self, other):
return Lattice(self.basis.blockVertical(other.basis))
def addGenerators(self, basisVectors: Matrix):
return Lattice(self.basis.blockVertical(basisVectors))
#Gets coordinates of the row vectors in a matrix where all row vectors are in this lattice
def getCoordinates(self, matrix: Matrix) -> Matrix:
return matrix * self.changeOfBasis
#Whether or not this lattice contains a multiple of the row vector for each row of a given matrix
def containsMultiple(self, matrix: Matrix) -> bool:
return self.getCoordinates(matrix) * self.basis == matrix
#The intersection of self with the plane other lies in
def intersectWithPlane(self,other):
#add in extra coordinates that don't lie in this plane
otherExtraBasis = other.basis
n = 0
while otherExtraBasis.height < otherExtraBasis.width:
testVector = Matrix([[Rational(int(a==n)) for a in range(otherExtraBasis.width)]])
n += 1
if not Lattice(otherExtraBasis).containsMultiple(testVector):
otherExtraBasis = testVector.blockVertical(otherExtraBasis)
otherExtraBasisInverse = otherExtraBasis.inverse()
basisInOtherCoordsReduced = (self.basis * otherExtraBasisInverse).integerRowReduce()
#Isolate only the rows that don't rely on the first few terms
basisInPlaneInOtherCoords = Matrix([row for row in basisInOtherCoordsReduced.terms if all(row[i]==0 for i in range(other.basis.width - other.basis.height))])
#Convert from coordinates
basisInPlane = basisInPlaneInOtherCoords * otherExtraBasis
return Lattice(basisInPlane)
#The dual of a lattice
def dual(self):
return Lattice(self.changeOfBasis.transpose(), False)
#The intersection of two lattices
def __and__(self, other):
return (self.dual() + other.dual()).dual().intersectWithPlane(self).intersectWithPlane(other)
#The lattice of integer divisors of a given lattice
def divisorLattice(self):
return LatticeGroup(Matrix.id(self.dimension)).intersectWithPlane(self)
#A basis for the torsion-free part of G/H
#Output as a matrix with rows v s.t. v+H form our basis
def quotientTorsionFreeBasis(self, sublattice):
divisorLattice = self.intersectWithPlane(sublattice)
divisorLatticeBasisExtended = divisorLattice.basis
nonPivots = [x for x in range(divisorLattice.dimension) if x not in divisorLattice.pivots]
for nonPivot in nonPivots:
divisorLatticeBasisExtended = self.basis.row(nonPivot).blockVertical(divisorLatticeBasisExtended)
divisorLatticeBasisExtendedInverse = divisorLatticeBasisExtended.inverse()
basisVectorsInDivisorLatticeExtendedCoordsReduced = (self.basis * divisorLatticeBasisExtendedInverse).integerRowReduce()
nonPivotBasisVectorsToCoords = basisVectorsInDivisorLatticeExtendedCoordsReduced[0:(divisorLattice.dimension-divisorLattice.rank),0:divisorLattice.dimension]
return CosetMatrix((nonPivotBasisVectorsToCoords * divisorLatticeBasisExtended).integerRowReduce(), sublattice)
#The torsion elements of G/H
def quotientTorsionElements(self, sublattice):
#We know these are all in divisorLattice
divisorLattice = self.intersectWithPlane(sublattice)
intermediateLattice = sublattice
#Find torsion of all basis elements
generators = Matrix([])
torsions = []
for basisElt in divisorLattice.basis.rows():
#Find the torsion of this basis element in the intermediate lattice
basisEltCoords = basisElt * intermediateLattice.changeOfBasis
#Torsion is the gcd of the elements of basisEltCoords
torsion = Rational.gcd(*basisEltCoords.terms[0]).den
torsions.append(torsion)
generators = generators.blockVertical(basisElt)
intermediateLattice = intermediateLattice.addGenerators(basisElt)
#Output as an iterator
def outputGenerator(basisElts, torsions):
multiplicities = [0 for torsion in torsions]
while True:
yield CosetMatrix(Matrix([multiplicities]) * basisElts, sublattice)
#Increment
index = 0
multiplicities[0]+=1
while index < len(multiplicities) and multiplicities[index] == torsions[index]:
multiplicities[index] = 0
index += 1
if index < len(multiplicities):
multiplicities[index]+=1
if index == len(multiplicities):
break
return outputGenerator(basisElts, torsions)
#Generators for G/H, with torsions (0 if torsion-free)
def quotientGeneratorsWithTorsions(self, sublattice):
#We know these are all in divisorLattice
divisorLattice = self.intersectWithPlane(sublattice)
intermediateLattice = sublattice
#Find torsion of all basis elements
generators = Matrix([])
torsions = []
for basisElt in divisorLattice.basis.rows():
#Find the torsion of this basis element in the intermediate lattice
basisEltCoords = basisElt * intermediateLattice.changeOfBasis
#Torsion is the gcd of the elements of basisEltCoords
torsion = Rational.gcd(*basisEltCoords.terms[0]).den
#if torsion != 1:
torsions.append(torsion)
generators = generators.blockVertical(basisElt)
intermediateLattice = intermediateLattice.addGenerators(basisElt)
#Add in the torsion-free basis
#return list(zip([CosetMatrix(row, sublattice) for row in generators.rows()], torsions)) + [(row,0) for row in self.quotientTorsionFreeBasis(sublattice).rows()]
return list(zip(generators.rows(), torsions)) + [(row.rep,0) for row in self.quotientTorsionFreeBasis(sublattice).rows()]
#Divides an envelope into a dictionary of cosets by a lattice
def divideIntoCosets(self, envelope):
output = dict()
for v in envelope:
key = CosetMatrix(v, self)
if key in output:
output[key].append(v)
else:
output[key] = [v]
#g.warn("".join(str(k.rep)+": "+str([str(x) for x in v])+"\n\n" for k,v in output.items()))
return output
#A matrix of lattice cosets of the form v+H
class CosetMatrix:
#Constructor
def __init__(self, rep: Matrix, lattice: Lattice):
self.lattice = lattice
self.rep = lattice.getCosetRepresentative(rep)
self.width = self.rep.width
self.height = self.rep.height
#Hashing
def __hash__(self) -> int:
return hash((self.rep))
def __eq__(self, other) -> bool:
return self.rep == other.rep
def __ne__(self, other) -> bool:
return self.rep != other.rep
#Arithmetic
def __add__(self, other) -> bool:
if isinstance(other, CosetMatrix):
return CosetMatrix(self.rep+other.rep, self.lattice)
elif isinstance(other, Matrix):
return CosetMatrix(self.rep+other, self.lattice)
def __sub__(self, other) -> bool:
if isinstance(other, CosetMatrix):
return CosetMatrix(self.rep-other.rep, self.lattice)
elif isinstance(other, Matrix):
return CosetMatrix(self.rep-other, self.lattice)
def __neg__(self) -> bool:
return CosetMatrix(-self.rep, self.lattice)
#Matrix multiplication
#Note: We also multiply the lattice basis
def __mul__(self, other):
return CosetMatrix(self.rep * other, Lattice(self.lattice.basis * other))
def rows(self):
return [CosetMatrix(row, self.lattice) for row in self.rep.rows()]
#A function from Z^n -> int
class LatticeFunction:
def __init__(self, data, dimension):
self.data = data
self.dimension = dimension
self.minCoords = [min(int(key[0,i]) for key,value in self.data.items()) for i in range(self.dimension)]
self.maxCoords = [max(int(key[0,i]) for key,value in self.data.items()) for i in range(self.dimension)]
self.coordDiffs = [x-y for x,y in zip(self.maxCoords, self.minCoords)]
#Convolve using Fourier transform
def convolve(self, other):
#Find amounts to wrap around
#These must be wrapArounds[i] a power of 2 satisfying wrapArounds[i] > self.coordDiffs[i] + other.coordDiffs[i]
#wrapArounds = [1<<(x+y).bit_length() for x,y in zip(self.coordDiffs, other.coordDiffs)]
wrapArounds = [x+y+1 for x,y in zip(self.coordDiffs, other.coordDiffs)]
#return LatticeFunction.unwrapData(LatticeFunction.fft([x*y for x,y in zip(LatticeFunction.fft(self.wrapData(wrapArounds), 1, 1), LatticeFunction.fft(other.wrapData(wrapArounds), 1, 1))], -1, 0.5), wrapArounds, Matrix([self.minCoords])+Matrix([other.minCoords]))
selfData = self.wrapData(wrapArounds)
otherData = other.wrapData(wrapArounds)
g.show("Convolving with length " + str(math.prod(wrapArounds)) + " " + str(tuple(wrapArounds)) + "...")
return LatticeFunction.unwrapData(signal.fftconvolve(selfData, otherData), wrapArounds, Matrix([self.minCoords])+Matrix([other.minCoords]))
#Wraps data to a list, where wrapArounds[i] are our sufficiently large powers of 2
def wrapData(self, wrapArounds):
g.show("Wrapping...")
wrapAroundsCumulative = [math.prod(wrapArounds[0:i]) for i in range(len(wrapArounds)+1)]
output = [0 for x in range(math.prod(wrapArounds))]
#Edit output.data
for key, value in self.data.items():
#Offset by self.minCoords so that indices are all positive
keyIndex = sum(mod(int(key[0,i] - self.minCoords[i]), wrapArounds[i])*wrapAroundsCumulative[i] for i in range(self.dimension))
output[keyIndex] = value
return output
#1-dimensional fast Fourier transform of an array of length 2^n
#Using the Cooley-Tukey algorithm
#I don't actually use this because signal.fftconvolve is faster but it was fun to implement
numFFTs = 0
def fft(data, sign: int = 1, scalePerStep = 1):
outputData = data.copy()
dataSize = len(outputData).bit_length() - 1
#Precompute twiddle factors
g.show("FFT " + str(LatticeFunction.numFFTs+1) + "/12: Computing twiddle factors...")
twiddleFactors = [cmath.exp(-sign * 2j * math.pi * k / (1 << dataSize)) for k in range(1 << dataSize)]
for step in range(0,dataSize):
g.show("FFT " + str(LatticeFunction.numFFTs+1) + "/12: " + str(step) + "/" + str(dataSize))
nextData = []
splitPos = dataSize - step - 1
splitPosMaskBit = 1 << splitPos
belowSplitPosMask = splitPosMaskBit - 1
aboveSplitPosMask = ((1 << (dataSize-1)) - 1) & ~belowSplitPosMask
for i in range(len(outputData)):
#Input indices
#How this works: Take i, split into before and after parts at data-step-1, bitshift after part up 1, insert a 0 or 1 bit
lowerInputIndex = (i & belowSplitPosMask) | ((i & aboveSplitPosMask) << 1)
upperInputIndex = lowerInputIndex | splitPosMaskBit
#Parity
paritySign = 1 - ((i >> (dataSize - 1)) << 1)
#Twiddle factor index
k = i & aboveSplitPosMask
#print(str(step) + ", " + str(i) + ": " + str(lowerInputIndex) + ", " + str(upperInputIndex) + str(" ") + str(k) + ", " + str(twiddleFactor))
nextData.append((outputData[lowerInputIndex] + paritySign * twiddleFactors[k] * outputData[upperInputIndex]) * scalePerStep)
#Progress bar for my sanity
outputData = nextData
g.show("FFT " + str(LatticeFunction.numFFTs) + "/6: " + str(dataSize) + "/" + str(dataSize))
LatticeFunction.numFFTs += 1
return outputData
#Unwrap a list to a LatticeFunction (rounding to ints)
def unwrapData(data, wrapArounds, offset):
g.show("Unwrapping...")
wrapAroundsCumulative = [math.prod(wrapArounds[0:i]) for i in range(len(wrapArounds)+1)]
outputData = {}
for keyIndex in range(len(data)):
if not cmath.isclose(data[keyIndex], 0, rel_tol=1e-09, abs_tol=1e-09):
#Nonzero entry
key = Matrix([[mod(keyIndex // wrapAroundsCumulative[i], wrapArounds[i]) for i in range(len(wrapArounds))]]) + offset
outputData[key] = round(data[keyIndex].real)
return LatticeFunction(outputData, len(wrapArounds))
#Wraps data to a function on a quotient group
def wrapToQuotientFunction(self, group, sign: int = 1):
outputData = {}
for key,value in self.data.items():
quotientKey = CosetMatrix(key * group.optimalLatticeBasis * sign, group.sublattice)
if quotientKey in outputData:
outputData[quotientKey] += value
else:
outputData[quotientKey] = value
return QuotientGroupFunction(group, outputData)
#A quotient of lattices
class QuotientGroup:
def __init__(self, lattice: Lattice, sublattice: Lattice):
#On initialization, organize
self.lattice = lattice
self.sublattice = sublattice
self.generatorsWithTorsions = lattice.quotientGeneratorsWithTorsions(sublattice)
#Find optimal basis for compact unwrapping
# I'm pretty sure this is actually pretty optimal for our purposes
self.optimalLatticeBasis = self.lattice.basis
self.optimalChangeOfBasis = self.optimalLatticeBasis.rightInverse()
#Other thing I considered, seems worse though
#self.optimalLatticeBasis = Matrix([generator.terms[0] for generator, torsion in self.generatorsWithTorsions])
#g.warn(str(self.lattice.basis) + "\n\n" + str(self.sublattice.basis) + "\n\n" + str(self.optimalLatticeBasis))
#A function from G/H -> int
class QuotientGroupFunction:
def __init__(self, group: QuotientGroup, data):
self.group = group
#A dictionary from cosets v+group.sublattice to ints
self.data = data
#Unwraps to a LatticeFunction
def unwrap(self):
return LatticeFunction({key.rep * self.group.optimalChangeOfBasis: self.data[key] for key in self.data}, self.group.optimalChangeOfBasis.width)
#Wraps to a further quotient
def wrapToQuotientFunction(self, group, sign: int = 1):
outputData = {}
for key,value in self.data.items():
quotientKey = CosetMatrix(key.rep * group.optimalLatticeBasis * sign, group.sublattice)
if quotientKey in outputData:
outputData[quotientKey] += value
else:
outputData[quotientKey] = value
return QuotientGroupFunction(group, outputData)
#Function convolution
def convolve(self, other):
return self.unwrap().convolve(other.unwrap()).wrapToQuotientFunction(self.group)
#Golly misc help stuff
#Helpful conversions
def toCellSet(cellList):
return {(cellList[i],cellList[i+1]) for i in range(0,len(cellList),2)}
def toCellList(cellSet):
return [num for x,y in cellSet for num in [x,y]]
#nonempty getrect
def getrect():
if g.empty():
return [0,0,1,1]
return g.getrect()
#This is just convenient
def gethash():
return g.hash(getrect())
def getcells():
return g.getcells(getrect())
#Does the pattern contain a given cell list
def patternContains(cellList, x=0, y=0):
return toCellSet(g.transform(cellList,x,y)).issubset(toCellSet(getcells()))
#Tools for pattern decomposition into components
#For a decomposition of Child(p) = DisjointUnion(q_i)
# Returns a decomposition of this pattern as p = DisjointUnion(p_j) such that Child(p_j) = DisjointUnion(q_{i_{j,k}})
# All inputs and outputs are given as cell sets
nbhd = {(x,y) for x in range(-1,2) for y in range(-1,2)}
def findSubpatterns(patternState, childDecomposition):
#Start by decomposing into connected components
#output = findConnectedComponents(patternState, {(x,y) for x in range(-1,2) for y in range(-1,2)})
output = set()
for cell in patternState:
nbhdOfCell = {(cell[0]+x,cell[1]+y) for x,y in nbhd}
#Check against all children in childDecomposition
requiredCells = {cell}
for childCellSet in childDecomposition:
if not nbhdOfCell.isdisjoint(childCellSet):
#This child's component must contain patternState intersect nbhd(childCellSet)
requiredCells |= patternState & set().union(*[{(a[0]+b[0],a[1]+b[1]) for a in nbhd} for b in childCellSet])
#We require all these cells in our component
componentsToUnionWith = {component for component in output if not requiredCells.isdisjoint(component)}
output -= componentsToUnionWith
output.add(frozenset({cell}.union(*componentsToUnionWith)))
#Additionally, unionize any components around cells that don't match
evolvedState = set().union(*childDecomposition)
evolvedComponentStatesUnion = set().union(*[toCellSet(g.evolve(toCellList(component),1)) for component in output])
error = evolvedState ^ evolvedComponentStatesUnion
for errorCell in error:
nbhdOfCell = {(errorCell[0]+x,errorCell[1]+y) for x,y in nbhd}
#Unionize all components intersecting nbhdOfCell
componentsToUnionWith = {component for component in output if not nbhdOfCell.isdisjoint(component)}
output -= componentsToUnionWith
output.add(frozenset().union(*componentsToUnionWith))
return output
#Removes unneccessary cells from the evolution of this pattern (requiring patFinalState in the final result)
def removeAshCells(patEvolution, patFinalState):
#Find the indepdenent subpatterns of this at each stage
patFinalStateCellSet = frozenset(toCellSet(patFinalState))
patFinalStateCellSetWithExtra = frozenset(toCellSet(g.evolve(patEvolution[len(patEvolution)-1], 1)))
patFinalDecomposition = {patFinalStateCellSet} | {frozenset({cell}) for cell in patFinalStateCellSetWithExtra - patFinalStateCellSet}
patDecompositions = [patFinalDecomposition]
for i in reversed(range(len(patEvolution))):
#Find the prior decomposition
prevDecomposition = findSubpatterns(toCellSet(patEvolution[i]), patDecompositions[0])
patDecompositions.insert(0, prevDecomposition)
#Construct list of only the minimal decompositions leading to patFinalState
minComponents = [patFinalStateCellSet]
for i in reversed(range(len(patEvolution))):
#Need component intersects nbhd(minComponents[0])
try:
prevMinComponent = next(component for component in patDecompositions[i] if not component.isdisjoint(set().union(*[{(a[0]+b[0],a[1]+b[1]) for a in nbhd} for b in minComponents[0]])))
minComponents.insert(0, prevMinComponent)
except StopIteration:
#This only happens when our cell has no predecessors
#This isn't common, but can occur when we add in components mid-evolution
continue
#Convert back to cell lists, remove the last component
return [toCellList(component) for component in minComponents[0:len(minComponents)-1]]
cellLattice = Lattice(Matrix.id(3))
#A periodic pattern with inputs and outputs
class PeriodicPattern:
def __init__(self, cellList, dT, dX, dY, inputs = [], outputs = [], computeExtras = False):
self.dX = dX
self.dY = dY
self.dT = dT
self.inputs = inputs
self.outputs = outputs
self.inputNamesToIndexes = {inputs[i][1]:i for i in range(len(inputs))}
self.outputNamesToIndexes = {outputs[i][1]:i for i in range(len(outputs))}
self.periodVector = Matrix([[self.dT, -self.dX, -self.dY]])
self.periodLattice = Lattice(self.periodVector)
self.positionGroup = QuotientGroup(cellLattice, self.periodLattice)
#Find states
currentState = cellList.copy()
self.state = []
g.setrule("B3/S23")
for t in range(self.dT):
#Remove all outputs on this generation from currentState
#TODO: Could be nice to add a way for outputs to be removed 'late'/after a full cycle
# Or generally for the pattern to 'fill in' over multiple cycles, so that sparks are covered too
for outputPattern, outputName, outputTimeToRemove, outputPosition in outputs:
if outputTimeToRemove == t:
currentState = outputPattern.joinInto(currentState, outputPosition, "andnot")
self.state.append(currentState)
#Join all inputs on this generation to currentState
for inputPattern, inputName, inputTimeToAdd, inputPosition in inputs:
if inputTimeToAdd == t:
currentState = inputPattern.joinInto(currentState, inputPosition, "or")
currentState = g.evolve(currentState, 1)
if computeExtras:
#Precompute some envelopes for collision purposes
g.setrule("B12345678/S012345678")
self.envelopeA = LatticeFunction(dict.fromkeys({Matrix([[t,-x,-y]]) for t in range(self.dT) for x,y in toCellSet(g.evolve(self.state[t],1))}, 1), 3)
g.setrule("B3/S012345678")
self.envelopeB = LatticeFunction(dict.fromkeys({Matrix([[t,-x,-y]]) for t in range(self.dT) for x,y in toCellSet(g.evolve(self.state[t],1))}, 1), 3)
g.setrule("B1/S")
self.envelopeC = LatticeFunction(dict.fromkeys({Matrix([[t,-x,-y]]) for t in range(self.dT) for x,y in toCellSet(g.evolve(self.state[t],1))}, 1), 3)
g.setrule("B2/S")
self.envelopeD = LatticeFunction(dict.fromkeys({Matrix([[t,-x,-y]]) for t in range(self.dT) for x,y in toCellSet(g.evolve(self.state[t],1))}, 1), 3)
g.setrule("B3/S23")
#Find states required for pattern to be restored
#TODO: Also find states required for outputs
# Approach we take: Remove any unnecessary cells (parts that permanently have no influence on the rest of the crawler)
#Fill in crawlerStates
#We iterate twice to prevent pruning ash near the end of the cycle that would collide with the crawler later
#TODO: Most of this is just copy-pasted, I could definitely do this better
extendedState = self.state.copy()
for t in range(self.dT):
#Remove all outputs on this generation from currentState
for outputPattern, outputName, outputTimeToRemove, outputPosition in outputs:
if outputTimeToRemove == t:
currentState = outputPattern.joinInto(currentState, outputPosition + Matrix([[0,self.dX,self.dY]]), "andnot")
extendedState.append(currentState)
#Join all inputs on this generation to currentState
for inputPattern, inputName, inputTimeToAdd, inputPosition in inputs:
if inputTimeToAdd == t:
currentState = inputPattern.joinInto(currentState, inputPosition + Matrix([[0,self.dX,self.dY]]), "or")
currentState = g.evolve(currentState, 1)
#TODO: This is *probably* too strict, since some of the pi-crawler pairs I expected don't show up
self.requiredState = removeAshCells(extendedState, g.transform(self.state[0], self.dX*2, self.dY*2))[0:self.dT]
def getStatePosition(self, position, onlyRequired = False):
if onlyRequired:
return g.transform(self.requiredState[int(position.rep[0,0])], int(position.rep[0,1]), int(position.rep[0,2]))
else:
return g.transform(self.state[int(position.rep[0,0])], int(position.rep[0,1]), int(position.rep[0,2]))
def joinInto(self, cellList, position, mode):
if mode == "or":
return g.join(cellList, self.getStatePosition(position))
elif mode == "andnot":
return toCellList(toCellSet(cellList) - toCellSet(self.getStatePosition(position)))
def place(self, position, mode = "or", onlyRequired = False):
g.putcells(self.getStatePosition(position, onlyRequired),0,0,1,0,0,1, mode)
def placeInput(self, position, index, mode = "or"):
stateT = int(position.rep[0,0])
for inputPattern, inputName, inputTimeToAdd, inputPosition in self.inputs:
indexToUse = index + (1,0)[inputTimeToAdd >= stateT]
inputPattern.place(inputPosition + (position.rep + Matrix([[-inputTimeToAdd, 0, 0]]) - Matrix([[self.dT, -self.dX, -self.dY]]) * indexToUse), mode)
def placeOutput(self, position, index, mode = "or"):
stateT = int(position.rep[0,0])
for outputPattern, outputName, outputTimeToRemove, outputPosition in self.outputs:
indexToUse = index + (1,0)[outputTimeToRemove <= stateT]
outputPattern.place(outputPosition + (position.rep + Matrix([[-outputTimeToRemove, 0, 0]]) + Matrix([[self.dT, -self.dX, -self.dY]]) * indexToUse), mode)
#Place with inputs (and outputs)
def placeWithInputs(self, position, numInputs = 0, numOutputs = 0, mode = "or", onlyRequired = False):
self.place(position, mode, onlyRequired)
for i in range(0,numInputs):
self.placeInput(position, i, mode)
for i in range(0,numOutputs):
self.placeOutput(position, i, mode)
#Test this pattern with inputs (and outputs)
# We only want to test against the minimum envelope required to sustain the component
#TODO: Allow more customizability in input/output testing
def test(self, position, onlyRequired = True):
return patternContains(self.getStatePosition(position, onlyRequired))
def testInput(self, position, index):
stateT = int(position.rep[0,0])
for inputPattern, inputName, inputTimeToAdd, inputPosition in self.inputs:
indexToUse = index + (1,0)[inputTimeToAdd >= stateT]
if not inputPattern.test(inputPosition + (position.rep + Matrix([[-inputTimeToAdd, 0, 0]]) - Matrix([[self.dT, -self.dX, -self.dY]]) * indexToUse)):
return False
return True
def testOutput(self, position, index):
stateT = int(position.rep[0,0])
for outputPattern, outputName, outputTimeToRemove, outputPosition in self.outputs:
indexToUse = index + (1,0)[outputTimeToRemove <= stateT]
if not outputPattern.test(outputPosition + (position.rep + Matrix([[-outputTimeToRemove, 0, 0]]) + Matrix([[self.dT, -self.dX, -self.dY]]) * indexToUse)):
return False
return True
def testWithInputs(self, position, numInputs = 0, numOutputs = 0):
return self.test(position) and all(self.testInput(position,i) for i in range(0, numInputs)) and all(self.testOutput(position,i) for i in range(0, numOutputs))
#Enumerate all possible collisions/interaction separations between two objects
#NOTE: This is optimized for the case where self is small
#TODO: Would probably like to make a version optimized for where self is not small
# I'm not entirely sure how best to do that
def enumerateCollisionSeparations(self, other):
separationLattice = self.periodLattice + other.periodLattice
separationGroup = QuotientGroup(cellLattice, separationLattice)
#Wrapping our envelopes first is probably more efficient
prewrapSelfA = self.envelopeA.wrapToQuotientFunction(separationGroup, -1)
prewrapSelfB = self.envelopeB.wrapToQuotientFunction(separationGroup, -1)
prewrapSelfC = self.envelopeC.wrapToQuotientFunction(separationGroup, -1)
prewrapSelfD = self.envelopeD.wrapToQuotientFunction(separationGroup, -1)
prewrapOtherA = other.envelopeA.wrapToQuotientFunction(separationGroup, 1)
prewrapOtherB = other.envelopeB.wrapToQuotientFunction(separationGroup, 1)
prewrapOtherC = other.envelopeC.wrapToQuotientFunction(separationGroup, 1)
prewrapOtherD = other.envelopeD.wrapToQuotientFunction(separationGroup, 1)
collisionSeparationCosets = set(prewrapSelfA.convolve(prewrapOtherB).data) | set(prewrapSelfB.convolve(prewrapOtherA).data) | set(prewrapSelfC.convolve(prewrapOtherD).data) | set(prewrapSelfD.convolve(prewrapOtherC).data)
#Want to find the first possible absolute separations
#This means, for each separationCoset in collisionSeparationCosets, we want to find the first time resulting in an interaction
#Divide our envelopes into cosets
selfCosetsA = separationLattice.divideIntoCosets(self.envelopeA.data)
selfCosetsB = separationLattice.divideIntoCosets(self.envelopeB.data)
selfCosetsC = separationLattice.divideIntoCosets(self.envelopeC.data)
selfCosetsD = separationLattice.divideIntoCosets(self.envelopeD.data)
otherCosetsA = separationLattice.divideIntoCosets(other.envelopeA.data)
otherCosetsB = separationLattice.divideIntoCosets(other.envelopeB.data)
otherCosetsC = separationLattice.divideIntoCosets(other.envelopeC.data)
otherCosetsD = separationLattice.divideIntoCosets(other.envelopeD.data)
#Find earliest interatction cells for each coset
#Idea:
# Want to understand the space of vectors v such that CosetMatrix(v, self.periodLattice) in selfEnvelope, and CosetMatrix(v + separation, other.periodLattice) in otherEnvelope
# That is, exist m,n such that v + m*self.periodVector in selfEnvelope.reps, v + separation + n*other.periodVector in otherEnvelope.reps
# Have x in selfEnvelope.reps, y in otherEnvelope.reps such that v + m*self.periodVector = x, v + separation + n*other.periodVector = y
# Then x+separation-y = m*self.periodVector - n*other.periodVector
# So [m,-n] = (x+separation-y) * changeOfCoords
# In particular, m = (x+separation-y) * changeOfCoords.col(0)
# Then v = x - self.periodVector * ((x+separation-y) * changeOfCoords.col(0))[0,0]
# Specifically, v[0,0] = x[0,0] - self.periodVector[0,0] * ((x+separation-y) * changeOfCoords.col(0))[0,0]
# = x[0,0] - self.periodVector[0,0] * (x * changeOfCoords.col(0))[0,0] + self.periodVector[0,0] * ((y-separation) * changeOfCoords.col(0))[0,0]
# = x * ([[1],[0],[0]] - changeOfCoords.col(0) * self.periodVector[0,0]) + (y-separation) * changeOfCoords.col(0) * self.periodVector[0,0]
cMulOther = self.periodVector.blockVertical(other.periodVector).rightInverse().col(0) * self.periodVector[0,0]
cMulSelf = Matrix([[1],[0],[0]]) - cMulOther
def findContribs(cosetReps, multiplier):
return {coset: min((rep * multiplier)[0,0] for rep in cosetReps[coset]) for coset in cosetReps}
selfContribsA = findContribs(selfCosetsA, cMulSelf)
selfContribsB = findContribs(selfCosetsB, cMulSelf)
selfContribsC = findContribs(selfCosetsC, cMulSelf)
selfContribsD = findContribs(selfCosetsD, cMulSelf)
otherContribsA = findContribs(otherCosetsA, cMulOther)
otherContribsB = findContribs(otherCosetsB, cMulOther)
otherContribsC = findContribs(otherCosetsC, cMulOther)
otherContribsD = findContribs(otherCosetsD, cMulOther)
#Remark: This is rather slow when self is large
#TODO: Would like a better approach to this
def minContrib(separation, selfContribs, otherContribs):
return min((selfContribs[coset] + otherContribs[coset + separation] for coset in selfContribs if coset + separation in otherContribs), default = math.inf)
for separationCoset in collisionSeparationCosets:
minT = min(minContrib(separationCoset.rep, selfContribsA, otherContribsB),
minContrib(separationCoset.rep, selfContribsB, otherContribsA),
minContrib(separationCoset.rep, selfContribsC, otherContribsD),
minContrib(separationCoset.rep, selfContribsD, otherContribsC)) - (separationCoset.rep * cMulOther)[0,0]
yield [CosetMatrix(Matrix([[minT,0,0]]), self.periodLattice), CosetMatrix(Matrix([[minT,0,0]]) + separationCoset.rep, other.periodLattice)]
#Enumerate interactions between two objects with the same velocity
#NOTE: This is less size-dependent
def enumerateInteractionSeparations(self, other):
separationLattice = self.periodLattice + other.periodLattice
separationGroup = QuotientGroup(cellLattice, separationLattice)
#Wrapping our envelopes first is probably more efficient
prewrapSelfA = self.envelopeA.wrapToQuotientFunction(separationGroup, -1)
prewrapSelfB = self.envelopeB.wrapToQuotientFunction(separationGroup, -1)
prewrapSelfC = self.envelopeC.wrapToQuotientFunction(separationGroup, -1)
prewrapSelfD = self.envelopeD.wrapToQuotientFunction(separationGroup, -1)
prewrapOtherA = other.envelopeA.wrapToQuotientFunction(separationGroup, 1)
prewrapOtherB = other.envelopeB.wrapToQuotientFunction(separationGroup, 1)
prewrapOtherC = other.envelopeC.wrapToQuotientFunction(separationGroup, 1)
prewrapOtherD = other.envelopeD.wrapToQuotientFunction(separationGroup, 1)
collisionSeparationCosets = set(prewrapSelfA.convolve(prewrapOtherB).data) | set(prewrapSelfB.convolve(prewrapOtherA).data) | set(prewrapSelfC.convolve(prewrapOtherD).data) | set(prewrapSelfD.convolve(prewrapOtherC).data)
return [[CosetMatrix(Matrix([[0,0,0]]), self.periodLattice), CosetMatrix(coset.rep, other.periodLattice)] for coset in collisionSeparationCosets]
#TODO: Could make a faster method for self-interactions, since half of the convolutions aren't really required
#Multiple patterns with the same period, with compatible inputs and outputs linked
class CompoundPattern:
def __init__(self, componentsWithPositions, name = ""):
#Members are of the form (component, position)
self.componentsWithPositions = componentsWithPositions
self.periodVector = componentsWithPositions[0][0].periodVector
self.periodLattice = componentsWithPositions[0][0].periodLattice
self.dT = int(self.periodVector[0,0])
self.dX = -int(self.periodVector[0,1])
self.dY = -int(self.periodVector[0,2])
#Figure out all inputs and outputs
self.inputDict = {}
for inputComponent, inputComponentName, inputComponentPosition in self.componentsWithPositions:
for inputPattern, inputName, inputTime, inputPosition in inputComponent.inputs:
if not inputPattern in self.inputDict:
self.inputDict[inputPattern] = {}
combinedLattice = inputPattern.periodLattice + self.periodLattice
#What lane is our input on
inputPositionInCompound = inputPosition + inputComponentPosition.rep - Matrix([[inputTime,0,0]])
inputLane = CosetMatrix(inputPositionInCompound.rep, combinedLattice)
if not inputLane in self.inputDict[inputPattern]:
self.inputDict[inputPattern][inputLane] = []
#Our input time and position in the larger compound pattern
inputTimeInCompoundPattern = mod(inputTime - int(inputComponentPosition.rep[0,0]), self.dT)
inputSpacing = ((inputTime - int(inputComponentPosition.rep[0,0])) - inputTimeInCompoundPattern) // self.dT
inputPositionInCompoundPattern = inputPosition.rep + inputComponentPosition.rep + Matrix([[inputTimeInCompoundPattern - inputTime,0,0]]) + self.periodVector * inputSpacing
self.inputDict[inputPattern][inputLane].append((inputTimeInCompoundPattern, inputPositionInCompoundPattern, inputComponentName+"."+inputName))
self.outputDict = {}
for outputComponent, outputComponentName, outputComponentPosition in self.componentsWithPositions:
for outputPattern, outputName, outputTime, outputPosition in outputComponent.outputs:
if not outputPattern in self.outputDict:
self.outputDict[outputPattern] = {}
combinedLattice = outputPattern.periodLattice + self.periodLattice
#What lane is our output on
outputPositionInCompound = outputPosition + outputComponentPosition.rep - Matrix([[outputTime,0,0]])
outputLane = CosetMatrix(outputPositionInCompound.rep, combinedLattice)
if not outputLane in self.outputDict[outputPattern]:
self.outputDict[outputPattern][outputLane] = []
#Our output time and position in the larger compound pattern
outputTimeInCompoundPattern = mod(outputTime - int(outputComponentPosition.rep[0,0]), self.dT)
outputSpacing = ((outputTime - int(outputComponentPosition.rep[0,0])) - outputTimeInCompoundPattern) // self.dT
outputPositionInCompoundPattern = outputPosition.rep + outputComponentPosition.rep + Matrix([[outputTimeInCompoundPattern - outputTime,0,0]]) + self.periodVector * outputSpacing
self.outputDict[outputPattern][outputLane].append((outputTimeInCompoundPattern, outputPositionInCompoundPattern, outputComponentName+"."+outputName))
#Whole pattern's inputs and outputs
#In same format as PeriodicPattern, to allow for nesting
self.inputs = []
self.outputs = []
self.linkages = []
#Input/output index registration with names
self.name = name
self.inputNamesToIndexes = {}
self.outputNamesToIndexes = {}
def registerInput(inputTimeInCompoundPattern, pattern, inputPositionInCompoundPattern, inputName):
self.inputNamesToIndexes[inputName] = len(self.inputs)
self.inputs.append((pattern, inputName, inputTimeInCompoundPattern, CosetMatrix(inputPositionInCompoundPattern, pattern.periodLattice)))
def registerOutput(outputTimeInCompoundPattern, pattern, outputPositionInCompoundPattern, outputName):
self.outputNamesToIndexes[outputName] = len(self.outputs)
self.outputs.append((pattern, outputName, outputTimeInCompoundPattern, CosetMatrix(outputPositionInCompoundPattern, pattern.periodLattice)))
#Figure out compatible input-output pairs and combine 'em
for pattern in self.inputDict:
if pattern in self.outputDict:
combinedLatticeChangeOfBasis = self.periodVector.blockVertical(pattern.periodVector).rightInverse()
for lane in self.inputDict[pattern]:
if lane in self.outputDict[pattern]:
#Positivity/spacing checks on pairs in the same lane
inputsMinPositiveDisplacements = [(math.inf, -1) for i in range(len(self.inputDict[pattern][lane]))]
outputsMinPositiveDisplacements = [(math.inf, -1) for j in range(len(self.outputDict[pattern][lane]))]
for i in range(len(self.inputDict[pattern][lane])):
inputTimeInCompoundPattern, inputPositionInCompoundPattern, inputName = self.inputDict[pattern][lane][i]
for j in range(len(self.outputDict[pattern][lane])):
outputTimeInCompoundPattern, outputPositionInCompoundPattern, outputName = self.outputDict[pattern][lane][j]
inputPos = inputPositionInCompoundPattern + Matrix([[inputTimeInCompoundPattern,0,0]])
outputPos = outputPositionInCompoundPattern + Matrix([[outputTimeInCompoundPattern,0,0]])
#This is incredibly scuffed and probably incorrect
#TODO: Yeah this is definitely incorrect
displacement = int((inputPos - outputPos)[0,0]) + int(((inputPos - outputPos) * combinedLatticeChangeOfBasis)[0,0]) * self.dT
if displacement >= 0 or True:
#Link up if these are an improvement
if displacement < inputsMinPositiveDisplacements[i][0]:
inputsMinPositiveDisplacements[i] = (displacement, j)
if displacement < outputsMinPositiveDisplacements[j][0]:
outputsMinPositiveDisplacements[j] = (displacement, i)
unboundInputs = set(range(len(self.inputDict[pattern][lane])))
unboundOutputs = set(range(len(self.outputDict[pattern][lane])))
#Register linkages for closest compatible pairs
for i in range(len(self.inputDict[pattern][lane])):
j = inputsMinPositiveDisplacements[i][1]
if j != -1 and outputsMinPositiveDisplacements[j][1] == i:
#i,j is a closest compatible pair
unboundInputs.remove(i)
unboundOutputs.remove(j)
inputTimeInCompoundPattern, inputPositionInCompoundPattern, inputName = self.inputDict[pattern][lane][i]
outputTimeInCompoundPattern, outputPositionInCompoundPattern, outputName = self.outputDict[pattern][lane][j]
self.linkages.append((pattern, inputTimeInCompoundPattern, inputPositionInCompoundPattern, outputTimeInCompoundPattern, outputPositionInCompoundPattern))
#Register unbound inputs and outputs
for i in unboundInputs:
inputTimeInCompoundPattern, inputPositionInCompoundPattern, inputName = self.inputDict[pattern][lane][i]
registerInput(inputTimeInCompoundPattern, pattern, inputPositionInCompoundPattern, inputName)
for j in unboundOutputs:
outputTimeInCompoundPattern, outputPositionInCompoundPattern, outputName = self.outputDict[pattern][lane][j]
registerOutput(outputTimeInCompoundPattern, pattern, outputPositionInCompoundPattern, outputName)
else:
for inputTimeInCompoundPattern, inputPositionInCompoundPattern, inputName in self.inputDict[pattern][lane]:
registerInput(inputTimeInCompoundPattern, pattern, inputPositionInCompoundPattern, inputName)
for lane in self.outputDict[pattern]:
if not lane in self.inputDict[pattern]:
for outputTimeInCompoundPattern, outputPositionInCompoundPattern, outputName in self.outputDict[pattern][lane]:
registerOutput(outputTimeInCompoundPattern, pattern, outputPositionInCompoundPattern, outputName)
else:
for lane in self.inputDict[pattern]:
for inputTimeInCompoundPattern, inputPositionInCompoundPattern, inputName in self.inputDict[pattern][lane]:
registerInput(inputTimeInCompoundPattern, pattern, inputPositionInCompoundPattern, inputName)
for pattern in self.outputDict:
if not pattern in self.inputDict:
for lane in self.outputDict[pattern]:
for outputTimeInCompoundPattern, outputPositionInCompoundPattern, outputName in self.outputDict[pattern][lane]:
registerOutput(outputTimeInCompoundPattern, pattern, outputPositionInCompoundPattern, outputName)
def place(self, position, mode = "or"):
#Place in all components
for component, componentName, componentPosition in self.componentsWithPositions:
component.place(position + componentPosition, mode)
#Place in all linkages
stateT = int(position.rep[0,0])
for pattern, inputTimeInCompoundPattern, inputPositionInCompoundPattern, outputTimeInCompoundPattern, outputPositionInCompoundPattern in self.linkages:
#TODO: These are wrong
inputIndexOffset = (1,0)[inputTimeInCompoundPattern >= stateT]
outputIndexOffset = (0,1)[outputTimeInCompoundPattern <= stateT]
#g.warn(str(inputTimeInCompoundPattern) +", "+str(outputTimeInCompoundPattern) +", "+str(stateT)+"\n\n"+str(inputIndexOffset) + ", "+str(outputIndexOffset))
inputBasePos = inputPositionInCompoundPattern + position.rep - Matrix([[inputTimeInCompoundPattern, 0, 0]])
outputBasePos = outputPositionInCompoundPattern + position.rep - Matrix([[outputTimeInCompoundPattern, 0, 0]])
combinedLatticeChangeOfBasis = self.periodVector.blockVertical(pattern.periodVector).rightInverse()
for index in range(inputIndexOffset, outputIndexOffset + int(((inputBasePos - outputBasePos) * combinedLatticeChangeOfBasis)[0,0])):
pattern.place(CosetMatrix(inputBasePos - Matrix([[self.dT, -self.dX, -self.dY]]) * index, pattern.periodLattice), mode)
def placeInput(self, position, index, mode = "or"):
stateT = int(position.rep[0,0])
for inputPattern, inputName, inputTimeToAdd, inputPosition in self.inputs:
indexToUse = index + (1,0)[inputTimeToAdd >= stateT]
inputPattern.place(inputPosition + (position.rep + Matrix([[-inputTimeToAdd, 0, 0]]) - Matrix([[self.dT, -self.dX, -self.dY]]) * indexToUse), mode)
def placeOutput(self, position, index, mode = "or"):
stateT = int(position.rep[0,0])
for outputPattern, outputName, outputTimeToRemove, outputPosition in self.outputs:
indexToUse = index + (1,0)[outputTimeToRemove <= stateT]
outputPattern.place(outputPosition + (position.rep + Matrix([[-outputTimeToRemove, 0, 0]]) + Matrix([[self.dT, -self.dX, -self.dY]]) * indexToUse), mode)
#Place with inputs (and outputs)
def placeWithInputs(self, position, numInputs = 0, numOutputs = 0, mode = "or"):
self.place(position, mode)
for i in range(0,numInputs):
self.placeInput(position, i, mode)
for i in range(0,numOutputs):
self.placeOutput(position, i, mode)
#Find the minimal offset displacement of pat2 linking an output in one PeriodicPattern (or CompoundPattern) to an input in another
# Plus extraSpacing steps worth of space
def findOffset(pat1, pat1OutputIndex, pat2, pat2InputIndex, extraSpacing = 0):
outputPattern, outputName, outputTimeToRemove, outputPosition = pat1.outputs[pat1OutputIndex]
inputPattern, inputName, inputTimeToAdd, inputPosition = pat2.inputs[pat2InputIndex]
if outputPattern != inputPattern:
g.warn("Pattern mismatch!")
#Want to add and remove in the same generation
return CosetMatrix(Matrix([[inputTimeToAdd - outputTimeToRemove,0,0]]) + outputPosition.rep - inputPosition.rep - outputPattern.periodVector * extraSpacing, pat1.periodLattice)
#A chain with certain spacings
def chain(patternInputOutputSpacingInfo):
periodLattice = patternInputOutputSpacingInfo[0][0].periodLattice
cumulativeOffset = CosetMatrix(Matrix.zero(1,3), periodLattice)
componentsWithPositions = [(patternInputOutputSpacingInfo[0][0], patternInputOutputSpacingInfo[0][1], cumulativeOffset)]
for i in range(len(patternInputOutputSpacingInfo) - 1):
outputComponent, _, _, outputComponentOutputName, _ = patternInputOutputSpacingInfo[i]
inputComponent, inputComponentName, inputComponentInputName, _, extraSpacing = patternInputOutputSpacingInfo[i+1]
outputComponentOutputIndex = outputComponent.outputNamesToIndexes[outputComponentOutputName]
inputComponentInputIndex = inputComponent.inputNamesToIndexes[inputComponentInputName]
addedOffset = CompoundPattern.findOffset(outputComponent, outputComponentOutputIndex, inputComponent, inputComponentInputIndex, extraSpacing)
cumulativeOffset += addedOffset
componentsWithPositions.append((inputComponent, inputComponentName, cumulativeOffset))
return CompoundPattern(componentsWithPositions)
#Automatically add in a collection of components with compatible spacings with certain inputs/outputs to form a loop
def addCompatibleComponents(self, componentsToAddData, selfName = "Main"):
newCompoundPatternComponents = [(self, selfName, CosetMatrix(Matrix.zero(1,3), self.periodLattice))]
for component, componentName, componentInputIndicesToSelfOutputIndices, componentOutputIndicesToSelfInputIndices in componentsToAddData:
#Get constraints
baseOffsets = []
stepDisplacements = []
#We expect exactly 2 of these constraints in total
for componentInputName, selfOutputName in componentInputIndicesToSelfOutputIndices.items():
componentInputIndex = component.inputNamesToIndexes[componentInputName]
selfOutputIndex = self.outputNamesToIndexes[selfOutputName]
baseOffsets.append(CompoundPattern.findOffset(self, selfOutputIndex, component, componentInputIndex).rep)
stepDisplacements.append(component.inputs[componentInputIndex][0].periodVector)
for componentOutputName, selfInputName in componentOutputIndicesToSelfInputIndices.items():
componentOutputIndex = component.outputNamesToIndexes[componentOutputName]
selfInputIndex = self.inputNamesToIndexes[selfInputName]
baseOffsets.append(-CompoundPattern.findOffset(component, componentOutputIndex, self, selfInputIndex).rep)
stepDisplacements.append(component.outputs[componentOutputIndex][0].periodVector)
#Our position must be, for all i, of the form v = baseOffsets[i] + n_i * stepDisplacements[i] + m_i * self.periodVector
# In particular, have 0 = baseOffsets[0] - baseOffsets[1] + n_0 * stepDisplacements[0] - n_1 * stepDisplacements[1] + (m_0-m_1)*self.periodVector
# baseOffsets[1] - baseOffsets[0] = Matrix([[n_0,-n_1,m_0-m_1]]) * BlockVertical(stepDisplacements[0], stepDisplacements[1], self.periodVector)
# (baseOffsets[1] - baseOffsets[0]) * blockMatrixInverse = Matrix([[n_0,-n_1,m_0-m_1]])
# ((baseOffsets[1] - baseOffsets[0]) * blockMatrixInverse.col(0))[0,0] = n_0
n0 = ((baseOffsets[1] - baseOffsets[0]) * stepDisplacements[0].blockVertical(stepDisplacements[1]).blockVertical(self.periodVector).inverse().col(0))[0,0]
v = baseOffsets[0] + stepDisplacements[0] * n0
newCompoundPatternComponents.append((component, componentName, CosetMatrix(v, component.periodLattice)))
return CompoundPattern(newCompoundPatternComponents)
#Settings
g.new("13131")
g.setrule("B3/S23")
g.setalgo("HashLife")
#Basic objects
block = PeriodicPattern(g.parse("2o$2o!",0,0), 1, 0, 0)
blinker = PeriodicPattern(g.parse("3o!",-1,0), 2, 0, 0)
SWGlider = PeriodicPattern(g.parse("bo$o$3o!",0,0), 4, -1, 1)
NWGlider = PeriodicPattern(g.parse("2o$obo$o!",0,0), 4, -1, -1)
NEGlider = PeriodicPattern(g.parse("3o$2bo$bo!",0,0), 4, 1, -1)
NLWSS = PeriodicPattern(g.parse("3o$o2bo$o$o$bobo!",0,0), 4, 0, -2)
NMWSS = PeriodicPattern(g.parse("3o$o2bo$o$o3bo$o$bobo!",0,0), 4, 0, -2)
NHWSS = PeriodicPattern(g.parse("3o$o2bo$o$o3bo$o3bo$o$bobo!",0,0), 4, 0, -2)
WLWSS = PeriodicPattern(g.parse("bo2bo$o$o3bo$4o!",0,0), 4, -2, 0)
'''
#Helix components
helixComponent1 = PeriodicPattern([],31*16,-1*16,-13*16,
[(NEGlider,"NEGlider0",0,CosetMatrix(Matrix([[0,0,4]]), NEGlider.periodLattice)),
(NLWSS,"NLWSS0",0,CosetMatrix(Matrix([[1,5,1]]), NLWSS.periodLattice)),
(NHWSS,"NHWSS0",8,CosetMatrix(Matrix([[2,12,-1]]), NHWSS.periodLattice))],
[(NEGlider,"NEGlider1",17,CosetMatrix(Matrix([[1,12,-5]]), NEGlider.periodLattice))])
helixComponent2 = PeriodicPattern([],31*16,-1*16,-13*16,
[(NEGlider,"NEGlider0",0,CosetMatrix(Matrix([[3,-1,1]]), NEGlider.periodLattice)),
(NLWSS,"NLWSS0",0,CosetMatrix(Matrix([[1,4,2]]), NLWSS.periodLattice)),
(NLWSS,"NLWSS1",10,CosetMatrix(Matrix([[3,2,7]]), NLWSS.periodLattice))],
[(NWGlider,"NWGlider0",19,CosetMatrix(Matrix([[0,-2,1]]), NWGlider.periodLattice))])
helixComponent3 = PeriodicPattern([],31*16,-1*16,-13*16,
[(NWGlider,"NWGlider0",0,CosetMatrix(Matrix([[2,13,4]]), NWGlider.periodLattice)),
(NLWSS,"NLWSS0",0,CosetMatrix(Matrix([[3,7,2]]), NLWSS.periodLattice)),
(NHWSS,"NHWSS0",8,CosetMatrix(Matrix([[0,0,-2]]), NHWSS.periodLattice))],
[(NWGlider,"NWGlider1",17,CosetMatrix(Matrix([[3,1,-5]]), NWGlider.periodLattice))])
helixComponent4 = PeriodicPattern([],31*16,-1*16,-13*16,
[(NWGlider,"NWGlider0",0,CosetMatrix(Matrix([[0,9,5]]), NWGlider.periodLattice)),
(NHWSS,"NHWSS0",0,CosetMatrix(Matrix([[0,3,0]]), NHWSS.periodLattice)),
(NHWSS,"NHWSS1",7,CosetMatrix(Matrix([[0,9,8]]), NHWSS.periodLattice)),
(NLWSS,"NLWSS0",23,CosetMatrix(Matrix([[2,0,4]]), NLWSS.periodLattice)),
(NLWSS,"NLWSS1",40,CosetMatrix(Matrix([[2,4,3]]), NLWSS.periodLattice))],
[(NEGlider,"NEGlider0",29,CosetMatrix(Matrix([[3,6,-6]]), NEGlider.periodLattice)),
(NWGlider,"NWGlider1",39,CosetMatrix(Matrix([[1,-3,-4]]), NWGlider.periodLattice))])
#TODO: Replace indices with names
helixSpacings = [
(helixComponent1,"H0","","NEGlider1",2),
(helixComponent1,"H1","NEGlider0","NEGlider1",2),
(helixComponent1,"H2","NEGlider0","NEGlider1",2),
(helixComponent1,"H3","NEGlider0","NEGlider1",2),
(helixComponent1,"H4","NEGlider0","NEGlider1",2),
(helixComponent1,"H5","NEGlider0","NEGlider1",2),
(helixComponent1,"H6","NEGlider0","NEGlider1",2),
(helixComponent1,"H7","NEGlider0","NEGlider1",2),
(helixComponent2,"H8","NEGlider0","NWGlider0",2),
(helixComponent3,"H9","NWGlider0","NWGlider1",0),
(helixComponent3,"H10","NWGlider0","NWGlider1",2),
(helixComponent3,"H11","NWGlider0","NWGlider1",2),
(helixComponent3,"H12","NWGlider0","NWGlider1",2),
(helixComponent3,"H13","NWGlider0","NWGlider1",2),
(helixComponent3,"H14","NWGlider0","NWGlider1",2),
(helixComponent3,"H15","NWGlider0","NWGlider1",2),
(helixComponent3,"H16","NWGlider0","NWGlider1",2),
(helixComponent3,"H17","NWGlider0","NWGlider1",2),
(helixComponent4,"H18","NWGlider0","NEGlider0",6),
]
helix = CompoundPattern.chain(helixSpacings)
#helix.placeWithInputs(CosetMatrix(Matrix([[0,0,0]]), helix.periodLattice), 20, 20)
#Fanout components
#TODO: Would be nice to figure these input/output values automatically
fanoutComponent1 = PeriodicPattern([],31*16,-1*16,-13*16,
[(NWGlider,"NWGlider0",0,CosetMatrix(Matrix([[1,1,0]]), NWGlider.periodLattice)),
(NLWSS,"NLWSS0",0,CosetMatrix(Matrix([[3,-5,0]]), NLWSS.periodLattice)),
(NLWSS,"NLWSS1",15,CosetMatrix(Matrix([[1,0,5]]), NLWSS.periodLattice)),
(NLWSS,"NLWSS2",16,CosetMatrix(Matrix([[2,6,4]]), NLWSS.periodLattice))],
[(blinker,"Blinker0",28,CosetMatrix(Matrix([[0,4,7]]), blinker.periodLattice)),
(WLWSS,"WLWSS0",29,CosetMatrix(Matrix([[-1,-7,-3]]), WLWSS.periodLattice))])
fanoutComponent2 = PeriodicPattern([],31*16,-1*16,-13*16,
[(blinker,"Blinker0",0,CosetMatrix(Matrix([[1,2,1]]), blinker.periodLattice)),
(NLWSS,"NLWSS0",0,CosetMatrix(Matrix([[1,2,4]]), NLWSS.periodLattice)),
(NLWSS,"NLWSS1",13,CosetMatrix(Matrix([[0,0,6]]), NLWSS.periodLattice))],
[(NWGlider,"NWGlider0",10,CosetMatrix(Matrix([[-1,1,-2]]), NWGlider.periodLattice))])
fanoutComponent3 = PeriodicPattern([],31*16,-1*16,-13*16,
[(NWGlider,"NWGlider0",0,CosetMatrix(Matrix([[2,7,5]]), NWGlider.periodLattice)),
(NHWSS,"NHWSS0",0,CosetMatrix(Matrix([[0,0,0]]), NHWSS.periodLattice)),
(NMWSS,"NMWSS0",10,CosetMatrix(Matrix([[2,9,9]]), NMWSS.periodLattice))],
[(NWGlider,"NWGlider1",26,CosetMatrix(Matrix([[0,2,-5]]), NWGlider.periodLattice))])
fanoutComponent4 = PeriodicPattern([],31*16,-1*16,-13*16,
[(NWGlider,"NWGlider0",0,CosetMatrix(Matrix([[2,5,0]]), NWGlider.periodLattice)),
(NLWSS,"NLWSS0",0,CosetMatrix(Matrix([[0,6,4]]), NLWSS.periodLattice)),
(NLWSS,"NLWSS1",16,CosetMatrix(Matrix([[3,0,7]]), NLWSS.periodLattice))],
[(blinker,"Blinker0",18,CosetMatrix(Matrix([[1,8,5]]), blinker.periodLattice)),
(NWGlider,"NWGlider1",20,CosetMatrix(Matrix([[3,1,4]]), NWGlider.periodLattice))])
fanoutComponent5 = PeriodicPattern([],31*16,-1*16,-13*16,
[(blinker,"Blinker0",0,CosetMatrix(Matrix([[0,1,0]]), blinker.periodLattice)),
(NLWSS,"NLWSS0",0,CosetMatrix(Matrix([[0,3,2]]), NLWSS.periodLattice)),
(NLWSS,"NLWSS0",9,CosetMatrix(Matrix([[3,7,6]]), NLWSS.periodLattice))],
[(NWGlider,"NWGlider0",23,CosetMatrix(Matrix([[2,6,1]]), NWGlider.periodLattice))])
fanoutComponent6 = PeriodicPattern([],31*16,-1*16,-13*16,
[(blinker,"Blinker0",0,CosetMatrix(Matrix([[0,1,2]]), blinker.periodLattice)),
(NLWSS,"NLWSS0",0,CosetMatrix(Matrix([[1,5,1]]), NLWSS.periodLattice)),
(NMWSS,"NMWSS0",25,CosetMatrix(Matrix([[3,9,3]]), NMWSS.periodLattice))],
[(NWGlider,"NWGlider0",37,CosetMatrix(Matrix([[1,5,-3]]), NWGlider.periodLattice))])
#Extra fanout components for the last track builder (slightly cheaper)
fanoutComponent7 = PeriodicPattern([],31*16,-1*16,-13*16,
[(NWGlider,"NWGlider0",0,CosetMatrix(Matrix([[1,4,0]]), NWGlider.periodLattice)),
(NLWSS,"NLWSS0",0,CosetMatrix(Matrix([[2,6,5]]), NLWSS.periodLattice)),
(NLWSS,"NLWSS1",2,CosetMatrix(Matrix([[2,0,4]]), NLWSS.periodLattice))],
[(blinker,"Blinker0",16,CosetMatrix(Matrix([[1,4,1]]), blinker.periodLattice)),
(NWGlider,"NWGlider1",17,CosetMatrix(Matrix([[1,-1,0]]), NWGlider.periodLattice))])
fanoutComponent8 = PeriodicPattern([],31*16,-1*16,-13*16,
[(blinker,"Blinker0",0,CosetMatrix(Matrix([[0,5,0]]), blinker.periodLattice)),
(NLWSS,"NLWSS0",0,CosetMatrix(Matrix([[2,8,2]]), NLWSS.periodLattice)),
(NLWSS,"NLWSS1",7,CosetMatrix(Matrix([[2,0,3]]), NLWSS.periodLattice))],
[(NWGlider,"NWGlider0",14,CosetMatrix(Matrix([[2,3,2]]), NWGlider.periodLattice))])
trackPairBuilderCollision1 = PeriodicPattern([],31*16,-1*16,-13*16,
[(WLWSS,"WLWSS0",0,CosetMatrix(Matrix([[1,1,-1]]), WLWSS.periodLattice)),
(NWGlider,"NWGlider0",0,CosetMatrix(Matrix([[2,3,5]]), NWGlider.periodLattice)),
(NWGlider,"NWGlider1",79,CosetMatrix(Matrix([[1,6,6]]), NWGlider.periodLattice))],
[(block,"Block0",8,CosetMatrix(Matrix([[0,-3,0]]), block.periodLattice)),
(block,"Block1",85,CosetMatrix(Matrix([[0,2,5]]), block.periodLattice))])
#TODO: Want to be able to 'complete a cycle with available components' when possible
#TODO: Want a slightly different last fanout
# First fanout should have different starting displacement, connect to helix
# Last fanout should not produce 'fanout continuation glider': It's cheaper to use an extra LWSS for period multiplication instead
# In fact, could potentially be even cheaper if we instead fan out into two gliders which support our climbers directly!
def fanoutPatSpacingInfo(n,dn, i, isFirstFanout = False, isLastFanout = False):
startSpacing = 207 + (dn-2)*192 - n * 16
if isFirstFanout:
startSpacing = 38 + n * 16
return [
(fanoutComponent1,"F1,"+str(i),"NWGlider0","Blinker0",startSpacing),
(fanoutComponent2,"F2,"+str(i),"Blinker0","NWGlider0",1 + n*24),
(fanoutComponent3,"F3,"+str(i),"NWGlider0","NWGlider1",50 + n*16),
(fanoutComponent4,"F4,"+str(i),"NWGlider0","Blinker0",47),
(fanoutComponent5,"F5,"+str(i),"Blinker0","NWGlider0",10),
(fanoutComponent4,"F6,"+str(i),"NWGlider0","Blinker0",94),
(fanoutComponent6,"F7,"+str(i),"Blinker0","NWGlider0",10),
]
fanoutDeviceSpacingsList = [3]
for i in range(15-1):
#15/12 is probably not the exact optimal value but it's fine
newN = int(math.ceil(fanoutDeviceSpacingsList[0] * 7 / 6 + 15/12))
fanoutDeviceSpacingsList.insert(0,newN)
fanoutPatSpacings = [(helix,"Helix","","H18.NWGlider1",0)]
for i in range(len(fanoutDeviceSpacingsList)):
if i == 0:
fanoutPatSpacings += fanoutPatSpacingInfo(fanoutDeviceSpacingsList[i], 0, i, True)
else:
fanoutPatSpacings += fanoutPatSpacingInfo(fanoutDeviceSpacingsList[i], fanoutDeviceSpacingsList[i-1] - fanoutDeviceSpacingsList[i], i, False)
#Cheaper last fanout
fanoutPatSpacings += [(fanoutComponent7,"F1,16","NWGlider0","Blinker0",68),(fanoutComponent8,"F2,16","Blinker0","NWGlider0",26)]
fanoutTrackPairBuilderConnections = [(trackPairBuilderCollision1, "T"+str(i), {"WLWSS0":"F1,"+str(i)+".WLWSS0", "NWGlider0":"F4,"+str(i)+".NWGlider1"}, {}) for i in range(15)]
periodDemultiplierCrawlerBlockInputs = [(block, "Block"+str(i), 31*i, CosetMatrix(Matrix([[0,6,-2]]) + Matrix([[0,-1,-13]])*i, block.periodLattice)) for i in range(15)]
periodDemultiplierCrawlerGliderOutputs = [(SWGlider, "SWGlider"+str(i), 22+31*i, CosetMatrix(Matrix([[1,0,3]]) + Matrix([[0,-1,-13]])*i, SWGlider.periodLattice)) for i in range(16)]
periodDemultiplierCrawler = PeriodicPattern(g.parse("2b3o$2bo2bo$bo$4b2o$o3b2o$o$2bo$2b3o$3b2o$4bo$2b2o$bobo$o3bo$2b2o!"),31*16,-1*16,-13*16,
periodDemultiplierCrawlerBlockInputs + [(NWGlider, "NWGlider0", 31*15, CosetMatrix(Matrix([[1,7,-2]]) + Matrix([[0,-1,-13]])*15, NWGlider.periodLattice))],
periodDemultiplierCrawlerGliderOutputs)
periodDemultiplierConnections = [(periodDemultiplierCrawler, "Demultiplier0", {"NWGlider0":"Main.F1,16.NWGlider1","Block0":"T0.Block0"}, {}),
(periodDemultiplierCrawler, "Demultiplier1", {"NWGlider0":"Main.F2,16.NWGlider0","Block0":"T0.Block1"}, {})]
fanoutDevice = CompoundPattern.chain(fanoutPatSpacings).addCompatibleComponents(fanoutTrackPairBuilderConnections).addCompatibleComponents(periodDemultiplierConnections)
#g.warn(str(set(fanoutDevice.outputNamesToIndexes)))
#fanoutDevice.placeWithInputs(CosetMatrix(Matrix([[0,0,0]]), fanoutDevice.periodLattice), 320, 3)
'''
#Crawlers on various objects
#TODO: May want to period-multiply periodic or compound patterns by 16
crawlerSWGliders = [0,0,0]
crawlerSWGliders[0] = PeriodicPattern(g.parse("2b3o$bo2bo$o$b3o3$4b2o$4b2o$5bo$5b2o$b3obob2o$b2o$5bo2bo$5b3o!"), 31, -1, -13,
[(SWGlider,"SWGlider0",24,CosetMatrix(Matrix([[0,6,-14]]), SWGlider.periodLattice))],
[(SWGlider,"SWGlider0",15,CosetMatrix(Matrix([[1,1,4]]), SWGlider.periodLattice))])
crawlerSWGliders[1] = PeriodicPattern(g.parse("2b3o$bo2bo$o$b3o3$4b2o$4b2o$5bo$5b2o$b3obob2o$b2o$5bo2bo$5b3o!"), 31, -1, -13,
[(SWGlider,"SWGlider0",24,CosetMatrix(Matrix([[0,6,-15]]), SWGlider.periodLattice))],
[(SWGlider,"SWGlider0",15,CosetMatrix(Matrix([[1,1,4]]), SWGlider.periodLattice))])
crawlerSWGliders[2] = PeriodicPattern(g.parse("2b3o$bo2bo$o$b3o3$4b2o$4b2o$5bo$5b2o$b3obob2o$b2o$5bo2bo$5b3o!"), 31, -1, -13,
[(SWGlider,"SWGlider0",24,CosetMatrix(Matrix([[1,6,-15]]), SWGlider.periodLattice))],
[(SWGlider,"SWGlider0",15,CosetMatrix(Matrix([[1,1,4]]), SWGlider.periodLattice))])
crawlerNWGliders = PeriodicPattern(g.parse("2b3o$bo2bo$o$b3o3$4b2o$4b2o$5bo$5b2o$b3obob2o$b2o$5bo2bo$5b3o!"), 31, -1, -13,
[(NWGlider,"NWGlider0",24,CosetMatrix(Matrix([[1,7,-14]]), NWGlider.periodLattice))],
[(SWGlider,"SWGlider0",15,CosetMatrix(Matrix([[1,1,4]]), SWGlider.periodLattice))])
crawlerBlocks = PeriodicPattern(g.parse("2b3o$bo2bo$o$b3o3$4b2o$4b2o$5bo$5b2o$b3obob2o$b2o$5bo2bo$5b3o!"), 31, -1, -13,
[(block,"Block0",24,CosetMatrix(Matrix([[0,6,-14]]), block.periodLattice))],
[(SWGlider,"SWGlider0",15,CosetMatrix(Matrix([[1,1,4]]), SWGlider.periodLattice))])
SWGliderStreamLattice = crawlerSWGliders[0].periodLattice + SWGlider.periodLattice
SWGliderStreamLaneChangeOfBasis = -Matrix([x.terms[0] for x,y in Lattice(Matrix.id(3)).quotientGeneratorsWithTorsions(SWGliderStreamLattice)]).inverse().col(2)
#The lane shift a SW glider -> SW glider crawler shifts a glider trail by
crawlerGliderLattice = SWGlider.periodLattice + crawlerSWGliders[0].periodLattice
def getGliderShift(pattern, inputIndex = 0, outputIndex = 0):
inputLane = CosetMatrix((pattern.inputs[inputIndex][3] - Matrix([[pattern.inputs[inputIndex][2],0,0]])).rep, crawlerGliderLattice)
outputLane = CosetMatrix((pattern.outputs[inputIndex][3] - Matrix([[pattern.outputs[inputIndex][2],0,0]])).rep, crawlerGliderLattice)
return outputLane - inputLane
gliderShifts = [int((getGliderShift(crawlerSWGliders[i]).rep * SWGliderStreamLaneChangeOfBasis)[0,0]) for i in range(3)] #[69,42,28]
blockLayerTrackDisplacementGoal = int(((Matrix([[0,-12,-12]]) - Matrix([[0,-15,6]])) * SWGliderStreamLaneChangeOfBasis)[0,0]) #237
#237 = 69 + 42*4
#TODO: Would like to figure out the optimal way to do this automatically
startingShiftSpacings = [(crawlerSWGliders[0],"C0","SWGlider0","SWGlider0",1),
(crawlerSWGliders[1],"C1","SWGlider0","SWGlider0",1),
(crawlerSWGliders[1],"C2","SWGlider0","SWGlider0",1),
(crawlerSWGliders[1],"C3","SWGlider0","SWGlider0",1),
(crawlerSWGliders[1],"C4","SWGlider0","SWGlider0",1)]
startingShifter = CompoundPattern.chain(startingShiftSpacings)
#startingShifter.placeWithInputs(CosetMatrix(Matrix([[0,0,0]]), startingShifter.periodLattice), 10, 10)
#TODO: All three pair-track blocklayers and all three pair-track rephasers (the latter can be compound patterns)
pairTrackBlockLayers = [0,0,0]
pairTrackBlockLayers[0] = PeriodicPattern(g.parse("2b3o$2bo2bo$bo$4b2o$o3b2o$o$2bo$2b3o$3b2o$4bo7b3o$2b2o8bo2bo$bobo6bo4bo$o3bo5bo$2b2o5b2o$10b2obo$12bo5$14b2o2$12bo2bo$11bo$11bo2bo$13bo!"),31,-1,-13,
[(SWGlider,"C0.SWGlider0",0,CosetMatrix(Matrix([[0,6,-2]]), SWGlider.periodLattice)),
(SWGlider,"C1.SWGlider0",20,CosetMatrix(Matrix([[0,16,-3]]), SWGlider.periodLattice))],
[(block,"Block0",2,CosetMatrix(Matrix([[0,11,23]]), block.periodLattice)),
(SWGlider,"C0.SWGlider0",22,CosetMatrix(Matrix([[1,0,3]]), SWGlider.periodLattice)),
(SWGlider,"C1.SWGlider0",11,CosetMatrix(Matrix([[1,11,15]]), SWGlider.periodLattice))])
pairTrackBlockLayers[1] = PeriodicPattern(g.parse("2b3o$2bo2bo$bo$4b2o$o3b2o$o$2bo$2b3o$3b2o$4bo7b3o$2b2o8bo2bo$bobo6bo4bo$o3bo5bo$2b2o5b2o$10b2obo$12bo5$14b2o2$12bo2bo$11bo$11bo2bo$13bo!"),31,-1,-13,
[(SWGlider,"C0.SWGlider0",0,CosetMatrix(Matrix([[0,6,-3]]), SWGlider.periodLattice)),
(SWGlider,"C1.SWGlider0",20,CosetMatrix(Matrix([[0,16,-4]]), SWGlider.periodLattice))],
[(block,"Block0",2,CosetMatrix(Matrix([[0,11,23]]), block.periodLattice)),
(SWGlider,"C0.SWGlider0",22,CosetMatrix(Matrix([[1,0,3]]), SWGlider.periodLattice)),
(SWGlider,"C1.SWGlider0",11,CosetMatrix(Matrix([[1,11,15]]), SWGlider.periodLattice))])
pairTrackBlockLayers[2] = PeriodicPattern(g.parse("2b3o$2bo2bo$bo$4b2o$o3b2o$o$2bo$2b3o$3b2o$4bo7b3o$2b2o8bo2bo$bobo6bo4bo$o3bo5bo$2b2o5b2o$10b2obo$12bo5$14b2o2$12bo2bo$11bo$11bo2bo$13bo!"),31,-1,-13,
[(SWGlider,"C0.SWGlider0",0,CosetMatrix(Matrix([[1,6,-3]]), SWGlider.periodLattice)),
(SWGlider,"C1.SWGlider0",20,CosetMatrix(Matrix([[1,16,-4]]), SWGlider.periodLattice))],
[(block,"Block0",2,CosetMatrix(Matrix([[0,11,23]]), block.periodLattice)),
(SWGlider,"C0.SWGlider0",22,CosetMatrix(Matrix([[1,0,3]]), SWGlider.periodLattice)),
(SWGlider,"C1.SWGlider0",11,CosetMatrix(Matrix([[1,11,15]]), SWGlider.periodLattice))])
pairTrackRephasers = [CompoundPattern([(crawlerSWGliders[i],"C0",CosetMatrix(Matrix([[0,0,0]]),crawlerSWGliders[i].periodLattice)),
(crawlerSWGliders[i],"C1",CosetMatrix(Matrix([[-16,11,-2]]),crawlerSWGliders[i].periodLattice))])
for i in range(3)]
#Block layer input for a NW rake
#Remark: The first of these should be able to be either pairTrackBlockLayer1, 2, or 3
blockLayersForNWRakeSpacings = [[(pairTrackBlockLayers[i],"BlockLayer0","C0.SWGlider0","C0.SWGlider0",4),
(pairTrackRephasers[0],"Rephaser0","C0.SWGlider0","C0.SWGlider0",4),
(pairTrackRephasers[0],"Rephaser1","C0.SWGlider0","C0.SWGlider0",1),
(pairTrackRephasers[0],"Rephaser2","C0.SWGlider0","C0.SWGlider0",1),
(pairTrackRephasers[0],"Rephaser3","C0.SWGlider0","C0.SWGlider0",1),
(pairTrackRephasers[0],"Rephaser4","C0.SWGlider0","C0.SWGlider0",1),
(pairTrackBlockLayers[0],"BlockLayer1","C0.SWGlider0","C0.SWGlider0",1),
(pairTrackBlockLayers[0],"BlockLayer2","C0.SWGlider0","C0.SWGlider0",4)] for i in range(3)]
blockLayersForNWRake = [CompoundPattern.chain(blockLayersForNWRakeSpacings[i]) for i in range(3)]
#NW rake from block input
NWRakeCore = PeriodicPattern(g.parse("2b3o$2bo2bo$bo$4b2o$o3b2o$o$2bo$2b3o$3b2o$4bo$2b2o$bobo$o3bo$2b2o5$9bo$9b2o$7bo2b2o$9b2o$7b3o$8bo8$11bo$10bobo4b2o$9b2o6b2o2$16bo$15bobo$15bobo$16b3o$16b3o$18bo$16b2o!")
,31,-1,-13,
[(block,"Block0",0,CosetMatrix(Matrix([[0,6,-2]]), block.periodLattice)),
(SWGlider,"SWGlider0",11,CosetMatrix(Matrix([[0,7,3]]), SWGlider.periodLattice)),
(block,"Block1",15,CosetMatrix(Matrix([[0,18,15]]), block.periodLattice))],
[(NWGlider,"NWGlider0",18,CosetMatrix(Matrix([[0,4,24]]), NWGlider.periodLattice))])
NWRakeFromBlocksSpacings = [(crawlerBlocks,"C0","Block0","SWGlider0",0),
(NWRakeCore,"R0","SWGlider0","NWGlider0",48)]
NWRakeFromBlocks = CompoundPattern.chain(NWRakeFromBlocksSpacings)
def NWRake(i, internalSpacing):
NWRakeSpacings = [(blockLayersForNWRake[i],"BlockLayer","BlockLayer0.C0.SWGlider0","BlockLayer0.Block0",0),
(NWRakeFromBlocks,"NWRakeFromBlocks","C0.Block0","R0.NWGlider0",internalSpacing+55)]
return CompoundPattern.chain(NWRakeSpacings)
#Component which converts a pair track into an easier-to-destroy single track
pairTrackToSingleTrackCore = PeriodicPattern(g.parse("2b3o$2bo2bo$bo$4b2o$o3b2o$o$2bo$2b3o$3b2o$4bo$2b2o$bobo$o3bo$2b2o!"), 31, -1, -13,
[(SWGlider,"SWGlider0",0,CosetMatrix(Matrix([[1,6,-3]]), SWGlider.periodLattice)),
(SWGlider,"SWGlider1",9,CosetMatrix(Matrix([[0,8,13]]), SWGlider.periodLattice))],
[(SWGlider,"SWGlider0",22,CosetMatrix(Matrix([[1,0,3]]), SWGlider.periodLattice))])
pairTrackToSingleTrackSpacings = [(crawlerSWGliders[0],"C0","SWGlider1","SWGlider0",1),
(crawlerSWGliders[0],"C1","SWGlider0","SWGlider0",1),
(crawlerSWGliders[0],"C2","SWGlider0","SWGlider0",1),
(crawlerSWGliders[0],"C3","SWGlider0","SWGlider0",1),
(crawlerSWGliders[0],"C4","SWGlider0","SWGlider0",1),
(pairTrackToSingleTrackCore,"Core","SWGlider1","SWGlider0",3)]
pairTrackToSingleTrack = CompoundPattern.chain(pairTrackToSingleTrackSpacings)
#Component which terminates a pair track
terminationGliderCollision = PeriodicPattern([],31,-1,-13,
[(SWGlider,"SWGlider0",0,CosetMatrix(Matrix([[0,0,0]]), SWGlider.periodLattice)),
(NWGlider,"NWGlider0",0,CosetMatrix(Matrix([[0,4,3]]), NWGlider.periodLattice))])
pairTrackTermination = CompoundPattern.chain([(NWRake(0,29),"NWRake","BlockLayer.BlockLayer0.C0.SWGlider0","BlockLayer.BlockLayer2.C0.SWGlider0",0),
(pairTrackToSingleTrack,"PairToSingle","Core.SWGlider0","Core.SWGlider0",31)]).addCompatibleComponents(
[(terminationGliderCollision, "Termination", {"SWGlider0":"PairToSingle.Core.SWGlider0","NWGlider0":"NWRake.NWRakeFromBlocks.R0.NWGlider0"}, {})])
#pairTrackTermination.placeWithInputs(CosetMatrix(Matrix([[0,0,0]]), pairTrackTermination.periodLattice), 10, 10)
#Track reset
#Spacings in this version are such that you can immediately construct a pair track without further spacing adjustments
minNWRakeSpacings = [297,298,299]
trackResetStart = CompoundPattern.chain([(NWRake(0,29+minNWRakeSpacings[0]+minNWRakeSpacings[1]+8),"NWRake0","BlockLayer.BlockLayer0.C0.SWGlider0","BlockLayer.BlockLayer2.C0.SWGlider0",0),
(NWRake(1,29+minNWRakeSpacings[0]),"NWRake1","BlockLayer.BlockLayer0.C0.SWGlider0","BlockLayer.BlockLayer2.C0.SWGlider0",3),
(pairTrackTermination,"Termination","Main.NWRake.BlockLayer.BlockLayer0.C0.SWGlider0","",3)])
#trackResetStart.placeWithInputs(CosetMatrix(Matrix([[0,0,0]]), trackResetStart.periodLattice), 100, 100)
trackResetEnd = CompoundPattern([(crawlerNWGliders,"C0",CosetMatrix(Matrix([[0,0,0]]),crawlerNWGliders.periodLattice)),
(crawlerNWGliders,"C1",CosetMatrix(Matrix([[-9,6,17]]),crawlerNWGliders.periodLattice))])
def trackReset(spacing):
return CompoundPattern.chain([(trackResetStart,"Start","NWRake0.BlockLayer.BlockLayer0.C0.SWGlider0","NWRake1.NWRakeFromBlocks.R0.NWGlider0",0),
(trackResetEnd,"End","C0.NWGlider0","C0.SWGlider0",spacing)])
trackReset(512).placeWithInputs(CosetMatrix(Matrix([[0,0,0]]), trackResetStart.periodLattice), 32, 32)EDIT: NE and SE rakes.
Code: Select all
x = 1141, y = 1589, rule = B3/S23
15$1055bo$1053b2o$1054b2o4$1040bo$1038b2o$1039b2o13$1047bo$1047bobo$
1047b2o4$1032bo$1032bobo$1032b2o13$1040bobo$1040b2o$1041bo4$1025bobo$
1025b2o$1026bo12$1034bo$1033bo$1033b3o4$1019bo$1018bo$1018b3o13$1028bo
$1026b2o$1027b2o4$1013bo$1011b2o$1012b2o6$357bobo$357b2o$358bo4$342bob
o$342b2o676bo$343bo676bobo$1020b2o4$1005bo$1005bobo$1005b2o5$351bo$
350bo$350b3o4$336bo$335bo$335b3o675bobo$1013b2o$1014bo4$998bobo$998b2o
$999bo5$345bo$343b2o$344b2o4$330bo$328b2o677bo$329b2o675bo$1006b3o4$
992bo$991bo$991b3o6$337bo$337bobo$337b2o4$322bo$322bobo676bo$322b2o
675b2o$1000b2o4$986bo$984b2o$985b2o6$330bobo$330b2o$331bo4$315bobo$
315b2o676bo$316bo676bobo$993b2o4$978bo$978bobo$978b2o5$324bo$323bo$
323b3o4$309bo$308bo$308b3o675bobo$986b2o$987bo4$971bobo$971b2o$972bo5$
318bo$316b2o$317b2o4$303bo$301b2o677bo$302b2o675bo$979b3o4$965bo$964bo
$964b3o6$310bo$310bobo$310b2o4$295bo$295bobo676bo$295b2o675b2o$973b2o
4$959bo$957b2o$958b2o6$303bobo$303b2o$304bo4$288bobo$288b2o676bo$289bo
676bobo$966b2o4$951bo$951bobo$951b2o5$297bo$296bo$296b3o4$282bo$281bo$
281b3o675bobo$959b2o$960bo4$944bobo$944b2o$945bo5$291bo$289b2o$290b2o
4$276bo$274b2o677bo$275b2o675bo$952b3o4$938bo$937bo$937b3o6$283bo$283b
obo$283b2o4$268bo$268bobo676bo$268b2o675b2o$946b2o4$932bo$930b2o$931b
2o6$276bobo$276b2o$277bo4$261bobo$261b2o676bo$262bo676bobo$939b2o4$
924bo$924bobo$924b2o5$270bo$269bo$269b3o4$255bo$254bo$254b3o675bobo$
932b2o$933bo4$917bobo$917b2o$918bo5$264bo$262b2o$263b2o4$249bo$247b2o
677bo$248b2o675bo$925b3o4$911bo$910bo$910b3o6$256bo$256bobo$256b2o4$
241bo$241bobo676bo$241b2o675b2o$919b2o4$905bo$903b2o$904b2o6$249bobo$
249b2o$250bo4$234bobo$234b2o676bo$235bo676bobo$912b2o4$897bo$897bobo$
897b2o5$243bo$242bo$242b3o4$228bo$227bo$223b3ob3o675bobo$223bo2bo678b
2o$222bo683bo$225b2o$221bo3b2o$221bo$223bo666bobo$223b3o664b2o$224b2o
665bo$225bo7b3o$223b2o8bo2bo$222bobo6bo4bo$221bo3bo5bo$223b2o5b2o$231b
2obo$233bo4$220bo$220bobo12b2o662bo$220b2o676bo$233bo2bo661b3o$232bo$
232bo2bo$214b3o17bo$213bo2bo667bo$213bo3bo665bo$214b4o665b3o$216bo2$
225b3o$224bo2bo$224bo2bo$212b2ob2o6bo2bo$212b3obo7b3o$224b2o7b2o$233b
2o$228bo$213bo14bo$212bo16bo$208b3ob3o10b2obo664bo$208bo2bo12bo666b2o$
207bo18bo4bo660b2o$210b2o$206bo3b2o16bobo$206bo21b3o$208bo10b3o656bo$
208b3o8bo2bo653b2o$209b2o8bob2o11b2o641b2o$210bo6b2o15b2o$208b2o7b2o$
207bobo6bo2bo$206bo3bo9bo$208b2o8b3o$219bo4$202bo$200b2ob2o$200b2o$
200b2ob2o29bobo648bo$213b3o15b2o652bobo$212bo2bo14bo5bo648b2o$203b2o7b
o4bo12b2o3bo$203b2o$217bo14bo2bo$205bo10bo16b2o635bo$200b2ob2obo5bob2o
14b2o638bobo$200b2o4b2o3bo2bo15b3o637b2o$203b2ob2o5b2o16bo$205bo4bo2bo
16b2ob2o$210bo19b2ob2o$214bo15bo3bo$196bo14bo18bo3bo$195b3o14b3o18bo$
194b2o2bo$194bo$193b2o12b3o$192bo14bo2bo$192b4o10bo3bo$194b2o10bobob2o
$207b2ob2o16bo649bobo$208b3o16bo650b2o$227b3o649bo4$206bob2o653bobo$
205bobobo653b2o$190bo15bo657bo$189b3o7bo$188bo2b2o6bo$192bo$190b3o8b2o
b2o$189bob2o7bo6bo$188b2obo8b2o4bo$190b2o$187b2obo11bo2bo$187b2ob2o11b
2o$187b2ob2o8b2o$189bo10b3o$201bo670bo$200b2ob2o17bo648bo$200b2ob2o15b
2o649b3o$200bo3bo16b2o$184bo15bo3bo$183b3o17bo$182b2o2bo670bo$184b3o
669bo$856b3o2$195bo$186bo7b3o$183bo9b2obo$182bo3bo5bo2bo$181b2ob2o7b2o
$194bo2$196b2o$183bo14bo$181b2o$178bo3b2o10bo2bobo$177b3o13bob3obo666b
o$176bo2b2o12bob2ob3o13bo649b2o$176b2ob2o16bobo14bobo648b2o$175b3o19b
3o14b2o$176b2obo18bo$177bo2bo$177bo673bo$178bobo668b2o$179bo8bo661b2o$
187b3o$176b3o7bo2b2o$176b2obo5b5o$175bob2o6bo2b2o$185bo2bo$186bobo4$
174bobo$174b2o13b2o$175bo13b2o$187b3o668bo$179b2o6b2o18bobo648bobo$
185bo2b2o17b2o649b2o$187bo20bo3$843bo$843bobo$843b2o3$183bo$182bo$182b
3o$187b2o$187b2o2$168bo$167bo$167b3o2$201bo649bobo$200bo650b2o$200b3o
649bo3$161b3o$161bo2bo23b2o646bobo$161bob2o23b2o646b2o$837bo3$163b2o$
161b4o7bo3b2o$160bo2bo7bobo$160bobo8b2o$160bobo9bo$174b2o$172b4o$160bo
10bo2bo$160bobo10bo15b2o$160b2o27b2o654bo$172bobo20bo648bo$166bo6b2o
10b3o5b2o649b3o$165bobo16bo2bo6b2o$164bo2bo3bo12bo3bo$165b2o2b2o12b2o
2bo$169b2o14bo644bo$169b2o3b3o9b2o641bo$171bo3b2o9b3o636b3ob3o$171b2ob
2o10b3o636bo2bo$152b3o19b2o648bo$151bo2bo18bo653b2o$151bo3bo29b2o636bo
3b2o$154b2o12bobo13b2obo635bo$152bobo13b2o13bo3bo637bo$149bo2b2o15bo
14bo640b3o$150bo2bo10bo661b2o$153bo9b3o5b2o654bo7b3o$150b2ob2o7b2o2bo
4b2o652b2o8bo2bo$151bobo8bo3bo17bobo637bobo6bo4bo$152bo9bobo20bo5b2o
630bo3bo5bo$192b2o631b2o5b2o$163b2ob2o20b5o640b2obo$165bo24b2o643bo$
157b2o31bo$157bobo$157b2o2bo$158b4o660bo$162b2o2bo655bobo12b2o$162bo2b
o656b2o$163b3o6b2o29bo631bo2bo$172b2o29b2o629bo$202bobo629bo2bo$162bo
653b3o17bo$160b2o653bo2bo$161b2o23bo628bo3bo$185b2o24b3o602b4o$185bobo
25bo604bo$168b3o41bo$147bo14b2o4bo2bo655b3o$145b2o15b2o4bo2bo22bo631bo
2bo$146b2o21bo2bo5b3o13bo25b2o604bo2bo$169bo2bo5bo15bo26b2o591b2ob2o6b
o2bo$167b2o10bo40bo593b3obo7b3o$167b2o657b2o7b2o$166bo3bo664b2o$166b2o
61b2o599bo$165bo8b2o52bobo584bo14bo$166bo3bo4b2o53bo583bo16bo$167b3o4b
o635b3ob3o10b2obo$810bo2bo12bo$238bo570bo18bo4bo$163b2o18b2o53b2o572b
2o$163b2o17bobo52bobo568bo3b2o16bobo$154bo29bo9b3o611bo21b3o$154bobo
653bo10b3o$154b2o654b3o8bo2bo$192bo53b3o562b2o8bob2o11b2o$192b2o54bo
563bo6b2o15b2o$191bobo53bo562b2o7b2o$139bo669bobo6bo2bo$139bobo666bo3b
o9bo$139b2o114b2o553b2o8b3o$256b2o563bo$255bo3$264b2o538bo27b3o$263bob
o536b2ob2o25bo2bo$265bo536b2o28bob2o$802b2ob2o23b2o$815b3o12b2o$273bo
540bo2bo11bo2bo$273b2o530b2o7bo4bo13bo$272bobo530b2o24b3o$819bo12bo$
807bo10bo$802b2ob2obo5bob2o$281b3o518b2o4b2o3bo2bo$283bo521b2ob2o5b2o$
282bo524bo4bo2bo$812bo$816bo$290b2o506bo14bo$291b2o504b3o14b3o$290bo
505b2o2bo$796bo$795b2o12b3o$299b2o493bo14bo2bo$298bobo493b4o10bo3bo$
300bo495b2o10bobob2o$809b2ob2o$810b3o$308bo$308b2o$307bobo516bobo$826b
2o$808bob2o15bo$807bobobo$316b3o473bo15bo$318bo472b3o7bo$317bo472bo2b
2o6bo$794bo$792b3o8b2ob2o$325b2o464bob2o7bo6bo$326b2o462b2obo8b2o4bo$
325bo466b2o$789b2obo11bo2bo$789b2ob2o11b2o$334b2o453b2ob2o8b2o$333bobo
455bo10b3o$335bo467bo$802b2ob2o$802b2ob2o$343bo458bo3bo$343b2o441bo15b
o3bo13bo$342bobo440b3o17bo13bo$784b2o2bo30b3o$786b3o2$351b3o$353bo$
352bo435bo$785bo10bo$784bo3bo6bobo$360b2o421b2ob2o7bobo$361b2o432b3o$
360bo435bo2bo$796bo$785bo13bo$369b2o412b2o$368bobo413b2o11bo$370bo427b
o$790bo6b2o$789bobo$378bo409bo2b2obo$378b2o409b2ob2obo18bo$377bobo412b
o2bo3bo12b2o$793bobo2bobo12b2o$795b3o$777bo17b3o$386b3o387b3o17bo2bo$
388bo386bo2b2o18bo$387bo391bo$777b3o12bo$776bob2o12bobo$395b2o378b2obo
13b2o$396b2o379b2o8b3o$395bo378b2obo8bo2bo5b2o$774b2ob2o7bo3bo4b2o$
774b2ob2o6b2o2bo$404b2o370bo10bo$403bobo382b2o$405bo382b3o$788b3o$781b
2o$413bo366bo2bo$413b2o366bo3bo20bo$412bobo366b5o20bobo$783b2ob2o18b2o
$786bo2b2o$787b3o6b2o$421b3o364bo7b2o$423bo$422bo362bo$784bo$768bo15b
3o$430b2o335b3o$431b2o333b2o2bo$430bo335bo$765b2o19b2o$764bo21b2o$439b
2o323b4o$438bobo325b2o10b3o$440bo337bo2bo15b2o$778bob2o15b2o2$448bo$
448b2o322b2o25bobo$447bobo322bo7b2o17b2o$772b3o3b4o18bo$771b3o3bo2bo$
770bobo4bobo$456b3o311bobo5b2o7b2o$458bo328b2o$457bo$777bo$777bobo18b
2o$465b2o310b2o19b2o$466b2o$465bo2$762bo$474b2o286bobo12b2o$473bobo
286b2o13b2o$475bo$788b2o$788b2o$785bo7bo$784b3o5bo$783bo2b2o4b3o4b2o$
783b2ob2o11b2o$782b3o$783b2obo$784bo2bo$784bo$778b2o5bobo$770bobo5b2o
6bo$770b2o$771bo11b3o$783b2obo$782bob2o$774b3o$755bobo16bo2bo22b2o$
755b2o17bob2o22b2o$756bo$784bo$784bo5b3o$776b2o10bo3bo$774b4o10bo3bo$
773bo2bo14bo$773bobo13b2o$773bobo3$773bo$773bobo$764bo8b2o$763bo$763b
3o27bo$792bobo4b2o$791bo2bo4b2o$784b2o6bo$749bo34bobo$748bo35bo12b3o$
748b3o46bobo2$778bo20b2o$777b2o18bob2o$777bobo18bo5$772bo$773bo$771b3o
2$758bo$756b2o$757b2o4$743bo$741b2o$742b2o9$780bo$781b2o$780b2o19$790b
o$788bobo$789b2o19$797bobo$798b2o$798bo18$807bo$808bo$806b3o19$815bo$
816b2o$815b2o19$825bo$823bobo$824b2o19$832bobo$833b2o$833bo18$842bo$
843bo$841b3o19$850bo$851b2o$850b2o19$860bo$858bobo$859b2o19$867bobo$
868b2o$868bo18$877bo$878bo$876b3o19$885bo$886b2o$885b2o19$895bo$893bob
o$894b2o19$902bobo$903b2o$903bo18$912bo$913bo$911b3o19$920bo$921b2o$
920b2o19$930bo$928bobo$929b2o19$937bobo$938b2o$938bo18$947bo$948bo$
946b3o19$955bo$956b2o$955b2o19$965bo$963bobo$964b2o19$972bobo$973b2o$
973bo18$982bo$983bo$981b3o19$990bo$991b2o$990b2o19$1000bo$998bobo$999b
2o19$1007bobo$1008b2o$1008bo18$1017bo$1018bo$1016b3o19$1025bo$1026b2o$
1025b2o19$1035bo$1033bobo$1034b2o19$1042bobo$1043b2o$1043bo!
Nora Brown
- glider_rider
- Posts: 197
- Joined: February 20th, 2013, 5:41 pm
- Location: CA
Re: 13131: The B-Heptomino/Glider Spaceship Thread
Alright, here's a prototype 16x backrake:
As it is, this alone should allow for arbitrary monochromatic monoparity slow salvos, meaning the only other thing we strictly need is probably a way to set up the first period-multiplied signal (as well as suitable xWSS recipes). However, in practice it will be very convenient to have a larger toolkit for manipulating period-multiplied signals. Of the top of my head, it will be nice to have: A way to pass the 16x signal along with our track resets, a 16x block layer (for targets), rake variants for the other colors & parities, and probably a rephaser. This did also involve some manual assembly since my tools can't really combine 1x and 16x parts conveniently yet, so it'll be important to fix that too.
EDIT: Alright, here's a script to generate 16x rakes for all colors and parities.
EDIT: Added a component for passing the filter along with track resets to the above script.
Code: Select all
x = 731, y = 2388, rule = B3/S23
724bo$724bobo$724b2o4$709bo$709bobo$709b2o13$717bobo$717b2o$718bo4$
702bobo$702b2o$703bo12$711bo$710bo$710b3o4$696bo$695bo$695b3o13$705bo$
703b2o$704b2o4$690bo$688b2o$689b2o13$697bo$697bobo$697b2o4$682bo$682bo
bo$682b2o13$690bobo$690b2o$691bo4$675bobo$675b2o$676bo12$684bo$683bo$
683b3o4$669bo$668bo$668b3o13$678bo$676b2o$677b2o4$663bo$661b2o$662b2o
13$670bo$670bobo$670b2o4$655bo$655bobo$655b2o13$663bobo$663b2o$664bo4$
648bobo$648b2o$649bo12$657bo$656bo$656b3o4$642bo$641bo$641b3o3$728bobo
$728b2o$729bo8$651bo$649b2o$650b2o4$636bo$634b2o$635b2o13$643bo$643bob
o$643b2o4$628bo$628bobo$628b2o13$636bobo$636b2o$637bo4$621bobo$621b2o$
622bo12$630bo$629bo$629b3o4$615bo$614bo$614b3o13$624bo$622b2o$623b2o4$
609bo$607b2o$608b2o13$616bo$616bobo$616b2o4$601bo$601bobo$601b2o13$
609bobo$609b2o$610bo4$594bobo$594b2o$595bo12$603bo$602bo$602b3o4$588bo
$587bo$587b3o13$597bo$595b2o$596b2o4$582bo$580b2o$581b2o13$589bo$589bo
bo$589b2o4$574bo$574bobo$574b2o13$582bobo$582b2o$583bo4$567bobo$567b2o
$568bo12$576bo$575bo$575b3o4$561bo$560bo$560b3o13$570bo$568b2o$569b2o
4$555bo$553b2o$554b2o13$562bo$562bobo$562b2o4$547bo$547bobo$547b2o13$
555bobo$555b2o$556bo4$540bobo$540b2o$541bo12$549bo$548bo$548b3o4$534bo
$533bo$533b3o3$620bobo$620b2o$621bo8$543bo$541b2o$542b2o4$528bo$526b2o
$527b2o13$535bo$535bobo$535b2o4$520bo$520bobo$520b2o13$528bobo$528b2o$
529bo4$513bobo$513b2o$514bo12$522bo$521bo$521b3o4$507bo$506bo$506b3o
13$516bo$514b2o$515b2o4$501bo$499b2o$500b2o13$508bo$508bobo$508b2o4$
493bo$493bobo$493b2o13$501bobo$501b2o$502bo4$486bobo$486b2o$487bo12$
495bo$494bo$494b3o4$480bo$479bo$479b3o13$489bo$487b2o$488b2o4$474bo$
472b2o$473b2o13$481bo$481bobo$481b2o4$466bo$466bobo$466b2o13$474bobo$
474b2o$475bo4$459bobo$459b2o$460bo12$468bo$467bo$467b3o4$453bo$452bo$
452b3o13$462bo$460b2o$461b2o4$447bo$445b2o$446b2o13$454bo$454bobo$454b
2o4$439bo$439bobo$439b2o13$447bobo$447b2o$448bo4$432bobo$432b2o$433bo
12$441bo$440bo$440b3o4$426bo$425bo$425b3o3$512bobo$512b2o$513bo8$435bo
$433b2o$434b2o4$420bo$418b2o$419b2o13$427bo$427bobo$427b2o4$412bo$412b
obo$412b2o13$420bobo$420b2o$421bo4$405bobo$405b2o$406bo12$414bo$413bo$
413b3o4$399bo$398bo$398b3o13$408bo$406b2o$407b2o4$393bo$391b2o$392b2o
13$400bo$400bobo$400b2o4$385bo$385bobo$385b2o13$393bobo$393b2o$394bo4$
378bobo$378b2o$379bo12$387bo$386bo$386b3o4$372bo$371bo$371b3o13$381bo$
379b2o$380b2o4$366bo$364b2o$365b2o13$373bo$373bobo$373b2o4$358bo$358bo
bo$358b2o13$366bobo$366b2o$367bo4$351bobo$351b2o$352bo12$360bo$359bo$
359b3o4$345bo$344bo$344b3o13$354bo$352b2o$353b2o4$339bo$337b2o$338b2o
13$346bo$346bobo$346b2o4$331bo$331bobo$331b2o13$339bobo$339b2o$340bo4$
324bobo$324b2o$325bo12$333bo$332bo$332b3o4$318bo$317bo$317b3o3$404bobo
$404b2o$405bo8$327bo$325b2o$326b2o4$312bo$310b2o$311b2o13$319bo$319bob
o$319b2o4$304bo$304bobo$304b2o13$312bobo$312b2o$313bo4$297bobo$297b2o$
298bo12$306bo$305bo$305b3o4$291bo$290bo$290b3o13$300bo$298b2o$299b2o4$
285bo$283b2o$284b2o13$292bo$292bobo$292b2o4$277bo$277bobo$277b2o13$
285bobo$285b2o$286bo4$270bobo$270b2o$271bo12$279bo$278bo$278b3o2$261bo
$260b3o$259b2obo$258bo2bo$259b2o$260bo2$262b2o7b3o$264bo6bo2bo$271bo2b
o$260bo2bobo6bo2bo$259bob3ob2o5bo2bo$259bob2ob2obo2b2o$263bob3o2b2o$
263b4o2bo3bo$264bo4b2o$268bo$269bo3bo$270b3o5$256bo$256bobo$256b2o12b
2o$270b2o12$264bobo4b2o$264b2o5b2o$265bo4$249bobo$249b2o$250bo5$272b2o
$272b2o6$258bo$257bo$257b3o4$243bo29b2o$242bo30b2o$242b3o11$274b2o$
274b2o$252bo$250b2o$251b2o4$237bo$235b2o$236b2o3$275b2o$275b2o9$244bo$
244bobo$244b2o$276b2o$276b2o2$229bo$229bobo$229b2o8$277b2o$277b2o4$
237bobo$237b2o$238bo4$222bobo$222b2o$223bo54b2o$278b2o11$231bo$230bo
48b2o$230b3o46b2o4$216bo$215bo$215b3o6$280b2o$280b2o6$225bo$223b2o$
224b2o4$210bo70b2o$208b2o71b2o$209b2o3$296bobo$296b2o$297bo2$203bo$
202b3o$201bo2b2o2$282b2o$282b2o$204b2o10b2o$202b3o8b2o4bo$201bo10bo5bo
$201b3o8b2o$202b2o$214bo2bo$215b2o$201bobo8b2o$201b2o9b3o$202bo10bo$
213bo2bo$207bo6b2o67b2o$206bobo74b2o$205bo2bo3bo$206b2o3bobo$210b2o4bo
$211bo4bo$212b2o2bo$215b2o$194bo18bobo$193b3o18bo$192b2o2bo13bo$193b4o
12bo$191bobo15b3o$190bo2bo90b2o$191b3o90b2o$192bobo9b3o5b2o$192bobo9bo
2bo4b2o$192b3o8bo3bo$203bobob2o$204b2ob2o$205b3o2$198b2o$198bo2bo$199b
o2bo$199b2obo3bo$203b2o2bo77b2o$204b3o78b2o$205bo7b2o$213b2o2$202bo$
202bobo$185bo16b2o$184b3o$183bo2b2o$182b5o$182bo2b2o9b3o4b2o$182bo2bo
9bo2bo4b2o$183bobo9bo3bo86b2o$196b4o86b2o$198bo15b2o$187b2o25b2o$186b
3o$184bo$185b2o$194b2ob2o$194b3obo$187bobo$179bo7bobo$178b3o7bo15b2o$
177b2o2bo13bo8b2o$178b4o12bo92b2o$176bobo11b3ob3o90b2o$175bo2bo11bo2bo
21b2o$176b3o10bo25b2o$177bobo12b2o$177bobo8bo3b2o$177b3o8bo$190bo$190b
3o$191b2o$192bo$190b2o13b2o$189bobo13b2o$173bo14bo3bo95b2o$172b3o15b2o
96b2o$171bo2b2o40b2o$216b2o3$174b2o8bo$172b3o7b2ob2o$171bo10b2o$171b3o
8b2ob2o$172b2o$206b2o$185b2o19b2o$171bobo11b2o102b2o$171b2o116b2o$172b
o14bo29b2o$167bo14b2ob2obo28b2o$166b3o13b2o4b2o$165b2o2bo15b2ob2o$165b
o3bo17bo$165bobo2$166b2ob2o$168bo$207b2o$177bo29b2o$176b3o110bobo$165b
4o6b2obo107b2o$164bobobo5bo2bo40b2o65bo5bo$165bo9b2o41b2o65b2o3bo$176b
o$287bo2bo$288b2o$165bo119b2o$163b2o120b3o$164b2o12b2o106bo$171bo6b2o
105b2ob2o$169b5o34b2o75b2ob2o$169b2ob2o2bo31b2o75bo3bo$169b6ob2o107bo
3bo$171bo2b2obo110bo$219b2o$219b2o$179b2o2$280bo$279b3o$278b2obo$172bo
104bo2bo$172bobo103b2o$172b2o35b2o68bo$176b2o31b2o$176b2o103b2o$283bo$
157bo62b2o$157bobo60b2o57bo2bobo$157b2o119bob3obo$278bob2ob3o$282bobo$
282b3o$283bo$274bo$273b3o$210b2o60bo2b2o$177b2o31b2o$177b2o92b2o$271b
2o$221b2o47bo2bo$221b2o49b3o$165bobo$165b2o$166bo4$150bobo$150b2o59b2o
$151bo26b2o31b2o55bo$178b2o87b3o$266b2o2bo$222b2o43b5o$145bo76b2o43b5o
$144b3o121bo$143b2o2bo118bobo$145b3o117bob2o$265bobo$264b3o$264bobo$
147bo117b4o$144bo10bo56b2o52b3o$143bo3bo6bobo22b2o31b2o53bo$142b2ob2o
7bobo22b2o$154b3o$155bo2bo64b2o37bo$155bo67b2o36b3o$144bo13bo101bo2b2o
$142b2o116bo3bo$143b2o11bo104b2obo$157bo105b2o$149bo6b2o$148bobo$147bo
2b2obo$148b2ob2obo58b2o$151bo2bo3bo21b2o31b2o44bo2b2o$152bobo2bobo20b
2o77bobobo$154b3o103bo$154b3o67b2o$136bo18bo2bo65b2o$135b3o19bo$134bo
2b2o117bob2obo$138bo12bo103b3ob2o$136b3o12bobo100b2ob4o$135bob2o12b2o
104b2o$134b2obo119b2o$136b2o8b3o5b2o101b2o$133b2obo8bo2bo5b2o58b2o38bo
$133b2ob2o7bo3bo31b2o31b2o38b2o$133b2ob2o6b2o2bo32b2o72bobo$135bo10bo
108bo2bo$147b2o76b2o28bobo$147b3o75b2o28b3o$147b3o104bob2o$140b2o112bo
2bo$139bo2bo113bo$140bo3bo$140b5o$142b2ob2o$145bo2b2o5b2o$146b3o6b2o
58b2o31b3o$147bo34b2o31b2o30bo2bo$182b2o62bo$144bo102b3o$143bo82b2o$
143b3o80b2o$250b2o$250b2o$251bo$129bo15b2o104b2o$128bo16b2o100b3obob2o
$128b3o116b2o$124b3o29b2o93bo2bo$124bo2bo28b2o58b2o33b3o$123bo59b2o31b
2o$126b2o55b2o$122bo3b2o114b3o$122bo104b2o12bo2bo$124bo102b2o12bo2bo$
124b3o$125b2o113b2o$126bo7b3o102bo2bo$124b2o8bo2bo8b2o91bo2bo$123bobo
6bo4bo8b2o94bo$122bo3bo5bo$124b2o5b2o24b2o$132b2obo21b2o58b2o$134bo49b
2o31b2o$184b2o2$228b2o$121bo106b2o$121bobo12b2o98b3o$121b2o113bo2bo$
134bo2bo98bo2bo$133bo13b2o88bo2bo$133bo2bo10b2o88bo2bo$115b3o17bo99b2o
$114bo2bo40b2o75b2o$114bo3bo39b2o58b2o14bo3bo$115b4o66b2o31b2o14b2o$
117bo67b2o46bo$234bo3bo$126b3o100b2o4b3o$125bo2bo100b2o$125bo2bo$113b
2ob2o6bo2bo$113b3obo7b3o$125b2o7b2o12b2o$134b2o12b2o$129bo$114bo14bo
29b2o$113bo16bo28b2o58b2o$109b3ob3o10b2obo56b2o31b2o$109bo2bo12bo60b2o
$108bo18bo4bo$111b2o117b2o$107bo3b2o16bobo98b2o$107bo21b3o$109bo10b3o$
109b3o8bo2bo$110b2o8bob2o11b2o12b2o$111bo6b2o15b2o12b2o$109b2o7b2o109b
obo$108bobo6bo2bo39b2o67b2o$107bo3bo9bo38b2o58b2o8bo$109b2o8b3o65b2o
31b2o$120bo66b2o2$231b2o$231b2o$103bo27b3o$101b2ob2o25bo2bo$101b2o28bo
b2o$101b2ob2o23b2o19b2o$114b3o12b2o19b2o$113bo2bo11bo2bo$104b2o7bo4bo
13bo28b2o53b3o$104b2o24b3o28b2o53bo2bo$118bo12bo56b2o24bo4bo$106bo10bo
70b2o24bo$101b2ob2obo5bob2o96b2o$101b2o4b2o3bo2bo98b2obo14b2o$104b2ob
2o5b2o100bo6bo8b2o$106bo4bo2bo107bo$111bo110b3o$115bo102bobo$97bo14bo
38b2o65bobo$96b3o14b3o35b2o$95b2o2bo117bo$95bo66b2o$94b2o12b3o51b2o$
93bo14bo2bo77b2o$93b4o10bo3bo77b2o28bobo$95b2o10bobob2o107bo$108b2ob2o
120b2o$109b3o121b2o$226b2o$230bo$125bobo98bo4bo$125b2o25b2o73b2o2bo$
107bob2o15bo25b2o73b2ob2o$106bobobo115bo2bo$91bo15bo55b2o57b4o3bo$90b
3o7bo62b2o56bob2ob3o$89bo2b2o6bo89b2o29bo2bo$93bo96b2o29bo2bo$91b3o8b
2ob2o115b2o$90bob2o7bo6bo$89b2obo8b2o4bo$91b2o$88b2obo11bo2bo107b2o$
88b2ob2o11b2o108bobo$88b2ob2o8b2o50b2o36b3o20bo$90bo10b3o49b2o36bo2bo$
102bo86bo5bo$101b2ob2o58b2o23bobo4bo11bo$101b2ob2o58b2o23b3o2bobo10b2o
$101bo3bo89bo11bobo$85bo15bo3bo13bo$84b3o17bo13bo$83b2o2bo30b3o$85b3o
112b3o$200bo$201bo2$87bo66b2o$84bo10bo58b2o$83bo3bo6bobo$82b2ob2o7bobo
68b2o$94b3o68b2o$95bo2bo$95bo98b2o$84bo13bo63bo31b2o$82b2o77b3o$83b2o
11bo63bo2b2o$97bo62bo3bo$89bo6b2o63b2obo$88bobo72b2o$87bo2b2obo61b2o$
88b2ob2obo18bo41b2o$91bo2bo3bo12b2o$92bobo2bobo12b2o$94b3o62bo2b2o$76b
o17b3o62bobobo$75b3o17bo2bo61bo34b2o$74bo2b2o18bo97b2o$78bo$76b3o12bo$
75bob2o12bobo65bobo$74b2obo13b2o66b2o$76b2o8b3o71bo$73b2obo8bo2bo5b2o
60b2o$73b2ob2o7bo3bo4b2o60b2o$73b2ob2o6b2o2bo$75bo10bo$87b2o$87b3o$87b
3o106b2o$80b2o114b2o$79bo2bo$80bo3bo20bo$80b5o20bobo$82b2ob2o18b2o$85b
o2b2o$86b3o6b2o$87bo7b2o2$84bo$83bo$67bo15b3o$66b3o128b2o$65b2o2bo127b
2o$65bo$64b2o19b2o$63bo21b2o$63b4o$65b2o10b3o$77bo2bo15b2o$77bob2o15b
2o3$71b2o25bobo$71bo7b2o17b2o$71b3o3b4o18bo98b2o$70b3o3bo2bo118b2o$69b
obo4bobo$69bobo5b2o7b2o$86b2o2$76bo$76bobo18b2o$76b2o19b2o4$61bo$61bob
o12b2o121b2o$61b2o13b2o121b2o2$87b2o$87b2o$84bo7bo$83b3o5bo$82bo2b2o4b
3o4b2o$82b2ob2o11b2o$81b3o$82b2obo$83bo2bo$83bo$77b2o5bobo113b2o$69bob
o5b2o6bo114b2o$69b2o$70bo11b3o$82b2obo$81bob2o$73b3o$54bobo16bo2bo22b
2o$54b2o17bob2o22b2o$55bo$83bo$83bo5b3o$75b2o10bo3bo$73b4o10bo3bo109b
2o$72bo2bo14bo110b2o$72bobo13b2o$72bobo3$72bo$72bobo$63bo8b2o$62bo$62b
3o27bo$91bobo4b2o$90bo2bo4b2o$83b2o6bo110b2o$48bo34bobo116b2o$47bo35bo
12b3o$47b3o46bobo2$77bo20b2o$76b2o18bob2o$76bobo18bo5$71bo$72bo130b2o$
70b3o130b2o2$57bo$55b2o$56b2o4$42bo$40b2o$41b2o2$204b2o$204b2o6$79bo$
80b2o$79b2o2$49bo$49bobo$49b2o154b2o$205b2o3$34bo$34bobo$34b2o7$206b2o
$206b2o$89bo$87bobo$88b2o2$42bobo$42b2o$43bo4$27bobo$27b2o178b2o$28bo
178b2o9$96bobo$97b2o$97bo$36bo171b2o$35bo172b2o$35b3o4$21bo$20bo$20b3o
9$106bo$107bo$105b3o2$30bo$28b2o$29b2o3$210b2o$15bo194b2o$13b2o$14b2o
9$114bo$115b2o94b2o$114b2o95b2o2$22bo$22bobo$22b2o4$7bo$7bobo$7b2o2$
95bo116b2o$93b2o117b2o$94b2o5$124bo$122bobo$123b2o2$15bobo$15b2o$16bo
196b2o$213b2o3$obo$2o$bo7$214b2o$214b2o$131bobo$132b2o$132bo9$215b2o$
215b2o8$141bo$142bo$140b3o2$216b2o$216b2o12$217b2o$217b2o3$149bo$150b
2o$149b2o7$218b2o$218b2o11$159bo$157bobo59b2o$158b2o59b2o12$220b2o$
220b2o6$166bobo$167b2o$167bo4$221b2o$221b2o12$222b2o$176bo45b2o$177bo$
175b3o10$223b2o$223b2o8$184bo$185b2o$184b2o2$224b2o$224b2o16$194bo$
192bobo$193b2o7$226b2o$226b2o11$201bobo$202b2o23b2o$202bo24b2o12$228b
2o$228b2o5$211bo$212bo$210b3o5$229b2o$229b2o12$230b2o$219bo10b2o$220b
2o$219b2o10$231b2o$231b2o8$229bo$227bobo$228b2o2$232b2o$232b2o!
EDIT: Alright, here's a script to generate 16x rakes for all colors and parities.
Code: Select all
import golly as g
from glife import *
import math
import cmath
import os
from scipy import signal
def mod(x,m):
return ((x%m)+m)%m
#Linear algebra stuff
#Wanted to do this myself rather than using a library
#Whether or not this was smart is debatable
#I ended up using scipy instead because it's much faster
#A rational number
class Rational:
#Constructor
def __init__(self, num: int, den: int = 1):
a = math.gcd(num, den)
self.num = (1, -1)[den < 0] * num // a
self.den = abs(den // a)
#Hashing
def __eq__(self, other)->bool:
if isinstance(other, int):
return self.num == other and self.den == 1
elif isinstance(other, Rational):
return self.num == other.num and self.den == other.den
def __hash__(self) -> int:
return hash((self.num,self.den))
#Comparison
def __ne__(self, other)->bool:
if isinstance(other, int):
return self.num != other or self.den != 1
elif isinstance(other, Rational):
return self.num != other.num or self.den != other.den
def __lt__(self, other) -> bool:
if isinstance(other, int | float):
return self.num < other*self.den
elif isinstance(other, Rational):
return self.num*other.den < other.num*self.den
def __le__(self, other) -> bool:
if isinstance(other, int | float):
return self.num <= other*self.den
elif isinstance(other, Rational):
return self.num*other.den <= other.num*self.den
def __gt__(self, other) -> bool:
if isinstance(other, int | float):
return self.num > other*self.den
elif isinstance(other, Rational):
return self.num*other.den > other.num*self.den
def __ge__(self, other) -> bool:
if isinstance(other, int | float):
return self.num >= other*self.den
elif isinstance(other, Rational):
return self.num*other.den >= other.num*self.den
#Arithmetic
def __add__(self, other):
if isinstance(other, int):
return Rational(self.num+other*self.den, self.den)
elif isinstance(other, Rational):
return Rational(self.num*other.den+other.num*self.den, self.den*other.den)
def __sub__(self, other):
if isinstance(other, int):
return Rational(self.num-other*self.den, self.den)
elif isinstance(other, Rational):
return Rational(self.num*other.den-other.num*self.den, self.den*other.den)
def __mul__(self, other):
if isinstance(other, int):
return Rational(self.num*other, self.den)
elif isinstance(other, Rational):
return Rational(self.num*other.num, self.den*other.den)
def __truediv__(self, other):
if isinstance(other, int):
return Rational(self.num, self.den*other)
elif isinstance(other, Rational):
return Rational(self.num*other.den, self.den*other.num)
def __floordiv__(self, other):
return Rational(int(self / other), 1)
def __mod__(self, other):
return (self / other) - (self // other)
def __neg__(self):
return Rational(-self.num, self.den)
def __abs__(self):
return Rational(abs(self.num), self.den)
#Casting
def __int__(self) -> int:
return self.num // self.den
def __float__(self) -> float:
return self.num / self.den
def __str__(self) -> str:
return str(self.num) + "/" + str(self.den)
#Other math
def gcd(*args):
output = abs(args[0])
for i in range(1,len(args)):
output = Rational(math.gcd(output.num, args[i].num), math.lcm(output.den, args[i].den))
return output
#A matrix of rational numbers
class Matrix:
#Constructor
def __init__(self, terms):
#Automatically convert ints to Rationals
self.terms = [[Rational(1) * term for term in row] for row in terms]
self.height = len(terms)
self.width = 0
if self.height > 0:
self.width = len(terms[0])
#Get terms
def sliceRange(s):
if isinstance(s, int):
return range(s,s+1)
elif isinstance(s, slice):
return range(s.start, s.stop)
def __getitem__(self, key: list[int] | list[slice]):
if isinstance(key[0], int) and isinstance(key[1], int):
return self.terms[key[0]][key[1]]
else:
return Matrix([[self.terms[row][col] for col in Matrix.sliceRange(key[1])] for row in Matrix.sliceRange(key[0])])
#Hashing
def __eq__(self, other)->bool:
return self.terms == other.terms
def __hash__(self) -> int:
return hash(tuple(tuple(row) for row in self.terms))
#Arithmetic
def __add__(self, other):
return Matrix([[term1 + term2 for term1, term2 in zip(row1,row2)] for row1, row2 in zip(self.terms,other.terms)])
def __sub__(self, other):
return Matrix([[term1 - term2 for term1, term2 in zip(row1,row2)] for row1, row2 in zip(self.terms,other.terms)])
#Scalar or matrix multiplication
def __mul__(self, other):
if isinstance(other, int | Rational):
return Matrix([[term * other for term in row] for row in self.terms])
elif isinstance(other, Matrix):
return Matrix([[sum([self[rowIndex,sharedIndex]*other[sharedIndex,colIndex] for sharedIndex in range(self.width)], Rational(0)) for colIndex in range(other.width)] for rowIndex in range(self.height)])
elif isinstance(other, CosetMatrix):
return CosetMatrix(self*other.rep, other.lattice)
def __div__(self, other):
return Matrix([[term / other for term in row] for row in self.terms])
def __neg__(self):
return Matrix([[-term for term in row] for row in self.terms])
def transpose(self):
return Matrix([[self[rowIndex,colIndex] for rowIndex in range(self.height)] for colIndex in range(self.width)])
def copy(self):
return Matrix([[term for term in row] for row in self.terms])
def row(self, row: int):
return self[row, 0:self.width]
def col(self, col: int):
return self[0:self.height, col]
def rows(self):
return [self.row(n) for n in range(self.height)]
def cols(self):
return [self.col(n) for n in range(self.width)]
def __str__(self):
output = ""
for row in range(self.height):
output += "["
for col in range(self.width):
output += str(self[row,col])
if col < self.width-1:
output += ","
output += "]"
if row < self.height-1:
output += "\n"
return output
def isZero(self):
return all(all(term == 0 for term in row) for row in self.terms)
#Tools for making block matrices
def blockHorizontal(self, other):
return Matrix([row1+row2 for row1,row2 in zip(self.terms, other.terms)])
def blockVertical(self, other):
return Matrix(self.terms+other.terms)
#Row reduction
def rowReduce(self):
output = self.copy()
rowIndex = 0
colIndex = 0
while rowIndex < output.height and colIndex < output.width:
#Check if this column is zero below rowIndex, if so goto next column
nonzeroRowIndex = next((rowCheckIndex for rowCheckIndex in range(rowIndex, output.height) if output[rowCheckIndex,colIndex] != 0), -1)
if nonzeroRowIndex == -1:
colIndex += 1
else:
#Otherwise, do a row-reduction step
#Swap rows rowIndex and nonzeroRowIndex if needed
if nonzeroRowIndex != rowIndex:
output.swapRowsInPlace(rowIndex, nonzeroRowIndex)
#Normalize to 1
divideByVal = output[rowIndex, colIndex]
output.terms[rowIndex] = [term / divideByVal for term in output.terms[rowIndex]]
for otherRowIndex in range(output.height):
if otherRowIndex != rowIndex:
output.terms[otherRowIndex] = [otherRowTerm - rowTerm * output[otherRowIndex, colIndex] for rowTerm, otherRowTerm in zip(output.terms[rowIndex], output.terms[otherRowIndex])]
rowIndex += 1
return output
def swapRowsInPlace(self, row1: int, row2: int):
self.terms[row1], self.terms[row2] = self.terms[row2], self.terms[row1]
def removeZeroRows(self):
return Matrix([row for row in self.terms if not all(term == 0 for term in row)])
def det(self):
rowReducedForm = self.rowReduce()
return math.prod([rowReducedForm[i,i] for i in range(rowReducedForm.width)])
def rank(self):
return len([row for row in self.terms if not all(term == 0 for term in row)])
def id(n: int):
return Matrix([[Rational(int(row == col)) for col in range(n)] for row in range(n)])
def zero(height: int, width: int):
return Matrix([[Rational(0) for col in range(width)] for row in range(height)])
#Gives the inverse of an invertible square matrix
def inverse(self):
return self.blockHorizontal(Matrix.id(self.width)).rowReduce()[0:self.height,self.width:self.width*2]
#Gives a right inverse
def rightInverse(self):
transpose = self.transpose()
return transpose * (self * transpose).inverse()
#Row reduction but we can only use integer multiples
def integerRowReduce(self):
output = self.copy()
rowIndex = 0
colIndex = 0
while rowIndex < output.height and colIndex < output.width:
#Check if this column is zero below rowIndex, if so goto next column
existsANonzeroEntry = False
rowToTest = rowIndex
while rowToTest < output.height:
if output[rowToTest, colIndex] > 0:
#Found a nonzero entry
existsANonzeroEntry = True
if rowToTest == rowIndex:
#On the starting row, so we don't do much
rowToTest += 1
else:
if output[rowIndex, colIndex] < output[rowToTest, colIndex]:
#swap rows
output.swapRowsInPlace(rowIndex, rowToTest)
else:
#subtract as many terms[rowToTest] from terms[rowIndex] as possible
mult = output[rowIndex, colIndex] // output[rowToTest, colIndex]
output.terms[rowIndex] = [term - testTerm * mult for term, testTerm in zip(output.terms[rowIndex],output.terms[rowToTest])]
elif output[rowToTest, colIndex] < 0:
#Switch sign of this row
output.terms[rowToTest] = [-term for term in output.terms[rowToTest]]
else:
#Entry cleared, move to next row
rowToTest += 1
if existsANonzeroEntry and rowIndex < output.height and colIndex < output.width and output[rowIndex, colIndex] != 0:
#Subtract as much from the rows < rowIndex as possible while leaving the term positive
for rowToModify in range(rowIndex):
mult = output[rowToModify, colIndex] // output[rowIndex, colIndex]
output.terms[rowToModify] = [termToModify - term * mult for term, termToModify in zip(output.terms[rowIndex],output.terms[rowToModify])]
rowIndex += 1
else:
colIndex += 1
return output
#A lattice of rational points
class Lattice:
#Constructor
def __init__(self, basis: Matrix, rowReduceBasis: bool = True):
#Do integer row reduction for our basis by default
if rowReduceBasis:
self.basis = basis.integerRowReduce().removeZeroRows()
else:
self.basis = basis.copy()
self.dimension = self.basis.width
self.rank = self.basis.height
#Find pivot columns
#The index of the first nonzero column in each row
self.pivots = [[x != 0 for x in row].index(True) for row in self.basis.terms]
#Find inverse of the generator matrix
self.changeOfBasis = self.basis.rightInverse()
#Gets canonical coset representative for a matrix
def getCosetRepresentative(self, matrix: Matrix) -> Matrix:
output = matrix.copy()
for matrixRowIndex in range(matrix.height):
for rowIndex in range(len(self.pivots)):
colIndex = self.pivots[rowIndex]
generatorValue = self.basis[rowIndex,colIndex]
matrixValue = output[matrixRowIndex,colIndex]
output.terms[matrixRowIndex] = [output[matrixRowIndex,termIndex] - self.basis[rowIndex,termIndex] * (matrixValue // generatorValue) for termIndex in range(matrix.width)]
return output
#Does this lattice group contain a given row vector
def __contains__(self, vector: Matrix) -> bool:
return self.getCosetRepresentative(vector).isZero()
#Sum of two lattices
def __add__(self, other):
return Lattice(self.basis.blockVertical(other.basis))
def addGenerators(self, basisVectors: Matrix):
return Lattice(self.basis.blockVertical(basisVectors))
#Gets coordinates of the row vectors in a matrix where all row vectors are in this lattice
def getCoordinates(self, matrix: Matrix) -> Matrix:
return matrix * self.changeOfBasis
#Whether or not this lattice contains a multiple of the row vector for each row of a given matrix
def containsMultiple(self, matrix: Matrix) -> bool:
return self.getCoordinates(matrix) * self.basis == matrix
#The intersection of self with the plane other lies in
def intersectWithPlane(self,other):
#add in extra coordinates that don't lie in this plane
otherExtraBasis = other.basis
n = 0
while otherExtraBasis.height < otherExtraBasis.width:
testVector = Matrix([[Rational(int(a==n)) for a in range(otherExtraBasis.width)]])
n += 1
if not Lattice(otherExtraBasis).containsMultiple(testVector):
otherExtraBasis = testVector.blockVertical(otherExtraBasis)
otherExtraBasisInverse = otherExtraBasis.inverse()
basisInOtherCoordsReduced = (self.basis * otherExtraBasisInverse).integerRowReduce()
#Isolate only the rows that don't rely on the first few terms
basisInPlaneInOtherCoords = Matrix([row for row in basisInOtherCoordsReduced.terms if all(row[i]==0 for i in range(other.basis.width - other.basis.height))])
#Convert from coordinates
basisInPlane = basisInPlaneInOtherCoords * otherExtraBasis
return Lattice(basisInPlane)
#The dual of a lattice
def dual(self):
return Lattice(self.changeOfBasis.transpose(), False)
#The intersection of two lattices
def __and__(self, other):
return (self.dual() + other.dual()).dual().intersectWithPlane(self).intersectWithPlane(other)
#The lattice of integer divisors of a given lattice
def divisorLattice(self):
return LatticeGroup(Matrix.id(self.dimension)).intersectWithPlane(self)
#A basis for the torsion-free part of G/H
#Output as a matrix with rows v s.t. v+H form our basis
def quotientTorsionFreeBasis(self, sublattice):
divisorLattice = self.intersectWithPlane(sublattice)
divisorLatticeBasisExtended = divisorLattice.basis
nonPivots = [x for x in range(divisorLattice.dimension) if x not in divisorLattice.pivots]
for nonPivot in nonPivots:
divisorLatticeBasisExtended = self.basis.row(nonPivot).blockVertical(divisorLatticeBasisExtended)
divisorLatticeBasisExtendedInverse = divisorLatticeBasisExtended.inverse()
basisVectorsInDivisorLatticeExtendedCoordsReduced = (self.basis * divisorLatticeBasisExtendedInverse).integerRowReduce()
nonPivotBasisVectorsToCoords = basisVectorsInDivisorLatticeExtendedCoordsReduced[0:(divisorLattice.dimension-divisorLattice.rank),0:divisorLattice.dimension]
return CosetMatrix((nonPivotBasisVectorsToCoords * divisorLatticeBasisExtended).integerRowReduce(), sublattice)
#The torsion elements of G/H
def quotientTorsionElements(self, sublattice):
#We know these are all in divisorLattice
divisorLattice = self.intersectWithPlane(sublattice)
intermediateLattice = sublattice
#Find torsion of all basis elements
generators = Matrix([])
torsions = []
for basisElt in divisorLattice.basis.rows():
#Find the torsion of this basis element in the intermediate lattice
basisEltCoords = basisElt * intermediateLattice.changeOfBasis
#Torsion is the gcd of the elements of basisEltCoords
torsion = Rational.gcd(*basisEltCoords.terms[0]).den
torsions.append(torsion)
generators = generators.blockVertical(basisElt)
intermediateLattice = intermediateLattice.addGenerators(basisElt)
#Output as an iterator
def outputGenerator(basisElts, torsions):
multiplicities = [0 for torsion in torsions]
while True:
yield CosetMatrix(Matrix([multiplicities]) * basisElts, sublattice)
#Increment
index = 0
multiplicities[0]+=1
while index < len(multiplicities) and multiplicities[index] == torsions[index]:
multiplicities[index] = 0
index += 1
if index < len(multiplicities):
multiplicities[index]+=1
if index == len(multiplicities):
break
return outputGenerator(basisElts, torsions)
#Generators for G/H, with torsions (0 if torsion-free)
def quotientGeneratorsWithTorsions(self, sublattice):
#We know these are all in divisorLattice
divisorLattice = self.intersectWithPlane(sublattice)
intermediateLattice = sublattice
#Find torsion of all basis elements
generators = Matrix([])
torsions = []
for basisElt in divisorLattice.basis.rows():
#Find the torsion of this basis element in the intermediate lattice
basisEltCoords = basisElt * intermediateLattice.changeOfBasis
#Torsion is the gcd of the elements of basisEltCoords
torsion = Rational.gcd(*basisEltCoords.terms[0]).den
#if torsion != 1:
torsions.append(torsion)
generators = generators.blockVertical(basisElt)
intermediateLattice = intermediateLattice.addGenerators(basisElt)
#Add in the torsion-free basis
#return list(zip([CosetMatrix(row, sublattice) for row in generators.rows()], torsions)) + [(row,0) for row in self.quotientTorsionFreeBasis(sublattice).rows()]
return list(zip(generators.rows(), torsions)) + [(row.rep,0) for row in self.quotientTorsionFreeBasis(sublattice).rows()]
#Divides an envelope into a dictionary of cosets by a lattice
def divideIntoCosets(self, envelope):
output = dict()
for v in envelope:
key = CosetMatrix(v, self)
if key in output:
output[key].append(v)
else:
output[key] = [v]
#g.warn("".join(str(k.rep)+": "+str([str(x) for x in v])+"\n\n" for k,v in output.items()))
return output
#A matrix of lattice cosets of the form v+H
class CosetMatrix:
#Constructor
def __init__(self, rep: Matrix, lattice: Lattice):
self.lattice = lattice
self.rep = lattice.getCosetRepresentative(rep)
self.width = self.rep.width
self.height = self.rep.height
#Hashing
def __hash__(self) -> int:
return hash((self.rep))
def __eq__(self, other) -> bool:
return self.rep == other.rep
def __ne__(self, other) -> bool:
return self.rep != other.rep
#Arithmetic
def __add__(self, other) -> bool:
if isinstance(other, CosetMatrix):
return CosetMatrix(self.rep+other.rep, self.lattice)
elif isinstance(other, Matrix):
return CosetMatrix(self.rep+other, self.lattice)
def __sub__(self, other) -> bool:
if isinstance(other, CosetMatrix):
return CosetMatrix(self.rep-other.rep, self.lattice)
elif isinstance(other, Matrix):
return CosetMatrix(self.rep-other, self.lattice)
def __neg__(self) -> bool:
return CosetMatrix(-self.rep, self.lattice)
#Matrix multiplication
#Note: We also multiply the lattice basis
def __mul__(self, other):
return CosetMatrix(self.rep * other, Lattice(self.lattice.basis * other))
def rows(self):
return [CosetMatrix(row, self.lattice) for row in self.rep.rows()]
#A function from Z^n -> int
class LatticeFunction:
def __init__(self, data, dimension):
self.data = data
self.dimension = dimension
self.minCoords = [min(int(key[0,i]) for key,value in self.data.items()) for i in range(self.dimension)]
self.maxCoords = [max(int(key[0,i]) for key,value in self.data.items()) for i in range(self.dimension)]
self.coordDiffs = [x-y for x,y in zip(self.maxCoords, self.minCoords)]
#Convolve using Fourier transform
def convolve(self, other):
#Find amounts to wrap around
#These must be wrapArounds[i] a power of 2 satisfying wrapArounds[i] > self.coordDiffs[i] + other.coordDiffs[i]
#wrapArounds = [1<<(x+y).bit_length() for x,y in zip(self.coordDiffs, other.coordDiffs)]
wrapArounds = [x+y+1 for x,y in zip(self.coordDiffs, other.coordDiffs)]
#return LatticeFunction.unwrapData(LatticeFunction.fft([x*y for x,y in zip(LatticeFunction.fft(self.wrapData(wrapArounds), 1, 1), LatticeFunction.fft(other.wrapData(wrapArounds), 1, 1))], -1, 0.5), wrapArounds, Matrix([self.minCoords])+Matrix([other.minCoords]))
selfData = self.wrapData(wrapArounds)
otherData = other.wrapData(wrapArounds)
g.show("Convolving with length " + str(math.prod(wrapArounds)) + " " + str(tuple(wrapArounds)) + "...")
return LatticeFunction.unwrapData(signal.fftconvolve(selfData, otherData), wrapArounds, Matrix([self.minCoords])+Matrix([other.minCoords]))
#Wraps data to a list, where wrapArounds[i] are our sufficiently large powers of 2
def wrapData(self, wrapArounds):
g.show("Wrapping...")
wrapAroundsCumulative = [math.prod(wrapArounds[0:i]) for i in range(len(wrapArounds)+1)]
output = [0 for x in range(math.prod(wrapArounds))]
#Edit output.data
for key, value in self.data.items():
#Offset by self.minCoords so that indices are all positive
keyIndex = sum(mod(int(key[0,i] - self.minCoords[i]), wrapArounds[i])*wrapAroundsCumulative[i] for i in range(self.dimension))
output[keyIndex] = value
return output
#1-dimensional fast Fourier transform of an array of length 2^n
#Using the Cooley-Tukey algorithm
#I don't actually use this because signal.fftconvolve is faster but it was fun to implement
numFFTs = 0
def fft(data, sign: int = 1, scalePerStep = 1):
outputData = data.copy()
dataSize = len(outputData).bit_length() - 1
#Precompute twiddle factors
g.show("FFT " + str(LatticeFunction.numFFTs+1) + "/12: Computing twiddle factors...")
twiddleFactors = [cmath.exp(-sign * 2j * math.pi * k / (1 << dataSize)) for k in range(1 << dataSize)]
for step in range(0,dataSize):
g.show("FFT " + str(LatticeFunction.numFFTs+1) + "/12: " + str(step) + "/" + str(dataSize))
nextData = []
splitPos = dataSize - step - 1
splitPosMaskBit = 1 << splitPos
belowSplitPosMask = splitPosMaskBit - 1
aboveSplitPosMask = ((1 << (dataSize-1)) - 1) & ~belowSplitPosMask
for i in range(len(outputData)):
#Input indices
#How this works: Take i, split into before and after parts at data-step-1, bitshift after part up 1, insert a 0 or 1 bit
lowerInputIndex = (i & belowSplitPosMask) | ((i & aboveSplitPosMask) << 1)
upperInputIndex = lowerInputIndex | splitPosMaskBit
#Parity
paritySign = 1 - ((i >> (dataSize - 1)) << 1)
#Twiddle factor index
k = i & aboveSplitPosMask
#print(str(step) + ", " + str(i) + ": " + str(lowerInputIndex) + ", " + str(upperInputIndex) + str(" ") + str(k) + ", " + str(twiddleFactor))
nextData.append((outputData[lowerInputIndex] + paritySign * twiddleFactors[k] * outputData[upperInputIndex]) * scalePerStep)
#Progress bar for my sanity
outputData = nextData
g.show("FFT " + str(LatticeFunction.numFFTs) + "/6: " + str(dataSize) + "/" + str(dataSize))
LatticeFunction.numFFTs += 1
return outputData
#Unwrap a list to a LatticeFunction (rounding to ints)
def unwrapData(data, wrapArounds, offset):
g.show("Unwrapping...")
wrapAroundsCumulative = [math.prod(wrapArounds[0:i]) for i in range(len(wrapArounds)+1)]
outputData = {}
for keyIndex in range(len(data)):
if not cmath.isclose(data[keyIndex], 0, rel_tol=1e-09, abs_tol=1e-09):
#Nonzero entry
key = Matrix([[mod(keyIndex // wrapAroundsCumulative[i], wrapArounds[i]) for i in range(len(wrapArounds))]]) + offset
outputData[key] = round(data[keyIndex].real)
return LatticeFunction(outputData, len(wrapArounds))
#Wraps data to a function on a quotient group
def wrapToQuotientFunction(self, group, sign: int = 1):
outputData = {}
for key,value in self.data.items():
quotientKey = CosetMatrix(key * group.optimalLatticeBasis * sign, group.sublattice)
if quotientKey in outputData:
outputData[quotientKey] += value
else:
outputData[quotientKey] = value
return QuotientGroupFunction(group, outputData)
#A quotient of lattices
class QuotientGroup:
def __init__(self, lattice: Lattice, sublattice: Lattice):
#On initialization, organize
self.lattice = lattice
self.sublattice = sublattice
self.generatorsWithTorsions = lattice.quotientGeneratorsWithTorsions(sublattice)
#Find optimal basis for compact unwrapping
# I'm pretty sure this is actually pretty optimal for our purposes
self.optimalLatticeBasis = self.lattice.basis
self.optimalChangeOfBasis = self.optimalLatticeBasis.rightInverse()
#Other thing I considered, seems worse though
#self.optimalLatticeBasis = Matrix([generator.terms[0] for generator, torsion in self.generatorsWithTorsions])
#g.warn(str(self.lattice.basis) + "\n\n" + str(self.sublattice.basis) + "\n\n" + str(self.optimalLatticeBasis))
#A function from G/H -> int
class QuotientGroupFunction:
def __init__(self, group: QuotientGroup, data):
self.group = group
#A dictionary from cosets v+group.sublattice to ints
self.data = data
#Unwraps to a LatticeFunction
def unwrap(self):
return LatticeFunction({key.rep * self.group.optimalChangeOfBasis: self.data[key] for key in self.data}, self.group.optimalChangeOfBasis.width)
#Wraps to a further quotient
def wrapToQuotientFunction(self, group, sign: int = 1):
outputData = {}
for key,value in self.data.items():
quotientKey = CosetMatrix(key.rep * group.optimalLatticeBasis * sign, group.sublattice)
if quotientKey in outputData:
outputData[quotientKey] += value
else:
outputData[quotientKey] = value
return QuotientGroupFunction(group, outputData)
#Function convolution
def convolve(self, other):
return self.unwrap().convolve(other.unwrap()).wrapToQuotientFunction(self.group)
#Golly misc help stuff
#Helpful conversions
def toCellSet(cellList):
return {(cellList[i],cellList[i+1]) for i in range(0,len(cellList),2)}
def toCellList(cellSet):
return [num for x,y in cellSet for num in [x,y]]
#nonempty getrect
def getrect():
if g.empty():
return [0,0,1,1]
return g.getrect()
#This is just convenient
def gethash():
return g.hash(getrect())
def getcells():
return g.getcells(getrect())
#Does the pattern contain a given cell list
def patternContains(cellList, x=0, y=0):
return toCellSet(g.transform(cellList,x,y)).issubset(toCellSet(getcells()))
#Tools for pattern decomposition into components
#For a decomposition of Child(p) = DisjointUnion(q_i)
# Returns a decomposition of this pattern as p = DisjointUnion(p_j) such that Child(p_j) = DisjointUnion(q_{i_{j,k}})
# All inputs and outputs are given as cell sets
nbhd = {(x,y) for x in range(-1,2) for y in range(-1,2)}
def findSubpatterns(patternState, childDecomposition):
#Start by decomposing into connected components
#output = findConnectedComponents(patternState, {(x,y) for x in range(-1,2) for y in range(-1,2)})
output = set()
for cell in patternState:
nbhdOfCell = {(cell[0]+x,cell[1]+y) for x,y in nbhd}
#Check against all children in childDecomposition
requiredCells = {cell}
for childCellSet in childDecomposition:
if not nbhdOfCell.isdisjoint(childCellSet):
#This child's component must contain patternState intersect nbhd(childCellSet)
requiredCells |= patternState & set().union(*[{(a[0]+b[0],a[1]+b[1]) for a in nbhd} for b in childCellSet])
#We require all these cells in our component
componentsToUnionWith = {component for component in output if not requiredCells.isdisjoint(component)}
output -= componentsToUnionWith
output.add(frozenset({cell}.union(*componentsToUnionWith)))
#Additionally, unionize any components around cells that don't match
evolvedState = set().union(*childDecomposition)
evolvedComponentStatesUnion = set().union(*[toCellSet(g.evolve(toCellList(component),1)) for component in output])
error = evolvedState ^ evolvedComponentStatesUnion
for errorCell in error:
nbhdOfCell = {(errorCell[0]+x,errorCell[1]+y) for x,y in nbhd}
#Unionize all components intersecting nbhdOfCell
componentsToUnionWith = {component for component in output if not nbhdOfCell.isdisjoint(component)}
output -= componentsToUnionWith
output.add(frozenset().union(*componentsToUnionWith))
return output
#Removes unneccessary cells from the evolution of this pattern (requiring patFinalState in the final result)
def removeAshCells(patEvolution, patFinalState):
#Find the indepdenent subpatterns of this at each stage
patFinalStateCellSet = frozenset(toCellSet(patFinalState))
patFinalStateCellSetWithExtra = frozenset(toCellSet(g.evolve(patEvolution[len(patEvolution)-1], 1)))
patFinalDecomposition = {patFinalStateCellSet} | {frozenset({cell}) for cell in patFinalStateCellSetWithExtra - patFinalStateCellSet}
patDecompositions = [patFinalDecomposition]
for i in reversed(range(len(patEvolution))):
#Find the prior decomposition
prevDecomposition = findSubpatterns(toCellSet(patEvolution[i]), patDecompositions[0])
patDecompositions.insert(0, prevDecomposition)
#Construct list of only the minimal decompositions leading to patFinalState
minComponents = [patFinalStateCellSet]
for i in reversed(range(len(patEvolution))):
#Need component intersects nbhd(minComponents[0])
try:
prevMinComponent = next(component for component in patDecompositions[i] if not component.isdisjoint(set().union(*[{(a[0]+b[0],a[1]+b[1]) for a in nbhd} for b in minComponents[0]])))
minComponents.insert(0, prevMinComponent)
except StopIteration:
#This only happens when our cell has no predecessors
#This isn't common, but can occur when we add in components mid-evolution
continue
#Convert back to cell lists, remove the last component
return [toCellList(component) for component in minComponents[0:len(minComponents)-1]]
cellLattice = Lattice(Matrix.id(3))
#A periodic pattern with inputs and outputs
class PeriodicPattern:
def __init__(self, cellList, dT, dX, dY, inputs = [], outputs = [], computeExtras = False):
self.dX = dX
self.dY = dY
self.dT = dT
self.inputs = inputs
self.outputs = outputs
self.inputNamesToIndexes = {inputs[i][1]:i for i in range(len(inputs))}
self.outputNamesToIndexes = {outputs[i][1]:i for i in range(len(outputs))}
self.periodVector = Matrix([[self.dT, -self.dX, -self.dY]])
self.periodLattice = Lattice(self.periodVector)
self.positionGroup = QuotientGroup(cellLattice, self.periodLattice)
#Find states
currentState = cellList.copy()
self.state = []
g.setrule("B3/S23")
for t in range(self.dT):
#Remove all outputs on this generation from currentState
#TODO: Could be nice to add a way for outputs to be removed 'late'/after a full cycle
# Or generally for the pattern to 'fill in' over multiple cycles, so that sparks are covered too
for outputPattern, outputName, outputTimeToRemove, outputPosition in outputs:
if outputTimeToRemove == t:
currentState = outputPattern.joinInto(currentState, outputPosition, "andnot")
self.state.append(currentState)
#Join all inputs on this generation to currentState
for inputPattern, inputName, inputTimeToAdd, inputPosition in inputs:
if inputTimeToAdd == t:
currentState = inputPattern.joinInto(currentState, inputPosition, "or")
currentState = g.evolve(currentState, 1)
if computeExtras:
#Precompute some envelopes for collision purposes
g.setrule("B12345678/S012345678")
self.envelopeA = LatticeFunction(dict.fromkeys({Matrix([[t,-x,-y]]) for t in range(self.dT) for x,y in toCellSet(g.evolve(self.state[t],1))}, 1), 3)
g.setrule("B3/S012345678")
self.envelopeB = LatticeFunction(dict.fromkeys({Matrix([[t,-x,-y]]) for t in range(self.dT) for x,y in toCellSet(g.evolve(self.state[t],1))}, 1), 3)
g.setrule("B1/S")
self.envelopeC = LatticeFunction(dict.fromkeys({Matrix([[t,-x,-y]]) for t in range(self.dT) for x,y in toCellSet(g.evolve(self.state[t],1))}, 1), 3)
g.setrule("B2/S")
self.envelopeD = LatticeFunction(dict.fromkeys({Matrix([[t,-x,-y]]) for t in range(self.dT) for x,y in toCellSet(g.evolve(self.state[t],1))}, 1), 3)
g.setrule("B3/S23")
#Find states required for pattern to be restored
#TODO: Also find states required for outputs
# Approach we take: Remove any unnecessary cells (parts that permanently have no influence on the rest of the crawler)
#Fill in crawlerStates
#We iterate twice to prevent pruning ash near the end of the cycle that would collide with the crawler later
#TODO: Most of this is just copy-pasted, I could definitely do this better
extendedState = self.state.copy()
for t in range(self.dT):
#Remove all outputs on this generation from currentState
for outputPattern, outputName, outputTimeToRemove, outputPosition in outputs:
if outputTimeToRemove == t:
currentState = outputPattern.joinInto(currentState, outputPosition + Matrix([[0,self.dX,self.dY]]), "andnot")
extendedState.append(currentState)
#Join all inputs on this generation to currentState
for inputPattern, inputName, inputTimeToAdd, inputPosition in inputs:
if inputTimeToAdd == t:
currentState = inputPattern.joinInto(currentState, inputPosition + Matrix([[0,self.dX,self.dY]]), "or")
currentState = g.evolve(currentState, 1)
#TODO: This is *probably* too strict, since some of the pi-crawler pairs I expected don't show up
self.requiredState = removeAshCells(extendedState, g.transform(self.state[0], self.dX*2, self.dY*2))[0:self.dT]
def getStatePosition(self, position, onlyRequired = False):
if onlyRequired:
return g.transform(self.requiredState[int(position.rep[0,0])], int(position.rep[0,1]), int(position.rep[0,2]))
else:
return g.transform(self.state[int(position.rep[0,0])], int(position.rep[0,1]), int(position.rep[0,2]))
def joinInto(self, cellList, position, mode):
if mode == "or":
return g.join(cellList, self.getStatePosition(position))
elif mode == "andnot":
return toCellList(toCellSet(cellList) - toCellSet(self.getStatePosition(position)))
def place(self, position, mode = "or", onlyRequired = False):
g.putcells(self.getStatePosition(position, onlyRequired),0,0,1,0,0,1, mode)
def placeInput(self, position, index, mode = "or"):
stateT = int(position.rep[0,0])
for inputPattern, inputName, inputTimeToAdd, inputPosition in self.inputs:
indexToUse = index + (1,0)[inputTimeToAdd >= stateT]
inputPattern.place(inputPosition + (position.rep + Matrix([[-inputTimeToAdd, 0, 0]]) - Matrix([[self.dT, -self.dX, -self.dY]]) * indexToUse), mode)
def placeOutput(self, position, index, mode = "or"):
stateT = int(position.rep[0,0])
for outputPattern, outputName, outputTimeToRemove, outputPosition in self.outputs:
indexToUse = index + (1,0)[outputTimeToRemove <= stateT]
outputPattern.place(outputPosition + (position.rep + Matrix([[-outputTimeToRemove, 0, 0]]) + Matrix([[self.dT, -self.dX, -self.dY]]) * indexToUse), mode)
#Place with inputs (and outputs)
def placeWithInputs(self, position, numInputs = 0, numOutputs = 0, mode = "or", onlyRequired = False):
self.place(position, mode, onlyRequired)
for i in range(0,numInputs):
self.placeInput(position, i, mode)
for i in range(0,numOutputs):
self.placeOutput(position, i, mode)
#Test this pattern with inputs (and outputs)
# We only want to test against the minimum envelope required to sustain the component
#TODO: Allow more customizability in input/output testing
def test(self, position, onlyRequired = True):
return patternContains(self.getStatePosition(position, onlyRequired))
def testInput(self, position, index):
stateT = int(position.rep[0,0])
for inputPattern, inputName, inputTimeToAdd, inputPosition in self.inputs:
indexToUse = index + (1,0)[inputTimeToAdd >= stateT]
if not inputPattern.test(inputPosition + (position.rep + Matrix([[-inputTimeToAdd, 0, 0]]) - Matrix([[self.dT, -self.dX, -self.dY]]) * indexToUse)):
return False
return True
def testOutput(self, position, index):
stateT = int(position.rep[0,0])
for outputPattern, outputName, outputTimeToRemove, outputPosition in self.outputs:
indexToUse = index + (1,0)[outputTimeToRemove <= stateT]
if not outputPattern.test(outputPosition + (position.rep + Matrix([[-outputTimeToRemove, 0, 0]]) + Matrix([[self.dT, -self.dX, -self.dY]]) * indexToUse)):
return False
return True
def testWithInputs(self, position, numInputs = 0, numOutputs = 0):
return self.test(position) and all(self.testInput(position,i) for i in range(0, numInputs)) and all(self.testOutput(position,i) for i in range(0, numOutputs))
#Enumerate all possible collisions/interaction separations between two objects
#NOTE: This is optimized for the case where self is small
#TODO: Would probably like to make a version optimized for where self is not small
# I'm not entirely sure how best to do that
def enumerateCollisionSeparations(self, other):
separationLattice = self.periodLattice + other.periodLattice
separationGroup = QuotientGroup(cellLattice, separationLattice)
#Wrapping our envelopes first is probably more efficient
prewrapSelfA = self.envelopeA.wrapToQuotientFunction(separationGroup, -1)
prewrapSelfB = self.envelopeB.wrapToQuotientFunction(separationGroup, -1)
prewrapSelfC = self.envelopeC.wrapToQuotientFunction(separationGroup, -1)
prewrapSelfD = self.envelopeD.wrapToQuotientFunction(separationGroup, -1)
prewrapOtherA = other.envelopeA.wrapToQuotientFunction(separationGroup, 1)
prewrapOtherB = other.envelopeB.wrapToQuotientFunction(separationGroup, 1)
prewrapOtherC = other.envelopeC.wrapToQuotientFunction(separationGroup, 1)
prewrapOtherD = other.envelopeD.wrapToQuotientFunction(separationGroup, 1)
collisionSeparationCosets = set(prewrapSelfA.convolve(prewrapOtherB).data) | set(prewrapSelfB.convolve(prewrapOtherA).data) | set(prewrapSelfC.convolve(prewrapOtherD).data) | set(prewrapSelfD.convolve(prewrapOtherC).data)
#Want to find the first possible absolute separations
#This means, for each separationCoset in collisionSeparationCosets, we want to find the first time resulting in an interaction
#Divide our envelopes into cosets
selfCosetsA = separationLattice.divideIntoCosets(self.envelopeA.data)
selfCosetsB = separationLattice.divideIntoCosets(self.envelopeB.data)
selfCosetsC = separationLattice.divideIntoCosets(self.envelopeC.data)
selfCosetsD = separationLattice.divideIntoCosets(self.envelopeD.data)
otherCosetsA = separationLattice.divideIntoCosets(other.envelopeA.data)
otherCosetsB = separationLattice.divideIntoCosets(other.envelopeB.data)
otherCosetsC = separationLattice.divideIntoCosets(other.envelopeC.data)
otherCosetsD = separationLattice.divideIntoCosets(other.envelopeD.data)
#Find earliest interatction cells for each coset
#Idea:
# Want to understand the space of vectors v such that CosetMatrix(v, self.periodLattice) in selfEnvelope, and CosetMatrix(v + separation, other.periodLattice) in otherEnvelope
# That is, exist m,n such that v + m*self.periodVector in selfEnvelope.reps, v + separation + n*other.periodVector in otherEnvelope.reps
# Have x in selfEnvelope.reps, y in otherEnvelope.reps such that v + m*self.periodVector = x, v + separation + n*other.periodVector = y
# Then x+separation-y = m*self.periodVector - n*other.periodVector
# So [m,-n] = (x+separation-y) * changeOfCoords
# In particular, m = (x+separation-y) * changeOfCoords.col(0)
# Then v = x - self.periodVector * ((x+separation-y) * changeOfCoords.col(0))[0,0]
# Specifically, v[0,0] = x[0,0] - self.periodVector[0,0] * ((x+separation-y) * changeOfCoords.col(0))[0,0]
# = x[0,0] - self.periodVector[0,0] * (x * changeOfCoords.col(0))[0,0] + self.periodVector[0,0] * ((y-separation) * changeOfCoords.col(0))[0,0]
# = x * ([[1],[0],[0]] - changeOfCoords.col(0) * self.periodVector[0,0]) + (y-separation) * changeOfCoords.col(0) * self.periodVector[0,0]
cMulOther = self.periodVector.blockVertical(other.periodVector).rightInverse().col(0) * self.periodVector[0,0]
cMulSelf = Matrix([[1],[0],[0]]) - cMulOther
def findContribs(cosetReps, multiplier):
return {coset: min((rep * multiplier)[0,0] for rep in cosetReps[coset]) for coset in cosetReps}
selfContribsA = findContribs(selfCosetsA, cMulSelf)
selfContribsB = findContribs(selfCosetsB, cMulSelf)
selfContribsC = findContribs(selfCosetsC, cMulSelf)
selfContribsD = findContribs(selfCosetsD, cMulSelf)
otherContribsA = findContribs(otherCosetsA, cMulOther)
otherContribsB = findContribs(otherCosetsB, cMulOther)
otherContribsC = findContribs(otherCosetsC, cMulOther)
otherContribsD = findContribs(otherCosetsD, cMulOther)
#Remark: This is rather slow when self is large
#TODO: Would like a better approach to this
def minContrib(separation, selfContribs, otherContribs):
return min((selfContribs[coset] + otherContribs[coset + separation] for coset in selfContribs if coset + separation in otherContribs), default = math.inf)
for separationCoset in collisionSeparationCosets:
minT = min(minContrib(separationCoset.rep, selfContribsA, otherContribsB),
minContrib(separationCoset.rep, selfContribsB, otherContribsA),
minContrib(separationCoset.rep, selfContribsC, otherContribsD),
minContrib(separationCoset.rep, selfContribsD, otherContribsC)) - (separationCoset.rep * cMulOther)[0,0]
yield [CosetMatrix(Matrix([[minT,0,0]]), self.periodLattice), CosetMatrix(Matrix([[minT,0,0]]) + separationCoset.rep, other.periodLattice)]
#Enumerate interactions between two objects with the same velocity
#NOTE: This is less size-dependent
def enumerateInteractionSeparations(self, other):
separationLattice = self.periodLattice + other.periodLattice
separationGroup = QuotientGroup(cellLattice, separationLattice)
#Wrapping our envelopes first is probably more efficient
prewrapSelfA = self.envelopeA.wrapToQuotientFunction(separationGroup, -1)
prewrapSelfB = self.envelopeB.wrapToQuotientFunction(separationGroup, -1)
prewrapSelfC = self.envelopeC.wrapToQuotientFunction(separationGroup, -1)
prewrapSelfD = self.envelopeD.wrapToQuotientFunction(separationGroup, -1)
prewrapOtherA = other.envelopeA.wrapToQuotientFunction(separationGroup, 1)
prewrapOtherB = other.envelopeB.wrapToQuotientFunction(separationGroup, 1)
prewrapOtherC = other.envelopeC.wrapToQuotientFunction(separationGroup, 1)
prewrapOtherD = other.envelopeD.wrapToQuotientFunction(separationGroup, 1)
collisionSeparationCosets = set(prewrapSelfA.convolve(prewrapOtherB).data) | set(prewrapSelfB.convolve(prewrapOtherA).data) | set(prewrapSelfC.convolve(prewrapOtherD).data) | set(prewrapSelfD.convolve(prewrapOtherC).data)
return [[CosetMatrix(Matrix([[0,0,0]]), self.periodLattice), CosetMatrix(coset.rep, other.periodLattice)] for coset in collisionSeparationCosets]
#TODO: Could make a faster method for self-interactions, since half of the convolutions aren't really required
#Multiple patterns with the same period, with compatible inputs and outputs linked
class CompoundPattern:
def __init__(self, componentsWithPositions, name = ""):
#Members are of the form (component, position)
self.componentsWithPositions = componentsWithPositions
self.periodVector = componentsWithPositions[0][0].periodVector
self.periodLattice = componentsWithPositions[0][0].periodLattice
self.dT = int(self.periodVector[0,0])
self.dX = -int(self.periodVector[0,1])
self.dY = -int(self.periodVector[0,2])
#Figure out all inputs and outputs
self.inputDict = {}
for inputComponent, inputComponentName, inputComponentPosition in self.componentsWithPositions:
for inputPattern, inputName, inputTime, inputPosition in inputComponent.inputs:
if not inputPattern in self.inputDict:
self.inputDict[inputPattern] = {}
combinedLattice = inputPattern.periodLattice + self.periodLattice
#What lane is our input on
inputPositionInCompound = inputPosition + inputComponentPosition.rep - Matrix([[inputTime,0,0]])
inputLane = CosetMatrix(inputPositionInCompound.rep, combinedLattice)
if not inputLane in self.inputDict[inputPattern]:
self.inputDict[inputPattern][inputLane] = []
#Our input time and position in the larger compound pattern
inputTimeInCompoundPattern = mod(inputTime - int(inputComponentPosition.rep[0,0]), self.dT)
inputSpacing = ((inputTime - int(inputComponentPosition.rep[0,0])) - inputTimeInCompoundPattern) // self.dT
inputPositionInCompoundPattern = inputPosition.rep + inputComponentPosition.rep + Matrix([[inputTimeInCompoundPattern - inputTime,0,0]]) + self.periodVector * inputSpacing
self.inputDict[inputPattern][inputLane].append((inputTimeInCompoundPattern, inputPositionInCompoundPattern, inputComponentName+"."+inputName))
self.outputDict = {}
for outputComponent, outputComponentName, outputComponentPosition in self.componentsWithPositions:
for outputPattern, outputName, outputTime, outputPosition in outputComponent.outputs:
if not outputPattern in self.outputDict:
self.outputDict[outputPattern] = {}
combinedLattice = outputPattern.periodLattice + self.periodLattice
#What lane is our output on
outputPositionInCompound = outputPosition + outputComponentPosition.rep - Matrix([[outputTime,0,0]])
outputLane = CosetMatrix(outputPositionInCompound.rep, combinedLattice)
if not outputLane in self.outputDict[outputPattern]:
self.outputDict[outputPattern][outputLane] = []
#Our output time and position in the larger compound pattern
outputTimeInCompoundPattern = mod(outputTime - int(outputComponentPosition.rep[0,0]), self.dT)
outputSpacing = ((outputTime - int(outputComponentPosition.rep[0,0])) - outputTimeInCompoundPattern) // self.dT
outputPositionInCompoundPattern = outputPosition.rep + outputComponentPosition.rep + Matrix([[outputTimeInCompoundPattern - outputTime,0,0]]) + self.periodVector * outputSpacing
self.outputDict[outputPattern][outputLane].append((outputTimeInCompoundPattern, outputPositionInCompoundPattern, outputComponentName+"."+outputName))
#Whole pattern's inputs and outputs
#In same format as PeriodicPattern, to allow for nesting
self.inputs = []
self.outputs = []
self.linkages = []
#Input/output index registration with names
self.name = name
self.inputNamesToIndexes = {}
self.outputNamesToIndexes = {}
def registerInput(inputTimeInCompoundPattern, pattern, inputPositionInCompoundPattern, inputName):
self.inputNamesToIndexes[inputName] = len(self.inputs)
self.inputs.append((pattern, inputName, inputTimeInCompoundPattern, CosetMatrix(inputPositionInCompoundPattern, pattern.periodLattice)))
def registerOutput(outputTimeInCompoundPattern, pattern, outputPositionInCompoundPattern, outputName):
self.outputNamesToIndexes[outputName] = len(self.outputs)
self.outputs.append((pattern, outputName, outputTimeInCompoundPattern, CosetMatrix(outputPositionInCompoundPattern, pattern.periodLattice)))
#Figure out compatible input-output pairs and combine 'em
for pattern in self.inputDict:
if pattern in self.outputDict:
combinedLatticeChangeOfBasis = self.periodVector.blockVertical(pattern.periodVector).rightInverse()
for lane in self.inputDict[pattern]:
if lane in self.outputDict[pattern]:
#Positivity/spacing checks on pairs in the same lane
inputsMinPositiveDisplacements = [(math.inf, -1) for i in range(len(self.inputDict[pattern][lane]))]
outputsMinPositiveDisplacements = [(math.inf, -1) for j in range(len(self.outputDict[pattern][lane]))]
for i in range(len(self.inputDict[pattern][lane])):
inputTimeInCompoundPattern, inputPositionInCompoundPattern, inputName = self.inputDict[pattern][lane][i]
for j in range(len(self.outputDict[pattern][lane])):
outputTimeInCompoundPattern, outputPositionInCompoundPattern, outputName = self.outputDict[pattern][lane][j]
inputPos = inputPositionInCompoundPattern + Matrix([[inputTimeInCompoundPattern,0,0]])
outputPos = outputPositionInCompoundPattern + Matrix([[outputTimeInCompoundPattern,0,0]])
#This is incredibly scuffed and probably incorrect
#TODO: Yeah this is definitely incorrect
displacement = int((inputPos - outputPos)[0,0]) + int(((inputPos - outputPos) * combinedLatticeChangeOfBasis)[0,0]) * self.dT
if displacement >= 0 or True:
#Link up if these are an improvement
if displacement < inputsMinPositiveDisplacements[i][0]:
inputsMinPositiveDisplacements[i] = (displacement, j)
if displacement < outputsMinPositiveDisplacements[j][0]:
outputsMinPositiveDisplacements[j] = (displacement, i)
unboundInputs = set(range(len(self.inputDict[pattern][lane])))
unboundOutputs = set(range(len(self.outputDict[pattern][lane])))
#Register linkages for closest compatible pairs
for i in range(len(self.inputDict[pattern][lane])):
j = inputsMinPositiveDisplacements[i][1]
if j != -1 and outputsMinPositiveDisplacements[j][1] == i:
#i,j is a closest compatible pair
unboundInputs.remove(i)
unboundOutputs.remove(j)
inputTimeInCompoundPattern, inputPositionInCompoundPattern, inputName = self.inputDict[pattern][lane][i]
outputTimeInCompoundPattern, outputPositionInCompoundPattern, outputName = self.outputDict[pattern][lane][j]
self.linkages.append((pattern, inputTimeInCompoundPattern, inputPositionInCompoundPattern, outputTimeInCompoundPattern, outputPositionInCompoundPattern))
#Register unbound inputs and outputs
for i in unboundInputs:
inputTimeInCompoundPattern, inputPositionInCompoundPattern, inputName = self.inputDict[pattern][lane][i]
registerInput(inputTimeInCompoundPattern, pattern, inputPositionInCompoundPattern, inputName)
for j in unboundOutputs:
outputTimeInCompoundPattern, outputPositionInCompoundPattern, outputName = self.outputDict[pattern][lane][j]
registerOutput(outputTimeInCompoundPattern, pattern, outputPositionInCompoundPattern, outputName)
else:
for inputTimeInCompoundPattern, inputPositionInCompoundPattern, inputName in self.inputDict[pattern][lane]:
registerInput(inputTimeInCompoundPattern, pattern, inputPositionInCompoundPattern, inputName)
for lane in self.outputDict[pattern]:
if not lane in self.inputDict[pattern]:
for outputTimeInCompoundPattern, outputPositionInCompoundPattern, outputName in self.outputDict[pattern][lane]:
registerOutput(outputTimeInCompoundPattern, pattern, outputPositionInCompoundPattern, outputName)
else:
for lane in self.inputDict[pattern]:
for inputTimeInCompoundPattern, inputPositionInCompoundPattern, inputName in self.inputDict[pattern][lane]:
registerInput(inputTimeInCompoundPattern, pattern, inputPositionInCompoundPattern, inputName)
for pattern in self.outputDict:
if not pattern in self.inputDict:
for lane in self.outputDict[pattern]:
for outputTimeInCompoundPattern, outputPositionInCompoundPattern, outputName in self.outputDict[pattern][lane]:
registerOutput(outputTimeInCompoundPattern, pattern, outputPositionInCompoundPattern, outputName)
def place(self, position, mode = "or"):
#Place in all components
for component, componentName, componentPosition in self.componentsWithPositions:
component.place(position + componentPosition, mode)
#Place in all linkages
stateT = int(position.rep[0,0])
for pattern, inputTimeInCompoundPattern, inputPositionInCompoundPattern, outputTimeInCompoundPattern, outputPositionInCompoundPattern in self.linkages:
#TODO: These are wrong
inputIndexOffset = (1,0)[inputTimeInCompoundPattern >= stateT]
outputIndexOffset = (0,1)[outputTimeInCompoundPattern <= stateT]
#g.warn(str(inputTimeInCompoundPattern) +", "+str(outputTimeInCompoundPattern) +", "+str(stateT)+"\n\n"+str(inputIndexOffset) + ", "+str(outputIndexOffset))
inputBasePos = inputPositionInCompoundPattern + position.rep - Matrix([[inputTimeInCompoundPattern, 0, 0]])
outputBasePos = outputPositionInCompoundPattern + position.rep - Matrix([[outputTimeInCompoundPattern, 0, 0]])
combinedLatticeChangeOfBasis = self.periodVector.blockVertical(pattern.periodVector).rightInverse()
for index in range(inputIndexOffset, outputIndexOffset + int(((inputBasePos - outputBasePos) * combinedLatticeChangeOfBasis)[0,0])):
pattern.place(CosetMatrix(inputBasePos - Matrix([[self.dT, -self.dX, -self.dY]]) * index, pattern.periodLattice), mode)
def placeInput(self, position, index, mode = "or"):
stateT = int(position.rep[0,0])
for inputPattern, inputName, inputTimeToAdd, inputPosition in self.inputs:
indexToUse = index + (1,0)[inputTimeToAdd >= stateT]
inputPattern.place(inputPosition + (position.rep + Matrix([[-inputTimeToAdd, 0, 0]]) - Matrix([[self.dT, -self.dX, -self.dY]]) * indexToUse), mode)
def placeOutput(self, position, index, mode = "or"):
stateT = int(position.rep[0,0])
for outputPattern, outputName, outputTimeToRemove, outputPosition in self.outputs:
indexToUse = index + (1,0)[outputTimeToRemove <= stateT]
outputPattern.place(outputPosition + (position.rep + Matrix([[-outputTimeToRemove, 0, 0]]) + Matrix([[self.dT, -self.dX, -self.dY]]) * indexToUse), mode)
#Place with inputs (and outputs)
def placeWithInputs(self, position, numInputs = 0, numOutputs = 0, mode = "or"):
self.place(position, mode)
for i in range(0,numInputs):
self.placeInput(position, i, mode)
for i in range(0,numOutputs):
self.placeOutput(position, i, mode)
#Find the minimal offset displacement of pat2 linking an output in one PeriodicPattern (or CompoundPattern) to an input in another
# Plus extraSpacing steps worth of space
def findOffset(pat1, pat1OutputIndex, pat2, pat2InputIndex, extraSpacing = 0):
outputPattern, outputName, outputTimeToRemove, outputPosition = pat1.outputs[pat1OutputIndex]
inputPattern, inputName, inputTimeToAdd, inputPosition = pat2.inputs[pat2InputIndex]
if outputPattern != inputPattern:
g.warn("Pattern mismatch!")
#Want to add and remove in the same generation
return CosetMatrix(Matrix([[inputTimeToAdd - outputTimeToRemove,0,0]]) + outputPosition.rep - inputPosition.rep - outputPattern.periodVector * extraSpacing, pat1.periodLattice)
#A chain with certain spacings
def chain(patternInputOutputSpacingInfo):
periodLattice = patternInputOutputSpacingInfo[0][0].periodLattice
cumulativeOffset = CosetMatrix(Matrix.zero(1,3), periodLattice)
componentsWithPositions = [(patternInputOutputSpacingInfo[0][0], patternInputOutputSpacingInfo[0][1], cumulativeOffset)]
for i in range(len(patternInputOutputSpacingInfo) - 1):
outputComponent, _, _, outputComponentOutputName, _ = patternInputOutputSpacingInfo[i]
inputComponent, inputComponentName, inputComponentInputName, _, extraSpacing = patternInputOutputSpacingInfo[i+1]
outputComponentOutputIndex = outputComponent.outputNamesToIndexes[outputComponentOutputName]
inputComponentInputIndex = inputComponent.inputNamesToIndexes[inputComponentInputName]
addedOffset = CompoundPattern.findOffset(outputComponent, outputComponentOutputIndex, inputComponent, inputComponentInputIndex, extraSpacing)
cumulativeOffset += addedOffset
componentsWithPositions.append((inputComponent, inputComponentName, cumulativeOffset))
return CompoundPattern(componentsWithPositions)
#Automatically add in a collection of components with compatible spacings with certain inputs/outputs to form a loop
def addCompatibleComponents(self, componentsToAddData, selfName = "Main"):
newCompoundPatternComponents = [(self, selfName, CosetMatrix(Matrix.zero(1,3), self.periodLattice))]
for component, componentName, componentInputIndicesToSelfOutputIndices, componentOutputIndicesToSelfInputIndices in componentsToAddData:
#Get constraints
baseOffsets = []
stepDisplacements = []
#We expect exactly 2 of these constraints in total
for componentInputName, selfOutputName in componentInputIndicesToSelfOutputIndices.items():
componentInputIndex = component.inputNamesToIndexes[componentInputName]
selfOutputIndex = self.outputNamesToIndexes[selfOutputName]
baseOffsets.append(CompoundPattern.findOffset(self, selfOutputIndex, component, componentInputIndex).rep)
stepDisplacements.append(component.inputs[componentInputIndex][0].periodVector)
for componentOutputName, selfInputName in componentOutputIndicesToSelfInputIndices.items():
componentOutputIndex = component.outputNamesToIndexes[componentOutputName]
selfInputIndex = self.inputNamesToIndexes[selfInputName]
baseOffsets.append(-CompoundPattern.findOffset(component, componentOutputIndex, self, selfInputIndex).rep)
stepDisplacements.append(component.outputs[componentOutputIndex][0].periodVector)
#Our position must be, for all i, of the form v = baseOffsets[i] + n_i * stepDisplacements[i] + m_i * self.periodVector
# In particular, have 0 = baseOffsets[0] - baseOffsets[1] + n_0 * stepDisplacements[0] - n_1 * stepDisplacements[1] + (m_0-m_1)*self.periodVector
# baseOffsets[1] - baseOffsets[0] = Matrix([[n_0,-n_1,m_0-m_1]]) * BlockVertical(stepDisplacements[0], stepDisplacements[1], self.periodVector)
# (baseOffsets[1] - baseOffsets[0]) * blockMatrixInverse = Matrix([[n_0,-n_1,m_0-m_1]])
# ((baseOffsets[1] - baseOffsets[0]) * blockMatrixInverse.col(0))[0,0] = n_0
n0 = ((baseOffsets[1] - baseOffsets[0]) * stepDisplacements[0].blockVertical(stepDisplacements[1]).blockVertical(self.periodVector).inverse().col(0))[0,0]
v = baseOffsets[0] + stepDisplacements[0] * n0
newCompoundPatternComponents.append((component, componentName, CosetMatrix(v, component.periodLattice)))
return CompoundPattern(newCompoundPatternComponents)
#Conversion from a 1x pattern to an nx pattern
# Basically the only thing this has to do is unfold our inputs and outputs
class PeriodMultipliedPattern:
def __init__(self, pattern, multiplier):
self.pattern = pattern
self.multiplier = multiplier
self.dT = pattern.dT * multiplier
self.dX = pattern.dX * multiplier
self.dY = pattern.dY * multiplier
self.periodVector = pattern.periodVector * multiplier
self.periodLattice = Lattice(self.periodVector)
#Register inputs and outputs
self.inputs = [(inputPat,"Instance"+str(i)+"."+inputName,inputTime+pattern.dT*i, CosetMatrix(inputPosition.rep,self.periodLattice)+Matrix([[0,self.pattern.dX,self.pattern.dY]])*i) for inputPat,inputName,inputTime,inputPosition in pattern.inputs for i in range(multiplier)]
self.outputs = [(outputPat,"Instance"+str(i)+"."+outputName,outputTime+pattern.dT*i, CosetMatrix(outputPosition.rep,self.periodLattice)+Matrix([[0,self.pattern.dX,self.pattern.dY]])*i) for outputPat,outputName,outputTime,outputPosition in pattern.outputs for i in range(multiplier)]
self.inputNamesToIndexes = {self.inputs[i][1]:i for i in range(len(self.inputs))}
self.outputNamesToIndexes = {self.outputs[i][1]:i for i in range(len(self.outputs))}
def place(self, position, mode = "or"):
self.pattern.place(CosetMatrix(position.rep, self.pattern.periodLattice), mode)
def placeWithInputs(self, position, numInputs = 0, numOutputs = 0, mode = "or"):
self.pattern.placeWithInputs(CosetMatrix(position.rep, self.pattern.periodLattice), numInputs*self.multiplier, numOutputs*self.multiplier, mode)
#Automatically add in a collection of components with compatible spacings with certain inputs/outputs to form a loop
def addCompatibleComponents(self, componentsToAddData, selfName = "Main"):
newCompoundPatternComponents = [(self, selfName, CosetMatrix(Matrix.zero(1,3), self.periodLattice))]
for component, componentName, componentInputIndicesToSelfOutputIndices, componentOutputIndicesToSelfInputIndices in componentsToAddData:
#Get constraints
baseOffsets = []
stepDisplacements = []
#We expect exactly 2 of these constraints in total
for componentInputName, selfOutputName in componentInputIndicesToSelfOutputIndices.items():
componentInputIndex = component.inputNamesToIndexes[componentInputName]
selfOutputIndex = self.outputNamesToIndexes[selfOutputName]
baseOffsets.append(CompoundPattern.findOffset(self, selfOutputIndex, component, componentInputIndex).rep)
stepDisplacements.append(component.inputs[componentInputIndex][0].periodVector)
for componentOutputName, selfInputName in componentOutputIndicesToSelfInputIndices.items():
componentOutputIndex = component.outputNamesToIndexes[componentOutputName]
selfInputIndex = self.inputNamesToIndexes[selfInputName]
baseOffsets.append(-CompoundPattern.findOffset(component, componentOutputIndex, self, selfInputIndex).rep)
stepDisplacements.append(component.outputs[componentOutputIndex][0].periodVector)
#Our position must be, for all i, of the form v = baseOffsets[i] + n_i * stepDisplacements[i] + m_i * self.periodVector
# In particular, have 0 = baseOffsets[0] - baseOffsets[1] + n_0 * stepDisplacements[0] - n_1 * stepDisplacements[1] + (m_0-m_1)*self.periodVector
# baseOffsets[1] - baseOffsets[0] = Matrix([[n_0,-n_1,m_0-m_1]]) * BlockVertical(stepDisplacements[0], stepDisplacements[1], self.periodVector)
# (baseOffsets[1] - baseOffsets[0]) * blockMatrixInverse = Matrix([[n_0,-n_1,m_0-m_1]])
# ((baseOffsets[1] - baseOffsets[0]) * blockMatrixInverse.col(0))[0,0] = n_0
n0 = ((baseOffsets[1] - baseOffsets[0]) * stepDisplacements[0].blockVertical(stepDisplacements[1]).blockVertical(self.periodVector).inverse().col(0))[0,0]
v = baseOffsets[0] + stepDisplacements[0] * n0
newCompoundPatternComponents.append((component, componentName, CosetMatrix(v, component.periodLattice)))
return CompoundPattern(newCompoundPatternComponents)
#Settings
g.new("13131")
g.setrule("B3/S23")
g.setalgo("HashLife")
#Basic objects
block = PeriodicPattern(g.parse("2o$2o!",0,0), 1, 0, 0)
blinker = PeriodicPattern(g.parse("3o!",-1,0), 2, 0, 0)
SWGlider = PeriodicPattern(g.parse("bo$o$3o!"), 4, -1, 1)
NWGlider = PeriodicPattern(g.parse("2o$obo$o!"), 4, -1, -1)
NEGlider = PeriodicPattern(g.parse("3o$2bo$bo!"), 4, 1, -1)
SEGlider = PeriodicPattern(g.parse("2bo$obo$b2o!"), 4, 1, 1)
NLWSS = PeriodicPattern(g.parse("3o$o2bo$o$o$bobo!",0,0), 4, 0, -2)
NMWSS = PeriodicPattern(g.parse("3o$o2bo$o$o3bo$o$bobo!",0,0), 4, 0, -2)
NHWSS = PeriodicPattern(g.parse("3o$o2bo$o$o3bo$o3bo$o$bobo!",0,0), 4, 0, -2)
WLWSS = PeriodicPattern(g.parse("bo2bo$o$o3bo$4o!",0,0), 4, -2, 0)
'''
#Helix components
helixComponent1 = PeriodicPattern([],31*16,-1*16,-13*16,
[(NEGlider,"NEGlider0",0,CosetMatrix(Matrix([[0,0,4]]), NEGlider.periodLattice)),
(NLWSS,"NLWSS0",0,CosetMatrix(Matrix([[1,5,1]]), NLWSS.periodLattice)),
(NHWSS,"NHWSS0",8,CosetMatrix(Matrix([[2,12,-1]]), NHWSS.periodLattice))],
[(NEGlider,"NEGlider1",17,CosetMatrix(Matrix([[1,12,-5]]), NEGlider.periodLattice))])
helixComponent2 = PeriodicPattern([],31*16,-1*16,-13*16,
[(NEGlider,"NEGlider0",0,CosetMatrix(Matrix([[3,-1,1]]), NEGlider.periodLattice)),
(NLWSS,"NLWSS0",0,CosetMatrix(Matrix([[1,4,2]]), NLWSS.periodLattice)),
(NLWSS,"NLWSS1",10,CosetMatrix(Matrix([[3,2,7]]), NLWSS.periodLattice))],
[(NWGlider,"NWGlider0",19,CosetMatrix(Matrix([[0,-2,1]]), NWGlider.periodLattice))])
helixComponent3 = PeriodicPattern([],31*16,-1*16,-13*16,
[(NWGlider,"NWGlider0",0,CosetMatrix(Matrix([[2,13,4]]), NWGlider.periodLattice)),
(NLWSS,"NLWSS0",0,CosetMatrix(Matrix([[3,7,2]]), NLWSS.periodLattice)),
(NHWSS,"NHWSS0",8,CosetMatrix(Matrix([[0,0,-2]]), NHWSS.periodLattice))],
[(NWGlider,"NWGlider1",17,CosetMatrix(Matrix([[3,1,-5]]), NWGlider.periodLattice))])
helixComponent4 = PeriodicPattern([],31*16,-1*16,-13*16,
[(NWGlider,"NWGlider0",0,CosetMatrix(Matrix([[0,9,5]]), NWGlider.periodLattice)),
(NHWSS,"NHWSS0",0,CosetMatrix(Matrix([[0,3,0]]), NHWSS.periodLattice)),
(NHWSS,"NHWSS1",7,CosetMatrix(Matrix([[0,9,8]]), NHWSS.periodLattice)),
(NLWSS,"NLWSS0",23,CosetMatrix(Matrix([[2,0,4]]), NLWSS.periodLattice)),
(NLWSS,"NLWSS1",40,CosetMatrix(Matrix([[2,4,3]]), NLWSS.periodLattice))],
[(NEGlider,"NEGlider0",29,CosetMatrix(Matrix([[3,6,-6]]), NEGlider.periodLattice)),
(NWGlider,"NWGlider1",39,CosetMatrix(Matrix([[1,-3,-4]]), NWGlider.periodLattice))])
#TODO: Replace indices with names
helixSpacings = [
(helixComponent1,"H0","","NEGlider1",2),
(helixComponent1,"H1","NEGlider0","NEGlider1",2),
(helixComponent1,"H2","NEGlider0","NEGlider1",2),
(helixComponent1,"H3","NEGlider0","NEGlider1",2),
(helixComponent1,"H4","NEGlider0","NEGlider1",2),
(helixComponent1,"H5","NEGlider0","NEGlider1",2),
(helixComponent1,"H6","NEGlider0","NEGlider1",2),
(helixComponent1,"H7","NEGlider0","NEGlider1",2),
(helixComponent2,"H8","NEGlider0","NWGlider0",2),
(helixComponent3,"H9","NWGlider0","NWGlider1",0),
(helixComponent3,"H10","NWGlider0","NWGlider1",2),
(helixComponent3,"H11","NWGlider0","NWGlider1",2),
(helixComponent3,"H12","NWGlider0","NWGlider1",2),
(helixComponent3,"H13","NWGlider0","NWGlider1",2),
(helixComponent3,"H14","NWGlider0","NWGlider1",2),
(helixComponent3,"H15","NWGlider0","NWGlider1",2),
(helixComponent3,"H16","NWGlider0","NWGlider1",2),
(helixComponent3,"H17","NWGlider0","NWGlider1",2),
(helixComponent4,"H18","NWGlider0","NEGlider0",6),
]
helix = CompoundPattern.chain(helixSpacings)
#helix.placeWithInputs(CosetMatrix(Matrix([[0,0,0]]), helix.periodLattice), 20, 20)
#Fanout components
#TODO: Would be nice to figure these input/output values automatically
fanoutComponent1 = PeriodicPattern([],31*16,-1*16,-13*16,
[(NWGlider,"NWGlider0",0,CosetMatrix(Matrix([[1,1,0]]), NWGlider.periodLattice)),
(NLWSS,"NLWSS0",0,CosetMatrix(Matrix([[3,-5,0]]), NLWSS.periodLattice)),
(NLWSS,"NLWSS1",15,CosetMatrix(Matrix([[1,0,5]]), NLWSS.periodLattice)),
(NLWSS,"NLWSS2",16,CosetMatrix(Matrix([[2,6,4]]), NLWSS.periodLattice))],
[(blinker,"Blinker0",28,CosetMatrix(Matrix([[0,4,7]]), blinker.periodLattice)),
(WLWSS,"WLWSS0",29,CosetMatrix(Matrix([[-1,-7,-3]]), WLWSS.periodLattice))])
fanoutComponent2 = PeriodicPattern([],31*16,-1*16,-13*16,
[(blinker,"Blinker0",0,CosetMatrix(Matrix([[1,2,1]]), blinker.periodLattice)),
(NLWSS,"NLWSS0",0,CosetMatrix(Matrix([[1,2,4]]), NLWSS.periodLattice)),
(NLWSS,"NLWSS1",13,CosetMatrix(Matrix([[0,0,6]]), NLWSS.periodLattice))],
[(NWGlider,"NWGlider0",10,CosetMatrix(Matrix([[-1,1,-2]]), NWGlider.periodLattice))])
fanoutComponent3 = PeriodicPattern([],31*16,-1*16,-13*16,
[(NWGlider,"NWGlider0",0,CosetMatrix(Matrix([[2,7,5]]), NWGlider.periodLattice)),
(NHWSS,"NHWSS0",0,CosetMatrix(Matrix([[0,0,0]]), NHWSS.periodLattice)),
(NMWSS,"NMWSS0",10,CosetMatrix(Matrix([[2,9,9]]), NMWSS.periodLattice))],
[(NWGlider,"NWGlider1",26,CosetMatrix(Matrix([[0,2,-5]]), NWGlider.periodLattice))])
fanoutComponent4 = PeriodicPattern([],31*16,-1*16,-13*16,
[(NWGlider,"NWGlider0",0,CosetMatrix(Matrix([[2,5,0]]), NWGlider.periodLattice)),
(NLWSS,"NLWSS0",0,CosetMatrix(Matrix([[0,6,4]]), NLWSS.periodLattice)),
(NLWSS,"NLWSS1",16,CosetMatrix(Matrix([[3,0,7]]), NLWSS.periodLattice))],
[(blinker,"Blinker0",18,CosetMatrix(Matrix([[1,8,5]]), blinker.periodLattice)),
(NWGlider,"NWGlider1",20,CosetMatrix(Matrix([[3,1,4]]), NWGlider.periodLattice))])
fanoutComponent5 = PeriodicPattern([],31*16,-1*16,-13*16,
[(blinker,"Blinker0",0,CosetMatrix(Matrix([[0,1,0]]), blinker.periodLattice)),
(NLWSS,"NLWSS0",0,CosetMatrix(Matrix([[0,3,2]]), NLWSS.periodLattice)),
(NLWSS,"NLWSS0",9,CosetMatrix(Matrix([[3,7,6]]), NLWSS.periodLattice))],
[(NWGlider,"NWGlider0",23,CosetMatrix(Matrix([[2,6,1]]), NWGlider.periodLattice))])
fanoutComponent6 = PeriodicPattern([],31*16,-1*16,-13*16,
[(blinker,"Blinker0",0,CosetMatrix(Matrix([[0,1,2]]), blinker.periodLattice)),
(NLWSS,"NLWSS0",0,CosetMatrix(Matrix([[1,5,1]]), NLWSS.periodLattice)),
(NMWSS,"NMWSS0",25,CosetMatrix(Matrix([[3,9,3]]), NMWSS.periodLattice))],
[(NWGlider,"NWGlider0",37,CosetMatrix(Matrix([[1,5,-3]]), NWGlider.periodLattice))])
#Extra fanout components for the last track builder (slightly cheaper)
fanoutComponent7 = PeriodicPattern([],31*16,-1*16,-13*16,
[(NWGlider,"NWGlider0",0,CosetMatrix(Matrix([[1,4,0]]), NWGlider.periodLattice)),
(NLWSS,"NLWSS0",0,CosetMatrix(Matrix([[2,6,5]]), NLWSS.periodLattice)),
(NLWSS,"NLWSS1",2,CosetMatrix(Matrix([[2,0,4]]), NLWSS.periodLattice))],
[(blinker,"Blinker0",16,CosetMatrix(Matrix([[1,4,1]]), blinker.periodLattice)),
(NWGlider,"NWGlider1",17,CosetMatrix(Matrix([[1,-1,0]]), NWGlider.periodLattice))])
fanoutComponent8 = PeriodicPattern([],31*16,-1*16,-13*16,
[(blinker,"Blinker0",0,CosetMatrix(Matrix([[0,5,0]]), blinker.periodLattice)),
(NLWSS,"NLWSS0",0,CosetMatrix(Matrix([[2,8,2]]), NLWSS.periodLattice)),
(NLWSS,"NLWSS1",7,CosetMatrix(Matrix([[2,0,3]]), NLWSS.periodLattice))],
[(NWGlider,"NWGlider0",14,CosetMatrix(Matrix([[2,3,2]]), NWGlider.periodLattice))])
trackPairBuilderCollision1 = PeriodicPattern([],31*16,-1*16,-13*16,
[(WLWSS,"WLWSS0",0,CosetMatrix(Matrix([[1,1,-1]]), WLWSS.periodLattice)),
(NWGlider,"NWGlider0",0,CosetMatrix(Matrix([[2,3,5]]), NWGlider.periodLattice)),
(NWGlider,"NWGlider1",79,CosetMatrix(Matrix([[1,6,6]]), NWGlider.periodLattice))],
[(block,"Block0",8,CosetMatrix(Matrix([[0,-3,0]]), block.periodLattice)),
(block,"Block1",85,CosetMatrix(Matrix([[0,2,5]]), block.periodLattice))])
#TODO: Want to be able to 'complete a cycle with available components' when possible
#TODO: Want a slightly different last fanout
# First fanout should have different starting displacement, connect to helix
# Last fanout should not produce 'fanout continuation glider': It's cheaper to use an extra LWSS for period multiplication instead
# In fact, could potentially be even cheaper if we instead fan out into two gliders which support our climbers directly!
def fanoutPatSpacingInfo(n,dn, i, isFirstFanout = False, isLastFanout = False):
startSpacing = 207 + (dn-2)*192 - n * 16
if isFirstFanout:
startSpacing = 38 + n * 16
return [
(fanoutComponent1,"F1,"+str(i),"NWGlider0","Blinker0",startSpacing),
(fanoutComponent2,"F2,"+str(i),"Blinker0","NWGlider0",1 + n*24),
(fanoutComponent3,"F3,"+str(i),"NWGlider0","NWGlider1",50 + n*16),
(fanoutComponent4,"F4,"+str(i),"NWGlider0","Blinker0",47),
(fanoutComponent5,"F5,"+str(i),"Blinker0","NWGlider0",10),
(fanoutComponent4,"F6,"+str(i),"NWGlider0","Blinker0",94),
(fanoutComponent6,"F7,"+str(i),"Blinker0","NWGlider0",10),
]
fanoutDeviceSpacingsList = [3]
for i in range(15-1):
#15/12 is probably not the exact optimal value but it's fine
newN = int(math.ceil(fanoutDeviceSpacingsList[0] * 7 / 6 + 15/12))
fanoutDeviceSpacingsList.insert(0,newN)
fanoutPatSpacings = [(helix,"Helix","","H18.NWGlider1",0)]
for i in range(len(fanoutDeviceSpacingsList)):
if i == 0:
fanoutPatSpacings += fanoutPatSpacingInfo(fanoutDeviceSpacingsList[i], 0, i, True)
else:
fanoutPatSpacings += fanoutPatSpacingInfo(fanoutDeviceSpacingsList[i], fanoutDeviceSpacingsList[i-1] - fanoutDeviceSpacingsList[i], i, False)
#Cheaper last fanout
fanoutPatSpacings += [(fanoutComponent7,"F1,16","NWGlider0","Blinker0",68),(fanoutComponent8,"F2,16","Blinker0","NWGlider0",26)]
fanoutTrackPairBuilderConnections = [(trackPairBuilderCollision1, "T"+str(i), {"WLWSS0":"F1,"+str(i)+".WLWSS0", "NWGlider0":"F4,"+str(i)+".NWGlider1"}, {}) for i in range(15)]
periodDemultiplierCrawlerBlockInputs = [(block, "Block"+str(i), 31*i, CosetMatrix(Matrix([[0,6,-2]]) + Matrix([[0,-1,-13]])*i, block.periodLattice)) for i in range(15)]
periodDemultiplierCrawlerGliderOutputs = [(SWGlider, "SWGlider"+str(i), 22+31*i, CosetMatrix(Matrix([[1,0,3]]) + Matrix([[0,-1,-13]])*i, SWGlider.periodLattice)) for i in range(16)]
periodDemultiplierCrawler = PeriodicPattern(g.parse("2b3o$2bo2bo$bo$4b2o$o3b2o$o$2bo$2b3o$3b2o$4bo$2b2o$bobo$o3bo$2b2o!"),31*16,-1*16,-13*16,
periodDemultiplierCrawlerBlockInputs + [(NWGlider, "NWGlider0", 31*15, CosetMatrix(Matrix([[1,7,-2]]) + Matrix([[0,-1,-13]])*15, NWGlider.periodLattice))],
periodDemultiplierCrawlerGliderOutputs)
periodDemultiplierConnections = [(periodDemultiplierCrawler, "Demultiplier0", {"NWGlider0":"Main.F1,16.NWGlider1","Block0":"T0.Block0"}, {}),
(periodDemultiplierCrawler, "Demultiplier1", {"NWGlider0":"Main.F2,16.NWGlider0","Block0":"T0.Block1"}, {})]
fanoutDevice = CompoundPattern.chain(fanoutPatSpacings).addCompatibleComponents(fanoutTrackPairBuilderConnections).addCompatibleComponents(periodDemultiplierConnections)
#g.warn(str(set(fanoutDevice.outputNamesToIndexes)))
#fanoutDevice.placeWithInputs(CosetMatrix(Matrix([[0,0,0]]), fanoutDevice.periodLattice), 320, 3)
'''
#Crawlers on various objects
#TODO: May want to period-multiply periodic or compound patterns by 16
crawlerSWGliders = [0,0,0]
crawlerSWGliders[0] = PeriodicPattern(g.parse("2b3o$bo2bo$o$b3o3$4b2o$4b2o$5bo$5b2o$b3obob2o$b2o$5bo2bo$5b3o!"), 31, -1, -13,
[(SWGlider,"SWGlider0",24,CosetMatrix(Matrix([[0,6,-14]]), SWGlider.periodLattice))],
[(SWGlider,"SWGlider0",15,CosetMatrix(Matrix([[1,1,4]]), SWGlider.periodLattice))])
crawlerSWGliders[1] = PeriodicPattern(g.parse("2b3o$bo2bo$o$b3o3$4b2o$4b2o$5bo$5b2o$b3obob2o$b2o$5bo2bo$5b3o!"), 31, -1, -13,
[(SWGlider,"SWGlider0",24,CosetMatrix(Matrix([[0,6,-15]]), SWGlider.periodLattice))],
[(SWGlider,"SWGlider0",15,CosetMatrix(Matrix([[1,1,4]]), SWGlider.periodLattice))])
crawlerSWGliders[2] = PeriodicPattern(g.parse("2b3o$bo2bo$o$b3o3$4b2o$4b2o$5bo$5b2o$b3obob2o$b2o$5bo2bo$5b3o!"), 31, -1, -13,
[(SWGlider,"SWGlider0",24,CosetMatrix(Matrix([[1,6,-15]]), SWGlider.periodLattice))],
[(SWGlider,"SWGlider0",15,CosetMatrix(Matrix([[1,1,4]]), SWGlider.periodLattice))])
crawlerNWGliders = PeriodicPattern(g.parse("2b3o$bo2bo$o$b3o3$4b2o$4b2o$5bo$5b2o$b3obob2o$b2o$5bo2bo$5b3o!"), 31, -1, -13,
[(NWGlider,"NWGlider0",24,CosetMatrix(Matrix([[1,7,-14]]), NWGlider.periodLattice))],
[(SWGlider,"SWGlider0",15,CosetMatrix(Matrix([[1,1,4]]), SWGlider.periodLattice))])
crawlerBlocks = PeriodicPattern(g.parse("2b3o$bo2bo$o$b3o3$4b2o$4b2o$5bo$5b2o$b3obob2o$b2o$5bo2bo$5b3o!"), 31, -1, -13,
[(block,"Block0",24,CosetMatrix(Matrix([[0,6,-14]]), block.periodLattice))],
[(SWGlider,"SWGlider0",15,CosetMatrix(Matrix([[1,1,4]]), SWGlider.periodLattice))])
SWGliderStreamLattice = crawlerSWGliders[0].periodLattice + SWGlider.periodLattice
SWGliderStreamLaneChangeOfBasis = -Matrix([x.terms[0] for x,y in Lattice(Matrix.id(3)).quotientGeneratorsWithTorsions(SWGliderStreamLattice)]).inverse().col(2)
#The lane shift a SW glider -> SW glider crawler shifts a glider trail by
crawlerGliderLattice = SWGlider.periodLattice + crawlerSWGliders[0].periodLattice
def getGliderShift(pattern, inputIndex = 0, outputIndex = 0):
inputLane = CosetMatrix((pattern.inputs[inputIndex][3] - Matrix([[pattern.inputs[inputIndex][2],0,0]])).rep, crawlerGliderLattice)
outputLane = CosetMatrix((pattern.outputs[inputIndex][3] - Matrix([[pattern.outputs[inputIndex][2],0,0]])).rep, crawlerGliderLattice)
return outputLane - inputLane
gliderShifts = [int((getGliderShift(crawlerSWGliders[i]).rep * SWGliderStreamLaneChangeOfBasis)[0,0]) for i in range(3)] #[69,42,28]
blockLayerTrackDisplacementGoal = int(((Matrix([[0,-12,-12]]) - Matrix([[0,-15,6]])) * SWGliderStreamLaneChangeOfBasis)[0,0]) #237
#237 = 69 + 42*4
#TODO: Would like to figure out the optimal way to do this automatically
startingShiftSpacings = [(crawlerSWGliders[0],"C0","SWGlider0","SWGlider0",1),
(crawlerSWGliders[1],"C1","SWGlider0","SWGlider0",1),
(crawlerSWGliders[1],"C2","SWGlider0","SWGlider0",1),
(crawlerSWGliders[1],"C3","SWGlider0","SWGlider0",1),
(crawlerSWGliders[1],"C4","SWGlider0","SWGlider0",1)]
startingShifter = CompoundPattern.chain(startingShiftSpacings)
#startingShifter.placeWithInputs(CosetMatrix(Matrix([[0,0,0]]), startingShifter.periodLattice), 10, 10)
#TODO: All three pair-track blocklayers and all three pair-track rephasers (the latter can be compound patterns)
pairTrackBlockLayers = [0,0,0]
pairTrackBlockLayers[0] = PeriodicPattern(g.parse("2b3o$2bo2bo$bo$4b2o$o3b2o$o$2bo$2b3o$3b2o$4bo7b3o$2b2o8bo2bo$bobo6bo4bo$o3bo5bo$2b2o5b2o$10b2obo$12bo5$14b2o2$12bo2bo$11bo$11bo2bo$13bo!"),31,-1,-13,
[(SWGlider,"C0.SWGlider0",0,CosetMatrix(Matrix([[0,6,-2]]), SWGlider.periodLattice)),
(SWGlider,"C1.SWGlider0",20,CosetMatrix(Matrix([[0,16,-3]]), SWGlider.periodLattice))],
[(block,"Block0",2,CosetMatrix(Matrix([[0,11,23]]), block.periodLattice)),
(SWGlider,"C0.SWGlider0",22,CosetMatrix(Matrix([[1,0,3]]), SWGlider.periodLattice)),
(SWGlider,"C1.SWGlider0",11,CosetMatrix(Matrix([[1,11,15]]), SWGlider.periodLattice))])
pairTrackBlockLayers[1] = PeriodicPattern(g.parse("2b3o$2bo2bo$bo$4b2o$o3b2o$o$2bo$2b3o$3b2o$4bo7b3o$2b2o8bo2bo$bobo6bo4bo$o3bo5bo$2b2o5b2o$10b2obo$12bo5$14b2o2$12bo2bo$11bo$11bo2bo$13bo!"),31,-1,-13,
[(SWGlider,"C0.SWGlider0",0,CosetMatrix(Matrix([[0,6,-3]]), SWGlider.periodLattice)),
(SWGlider,"C1.SWGlider0",20,CosetMatrix(Matrix([[0,16,-4]]), SWGlider.periodLattice))],
[(block,"Block0",2,CosetMatrix(Matrix([[0,11,23]]), block.periodLattice)),
(SWGlider,"C0.SWGlider0",22,CosetMatrix(Matrix([[1,0,3]]), SWGlider.periodLattice)),
(SWGlider,"C1.SWGlider0",11,CosetMatrix(Matrix([[1,11,15]]), SWGlider.periodLattice))])
pairTrackBlockLayers[2] = PeriodicPattern(g.parse("2b3o$2bo2bo$bo$4b2o$o3b2o$o$2bo$2b3o$3b2o$4bo7b3o$2b2o8bo2bo$bobo6bo4bo$o3bo5bo$2b2o5b2o$10b2obo$12bo5$14b2o2$12bo2bo$11bo$11bo2bo$13bo!"),31,-1,-13,
[(SWGlider,"C0.SWGlider0",0,CosetMatrix(Matrix([[1,6,-3]]), SWGlider.periodLattice)),
(SWGlider,"C1.SWGlider0",20,CosetMatrix(Matrix([[1,16,-4]]), SWGlider.periodLattice))],
[(block,"Block0",2,CosetMatrix(Matrix([[0,11,23]]), block.periodLattice)),
(SWGlider,"C0.SWGlider0",22,CosetMatrix(Matrix([[1,0,3]]), SWGlider.periodLattice)),
(SWGlider,"C1.SWGlider0",11,CosetMatrix(Matrix([[1,11,15]]), SWGlider.periodLattice))])
pairTrackRephasers = [CompoundPattern([(crawlerSWGliders[i],"C0",CosetMatrix(Matrix([[0,0,0]]),crawlerSWGliders[i].periodLattice)),
(crawlerSWGliders[i],"C1",CosetMatrix(Matrix([[-16,11,-2]]),crawlerSWGliders[i].periodLattice))])
for i in range(3)]
#Block layer input for a NW rake
#Remark: The first of these should be able to be either pairTrackBlockLayer1, 2, or 3
blockLayersForNWRakeSpacings = [[(pairTrackBlockLayers[i],"BlockLayer0","C0.SWGlider0","C0.SWGlider0",4),
(pairTrackRephasers[0],"Rephaser0","C0.SWGlider0","C0.SWGlider0",4),
(pairTrackRephasers[0],"Rephaser1","C0.SWGlider0","C0.SWGlider0",1),
(pairTrackRephasers[0],"Rephaser2","C0.SWGlider0","C0.SWGlider0",1),
(pairTrackRephasers[0],"Rephaser3","C0.SWGlider0","C0.SWGlider0",1),
(pairTrackRephasers[0],"Rephaser4","C0.SWGlider0","C0.SWGlider0",1),
(pairTrackBlockLayers[0],"BlockLayer1","C0.SWGlider0","C0.SWGlider0",1),
(pairTrackBlockLayers[0],"BlockLayer2","C0.SWGlider0","C0.SWGlider0",4)] for i in range(3)]
blockLayersForNWRake = [CompoundPattern.chain(blockLayersForNWRakeSpacings[i]) for i in range(3)]
#NW rake from block input
NWRakeCore = PeriodicPattern(g.parse("2b3o$2bo2bo$bo$4b2o$o3b2o$o$2bo$2b3o$3b2o$4bo$2b2o$bobo$o3bo$2b2o5$9bo$9b2o$7bo2b2o$9b2o$7b3o$8bo8$11bo$10bobo4b2o$9b2o6b2o2$16bo$15bobo$15bobo$16b3o$16b3o$18bo$16b2o!")
,31,-1,-13,
[(block,"Block0",0,CosetMatrix(Matrix([[0,6,-2]]), block.periodLattice)),
(SWGlider,"SWGlider0",11,CosetMatrix(Matrix([[0,7,3]]), SWGlider.periodLattice)),
(block,"Block1",15,CosetMatrix(Matrix([[0,18,15]]), block.periodLattice))],
[(NWGlider,"NWGlider0",18,CosetMatrix(Matrix([[0,4,24]]), NWGlider.periodLattice))])
NWRakeFromBlocksSpacings = [(crawlerBlocks,"C0","Block0","SWGlider0",0),
(NWRakeCore,"R0","SWGlider0","NWGlider0",48)]
NWRakeFromBlocks = CompoundPattern.chain(NWRakeFromBlocksSpacings)
def NWRake(i, internalSpacing):
NWRakeSpacings = [(blockLayersForNWRake[i],"BlockLayer","BlockLayer0.C0.SWGlider0","BlockLayer0.Block0",0),
(NWRakeFromBlocks,"NWRakeFromBlocks","C0.Block0","R0.NWGlider0",internalSpacing+55)]
return CompoundPattern.chain(NWRakeSpacings)
#Component which converts a pair track into an easier-to-destroy single track
pairTrackToSingleTrackCore = PeriodicPattern(g.parse("2b3o$2bo2bo$bo$4b2o$o3b2o$o$2bo$2b3o$3b2o$4bo$2b2o$bobo$o3bo$2b2o!"), 31, -1, -13,
[(SWGlider,"SWGlider0",0,CosetMatrix(Matrix([[1,6,-3]]), SWGlider.periodLattice)),
(SWGlider,"SWGlider1",9,CosetMatrix(Matrix([[0,8,13]]), SWGlider.periodLattice))],
[(SWGlider,"SWGlider0",22,CosetMatrix(Matrix([[1,0,3]]), SWGlider.periodLattice))])
pairTrackToSingleTrackSpacings = [(crawlerSWGliders[0],"C0","SWGlider1","SWGlider0",1),
(crawlerSWGliders[0],"C1","SWGlider0","SWGlider0",1),
(crawlerSWGliders[0],"C2","SWGlider0","SWGlider0",1),
(crawlerSWGliders[0],"C3","SWGlider0","SWGlider0",1),
(crawlerSWGliders[0],"C4","SWGlider0","SWGlider0",1),
(pairTrackToSingleTrackCore,"Core","SWGlider1","SWGlider0",3)]
pairTrackToSingleTrack = CompoundPattern.chain(pairTrackToSingleTrackSpacings)
#Component which terminates a pair track
terminationGliderCollision = PeriodicPattern([],31,-1,-13,
[(SWGlider,"SWGlider0",0,CosetMatrix(Matrix([[0,0,0]]), SWGlider.periodLattice)),
(NWGlider,"NWGlider0",0,CosetMatrix(Matrix([[0,4,3]]), NWGlider.periodLattice))])
pairTrackTermination = CompoundPattern.chain([(NWRake(0,29),"NWRake","BlockLayer.BlockLayer0.C0.SWGlider0","BlockLayer.BlockLayer2.C0.SWGlider0",0),
(pairTrackToSingleTrack,"PairToSingle","Core.SWGlider0","Core.SWGlider0",31)]).addCompatibleComponents(
[(terminationGliderCollision, "Termination", {"SWGlider0":"PairToSingle.Core.SWGlider0","NWGlider0":"NWRake.NWRakeFromBlocks.R0.NWGlider0"}, {})])
#pairTrackTermination.placeWithInputs(CosetMatrix(Matrix([[0,0,0]]), pairTrackTermination.periodLattice), 10, 10)
#Track reset
#Spacings in this version are such that you can immediately construct a pair track without further spacing adjustments
minNWRakeSpacings = [297,298,299]
trackResetStart = CompoundPattern.chain([(NWRake(0,29+minNWRakeSpacings[0]+minNWRakeSpacings[1]+8),"NWRake0","BlockLayer.BlockLayer0.C0.SWGlider0","BlockLayer.BlockLayer2.C0.SWGlider0",0),
(NWRake(1,29+minNWRakeSpacings[0]),"NWRake1","BlockLayer.BlockLayer0.C0.SWGlider0","BlockLayer.BlockLayer2.C0.SWGlider0",3),
(pairTrackTermination,"Termination","Main.NWRake.BlockLayer.BlockLayer0.C0.SWGlider0","",3)])
#trackResetStart.placeWithInputs(CosetMatrix(Matrix([[0,0,0]]), trackResetStart.periodLattice), 100, 100)
trackResetEnd = CompoundPattern([(crawlerNWGliders,"C0",CosetMatrix(Matrix([[0,0,0]]),crawlerNWGliders.periodLattice)),
(crawlerNWGliders,"C1",CosetMatrix(Matrix([[-9,6,17]]),crawlerNWGliders.periodLattice))])
def trackReset(spacing):
return CompoundPattern.chain([(trackResetStart,"Start","NWRake0.BlockLayer.BlockLayer0.C0.SWGlider0","NWRake1.NWRakeFromBlocks.R0.NWGlider0",0),
(trackResetEnd,"End","C0.NWGlider0","C0.SWGlider0",spacing)])
#trackReset(512).placeWithInputs(CosetMatrix(Matrix([[0,0,0]]), trackResetStart.periodLattice), 32, 32)
#NE rake
blockLayersForNERakeSpacings = [[(pairTrackBlockLayers[i],"BlockLayer0","C0.SWGlider0","C0.SWGlider0",4),
(pairTrackRephasers[0],"Rephaser0","C0.SWGlider0","C0.SWGlider0",4),
(pairTrackRephasers[0],"Rephaser1","C0.SWGlider0","C0.SWGlider0",1),
(pairTrackRephasers[0],"Rephaser2","C0.SWGlider0","C0.SWGlider0",1),
(pairTrackRephasers[0],"Rephaser3","C0.SWGlider0","C0.SWGlider0",1),
(pairTrackRephasers[0],"Rephaser4","C0.SWGlider0","C0.SWGlider0",1),
(pairTrackRephasers[0],"Rephaser5","C0.SWGlider0","C0.SWGlider0",1),
(pairTrackBlockLayers[0],"BlockLayer1","C0.SWGlider0","C0.SWGlider0",1),
(pairTrackBlockLayers[1],"BlockLayer2","C0.SWGlider0","C0.SWGlider0",12),
(pairTrackBlockLayers[0],"BlockLayer3","C0.SWGlider0","C0.SWGlider0",4)] for i in range(3)]
blockLayersForNERake = [CompoundPattern.chain(blockLayersForNERakeSpacings[i]) for i in range(3)]
NERakeCore = PeriodicPattern(g.parse("2b3o$2bo2bo$bo$4b2o$o3b2o$o$2bo$2b3o$3b2o$4bo$2b2o$bobo$o3bo$2b2o5$9bo$9b2o$7bo2b2o$9b2o$7b3o$8bo!"),
31,-1,-13,
[(block,"Block0",0,CosetMatrix(Matrix([[0,6,-2]]), block.periodLattice)),
(SWGlider,"SWGlider0",11,CosetMatrix(Matrix([[0,7,3]]), SWGlider.periodLattice))],
[(NWGlider,"NWGlider0",18,CosetMatrix(Matrix([[0,4,24]]), NWGlider.periodLattice)),
(NEGlider,"NEGlider0",20,CosetMatrix(Matrix([[0,16,19]]), NEGlider.periodLattice)),
(blinker,"Blinker0",22,CosetMatrix(Matrix([[0,10,27]]), blinker.periodLattice))])
NERakeBlinkerCleanupKickback = PeriodicPattern(g.parse("2b3o$2bo2bo$bo$4b2o$o3b2o$o$2bo$2b3o$3b2o$4bo$2b2o$bobo$o3bo$2b2o!"),
31,-1,-13,
[(block,"Block0",0,CosetMatrix(Matrix([[0,6,-2]]), block.periodLattice)),
(NWGlider,"NWGlider0",8,CosetMatrix(Matrix([[2,8,4]]), NWGlider.periodLattice))],
[(NEGlider,"NEGlider0",14,CosetMatrix(Matrix([[2,5,4]]), NEGlider.periodLattice)),
(SWGlider,"SWGlider0",22,CosetMatrix(Matrix([[1,0,3]]), SWGlider.periodLattice))])
NERakeTerminator = PeriodicPattern([],31,-1,-13,
[(SWGlider,"SWGlider0",0,CosetMatrix(Matrix([[0,3,0]]), SWGlider.periodLattice)),
(block,"Block0",0,CosetMatrix(Matrix([[0,0,3]]), block.periodLattice))])
NERakeTerminator2 = PeriodicPattern([],31,-1,-13,
[(NEGlider,"NEGlider0",0,CosetMatrix(Matrix([[0,0,4]]), NEGlider.periodLattice)),
(blinker,"Blinker0",0,CosetMatrix(Matrix([[1,3,1]]), blinker.periodLattice))])
NERakeFromBlocksSpacings = [(crawlerBlocks,"C0","Block0","SWGlider0",0),
(NERakeCore,"R0","SWGlider0","NWGlider0",45),
(NERakeBlinkerCleanupKickback,"K0","NWGlider0","SWGlider0",15),
(NERakeTerminator,"T0","SWGlider0","",1)]
NERakeFromBlocks = CompoundPattern.chain(NERakeFromBlocksSpacings).addCompatibleComponents([(NERakeTerminator2,"T1",{"NEGlider0":"K0.NEGlider0","Blinker0":"R0.Blinker0"},{})])
def NERake(i, internalSpacing):
NERakeSpacings = [(blockLayersForNERake[i],"BlockLayer","BlockLayer0.C0.SWGlider0","BlockLayer0.Block0",0),
(NERakeFromBlocks,"NERakeFromBlocks","Main.C0.Block0","Main.R0.NWGlider0",internalSpacing+89)]
return CompoundPattern.chain(NERakeSpacings)
#NERake(0,0).placeWithInputs(CosetMatrix(Matrix([[0,0,0]]), blockLayersForNERake[0].periodLattice), 32, 32)
#SE rake (NW rake with kickback)
blockLayersForSERakeSpacings = [[(pairTrackBlockLayers[i],"BlockLayer0","C0.SWGlider0","C0.SWGlider0",4),
(pairTrackRephasers[0],"Rephaser0","C0.SWGlider0","C0.SWGlider0",4),
(pairTrackRephasers[0],"Rephaser1","C0.SWGlider0","C0.SWGlider0",1),
(pairTrackRephasers[0],"Rephaser2","C0.SWGlider0","C0.SWGlider0",1),
(pairTrackRephasers[0],"Rephaser3","C0.SWGlider0","C0.SWGlider0",1),
(pairTrackRephasers[0],"Rephaser4","C0.SWGlider0","C0.SWGlider0",1),
(pairTrackBlockLayers[0],"BlockLayer1","C0.SWGlider0","C0.SWGlider0",1),
(pairTrackBlockLayers[0],"BlockLayer2","C0.SWGlider0","C0.SWGlider0",4),
(pairTrackBlockLayers[1],"BlockLayer3","C0.SWGlider0","Block0",4)] for i in range(3)]
blockLayersForSERake = [CompoundPattern.chain(blockLayersForSERakeSpacings[i]) for i in range(3)]
SERakeKickback = PeriodicPattern([],31,-1,-13,
[(SWGlider,"SWGlider0",0,CosetMatrix(Matrix([[1,0,-1]]), SWGlider.periodLattice)),
(NWGlider,"NWGlider0",0,CosetMatrix(Matrix([[2,5,1]]), NWGlider.periodLattice))],
[(SEGlider,"SEGlider0",6,CosetMatrix(Matrix([[0,2,0]]), SEGlider.periodLattice))])
def SERake(i, internalSpacing):
NWRakeSpacings = [(blockLayersForSERake[i],"BlockLayer","BlockLayer0.C0.SWGlider0","BlockLayer0.Block0",0),
(NWRakeFromBlocks,"NWRakeFromBlocks","C0.Block0","R0.NWGlider0",internalSpacing+76),
(SERakeKickback,"K0","NWGlider0","SEGlider0",16)]
return CompoundPattern.chain(NWRakeSpacings).addCompatibleComponents([(crawlerBlocks,"C0",{"Block0":"BlockLayer.BlockLayer3.Block0"},{"SWGlider0":"K0.SWGlider0"})])
#SERake(0,0).placeWithInputs(CosetMatrix(Matrix([[0,0,0]]), blockLayersForNERake[0].periodLattice), 32, 32)
#A 16x rake
blockLayersForFilterSpacings = [[(pairTrackBlockLayers[i],"BlockLayer0","C0.SWGlider0","C0.SWGlider0",4),
(pairTrackBlockLayers[1],"BlockLayer1","C0.SWGlider0","C0.SWGlider0",61),
(pairTrackBlockLayers[0],"BlockLayer2","C0.SWGlider0","C0.SWGlider0",4),
(pairTrackRephasers[0],"Rephaser0","C0.SWGlider0","C0.SWGlider0",4),
(pairTrackRephasers[0],"Rephaser1","C0.SWGlider0","C0.SWGlider0",1),
(pairTrackRephasers[0],"Rephaser2","C0.SWGlider0","C0.SWGlider0",1),
(pairTrackBlockLayers[0],"BlockLayer3","C0.SWGlider0","C0.SWGlider0",1),
(pairTrackBlockLayers[0],"BlockLayer4","C0.SWGlider0","C0.SWGlider0",7+6*2),
(pairTrackBlockLayers[1],"BlockLayer5","C0.SWGlider0","C0.SWGlider0",4)] for i in range(3)]
blockLayersForFilter = [CompoundPattern.chain(blockLayersForFilterSpacings[i]) for i in range(3)]
NWRakeFromFilterBlocksSpacings = [(crawlerBlocks,"C0","Block0","SWGlider0",0),
(crawlerSWGliders[0],"C0","SWGlider0","SWGlider0",1),
(crawlerSWGliders[0],"C0","SWGlider0","SWGlider0",1),
(crawlerSWGliders[0],"C0","SWGlider0","SWGlider0",1),
(crawlerSWGliders[0],"C0","SWGlider0","SWGlider0",1),
(crawlerSWGliders[0],"C0","SWGlider0","SWGlider0",1),
(crawlerSWGliders[0],"C0","SWGlider0","SWGlider0",1),
(crawlerSWGliders[0],"C0","SWGlider0","SWGlider0",1),
(crawlerSWGliders[0],"C0","SWGlider0","SWGlider0",1),
(NWRakeCore,"R0","SWGlider0","NWGlider0",15)]
NWRakeFromFilterBlocks = CompoundPattern.chain(NWRakeFromFilterBlocksSpacings)
def Filter(i, internalSpacing):
filterSpacings = [(blockLayersForFilter[i],"BlockLayer","BlockLayer0.C0.SWGlider0","BlockLayer0.Block0",0),
(NWRakeFromFilterBlocks,"FilterFromBlocks","C0.Block0","R0.NWGlider0",internalSpacing+112)]
return CompoundPattern.chain(filterSpacings)
def FilteredSERake1XSupport(parity, color):
filteredRakeSpacings = [(Filter(1,342-color*4+parity),"Filter","BlockLayer.BlockLayer0.C0.SWGlider0","BlockLayer.BlockLayer5.C0.SWGlider0",0),
(SERake(color,parity),"Rake","Main.BlockLayer.BlockLayer0.C0.SWGlider0","Main.BlockLayer.BlockLayer3.C0.SWGlider0",6)]
if color == 1:
filteredRakeSpacings.append((pairTrackRephasers[0],"Rephaser0","C0.SWGlider0","C0.SWGlider0",11))
return CompoundPattern.chain(filteredRakeSpacings)
filterBlockPull = PeriodicPattern([],31*16,-1*16,-13*16,
[(block, "Block"+str(i), 31*i, CosetMatrix(Matrix([[0,0,2]]) + Matrix([[0,-1,-13]])*i, block.periodLattice)) for i in range(15)] +
[(NWGlider, "NWGlider"+str(i), 31*i, CosetMatrix(Matrix([[1,4,0]]) + Matrix([[0,-1,-13]])*i, NWGlider.periodLattice)) for i in range(15)],
[(block, "Block"+str(i), 8+31*i, CosetMatrix(Matrix([[0,2,3]]) + Matrix([[0,-1,-13]])*i, block.periodLattice)) for i in range(15)])
filterGliderTurn = PeriodicPattern(g.parse("2b3o$2bo2bo$bo$4b2o$o3b2o$o$2bo$2b3o$3b2o$4bo$2b2o$bobo$o3bo$2b2o!"),31*16,-1*16,-13*16,
[(block,"Block"+str(i), 31*i, CosetMatrix(Matrix([[0,6,-2]]) + Matrix([[0,-1,-13]])*i, block.periodLattice)) for i in range(16)]+
[(NWGlider,"NWGlider0",6,CosetMatrix(Matrix([[0,5,14]]), NWGlider.periodLattice))],
[(SWGlider,"SWGlider0",10,CosetMatrix(Matrix([[1,5,10]]), SWGlider.periodLattice))]+
[(SWGlider,"ExtraSWGlider"+str(i), 22+31*i, CosetMatrix(Matrix([[1,0,3]]) + Matrix([[0,-1,-13]])*i, SWGlider.periodLattice)) for i in range(16)])
filterGliderTurnTerminator = PeriodMultipliedPattern(PeriodicPattern([],31,-1,-13,
[(SWGlider,"SWGlider0",0,CosetMatrix(Matrix([[2,3,-1]]), SWGlider.periodLattice)),
(block,"Block0",0,CosetMatrix(Matrix([[0,0,3]]), block.periodLattice))]), 16)
#The different glider colors use different reactions here
filterGliderBlockCollisionColor = [PeriodicPattern([],31*16,-1*16,-13*16,
[(block, "Block"+str(i), 31*i, CosetMatrix(Matrix([[0,2,4]]) + Matrix([[0,-1,-13]])*i, block.periodLattice)) for i in range(15)] +
[(SEGlider, "SEGlider"+str(i), 31*i, CosetMatrix(Matrix([[3,-1,-1]]) + Matrix([[0,-1,-13]])*i, SEGlider.periodLattice)) for i in range(15)],[]),
PeriodicPattern([],31*16,-1*16,-13*16,
[(block, "Block"+str(i), 31*i, CosetMatrix(Matrix([[0,3,4]]) + Matrix([[0,-1,-13]])*i, block.periodLattice)) for i in range(15)] +
[(SEGlider, "SEGlider"+str(i), 31*i, CosetMatrix(Matrix([[0,0,0]]) + Matrix([[0,-1,-13]])*i, SEGlider.periodLattice)) for i in range(15)],[])]
#Input timing can be fairly variable in this design
def FilteredSERakeWithoutInput(parity,color):
support = PeriodMultipliedPattern(FilteredSERake1XSupport(parity,color), 16)
return support.addCompatibleComponents([
(filterBlockPull,"BlockPull",{"Block0":"Instance0.Filter.BlockLayer.BlockLayer3.Block0","NWGlider0":"Instance0.Filter.FilterFromBlocks.R0.NWGlider0"},{}),
(filterGliderTurn,"GliderTurn",{"Block0":"Instance8.Filter.BlockLayer.BlockLayer4.Block0","NWGlider0":"Instance0.Filter.FilterFromBlocks.R0.NWGlider0"},{})
]).addCompatibleComponents([
(filterGliderTurnTerminator,"GliderTurnTerminator",{"Instance0.Block0":"Main.Instance0.Filter.BlockLayer.BlockLayer5.Block0","Instance0.SWGlider0":"GliderTurn.ExtraSWGlider0"},{}),
(filterGliderBlockCollisionColor[color],"FilterCollision",{"Block0":"BlockPull.Block0","SEGlider0":"Main.Instance0.Rake.Main.K0.SEGlider0"},{})
])
filteredSERakeWithoutInputCache = [[FilteredSERakeWithoutInput(parity,color) for color in range(2)] for parity in range(2)]
filterInputCollision = PeriodicPattern([],31*16,-1*16,-13*16,
[(SWGlider,"SWGlider0",0,CosetMatrix(Matrix([[1,1,-1]]), SWGlider.periodLattice)),
(block,"Block0",0,CosetMatrix(Matrix([[0,0,4]]), block.periodLattice))])
def FilteredSERake(parity,color,inputTiming):
return CompoundPattern.chain([(filteredSERakeWithoutInputCache[parity][color],"Filter","","Main.Main.Instance15.Filter.BlockLayer.BlockLayer3.Block0",0),
(filterInputCollision,"InputCollision","Block0","",inputTiming+66)])
'''
periodLattice = Lattice(Matrix([[31,1,13]])*16)
FilteredSERake(0,0,239).placeWithInputs(CosetMatrix(Matrix([[0,0,0]]), periodLattice), 16, 16)
FilteredSERake(1,0,240).placeWithInputs(CosetMatrix(Matrix([[0,4096,0]]), periodLattice), 16, 16)
FilteredSERake(0,1,238).placeWithInputs(CosetMatrix(Matrix([[0,4096*2,0]]), periodLattice), 16, 16)
FilteredSERake(1,1,239).placeWithInputs(CosetMatrix(Matrix([[0,4096*3,0]]), periodLattice), 16, 16)
'''
#Pass the filter stream along with our track reset
blockLayersForFilterResetsSpacings = [[(pairTrackBlockLayers[i],"BlockLayer0","C0.SWGlider0","C0.SWGlider0",4),
(pairTrackBlockLayers[1],"BlockLayer1","C0.SWGlider0","C0.SWGlider0",61),
(pairTrackBlockLayers[0],"BlockLayer2","C0.SWGlider0","C0.SWGlider0",4),
(pairTrackRephasers[0],"Rephaser0","C0.SWGlider0","C0.SWGlider0",4),
(pairTrackRephasers[0],"Rephaser1","C0.SWGlider0","C0.SWGlider0",1),
(pairTrackRephasers[0],"Rephaser2","C0.SWGlider0","C0.SWGlider0",1),
(pairTrackBlockLayers[0],"BlockLayer3","C0.SWGlider0","C0.SWGlider0",3)] for i in range(3)]
blockLayersForFilterResets = [CompoundPattern.chain(blockLayersForFilterResetsSpacings[i]) for i in range(3)]
filterResetStart = CompoundPattern.chain([(blockLayersForFilterResets[1],"BlockLayer","BlockLayer0.C0.SWGlider0","BlockLayer0.Block0",0),
(NWRakeFromFilterBlocks,"NWRake","C0.Block0","R0.NWGlider0",1178+128)])
def TrackResetWithFilter1XPart(spacing):
componentSpacings = [(filterResetStart,"FilterResetStart","BlockLayer.BlockLayer0.C0.SWGlider0","BlockLayer.BlockLayer3.C0.SWGlider0",0),
(trackReset(spacing),"TrackReset","Start.NWRake0.BlockLayer.BlockLayer0.C0.SWGlider0","End.C0.SWGlider0",4+3),
(pairTrackBlockLayers[0],"BlockLayer0","C0.SWGlider0","C0.SWGlider0",6),
(pairTrackBlockLayers[0],"BlockLayer1","C0.SWGlider0","C0.SWGlider0",4),
(pairTrackRephasers[0],"Rephaser0","C0.SWGlider0","C0.SWGlider0",4),
(pairTrackRephasers[0],"Rephaser1","C0.SWGlider0","C0.SWGlider0",1),
(pairTrackRephasers[0],"Rephaser1","C0.SWGlider0","C0.SWGlider0",1),
(pairTrackRephasers[0],"Rephaser1","C0.SWGlider0","C0.SWGlider0",1),
(pairTrackRephasers[0],"Rephaser1","C0.SWGlider0","C0.SWGlider0",1),
(pairTrackRephasers[0],"Rephaser1","C0.SWGlider0","C0.SWGlider0",1),
(pairTrackRephasers[0],"Rephaser1","C0.SWGlider0","C0.SWGlider0",1)]
return CompoundPattern.chain(componentSpacings)
filterResetBlockCollision = PeriodicPattern([],31*16,-1*16,-13*16,
[(block, "Block"+str(i), 31*i, CosetMatrix(Matrix([[0,0,0]]) + Matrix([[0,-1,-13]])*i, block.periodLattice)) for i in range(15)] +
[(NWGlider, "NWGlider"+str(i), 31*i, CosetMatrix(Matrix([[3,2,4]]) + Matrix([[0,-1,-13]])*i, NWGlider.periodLattice)) for i in range(15)])
filterGliderTurnTerminator2 = PeriodMultipliedPattern(PeriodicPattern([],31,-1,-13,
[(SWGlider,"SWGlider0",0,CosetMatrix(Matrix([[0,3,0]]), SWGlider.periodLattice)),
(block,"Block0",0,CosetMatrix(Matrix([[0,0,3]]), block.periodLattice))]), 16)
def TrackResetWithFilterNoInput(spacing):
support = PeriodMultipliedPattern(TrackResetWithFilter1XPart(spacing), 16)
#I do not like this: The fact that I have to do this kludge indicates a flaw in my approach here
blockInstance = mod((spacing * 4 + 21) // 31 + 9, 16)
return support.addCompatibleComponents([
(filterResetBlockCollision,"BlockCollision",{"Block0":"Instance0.FilterResetStart.BlockLayer.BlockLayer3.Block0","NWGlider0":"Instance0.FilterResetStart.NWRake.R0.NWGlider0"},{}),
(filterGliderTurn,"GliderTurn",{"Block0":"Instance"+str(blockInstance)+".BlockLayer0.Block0","NWGlider0":"Instance0.FilterResetStart.NWRake.R0.NWGlider0"},{})
]).addCompatibleComponents([
(filterGliderTurnTerminator2,"GliderTurnTerminator",{"Instance0.Block0":"Main.Instance0.BlockLayer1.Block0","Instance0.SWGlider0":"GliderTurn.ExtraSWGlider0"},{})
])
#With variable input position
def TrackResetWithFilter(trackResetSpacing, inputTiming):
return CompoundPattern.chain([
(TrackResetWithFilterNoInput(trackResetSpacing),"TrackReset","","Main.Main.Instance15.FilterResetStart.BlockLayer.BlockLayer3.Block0",0),
(filterInputCollision,"InputCollision","Block0","",inputTiming+66)
])
periodLattice = Lattice(Matrix([[31,1,13]])*16)
TrackResetWithFilter(1024,99).placeWithInputs(CosetMatrix(Matrix([[0,0,0]]), periodLattice), 8, 8)
#TODO: Some of these names are getting really long
#Might be good to be able to rename things
#TODO: Would also be nice to have a function for making trees instead of just chainsNora Brown
- I6_I6
- Posts: 1040
- Joined: July 26th, 2025, 8:44 pm
- Location: Here, there, somewhere, anywhere, everywhere.
- Contact:
Re: 13131: The B-Heptomino/Glider Spaceship Thread
You probably noticed already, but that mechanism is highly adjustable. You can move the 16x gliders around however you want as long as they destroy the correct block and it'll output a glider; that means if the helix period is reduced you could reduce the backrake to <16x.glider_rider wrote: February 13th, 2026, 2:06 pm Alright, here's a prototype 16x backrake:...Code: Select all
[SNIP]
Code: Select all
#C [[ THEME Golly ]]
x = 27, y = 15, rule = LifeHistory
8.A$A6.A.A$3A4.BA2B.B2D$3.A4.2B.2B2DB$2.2A2.3B.6B2.3B$2.20B$4.19B$4.2B
C10BD4B$4.2B2C10BD4B$4.B2C11B2D3B$4.13B2D4B$5.12BD3B.B2A$6.13B3.BA.A$
6.3B.B3.B10.A$25.2A!
- glider_rider
- Posts: 197
- Joined: February 20th, 2013, 5:41 pm
- Location: CA
Re: 13131: The B-Heptomino/Glider Spaceship Thread
Seeing as I'd prefer to avoid having to use edgy slow salvo xWSS constructions on account of those being rather expensive, I've made a filtered NE rake as well:
The output lane of the rake is fixed relative to the lane of the input 16x glider, so in order to make full use of this I'll also need a lane-shifting toolkit for that. However, current technology doesn't allow the 16x glider to change color, so even then this rake would still be color-restricted. I can probably get around that with like a kickback from a SE rake or something, but I'm a bit tired so that's a tomorrow problem.
I have also been considering a potentially simpler approach to duplicating the period-multiplied signal: Namely, reactions like the following.
In most of these the signal is inverted, but that's fine (since some of these inverters work at 1x as well so don't have repeat time concerns.) This would cause the primary track and signal to drift apart over time, and the amount of rephasing work involved means it may not be any more efficient than the current approach, and it's also definitely a lot more 'thinking about it' work than the current approach, but it could be a route to some optimization down the line if anyone wants to do that. (Some of these do also change the signal glider's color, so could help with the issue I mentioned above.)
EDIT:
Much smaller 1x NE rake:
EDIT:
Very slightly smaller 1x SE rake:
(This is specifically smaller in the sense that its footprint on the main block-laying track is smaller, which is probably the most important metric here.)
EDIT: Better filtered NE rake with much more lane adjustability:
EDIT: Another adjustable filtered NE rake design: This is smaller and accepts a much wider range of filter lane inputs, but results in a very large shift in the filter stream.
Code: Select all
x = 2047, y = 6168, rule = B3/S23
2045bo$2043b2o$2044b2o4$2030bo$2028b2o$2029b2o13$2037bo$2037bobo$2037b
2o4$2022bo$2022bobo$2022b2o13$2030bobo$2030b2o$2031bo4$2015bobo$2015b
2o$2016bo12$2024bo$2023bo$2023b3o4$2009bo$2008bo$2008b3o13$2018bo$
2016b2o$2017b2o4$2003bo$2001b2o$2002b2o13$2010bo$2010bobo$2010b2o4$
1995bo$1995bobo$1995b2o13$2003bobo$2003b2o$2004bo4$1988bobo$1988b2o$
1989bo12$1997bo$1996bo$1996b3o4$1982bo$1981bo$1981b3o13$1991bo$1989b2o
$1990b2o4$1976bo$1974b2o$1975b2o13$1983bo$1983bobo$1983b2o4$1968bo$
1968bobo$1968b2o13$1976bobo$1976b2o$1977bo4$1961bobo$1961b2o$1962bo12$
1970bo$1969bo$1969b3o4$1955bo$1954bo$1954b3o13$1964bo$1962b2o$1963b2o
4$1949bo$1947b2o$1948b2o13$1956bo$1956bobo$1956b2o4$1941bo$1941bobo$
1941b2o13$1949bobo$1949b2o$1950bo4$1934bobo$1934b2o$1935bo12$1943bo$
1942bo$1942b3o4$1928bo$1927bo$1927b3o13$1937bo$1935b2o$1936b2o4$1922bo
$1920b2o$1921b2o13$1929bo$1929bobo$1929b2o4$1914bo$1914bobo$1914b2o13$
1922bobo$1922b2o$1923bo4$1907bobo$1907b2o$1908bo12$1916bo$1915bo$1915b
3o4$1901bo$1900bo$1900b3o13$1910bo$1908b2o$1909b2o4$1895bo$1893b2o$
1894b2o13$1902bo$1902bobo$1902b2o4$1887bo$1887bobo$1887b2o13$1895bobo$
1895b2o$1896bo4$1880bobo$1880b2o$1881bo12$1889bo$1888bo$1888b3o4$1874b
o$1873bo$1873b3o13$1883bo$1881b2o$1882b2o4$1868bo$1866b2o$1867b2o13$
1875bo$1875bobo$1875b2o4$1860bo$1860bobo$1860b2o13$1868bobo$1868b2o$
1869bo$1920bo$1920bobo$1920b2o$1853bobo$1853b2o$1854bo12$1862bo$1861bo
$1861b3o4$1847bo$1846bo$1846b3o13$1856bo$1854b2o$1855b2o4$1841bo$1839b
2o$1840b2o13$1848bo$1848bobo$1848b2o4$1833bo$1833bobo$1833b2o13$1841bo
bo$1841b2o$1842bo4$1826bobo$1826b2o$1827bo12$1835bo$1834bo$1834b3o4$
1820bo$1819bo$1819b3o13$1829bo$1827b2o$1828b2o4$1814bo$1812b2o$1813b2o
13$1821bo$1821bobo$1821b2o4$1806bo$1806bobo$1806b2o13$1814bobo$1814b2o
$1815bo4$1799bobo$1799b2o$1800bo12$1808bo$1807bo$1807b3o4$1793bo$1792b
o$1792b3o13$1802bo$1800b2o$1801b2o4$1787bo$1785b2o$1786b2o13$1794bo$
1794bobo$1794b2o4$1779bo$1779bobo$1779b2o13$1787bobo$1787b2o$1788bo4$
1772bobo$1772b2o$1773bo12$1781bo$1780bo$1780b3o4$1766bo$1765bo$1765b3o
13$1775bo$1773b2o$1774b2o4$1760bo$1758b2o$1759b2o13$1767bo$1767bobo$
1767b2o4$1752bo$1752bobo$1752b2o13$1760bobo$1760b2o$1761bo$1812bo$
1812bobo$1812b2o$1745bobo$1745b2o$1746bo12$1754bo$1753bo$1753b3o4$
1739bo$1738bo$1738b3o13$1748bo$1746b2o$1747b2o4$1733bo$1731b2o$1732b2o
13$1740bo$1740bobo$1740b2o4$1725bo$1725bobo$1725b2o13$1733bobo$1733b2o
$1734bo4$1718bobo$1718b2o$1719bo12$1727bo$1726bo$1726b3o4$1712bo$1711b
o$1711b3o13$1721bo$1719b2o$1720b2o4$1706bo$1704b2o$1705b2o13$1713bo$
1713bobo$1713b2o4$1698bo$1698bobo$1698b2o13$1706bobo$1706b2o$1707bo4$
1691bobo$1691b2o$1692bo12$1700bo$1699bo$1699b3o4$1685bo$1684bo$1684b3o
13$1694bo$1692b2o$1693b2o4$1679bo$1677b2o$1678b2o13$1686bo$1686bobo$
1686b2o4$1671bo$1671bobo$1671b2o13$1679bobo$1679b2o$1680bo4$1664bobo$
1664b2o$1665bo12$1673bo$1672bo$1672b3o4$1658bo$1657bo$1657b3o13$1667bo
$1665b2o$1666b2o4$1652bo$1650b2o$1651b2o13$1659bo$1659bobo$1659b2o4$
1644bo$1644bobo$1644b2o13$1652bobo$1652b2o$1653bo$1704bo$1704bobo$
1704b2o$1637bobo$1637b2o$1638bo12$1646bo$1645bo$1645b3o4$1631bo$1630bo
$1630b3o13$1640bo$1638b2o$1639b2o4$1625bo$1623b2o$1624b2o13$1632bo$
1632bobo$1632b2o4$1617bo$1617bobo$1617b2o13$1625bobo$1625b2o$1626bo4$
1610bobo$1610b2o$1611bo12$1619bo$1618bo$1618b3o4$1604bo$1603bo$1603b3o
13$1613bo$1611b2o$1612b2o4$1598bo$1596b2o$1597b2o13$1605bo$1605bobo$
1605b2o4$1590bo$1590bobo$1590b2o13$1598bobo$1598b2o$1599bo4$1583bobo$
1583b2o$1584bo12$1592bo$1591bo$1591b3o4$1577bo$1576bo$1576b3o13$1586bo
$1584b2o$1585b2o4$1571bo$1569b2o$1570b2o13$1578bo$1578bobo$1578b2o4$
1563bo$1563bobo$1563b2o13$1571bobo$1571b2o$1572bo4$1556bobo$1556b2o$
1557bo12$1565bo$1564bo$1564b3o4$1550bo$1549bo$1549b3o13$1559bo$1557b2o
$1558b2o4$1544bo$1542b2o$1543b2o13$1551bo$1551bobo$1551b2o4$1536bo$
1536bobo$1536b2o13$1544bobo$1544b2o$1545bo$1596bo$1596bobo$1596b2o$
1529bobo$1529b2o$1530bo12$1538bo$1537bo$1537b3o4$1523bo$1522bo$1522b3o
13$1532bo$1530b2o$1531b2o4$1517bo$1515b2o$1516b2o13$1524bo$1524bobo$
1524b2o4$1509bo$1509bobo$1509b2o13$1517bobo$1517b2o$1518bo4$1502bobo$
1502b2o$1503bo12$1511bo$1510bo$1510b3o4$1496bo$1495bo$1495b3o13$1505bo
$1503b2o$1504b2o4$1490bo$1488b2o$1489b2o13$1497bo$1497bobo$1497b2o4$
1482bo$1482bobo$1482b2o13$1490bobo$1490b2o$1491bo4$1475bobo$1475b2o$
1476bo12$1484bo$1483bo$1483b3o4$1469bo$1468bo$1468b3o13$1478bo$1476b2o
$1477b2o4$1463bo$1461b2o$1462b2o13$1470bo$1470bobo$1470b2o4$1455bo$
1455bobo$1455b2o13$1463bobo$1463b2o$1464bo4$1448bobo$1448b2o$1449bo12$
1457bo$1456bo$1456b3o4$1442bo$1441bo$1441b3o13$1451bo$1449b2o$1450b2o
4$1436bo$1434b2o$1435b2o13$1443bo$1443bobo$1443b2o4$1428bo$1428bobo$
1428b2o13$1436bobo$1436b2o$1437bo$1488bo$1488bobo$1488b2o$1421bobo$
1421b2o$1422bo12$1430bo$1429bo$1429b3o4$1415bo$1414bo$1414b3o13$1424bo
$1422b2o$1423b2o4$1409bo$1407b2o$1408b2o13$1416bo$1416bobo$1416b2o4$
1401bo$1401bobo$1401b2o13$1409bobo$1409b2o$1410bo4$1394bobo$1394b2o$
1395bo12$1403bo$1402bo$1402b3o4$1388bo$1387bo$1387b3o13$1397bo$1395b2o
$1396b2o4$1382bo$1380b2o$1381b2o13$1389bo$1389bobo$1389b2o4$1374bo$
1374bobo$1374b2o13$1382bobo$1382b2o$1383bo4$1367bobo$1367b2o$1368bo12$
1376bo$1375bo$1375b3o4$1361bo$1360bo$1360b3o13$1370bo$1368b2o$1369b2o
4$1355bo$1353b2o$1354b2o13$1362bo$1362bobo$1362b2o4$1347bo$1347bobo$
1347b2o13$1355bobo$1355b2o$1356bo4$1340bobo$1340b2o$1341bo12$1349bo$
1348bo$1348b3o4$1334bo$1333bo$1333b3o13$1343bo$1341b2o$1342b2o4$1328bo
$1326b2o$1327b2o13$1335bo$1335bobo$1335b2o4$1320bo$1320bobo$1320b2o13$
1328bobo$1328b2o$1329bo$1380bo$1380bobo$1380b2o$1313bobo$1313b2o$1314b
o12$1322bo$1321bo$1321b3o4$1307bo$1306bo$1306b3o13$1316bo$1314b2o$
1315b2o4$1301bo$1299b2o$1300b2o13$1308bo$1308bobo$1308b2o4$1293bo$
1293bobo$1293b2o13$1301bobo$1301b2o$1302bo4$1286bobo$1286b2o$1287bo12$
1295bo$1294bo$1294b3o4$1280bo$1279bo$1279b3o13$1289bo$1287b2o$1288b2o
4$1274bo$1272b2o$1273b2o13$1281bo$1281bobo$1281b2o4$1266bo$1266bobo$
1266b2o13$1274bobo$1274b2o$1275bo4$1259bobo$1259b2o$1260bo12$1268bo$
1267bo$1267b3o4$1253bo$1252bo$1252b3o13$1262bo$1260b2o$1261b2o4$1247bo
$1245b2o$1246b2o13$1254bo$1254bobo$1254b2o4$1239bo$1239bobo$1239b2o13$
1247bobo$1247b2o$1248bo4$1232bobo$1232b2o$1233bo12$1241bo$1240bo$1240b
3o4$1226bo$1225bo$1225b3o13$1235bo$1233b2o$1234b2o4$1220bo$1218b2o$
1219b2o13$1227bo$1227bobo$1227b2o4$1212bo$1212bobo$1212b2o13$1220bobo$
1220b2o$1221bo$1272bo$1272bobo$1272b2o$1205bobo$1205b2o$1206bo12$1214b
o$1213bo$1213b3o4$1199bo$1198bo$1198b3o13$1208bo$1206b2o$1207b2o4$
1193bo$1191b2o$1192b2o13$1200bo$1200bobo$1200b2o4$1185bo$1185bobo$
1185b2o13$1193bobo$1193b2o$1194bo4$1178bobo$1178b2o$1179bo12$1187bo$
1186bo$1186b3o4$1172bo$1171bo$1171b3o$1167b3o$1167bo2bo$1166bo$1169b2o
$1165bo3b2o$1165bo$1167bo$1167b3o$1168b2o$1169bo7b3o$1167b2o8bo2bo$
1166bobo6bo4bo$1165bo3bo5bo$1167b2o5b2o$1175b2obo$1177bo4$1164bo$1164b
obo12b2o$1164b2o$1177bo2bo$1176bo$1176bo2bo$1178bo9$1172bobo$1172b2o$
1173bo3b2o$1177b2o3$1157bobo$1157b2o$1158bo7$1178b2o$1178b2o4$1166bo$
1165bo$1165b3o4$1151bo$1150bo$1150b3o26b2o$1179b2o12$1160bo19b2o$1158b
2o20b2o$1159b2o4$1145bo$1143b2o$1144b2o5$1181b2o$1181b2o7$1152bo$1152b
obo$1152b2o3$1182b2o$1137bo44b2o$1137bobo$1137b2o10$1183b2o$1183b2o2$
1145bobo$1145b2o$1146bo4$1130bobo$1130b2o$1131bo2$1184b2o$1184b2o9$
1139bo$1138bo$1138b3o$1185b2o$1185b2o2$1124bo$1123bo$1123b3o8$1186b2o$
1186b2o4$1133bo$1131b2o$1132b2o4$1118bo$1116b2o$1117b2o68b2o$1187b2o
12$1109bo15bo62b2o$1108b3o14bobo60b2o$1107bo2b2o13b2o2$1106b2o$1106b2o
$1105bo2bo$1107b3o9b3o$1118bo2bo$1118bo3bo$1119b4o$1121bo2$1113b2o74b
2o$1113bobo73b2o$1114b3o$1118bob2o$1118bob2o$1119b3o3$1118bo$1117bo$
1117b3o2$1100bo$1099b3o88b2o$1098b2obo88b2o$1097bo2bo17b2o$1098b2o18b
2o$1099bo2$1101b2o7b3o$1103bo6bo2bo$1110bo2bo$1099bo2bobo6bo2bo$1098bo
b3ob2o5bo2bo$1098bob2ob2obo2b2o$1102bob3o2b2o$1102b4o2bo3bo78b2o$1103b
o4b2o81b2o$1107bo11b2o$1108bo3bo6b2o$1109b3o$1164bo$1164bobo$1164b2o2$
1091b2ob2o$1090bo6bo$1090b2o4bo12b2o$1109b2o$1092bo2bo96b2o$1093b2o97b
2o$1090b2o10b3o15b2o$1090b3o8bo2bo15b2o$1091bo9bo3bo$1090b2ob2o9b2o$
1090b2ob2o7bobo$1090bo3bo4bo2b2o84b3o$1090bo3bo5bo2bo83bo2bo$1093bo9bo
83bo4bo$1100b2ob2o$1101bobo6b2o80bo$1102bo7b2o79bo$1187bob2o$1085bo
100bo2bo$1084b3o34b2o65b2o$1083b2obo34b2o62bo2bo$1082bo2bo99bo$1083b2o
11b3o90bo$1084bo11bo2bo86bo$1096bob2o87b3o$1086b2o$1088bo$1182b3o$
1084bo2bobo8b2o11b2o69bo2bo$1083bob3obo6b4o11b2o68bo3bo$1083bob2ob3o4b
o2bo82bobob2o$1087bobo5bobo84b2ob2o$1087b3o5bobo24b2o59b3o$1088bo33b2o
$1079bo$1078b3o14bo$1077bo2b2o13bobo$1095b2o84bob2o$1076b2o12b3o87bobo
bo$1076b2o11bo2bo88bo$1075bo2bo10bo3bo$1077b3o8b2o2bo19b2o$1090bo21b2o
$1091b2o83b2ob2o$1091b3o81bo6bo$1091b3o29b2o50b2o4bo$1123b2o$1177bo2bo
$1090b2o86b2o$1089b2obo82b2o$1073bo14bo3bo82b3o$1072b3o14bo86bo$1071b
2o2bo99b2ob2o$1072b5o98b2ob2o$1072b5o36b2o60bo3bo$1073bo14bo24b2o60bo
3bo$1071bobo13bo90bo$1070bob2o9b3ob3o$1070bobo10bo2bo37b2o$1069b3o10bo
41b2o$1069bobo13b2o$1070b4o7bo3b2o83bo$1071b3o7bo87b3o$1072bo10bo84b2o
bo$1083b3o81bo2bo$1084b2o82b2o$1077bo7bo83bo$1076bobo35b2o$1076b2o36b
2o55b2o$1076b2o4bo90bo$1081b3o$1081bo2b3o38b2o42bo2bobo$1083bo2bo38b2o
41bob3obo$1083b3o82bob2ob3o$1084bo87bobo$1172b3o$1080bo92bo$1080bobo
81bo$1080b2o81b3o$1162bo2b2o$1115b2o$1082b2o31b2o44b2o$1065bo16b2o77b
2o$1065bobo92bo2bo$1065b2o59b2o34b3o$1126b2o8$1116b2o40bo$1083b2o31b2o
39b3o$1083b2o71b2o2bo$1157b5o$1073bobo51b2o28b5o$1073b2o52b2o29bo$
1074bo81bobo$1155bob2o$1155bobo$1154b3o$1058bobo93bobo$1058b2o95b4o$
1059bo96b3o$1117b2o38bo$1084b2o31b2o$1084b2o$1152bo$1128b2o21b3o$1128b
2o20bo2b2o$1150bo3bo$1151b2obo$1153b2o3$1067bo$1066bo$1066b3o49b2o29bo
2b2o$1085b2o31b2o29bobobo$1085b2o63bo2$1052bo76b2o$1051bo77b2o$1051b3o
92bob2obo$1145b3ob2o$1144b2ob4o$1147b2o$1147b2o$1147b2o$1144bo$1119b2o
23b2o$1086b2o31b2o24bobo$1086b2o57bo2bo$1145bobo$1130b2o13b3o$1130b2o
12bob2o$1061bo82bo2bo$1059b2o85bo$1060b2o4$1046bo91b3o$1044b2o74b2o15b
o2bo$1045b2o40b2o31b2o14bo$1087b2o48b3o2$1131b2o$1131b2o7b2o$1140b2o$
1141bo$1141b2o$1137b3obob2o$1137b2o$1141bo2bo$1141b3o$1121b2o$1053bo
34b2o31b2o$1053bobo32b2o$1053b2o$1132b2o$1132b2o$1035bo$1033b2ob2o$
1033b2o99bobo$1033b2ob2o96b2o$1135bo2$1036b2o$1036b2o7b3o74b2o$1044bo
2bo41b2o31b2o$1038bo5bo3bo40b2o$1033b2ob2obo7b2o$1033b2o4b2o4bobo85b2o
$1036b2ob2obo2b2o86b2o$1038bo4bo2bo$1046bo$1043b2ob2o$1044bobo$1045bo
3$1123b2o$1031bo58b2o31b2o$1030bo59b2o28bo7bo$1030b3o86b3o5bo$1026b3o
15b2o72bo2b2o4b3o4b2o$1026bo2bo14b2o72b2ob2o11b2o$1025bo91b3o$1028b2o
88b2obo$1024bo3b2o89bo2bo$1024bo94bo$1026bo93bobo$1026b3o92bo$1027b2o$
1028bo7b3o79b3o$1026b2o8bo2bo51b2o25b2obo$1025bobo6bo4bo51b2o24bob2o$
1024bo3bo5bo$1026b2o5b2o10b2o88b2o$1034b2obo7b2o88b2o$1036bo$1119bo$
1119bo5b3o$1123bo3bo$1023bo99bo3bo$1023bobo12b2o86bo$1023b2o99b2o$
1036bo2bo$1035bo56b2o$1035bo2bo53b2o$1017b3o17bo$1016bo2bo26b2o$1016bo
3bo25b2o$1017b4o$1019bo108bo$1127bobo4b2o$1028b3o95bo2bo4b2o$1027bo2bo
88b2o6bo$1027bo2bo88bobo$1015b2ob2o6bo2bo89bo12b3o$1015b3obo7b3o102bob
o$1027b2o7b2o55b2o$1036b2o55b2o18bo20b2o$1031bo80b2o18bob2o$1016bo14bo
15b2o63bobo18bo$1015bo16bo14b2o$1011b3ob3o10b2obo$1011bo2bo12bo$1010bo
18bo4bo70b3o$1013b2o90bo$1009bo3b2o16bobo72bo$1009bo21b3o$1011bo10b3o$
1011b3o8bo2bo73b2o$1012b2o8bob2o11b2o55b2o2b2o$1013bo6b2o15b2o55b2o4bo
$1011b2o7b2o$1010bobo6bo2bo25b2o$1009bo3bo9bo24b2o$1011b2o8b3o$1022bo
4$1005bo$1003b2ob2o$1003b2o$1003b2ob2o30b2o$1016b3o19b2o57b2o$1015bo2b
o78b2o$1006b2o7bo4bo28b2o$1006b2o41b2o$1020bo$1008bo10bo$1003b2ob2obo
5bob2o53b2o$1003b2o4b2o3bo2bo53b2o$1006b2ob2o5b2o27b3o25bo$1008bo4bo2b
o28bo2bo$1013bo31bob2o$1017bo$999bo14bo24b2o$998b3o14b3o21b2o57b2o$
997b2o2bo45b2o49b2o$997bo47b4o$996b2o12b3o31bo2bo$995bo14bo2bo30bobo$
995b4o10bo3bo30bobo$997b2o10bobob2o$1010b2ob2o$1011b3o30bo$1044bobo$
1044b2o2$1040b2o$1009bob2o27b2o57b2o$1008bobobo86b2o$993bo15bo$992b3o
7bo$991bo2b2o6bo$995bo$993b3o12bo$992bob2o12bobo$991b2obo13b2o$993b2o
8b3o$990b2obo8bo2bo$990b2ob2o7bo3bo$990b2ob2o6b2o2bo$992bo10bo$1004b2o
$1004b3o$1004b3o$997b2o$996bo2bo$997bo3bo$997b5o$999b2ob2o$1002bo2b2o$
1003b3o$1004bo2$1001bo99b2o$984bo15bo100b2o$983b3o14b3o$982b2o2bo$982b
o$981b2o12b3o$980bo14bo2bo3b2o$980b4o10bo3bo3b2o$982b2o10bobob2o$995b
2ob2o$996b3o3$1102b2o$1102b2o$994bob2o$993bobobo$978bo15bo$977b3o7bo$
976bo2b2o6bo15b2o$980bo22b2o$978b3o8b2ob2o$977bob2o7bo6bo$976b2obo8b2o
4bo$978b2o$975b2obo11bo2bo$975b2ob2o11b2o110b2o$975b2ob2o8b2o113b2o$
977bo10b3o$989bo$988b2ob2o$988b2ob2o$988bo3bo11b2o$972bo15bo3bo11b2o$
971b3o17bo$970b2o2bo$972b3o3$983bo120b2o$974bo7b3o15b3o101b2o$971bo9b
2obo15bo2bo$970bo3bo5bo2bo16bo2bo$969b2ob2o7b2o18bo2bo$982bo18bo2bo$
999b2o$984b2o13b2o$971bo14bo11bo3bo$969b2o27b2o$966bo3b2o10bo2bobo9bo$
965b3o13bob3obo10bo3bo$964bo2b2o12bob2ob3o10b3o$964b2ob2o16bobo117b2o$
963b3o19b3o117b2o$964b2obo18bo$965bo2bo8bo$965bo10b3o$966bobo6bo2b2o$
967bo$974b2o$964b3o7b2o$964b2obo5bo2bo$963bob2o8b3o3$1106b2o$1106b2o$
959bo$958bobo$957b2ob2o$958bob2o$971bo21bobo$970b3o20b2o$960b2o7b2o2bo
20bo$960bo9b5o$970b5o$963bo7bo$957b2ob2obo5bobo$957b2ob2ob2o3bob2o135b
2o$961bobo4bobo136b2o$962bo4b3o$967bobo$968b4o$969b3o$952b3o15bo$952bo
2bo$950bo4bo$950bo14bo$949b2o13b3o$950b2obo9bo2b2o$952bo10bo3bo$964b2o
bo19bo120b2o$966b2o18bo121b2o$954bobo29b3o$954bobo2$953bo$962bo2b2o$
962bobobo$963bo$946b3o6bobo$945bo2bo7bo$945bo3bo$948b2o12bobo$946bobo
13b2o145b2o$943bo2b2o15bo145b2o$944bo2bo10bo$947bo9b3o$944b2ob2o7b2o2b
o$945bobo8bo3bo$946bo9bobo2$957b2ob2o19bo$959bo19b2o$951b2o27b2o$951bo
bo$951b2o2bo$952b4o154b2o$956b2o2bo149b2o$956bo2bo$957b3o3$956bo$954b
2o$955b2o4$941bo14b2o$939b2o15b2o153b2o$940b2o169b2o2$973bo$973bobo$
973b2o7$957b2o$957b2o153b2o$948bo163b2o$948bobo$948b2o$931bo$930b3o$
929bo2b2o$928b5o$928bo2b2o$928bo2bo$929bobo$941b3o22bobo$940bo2bo14b2o
6b2o$933b2o5bo4bo12b2o7bo145b2o$932b4o177b2o$930bo3b2o9bo$931b2o3bo7bo
$937bob2ob2o$936bo5bo$933b2o6b2o$933b2o6bo$938bo$942bo11b3o$939bo14bo
2bo$940b3o11bob2o$952b2o$952b2o160b2o$951bo2bo159b2o$922bo32bo$921bobo
29b3o$921bobo16b2o12bo$921b3o16b2o16b3o$922bo2bo32bo2bo$922bo36b2o$
925bo$923b2o$923b3o6b3o$924b2o6bo2bo$920b2o2bobo5bob2o$920b2o2bobo3b2o
183b2o$924b3o3b2o183b2o$929bo2bo$933bo$931b3o7b2o$932bo8b2o$967bo2bo$
966bo3bo$966bo4bo$961bo7b2o$918bo42bo3b2o$918bobo44bo$918b2o42bo3b2o$
913b3o15b2o24b2o2bo3b2o10b2o$912bo2bo15b2o25b2o3b3o10bobo$912bo3bo42b
6o13bo$911b2o2bo44bo$913bo$914b2o22bo12b2o33bo$914b3o7b3o10bobo11bobo
32b2o$914b3o6bo2bo9b2ob2o10bo33bobo$923bo2bo10bob2o2$913b2o7b2o21bo$
912b2obo5bo2bo14b2o3b2o48b3o$911bo3bo5bo2bo14bo4bobo49bo$912bo11bo7b2o
61bo121b2o$932b2o8bo174b2o$936b2ob2obo20b3o$936b2ob2ob2o59b2o$907bo32b
obo5b3o53b2o$906bobo32bo8bo52bo$906bobo40bo$906b3o$907bo2bo101b2o$907b
o10b3o36b2o52bobo$910bo7bo2bo36b2o53bo$908b2o8bo2bo35bo$908b3o8bo2bo$
909b2o8bo2bo98bo96b2o$905b2o2bobo5b2o102b2o95b2o$905b2o2bobo5b2o101bob
o$909b3o4bo3bo$916b2o$915bo$916bo3bo108b3o$917b3o45bo65bo$901bo63bobo
62bo$900b3o62b2o$899bo2b2o$898b5o135b2o$898bo2b2o9b3o124b2o$898bo2bo9b
o2bo123bo80b2o$899bobo9bo3bo203b2o$912b4o$914bo132b2o$903b2o141bobo$
902b3o143bo$900bo$901b2o$910b2ob2o141bo$910b3obo141b2o$903bobo149bobo$
895bo7bobo$894b3o7bo$893b2o2bo13bo208b2o$894b4o12bo153b3o53b2o$892bobo
11b3ob3o153bo$891bo2bo11bo2bo155bo$892b3o10bo$893bobo12b2o$893bobo8bo
3b2o163b2o$893b3o8bo169b2o$906bo166bo$906b3o$907b2o$908bo173b2o$906b2o
173bobo$905bobo175bo37b2o$889bo14bo3bo212b2o$888b3o15b2o$887bo2b2o199b
o$1091b2o$1090bobo2$890b2o8bo$888b3o7b2ob2o$887bo10b2o199b3o$887b3o8b
2ob2o198bo$888b2o210bo2$901b2o219b2o$887bobo11b2o205b2o12b2o$887b2o
220b2o$888bo14bo204bo$883bo14b2ob2obo$882b3o13b2o4b2o$881b2o2bo15b2ob
2o211b2o$881bo3bo17bo212bobo$881bobo234bo2$882b2ob2o7bo$884bo8b3o$892b
2o2bo$892bo$891b2o$881b4o5bo$880bobobo5b4o$881bo10b2o4$876bo$875bobo2b
2o$875b2o$876bo$878b2o$876b4o8bo$875bo2bo8b3o7bo$877bo8bo2b2o6bo$878bo
11bo$878b2o8b3o$874bo5bo6bob2o$874b2o3b2o5b2obo$878b2o8b2o$885b2obo$
885b2ob2o$885b2ob2o$887bo2$869b3o$868bo2bo$868bo2bo$867bo2bo11bo$868b
3o10b3o$868b2o10b2o2bo$882b3o$872bo$872bo$873bo$869b2obo11bo$868bo12bo
$870bo4bo4bo3bo$879b2ob2o$872bobo$872b3o$863b3o$863bo2bo14bo$863bob2o
12b2o$861b2o13bo3b2o$861b2o12b3o326b3o$860bo2bo10bo2b2o327bo$864bo9b2o
b2o326bo$862b3o8b3o$863bo10b2obo$875bo2bo$875bo$876bobo$877bo2$874b3o$
874b2obo$873bob2o6$872bobo$872b2o$873bo4$857bobo$857b2o$858bo12$866bo$
865bo$865b3o4$851bo$850bo$850b3o13$860bo$858b2o$859b2o4$845bo$843b2o$
844b2o13$852bo$852bobo$852b2o2$1344b3o$1346bo$837bo507bo$837bobo$837b
2o13$845bobo$845b2o$846bo4$830bobo$830b2o$831bo12$839bo$838bo$838b3o4$
824bo$823bo$823b3o13$833bo$831b2o$832b2o4$818bo$816b2o$817b2o13$825bo$
825bobo$825b2o3$1484b3o$810bo675bo$810bobo672bo$810b2o13$818bobo$818b
2o$819bo4$803bobo$803b2o$804bo12$812bo$811bo$811b3o4$797bo$796bo$796b
3o13$806bo$804b2o$805b2o$857bo$857bobo$857b2o$791bo$789b2o$790b2o13$
798bo$798bobo$798b2o4$783bo840b3o$783bobo840bo$783b2o840bo13$791bobo$
791b2o$792bo4$776bobo$776b2o$777bo12$785bo$784bo$784b3o4$770bo$769bo$
769b3o13$779bo$777b2o$778b2o4$764bo$762b2o$763b2o13$771bo$771bobo$771b
2o4$756bo$756bobo1005b3o$756b2o1008bo$1765bo12$764bobo$764b2o$765bo4$
749bobo$749b2o$750bo12$758bo$757bo$757b3o4$743bo$742bo$742b3o13$752bo$
750b2o$751b2o4$737bo$735b2o$736b2o13$744bo$744bobo$744b2o4$729bo$729bo
bo$729b2o1173b3o$1906bo$1905bo11$737bobo$737b2o$738bo4$722bobo$722b2o$
723bo12$731bo$730bo$730b3o4$716bo$715bo$715b3o13$725bo$723b2o$724b2o4$
710bo$708b2o$709b2o13$717bo$717bobo$717b2o4$702bo$702bobo$702b2o$2044b
3o$2046bo$2045bo10$710bobo$710b2o$711bo4$695bobo$695b2o$696bo12$704bo$
703bo$703b3o4$689bo$688bo$688b3o13$698bo$696b2o$697b2o$749bo$749bobo$
749b2o$683bo$681b2o$682b2o13$690bo$690bobo$690b2o4$675bo$675bobo$675b
2o13$683bobo$683b2o$684bo4$668bobo$668b2o$669bo12$677bo$676bo$676b3o4$
662bo$661bo$661b3o13$671bo$669b2o$670b2o4$656bo$654b2o$655b2o13$663bo$
663bobo$663b2o4$648bo$648bobo$648b2o13$656bobo$656b2o$657bo4$641bobo$
641b2o$642bo12$650bo$649bo$649b3o4$635bo$634bo$634b3o13$644bo$642b2o$
643b2o4$629bo$627b2o$628b2o13$636bo$636bobo$636b2o4$621bo$621bobo$621b
2o13$629bobo$629b2o$630bo4$614bobo$614b2o$615bo12$623bo$622bo$622b3o4$
608bo$607bo$607b3o13$617bo$615b2o$616b2o4$602bo$600b2o$601b2o13$609bo$
609bobo$609b2o4$594bo$594bobo$594b2o13$602bobo$602b2o$603bo4$587bobo$
587b2o$588bo12$596bo$595bo$595b3o4$581bo$580bo$580b3o13$590bo$588b2o$
589b2o$641bo$641bobo$641b2o$575bo$573b2o$574b2o13$582bo$582bobo$582b2o
4$567bo$567bobo$567b2o13$575bobo$575b2o$576bo4$560bobo$560b2o$561bo12$
569bo$568bo$568b3o4$554bo$553bo$553b3o13$563bo$561b2o$562b2o4$548bo$
546b2o$547b2o13$555bo$555bobo$555b2o4$540bo$540bobo$540b2o13$548bobo$
548b2o$549bo4$533bobo$533b2o$534bo12$542bo$541bo$541b3o4$527bo$526bo$
526b3o13$536bo$534b2o$535b2o4$521bo$519b2o$520b2o13$528bo$528bobo$528b
2o4$513bo$513bobo$513b2o13$521bobo$521b2o$522bo4$506bobo$506b2o$507bo
12$515bo$514bo$514b3o4$500bo$499bo$499b3o13$509bo$507b2o$508b2o4$494bo
$492b2o$493b2o13$501bo$501bobo$501b2o4$486bo$486bobo$486b2o13$494bobo$
494b2o$495bo4$479bobo$479b2o$480bo12$488bo$487bo$487b3o4$473bo$472bo$
472b3o13$482bo$480b2o$481b2o$533bo$533bobo$533b2o$467bo$465b2o$466b2o
13$474bo$474bobo$474b2o4$459bo$459bobo$459b2o13$467bobo$467b2o$468bo4$
452bobo$452b2o$453bo12$461bo$460bo$460b3o4$446bo$445bo$445b3o13$455bo$
453b2o$454b2o4$440bo$438b2o$439b2o13$447bo$447bobo$447b2o4$432bo$432bo
bo$432b2o13$440bobo$440b2o$441bo4$425bobo$425b2o$426bo12$434bo$433bo$
433b3o4$419bo$418bo$418b3o13$428bo$426b2o$427b2o4$413bo$411b2o$412b2o
13$420bo$420bobo$420b2o4$405bo$405bobo$405b2o13$413bobo$413b2o$414bo4$
398bobo$398b2o$399bo12$407bo$406bo$406b3o4$392bo$391bo$391b3o13$401bo$
399b2o$400b2o4$386bo$384b2o$385b2o13$393bo$393bobo$393b2o4$378bo$378bo
bo$378b2o13$386bobo$386b2o$387bo4$371bobo$371b2o$372bo12$380bo$379bo$
379b3o4$365bo$364bo$364b3o13$374bo$372b2o$373b2o$425bo$425bobo$425b2o$
359bo$357b2o$358b2o13$366bo$366bobo$366b2o4$351bo$351bobo$351b2o13$
359bobo$359b2o$360bo4$344bobo$344b2o$345bo12$353bo$352bo$352b3o4$338bo
$337bo$337b3o13$347bo$345b2o$346b2o4$332bo$330b2o$331b2o13$339bo$339bo
bo$339b2o4$324bo$324bobo$324b2o13$332bobo$332b2o$333bo4$317bobo$317b2o
$318bo12$326bo$325bo$325b3o4$311bo$310bo$310b3o13$320bo$318b2o$319b2o
4$305bo$303b2o$304b2o13$312bo$312bobo$312b2o4$297bo$297bobo$297b2o13$
305bobo$305b2o$306bo4$290bobo$290b2o$291bo12$299bo$298bo$298b3o4$284bo
$283bo$283b3o13$293bo$291b2o$292b2o4$278bo$276b2o$277b2o13$285bo$285bo
bo$285b2o4$270bo$270bobo$270b2o13$278bobo$278b2o$279bo4$263bobo$263b2o
$264bo12$272bo$271bo$271b3o4$257bo$256bo$256b3o13$266bo$264b2o$265b2o$
317bo$317bobo$317b2o$251bo$249b2o$250b2o13$258bo$258bobo$258b2o4$243bo
$243bobo$243b2o13$251bobo$251b2o$252bo4$236bobo$236b2o$237bo12$245bo$
244bo$244b3o4$230bo$229bo$229b3o13$239bo$237b2o$238b2o4$224bo$222b2o$
223b2o13$231bo$231bobo$231b2o4$216bo$216bobo$216b2o13$224bobo$224b2o$
225bo4$209bobo$209b2o$210bo12$218bo$217bo$217b3o4$203bo$202bo$202b3o
13$212bo$210b2o$211b2o4$197bo$195b2o$196b2o13$204bo$204bobo$204b2o4$
189bo$189bobo$189b2o13$197bobo$197b2o$198bo4$182bobo$182b2o$183bo12$
191bo$190bo$190b3o4$176bo$175bo$175b3o13$185bo$183b2o$184b2o4$170bo$
168b2o$169b2o13$177bo$177bobo$177b2o4$162bo$162bobo$162b2o13$170bobo$
170b2o$171bo4$155bobo$155b2o$156bo12$164bo$163bo$163b3o4$149bo$148bo$
148b3o13$158bo$156b2o$157b2o$209bo$209bobo$209b2o$143bo$141b2o$142b2o
13$150bo$150bobo$150b2o4$135bo$135bobo$135b2o13$143bobo$143b2o$144bo4$
128bobo$128b2o$129bo12$137bo$136bo$136b3o4$122bo$121bo$121b3o13$131bo$
129b2o$130b2o4$116bo$114b2o$115b2o13$123bo$123bobo$123b2o4$108bo$108bo
bo$108b2o13$116bobo$116b2o$117bo4$101bobo$101b2o$102bo12$110bo$109bo$
109b3o4$95bo$94bo$94b3o13$104bo$102b2o$103b2o4$89bo$87b2o$88b2o13$96bo
$96bobo$96b2o4$81bo$81bobo$81b2o13$89bobo$89b2o$90bo4$74bobo$74b2o$75b
o12$83bo$82bo$82b3o4$68bo$67bo$67b3o13$77bo$75b2o$76b2o4$62bo$60b2o$
61b2o13$69bo$69bobo$69b2o4$54bo$54bobo$54b2o13$62bobo$62b2o$63bo4$47bo
bo$47b2o$48bo12$56bo$55bo$55b3o4$41bo$40bo$40b3o13$50bo$48b2o$49b2o4$
35bo$33b2o$34b2o13$42bo$42bobo$42b2o4$27bo$27bobo$27b2o13$35bobo$35b2o
$36bo4$20bobo$20b2o$21bo12$29bo$28bo$28b3o4$14bo$13bo$13b3o13$23bo$21b
2o$22b2o4$8bo$6b2o$7b2o13$15bo$15bobo$15b2o4$o$obo$2o!
I have also been considering a potentially simpler approach to duplicating the period-multiplied signal: Namely, reactions like the following.
Code: Select all
x = 783, y = 594, rule = B3/S23
39bo87bo322bo$37b2o87bo322bo$38b2o86b3o320b3o167bo73bo87bo$373bo244bo
73bo87bo$372bo159bo85b3o71b3o85b3o$372b3o156bo$531b3o2$295bo$217bo76bo
$216bo77b3o$216b3o10$31bo89bo322bo$31bobo85b2o321b2o$31b2o87b2o321b2o
168bo73bo87bo$367bo243b2o72b2o86b2o$365b2o159bo85b2o72b2o86b2o$366b2o
156b2o$525b2o2$289bo$211bo75b2o$209b2o77b2o$210b2o10$24bobo86bo322bo$
24b2o87bobo320bobo$25bo87b2o321b2o167bo73bo87bo$359bo245bobo71bobo85bo
bo$359bobo156bo86b2o72b2o86b2o$359b2o157bobo$518b2o$30bo$28b2o251bo$
29b2o172bo77bobo$203bobo75b2o$203b2o3$116bo$114b2o$115b2o4$18bo$17bo
88bobo320bobo$17b3o86b2o321b2o$13b3o91bo322bo167bobo71bobo85bobo$13bo
2bo335bobo243b2o72b2o86b2o$12bo339b2o157bobo85bo73bo87bo$15b2o336bo
157b2o$11bo3b2o495bo$11bo$13bo260bobo78bobo$13b3o180bobo75b2o79b2o$14b
2o180b2o77bo80bo$15bo181bo316bobo84bo$13b2o499b2o84bo$12bobo185bobo
312bo84b3o$11bo3bo184b2o$13b2o186bo230bo$430b2o$431b2o2$671bo$100bo
322bo246bo$10bo88bo322bo247b3o$10bobo86b3o175bo144b3o167bo73bo87bo$10b
2o83b3o178bo69bo71b3o170bo73bo87bo$95bo2bo177b3o66bo72bo2bo83bo85b3o
71b3o85b3o$94bo250b3o69bo86bo82b3o71b3o85b3o$97b2o242b3o76b2o82b3o80bo
2bo70bo2bo84bo2bo$93bo3b2o242bo2bo71bo3b2o78b3o83bo73bo87bo$93bo174bo
71bo75bo83bo2bo85b2o72b2o86b2o4bo$95bo94bo76bo75b2o73bo80bo85bo3b2o68b
o3b2o82bo3b2o4bobo$95b3o91bo77b3o69bo3b2o73b3o81b2o81bo73bo87bo9b2o$
96b2o91b3o71b3o73bo79b2o77bo3b2o83bo73bo87bo$97bo87b3o75bo2bo74bo78bo
77bo88b3o71b3o85b3o$95b2o88bo2bo73bo78b3o74b2o80bo87b2o72b2o86b2o$94bo
bo87bo80b2o75b2o73bobo80b3o86bo73bo87bo$93bo3bo89b2o72bo3b2o76bo72bo3b
o80b2o84b2o72b2o86b2o$95b2o86bo3b2o72bo79b2o75b2o82bo83bobo71bobo85bob
o$183bo79bo76bobo157b2o83bo3bo69bo3bo83bo3bo$185bo77b3o73bo3bo155bobo
85b2o72b2o86b2o$185b3o76b2o75b2o155bo3bo$186b2o77bo234b2o$187bo75b2o$
92bo92b2o75bobo$92bobo89bobo74bo3bo$92b2o89bo3bo75b2o$185b2o52$741bobo
$531bobo207b2o$531b2o209bo$532bo10$624bo$623bo$623b3o5$735bo$525bo208b
o$524bo209b3o$524b3o8$29bo329bo$27b2o253bo74b2o79bo$28b2o250b2o76b2o
76b2o$201bo79b2o154b2o179bo$199b2o415b2o$200b2o415b2o2$112bo508bo$110b
2o507b2o$111b2o507b2o$729bo$519bo207b2o$517b2o209b2o$518b2o8$21bo329bo
$21bobo250bo76bobo76bo$21b2o251bobo74b2o77bobo298bo$193bo80b2o154b2o
178bo118b2o$193bobo414bobo117b2o$193b2o415b2o2$104bo$104bobo$104b2o$
721bo$511bo209bobo$511bobo207b2o$511b2o6$516bo$516bobo$14bobo327bobo
169b2o$14b2o251bobo74b2o77bobo$15bo251b2o76bo77b2o$186bobo79bo155bo
178bobo$186b2o415b2o$187bo416bo2$97bobo$97b2o$98bo$714bobo$504bobo207b
2o$504b2o209bo$505bo7$8bo329bo$7bo253bo75bo79bo$7b3o250bo76b3o76bo$3b
3o174bo79b3o70b3o80b3o178bo$3bo2bo172bo76b3o74bo2bo75b3o181bo$2bo176b
3o74bo2bo72bo79bo2bo180b3o$5b2o168b3o77bo79b2o74bo180b3o$bo3b2o84bo83b
o2bo79b2o71bo3b2o77b2o176bo2bo$bo88bo83bo79bo3b2o71bo78bo3b2o175bo$3bo
86b3o84b2o75bo78bo6bo69bo183b2o$3b3o80b3o84bo3b2o77bo76b3o3bo72bo177bo
3b2o112bo$4b2o6bo73bo2bo83bo82b3o75b2o3b3o70b3o83bo91bo116bo$5bo4b2o
73bo89bo81b2o76bo77b2o82bo94bo114b3o$3b2o6b2o75b2o85b3o80bo74b2o79bo
82b3o92b3o108b3o$2bobo79bo3b2o86b2o78b2o74bobo77b2o79b3o97b2o108bo2bo$
bo3bo78bo92bo77bobo73bo3bo75bobo79bo2bo97bo107bo$3b2o81bo88b2o7bobo67b
o3bo4bo69b2o75bo3bo3bo73bo212b2o$86b3o85bobo7b2o70b2o3b2o149b2o2b2o77b
2o204bo3b2o$87b2o84bo3bo7bo76b2o153b2o72bo3b2o96b3o105bo$88bo86b2o314b
o100bo2b2o106bo$86b2o405bo101bo107b3o$85bobo3bobo399b3o94bo6b2o105b2o$
84bo3bo2b2o401b2o93bo2bo3bo108bo$86b2o4bo402bo93b3ob3o107b2o$493b2o95b
o4b3obo4b2o96bobo$492bobo101bo7b2o95bo3bo$491bo3bo99b2ob2o103b2o$493b
2o101bo2bo$597b2o3$704bo$700bo4bo$700bo3bo$700b2ob2o$706b2o$706b2o$
707bo38$619bo$618bo$618b3o106bo$726bo$726b3o3$34bo$33bo$33b3o254bo235b
o$289bo158bo76bo$289b3o79bo75bo77b3o$370bo76b3o$128bo241b3o$127bo77bo$
127b3o74bo$204b3o5$613bo$611b2o$612b2o107bo$719b2o$720b2o3$28bo$26b2o$
27b2o255bo235bo$282b2o158bo75b2o$283b2o80bo74b2o77b2o$363b2o76b2o$122b
o241b2o$120b2o77bo$121b2o74b2o$198b2o5$605bo$605bobo$605b2o106bo$713bo
bo$713b2o3$20bo$20bobo$20b2o254bo235bo$276bobo155bo77bobo$276b2o79bo
76bobo75b2o$357bobo74b2o$114bo242b2o$114bobo74bo$114b2o75bobo$191b2o5$
598bobo$598b2o$599bo106bobo$706b2o$707bo3$13bobo$13b2o586bo$14bo254bob
o233bobo93bobo$269b2o156bobo75b2o94b2o107bo$270bo79bobo74b2o77bo201b2o
$350b2o76bo280b2o$107bobo241bo$107b2o75bobo$19bo88bo75b2o$17b2o166bo$
18b2o3$592bo$272bo235bobo80bo$272bobo233b2o81b3o106bo$272b2o235bo77b3o
109bo$429bobo155bo2bo108b3o$429b2o155bo108b3o$112bo74bo162bobo77bo158b
2o104bo2bo$7bo102b2o74bo163b2o233bo3b2o103bo$6bo104b2o73b3o162bo233bo
111b2o$6b3o254bo235bo87bo105bo3b2o$2b3o257bo158bo76bo88b3o103bo$2bo2bo
256b3o79bo75bo77b3o87b2o105bo$bo256b3o82bo76b3o71b3o92bo105b3o$4b2o95b
o156bo2bo81b3o70b3o75bo2bo89b2o107b2o$o3b2o94bo77bo78bo81b3o74bo2bo73b
o92bobo108bo$o99b3o74bo82b2o77bo2bo72bo80b2o87bo3bo105b2o$2bo93b3o78b
3o76bo3b2o76bo79b2o72bo3b2o89b2o105bobo$2b3o91bo2bo73b3o80bo84b2o71bo
3b2o72bo200bo3bo$3b2o90bo77bo2bo81bo78bo3b2o71bo79bo200b2o$4bo93b2o72b
o85b3o76bo78bo77b3o$2b2o90bo3b2o75b2o82b2o78bo76b3o76b2o$bobo90bo76bo
3b2o83bo78b3o75b2o77bo$o3bo91bo74bo86b2o80b2o76bo75b2o$2b2o92b3o74bo
83bobo81bo74b2o75bobo$97b2o74b3o80bo3bo78b2o74bobo74bo3bo$98bo75b2o82b
2o78bobo73bo3bo75b2o$96b2o77bo161bo3bo74b2o$95bobo75b2o164b2o$94bo3bo
73bobo$96b2o73bo3bo$173b2o43$291bo$290bo$290b3o4$209bo$119bo88bo160bo$
118bo89b3o157bo$118b3o247b3o$35bo$34bo$34b3o9$285bo$283b2o$284b2o4$
203bo$113bo87b2o160bo$111b2o89b2o157b2o$112b2o248b2o$29bo$27b2o$28b2o
9$277bo$277bobo$277b2o4$195bo$105bo89bobo157bo$105bobo87b2o158bobo$
105b2o248b2o$21bo$21bobo$21b2o9$270bobo$270b2o$271bo4$188bobo$98bobo
87b2o158bobo$98b2o89bo158b2o$99bo172bo76bo$14bobo255bobo$14b2o256b2o
77bo$15bo334bo$192bo157b3o$190b2o$191b2o4$18bo$17bo246bo$17b3o243bo$
263b3o$99bo159b3o$97b2o160bo2bo$98b2o158bo$182bo78b2o$92bo88bo75bo3b2o
79bo$91bo89b3o73bo83bo$91b3o83b3o79bo81b3o$8bo78b3o87bo2bo78b3o75b3o$
7bo79bo2bo85bo83b2o75bo2bo$7b3o76bo92b2o80bo74bo$3b3o83b2o84bo3b2o78b
2o78b2o$3bo2bo78bo3b2o84bo82bobo74bo3b2o$2bo82bo91bo79bo3bo73bo$5b2o
80bo89b3o79b2o76bo$bo3b2o80b3o88b2o157b3o$bo86b2o89bo158b2o$3bo85bo87b
2o160bo$3b3o81b2o87bobo158b2o$4b2o80bobo86bo3bo156bobo$5bo79bo3bo87b2o
156bo3bo$3b2o82b2o248b2o$2bobo$bo3bo$3b2o!
EDIT:
Much smaller 1x NE rake:
Code: Select all
x = 199, y = 274, rule = B3/S23
13$105bobo$105b2o$106bo4$90bobo$90b2o$91bo12$99bo$98bo$98b3o4$84bo$83b
o$83b3o13$93bo$91b2o$92b2o4$78bo$76b2o$77b2o13$85bo$85bobo$85b2o4$70bo
$70bobo$70b2o13$78bobo$78b2o$79bo4$63bobo$63b2o$64bo12$72bo$71bo$71b3o
4$57bo$56bo$52b3ob3o$52bo2bo$51bo$54b2o$50bo3b2o$50bo$52bo$52b3o$53b2o
$54bo7b3o$52b2o8bo2bo$51bobo6bo4bo$50bo3bo5bo$52b2o5b2o$60b2obo$62bo4$
49bo$49bobo12b2o$49b2o$62bo2bo$61bo$61bo2bo$43b3o17bo$42bo2bo$42bo3bo$
43b4o$45bo2$54b3o$53bo2bo$53bo2bo$41b2ob2o6bo2bo$41b3obo7b3o$53b2o7b2o
$62b2o$57bo$42bo14bo$41bo16bo$37b3ob3o10b2obo$37bo2bo12bo$36bo18bo4bo$
39b2o$35bo3b2o16bobo$35bo21b3o$37bo$37b3o$38b2o23b2o$39bo7b3o13b2o$37b
2o8bo2bo$36bobo6bo4bo$35bo3bo5bo$37b2o5b2o$45b2obo$47bo2$60bo$59b3o$
34bo23b2o2bo$34bobo12b2o8b4o$34b2o21bobo$47bo2bo5bo2bo$46bo10b3o$46bo
2bo8bobo$28b3o17bo9bobo$27bo2bo27b3o$27bo3bo$28b4o$30bo4$39bo$26b2ob2o
7bobo$26b3obo6b2ob2o$38bob2o5b2o$47b2o2$27bo$26bo$26b3o$41bo$33bo6b2o$
32bob2o$31bo5bo$32b2o4bo14bo$34b2o2b2o2bo10bobo$38bob3o10b2o$41bo6b2o$
41bo6b2o$38b2obo2$44b3o$36bo7bo2bo$34b2o7bo3bo9b2o$35b2o6bobob2o7bobo$
44b2ob2o9bo$38b2o5b3o$38b2o$21bo44bo$19b2o45b2o$20b2o43bobo$43bob2o$
42bobobo$43bo$74b3o$76bo$75bo$41b2o$44bo$39bo3bo39b2o$39bobo42b2o$83bo
2$28bo$28bobo61b2o$28b2o61bobo$93bo3$13bo87bo$13bobo85b2o$13b2o85bobo
4$109b3o$111bo$110bo3$118b2o$119b2o$118bo2$21bobo$21b2o$22bo4$6bobo$6b
2o$7bo!
Very slightly smaller 1x SE rake:
Code: Select all
x = 306, y = 797, rule = B3/S23
278bo$276b2o$277b2o4$263bo$261b2o$262b2o13$270bo$270bobo$270b2o4$255bo
$255bobo$255b2o13$263bobo$263b2o$264bo4$248bobo$248b2o$249bo12$257bo$
256bo$256b3o4$242bo$241bo$241b3o13$251bo$249b2o$250b2o4$236bo$234b2o$
235b2o13$243bo$243bobo$243b2o4$228bo$228bobo$228b2o13$236bobo$236b2o$
237bo4$221bobo$221b2o$222bo12$230bo$229bo$229b3o4$215bo$214bo$214b3o
13$224bo$222b2o$223b2o4$209bo$207b2o$208b2o13$216bo$216bobo$216b2o4$
201bo$201bobo$201b2o13$209bobo$209b2o$210bo4$194bobo$194b2o$195bo12$
203bo$202bo$202b3o4$188bo$187bo$187b3o13$197bo$195b2o$196b2o4$182bo$
180b2o$181b2o13$189bo$189bobo$189b2o4$174bo$174bobo$174b2o13$182bobo$
182b2o$183bo4$167bobo$167b2o$168bo12$176bo$175bo$175b3o4$161bo$160bo$
156b3ob3o$156bo2bo$155bo$158b2o$154bo3b2o$154bo$156bo$156b3o$157b2o$
158bo7b3o$156b2o8bo2bo$155bobo6bo4bo$154bo3bo5bo$156b2o5b2o$164b2obo$
166bo4$153bo$153bobo12b2o$153b2o$148b3o15bo2bo$147bo2bo14bo$147bo3bo
13bo2bo$146b2o2bo16bo$148bo$149b2o$149b3o$149b3o2$158b3o$148b2o7bo2bo$
147b2obo6bo2bo$146bo3bo5bo2bo$147bo9b3o$157b2o7b2o$166b2o2$146bo$145bo
$145b3o12b2o$153bo6b2o$151bo3bo$150bo6b3o$151bo7bo$153bo2b2obo$139b3o$
139bo2bo$139bob2o24b2o$167b2o3$141b2o7b3o$139b4o6bo2bo$138bo2bo6bo$
138bobo8b3o$138bobo17b2o$158b2o$152b2o$138bo13b2o$138bobo12bo$138b2o
13b2o13b2o$133b3o13b3obob2o11b2o$132bo2bo13b2o$132bo3bo16bo2bo$131b2o
2bo17b3o$133bo$134b2o$134b3o$134b3o22b2o$159b2o$143b3o$133b2o7bo2bo$
132b2obo6bo2bo$131bo3bo5bo2bo24b2o$132bo9b3o24b2o$142b2o3$131bo$130bo
25bo$130b3o12b2o8b3o$138bo6b2o7b2o2bo$136bo3bo13bo$135bo6b3o8b2o$136bo
7bo7bo$138bo2b2obo7b4o$154b2o14b2o$124b3o43b2o$124bo2bo$124bob2o4$126b
2o$124b4o7bo3b2o$123bo2bo7bobo$123bobo8b2o7b2o14bo$123bobo9bo7b2o14bo$
137b2o$135b4o32b2o$123bo10bo2bo33b2o$123bobo10bo$123b2o$135bobo$129bo
6b2o$128bobo19bo$127bo2bo3bo15bobo$128b2o2b2o16b2o$132b2o$116b3o13b2o
3b3o4b2o$115bo2bo15bo3b2o4b2o$115bo4bo13b2ob2o$137b2o29bo$120bo15bo30b
3o$119bo46b2obo$115bob2o9bob2obo6b3o22bo2bo$114bo2bo9b3ob2o7bo2bo8b2o
12b2o$116b2o8b2ob4o7bob2o7bobo13bo$113bo2bo12b2o22bo$113bo15b2o3b2o$
117bo11b2o3b2o$114bo11bo15b2o17bo$115b3o8b2o12b4o17b2o6b2o$127bobo9bo
2bo17bobo6b2o$127bo2bo8bobo$121bo6b2o9bobo$120bobo$119bo2bo$120b2o3b3o
11bo$125bob3o9bobo19bo10bo$125bo2b3o8b2o19b3o10b2o$108b3o15b2o2bo28b2o
2bo8b2o$108bo2bo15bobo5b2o22bo$108bo2bo15b3o5b2o21b2o$109bo2bo44bo$
109bo2bo12bo31b4o9b2o$107b2o14b2o34b2o9b2o$107b2o11bo3b2o$106bo3bo8b3o
$106b2o10bo2b2o$105bo12b2ob2o3b2o$106bo3bo6b3o6b2o$107b3o8b2obo$119bo
2bo$119bo$120bobo$113b2o6bo42bo$112bo51bo$112b2o3bo$113bo53bo$118b2o
46bobo13bo$117b2o2b2o42b2ob2o10bobo$119bo2bo43bob2o11b2o$119b3o5b2o$
127b2o$155bo12b2o$116bobo36bobo10bo$116b2o37b2o$117bo53bo$165b2ob2obo$
165b2ob2ob2o$118b2o49bobo$101bobo14b2o50bo$101b2o$102bo2$128b2o$128b2o
3$164bo$162b2o25bobo$163b2o25b2o$190bo$119b2o$119b2o$110bo37bobo$109bo
38b2o$109b3o37bo$129b2o$129b2o2$95bo$94bo$94b3o3$120b2o$120b2o3$156bo
42bo$130b2o24bobo41bo$130b2o24b2o40b3o3$142bo$104bo36bo$102b2o37b3o$
103b2o$121b2o$121b2o2$89bo$87b2o$88b2o41b2o$131b2o6$149bobo55bo$122b2o
25b2o57b2o$122b2o26bo56b2o3$133b4o$96bo36b2o2bo$96bobo34bob2o$96b2o4$
81bo$81bobo$81b2o40b2o$123b2o5$143bo$142bo74bo$142b3o70bobo$216b2o4$
89bobo32b2o$89b2o33b2o$90bo4$74bobo$74b2o$75bo5$125b2o$125b2o10bo$135b
2o87bobo$136b2o87b2o$225bo3$83bo$82bo$82b3o4$68bo57b2o$67bo58b2o$67b3o
7$129bo104bo$129bobo103bo$129b2o102b3o2$127b2o$127b2o$77bo$75b2o$76b2o
4$62bo$60b2o$61b2o7$242bo$243b2o$242b2o4$69bo$69bobo$69b2o4$54bo$54bob
o$54b2o7$252bo$250bobo$251b2o4$62bobo$62b2o$63bo4$47bobo$47b2o$48bo7$
259bobo$260b2o$260bo3$56bo$55bo$55b3o4$41bo$40bo$40b3o7$269bo$270bo$
268b3o4$50bo$48b2o$49b2o4$35bo$33b2o$34b2o7$277bo$278b2o$277b2o4$42bo$
42bobo$42b2o4$27bo$27bobo$27b2o7$287bo$285bobo$286b2o4$35bobo$35b2o$
36bo4$20bobo$20b2o$21bo7$294bobo$295b2o$295bo3$29bo$28bo$28b3o4$14bo$
13bo$13b3o7$304bo$305bo$303b3o4$23bo$21b2o$22b2o4$8bo$6b2o$7b2o13$15bo
$15bobo$15b2o4$o$obo$2o!
EDIT: Better filtered NE rake with much more lane adjustability:
Code: Select all
x = 436, y = 981, rule = B3/S23
346bo$346bobo$346b2o4$331bo$331bobo$331b2o10$406bo$405bo$405b3o$339bob
o$339b2o$340bo4$324bobo$324b2o$325bo12$333bo$332bo$332b3o4$318bo$317bo
$317b3o13$327bo$325b2o$326b2o4$312bo$310b2o$311b2o13$319bo$319bobo$
319b2o4$304bo$304bobo$304b2o13$312bobo$312b2o$313bo4$297bobo$297b2o$
298bo12$306bo$305bo$305b3o4$291bo$290bo$290b3o13$300bo$298b2o$299b2o4$
285bo$283b2o$284b2o13$292bo$292bobo$292b2o4$277bo$277bobo$277b2o13$
285bobo$285b2o$286bo4$270bobo$270b2o$271bo12$279bo$278bo$278b3o4$264bo
$263bo$263b3o13$273bo$271b2o$272b2o4$258bo$256b2o$257b2o13$265bo$265bo
bo$265b2o4$250bo$250bobo$250b2o13$258bobo$258b2o$259bo4$243bobo$243b2o
$244bo12$252bo$251bo$251b3o4$237bo$236bo$236b3o13$246bo$244b2o$245b2o
4$231bo$229b2o$230b2o13$238bo$238bobo$238b2o4$223bo$223bobo$223b2o10$
298bo$297bo$297b3o$231bobo$231b2o$232bo4$216bobo$216b2o$217bo12$225bo$
224bo$224b3o4$210bo$209bo$205b3ob3o$205bo2bo$204bo$207b2o$203bo3b2o$
203bo$205bo$205b3o$206b2o$207bo7b3o$205b2o8bo2bo$204bobo6bo4bo$203bo3b
o5bo$205b2o5b2o$213b2obo$215bo4$202bo$202bobo12b2o$202b2o$197b3o15bo2b
o$196bo2bo14bo$196bo3bo13bo2bo$195b2o2bo16bo$197bo$198b2o$198b3o$198b
3o2$207b3o$197b2o7bo2bo$196b2obo6bo2bo$195bo3bo5bo2bo$196bo9b3o$206b2o
7b2o$215b2o2$195bo$194bo$194b3o12b2o$202bo6b2o$200bo3bo$199bo6b3o$200b
o7bo$202bo2b2obo$188b3o$188bo2bo$188bob2o24b2o$216b2o3$190b2o7b3o$188b
4o6bo2bo$187bo2bo6bo$187bobo8b3o$187bobo17b2o$207b2o$201b2o$187bo13b2o
$187bobo12bo$187b2o13b2o13b2o$182b3o13b3obob2o11b2o$181bo2bo13b2o$181b
o3bo16bo2bo$180b2o2bo17b3o$182bo$183b2o$183b3o$183b3o22b2o$208b2o$192b
3o$182b2o7bo2bo$181b2obo6bo2bo$180bo3bo5bo2bo24b2o$181bo9b3o24b2o$191b
2o3$180bo$179bo25bo$179b3o12b2o8b3o$187bo6b2o7b2o2bo$185bo3bo13bo$184b
o6b3o8b2o$185bo7bo7bo$187bo2b2obo7b4o$203b2o14b2o$173b3o43b2o$173bo2bo
$173bob2o4$175b2o$173b4o7bo3b2o$172bo2bo7bobo$172bobo8b2o7b2o14bo$172b
obo9bo7b2o14bo$186b2o$184b4o32b2o$172bo10bo2bo33b2o$172bobo10bo$172b2o
$184bobo$178bo6b2o$177bobo19bo$176bo2bo3bo15bobo$177b2o2b2o16b2o$181b
2o$165b3o13b2o3b3o4b2o$164bo2bo15bo3b2o4b2o$164bo4bo13b2ob2o$186b2o29b
o$169bo15bo30b3o$168bo46b2obo$164bob2o9bob2obo6b3o22bo2bo$163bo2bo9b3o
b2o7bo2bo8b2o12b2o$165b2o8b2ob4o7bob2o7bobo13bo$162bo2bo12b2o22bo$162b
o15b2o3b2o$166bo11b2o3b2o$163bo11bo15b2o17bo$164b3o8b2o12b4o17b2o6b2o$
176bobo9bo2bo17bobo6b2o$176bo2bo8bobo$170bo6b2o9bobo$169bobo$168bo2bo$
169b2o3b3o11bo$174bob3o9bobo19bo10bo$174bo2b3o8b2o19b3o10b2o$175b2o2bo
28b2o2bo8b2o$176bobo5b2o22bo$176b3o5b2o21b2o$156b3o47bo$156bo2bo14bo
31b4o9b2o$156bob2o12b2o34b2o9b2o$154b2o13bo3b2o$154b2o12b3o$153bo2bo
10bo2b2o$157bo9b2ob2o3b2o$155b3o8b3o6b2o$156bo10b2obo$168bo2bo$168bo$
169bobo$170bo42bo$213bo$167b3o$167b2obo45bo$150b3o13bob2o45bobo13bo$
149bo2bo62bobo11bobo$149bo4bo60b3o12b2o$176b2o38bo2bo$154bo21b2o38bo$
153bo8bo41bo14bo$149bob2o8bobo40bobo10b2o$148bo2bo8b2ob2o39b2o11b3o$
150b2o9bob2o53b2o$147bo2bo63b2o2bobo$147bo66b2o2bobo$151bo11b2o53b3o$
148bo14bo$149b3o$166bo$160b2ob2obo$144b3o13b2ob2ob2o9b2o$144bo2bo16bob
o10b2o$143bo3bo17bo$143bobob2o$144b2ob2o63bo$145b3o64bobo23bobo$155b3o
54b2o25b2o$155bo2bo80bo$153bo4bo$153bo$143bob2o5b2o43bobo$142bobobo6b
2obo40b2o$143bo11bo42bo$178b2o$178b2o$157bobo$138b2ob2o14bobo$137bo6bo
$137b2o4bo12bo2$139bo2bo$140b2o$137b2o10b3o6bobo$137b3o8bo2bo7bo$138bo
9bo3bo$137b2ob2o9b2o52bobo40bo$137b2ob2o7bobo27b2o24b2o42bo$137bo3bo4b
o2b2o28b2o25bo40b3o$137bo3bo5bo2bo$140bo9bo$147b2ob2o39bo$148bobo39bo$
149bo40b3o2$132bo$131b3o$130b2obo$129bo2bo$130b2o11b3o$131bo11bo2bo33b
2o$143bob2o33b2o$133b2o$135bo2$131bo2bobo8b2o$130bob3obo6b4o52bo$130bo
b2ob3o4bo2bo52bo57bo$134bobo5bobo53b3o56b2o$134b3o5bobo111b2o$135bo$
126bo$125b3o14bo39b4o$124bo2b2o13bobo37b2o2bo$142b2o38bob2o$123b2o12b
3o$123b2o11bo2bo$122bo2bo10bo3bo$124b3o8b2o2bo$137bo$138b2o$138b3o$
138b3o3$137b2o$136b2obo$120bo14bo3bo$119b3o14bo129bo$118b2o2bo141bobo$
119b5o141b2o$119b5o$120bo10bo$118bobo9bobo$117bob2o9bobo$117bobo10b3o$
116b3o12bo2bo$116bobo12bo$117b4o13bo$118b3o11b2o$119bo12b3o$133b2o$
129b2o2bobo$114bo14b2o2bobo$113b3o17b3o$112bo2b2o$112bo3bo$113b2obo$
115b2o68bo$125bo59bobo85bobo$124b3o58b2o87b2o$123bo2b2o146bo$122b5o$
111bo2b2o6bo2b2o$111bobobo6bo2bo$112bo10bobo3$127b2o$108bob2obo12b3o$
107b3ob2o11bo$106b2ob4o12b2o$109b2o$109b2o$109b2o16bobo$106bo20bobo$
106b2o20bo$107bobo$107bo2bo7bo$107bobo7b3o58bobo102bo$107b3o6b2o2bo57b
2o104bo$106bob2o6bo62bo102b3o$106bo2bo5b2o$108bo5bo$114b4o$116b2o4$
105bo$103b2o$104b2o13b2o2$116b2o$99bo17bo$98b3o$97bo2b2o$97bo3bo$98b2o
bo$100b2o70bo$110bo60bo$109b3o59b3o$108bo2b2o$107b5o$96bo2b2o6bo2b2o$
96bobobo6bo2bo$97bo10bobo6b2o$117b2o2$112b2o$93bob2obo12b3o$92b3ob2o
11bo$91b2ob4o12b2o$94b2o$94b2o$94b2o16bobo$91bo20bobo$91b2o20bo$92bobo
$92bo2bo7bo14b2o$92bobo7b3o13b2o46bo$92b3o6b2o2bo58b2o135bo$91bob2o6bo
63b2o132bobo$91bo2bo5b2o198b2o$93bo5bo$99b4o$101b2o4$90bo$88b2o$89b2o
13b2o8b3o$113bo2bo$101b2o10bo2bo$84bo17bo9bo2bo$83b3o27b3o$82bo2b2o26b
2o$82bo3bo$83b2obo30bo$85b2o30bo$118bo39bo$114b2obo40bobo147bobo$113bo
44b2o149b2o$94bo20bo4bo188bo$81bo2b2o6b2ob2o$81bobobo6b2o23bobo$82bo9b
2ob2o5b2o13b3o$102b2o3$81bobo$81b2o$82bo12b2o$88b2o5b2o$87b3o21bo$86bo
2bo19b2o$87b3o2b3o15b2o$88b2o2b2obobo$93bobobo$103b2o$96b2o5b2o$95bo
55bobo164bo$151b2o166bo$152bo164b3o$90bo$89bo$89b3o8bo$99b3o8b2o$93b2o
3b2o2bo8b2o$93b2o4b5o6bo$75bo23b5o$74bo25bo$74b3o21bobo18b2o$97bob2o
17bobo$97bobo20bo$96b3o$96bobo$97b4o27bo$98b3o27b2o$99bo27bobo2$94b2o
49bo$94b2o48bo181bo$136b3o5b3o180b2o$138bo187b2o$84bo52bo$82b2o$83b2o$
145b2o$146b2o$145bo$69bo$67b2o$68b2o84b2o$153bobo$155bo3$163bo$163b2o$
162bobo2$139bo$137b2o197bo$138b2o31b3o160bobo$173bo161b2o$76bo95bo$76b
obo$76b2o$180b2o$181b2o$180bo$61bo$61bobo$61b2o126b2o$188bobo$190bo3$
198bo$198b2o$197bobo2$131bo$131bobo209bobo$131b2o73b3o135b2o$208bo135b
o$69bobo135bo$69b2o$70bo$215b2o$216b2o$215bo$54bobo$54b2o$55bo168b2o$
223bobo$225bo3$233bo$233b2o$232bobo2$124bobo226bo$124b2o228bo$125bo
115b3o108b3o$63bo179bo$62bo179bo$62b3o2$250b2o$251b2o$48bo201bo$47bo$
47b3o$259b2o$258bobo$260bo3$268bo$268b2o$267bobo$118bo$117bo243bo$117b
3o242b2o$276b3o82b2o$57bo220bo$55b2o220bo$56b2o2$285b2o$286b2o$42bo
242bo$40b2o$41b2o$294b2o$293bobo$295bo3$303bo$303b2o$302bobo$112bo$
110b2o259bo$111b2o256bobo$311b3o56b2o$49bo263bo$49bobo260bo$49b2o2$
320b2o$321b2o$34bo285bo$34bobo$34b2o$329b2o$328bobo$330bo3$338bo$338b
2o$337bobo$104bo$104bobo271bobo$104b2o273b2o$346b3o30bo$42bobo303bo$
42b2o303bo$43bo2$355b2o$356b2o$27bobo325bo$27b2o$28bo$364b2o$363bobo$
365bo3$373bo$373b2o$372bobo$97bobo288bo$97b2o290bo$98bo288b3o$36bo344b
3o$35bo347bo$35b3o344bo3$390b2o$21bo369b2o$20bo369bo$20b3o9$91bo$90bo$
90b3o2$30bo$28b2o$29b2o4$15bo$13b2o$14b2o2$434b2o$433bobo$435bo9$22bo$
22bobo$22b2o4$7bo$7bobo$7b2o9$77bo$77bobo$77b2o2$15bobo$15b2o$16bo4$ob
o$2o$bo!
Code: Select all
x = 461, y = 1211, rule = B3/S23
416bo$414b2o$415b2o4$401bo$399b2o$400b2o13$408bo$408bobo$408b2o4$393bo
$393bobo$393b2o13$401bobo$401b2o$402bo4$386bobo$386b2o$387bo12$395bo$
394bo$394b3o4$380bo$379bo$379b3o13$389bo$387b2o$388b2o4$374bo$372b2o$
373b2o13$381bo$381bobo$381b2o4$366bo$366bobo$366b2o5$460bo$458b2o$459b
2o6$374bobo$374b2o$375bo4$359bobo$359b2o$360bo12$368bo$367bo$367b3o4$
353bo$352bo$352b3o13$362bo$360b2o$361b2o4$347bo$345b2o$346b2o13$354bo$
354bobo$354b2o4$339bo$339bobo$339b2o13$347bobo$347b2o$348bo4$332bobo$
332b2o$333bo12$341bo$340bo$340b3o4$326bo$325bo$325b3o13$335bo$333b2o$
334b2o4$320bo$318b2o$319b2o13$327bo$327bobo$327b2o4$312bo$312bobo$312b
2o13$320bobo$320b2o$321bo4$305bobo$305b2o$306bo12$314bo$313bo$313b3o4$
299bo$298bo$298b3o13$308bo$306b2o$307b2o4$293bo$291b2o$292b2o13$300bo$
300bobo$300b2o4$285bo$285bobo$285b2o13$293bobo$293b2o$294bo4$278bobo$
278b2o$279bo12$287bo$286bo$286b3o4$272bo$271bo$271b3o13$281bo$279b2o$
280b2o4$266bo$264b2o$265b2o13$273bo$273bobo$273b2o4$258bo$258bobo$258b
2o5$352bo$350b2o$351b2o6$266bobo$266b2o$267bo4$251bobo$251b2o$252bo12$
260bo$259bo$259b3o4$245bo$244bo$244b3o13$254bo$252b2o$253b2o4$239bo$
237b2o$238b2o13$246bo$246bobo$246b2o4$231bo$231bobo$231b2o13$239bobo$
239b2o$240bo4$224bobo$224b2o$225bo12$233bo$232bo$232b3o4$218bo$217bo$
217b3o13$227bo$225b2o$226b2o4$212bo$210b2o$211b2o13$219bo$219bobo$219b
2o4$204bo$204bobo$204b2o13$212bobo$212b2o$213bo4$197bobo$197b2o$198bo
12$206bo$205bo$205b3o4$191bo$190bo$186b3ob3o$186bo2bo$185bo$188b2o$
184bo3b2o$184bo$186bo$186b3o$187b2o$188bo7b3o$186b2o8bo2bo$185bobo6bo
4bo$184bo3bo5bo$186b2o5b2o$194b2obo$196bo4$183bo$183bobo12b2o$183b2o$
178b3o15bo2bo$177bo2bo14bo$177bo3bo13bo2bo$176b2o2bo16bo$178bo$179b2o$
179b3o$179b3o2$188b3o$178b2o7bo2bo$177b2obo6bo2bo$176bo3bo5bo2bo$177bo
9b3o$187b2o7b2o$196b2o2$176bo$175bo$175b3o12b2o$183bo6b2o$181bo3bo$
180bo6b3o$181bo7bo$183bo2b2obo$169b3o$169bo2bo$169bob2o24b2o$197b2o3$
171b2o7b3o$169b4o6bo2bo$168bo2bo6bo$168bobo8b3o$168bobo17b2o$188b2o$
182b2o$168bo13b2o$168bobo12bo$168b2o13b2o13b2o$163b3o13b3obob2o11b2o$
162bo2bo13b2o$162bo3bo16bo2bo$161b2o2bo17b3o$163bo$164b2o$164b3o$164b
3o22b2o$189b2o$173b3o$163b2o7bo2bo$162b2obo6bo2bo$161bo3bo5bo2bo24b2o$
162bo9b3o24b2o$172b2o3$161bo$160bo25bo$160b3o12b2o8b3o$168bo6b2o7b2o2b
o$166bo3bo13bo$165bo6b3o8b2o$166bo7bo7bo$168bo2b2obo7b4o$184b2o14b2o$
154b3o43b2o$154bo2bo$154bob2o4$156b2o$154b4o7bo3b2o$153bo2bo7bobo$153b
obo8b2o7b2o14bo$153bobo9bo7b2o14bo$167b2o$165b4o32b2o$153bo10bo2bo33b
2o$153bobo10bo$153b2o$165bobo$159bo6b2o$158bobo19bo$157bo2bo3bo15bobo$
158b2o2b2o16b2o$162b2o$146b3o13b2o3b3o4b2o$145bo2bo15bo3b2o4b2o$145bo
4bo13b2ob2o$167b2o29bo$150bo15bo30b3o$149bo46b2obo$145bob2o9bob2obo6b
3o22bo2bo$144bo2bo9b3ob2o7bo2bo8b2o12b2o$146b2o8b2ob4o7bob2o7bobo13bo$
143bo2bo12b2o22bo$143bo15b2o3b2o$147bo11b2o3b2o$144bo11bo15b2o17bo$
145b3o8b2o12b4o17b2o6b2o$157bobo9bo2bo17bobo6b2o$157bo2bo8bobo$151bo6b
2o9bobo$150bobo$149bo2bo$150b2o3b3o11bo74bo$155bob3o9bobo19bo10bo39b2o
$155bo2b3o8b2o19b3o10b2o38b2o$138b3o15b2o2bo28b2o2bo8b2o$138bo2bo15bob
o5b2o22bo$138bo2bo15b3o5b2o21b2o$139bo2bo44bo$139bo2bo12bo31b4o9b2o$
137b2o14b2o34b2o9b2o$137b2o11bo3b2o$136bo3bo8b3o$136b2o10bo2b2o$135bo
12b2ob2o3b2o$136bo3bo6b3o6b2o$137b3o8b2obo$149bo2bo$149bo$150bobo$143b
2o6bo42bo$142bo51bo$142b2o3bo$143bo53bo$148b2o46bobo13bo$147b2o2b2o42b
2ob2o10bobo$149bo2bo43bob2o11b2o$130b3o16b3o5b2o$129bo2bo24b2o$129bo3b
o51bo12b2o$132b2o12bobo36bobo10bo$130bobo13b2o37b2o$127bo2b2o15bo53bo$
128bo2bo10bo52b2ob2obo$131bo9b3o51b2ob2ob2o$128b2ob2o7b2o2bo3b2o49bobo
$129bobo8bo3bo3b2o50bo$130bo9bobo2$141b2ob2o$143bo14b2o$135b2o21b2o$
135bobo$135b2o2bo$136b4o54bo$140b2o2bo47b2o25bobo$140bo2bo49b2o25b2o$
141b3o76bo$149b2o$149b2o$140bo37bobo$138b2o38b2o$121b3o15b2o38bo$121bo
2bo34b2o$119bo4bo34b2o$119bo14bo$118b2o13b3o4b2o$119b2obo9bo2b2o3b2o$
121bo10bo3bo$133b2obo$135b2o$123bobo24b2o$123bobo24b2o2$122bo$131bo2b
2o50bo42bo$131bobobo24b2o24bobo41bo$132bo27b2o24b2o40b3o$115b3o6bobo$
114bo2bo7bo15b2o$114bo3bo22b2o29bo$117b2o12bobo37bo$115bobo13b2o38b3o$
112bo2b2o15bo$113bo2bo10bo23b2o$116bo9b3o22b2o$113b2ob2o7b2o2bo$114bob
o8bo3bo$115bo9bobo$161b2o$126b2ob2o30b2o$128bo$120b2o20b2o$120bobo19b
2o$120b2o2bo$121b4o$125b2o2bo49bobo55bo$125bo2bo23b2o25b2o57b2o$126b3o
23b2o26bo56b2o3$125bo37b4o$123b2o38b2o2bo$106b3o15b2o37bob2o$106bo2bo$
104bo4bo33b2o$104bo38b2o$103b2o20b2o$104b2obo17b2o$106bo11bo$117b3o33b
2o$116bo2b2o32b2o$108bo2bo$108bo$112bo$107bo3b2o6b2o$112b2o3b3o53bo$
116bo55bo74bo$109b3o5b2o25b2o26b3o70bobo$109b2o6b2o25b2o100b2o$126b2o$
126b2o$116bobo$116b2o36b2o$117bo36b2o4$101bobo$101b2o13b2o$102bo13b2o
22b3o$140bo2bo$138bo4bo$127b2o9bo$127b2o8b2o$138b2obo$140bo14b2o$155b
2o10bo$165b2o87bobo$142bobo21b2o87b2o$142bobo110bo2$110bo6b2o22bo$109b
o7b2o$109b3o2$128b2o13bobo$128b2o14bo$95bo$94bo61b2o$94b3o59b2o5$118b
2o15bobo$118b2o15b2o$136bo$159bo104bo$129b2o28bobo103bo$129b2o28b2o
102b3o2$157b2o$104bo52b2o$102b2o$103b2o21bo$125b3o9bo$124bo2b2o8b2o$
119b2o15bobo$89bo29b2o$87b2o$88b2o37b2o$125b3o17b3o$124bo22bo$124b3o
19bo$125b2o2$154b2o$124bobo28b2o$124b2o28bo117bo$125bo147b2o$120b2o
150b2o$120b2o41b2o$162bobo$96bo67bo$96bobo$96b2o$172bo$172b2o$171bobo$
81bo$81bobo$81b2o$180b3o$182bo$181bo3$189b2o$190b2o$189bo92bo$280bobo$
281b2o$198b2o$197bobo$89bobo107bo$89b2o$90bo$207bo$207b2o$206bobo$74bo
bo$74b2o$75bo$215b3o$217bo$216bo3$224b2o$225b2o$224bo64bobo$290b2o$
290bo$233b2o$83bo148bobo$82bo151bo$82b3o2$242bo$242b2o$68bo172bobo$67b
o$67b3o2$250b3o$252bo$251bo3$259b2o$260b2o37bo$259bo40bo$298b3o2$268b
2o$77bo189bobo$75b2o192bo$76b2o2$277bo$277b2o$62bo213bobo$60b2o$61b2o
2$285b3o$287bo$286bo3$294b2o$295b2o10bo$294bo13b2o$307b2o2$303b2o$69bo
232bobo$69bobo232bo$69b2o4$54bo$54bobo$54b2o7$302bobo$302b2o$303bo3$
338b2o$62bobo272bobo$62b2o275bo$63bo4$47bobo$47b2o$48bo6$296bo$295bo$
295b3o4$56bo$55bo$55b3o4$41bo$40bo$40b3o7$290bo$288b2o$289b2o4$50bo$
48b2o$49b2o4$35bo$33b2o$34b2o13$42bo$42bobo$42b2o4$27bo$27bobo$27b2o7$
275bobo$275b2o$276bo4$35bobo$35b2o$36bo4$20bobo$20b2o$21bo6$269bo$268b
o$268b3o4$29bo$28bo$28b3o4$14bo$13bo$13b3o7$263bo$261b2o$262b2o4$23bo$
21b2o$22b2o4$8bo$6b2o$7b2o7$255bo$255bobo$255b2o4$15bo$15bobo$15b2o4$o
$obo$2o!
Nora Brown
- glider_rider
- Posts: 197
- Joined: February 20th, 2013, 5:41 pm
- Location: CA
Re: 13131: The B-Heptomino/Glider Spaceship Thread
16x LWSS rake complete! (Well technically for it to be complete I'd need to also add in all the blocklayers and rephasers, but I'll do that later: The important part is that the spacing is possible.)
Here's the code to generate it:
The automatic assembly is certainly convenient, but also a. really slow, I should really just use an actual linear algebra library, and b. places things backwards a lot so requires a lot of fiddling with the spacing inputs to get something that actually works. I'll hopefully get around to fixing those issues at some point.
EDIT: Improved the above script, it is now a. somewhat faster and b. automatically finds the minimal spacings with significantly less input required.
Code: Select all
x = 2190, y = 6578, rule = B3/S23
2187bobo$2187b2o$2188bo330$2079bobo$2079b2o$2080bo330$1971bobo$1971b2o
$1972bo61$1275b2o$1275b2o12$1276b2o$1276b2o12$1277b2o$1277b2o12$1278b
2o$1278b2o12$1279b2o$1279b2o12$1280b2o$1280b2o12$1281b2o$1281b2o12$
1282b2o$1282b2o12$1283b2o$1283b2o12$1284b2o$1284b2o12$1285b2o$1285b2o
12$1286b2o$1286b2o12$1287b2o$1287b2o12$1288b2o$1288b2o12$1289b2o$1289b
2o12$1290b2o$1290b2o12$1291b2o$1291b2o12$1292b2o$1292b2o12$1293b2o$
1293b2o12$1294b2o$1294b2o12$1295b2o$1295b2o8$1863bobo$1863b2o$1864bo2$
1296b2o$1296b2o12$1297b2o$1297b2o12$1298b2o$1298b2o12$1299b2o$1299b2o
12$1300b2o$1300b2o12$1301b2o$1301b2o12$1302b2o$1302b2o12$1303b2o$1303b
2o12$1304b2o$1304b2o12$1305b2o$1305b2o12$1306b2o$1306b2o12$1307b2o$
1307b2o12$1308b2o$1308b2o12$1309b2o$1309b2o12$1310b2o$1310b2o12$1311b
2o$1311b2o12$1312b2o$1312b2o12$1313b2o$1313b2o12$1314b2o$1314b2o12$
1315b2o$1315b2o12$1316b2o$1316b2o12$1317b2o$1317b2o12$1318b2o$1318b2o
12$1319b2o$1319b2o12$1320b2o$1320b2o12$1321b2o$1321b2o2$1755bobo$1755b
2o$1756bo8$1322b2o$1322b2o12$1323b2o$1323b2o12$1324b2o$1324b2o12$1325b
2o$1325b2o12$1326b2o$1326b2o12$1327b2o$1327b2o12$1328b2o$1328b2o12$
1329b2o$1329b2o12$1330b2o$1330b2o12$1331b2o$1331b2o12$1332b2o$1332b2o
12$1333b2o$1333b2o12$1334b2o$1334b2o12$1335b2o$1335b2o12$1336b2o$1336b
2o12$1337b2o$1337b2o12$1338b2o$1338b2o12$1339b2o$1339b2o12$1340b2o$
1340b2o12$1341b2o$1341b2o12$1342b2o$1342b2o12$1343b2o$1343b2o12$1344b
2o$1344b2o12$1345b2o$1345b2o12$1346b2o$1346b2o9$1647bobo$1647b2o$1648b
o$1347b2o$1347b2o12$1348b2o$1348b2o12$1349b2o$911b2o436b2o$911b2o11$
1350b2o$912b2o436b2o$912b2o11$1351b2o$913b2o436b2o$913b2o$895b2o$895b
2o2$923b2o$923b2o6$1352b2o$914b2o436b2o$914b2o$896b2o$896b2o2$924b2o$
924b2o6$886b2o465b2o$886b2o27b2o436b2o$915b2o$897b2o$897b2o2$925b2o$
925b2o6$887b2o465b2o$887b2o27b2o436b2o$916b2o$898b2o$898b2o2$926b2o$
926b2o6$888b2o465b2o$888b2o27b2o436b2o$917b2o$899b2o$899b2o2$927b2o$
927b2o6$889b2o465b2o$889b2o27b2o436b2o$918b2o$900b2o$900b2o2$928b2o$
928b2o6$890b2o465b2o$890b2o27b2o436b2o$919b2o$901b2o$901b2o2$929b2o$
929b2o6$891b2o465b2o$891b2o27b2o436b2o$920b2o$902b2o$902b2o2$930b2o$
930b2o6$892b2o465b2o$892b2o27b2o436b2o$921b2o$903b2o$903b2o2$931b2o$
931b2o$883b2o$883b2o4$893b2o465b2o$893b2o27b2o436b2o$922b2o$904b2o$
904b2o2$932b2o$932b2o$884b2o$884b2o4$894b2o465b2o$894b2o27b2o436b2o$
923b2o$905b2o$905b2o2$933b2o$933b2o$885b2o$885b2o4$895b2o465b2o$895b2o
27b2o436b2o$924b2o$906b2o$906b2o2$934b2o$934b2o$886b2o$886b2o4$896b2o
465b2o$896b2o27b2o436b2o$925b2o$907b2o$907b2o2$935b2o$935b2o$887b2o$
887b2o4$897b2o465b2o$897b2o27b2o436b2o$926b2o$908b2o$908b2o2$936b2o$
936b2o$888b2o$888b2o4$898b2o465b2o$898b2o27b2o436b2o$927b2o$909b2o$
909b2o2$937b2o$937b2o$889b2o$889b2o4$899b2o465b2o$899b2o27b2o436b2o$
928b2o$910b2o$910b2o2$938b2o$938b2o$890b2o$890b2o4$900b2o465b2o$900b2o
27b2o436b2o$929b2o$911b2o$911b2o2$939b2o$939b2o$891b2o$891b2o4$901b2o
465b2o$901b2o27b2o436b2o$930b2o$912b2o$912b2o2$940b2o$940b2o$892b2o$
892b2o4$902b2o465b2o$902b2o27b2o436b2o$931b2o$913b2o$913b2o2$941b2o$
941b2o$893b2o$893b2o4$903b2o465b2o$903b2o27b2o436b2o$932b2o$914b2o$
914b2o2$942b2o$942b2o$894b2o$894b2o4$904b2o465b2o$904b2o27b2o436b2o$
933b2o$915b2o$915b2o2$943b2o$943b2o$895b2o$895b2o4$905b2o465b2o$905b2o
27b2o436b2o$934b2o$916b2o$916b2o621bobo$1539b2o$944b2o594bo$944b2o$
896b2o$896b2o4$906b2o465b2o$906b2o27b2o436b2o$935b2o$917b2o$917b2o2$
945b2o$945b2o$897b2o$897b2o4$907b2o465b2o$907b2o27b2o436b2o$936b2o$
918b2o$918b2o2$946b2o$946b2o$898b2o$898b2o4$908b2o465b2o$908b2o27b2o
436b2o$937b2o$919b2o$919b2o2$947b2o$947b2o$899b2o$899b2o4$909b2o465b2o
$909b2o27b2o436b2o$938b2o$920b2o$920b2o2$948b2o$948b2o$900b2o$900b2o4$
910b2o465b2o$910b2o27b2o436b2o$939b2o$921b2o$921b2o2$949b2o$949b2o$
901b2o$901b2o4$911b2o465b2o$911b2o27b2o436b2o$940b2o$922b2o$922b2o2$
950b2o$950b2o$902b2o$902b2o4$912b2o465b2o$912b2o27b2o436b2o$941b2o$
923b2o$923b2o2$951b2o$951b2o$903b2o$903b2o4$913b2o465b2o$913b2o27b2o
436b2o$942b2o$924b2o$924b2o2$952b2o$952b2o$904b2o$904b2o4$914b2o465b2o
$914b2o27b2o436b2o$943b2o$925b2o$925b2o2$953b2o$953b2o$905b2o$905b2o4$
915b2o465b2o$915b2o27b2o436b2o$944b2o$926b2o$926b2o2$954b2o$954b2o$
906b2o$906b2o4$916b2o465b2o$916b2o27b2o436b2o$945b2o$927b2o$927b2o2$
955b2o$955b2o$907b2o$907b2o4$917b2o465b2o$917b2o27b2o436b2o$946b2o$
928b2o$928b2o2$956b2o$956b2o$908b2o$908b2o4$918b2o465b2o$918b2o27b2o
436b2o$947b2o$929b2o$929b2o2$957b2o$957b2o$909b2o$909b2o4$919b2o465b2o
$919b2o27b2o436b2o$948b2o$930b2o$930b2o2$958b2o$958b2o$910b2o$910b2o4$
920b2o465b2o$920b2o27b2o436b2o$949b2o$931b2o$727b2o202b2o$727b2o$959b
2o$959b2o$911b2o$911b2o4$921b2o465b2o$921b2o27b2o436b2o$950b2o$932b2o$
728b2o202b2o$728b2o$960b2o$960b2o$912b2o$912b2o4$922b2o465b2o$922b2o
27b2o436b2o$951b2o$933b2o$729b2o202b2o$729b2o$961b2o$961b2o$913b2o$
739b2o172b2o$739b2o3$923b2o465b2o$923b2o27b2o436b2o$952b2o$934b2o$730b
2o202b2o$730b2o$712b2o248b2o$712b2o248b2o$914b2o$740b2o172b2o$740b2o3$
924b2o465b2o$924b2o27b2o436b2o$953b2o$935b2o$731b2o202b2o$731b2o$713b
2o248b2o$713b2o248b2o$915b2o$741b2o172b2o$741b2o3$925b2o465b2o$925b2o
27b2o436b2o$954b2o$703b2o231b2o$703b2o27b2o202b2o$732b2o$714b2o248b2o$
714b2o248b2o$916b2o$742b2o172b2o$742b2o3$926b2o465b2o$926b2o27b2o436b
2o$955b2o$704b2o231b2o$704b2o27b2o202b2o$733b2o$715b2o248b2o$715b2o
248b2o$917b2o$743b2o172b2o$743b2o3$927b2o465b2o$927b2o27b2o436b2o$956b
2o$705b2o231b2o$705b2o27b2o202b2o$734b2o$716b2o248b2o$716b2o248b2o$
918b2o$744b2o172b2o$744b2o3$928b2o465b2o$928b2o27b2o436b2o$957b2o$706b
2o231b2o$706b2o27b2o202b2o$735b2o$717b2o248b2o$717b2o248b2o$919b2o$
745b2o172b2o$745b2o3$929b2o465b2o$929b2o27b2o436b2o$958b2o$707b2o231b
2o$707b2o27b2o202b2o$736b2o$718b2o248b2o$718b2o248b2o$920b2o$746b2o
172b2o$746b2o3$930b2o465b2o$930b2o27b2o436b2o$959b2o$708b2o231b2o$708b
2o27b2o202b2o$737b2o$719b2o248b2o$719b2o248b2o$921b2o$747b2o172b2o$
747b2o$699b2o730bobo$699b2o730b2o$931b2o465b2o32bo$931b2o27b2o436b2o$
960b2o$709b2o231b2o$709b2o27b2o202b2o$738b2o$720b2o248b2o$720b2o248b2o
$922b2o$748b2o172b2o$748b2o$700b2o$700b2o$932b2o465b2o$932b2o27b2o436b
2o$961b2o$710b2o231b2o$710b2o27b2o202b2o$739b2o$721b2o248b2o$721b2o
248b2o$923b2o$749b2o172b2o$749b2o$701b2o$701b2o$933b2o465b2o$933b2o27b
2o436b2o$962b2o$711b2o231b2o$711b2o27b2o202b2o$740b2o$722b2o248b2o$
722b2o248b2o$924b2o$750b2o172b2o$750b2o$702b2o$702b2o$934b2o465b2o$
934b2o27b2o436b2o$963b2o$712b2o231b2o$712b2o27b2o202b2o$741b2o$723b2o
248b2o$723b2o248b2o$925b2o$751b2o172b2o$751b2o$703b2o$703b2o$935b2o
465b2o$935b2o27b2o436b2o$964b2o$713b2o231b2o$713b2o27b2o202b2o$742b2o$
724b2o248b2o$724b2o248b2o$926b2o$752b2o172b2o$752b2o$704b2o$704b2o692b
3o$936b2o460bo2bo$936b2o27b2o429bo4bo$965b2o429bo$714b2o231b2o446b2o$
714b2o27b2o202b2o447b2obo$743b2o653bo$725b2o248b2o$725b2o248b2o$927b2o
471bobo$753b2o172b2o471bobo$753b2o$705b2o692bo$705b2o$937b2o$937b2o27b
2o$966b2o433bobo$715b2o231b2o452bo$715b2o27b2o202b2o$744b2o$726b2o248b
2o$726b2o248b2o$928b2o$754b2o172b2o$754b2o$706b2o685bobo$706b2o685b2o$
938b2o454bo$938b2o27b2o$967b2o$716b2o231b2o$716b2o27b2o202b2o$745b2o$
727b2o248b2o$727b2o248b2o$929b2o$755b2o172b2o$755b2o$707b2o$707b2o$
939b2o$939b2o27b2o$968b2o$717b2o231b2o$717b2o27b2o202b2o$607b2o137b2o
639bo$607b2o119b2o248b2o406bo$728b2o248b2o406b3o$930b2o$756b2o172b2o$
756b2o$708b2o$708b2o$940b2o$940b2o27b2o$969b2o$718b2o231b2o$718b2o27b
2o202b2o$608b2o137b2o$608b2o119b2o248b2o$729b2o248b2o$931b2o$757b2o
172b2o$757b2o$709b2o$709b2o$941b2o438bo$941b2o27b2o407b2o$970b2o408b2o
$719b2o231b2o$719b2o27b2o202b2o$609b2o137b2o$609b2o119b2o248b2o$730b2o
248b2o$932b2o$758b2o172b2o$758b2o$710b2o$710b2o$942b2o$942b2o27b2o$
971b2o$720b2o231b2o$720b2o27b2o202b2o$610b2o137b2o$610b2o119b2o248b2o$
592b2o137b2o248b2o$592b2o339b2o438bo$759b2o172b2o438bobo$759b2o612b2o$
711b2o$711b2o$943b2o$943b2o27b2o$972b2o$582b2o137b2o231b2o$582b2o137b
2o27b2o202b2o$611b2o137b2o$611b2o119b2o248b2o$593b2o137b2o248b2o$593b
2o339b2o$760b2o172b2o$760b2o$712b2o$712b2o$944b2o$944b2o27b2o$973b2o$
583b2o137b2o231b2o409bobo$583b2o137b2o27b2o202b2o409b2o$612b2o137b2o
614bo$612b2o119b2o248b2o$594b2o137b2o248b2o$594b2o339b2o$761b2o172b2o$
761b2o$713b2o$713b2o$945b2o$945b2o27b2o$974b2o$584b2o137b2o231b2o$584b
2o137b2o27b2o202b2o$613b2o137b2o$613b2o119b2o248b2o$595b2o137b2o248b2o
$595b2o339b2o$762b2o172b2o$762b2o596bo$714b2o643bo$714b2o643b3o$946b2o
$946b2o27b2o$975b2o$585b2o137b2o231b2o$585b2o137b2o27b2o202b2o$614b2o
137b2o$614b2o119b2o248b2o$596b2o137b2o248b2o$596b2o339b2o$763b2o172b2o
$763b2o$715b2o$715b2o$947b2o$947b2o27b2o$976b2o$586b2o137b2o231b2o$
586b2o137b2o27b2o202b2o$615b2o137b2o598bo$615b2o119b2o248b2o364b2o$
597b2o137b2o248b2o365b2o$597b2o339b2o$764b2o172b2o$764b2o$716b2o$716b
2o$948b2o$948b2o27b2o$977b2o$587b2o137b2o231b2o$587b2o137b2o27b2o202b
2o$616b2o137b2o$616b2o119b2o248b2o$598b2o137b2o248b2o$598b2o339b2o471b
2o$765b2o172b2o471b2o$765b2o$717b2o$717b2o$949b2o395bo$949b2o27b2o366b
obo$978b2o366b2o$588b2o137b2o231b2o$588b2o137b2o27b2o202b2o$617b2o137b
2o$617b2o119b2o248b2o$599b2o137b2o248b2o$599b2o339b2o$766b2o172b2o$
766b2o$718b2o$718b2o$950b2o$950b2o27b2o$979b2o$589b2o137b2o231b2o$589b
2o137b2o27b2o202b2o$618b2o137b2o$618b2o119b2o248b2o$600b2o137b2o248b2o
$600b2o339b2o396bobo$767b2o172b2o396b2o$767b2o571bo$719b2o$719b2o$951b
2o$951b2o27b2o$980b2o$590b2o137b2o231b2o$590b2o137b2o27b2o202b2o$619b
2o137b2o$619b2o119b2o248b2o$601b2o137b2o248b2o$601b2o339b2o$768b2o172b
2o$768b2o$720b2o$720b2o$952b2o$952b2o27b2o$981b2o350bo$591b2o137b2o
231b2o367bo$591b2o137b2o27b2o202b2o367b3o$620b2o137b2o$620b2o119b2o
248b2o$602b2o137b2o248b2o$602b2o339b2o$769b2o172b2o$769b2o$721b2o$721b
2o$953b2o$953b2o27b2o$982b2o$592b2o137b2o231b2o$592b2o137b2o27b2o202b
2o$621b2o137b2o$621b2o119b2o248b2o$603b2o137b2o248b2o$603b2o339b2o$
770b2o172b2o$770b2o555bo$722b2o601b2o$722b2o602b2o$954b2o$954b2o27b2o$
983b2o$593b2o137b2o231b2o$593b2o137b2o27b2o202b2o$622b2o137b2o$622b2o
119b2o248b2o$604b2o137b2o248b2o$604b2o339b2o$771b2o172b2o$771b2o$723b
2o$723b2o$955b2o$955b2o27b2o$984b2o$594b2o137b2o231b2o$594b2o137b2o27b
2o202b2o$623b2o137b2o$623b2o119b2o248b2o$605b2o137b2o248b2o$605b2o339b
2o$772b2o172b2o$772b2o$724b2o$724b2o$956b2o$956b2o27b2o$985b2o$595b2o
137b2o231b2o$595b2o137b2o27b2o202b2o$624b2o137b2o$624b2o119b2o248b2o$
606b2o137b2o248b2o$606b2o339b2o$773b2o172b2o$773b2o$725b2o$725b2o$957b
2o353bobo$957b2o27b2o324b2o$986b2o325bo$596b2o137b2o231b2o$596b2o137b
2o27b2o202b2o$625b2o137b2o$625b2o119b2o248b2o$607b2o137b2o248b2o$607b
2o339b2o$774b2o172b2o$774b2o$726b2o$726b2o$958b2o$958b2o27b2o$987b2o$
597b2o137b2o231b2o$597b2o137b2o27b2o202b2o$626b2o137b2o$626b2o119b2o
248b2o$608b2o137b2o248b2o307bo$608b2o339b2o354bo$775b2o172b2o354b3o$
775b2o$727b2o$727b2o$959b2o$959b2o27b2o$988b2o$598b2o137b2o231b2o$598b
2o137b2o27b2o202b2o$627b2o137b2o$627b2o119b2o248b2o$609b2o137b2o248b2o
$609b2o339b2o$776b2o172b2o$776b2o$728b2o$728b2o$960b2o$960b2o27b2o$
989b2o309bo$599b2o137b2o231b2o325b2o$599b2o137b2o27b2o202b2o326b2o$
628b2o137b2o$628b2o119b2o248b2o$610b2o137b2o248b2o$610b2o339b2o$777b2o
172b2o$777b2o$729b2o$729b2o$961b2o$961b2o27b2o$990b2o$600b2o137b2o231b
2o$600b2o137b2o27b2o202b2o$629b2o137b2o$629b2o119b2o248b2o$611b2o137b
2o248b2o$611b2o339b2o$778b2o172b2o$778b2o512bo$730b2o560bobo$730b2o
560b2o$962b2o$962b2o27b2o$991b2o$601b2o137b2o231b2o$601b2o137b2o27b2o
202b2o$630b2o137b2o$630b2o119b2o248b2o$612b2o137b2o248b2o$612b2o339b2o
$779b2o172b2o$779b2o$731b2o$731b2o$963b2o$963b2o27b2o$992b2o$602b2o
137b2o231b2o$602b2o137b2o27b2o202b2o$631b2o137b2o513bobo$631b2o119b2o
248b2o281b2o$613b2o137b2o248b2o282bo$613b2o339b2o$780b2o172b2o$780b2o$
732b2o$732b2o$964b2o$964b2o27b2o$993b2o$603b2o137b2o231b2o$603b2o137b
2o27b2o202b2o$632b2o137b2o$632b2o119b2o248b2o$614b2o137b2o248b2o$614b
2o339b2o471b2o$781b2o172b2o471b2o$781b2o$733b2o$733b2o544bo$965b2o311b
o$965b2o27b2o282b3o$994b2o$604b2o137b2o231b2o$604b2o137b2o27b2o202b2o$
633b2o137b2o$633b2o119b2o248b2o$615b2o137b2o248b2o$615b2o339b2o$782b2o
172b2o$782b2o$734b2o$734b2o$966b2o$966b2o27b2o$995b2o$605b2o137b2o231b
2o$605b2o137b2o27b2o202b2o$634b2o137b2o$634b2o119b2o248b2o$616b2o137b
2o248b2o266bo$616b2o339b2o312b2o$783b2o172b2o313b2o$783b2o$735b2o$735b
2o$967b2o$967b2o27b2o$996b2o$606b2o137b2o231b2o$606b2o137b2o27b2o202b
2o$635b2o137b2o$635b2o119b2o248b2o$617b2o137b2o248b2o$617b2o339b2o$
784b2o172b2o$784b2o$736b2o$736b2o$968b2o$968b2o27b2o$997b2o266bo$607b
2o137b2o231b2o284bobo$607b2o137b2o27b2o202b2o284b2o$636b2o137b2o$636b
2o119b2o248b2o$618b2o137b2o248b2o$618b2o339b2o$785b2o172b2o$785b2o$
737b2o$737b2o$969b2o$969b2o27b2o$998b2o$608b2o137b2o231b2o$608b2o137b
2o27b2o202b2o$637b2o137b2o$637b2o119b2o248b2o$619b2o137b2o248b2o$619b
2o339b2o$786b2o172b2o$786b2o470bobo$738b2o518b2o$738b2o519bo$970b2o$
970b2o27b2o$999b2o$609b2o137b2o231b2o$609b2o137b2o27b2o202b2o$638b2o
137b2o$638b2o119b2o248b2o$620b2o137b2o248b2o$620b2o339b2o$787b2o172b2o
$787b2o$739b2o$739b2o$971b2o$971b2o27b2o$1000b2o$610b2o137b2o231b2o$
610b2o137b2o27b2o202b2o268bo$639b2o137b2o471bo$639b2o119b2o248b2o239b
3o$621b2o137b2o248b2o$621b2o339b2o$788b2o172b2o$788b2o$740b2o$740b2o$
972b2o$972b2o27b2o$1001b2o$611b2o137b2o231b2o$611b2o137b2o27b2o202b2o$
640b2o137b2o$640b2o119b2o248b2o$622b2o137b2o248b2o$622b2o339b2o$789b2o
172b2o$789b2o$741b2o$741b2o503bo$973b2o269b2o$973b2o27b2o241b2o$1002b
2o$612b2o137b2o231b2o$612b2o137b2o27b2o202b2o$641b2o137b2o$641b2o119b
2o248b2o$623b2o137b2o248b2o$623b2o339b2o$790b2o172b2o$790b2o$742b2o$
742b2o$974b2o$974b2o27b2o$1003b2o$613b2o137b2o231b2o$613b2o137b2o27b2o
202b2o$642b2o137b2o$642b2o119b2o248b2o$624b2o137b2o248b2o223bo$624b2o
339b2o271bobo$791b2o172b2o271b2o$791b2o$743b2o$743b2o$975b2o$975b2o27b
2o$1004b2o$614b2o137b2o231b2o$614b2o137b2o27b2o202b2o$643b2o137b2o$
643b2o119b2o248b2o$625b2o137b2o248b2o$625b2o339b2o$792b2o172b2o$792b2o
$744b2o$744b2o$976b2o$976b2o27b2o$1005b2o224bobo$615b2o137b2o231b2o
242b2o$615b2o137b2o27b2o202b2o243bo$644b2o137b2o$644b2o119b2o248b2o$
626b2o137b2o248b2o$626b2o339b2o$793b2o172b2o$793b2o$745b2o$745b2o$977b
2o$977b2o27b2o$1006b2o$616b2o137b2o231b2o$616b2o137b2o27b2o202b2o$645b
2o137b2o$645b2o119b2o248b2o$627b2o137b2o248b2o$627b2o339b2o$794b2o172b
2o255bo$794b2o428bo$746b2o476b3o$746b2o$978b2o$978b2o27b2o$1007b2o$
617b2o137b2o231b2o$617b2o137b2o27b2o202b2o$646b2o137b2o$646b2o119b2o
248b2o$628b2o137b2o248b2o$628b2o339b2o$795b2o172b2o$795b2o$747b2o$747b
2o$979b2o$979b2o27b2o$1008b2o$618b2o137b2o231b2o$618b2o137b2o27b2o202b
2o227bo$647b2o137b2o429b2o$647b2o119b2o248b2o198b2o$629b2o137b2o248b2o
$629b2o339b2o$796b2o172b2o$796b2o$748b2o$748b2o$980b2o$980b2o27b2o$
1009b2o$619b2o137b2o231b2o$619b2o137b2o27b2o202b2o$648b2o137b2o$648b2o
119b2o248b2o$630b2o137b2o248b2o$630b2o339b2o471b2o$797b2o172b2o471b2o$
797b2o$749b2o$749b2o$981b2o$981b2o27b2o$1010b2o$620b2o137b2o231b2o$
620b2o137b2o27b2o202b2o$649b2o137b2o$649b2o119b2o248b2o$631b2o137b2o
248b2o$631b2o339b2o$798b2o172b2o$798b2o$750b2o$750b2o$982b2o$982b2o27b
2o$1011b2o$621b2o137b2o231b2o$621b2o137b2o27b2o202b2o$650b2o137b2o$
650b2o119b2o248b2o$632b2o137b2o248b2o181bobo$632b2o339b2o229b2o$799b2o
172b2o230bo$799b2o$751b2o$751b2o$983b2o$983b2o27b2o$1012b2o$622b2o137b
2o231b2o$622b2o137b2o27b2o202b2o$651b2o137b2o$651b2o119b2o248b2o$633b
2o137b2o248b2o$633b2o339b2o$800b2o172b2o$800b2o$752b2o$752b2o$984b2o$
984b2o27b2o183bo$1013b2o182bo$623b2o137b2o231b2o200b3o$623b2o137b2o27b
2o202b2o$652b2o137b2o$652b2o119b2o248b2o$634b2o137b2o248b2o$634b2o339b
2o$801b2o172b2o$801b2o$753b2o$753b2o$985b2o$985b2o27b2o$1014b2o$624b2o
137b2o231b2o$624b2o137b2o27b2o202b2o$653b2o137b2o$653b2o119b2o248b2o$
635b2o137b2o248b2o$635b2o339b2o$802b2o172b2o214bo$802b2o386b2o$754b2o
435b2o$754b2o$986b2o$986b2o27b2o$1015b2o$625b2o137b2o231b2o$625b2o137b
2o27b2o202b2o$654b2o137b2o$654b2o119b2o248b2o$636b2o137b2o248b2o$636b
2o339b2o$803b2o172b2o$803b2o$755b2o$755b2o$987b2o$987b2o27b2o$1016b2o$
626b2o137b2o231b2o$626b2o137b2o27b2o202b2o184bo$655b2o137b2o388bobo$
655b2o119b2o248b2o156b2o$637b2o137b2o248b2o$637b2o339b2o$804b2o172b2o$
804b2o$756b2o$756b2o$988b2o$988b2o27b2o$1017b2o$627b2o137b2o231b2o$
627b2o137b2o27b2o202b2o$656b2o137b2o$656b2o119b2o248b2o$638b2o137b2o
248b2o$638b2o339b2o$805b2o172b2o$805b2o$757b2o$757b2o418bobo$989b2o
186b2o$989b2o27b2o158bo$1018b2o$628b2o137b2o231b2o$628b2o137b2o27b2o
202b2o$657b2o137b2o$657b2o119b2o248b2o$639b2o137b2o248b2o$639b2o339b2o
$806b2o172b2o$806b2o$758b2o$758b2o$990b2o$990b2o27b2o$1019b2o$629b2o
137b2o231b2o$629b2o137b2o27b2o202b2o$658b2o137b2o$658b2o119b2o248b2o
140bo$640b2o137b2o248b2o139bo$640b2o339b2o187b3o$807b2o172b2o$807b2o$
759b2o$759b2o$991b2o$991b2o27b2o$1020b2o$630b2o137b2o231b2o$630b2o137b
2o27b2o202b2o$659b2o137b2o$659b2o119b2o248b2o$641b2o137b2o248b2o$641b
2o339b2o$808b2o172b2o$808b2o$760b2o$760b2o$992b2o$992b2o27b2o142bo$
1021b2o140b2o$631b2o137b2o231b2o159b2o$631b2o137b2o27b2o202b2o$660b2o
137b2o$660b2o119b2o248b2o$642b2o137b2o248b2o$642b2o339b2o$809b2o172b2o
$809b2o$761b2o$761b2o$993b2o$993b2o27b2o$1022b2o$632b2o137b2o231b2o$
632b2o137b2o27b2o202b2o$661b2o137b2o$661b2o119b2o248b2o$643b2o137b2o
248b2o$643b2o339b2o$810b2o172b2o171bo$810b2o345bobo$762b2o393b2o$762b
2o$994b2o$994b2o27b2o$1023b2o$633b2o137b2o231b2o$633b2o137b2o27b2o202b
2o$662b2o137b2o$662b2o119b2o248b2o$644b2o137b2o248b2o$644b2o339b2o$
811b2o172b2o$811b2o$763b2o$763b2o$995b2o$995b2o27b2o$1024b2o$634b2o
137b2o231b2o$634b2o137b2o27b2o202b2o142bobo$663b2o137b2o346b2o$663b2o
119b2o248b2o115bo$645b2o137b2o248b2o$645b2o339b2o$812b2o172b2o$812b2o$
764b2o$764b2o$996b2o$996b2o27b2o$1025b2o$635b2o137b2o231b2o$635b2o137b
2o27b2o202b2o$664b2o137b2o$664b2o119b2o248b2o$646b2o137b2o248b2o$646b
2o339b2o471b2o$813b2o172b2o471b2o$813b2o$765b2o377bo$765b2o376bo$997b
2o144b3o$997b2o27b2o$1026b2o$636b2o137b2o231b2o$636b2o137b2o27b2o202b
2o$665b2o137b2o$665b2o119b2o248b2o$647b2o137b2o248b2o$647b2o339b2o$
814b2o172b2o$814b2o$766b2o$766b2o$998b2o$998b2o27b2o$1027b2o$637b2o
137b2o231b2o$637b2o137b2o27b2o202b2o$666b2o137b2o$666b2o119b2o248b2o
99bo$648b2o137b2o248b2o97b2o$648b2o339b2o146b2o$815b2o172b2o$815b2o$
767b2o$767b2o$999b2o$999b2o27b2o$1028b2o$638b2o137b2o231b2o$638b2o137b
2o27b2o202b2o$667b2o137b2o$667b2o119b2o248b2o$649b2o137b2o248b2o$649b
2o339b2o$816b2o172b2o$816b2o$768b2o$768b2o$1000b2o$1000b2o27b2o99bo$
1029b2o99bobo$639b2o137b2o231b2o117b2o$639b2o137b2o27b2o202b2o$668b2o
137b2o$668b2o119b2o248b2o$650b2o137b2o248b2o$650b2o339b2o$817b2o172b2o
$817b2o$769b2o$769b2o$1001b2o$1001b2o27b2o$1030b2o$640b2o137b2o231b2o$
640b2o137b2o27b2o202b2o$669b2o137b2o$669b2o119b2o248b2o$651b2o137b2o
248b2o$651b2o339b2o$818b2o172b2o129bobo$818b2o303b2o$770b2o352bo$770b
2o$1002b2o$1002b2o27b2o$1031b2o$641b2o137b2o231b2o$641b2o137b2o27b2o
202b2o$670b2o137b2o$670b2o119b2o248b2o$652b2o137b2o248b2o$652b2o339b2o
$819b2o172b2o$819b2o$771b2o$771b2o$1003b2o$1003b2o27b2o$1032b2o$642b2o
137b2o231b2o101bo$642b2o137b2o27b2o202b2o100bo$671b2o137b2o304b3o$671b
2o119b2o248b2o$653b2o137b2o248b2o$653b2o339b2o$820b2o172b2o$820b2o$
772b2o$772b2o$1004b2o$1004b2o27b2o$1033b2o$643b2o137b2o231b2o$643b2o
137b2o27b2o202b2o$672b2o137b2o$672b2o119b2o248b2o$654b2o137b2o248b2o$
654b2o339b2o$821b2o172b2o$821b2o$773b2o336bo$773b2o334b2o$1005b2o103b
2o$1005b2o27b2o$1034b2o$644b2o137b2o231b2o$644b2o137b2o27b2o202b2o$
673b2o137b2o$673b2o119b2o248b2o$655b2o137b2o248b2o$655b2o339b2o$822b2o
172b2o$822b2o$774b2o$774b2o$1006b2o$1006b2o27b2o$1035b2o$645b2o137b2o
231b2o$645b2o137b2o27b2o202b2o$674b2o137b2o$674b2o119b2o248b2o$656b2o
137b2o248b2o$656b2o339b2o$823b2o172b2o$823b2o$775b2o$775b2o$1007b2o$
1007b2o27b2o$1036b2o$646b2o137b2o231b2o$646b2o137b2o27b2o202b2o$675b2o
137b2o$675b2o119b2o248b2o$657b2o137b2o248b2o$657b2o339b2o$824b2o172b2o
$824b2o$776b2o$776b2o$1008b2o$1008b2o27b2o57bobo$1037b2o57b2o$647b2o
137b2o231b2o76bo$647b2o137b2o27b2o202b2o$676b2o137b2o$676b2o119b2o248b
2o$658b2o137b2o248b2o$658b2o339b2o$825b2o172b2o$825b2o$777b2o$777b2o$
1009b2o$1009b2o27b2o$1038b2o$648b2o137b2o231b2o$648b2o137b2o27b2o202b
2o12b3o$677b2o137b2o215bo2bo$677b2o119b2o233bo3bo10b2o$659b2o137b2o
232b2o2bo11b2o$659b2o339b2o32bo55bo$826b2o172b2o33b2o52bo$826b2o207b3o
51b3o$778b2o255b3o$778b2o$1010b2o$1010b2o22b2o$1033b2obo$649b2o137b2o
231b2o9bo3bo$649b2o137b2o27b2o202b2o10bo$678b2o137b2o$678b2o119b2o248b
2o$660b2o137b2o248b2o$660b2o339b2o29bo$827b2o172b2o28bo$827b2o202b3o$
779b2o$779b2o$1011b2o$1011b2o2$650b2o137b2o231b2o60bo$650b2o137b2o27b
2o202b2o58b2o$679b2o137b2o263b2o$679b2o119b2o248b2o$661b2o137b2o248b2o
$661b2o339b2o$828b2o172b2o$828b2o$780b2o264b3o$780b2o263bo2bo$1012b2o
31bo3bo$1012b2o12b3o17b4o$1028bo19bo$651b2o137b2o226b3o6bo$651b2o137b
2o27b2o196bo2bo$680b2o137b2o196bo2bo$680b2o119b2o213bo2bo15b2o$662b2o
137b2o214b3o16b2o8bobo$662b2o339b2o12b2o16bo11b2o427b2o$829b2o172b2o
42bo428b2o$829b2o190bo$781b2o238bo54bo$781b2o239bo20b2o31bobo$1013b2o
3b2obo21b2o31b2o$1013b2o2bo$1019bo4bo14b3o$652b2o137b2o245bo2bo6b2o$
652b2o137b2o27b2o199bobo14bo3bo5b2o$681b2o137b2o199b3o13b2o2bo$681b2o
119b2o235bo$663b2o137b2o236b2o$663b2o339b2o34b3o$830b2o172b2o34b3o$
830b2o$782b2o$782b2o255b2o$1038b2obo$1037bo3bo14bo$1038bo18bo$653b2o
137b2o255b2o4b3o$653b2o137b2o27b2o226b2o$682b2o137b2o$682b2o119b2o232b
o31bobo$664b2o137b2o231bo32b2o$664b2o339b2o29b3o31bo$831b2o172b2o$831b
2o212b3o$783b2o259bo2bo$783b2o259bo4bo2$1049bo$1048bo$654b2o137b2o249b
ob2o$654b2o137b2o27b2o219bo2bo$683b2o137b2o221b2o$683b2o119b2o236bo2bo
$665b2o137b2o236bo$665b2o339b2o38bo$832b2o172b2o35bo$832b2o210b3o17b2o
$784b2o277b2o$784b2o278bo$1062bo$1031bo$1029b2o26b2o3b3o$655b2o137b2o
234b2o25bobo$655b2o137b2o27b2o232bo$684b2o137b2o$684b2o119b2o$666b2o
137b2o244bo$666b2o339b2o41b2o$833b2o172b2o41bobo$833b2o$785b2o$785b2o$
1043b3o$1043bo$1044bo$656b2o137b2o$656b2o137b2o27b2o$685b2o137b2o$685b
2o119b2o$667b2o137b2o$667b2o339b2o$834b2o172b2o13bo$834b2o187bobo$786b
2o235b2o$786b2o4$657b2o137b2o$657b2o137b2o27b2o$686b2o137b2o$686b2o
119b2o$668b2o137b2o$668b2o339b2o$835b2o172b2o$835b2o$787b2o$787b2o4$
658b2o137b2o$658b2o137b2o27b2o188bobo$687b2o137b2o188b2o$687b2o119b2o
207bo$669b2o137b2o$669b2o339b2o$836b2o172b2o$836b2o$788b2o$788b2o4$
659b2o137b2o$659b2o137b2o27b2o$688b2o137b2o$688b2o119b2o207bo$670b2o
137b2o205b2obo$670b2o341bo6bo$837b2o180bo$837b2o$789b2o221bo4bo$789b2o
225bo$1015bo3$660b2o137b2o$660b2o137b2o27b2o$689b2o137b2o$689b2o119b2o
$671b2o137b2o$671b2o$838b2o$838b2o$790b2o$790b2o4$661b2o137b2o$661b2o
137b2o27b2o$690b2o137b2o$690b2o119b2o$672b2o137b2o$672b2o$839b2o$839b
2o$791b2o$791b2o4$662b2o137b2o$662b2o137b2o27b2o$691b2o137b2o$691b2o
119b2o$673b2o137b2o$673b2o$840b2o$840b2o$792b2o$792b2o4$663b2o137b2o$
663b2o137b2o27b2o$692b2o137b2o$692b2o119b2o$674b2o137b2o$674b2o$841b2o
$841b2o$793b2o$793b2o4$664b2o137b2o$664b2o137b2o27b2o$693b2o137b2o$
693b2o119b2o$675b2o137b2o$675b2o$842b2o$842b2o$794b2o$794b2o4$665b2o
137b2o$665b2o137b2o27b2o$694b2o137b2o$694b2o119b2o$676b2o137b2o$676b2o
$843b2o$843b2o$795b2o200bobo$795b2o200b2o$998bo3$666b2o137b2o$666b2o
137b2o27b2o$695b2o137b2o$695b2o119b2o$677b2o137b2o$677b2o$844b2o$844b
2o$796b2o$796b2o4$667b2o137b2o$667b2o137b2o27b2o$696b2o137b2o$696b2o
119b2o$678b2o137b2o$678b2o812b2o$845b2o645b2o$845b2o$797b2o$797b2o4$
668b2o137b2o$668b2o137b2o27b2o$697b2o137b2o$697b2o119b2o$679b2o137b2o$
679b2o$846b2o$846b2o$798b2o$798b2o4$669b2o137b2o$669b2o137b2o27b2o$
698b2o137b2o$698b2o119b2o$680b2o137b2o$680b2o$847b2o$847b2o$799b2o$
799b2o4$670b2o137b2o$670b2o137b2o27b2o$699b2o137b2o$699b2o119b2o$681b
2o137b2o$681b2o$848b2o301bobo$848b2o302b2o$800b2o350bo$800b2o4$671b2o
137b2o$671b2o137b2o27b2o$700b2o137b2o$700b2o119b2o$682b2o137b2o$682b2o
$849b2o$849b2o$801b2o$801b2o4$672b2o137b2o$672b2o137b2o27b2o$701b2o
137b2o$701b2o119b2o$683b2o137b2o$683b2o$850b2o$850b2o$802b2o$802b2o4$
673b2o137b2o$673b2o137b2o27b2o$702b2o137b2o$702b2o119b2o$684b2o137b2o$
684b2o$851b2o$851b2o$803b2o$803b2o4$674b2o137b2o$674b2o137b2o27b2o$
703b2o137b2o$703b2o119b2o$685b2o137b2o$685b2o$852b2o$852b2o$804b2o$
804b2o4$675b2o137b2o$675b2o137b2o27b2o$704b2o137b2o$704b2o119b2o$686b
2o137b2o$686b2o$853b2o$853b2o$805b2o$805b2o4$676b2o137b2o$676b2o137b2o
27b2o$705b2o137b2o$705b2o119b2o$687b2o137b2o$687b2o$854b2o$854b2o$806b
2o$806b2o4$677b2o137b2o$677b2o137b2o27b2o$706b2o137b2o$706b2o119b2o$
688b2o137b2o$688b2o$855b2o$855b2o$807b2o$807b2o4$678b2o137b2o$678b2o
137b2o27b2o$707b2o137b2o$707b2o119b2o$689b2o137b2o$689b2o$856b2o$856b
2o$808b2o$808b2o4$679b2o137b2o$679b2o137b2o27b2o$708b2o137b2o$708b2o
119b2o$690b2o137b2o$690b2o$857b2o$857b2o$809b2o$809b2o4$680b2o137b2o$
680b2o137b2o27b2o$709b2o137b2o$709b2o119b2o$691b2o137b2o$691b2o$858b2o
$858b2o$810b2o$810b2o4$681b2o137b2o$681b2o137b2o27b2o$710b2o137b2o$
710b2o119b2o$692b2o137b2o$692b2o$859b2o$859b2o$811b2o$811b2o4$682b2o
137b2o$682b2o137b2o27b2o$711b2o137b2o$711b2o119b2o$693b2o137b2o$693b2o
$860b2o$860b2o$812b2o$812b2o4$683b2o137b2o$683b2o137b2o27b2o$712b2o
137b2o$712b2o119b2o$694b2o137b2o$694b2o812b2o$861b2o645b2o$861b2o$813b
2o$813b2o4$684b2o137b2o$684b2o137b2o27b2o$713b2o137b2o$713b2o119b2o$
695b2o137b2o$695b2o$862b2o$862b2o$814b2o$814b2o4$685b2o137b2o$685b2o
137b2o27b2o$714b2o137b2o$714b2o119b2o$696b2o137b2o$696b2o$863b2o$863b
2o$815b2o$815b2o4$686b2o137b2o$686b2o137b2o27b2o$715b2o137b2o$715b2o
119b2o$697b2o137b2o$697b2o$864b2o$864b2o$816b2o$816b2o3$850b3o$687b2o
137b2o21bo2bo$687b2o137b2o21bo2bo$716b2o$716b2o119b2o9b2o$698b2o137b2o
8bo2bo$698b2o147bo2bo$850bo14b2o$865b2o$817b2o$817b2o4$688b2o137b2o$
688b2o137b2o$717b2o$717b2o119b2o$699b2o137b2o$699b2o$866b2o$866b2o$
818b2o$818b2o3$846bo$689b2o137b2o14b2o$689b2o137b2o15b2o$718b2o$718b2o
119b2o$700b2o137b2o$700b2o$862b3o$861bo2bo$819b2o15bo24bo2bo$819b2o14b
3o22bo2bo$834b2o2bo8b2o12b3o$836b3o9b2o11b2o$847bo$690b2o137b2o$690b2o
137b2o$719b2o117bo17b2o$719b2o114bo19bobo6b2o$701b2o131bo3bo18bo6b2o$
701b2o130b2ob2o3$820b2o$820b2o13bo$833b2o20b3o10bo$834b2o18bo2bo11bo$
854bo2bo9b3o$691b2o137b2o$691b2o137b2o21b2o$720b2o130bo2bo33bobo$720b
2o130bo2bo9b2o22b2o$702b2o151bo9b2o23bo$702b2o3$821b2o$821b2o4$692b2o$
692b2o$721b2o$721b2o$703b2o157bo$703b2o156bobo12bo$860b2ob2o12b2o$861b
ob2o11b2o$822b2o$822b2o$851bo11b2o$849b2o12bo$850b2o$693b2o171bo$693b
2o165b2ob2obo$722b2o136b2ob2ob2o$722b2o140bobo$704b2o159bo$704b2o3$
823b2o$823b2o3$859bo$694b2o161b2o27bo$694b2o162b2o24bobo$723b2o160b2o$
723b2o$705b2o$705b2o136bo$843bobo$843b2o$824b2o$824b2o4$695b2o$695b2o$
724b2o$724b2o$706b2o$706b2o2$851bo$825b2o24bobo39bobo$825b2o24b2o41b2o
$894bo3$696b2o138bobo452bobo$696b2o138b2o454b2o$725b2o110bo454bo$725b
2o$707b2o$707b2o3$826b2o$826b2o4$697b2o$697b2o$726b2o116bobo56bo$726b
2o116b2o58bo$708b2o135bo56b3o$708b2o$829b2o$828bob2o$827bo4bo$828bob2o
4$698b2o$698b2o$727b2o$727b2o$709b2o$709b2o4$838bo$837bo73bo$837b3o72b
2o$911b2o$699b2o$699b2o$728b2o$728b2o$710b2o$710b2o812b2o$1524b2o7$
700b2o$700b2o$729b2o$729b2o$711b2o119bo$711b2o117b2o89bo$831b2o86bobo$
920b2o6$701b2o$701b2o$730b2o$730b2o$712b2o$712b2o7$824bo$702b2o120bobo
101bobo$702b2o120b2o103b2o$731b2o196bo$731b2o$713b2o$713b2o8$703b2o$
703b2o$732b2o$732b2o$714b2o$714b2o2$817bobo118bo$817b2o120bo$818bo118b
3o4$704b2o$704b2o$733b2o$733b2o$715b2o$715b2o8$705b2o$705b2o104bo$734b
2o74bo135bo$734b2o74b3o134b2o$716b2o228b2o$716b2o5$731bo$730b3o$729bo
2b2o$706b2o25bo$706b2o23b3o$730bob2o$729b2obo$717b2o12b2o$717b2o9b2obo
$728b2ob2o$728b2ob2o$730bo$805bo$803b2o151bo$804b2o148bobo$955b2o$707b
2o$707b2o3$718b2o$718b2o8$708b2o$708b2o14bo$723bo$723b3o$719b2o76bo$
719b2o76bobo163bobo$797b2o165b2o$715b3o246bo$714bo2bo$714bo3bo$713b2o
2bo10b3o$715bo14bo$716b2o11bo$709b2o5b3o$709b2o5b3o$737b2o$738b2o$715b
2o20bo$714b2obo$713bo3bo$714bo31b2o$745bobo$747bo3$755bo34bobo180bo$
712bo42b2o33b2o182bo$754bobo34bo180b3o4$763b3o$765bo$764bo3$772b2o$
773b2o$772bo3$781b2o$780bobo$782bo3$790bo190bo$790b2o190b2o$789bobo
189b2o4$798b3o$800bo$799bo3$807b2o$808b2o$807bo3$816b2o$815bobo$817bo
2$778bo$776b2o47bo165bo$777b2o46b2o162bobo$824bobo163b2o4$833b3o$835bo
$834bo3$842b2o$843b2o$842bo3$851b2o$850bobo$852bo2$770bo$770bobo87bo
137bobo$770b2o88b2o137b2o$859bobo137bo4$868b3o$870bo$869bo670b2o$1540b
2o2$877b2o$878b2o$877bo3$886b2o$885bobo$887bo2$763bobo$763b2o130bo$
764bo130b2o$894bobo4$903b3o$905bo$904bo3$912b2o$913b2o$912bo3$921b2o$
920bobo$922bo$757bo$756bo259bo$756b3o171bo86b2o$930b2o84b2o$929bobo4$
938b3o$940bo$939bo3$947b2o$948b2o$947bo3$956b2o$955bobo$957bo$751bo$
749b2o275bo$750b2o213bo58bobo$965b2o58b2o$964bobo4$973b3o$975bo$974bo
3$982b2o$983b2o$982bo3$991b2o$990bobo$992bo$743bo$743bobo287bobo$743b
2o255bo33b2o$1000b2o32bo$999bobo2$1431bobo$1432b2o$1008b3o421bo$1010bo
$1009bo3$1017b2o$1018b2o$1017bo3$1026b2o$1025bobo$1027bo672b3o$736bobo
304bo656bo2bo$736b2o306bo655bo$737bo297bo6b3o655bo$1035b2o664bobo$
1034bobo4$1043b3o$1045bo$1044bo10$730bo$729bo$729b3o17$1684b3o$1684bo
2bo$724bo959bo$722b2o960bo$723b2o960bobo19$716bo$716bobo$716b2o7$1148b
3o$1150bo$1149bo6$1668b3o$1668bo2bo$1668bo$1668bo$709bobo957bobo$709b
2o$710bo18$703bo$702bo$702b3o8$1556b2o$1556b2o5$1652b3o$1652bo2bo$
1652bo$1652bo$1653bobo$697bo$695b2o$696b2o19$689bo$689bobo$689b2o8$
1288b3o$1290bo$1289bo2$1636b3o$1636bo2bo$1636bo$1636bo$1637bobo3$682bo
bo$682b2o$683bo31$1620b3o$1620bo2bo$1620bo$1620bo$1621bobo4$670bo$668b
2o$669b2o19$662bo$662bobo$662b2o9$1428b3o173b3o$1430bo173bo2bo$1429bo
174bo$1604bo$1605bobo6$655bobo$655b2o$656bo18$649bo$648bo$648b3o8$
1588b3o$1588bo2bo$1588bo$1588bo$1589bobo7$643bo$641b2o$642b2o19$635bo$
635bobo$635b2o4$1571bobo$1572b2o$1572bo2$1572b2o$1572b2o$1568b3o$1570b
o$1569bo7$628bobo$628b2o$629bo18$622bo$621bo$621b3o19$616bo$614b2o$
615b2o19$608bo$608bobo$608b2o19$601bobo$601b2o$602bo18$595bo$594bo$
594b3o19$589bo$587b2o$588b2o19$581bo$581bobo$581b2o19$574bobo$574b2o$
575bo39$562bo$560b2o$561b2o19$554bo$554bobo$554b2o19$547bobo$547b2o$
548bo18$541bo$540bo$540b3o19$535bo$533b2o$534b2o19$527bo$527bobo$527b
2o19$520bobo$520b2o$521bo18$514bo$513bo$513b3o19$508bo$506b2o$507b2o
19$500bo$500bobo$500b2o19$493bobo$493b2o$494bo18$487bo$486bo$486b3o19$
481bo$479b2o$480b2o19$473bo$473bobo$473b2o19$466bobo$466b2o$467bo39$
454bo$452b2o$453b2o19$446bo$446bobo$446b2o19$439bobo$439b2o$440bo18$
433bo$432bo$432b3o19$427bo$425b2o$426b2o19$419bo$419bobo$419b2o19$412b
obo$412b2o$413bo18$406bo$405bo$405b3o19$400bo$398b2o$399b2o19$392bo$
392bobo$392b2o19$385bobo$385b2o$386bo18$379bo$378bo$378b3o19$373bo$
371b2o$372b2o19$365bo$365bobo$365b2o19$358bobo$358b2o$359bo39$346bo$
344b2o$345b2o19$338bo$338bobo$338b2o19$331bobo$331b2o$332bo18$325bo$
324bo$324b3o19$319bo$317b2o$318b2o19$311bo$311bobo$311b2o19$304bobo$
304b2o$305bo18$298bo$297bo$297b3o19$292bo$290b2o$291b2o19$284bo$284bob
o$284b2o19$277bobo$277b2o$278bo18$271bo$270bo$270b3o19$265bo$263b2o$
264b2o19$257bo$257bobo$257b2o19$250bobo$250b2o$251bo39$238bo$236b2o$
237b2o19$230bo$230bobo$230b2o19$223bobo$223b2o$224bo18$217bo$216bo$
216b3o19$211bo$209b2o$210b2o19$203bo$203bobo$203b2o19$196bobo$196b2o$
197bo18$190bo$189bo$189b3o19$184bo$182b2o$183b2o19$176bo$176bobo$176b
2o19$169bobo$169b2o$170bo18$163bo$162bo$162b3o19$157bo$155b2o$156b2o
19$149bo$149bobo$149b2o19$142bobo$142b2o$143bo39$130bo$128b2o$129b2o
19$122bo$122bobo$122b2o19$115bobo$115b2o$116bo18$109bo$108bo$108b3o19$
103bo$101b2o$102b2o19$95bo$95bobo$95b2o19$88bobo$88b2o$89bo18$82bo$81b
o$81b3o19$76bo$74b2o$75b2o19$68bo$68bobo$68b2o19$61bobo$61b2o$62bo18$
55bo$54bo$54b3o19$49bo$47b2o$48b2o19$41bo$41bobo$41b2o19$34bobo$34b2o$
35bo39$22bo$20b2o$21b2o19$14bo$14bobo$14b2o19$7bobo$7b2o$8bo18$bo$o$3o
!
Code: Select all
import golly as g
from glife import *
import math
import cmath
import os
from scipy import signal, optimize
import numpy as np
def mod(x,m):
return ((x%m)+m)%m
#Returns x,y such that ax+by=gcd(a,b)
#Uses Euclidean algorithm
def extendedGCD(a,b):
#Want to find x, y such that ax+my=1
aSign = (1, -1)[a < 0]
bigVal = a * aSign
bigValCoords = [aSign,0]
bSign = (1, -1)[b < 0]
smallVal = b * bSign
smallValCoords = [0,bSign]
while smallVal > 0:
subtractOutMult = bigVal // smallVal
bigVal, smallVal = smallVal, bigVal - smallVal * subtractOutMult
bigValCoords, smallValCoords = smallValCoords, [bigValCoords[i] - smallValCoords[i] * subtractOutMult for i in range(2)]
return bigValCoords
#Linear algebra stuff
#Wanted to do this myself rather than using a library
#Whether or not this was smart is debatable
#I ended up using scipy instead because it's much faster
#A rational number
class Rational:
#Constructor
def __init__(self, num: int, den: int = 1):
a = math.gcd(num, den)
self.num = (1, -1)[den < 0] * num // a
self.den = abs(den // a)
#Hashing
def __eq__(self, other)->bool:
if isinstance(other, int):
return self.num == other and self.den == 1
elif isinstance(other, Rational):
return self.num == other.num and self.den == other.den
def __hash__(self) -> int:
return hash((self.num,self.den))
#Comparison
def __ne__(self, other)->bool:
if isinstance(other, int):
return self.num != other or self.den != 1
elif isinstance(other, Rational):
return self.num != other.num or self.den != other.den
def __lt__(self, other) -> bool:
if isinstance(other, int | float):
return self.num < other*self.den
elif isinstance(other, Rational):
return self.num*other.den < other.num*self.den
def __le__(self, other) -> bool:
if isinstance(other, int | float):
return self.num <= other*self.den
elif isinstance(other, Rational):
return self.num*other.den <= other.num*self.den
def __gt__(self, other) -> bool:
if isinstance(other, int | float):
return self.num > other*self.den
elif isinstance(other, Rational):
return self.num*other.den > other.num*self.den
def __ge__(self, other) -> bool:
if isinstance(other, int | float):
return self.num >= other*self.den
elif isinstance(other, Rational):
return self.num*other.den >= other.num*self.den
#Arithmetic
def __add__(self, other):
if isinstance(other, int):
return Rational(self.num+other*self.den, self.den)
elif isinstance(other, Rational):
return Rational(self.num*other.den+other.num*self.den, self.den*other.den)
def __radd__(self, other):
if isinstance(other, int):
return self + other
def __sub__(self, other):
if isinstance(other, int):
return Rational(self.num-other*self.den, self.den)
elif isinstance(other, Rational):
return Rational(self.num*other.den-other.num*self.den, self.den*other.den)
def __rsub__(self, other):
if isinstance(other, int):
return -self + other
def __mul__(self, other):
if isinstance(other, int):
return Rational(self.num*other, self.den)
elif isinstance(other, Rational):
return Rational(self.num*other.num, self.den*other.den)
def __rmul__(self, other):
if isinstance(other, int):
return self * other
def __truediv__(self, other):
if isinstance(other, int):
return Rational(self.num, self.den*other)
elif isinstance(other, Rational):
return Rational(self.num*other.den, self.den*other.num)
def __floordiv__(self, other):
return Rational(int(self / other), 1)
def __mod__(self, other):
return self - (self // other) * other
def __neg__(self):
return Rational(-self.num, self.den)
def __abs__(self):
return Rational(abs(self.num), self.den)
#Casting
def __int__(self) -> int:
return self.num // self.den
def __float__(self) -> float:
return self.num / self.den
def __str__(self) -> str:
return str(self.num) + "/" + str(self.den)
#Other math
def gcd(*args):
output = abs(args[0])
for i in range(1,len(args)):
output = Rational(math.gcd(output.num, args[i].num), math.lcm(output.den, args[i].den))
return output
#A matrix of rational numbers
class Matrix:
#Constructor
def __init__(self, terms):
#Automatically convert ints to Rationals
self.terms = [[Rational(1) * term for term in row] for row in terms]
self.height = len(terms)
self.width = 0
if self.height > 0:
self.width = len(terms[0])
#Get terms
def sliceRange(s):
if isinstance(s, int):
return range(s,s+1)
elif isinstance(s, slice):
return range(s.start, s.stop)
def __getitem__(self, key: list[int] | list[slice]):
if isinstance(key[0], int) and isinstance(key[1], int):
return self.terms[key[0]][key[1]]
else:
return Matrix([[self.terms[row][col] for col in Matrix.sliceRange(key[1])] for row in Matrix.sliceRange(key[0])])
#Hashing
def __eq__(self, other)->bool:
return self.terms == other.terms
def __hash__(self) -> int:
return hash(tuple(tuple(row) for row in self.terms))
#Arithmetic
def __add__(self, other):
return Matrix([[term1 + term2 for term1, term2 in zip(row1,row2)] for row1, row2 in zip(self.terms,other.terms)])
def __sub__(self, other):
return Matrix([[term1 - term2 for term1, term2 in zip(row1,row2)] for row1, row2 in zip(self.terms,other.terms)])
#Scalar or matrix multiplication
def __mul__(self, other):
if isinstance(other, int | Rational):
return Matrix([[term * other for term in row] for row in self.terms])
elif isinstance(other, Matrix):
return Matrix([[sum([self[rowIndex,sharedIndex]*other[sharedIndex,colIndex] for sharedIndex in range(self.width)], Rational(0)) for colIndex in range(other.width)] for rowIndex in range(self.height)])
elif isinstance(other, CosetMatrix):
return CosetMatrix(self*other.rep, other.lattice)
def __truediv__(self, other):
return Matrix([[term / other for term in row] for row in self.terms])
def __neg__(self):
return Matrix([[-term for term in row] for row in self.terms])
def transpose(self):
return Matrix([[self[rowIndex,colIndex] for rowIndex in range(self.height)] for colIndex in range(self.width)])
def copy(self):
return Matrix([[term for term in row] for row in self.terms])
def row(self, row: int):
return self[row, 0:self.width]
def col(self, col: int):
return self[0:self.height, col]
def rows(self):
return [self.row(n) for n in range(self.height)]
def cols(self):
return [self.col(n) for n in range(self.width)]
def __str__(self):
output = ""
for row in range(self.height):
output += "["
for col in range(self.width):
output += str(self[row,col])
if col < self.width-1:
output += ","
output += "]"
if row < self.height-1:
output += "\n"
return output
def isZero(self):
return all(all(term == 0 for term in row) for row in self.terms)
#Tools for making block matrices
def blockHorizontal(self, other):
return Matrix([row1+row2 for row1,row2 in zip(self.terms, other.terms)])
def blockVertical(self, other):
return Matrix(self.terms+other.terms)
#Row reduction
def rowReduce(self, normalizeDiagonal = True):
output = self.copy()
rowIndex = 0
colIndex = 0
while rowIndex < output.height and colIndex < output.width:
#Check if this column is zero below rowIndex, if so goto next column
nonzeroRowIndex = next((rowCheckIndex for rowCheckIndex in range(rowIndex, output.height) if output[rowCheckIndex,colIndex] != 0), -1)
if nonzeroRowIndex == -1:
colIndex += 1
else:
#Otherwise, do a row-reduction step
#Swap rows rowIndex and nonzeroRowIndex if needed
if nonzeroRowIndex != rowIndex:
output.swapRowsInPlace(rowIndex, nonzeroRowIndex)
#Normalize to 1
if normalizeDiagonal:
divideByVal = output[rowIndex, colIndex]
output.terms[rowIndex] = [term / divideByVal for term in output.terms[rowIndex]]
for otherRowIndex in range(output.height):
if otherRowIndex != rowIndex:
mult = output[otherRowIndex, colIndex] / output[rowIndex, colIndex]
output.terms[otherRowIndex] = [otherRowTerm - rowTerm * mult for rowTerm, otherRowTerm in zip(output.terms[rowIndex], output.terms[otherRowIndex])]
rowIndex += 1
return output
def swapRowsInPlace(self, row1: int, row2: int):
self.terms[row1], self.terms[row2] = self.terms[row2], self.terms[row1]
def removeZeroRows(self):
return Matrix([row for row in self.terms if not all(term == 0 for term in row)])
def det(self):
#TODO: This is wrong because our row reduction isn't like that
rowReducedForm = self.rowReduce(normalizeDiagonal = False)
return math.prod([rowReducedForm[i,i] for i in range(rowReducedForm.width)], start = Rational(1))
def rank(self):
return len([row for row in self.terms if not all(term == 0 for term in row)])
def id(n: int):
return Matrix([[Rational(int(row == col)) for col in range(n)] for row in range(n)])
def zero(height: int, width: int):
return Matrix([[Rational(0) for col in range(width)] for row in range(height)])
#Gives the inverse of an invertible square matrix
def inverse(self):
return self.blockHorizontal(Matrix.id(self.width)).rowReduce()[0:self.height,self.width:self.width*2]
#Gives a right inverse
def rightInverse(self):
transpose = self.transpose()
return transpose * (self * transpose).inverse()
#Gives a left inverse
def leftInverse(self):
transpose = self.transpose()
return (transpose * self).inverse() * transpose
'''
#Row reduction but we can only use integer multiples
#This is a naive algorithm prone to blowups in term size
#TODO: Implement an algorithm that's actually fast
def integerRowReduceOld(self):
output = self.copy()
rowIndex = 0
colIndex = 0
while rowIndex < output.height and colIndex < output.width:
#Check if this column is zero below rowIndex, if so goto next column
existsANonzeroEntry = False
for rowToTest in range(rowIndex, output.height):
if output[rowToTest, colIndex] != 0:
existsANonzeroEntry = True
if rowToTest == rowIndex:
#On the starting row, so the most we do is swap the sign to positive if needed
if output[rowToTest, colIndex] < 0:
output.terms[rowIndex] = [-term for term in output.terms[rowIndex]]
continue
else:
#TODO: Some of the ints going into here have hundreds of thousands of bits
# This is surely avoidable
#Find best possible linear combination with output[rowToTest, colIndex] and output[rowIndex, colIndex]
startingSign = (-1,1)[output[rowToTest, colIndex] > 0]
vals = [output[rowIndex, colIndex], output[rowToTest, colIndex] * startingSign]
coords = [[1,0], [0,startingSign]]
while vals[1] != 0:
g.show("Row Reducing: Row "+str(rowIndex)+", Col "+str(colIndex) + ", Val length: "+str(vals[0].num.bit_length()+vals[0].den.bit_length()))
subtractOutMult = int(vals[0] // vals[1])
vals = [vals[1], vals[0] - vals[1] * subtractOutMult]
coords = [coords[1], [coords[0][i] - coords[1][i] * subtractOutMult for i in range(2)]]
#Use this linear combination
output.terms[rowIndex], output.terms[rowToTest] = [term * coords[0][0] + termTest * coords[0][1] for term, termTest in zip(output.terms[rowIndex], output.terms[rowToTest])], [term * coords[1][0] + termTest * coords[1][1] for term, termTest in zip(output.terms[rowIndex], output.terms[rowToTest])]
if existsANonzeroEntry and rowIndex < output.height and colIndex < output.width and output[rowIndex, colIndex] != 0:
#Subtract as much from the rows < rowIndex as possible while leaving the term positive
for rowToModify in range(rowIndex):
mult = output[rowToModify, colIndex] // output[rowIndex, colIndex]
if mult != 0:
output.terms[rowToModify] = [termToModify - term * mult for term, termToModify in zip(output.terms[rowIndex],output.terms[rowToModify])]
rowIndex += 1
else:
colIndex += 1
return output
def integerRowReduceTest(self):
#output = self.hnf()
try:
output = self.hnf()
except:
g.warn("Error at "+str(self))
test = self.integerRowReduceOld()
if test != output:
g.warn(str(self)+"\n\n"+str(test) + "\n\n"+str(output))
return output
'''
#Gram-Schmidt orthogonalization
def orthogonalize(self):
output = self.copy()
for rowIndex in range(self.height):
for priorRowIndex in range(rowIndex):
dot = (output.row(priorRowIndex) * output.row(priorRowIndex).transpose())[0,0]
if dot != 0:
removalMult = (output.row(rowIndex) * output.row(priorRowIndex).transpose())[0,0] / dot
output.terms[rowIndex] = [term - priorTerm * removalMult for term, priorTerm in zip(output.terms[rowIndex], output.terms[priorRowIndex])]
return output
#Hermite normal form (row-oriented)
#https://cseweb.ucsd.edu/classes/wi16/cse206A-a/lec4.pdf
def hnf(self):
g.show("HNF: "+str(self.width)+"x"+str(self.height))
#Find *column*-oriented Gram-Schmidt orthogonalization of the *columns* of this matrix
gso = self.transpose().orthogonalize().transpose()
#Projection map to GSO coords
nonzeroGSOColIndices = [k for k in range(gso.width) if not gso.col(k).isZero()][0:self.height]
projectionMatrix = Matrix([[int(k == nonzeroGSOColIndices[i]) for i in range(len(nonzeroGSOColIndices))] for k in range(gso.width)])
#Want self * projectionMatrix * projectionMatrixInverse = self
# (self * projectionMatrix).leftInverse() * (self * projectionMatrix) * projectionMatrixInverse = (self * projectionMatrix).leftInverse() * self
projectionMatrixInverse = (self * projectionMatrix).leftInverse() * self
output = (self * projectionMatrix).fullRankHNF() * projectionMatrixInverse
return output
def fullRankHNF(self):
denLCM = math.lcm(*(self[row,col].den for row in range(self.height) for col in range(self.width)))
selfIntForm = self * denLCM
return selfIntForm.fullRankIntHNF() / denLCM
#Row-oriented HNF for an integer matrix with full column rank
def fullRankIntHNF(self):
#Find maximal set of linearly independent rows
linearIndependentRowIndices = []
linearIndependentRowsMinor = Matrix([])
spanChecker = Matrix([])
for testRowIndex in range(self.height):
testRow = self.row(testRowIndex)
if len(linearIndependentRowIndices) == 0 and not testRow.isZero():
linearIndependentRowIndices.append(testRowIndex)
linearIndependentRowsMinor = testRow
spanChecker = linearIndependentRowsMinor.rightInverse() * linearIndependentRowsMinor
#Check if testRow not in span(linearIndependentRowsMinor)
elif testRow != testRow * spanChecker:
linearIndependentRowIndices.append(testRowIndex)
linearIndependentRowsMinor = linearIndependentRowsMinor.blockVertical(testRow)
spanChecker = linearIndependentRowsMinor.rightInverse() * linearIndependentRowsMinor
d = linearIndependentRowsMinor.det()
#Repeatedly add rows to this starting h (since this is guaranteed to generate a sublattice for integer matrices)
H = Matrix.id(self.width) * d
for row in self.rows():
H = H.hnfAddRow(row)
#Add zero padding
return H.blockVertical(Matrix.zero(self.height-self.width, self.width))
def hnfAddRow(self, row):
if self.width == 0:
return self
selfEntry = self[0,0]
selfSubvector = self[0:1,1:self.width]
selfMinor = self[1:self.width,1:self.width]
rowEntry = row[0,0]
rowSubvector = row[0:1,1:self.width]
#Extended GCD algo
x,y = extendedGCD(selfEntry, rowEntry)
entryGCD = selfEntry * x + rowEntry * y
newSubvector = selfSubvector * x + rowSubvector * y
newRow = selfSubvector * (-rowEntry // entryGCD) + rowSubvector * (selfEntry // entryGCD)
#Reduce newRow so that its elements are bounded by the diagonal elements of selfMinor
for i in range(selfMinor.width):
entryToReduce = newRow[0,i]
valToReduceBy = selfMinor[i,i]
subtractOutMult = entryToReduce // valToReduceBy
newRow -= selfMinor.row(i) * subtractOutMult
selfMinorRowAdded = selfMinor.hnfAddRow(newRow)
#Reduce newSubvector so that its elements are bounded by diagonal elements of selfMinorRowAdded
for i in range(selfMinorRowAdded.width):
entryToReduce = newSubvector[0,i]
valToReduceBy = selfMinorRowAdded[i,i]
subtractOutMult = entryToReduce // valToReduceBy
newSubvector -= selfMinorRowAdded.row(i) * subtractOutMult
return Matrix([[entryGCD]]).blockHorizontal(newSubvector).blockVertical(Matrix.zero(selfMinorRowAdded.height,1).blockHorizontal(selfMinorRowAdded))
def resize(self, height, width):
return Matrix([[self[(row * width + col) // self.width, (row * width + col) % self.width] for col in range(width)] for row in range(height)])
#A lattice of rational points
class Lattice:
#Constructor
def __init__(self, basis: Matrix, rowReduceBasis: bool = True):
#Do integer row reduction for our basis by default
if rowReduceBasis:
self.basis = basis.hnf().removeZeroRows()
else:
self.basis = basis.copy()
self.dimension = self.basis.width
self.rank = self.basis.height
#Find pivot columns
#The index of the first nonzero column in each row
self.pivots = [[x != 0 for x in row].index(True) for row in self.basis.terms]
#Find inverse of the generator matrix
self.changeOfBasis = self.basis.rightInverse()
#Gets canonical coset representative for a matrix
def getCosetRepresentative(self, matrix: Matrix) -> Matrix:
output = matrix.copy()
for matrixRowIndex in range(matrix.height):
for rowIndex in range(len(self.pivots)):
colIndex = self.pivots[rowIndex]
generatorValue = self.basis[rowIndex,colIndex]
matrixValue = output[matrixRowIndex,colIndex]
output.terms[matrixRowIndex] = [output[matrixRowIndex,termIndex] - self.basis[rowIndex,termIndex] * (matrixValue // generatorValue) for termIndex in range(matrix.width)]
return output
#Quotient for a Matrix or CosetMatrix
def getQuotient(self, matrix):
if isinstance(matrix, Matrix):
return CosetMatrix(matrix, self)
elif isinstance(matrix, CosetMatrix):
return CosetMatrix(matrix.rep, self + matrix.lattice)
#Does this lattice group contain a given row vector
def __contains__(self, vector: Matrix) -> bool:
return self.getCosetRepresentative(vector).isZero()
#Sum of two lattices
def __add__(self, other):
return Lattice(self.basis.blockVertical(other.basis))
def addGenerators(self, basisVectors: Matrix):
return Lattice(self.basis.blockVertical(basisVectors))
#Gets coordinates of the row vectors in a matrix where all row vectors are in this lattice
def getCoordinates(self, matrix: Matrix) -> Matrix:
return matrix * self.changeOfBasis
#Whether or not this lattice contains a multiple of the row vector for each row of a given matrix
def containsMultiple(self, matrix: Matrix) -> bool:
return self.getCoordinates(matrix) * self.basis == matrix
#The intersection of self with the plane other lies in
def intersectWithPlane(self,other):
#add in extra coordinates that don't lie in this plane
otherExtraBasis = other.basis
n = 0
while otherExtraBasis.height < otherExtraBasis.width:
testVector = Matrix([[Rational(int(a==n)) for a in range(otherExtraBasis.width)]])
n += 1
if not Lattice(otherExtraBasis, False).containsMultiple(testVector):
otherExtraBasis = testVector.blockVertical(otherExtraBasis)
otherExtraBasisInverse = otherExtraBasis.inverse()
basisInOtherCoordsReduced = (self.basis * otherExtraBasisInverse).hnf()
#Isolate only the rows that don't rely on the first few terms
basisInPlaneInOtherCoords = Matrix([row for row in basisInOtherCoordsReduced.terms if all(row[i]==0 for i in range(other.basis.width - other.basis.height))])
#Convert from coordinates
basisInPlane = basisInPlaneInOtherCoords * otherExtraBasis
return Lattice(basisInPlane)
#The dual of a lattice
def dual(self):
return Lattice(self.changeOfBasis.transpose(), False)
#The intersection of two lattices
def __and__(self, other):
return (self.dual() + other.dual()).dual().intersectWithPlane(self).intersectWithPlane(other)
#The lattice of integer divisors of a given lattice
def divisorLattice(self):
return LatticeGroup(Matrix.id(self.dimension)).intersectWithPlane(self)
#A basis for the torsion-free part of G/H
#Output as a matrix with rows v s.t. v+H form our basis
def quotientTorsionFreeBasis(self, sublattice):
divisorLattice = self.intersectWithPlane(sublattice)
divisorLatticeBasisExtended = divisorLattice.basis
nonPivots = [x for x in range(divisorLattice.dimension) if x not in divisorLattice.pivots]
for nonPivot in nonPivots:
divisorLatticeBasisExtended = self.basis.row(nonPivot).blockVertical(divisorLatticeBasisExtended)
divisorLatticeBasisExtendedInverse = divisorLatticeBasisExtended.inverse()
basisVectorsInDivisorLatticeExtendedCoordsReduced = (self.basis * divisorLatticeBasisExtendedInverse).hnf()
nonPivotBasisVectorsToCoords = basisVectorsInDivisorLatticeExtendedCoordsReduced[0:(divisorLattice.dimension-divisorLattice.rank),0:divisorLattice.dimension]
return CosetMatrix((nonPivotBasisVectorsToCoords * divisorLatticeBasisExtended).hnf(), sublattice)
#The torsion elements of G/H
def quotientTorsionElements(self, sublattice):
#We know these are all in divisorLattice
divisorLattice = self.intersectWithPlane(sublattice)
intermediateLattice = sublattice
#Find torsion of all basis elements
generators = Matrix([])
torsions = []
for basisElt in divisorLattice.basis.rows():
#Find the torsion of this basis element in the intermediate lattice
basisEltCoords = basisElt * intermediateLattice.changeOfBasis
#Torsion is the gcd of the elements of basisEltCoords
torsion = Rational.gcd(*basisEltCoords.terms[0]).den
torsions.append(torsion)
generators = generators.blockVertical(basisElt)
intermediateLattice = intermediateLattice.addGenerators(basisElt)
#Output as an iterator
def outputGenerator(basisElts, torsions):
multiplicities = [0 for torsion in torsions]
while True:
yield CosetMatrix(Matrix([multiplicities]) * basisElts, sublattice)
#Increment
index = 0
multiplicities[0]+=1
while index < len(multiplicities) and multiplicities[index] == torsions[index]:
multiplicities[index] = 0
index += 1
if index < len(multiplicities):
multiplicities[index]+=1
if index == len(multiplicities):
break
return outputGenerator(basisElts, torsions)
#Generators for G/H, with torsions (0 if torsion-free)
def quotientGeneratorsWithTorsions(self, sublattice):
#We know these are all in divisorLattice
divisorLattice = self.intersectWithPlane(sublattice)
intermediateLattice = sublattice
#Find torsion of all basis elements
generators = Matrix([])
torsions = []
for basisElt in divisorLattice.basis.rows():
#Find the torsion of this basis element in the intermediate lattice
basisEltCoords = basisElt * intermediateLattice.changeOfBasis
#Torsion is the gcd of the elements of basisEltCoords
torsion = Rational.gcd(*basisEltCoords.terms[0]).den
#if torsion != 1:
torsions.append(torsion)
generators = generators.blockVertical(basisElt)
intermediateLattice = intermediateLattice.addGenerators(basisElt)
#Add in the torsion-free basis
#return list(zip([CosetMatrix(row, sublattice) for row in generators.rows()], torsions)) + [(row,0) for row in self.quotientTorsionFreeBasis(sublattice).rows()]
return list(zip(generators.rows(), torsions)) + [(row.rep,0) for row in self.quotientTorsionFreeBasis(sublattice).rows()]
#Divides an envelope into a dictionary of cosets by a lattice
def divideIntoCosets(self, envelope):
output = dict()
for v in envelope:
key = CosetMatrix(v, self)
if key in output:
output[key].append(v)
else:
output[key] = [v]
#g.warn("".join(str(k.rep)+": "+str([str(x) for x in v])+"\n\n" for k,v in output.items()))
return output
#A matrix of lattice cosets of the form v+H
class CosetMatrix:
#Constructor
def __init__(self, rep: Matrix, lattice: Lattice):
self.lattice = lattice
self.rep = lattice.getCosetRepresentative(rep)
self.width = self.rep.width
self.height = self.rep.height
#Hashing
def __hash__(self) -> int:
return hash((self.rep))
def __eq__(self, other) -> bool:
return self.rep == other.rep
def __ne__(self, other) -> bool:
return self.rep != other.rep
#Arithmetic
def __add__(self, other) -> bool:
if isinstance(other, CosetMatrix):
return CosetMatrix(self.rep+other.rep, self.lattice)
elif isinstance(other, Matrix):
return CosetMatrix(self.rep+other, self.lattice)
def __sub__(self, other) -> bool:
if isinstance(other, CosetMatrix):
return CosetMatrix(self.rep-other.rep, self.lattice)
elif isinstance(other, Matrix):
return CosetMatrix(self.rep-other, self.lattice)
def __neg__(self) -> bool:
return CosetMatrix(-self.rep, self.lattice)
#Matrix multiplication
#Note: We also multiply the lattice basis
def __mul__(self, other):
return CosetMatrix(self.rep * other, Lattice(self.lattice.basis * other))
def rows(self):
return [CosetMatrix(row, self.lattice) for row in self.rep.rows()]
#A function from Z^n -> int
class LatticeFunction:
def __init__(self, data, dimension):
self.data = data
self.dimension = dimension
self.minCoords = [min(int(key[0,i]) for key,value in self.data.items()) for i in range(self.dimension)]
self.maxCoords = [max(int(key[0,i]) for key,value in self.data.items()) for i in range(self.dimension)]
self.coordDiffs = [x-y for x,y in zip(self.maxCoords, self.minCoords)]
#Convolve using Fourier transform
def convolve(self, other):
#Find amounts to wrap around
#These must be wrapArounds[i] a power of 2 satisfying wrapArounds[i] > self.coordDiffs[i] + other.coordDiffs[i]
#wrapArounds = [1<<(x+y).bit_length() for x,y in zip(self.coordDiffs, other.coordDiffs)]
wrapArounds = [x+y+1 for x,y in zip(self.coordDiffs, other.coordDiffs)]
#return LatticeFunction.unwrapData(LatticeFunction.fft([x*y for x,y in zip(LatticeFunction.fft(self.wrapData(wrapArounds), 1, 1), LatticeFunction.fft(other.wrapData(wrapArounds), 1, 1))], -1, 0.5), wrapArounds, Matrix([self.minCoords])+Matrix([other.minCoords]))
selfData = self.wrapData(wrapArounds)
otherData = other.wrapData(wrapArounds)
g.show("Convolving with length " + str(math.prod(wrapArounds)) + " " + str(tuple(wrapArounds)) + "...")
return LatticeFunction.unwrapData(signal.fftconvolve(selfData, otherData), wrapArounds, Matrix([self.minCoords])+Matrix([other.minCoords]))
#Wraps data to a list, where wrapArounds[i] are our sufficiently large powers of 2
def wrapData(self, wrapArounds):
g.show("Wrapping...")
wrapAroundsCumulative = [math.prod(wrapArounds[0:i]) for i in range(len(wrapArounds)+1)]
output = [0 for x in range(math.prod(wrapArounds))]
#Edit output.data
for key, value in self.data.items():
#Offset by self.minCoords so that indices are all positive
keyIndex = sum(mod(int(key[0,i] - self.minCoords[i]), wrapArounds[i])*wrapAroundsCumulative[i] for i in range(self.dimension))
output[keyIndex] = value
return output
#1-dimensional fast Fourier transform of an array of length 2^n
#Using the Cooley-Tukey algorithm
#I don't actually use this because signal.fftconvolve is faster but it was fun to implement
numFFTs = 0
def fft(data, sign: int = 1, scalePerStep = 1):
outputData = data.copy()
dataSize = len(outputData).bit_length() - 1
#Precompute twiddle factors
g.show("FFT " + str(LatticeFunction.numFFTs+1) + "/12: Computing twiddle factors...")
twiddleFactors = [cmath.exp(-sign * 2j * math.pi * k / (1 << dataSize)) for k in range(1 << dataSize)]
for step in range(0,dataSize):
g.show("FFT " + str(LatticeFunction.numFFTs+1) + "/12: " + str(step) + "/" + str(dataSize))
nextData = []
splitPos = dataSize - step - 1
splitPosMaskBit = 1 << splitPos
belowSplitPosMask = splitPosMaskBit - 1
aboveSplitPosMask = ((1 << (dataSize-1)) - 1) & ~belowSplitPosMask
for i in range(len(outputData)):
#Input indices
#How this works: Take i, split into before and after parts at data-step-1, bitshift after part up 1, insert a 0 or 1 bit
lowerInputIndex = (i & belowSplitPosMask) | ((i & aboveSplitPosMask) << 1)
upperInputIndex = lowerInputIndex | splitPosMaskBit
#Parity
paritySign = 1 - ((i >> (dataSize - 1)) << 1)
#Twiddle factor index
k = i & aboveSplitPosMask
#print(str(step) + ", " + str(i) + ": " + str(lowerInputIndex) + ", " + str(upperInputIndex) + str(" ") + str(k) + ", " + str(twiddleFactor))
nextData.append((outputData[lowerInputIndex] + paritySign * twiddleFactors[k] * outputData[upperInputIndex]) * scalePerStep)
#Progress bar for my sanity
outputData = nextData
g.show("FFT " + str(LatticeFunction.numFFTs) + "/6: " + str(dataSize) + "/" + str(dataSize))
LatticeFunction.numFFTs += 1
return outputData
#Unwrap a list to a LatticeFunction (rounding to ints)
def unwrapData(data, wrapArounds, offset):
g.show("Unwrapping...")
wrapAroundsCumulative = [math.prod(wrapArounds[0:i]) for i in range(len(wrapArounds)+1)]
outputData = {}
for keyIndex in range(len(data)):
if not cmath.isclose(data[keyIndex], 0, rel_tol=1e-09, abs_tol=1e-09):
#Nonzero entry
key = Matrix([[mod(keyIndex // wrapAroundsCumulative[i], wrapArounds[i]) for i in range(len(wrapArounds))]]) + offset
outputData[key] = round(data[keyIndex].real)
return LatticeFunction(outputData, len(wrapArounds))
#Wraps data to a function on a quotient group
def wrapToQuotientFunction(self, group, sign: int = 1):
outputData = {}
for key,value in self.data.items():
quotientKey = CosetMatrix(key * group.optimalLatticeBasis * sign, group.sublattice)
if quotientKey in outputData:
outputData[quotientKey] += value
else:
outputData[quotientKey] = value
return QuotientGroupFunction(group, outputData)
#A quotient of lattices
class QuotientGroup:
def __init__(self, lattice: Lattice, sublattice: Lattice):
#On initialization, organize
self.lattice = lattice
self.sublattice = sublattice
self.generatorsWithTorsions = lattice.quotientGeneratorsWithTorsions(sublattice)
#Find optimal basis for compact unwrapping
# I'm pretty sure this is actually pretty optimal for our purposes
self.optimalLatticeBasis = self.lattice.basis
self.optimalChangeOfBasis = self.optimalLatticeBasis.rightInverse()
#Other thing I considered, seems worse though
#self.optimalLatticeBasis = Matrix([generator.terms[0] for generator, torsion in self.generatorsWithTorsions])
#g.warn(str(self.lattice.basis) + "\n\n" + str(self.sublattice.basis) + "\n\n" + str(self.optimalLatticeBasis))
#A function from G/H -> int
class QuotientGroupFunction:
def __init__(self, group: QuotientGroup, data):
self.group = group
#A dictionary from cosets v+group.sublattice to ints
self.data = data
#Unwraps to a LatticeFunction
def unwrap(self):
return LatticeFunction({key.rep * self.group.optimalChangeOfBasis: self.data[key] for key in self.data}, self.group.optimalChangeOfBasis.width)
#Wraps to a further quotient
def wrapToQuotientFunction(self, group, sign: int = 1):
outputData = {}
for key,value in self.data.items():
quotientKey = CosetMatrix(key.rep * group.optimalLatticeBasis * sign, group.sublattice)
if quotientKey in outputData:
outputData[quotientKey] += value
else:
outputData[quotientKey] = value
return QuotientGroupFunction(group, outputData)
#Function convolution
def convolve(self, other):
return self.unwrap().convolve(other.unwrap()).wrapToQuotientFunction(self.group)
#Golly misc help stuff
#Helpful conversions
def toCellSet(cellList):
return {(cellList[i],cellList[i+1]) for i in range(0,len(cellList),2)}
def toCellList(cellSet):
return [num for x,y in cellSet for num in [x,y]]
#nonempty getrect
def getrect():
if g.empty():
return [0,0,1,1]
return g.getrect()
#This is just convenient
def gethash():
return g.hash(getrect())
def getcells():
return g.getcells(getrect())
#Does the pattern contain a given cell list
def patternContains(cellList, x=0, y=0):
return toCellSet(g.transform(cellList,x,y)).issubset(toCellSet(getcells()))
#Tools for pattern decomposition into components
#For a decomposition of Child(p) = DisjointUnion(q_i)
# Returns a decomposition of this pattern as p = DisjointUnion(p_j) such that Child(p_j) = DisjointUnion(q_{i_{j,k}})
# All inputs and outputs are given as cell sets
nbhd = {(x,y) for x in range(-1,2) for y in range(-1,2)}
def findSubpatterns(patternState, childDecomposition):
#Start by decomposing into connected components
#output = findConnectedComponents(patternState, {(x,y) for x in range(-1,2) for y in range(-1,2)})
output = set()
for cell in patternState:
nbhdOfCell = {(cell[0]+x,cell[1]+y) for x,y in nbhd}
#Check against all children in childDecomposition
requiredCells = {cell}
for childCellSet in childDecomposition:
if not nbhdOfCell.isdisjoint(childCellSet):
#This child's component must contain patternState intersect nbhd(childCellSet)
requiredCells |= patternState & set().union(*[{(a[0]+b[0],a[1]+b[1]) for a in nbhd} for b in childCellSet])
#We require all these cells in our component
componentsToUnionWith = {component for component in output if not requiredCells.isdisjoint(component)}
output -= componentsToUnionWith
output.add(frozenset({cell}.union(*componentsToUnionWith)))
#Additionally, unionize any components around cells that don't match
evolvedState = set().union(*childDecomposition)
evolvedComponentStatesUnion = set().union(*[toCellSet(g.evolve(toCellList(component),1)) for component in output])
error = evolvedState ^ evolvedComponentStatesUnion
for errorCell in error:
nbhdOfCell = {(errorCell[0]+x,errorCell[1]+y) for x,y in nbhd}
#Unionize all components intersecting nbhdOfCell
componentsToUnionWith = {component for component in output if not nbhdOfCell.isdisjoint(component)}
output -= componentsToUnionWith
output.add(frozenset().union(*componentsToUnionWith))
return output
#Removes unneccessary cells from the evolution of this pattern (requiring patFinalState in the final result)
def removeAshCells(patEvolution, patFinalState):
#Find the indepdenent subpatterns of this at each stage
patFinalStateCellSet = frozenset(toCellSet(patFinalState))
patFinalStateCellSetWithExtra = frozenset(toCellSet(g.evolve(patEvolution[len(patEvolution)-1], 1)))
patFinalDecomposition = {patFinalStateCellSet} | {frozenset({cell}) for cell in patFinalStateCellSetWithExtra - patFinalStateCellSet}
patDecompositions = [patFinalDecomposition]
for i in reversed(range(len(patEvolution))):
#Find the prior decomposition
prevDecomposition = findSubpatterns(toCellSet(patEvolution[i]), patDecompositions[0])
patDecompositions.insert(0, prevDecomposition)
#Construct list of only the minimal decompositions leading to patFinalState
minComponents = [patFinalStateCellSet]
for i in reversed(range(len(patEvolution))):
#Need component intersects nbhd(minComponents[0])
try:
prevMinComponent = next(component for component in patDecompositions[i] if not component.isdisjoint(set().union(*[{(a[0]+b[0],a[1]+b[1]) for a in nbhd} for b in minComponents[0]])))
minComponents.insert(0, prevMinComponent)
except StopIteration:
#This only happens when our cell has no predecessors
#This isn't common, but can occur when we add in components mid-evolution
continue
#Convert back to cell lists, remove the last component
return [toCellList(component) for component in minComponents[0:len(minComponents)-1]]
cellLattice = Lattice(Matrix.id(3))
#A periodic pattern with inputs and outputs
class PeriodicPattern:
def __init__(self, cellList, dT, dX, dY, inputs = [], outputs = [], computeExtras = False):
self.dX = dX
self.dY = dY
self.dT = dT
#Do a bit of processing so I can be lazy when giving inputs
self.inputs = [(inputPattern, inputName, mod(inputTimeToAdd, self.dT), inputPattern.periodLattice.getQuotient(inputPosition)) for inputPattern, inputName, inputTimeToAdd, inputPosition in inputs]
self.outputs = [(outputPattern, outputName, mod(outputTimeToAdd, self.dT), outputPattern.periodLattice.getQuotient(outputPosition)) for outputPattern, outputName, outputTimeToAdd, outputPosition in outputs]
self.inputNamesToIndexes = {inputs[i][1]:i for i in range(len(inputs))}
self.outputNamesToIndexes = {outputs[i][1]:i for i in range(len(outputs))}
self.periodVector = Matrix([[self.dT, -self.dX, -self.dY]])
self.periodLattice = Lattice(self.periodVector)
self.positionGroup = QuotientGroup(cellLattice, self.periodLattice)
#Find states
currentState = cellList.copy()
self.state = []
g.setrule("B3/S23")
for t in range(self.dT):
#Remove all outputs on this generation from currentState
#TODO: Could be nice to add a way for outputs to be removed 'late'/after a full cycle
# Or generally for the pattern to 'fill in' over multiple cycles, so that sparks are covered too
for outputPattern, outputName, outputTimeToRemove, outputPosition in self.outputs:
if outputTimeToRemove == t:
currentState = outputPattern.joinInto(currentState, outputPosition, "andnot")
self.state.append(currentState)
#Join all inputs on this generation to currentState
for inputPattern, inputName, inputTimeToAdd, inputPosition in self.inputs:
if inputTimeToAdd == t:
currentState = inputPattern.joinInto(currentState, inputPosition, "or")
currentState = g.evolve(currentState, 1)
if computeExtras:
#Precompute some envelopes for collision purposes
g.setrule("B12345678/S012345678")
self.envelopeA = LatticeFunction(dict.fromkeys({Matrix([[t,-x,-y]]) for t in range(self.dT) for x,y in toCellSet(g.evolve(self.state[t],1))}, 1), 3)
g.setrule("B3/S012345678")
self.envelopeB = LatticeFunction(dict.fromkeys({Matrix([[t,-x,-y]]) for t in range(self.dT) for x,y in toCellSet(g.evolve(self.state[t],1))}, 1), 3)
g.setrule("B1/S")
self.envelopeC = LatticeFunction(dict.fromkeys({Matrix([[t,-x,-y]]) for t in range(self.dT) for x,y in toCellSet(g.evolve(self.state[t],1))}, 1), 3)
g.setrule("B2/S")
self.envelopeD = LatticeFunction(dict.fromkeys({Matrix([[t,-x,-y]]) for t in range(self.dT) for x,y in toCellSet(g.evolve(self.state[t],1))}, 1), 3)
g.setrule("B3/S23")
#Find states required for pattern to be restored
#TODO: Also find states required for outputs
# Approach we take: Remove any unnecessary cells (parts that permanently have no influence on the rest of the crawler)
#Fill in crawlerStates
#We iterate twice to prevent pruning ash near the end of the cycle that would collide with the crawler later
#TODO: Most of this is just copy-pasted, I could definitely do this better
extendedState = self.state.copy()
for t in range(self.dT):
#Remove all outputs on this generation from currentState
for outputPattern, outputName, outputTimeToRemove, outputPosition in self.outputs:
if outputTimeToRemove == t:
currentState = outputPattern.joinInto(currentState, outputPosition + Matrix([[0,self.dX,self.dY]]), "andnot")
extendedState.append(currentState)
#Join all inputs on this generation to currentState
for inputPattern, inputName, inputTimeToAdd, inputPosition in self.inputs:
if inputTimeToAdd == t:
currentState = inputPattern.joinInto(currentState, inputPosition + Matrix([[0,self.dX,self.dY]]), "or")
currentState = g.evolve(currentState, 1)
#TODO: This is *probably* too strict, since some of the pi-crawler pairs I expected don't show up
self.requiredState = removeAshCells(extendedState, g.transform(self.state[0], self.dX*2, self.dY*2))[0:self.dT]
def getStatePosition(self, position, onlyRequired = False):
positionToUse = self.periodLattice.getQuotient(position)
if onlyRequired:
return g.transform(self.requiredState[int(positionToUse.rep[0,0])], int(positionToUse.rep[0,1]), int(positionToUse.rep[0,2]))
else:
return g.transform(self.state[int(positionToUse.rep[0,0])], int(positionToUse.rep[0,1]), int(positionToUse.rep[0,2]))
def joinInto(self, cellList, position, mode):
if mode == "or":
return g.join(cellList, self.getStatePosition(position))
elif mode == "andnot":
return toCellList(toCellSet(cellList) - toCellSet(self.getStatePosition(position)))
def place(self, position, mode = "or", onlyRequired = False):
g.putcells(self.getStatePosition(position, onlyRequired),0,0,1,0,0,1, mode)
def placeInput(self, position, index, mode = "or"):
positionToUse = self.periodLattice.getQuotient(position)
stateT = int(positionToUse.rep[0,0])
for inputPattern, inputName, inputTimeToAdd, inputPosition in self.inputs:
indexToUse = index + (1,0)[inputTimeToAdd >= stateT]
inputPattern.place(inputPosition + (positionToUse.rep + Matrix([[-inputTimeToAdd, 0, 0]]) - Matrix([[self.dT, -self.dX, -self.dY]]) * indexToUse), mode)
def placeOutput(self, position, index, mode = "or"):
positionToUse = self.periodLattice.getQuotient(position)
stateT = int(positionToUse.rep[0,0])
for outputPattern, outputName, outputTimeToRemove, outputPosition in self.outputs:
indexToUse = index + (1,0)[outputTimeToRemove <= stateT]
outputPattern.place(outputPosition + (positionToUse.rep + Matrix([[-outputTimeToRemove, 0, 0]]) + Matrix([[self.dT, -self.dX, -self.dY]]) * indexToUse), mode)
#Place with inputs (and outputs)
def placeWithInputs(self, position, numInputs = 0, numOutputs = 0, mode = "or", onlyRequired = False):
self.place(position, mode, onlyRequired)
for i in range(0,numInputs):
self.placeInput(position, i, mode)
for i in range(0,numOutputs):
self.placeOutput(position, i, mode)
#Test this pattern with inputs (and outputs)
# We only want to test against the minimum envelope required to sustain the component
#TODO: Allow more customizability in input/output testing
def test(self, position, onlyRequired = True):
return patternContains(self.getStatePosition(position, onlyRequired))
def testInput(self, position, index):
stateT = int(position.rep[0,0])
for inputPattern, inputName, inputTimeToAdd, inputPosition in self.inputs:
indexToUse = index + (1,0)[inputTimeToAdd >= stateT]
if not inputPattern.test(inputPosition + (position.rep + Matrix([[-inputTimeToAdd, 0, 0]]) - Matrix([[self.dT, -self.dX, -self.dY]]) * indexToUse)):
return False
return True
def testOutput(self, position, index):
stateT = int(position.rep[0,0])
for outputPattern, outputName, outputTimeToRemove, outputPosition in self.outputs:
indexToUse = index + (1,0)[outputTimeToRemove <= stateT]
if not outputPattern.test(outputPosition + (position.rep + Matrix([[-outputTimeToRemove, 0, 0]]) + Matrix([[self.dT, -self.dX, -self.dY]]) * indexToUse)):
return False
return True
def testWithInputs(self, position, numInputs = 0, numOutputs = 0):
return self.test(position) and all(self.testInput(position,i) for i in range(0, numInputs)) and all(self.testOutput(position,i) for i in range(0, numOutputs))
#Enumerate all possible collisions/interaction separations between two objects
#NOTE: This is optimized for the case where self is small
#TODO: Would probably like to make a version optimized for where self is not small
# I'm not entirely sure how best to do that
def enumerateCollisionSeparations(self, other):
separationLattice = self.periodLattice + other.periodLattice
separationGroup = QuotientGroup(cellLattice, separationLattice)
#Wrapping our envelopes first is probably more efficient
prewrapSelfA = self.envelopeA.wrapToQuotientFunction(separationGroup, -1)
prewrapSelfB = self.envelopeB.wrapToQuotientFunction(separationGroup, -1)
prewrapSelfC = self.envelopeC.wrapToQuotientFunction(separationGroup, -1)
prewrapSelfD = self.envelopeD.wrapToQuotientFunction(separationGroup, -1)
prewrapOtherA = other.envelopeA.wrapToQuotientFunction(separationGroup, 1)
prewrapOtherB = other.envelopeB.wrapToQuotientFunction(separationGroup, 1)
prewrapOtherC = other.envelopeC.wrapToQuotientFunction(separationGroup, 1)
prewrapOtherD = other.envelopeD.wrapToQuotientFunction(separationGroup, 1)
collisionSeparationCosets = set(prewrapSelfA.convolve(prewrapOtherB).data) | set(prewrapSelfB.convolve(prewrapOtherA).data) | set(prewrapSelfC.convolve(prewrapOtherD).data) | set(prewrapSelfD.convolve(prewrapOtherC).data)
#Want to find the first possible absolute separations
#This means, for each separationCoset in collisionSeparationCosets, we want to find the first time resulting in an interaction
#Divide our envelopes into cosets
selfCosetsA = separationLattice.divideIntoCosets(self.envelopeA.data)
selfCosetsB = separationLattice.divideIntoCosets(self.envelopeB.data)
selfCosetsC = separationLattice.divideIntoCosets(self.envelopeC.data)
selfCosetsD = separationLattice.divideIntoCosets(self.envelopeD.data)
otherCosetsA = separationLattice.divideIntoCosets(other.envelopeA.data)
otherCosetsB = separationLattice.divideIntoCosets(other.envelopeB.data)
otherCosetsC = separationLattice.divideIntoCosets(other.envelopeC.data)
otherCosetsD = separationLattice.divideIntoCosets(other.envelopeD.data)
#Find earliest interatction cells for each coset
#Idea:
# Want to understand the space of vectors v such that CosetMatrix(v, self.periodLattice) in selfEnvelope, and CosetMatrix(v + separation, other.periodLattice) in otherEnvelope
# That is, exist m,n such that v + m*self.periodVector in selfEnvelope.reps, v + separation + n*other.periodVector in otherEnvelope.reps
# Have x in selfEnvelope.reps, y in otherEnvelope.reps such that v + m*self.periodVector = x, v + separation + n*other.periodVector = y
# Then x+separation-y = m*self.periodVector - n*other.periodVector
# So [m,-n] = (x+separation-y) * changeOfCoords
# In particular, m = (x+separation-y) * changeOfCoords.col(0)
# Then v = x - self.periodVector * ((x+separation-y) * changeOfCoords.col(0))[0,0]
# Specifically, v[0,0] = x[0,0] - self.periodVector[0,0] * ((x+separation-y) * changeOfCoords.col(0))[0,0]
# = x[0,0] - self.periodVector[0,0] * (x * changeOfCoords.col(0))[0,0] + self.periodVector[0,0] * ((y-separation) * changeOfCoords.col(0))[0,0]
# = x * ([[1],[0],[0]] - changeOfCoords.col(0) * self.periodVector[0,0]) + (y-separation) * changeOfCoords.col(0) * self.periodVector[0,0]
cMulOther = self.periodVector.blockVertical(other.periodVector).rightInverse().col(0) * self.periodVector[0,0]
cMulSelf = Matrix([[1],[0],[0]]) - cMulOther
def findContribs(cosetReps, multiplier):
return {coset: min((rep * multiplier)[0,0] for rep in cosetReps[coset]) for coset in cosetReps}
selfContribsA = findContribs(selfCosetsA, cMulSelf)
selfContribsB = findContribs(selfCosetsB, cMulSelf)
selfContribsC = findContribs(selfCosetsC, cMulSelf)
selfContribsD = findContribs(selfCosetsD, cMulSelf)
otherContribsA = findContribs(otherCosetsA, cMulOther)
otherContribsB = findContribs(otherCosetsB, cMulOther)
otherContribsC = findContribs(otherCosetsC, cMulOther)
otherContribsD = findContribs(otherCosetsD, cMulOther)
#Remark: This is rather slow when self is large
#TODO: Would like a better approach to this
def minContrib(separation, selfContribs, otherContribs):
return min((selfContribs[coset] + otherContribs[coset + separation] for coset in selfContribs if coset + separation in otherContribs), default = math.inf)
for separationCoset in collisionSeparationCosets:
minT = min(minContrib(separationCoset.rep, selfContribsA, otherContribsB),
minContrib(separationCoset.rep, selfContribsB, otherContribsA),
minContrib(separationCoset.rep, selfContribsC, otherContribsD),
minContrib(separationCoset.rep, selfContribsD, otherContribsC)) - (separationCoset.rep * cMulOther)[0,0]
yield [CosetMatrix(Matrix([[minT,0,0]]), self.periodLattice), CosetMatrix(Matrix([[minT,0,0]]) + separationCoset.rep, other.periodLattice)]
#Enumerate interactions between two objects with the same velocity
#NOTE: This is less size-dependent
def enumerateInteractionSeparations(self, other):
separationLattice = self.periodLattice + other.periodLattice
separationGroup = QuotientGroup(cellLattice, separationLattice)
#Wrapping our envelopes first is probably more efficient
prewrapSelfA = self.envelopeA.wrapToQuotientFunction(separationGroup, -1)
prewrapSelfB = self.envelopeB.wrapToQuotientFunction(separationGroup, -1)
prewrapSelfC = self.envelopeC.wrapToQuotientFunction(separationGroup, -1)
prewrapSelfD = self.envelopeD.wrapToQuotientFunction(separationGroup, -1)
prewrapOtherA = other.envelopeA.wrapToQuotientFunction(separationGroup, 1)
prewrapOtherB = other.envelopeB.wrapToQuotientFunction(separationGroup, 1)
prewrapOtherC = other.envelopeC.wrapToQuotientFunction(separationGroup, 1)
prewrapOtherD = other.envelopeD.wrapToQuotientFunction(separationGroup, 1)
collisionSeparationCosets = set(prewrapSelfA.convolve(prewrapOtherB).data) | set(prewrapSelfB.convolve(prewrapOtherA).data) | set(prewrapSelfC.convolve(prewrapOtherD).data) | set(prewrapSelfD.convolve(prewrapOtherC).data)
return [[CosetMatrix(Matrix([[0,0,0]]), self.periodLattice), CosetMatrix(coset.rep, other.periodLattice)] for coset in collisionSeparationCosets]
#TODO: Could make a faster method for self-interactions, since half of the convolutions aren't really required
#Multiple patterns with the same period, with compatible inputs and outputs linked
class CompoundPattern:
def __init__(self, componentsWithPositions, name = ""):
#Members are of the form (component, position)
self.componentsWithPositions = [(component, componentName, component.periodLattice.getQuotient(componentPosition)) for component, componentName, componentPosition in componentsWithPositions]
self.periodVector = componentsWithPositions[0][0].periodVector
self.periodLattice = componentsWithPositions[0][0].periodLattice
self.dT = int(self.periodVector[0,0])
self.dX = -int(self.periodVector[0,1])
self.dY = -int(self.periodVector[0,2])
#Figure out all inputs and outputs
self.inputDict = {}
for inputComponent, inputComponentName, inputComponentPosition in self.componentsWithPositions:
for inputPattern, inputName, inputTime, inputPosition in inputComponent.inputs:
if not inputPattern in self.inputDict:
self.inputDict[inputPattern] = {}
combinedLattice = inputPattern.periodLattice + self.periodLattice
#What lane is our input on
inputPositionInCompound = inputPosition + inputComponentPosition.rep - Matrix([[inputTime,0,0]])
inputLane = CosetMatrix(inputPositionInCompound.rep, combinedLattice)
if not inputLane in self.inputDict[inputPattern]:
self.inputDict[inputPattern][inputLane] = []
#Our input time and position in the larger compound pattern
inputTimeInCompoundPattern = mod(inputTime - int(inputComponentPosition.rep[0,0]), self.dT)
inputSpacing = ((inputTime - int(inputComponentPosition.rep[0,0])) - inputTimeInCompoundPattern) // self.dT
inputPositionInCompoundPattern = inputPosition.rep + inputComponentPosition.rep + Matrix([[inputTimeInCompoundPattern - inputTime,0,0]]) + self.periodVector * inputSpacing
self.inputDict[inputPattern][inputLane].append((inputTimeInCompoundPattern, inputPositionInCompoundPattern, inputComponentName+"."+inputName))
self.outputDict = {}
for outputComponent, outputComponentName, outputComponentPosition in self.componentsWithPositions:
for outputPattern, outputName, outputTime, outputPosition in outputComponent.outputs:
if not outputPattern in self.outputDict:
self.outputDict[outputPattern] = {}
combinedLattice = outputPattern.periodLattice + self.periodLattice
#What lane is our output on
outputPositionInCompound = outputPosition + outputComponentPosition.rep - Matrix([[outputTime,0,0]])
outputLane = CosetMatrix(outputPositionInCompound.rep, combinedLattice)
if not outputLane in self.outputDict[outputPattern]:
self.outputDict[outputPattern][outputLane] = []
#Our output time and position in the larger compound pattern
outputTimeInCompoundPattern = mod(outputTime - int(outputComponentPosition.rep[0,0]), self.dT)
outputSpacing = ((outputTime - int(outputComponentPosition.rep[0,0])) - outputTimeInCompoundPattern) // self.dT
outputPositionInCompoundPattern = outputPosition.rep + outputComponentPosition.rep + Matrix([[outputTimeInCompoundPattern - outputTime,0,0]]) + self.periodVector * outputSpacing
self.outputDict[outputPattern][outputLane].append((outputTimeInCompoundPattern, outputPositionInCompoundPattern, outputComponentName+"."+outputName))
#Whole pattern's inputs and outputs
#In same format as PeriodicPattern, to allow for nesting
self.inputs = []
self.outputs = []
self.linkages = []
#Input/output index registration with names
self.name = name
self.inputNamesToIndexes = {}
self.outputNamesToIndexes = {}
def registerInput(inputTimeInCompoundPattern, pattern, inputPositionInCompoundPattern, inputName):
self.inputNamesToIndexes[inputName] = len(self.inputs)
self.inputs.append((pattern, inputName, inputTimeInCompoundPattern, CosetMatrix(inputPositionInCompoundPattern, pattern.periodLattice)))
def registerOutput(outputTimeInCompoundPattern, pattern, outputPositionInCompoundPattern, outputName):
self.outputNamesToIndexes[outputName] = len(self.outputs)
self.outputs.append((pattern, outputName, outputTimeInCompoundPattern, CosetMatrix(outputPositionInCompoundPattern, pattern.periodLattice)))
#Figure out compatible input-output pairs and combine 'em
for pattern in self.inputDict:
if pattern in self.outputDict:
combinedLatticeChangeOfBasis = self.periodVector.blockVertical(pattern.periodVector).rightInverse()
for lane in self.inputDict[pattern]:
if lane in self.outputDict[pattern]:
#Positivity/spacing checks on pairs in the same lane
inputsMinPositiveDisplacements = [(math.inf, -1) for i in range(len(self.inputDict[pattern][lane]))]
outputsMinPositiveDisplacements = [(math.inf, -1) for j in range(len(self.outputDict[pattern][lane]))]
for i in range(len(self.inputDict[pattern][lane])):
inputTimeInCompoundPattern, inputPositionInCompoundPattern, inputName = self.inputDict[pattern][lane][i]
for j in range(len(self.outputDict[pattern][lane])):
outputTimeInCompoundPattern, outputPositionInCompoundPattern, outputName = self.outputDict[pattern][lane][j]
inputPos = inputPositionInCompoundPattern + Matrix([[inputTimeInCompoundPattern,0,0]])
outputPos = outputPositionInCompoundPattern + Matrix([[outputTimeInCompoundPattern,0,0]])
#This is incredibly scuffed and probably incorrect
#TODO: Yeah this is definitely incorrect
displacement = int((inputPos - outputPos)[0,0]) + int(((inputPos - outputPos) * combinedLatticeChangeOfBasis)[0,0]) * self.dT
if displacement >= 0 or True:
#Link up if these are an improvement
if displacement < inputsMinPositiveDisplacements[i][0]:
inputsMinPositiveDisplacements[i] = (displacement, j)
if displacement < outputsMinPositiveDisplacements[j][0]:
outputsMinPositiveDisplacements[j] = (displacement, i)
unboundInputs = set(range(len(self.inputDict[pattern][lane])))
unboundOutputs = set(range(len(self.outputDict[pattern][lane])))
#Register linkages for closest compatible pairs
for i in range(len(self.inputDict[pattern][lane])):
j = inputsMinPositiveDisplacements[i][1]
if j != -1 and outputsMinPositiveDisplacements[j][1] == i:
#i,j is a closest compatible pair
unboundInputs.remove(i)
unboundOutputs.remove(j)
inputTimeInCompoundPattern, inputPositionInCompoundPattern, inputName = self.inputDict[pattern][lane][i]
outputTimeInCompoundPattern, outputPositionInCompoundPattern, outputName = self.outputDict[pattern][lane][j]
self.linkages.append((pattern, inputTimeInCompoundPattern, inputPositionInCompoundPattern, outputTimeInCompoundPattern, outputPositionInCompoundPattern))
#Register unbound inputs and outputs
for i in unboundInputs:
inputTimeInCompoundPattern, inputPositionInCompoundPattern, inputName = self.inputDict[pattern][lane][i]
registerInput(inputTimeInCompoundPattern, pattern, inputPositionInCompoundPattern, inputName)
for j in unboundOutputs:
outputTimeInCompoundPattern, outputPositionInCompoundPattern, outputName = self.outputDict[pattern][lane][j]
registerOutput(outputTimeInCompoundPattern, pattern, outputPositionInCompoundPattern, outputName)
else:
for inputTimeInCompoundPattern, inputPositionInCompoundPattern, inputName in self.inputDict[pattern][lane]:
registerInput(inputTimeInCompoundPattern, pattern, inputPositionInCompoundPattern, inputName)
for lane in self.outputDict[pattern]:
if not lane in self.inputDict[pattern]:
for outputTimeInCompoundPattern, outputPositionInCompoundPattern, outputName in self.outputDict[pattern][lane]:
registerOutput(outputTimeInCompoundPattern, pattern, outputPositionInCompoundPattern, outputName)
else:
for lane in self.inputDict[pattern]:
for inputTimeInCompoundPattern, inputPositionInCompoundPattern, inputName in self.inputDict[pattern][lane]:
registerInput(inputTimeInCompoundPattern, pattern, inputPositionInCompoundPattern, inputName)
for pattern in self.outputDict:
if not pattern in self.inputDict:
for lane in self.outputDict[pattern]:
for outputTimeInCompoundPattern, outputPositionInCompoundPattern, outputName in self.outputDict[pattern][lane]:
registerOutput(outputTimeInCompoundPattern, pattern, outputPositionInCompoundPattern, outputName)
def place(self, position, mode = "or"):
#Place in all components
positionToUse = self.periodLattice.getQuotient(position)
for component, componentName, componentPosition in self.componentsWithPositions:
component.place(positionToUse + componentPosition, mode)
#Place in all linkages
stateT = int(positionToUse.rep[0,0])
for pattern, inputTimeInCompoundPattern, inputPositionInCompoundPattern, outputTimeInCompoundPattern, outputPositionInCompoundPattern in self.linkages:
#TODO: These are wrong
inputIndexOffset = (1,0)[inputTimeInCompoundPattern >= stateT]
outputIndexOffset = (0,1)[outputTimeInCompoundPattern <= stateT]
#g.warn(str(inputTimeInCompoundPattern) +", "+str(outputTimeInCompoundPattern) +", "+str(stateT)+"\n\n"+str(inputIndexOffset) + ", "+str(outputIndexOffset))
inputBasePos = inputPositionInCompoundPattern + positionToUse.rep - Matrix([[inputTimeInCompoundPattern, 0, 0]])
outputBasePos = outputPositionInCompoundPattern + positionToUse.rep - Matrix([[outputTimeInCompoundPattern, 0, 0]])
combinedLatticeChangeOfBasis = self.periodVector.blockVertical(pattern.periodVector).rightInverse()
for index in range(inputIndexOffset, outputIndexOffset + int(((inputBasePos - outputBasePos) * combinedLatticeChangeOfBasis)[0,0])):
pattern.place(CosetMatrix(inputBasePos - Matrix([[self.dT, -self.dX, -self.dY]]) * index, pattern.periodLattice), mode)
def placeInput(self, position, index, mode = "or"):
positionToUse = self.periodLattice.getQuotient(position)
stateT = int(positionToUse.rep[0,0])
for inputPattern, inputName, inputTimeToAdd, inputPosition in self.inputs:
indexToUse = index + (1,0)[inputTimeToAdd >= stateT]
inputPattern.place(inputPosition + (positionToUse.rep + Matrix([[-inputTimeToAdd, 0, 0]]) - Matrix([[self.dT, -self.dX, -self.dY]]) * indexToUse), mode)
def placeOutput(self, position, index, mode = "or"):
positionToUse = self.periodLattice.getQuotient(position)
stateT = int(positionToUse.rep[0,0])
for outputPattern, outputName, outputTimeToRemove, outputPosition in self.outputs:
indexToUse = index + (1,0)[outputTimeToRemove <= stateT]
outputPattern.place(outputPosition + (positionToUse.rep + Matrix([[-outputTimeToRemove, 0, 0]]) + Matrix([[self.dT, -self.dX, -self.dY]]) * indexToUse), mode)
#Place with inputs (and outputs)
def placeWithInputs(self, position, numInputs = 0, numOutputs = 0, mode = "or"):
self.place(position, mode)
for i in range(0,numInputs):
self.placeInput(position, i, mode)
for i in range(0,numOutputs):
self.placeOutput(position, i, mode)
#Find the minimal offset displacement of pat2 linking an output in one PeriodicPattern (or CompoundPattern) to an input in another
# Plus extraSpacing steps worth of space
def findOffset(pat1, pat1OutputIndex, pat2, pat2InputIndex, extraSpacing = 0):
outputPattern, outputName, outputTimeToRemove, outputPosition = pat1.outputs[pat1OutputIndex]
inputPattern, inputName, inputTimeToAdd, inputPosition = pat2.inputs[pat2InputIndex]
if outputPattern != inputPattern:
raise ValueError("Pattern mismatch!")
retur
#Want to add and remove in the same generation
return CosetMatrix(Matrix([[inputTimeToAdd - outputTimeToRemove,0,0]]) + outputPosition.rep - inputPosition.rep - outputPattern.periodVector * extraSpacing, pat1.periodLattice)
#A chain with certain spacings
def chain(patternInputOutputSpacingInfo):
periodLattice = patternInputOutputSpacingInfo[0][0].periodLattice
cumulativeOffset = CosetMatrix(Matrix.zero(1,3), periodLattice)
componentsWithPositions = [(patternInputOutputSpacingInfo[0][0], patternInputOutputSpacingInfo[0][1], cumulativeOffset)]
for i in range(len(patternInputOutputSpacingInfo) - 1):
outputComponent, _, _, outputComponentOutputName, _ = patternInputOutputSpacingInfo[i]
inputComponent, inputComponentName, inputComponentInputName, _, extraSpacing = patternInputOutputSpacingInfo[i+1]
outputComponentOutputIndex = outputComponent.outputNamesToIndexes[outputComponentOutputName]
inputComponentInputIndex = inputComponent.inputNamesToIndexes[inputComponentInputName]
addedOffset = CompoundPattern.findOffset(outputComponent, outputComponentOutputIndex, inputComponent, inputComponentInputIndex, extraSpacing)
cumulativeOffset += addedOffset
componentsWithPositions.append((inputComponent, inputComponentName, cumulativeOffset))
return CompoundPattern(componentsWithPositions)
#A tree with certain spacings
def tree(patternConnectionInfo):
periodLattice = patternConnectionInfo[0][0].periodLattice
componentsWithPositions = [(patternConnectionInfo[0][0], patternConnectionInfo[0][1], CosetMatrix(Matrix.zero(1,3), periodLattice))]
nameToIndex = {patternConnectionInfo[0][1]: 0}
for i in range(1, len(patternConnectionInfo)):
component, componentName, linkViaInput, thisLinkName, componentToLinkToName, componentToLinkToLinkName, extraSpacing = patternConnectionInfo[i]
componentToLinkToIndex = nameToIndex[componentToLinkToName]
componentToLink = componentsWithPositions[componentToLinkToIndex][0]
componentPosition = componentsWithPositions[componentToLinkToIndex][2] #We add something to this value
if linkViaInput:
#We're linked via an input in this to an output in componentToLinkToName
componentToLinkOutputIndex = componentToLink.outputNamesToIndexes[componentToLinkToLinkName]
componentInputIndex = component.inputNamesToIndexes[thisLinkName]
componentPosition += CompoundPattern.findOffset(componentToLink, componentToLinkOutputIndex, component, componentInputIndex, extraSpacing)
else:
componentToLinkInputIndex = componentToLink.inputNamesToIndexes[componentToLinkToLinkName]
componentOutputIndex = component.outputNamesToIndexes[thisLinkName]
componentPosition -= CompoundPattern.findOffset(component, componentOutputIndex, componentToLink, componentToLinkInputIndex, extraSpacing)
nameToIndex[componentName] = i
componentsWithPositions.append((component, componentName, componentPosition))
return CompoundPattern(componentsWithPositions)
#Automatically add in a collection of components with compatible spacings with certain inputs/outputs to form a loop
def addCompatibleComponents(self, componentsToAddData, selfName = "Main"):
newCompoundPatternComponents = [(self, selfName, CosetMatrix(Matrix.zero(1,3), self.periodLattice))]
for component, componentName, componentInputIndicesToSelfOutputIndices, componentOutputIndicesToSelfInputIndices in componentsToAddData:
#Get constraints
baseOffsets = []
stepDisplacements = []
#We expect exactly 2 of these constraints in total
for componentInputName, selfOutputName in componentInputIndicesToSelfOutputIndices.items():
componentInputIndex = component.inputNamesToIndexes[componentInputName]
selfOutputIndex = self.outputNamesToIndexes[selfOutputName]
baseOffsets.append(CompoundPattern.findOffset(self, selfOutputIndex, component, componentInputIndex).rep)
stepDisplacements.append(component.inputs[componentInputIndex][0].periodVector)
for componentOutputName, selfInputName in componentOutputIndicesToSelfInputIndices.items():
componentOutputIndex = component.outputNamesToIndexes[componentOutputName]
selfInputIndex = self.inputNamesToIndexes[selfInputName]
baseOffsets.append(-CompoundPattern.findOffset(component, componentOutputIndex, self, selfInputIndex).rep)
stepDisplacements.append(component.outputs[componentOutputIndex][0].periodVector)
#Our position must be, for all i, of the form v = baseOffsets[i] + n_i * stepDisplacements[i] + m_i * self.periodVector
# In particular, have 0 = baseOffsets[0] - baseOffsets[1] + n_0 * stepDisplacements[0] - n_1 * stepDisplacements[1] + (m_0-m_1)*self.periodVector
# baseOffsets[1] - baseOffsets[0] = Matrix([[n_0,-n_1,m_0-m_1]]) * BlockVertical(stepDisplacements[0], stepDisplacements[1], self.periodVector)
# (baseOffsets[1] - baseOffsets[0]) * blockMatrixInverse = Matrix([[n_0,-n_1,m_0-m_1]])
# ((baseOffsets[1] - baseOffsets[0]) * blockMatrixInverse.col(0))[0,0] = n_0
n0 = ((baseOffsets[1] - baseOffsets[0]) * stepDisplacements[0].blockVertical(stepDisplacements[1]).blockVertical(self.periodVector).inverse().col(0))[0,0]
v = baseOffsets[0] + stepDisplacements[0] * n0
newCompoundPatternComponents.append((component, componentName, CosetMatrix(v, component.periodLattice)))
return CompoundPattern(newCompoundPatternComponents)
#Suppose we want to assemble a set of patterns with linkages
# How do we figure out the space of solutions with those linkages?
# Want to express as system of linear equations
def findSolutionSpace(patternsWithNames, linkages):
#Suppose we have n patterns connected by k linkages
#Solutions M are nx3 matrices with rows v_i, i=1..n, can (non-canonically) assume v_1 = [0,0,0]
#If (i,j) is a linkage, want v_i - v_j = baseOffset(i,j) + x_{i,j} * displacementsOffsetVector(i,j) + y_{i,j} * globalPeriodVector
#Let D be a kxn matrix with rows [i:1,j:-1]:
# B be a kx3 matrix with rows baseOffset(i,j)
# O be a kx3 matrix with rows displacementsOffsetVector(i,j)
# Then have D * M = B + X * O + Y * globalPeriodVector, for some diagonal kxk matrix X and kx1 column vector Y
# If M is a solution, then M+C is too for D*C = 0 (so C in Ann(D))
# Augment D with the extra row [1:1] to get D'
# If our linkage is connected, the rows of D' span Z^n
# Therefore D' has a (non-unique) left inverse, D'.leftInverse(), a nx(k+1) matrix
# Have D' * M is D*M but with an extra row of v_1 = [0,0,0]
# So must have M = D'.leftInverse() * D' * M = D'.leftInverse() * BlockVertical([0,0,0], B + X * O + Y * globalPeriodVector)
#
# Okay, suppose M is of this form, and let E be D'.leftInverse() with the first column lopped off
# Then D*M = D*E*D*M = D*E*(B + X*O + Y*globalPeriodVector) = D*E*B + D*E*X*O + D*E*Y*globalPeriodVector
# This alone does not guarantee D*M is of the correct form
# We also require that D*E*B + D*E*X*O + D*E*Y*globalPeriodVector is of the form B + X'*O + Y'*globalPeriodVector for suitable X', Y'
# So need (D*E-1)*B + (D*E*X-X')*O + (D*E*Y-Y')*globalPeriodVector = 0
# The Y part is easy, can relabel to: (D*E-1)*B + (D*E*X-X')*O = Y*globalPeriodVector
# Requirement for a solution to exist: (D*E-1)*B is in the lattice generated by globalPeriodVector_i, e_ii, D*E*e_ii
# Have (D*E-1)*B = -(D*E*X-X')*O + Y*globalPeriodVector
# Want to find possible values of X (or for X')
n = len(patternsWithNames)
k = len(linkages)
patNameToIndex = {patternsWithNames[i][1]:i for i in range(n)}
#linkages terms: outputPatName, outputPatOutputName, inputPatName, inputPatInputName
#These should all be the same
allPeriodVectors = Matrix([patternsWithNames[i][0].periodVector.terms[0] for i in range(n)])
#The linkage matrix D
linkagesMatrix = Matrix([[int(i == patNameToIndex[outputPatName]) - int(i == patNameToIndex[inputPatName]) for i in range(n)]
for outputPatName, _, inputPatName, _ in linkages])
#E: Inverse with the first column removed (we don't need that since it'd only be multiplied by 0)
changeOfBasisMatrix = Matrix([[int(i == 0) for i in range(n)]]).blockVertical(linkagesMatrix).leftInverse()[0:n, 1:k+1]
#the base offsets matrix
baseOffsetsMatrix = -Matrix([CompoundPattern.findOffset(patternsWithNames[patNameToIndex[outputPatName]][0], patternsWithNames[patNameToIndex[outputPatName]][0].outputNamesToIndexes[outputPatOutputName],
patternsWithNames[patNameToIndex[inputPatName]][0], patternsWithNames[patNameToIndex[inputPatName]][0].inputNamesToIndexes[inputPatInputName], 0).rep.terms[0]
for outputPatName, outputPatOutputName, inputPatName, inputPatInputName in linkages])
#the offset displacement matrix
offsetDisplacementMatrix = Matrix([patternsWithNames[patNameToIndex[outputPatName]][0].outputs[patternsWithNames[patNameToIndex[outputPatName]][0].outputNamesToIndexes[outputPatOutputName]][0].periodVector.terms[0]
for outputPatName, outputPatOutputName, _, _ in linkages])
#Variable names moment
dembResized = ((linkagesMatrix * changeOfBasisMatrix - Matrix.id(k)) * baseOffsetsMatrix).resize(1, k*3)
gpvPartsResized = [(Matrix([[int(j == i)] for j in range(k)]) * allPeriodVectors).resize(1, k*3) for i in range(k)]
xPartsResized = [(Matrix([[int(a == i and b == i) for a in range(k)] for b in range(k)]) * offsetDisplacementMatrix).resize(1, k*3) for i in range(k)]
dexPartsResized = [(linkagesMatrix * changeOfBasisMatrix * Matrix([[int(a == i and b == i) for a in range(k)] for b in range(k)]) * offsetDisplacementMatrix).resize(1, k*3) for i in range(k)]
dembCheckLatticeSpanner = Matrix([row.terms[0] for row in gpvPartsResized + xPartsResized + dexPartsResized])
dembCheckLattice = Lattice(dembCheckLatticeSpanner)
if dembResized in dembCheckLattice:
#Integer solution can exist
#Want to find possible values of X (or for X') which are solutions for (D*E-1)*B = -(D*E*X'-X)*O + Y*globalPeriodVector
#This gives a possible value of X
xVal = dembResized * dembCheckLatticeSpanner.rightInverse()[0:k*3,k:k*2]
xValDiagonalMatrix = Matrix([[xVal[0,i] * int(i==j) for j in range(k)] for i in range(k)])
#dexVal = -dembResized * dembCheckLatticeSpanner.rightInverse()[0:k*3,k*2:k*3]
#dexValDiagonalMatrix = Matrix([[xVal[0,i] * int(i==j) for j in range(k)] for i in range(k)])
#testVal = dembResized + (linkagesMatrix * changeOfBasisMatrix * dexValDiagonalMatrix - xValDiagonalMatrix) * offsetDisplacementMatrix
#g.warn(str(testVal))
mVal = changeOfBasisMatrix * (baseOffsetsMatrix + xValDiagonalMatrix * offsetDisplacementMatrix)
#g.warn(str(linkagesMatrix * mVal - baseOffsetsMatrix))
#Want dX a valid X offset
# This happens when have dX', dY such that 0 = dX*O - D*E*dX'*O + dY*G
# In other words, dX*O is in the lattice generated by D*E*e_ii*O, G_i
# And also in the lattice generated by e_ii*O
latticeASpanner = Matrix([row.terms[0] for row in gpvPartsResized + dexPartsResized])
latticeA = Lattice(latticeASpanner)
latticeBSpanner = Matrix([row.terms[0] for row in xPartsResized])
latticeB = Lattice(latticeBSpanner)
combinedLattice = latticeA & latticeB
#We then have that E*dX*O is a valid offset for mVal
eTimesCombinedLatticeSpanner = Matrix([(changeOfBasisMatrix * row.resize(k, 3)).resize(1,n*3).terms[0] for row in combinedLattice.basis.rows()])
eTimesCombinedLatticeIntegers = Lattice(eTimesCombinedLatticeSpanner) & Lattice(Matrix.id(n*3))
return (mVal, eTimesCombinedLatticeIntegers.basis)
else:
#Integer solution can't exist
raise ValueError("Incompatible Arrangement")
#Actually put together a solution, with given spacingConfiguration values
def findSolution(patternsWithNames, linkages, spacingConfiguration):
integerSolution, solutionOffsetsMatrix = CompoundPattern.findSolutionSpace(patternsWithNames, linkages)
#g.warn(str(integerSolution) + "\n\n" + str(solutionOffsetsMatrix))
if spacingConfiguration.width != solutionOffsetsMatrix.height:
raise ValueError("Incorrect spacing configuration size: "+str(spacingConfiguration.width)+" != "+str(solutionOffsetsMatrix.height))
solutionToUse = integerSolution + (spacingConfiguration * solutionOffsetsMatrix).resize(len(patternsWithNames), 3)
#g.warn(str(solutionToUse))
patternPlacements = [(patternsWithNames[i][0], patternsWithNames[i][1], solutionToUse.row(i)) for i in range(len(patternsWithNames))]
return CompoundPattern(patternPlacements)
#We want to find a *positive* solution (i.e. one which actually corresponds to a pattern, ignoring clearance requirements)
def findPositiveSolution(patternsWithNames, linkages):
integerSolution, solutionOffsetsMatrix = CompoundPattern.findSolutionSpace(patternsWithNames, [(a,b,c,d) for a, b, c, d, _ in linkages])
n = len(patternsWithNames)
k = len(linkages)
patNameToIndex = {patternsWithNames[i][1]:i for i in range(n)}
#These should all be the same
globalPeriodVector = patternsWithNames[0][0].periodVector
#the base offsets matrix
baseOffsetsMatrix = -Matrix([CompoundPattern.findOffset(patternsWithNames[patNameToIndex[outputPatName]][0], patternsWithNames[patNameToIndex[outputPatName]][0].outputNamesToIndexes[outputPatOutputName],
patternsWithNames[patNameToIndex[inputPatName]][0], patternsWithNames[patNameToIndex[inputPatName]][0].inputNamesToIndexes[inputPatInputName], 0).rep.terms[0]
for outputPatName, outputPatOutputName, inputPatName, inputPatInputName, _ in linkages])
#the offset displacement matrix
offsetDisplacementMatrix = Matrix([patternsWithNames[patNameToIndex[outputPatName]][0].outputs[patternsWithNames[patNameToIndex[outputPatName]][0].outputNamesToIndexes[outputPatOutputName]][0].periodVector.terms[0]
for outputPatName, outputPatOutputName, _, _, _ in linkages])
linkagesLattices = [Lattice(offsetDisplacementMatrix.row(rowIndex).blockVertical(globalPeriodVector), False) for rowIndex in range(k)]
linkageSeparationsFromIntegerSolutionTerms = []
#Offset spacings for our linkages in the default integerSolution
for linkageIndex in range(k):
outputPatName, outputPatOutputName, inputPatName, inputPatInputName, _ = linkages[linkageIndex]
outputPatIndex = patNameToIndex[outputPatName]
outputPat = patternsWithNames[outputPatIndex][0]
inputPatIndex = patNameToIndex[inputPatName]
inputPat = patternsWithNames[inputPatIndex][0]
outputPatOutputIndex = outputPat.outputNamesToIndexes[outputPatOutputName]
inputPatInputIndex = inputPat.inputNamesToIndexes[inputPatInputName]
outputPatOutput, _, outputPatOutputTime, outputPatOutputPosition = outputPat.outputs[outputPatOutputIndex]
inputPatInput, _, inputPatInputTime, inputPatInputPosition = inputPat.inputs[inputPatInputIndex]
displacementFromIntegerSolution = integerSolution.row(outputPatIndex) - integerSolution.row(inputPatIndex) + Matrix([[inputPatInputTime - outputPatOutputTime,0,0]]) + outputPatOutputPosition.rep - inputPatInputPosition.rep
#g.warn(str(displacementFromIntegerSolution) + "\n\n" + str(displacementFromIntegerSolution in linkagesLattices[linkageIndex]))
spacingFromIntegerSolution = (displacementFromIntegerSolution * linkagesLattices[linkageIndex].changeOfBasis)[0,0]
linkageSeparationsFromIntegerSolutionTerms.append(spacingFromIntegerSolution)
integerSolutionSeparations = Matrix([linkageSeparationsFromIntegerSolutionTerms])
linkageSeparationsFromSolutionOffsetsMatrixTerms = []
#We want, from a given row of solutionOffsetsMatrix, to find the corresponding impact on the base pattern spacings between linkages
for rowIndex in range(solutionOffsetsMatrix.height):
solutionOffsets = solutionOffsetsMatrix.row(rowIndex).resize(n,3)
linkageSeparationsFromSolutionOffsetsTerms = []
for linkageIndex in range(k):
outputPatName, outputPatOutputName, inputPatName, inputPatInputName, _ = linkages[linkageIndex]
outputPatIndex = patNameToIndex[outputPatName]
inputPatIndex = patNameToIndex[inputPatName]
displacementFromTheseOffsets = solutionOffsets.row(outputPatIndex) - solutionOffsets.row(inputPatIndex)
#g.warn(str(displacementFromTheseOffsets) + "\n\n" + str(displacementFromTheseOffsets in linkagesLattices[linkageIndex]))
#Find the actual spacing of these
spacingFromTheseOffsets = (displacementFromTheseOffsets * linkagesLattices[linkageIndex].changeOfBasis)[0,0]
linkageSeparationsFromSolutionOffsetsTerms.append(spacingFromTheseOffsets)
linkageSeparationsFromSolutionOffsetsMatrixTerms.append(linkageSeparationsFromSolutionOffsetsTerms)
solutionOffsetsSeparations = Matrix(linkageSeparationsFromSolutionOffsetsMatrixTerms)
#1329 ("BlockLayer0","Block0","LWSSSynth0","Block0",0),
#129 (That's... not right, right?) ("SERake0", "SERake.Instance15.SERakeCore.SEGlider0", "LWSSSynth0", "SEGlider0",0),
#95 ("BlockLayer0","SWGlider1","SERake0","KB0.SWGlider1",0),
#118 (That's definitely not right) ("SERake0", "SERake.Instance4.C3.SWGlider0", "SERake1", "KB0.SWGlider0",0),
#0 (That probably isn't right) ("NERake0","Instance0.C1.NEGlider0","LWSSSynth0","NEGlider0",0),
#-63 ("SERake1","SERake.Instance1.SERakeCore.SEGlider0","NERakeFilter","SEGlider1",0),
#-298 ("NERake0","Instance1.C1.NEGlider0","NERakeFilter","NEGlider1",0)
#g.warn(str(integerSolutionSeparations) + "\n\n" + str(solutionOffsetsSeparations))
#This amounts to finding an integer solution to a system of linear inequalities
# I'm too lazy to reimplement linear programming so scipy
#TODO: Not sure what I want to optimize for
c = np.array([-float(solutionOffsetsSeparations[0,i]) for i in range(solutionOffsetsSeparations.height)])
integrality = np.ones_like(c) #Want all integers
A = np.array([[float(x) for x in row] for row in solutionOffsetsSeparations.transpose().terms])
bl = np.array([float(linkages[i][4] - integerSolutionSeparations[0,i]) for i in range(k)])
bu = np.array([math.inf for i in range(solutionOffsetsSeparations.width)])
constraints = optimize.LinearConstraint(A, bl, bu)
bounds = optimize.Bounds(-math.inf,math.inf)
res = optimize.milp(c=c, constraints=constraints, integrality=integrality, bounds=bounds)
if res.status != 0:
raise ValueError("Invalid Solution\n\n"+str(res))
milpSolution = Matrix([[int(y) for y in res.x]])
solutionToUse = integerSolution + (milpSolution * solutionOffsetsMatrix).resize(n,3)
patternPlacements = [(patternsWithNames[i][0], patternsWithNames[i][1], solutionToUse.row(i)) for i in range(len(patternsWithNames))]
return CompoundPattern(patternPlacements)
#Conversion from a 1x pattern to an nx pattern
# Basically the only thing this has to do is unfold our inputs and outputs
class PeriodMultipliedPattern:
def __init__(self, pattern, multiplier):
self.pattern = pattern
self.multiplier = multiplier
self.dT = pattern.dT * multiplier
self.dX = pattern.dX * multiplier
self.dY = pattern.dY * multiplier
self.periodVector = pattern.periodVector * multiplier
self.periodLattice = Lattice(self.periodVector)
#Register inputs and outputs
self.inputs = [(inputPat,"Instance"+str(i)+"."+inputName,inputTime+pattern.dT*i, CosetMatrix(inputPosition.rep,self.periodLattice)+Matrix([[0,self.pattern.dX,self.pattern.dY]])*i) for inputPat,inputName,inputTime,inputPosition in pattern.inputs for i in range(multiplier)]
self.outputs = [(outputPat,"Instance"+str(i)+"."+outputName,outputTime+pattern.dT*i, CosetMatrix(outputPosition.rep,self.periodLattice)+Matrix([[0,self.pattern.dX,self.pattern.dY]])*i) for outputPat,outputName,outputTime,outputPosition in pattern.outputs for i in range(multiplier)]
self.inputNamesToIndexes = {self.inputs[i][1]:i for i in range(len(self.inputs))}
self.outputNamesToIndexes = {self.outputs[i][1]:i for i in range(len(self.outputs))}
def place(self, position, mode = "or"):
self.pattern.place(CosetMatrix(position.rep, self.pattern.periodLattice), mode)
def placeWithInputs(self, position, numInputs = 0, numOutputs = 0, mode = "or"):
self.pattern.placeWithInputs(CosetMatrix(position.rep, self.pattern.periodLattice), numInputs*self.multiplier, numOutputs*self.multiplier, mode)
#Automatically add in a collection of components with compatible spacings with certain inputs/outputs to form a loop
def addCompatibleComponents(self, componentsToAddData, selfName = "Main"):
newCompoundPatternComponents = [(self, selfName, CosetMatrix(Matrix.zero(1,3), self.periodLattice))]
for component, componentName, componentInputIndicesToSelfOutputIndices, componentOutputIndicesToSelfInputIndices in componentsToAddData:
#Get constraints
baseOffsets = []
stepDisplacements = []
#We expect exactly 2 of these constraints in total
for componentInputName, selfOutputName in componentInputIndicesToSelfOutputIndices.items():
componentInputIndex = component.inputNamesToIndexes[componentInputName]
selfOutputIndex = self.outputNamesToIndexes[selfOutputName]
baseOffsets.append(CompoundPattern.findOffset(self, selfOutputIndex, component, componentInputIndex).rep)
stepDisplacements.append(component.inputs[componentInputIndex][0].periodVector)
for componentOutputName, selfInputName in componentOutputIndicesToSelfInputIndices.items():
componentOutputIndex = component.outputNamesToIndexes[componentOutputName]
selfInputIndex = self.inputNamesToIndexes[selfInputName]
baseOffsets.append(-CompoundPattern.findOffset(component, componentOutputIndex, self, selfInputIndex).rep)
stepDisplacements.append(component.outputs[componentOutputIndex][0].periodVector)
#Our position must be, for all i, of the form v = baseOffsets[i] + n_i * stepDisplacements[i] + m_i * self.periodVector
# In particular, have 0 = baseOffsets[0] - baseOffsets[1] + n_0 * stepDisplacements[0] - n_1 * stepDisplacements[1] + (m_0-m_1)*self.periodVector
# baseOffsets[1] - baseOffsets[0] = Matrix([[n_0,-n_1,m_0-m_1]]) * BlockVertical(stepDisplacements[0], stepDisplacements[1], self.periodVector)
# (baseOffsets[1] - baseOffsets[0]) * blockMatrixInverse = Matrix([[n_0,-n_1,m_0-m_1]])
# ((baseOffsets[1] - baseOffsets[0]) * blockMatrixInverse.col(0))[0,0] = n_0
n0 = ((baseOffsets[1] - baseOffsets[0]) * stepDisplacements[0].blockVertical(stepDisplacements[1]).blockVertical(self.periodVector).inverse().col(0))[0,0]
v = baseOffsets[0] + stepDisplacements[0] * n0
newCompoundPatternComponents.append((component, componentName, CosetMatrix(v, component.periodLattice)))
return CompoundPattern(newCompoundPatternComponents)
#Settings
g.new("13131")
g.setrule("B3/S23")
g.setalgo("HashLife")
#Basic objects
block = PeriodicPattern(g.parse("2o$2o!",0,0), 1, 0, 0)
blinker = PeriodicPattern(g.parse("3o!",-1,0), 2, 0, 0)
SWGlider = PeriodicPattern(g.parse("bo$o$3o!"), 4, -1, 1)
NWGlider = PeriodicPattern(g.parse("2o$obo$o!"), 4, -1, -1)
NEGlider = PeriodicPattern(g.parse("3o$2bo$bo!"), 4, 1, -1)
SEGlider = PeriodicPattern(g.parse("2bo$obo$b2o!"), 4, 1, 1)
NLWSS = PeriodicPattern(g.parse("3o$o2bo$o$o$bobo!",0,0), 4, 0, -2)
NMWSS = PeriodicPattern(g.parse("3o$o2bo$o$o3bo$o$bobo!",0,0), 4, 0, -2)
NHWSS = PeriodicPattern(g.parse("3o$o2bo$o$o3bo$o3bo$o$bobo!",0,0), 4, 0, -2)
WLWSS = PeriodicPattern(g.parse("bo2bo$o$o3bo$4o!",0,0), 4, -2, 0)
'''
#Helix components
helixComponent1 = PeriodicPattern([],31*16,-1*16,-13*16,
[(NEGlider, "NEGlider0", 0, Matrix([[0,0,4]])),
(NLWSS, "NLWSS0", 0, Matrix([[1,5,1]])),
(NHWSS, "NHWSS0", 8, Matrix([[2,12,-1]]))],
[(NEGlider, "NEGlider1", 17, Matrix([[1,12,-5]]))])
helixComponent2 = PeriodicPattern([],31*16,-1*16,-13*16,
[(NEGlider, "NEGlider0", 0, Matrix([[3,-1,1]])),
(NLWSS, "NLWSS0", 0, Matrix([[1,4,2]])),
(NLWSS, "NLWSS1", 10, Matrix([[3,2,7]]))],
[(NWGlider, "NWGlider0", 19, Matrix([[0,-2,1]]))])
helixComponent3 = PeriodicPattern([],31*16,-1*16,-13*16,
[(NWGlider, "NWGlider0", 0, Matrix([[2,13,4]])),
(NLWSS, "NLWSS0", 0, Matrix([[3,7,2]])),
(NHWSS, "NHWSS0", 8, Matrix([[0,0,-2]]))],
[(NWGlider, "NWGlider1", 17, Matrix([[3,1,-5]]))])
helixComponent4 = PeriodicPattern([],31*16,-1*16,-13*16,
[(NWGlider, "NWGlider0", 0, Matrix([[0,9,5]])),
(NHWSS, "NHWSS0", 0, Matrix([[0,3,0]])),
(NHWSS, "NHWSS1", 7, Matrix([[0,9,8]])),
(NLWSS, "NLWSS0", 23, Matrix([[2,0,4]])),
(NLWSS, "NLWSS1", 40, Matrix([[2,4,3]]))],
[(NEGlider, "NEGlider0", 29, Matrix([[3,6,-6]])),
(NWGlider, "NWGlider1", 39, Matrix([[1,-3,-4]]))])
#TODO: Replace indices with names
helixSpacings = [
(helixComponent1,"H0","","NEGlider1",2),
(helixComponent1,"H1","NEGlider0","NEGlider1",2),
(helixComponent1,"H2","NEGlider0","NEGlider1",2),
(helixComponent1,"H3","NEGlider0","NEGlider1",2),
(helixComponent1,"H4","NEGlider0","NEGlider1",2),
(helixComponent1,"H5","NEGlider0","NEGlider1",2),
(helixComponent1,"H6","NEGlider0","NEGlider1",2),
(helixComponent1,"H7","NEGlider0","NEGlider1",2),
(helixComponent2,"H8","NEGlider0","NWGlider0",2),
(helixComponent3,"H9","NWGlider0","NWGlider1",0),
(helixComponent3,"H10","NWGlider0","NWGlider1",2),
(helixComponent3,"H11","NWGlider0","NWGlider1",2),
(helixComponent3,"H12","NWGlider0","NWGlider1",2),
(helixComponent3,"H13","NWGlider0","NWGlider1",2),
(helixComponent3,"H14","NWGlider0","NWGlider1",2),
(helixComponent3,"H15","NWGlider0","NWGlider1",2),
(helixComponent3,"H16","NWGlider0","NWGlider1",2),
(helixComponent3,"H17","NWGlider0","NWGlider1",2),
(helixComponent4,"H18","NWGlider0","NEGlider0",6),
]
helix = CompoundPattern.chain(helixSpacings)
#helix.placeWithInputs(CosetMatrix(Matrix([[0,0,0]]), helix.periodLattice), 20, 20)
#Fanout components
#TODO: Would be nice to figure these input/output values automatically
fanoutComponent1 = PeriodicPattern([],31*16,-1*16,-13*16,
[(NWGlider, "NWGlider0", 0, Matrix([[1,1,0]])),
(NLWSS, "NLWSS0", 0, Matrix([[3,-5,0]])),
(NLWSS, "NLWSS1", 15, Matrix([[1,0,5]])),
(NLWSS, "NLWSS2", 16, Matrix([[2,6,4]]))],
[(blinker, "Blinker0", 28, Matrix([[0,4,7]])),
(WLWSS, "WLWSS0", 29, Matrix([[-1,-7,-3]]))])
fanoutComponent2 = PeriodicPattern([],31*16,-1*16,-13*16,
[(blinker, "Blinker0", 0, Matrix([[1,2,1]])),
(NLWSS, "NLWSS0", 0, Matrix([[1,2,4]])),
(NLWSS, "NLWSS1", 13, Matrix([[0,0,6]]))],
[(NWGlider, "NWGlider0", 10, Matrix([[-1,1,-2]]))])
fanoutComponent3 = PeriodicPattern([],31*16,-1*16,-13*16,
[(NWGlider, "NWGlider0", 0, Matrix([[2,7,5]])),
(NHWSS, "NHWSS0", 0, Matrix([[0,0,0]])),
(NMWSS, "NMWSS0", 10, Matrix([[2,9,9]]))],
[(NWGlider, "NWGlider1", 26, Matrix([[0,2,-5]]))])
fanoutComponent4 = PeriodicPattern([],31*16,-1*16,-13*16,
[(NWGlider, "NWGlider0", 0, Matrix([[2,5,0]])),
(NLWSS, "NLWSS0", 0, Matrix([[0,6,4]])),
(NLWSS, "NLWSS1", 16, Matrix([[3,0,7]]))],
[(blinker, "Blinker0", 18, Matrix([[1,8,5]])),
(NWGlider, "NWGlider1", 20, Matrix([[3,1,4]]))])
fanoutComponent5 = PeriodicPattern([],31*16,-1*16,-13*16,
[(blinker, "Blinker0", 0, Matrix([[0,1,0]])),
(NLWSS, "NLWSS0", 0, Matrix([[0,3,2]])),
(NLWSS, "NLWSS0", 9, Matrix([[3,7,6]]))],
[(NWGlider, "NWGlider0", 23, Matrix([[2,6,1]]))])
fanoutComponent6 = PeriodicPattern([],31*16,-1*16,-13*16,
[(blinker, "Blinker0", 0, Matrix([[0,1,2]])),
(NLWSS, "NLWSS0", 0, Matrix([[1,5,1]])),
(NMWSS, "NMWSS0", 25, Matrix([[3,9,3]]))],
[(NWGlider, "NWGlider0", 37, Matrix([[1,5,-3]]))])
#Extra fanout components for the last track builder (slightly cheaper)
fanoutComponent7 = PeriodicPattern([],31*16,-1*16,-13*16,
[(NWGlider, "NWGlider0", 0, Matrix([[1,4,0]])),
(NLWSS, "NLWSS0", 0, Matrix([[2,6,5]])),
(NLWSS, "NLWSS1", 2, Matrix([[2,0,4]]))],
[(blinker, "Blinker0", 16, Matrix([[1,4,1]])),
(NWGlider, "NWGlider1", 17, Matrix([[1,-1,0]]))])
fanoutComponent8 = PeriodicPattern([],31*16,-1*16,-13*16,
[(blinker, "Blinker0", 0, Matrix([[0,5,0]])),
(NLWSS, "NLWSS0", 0, Matrix([[2,8,2]])),
(NLWSS, "NLWSS1", 7, Matrix([[2,0,3]]))],
[(NWGlider, "NWGlider0", 14, Matrix([[2,3,2]]))])
trackPairBuilderCollision1 = PeriodicPattern([],31*16,-1*16,-13*16,
[(WLWSS, "WLWSS0", 0, Matrix([[1,1,-1]])),
(NWGlider, "NWGlider0", 0, Matrix([[2,3,5]])),
(NWGlider, "NWGlider1", 79, Matrix([[1,6,6]]))],
[(block, "Block0", 8, Matrix([[0,-3,0]])),
(block, "Block1", 85, Matrix([[0,2,5]]))])
#TODO: Want to be able to 'complete a cycle with available components' when possible
#TODO: Want a slightly different last fanout
# First fanout should have different starting displacement, connect to helix
# Last fanout should not produce 'fanout continuation glider': It's cheaper to use an extra LWSS for period multiplication instead
# In fact, could potentially be even cheaper if we instead fan out into two gliders which support our climbers directly!
def fanoutPatSpacingInfo(n,dn, i, isFirstFanout = False, isLastFanout = False):
startSpacing = 207 + (dn-2)*192 - n * 16
if isFirstFanout:
startSpacing = 38 + n * 16
return [
(fanoutComponent1,"F1,"+str(i),"NWGlider0","Blinker0",startSpacing),
(fanoutComponent2,"F2,"+str(i),"Blinker0","NWGlider0",1 + n*24),
(fanoutComponent3,"F3,"+str(i),"NWGlider0","NWGlider1",50 + n*16),
(fanoutComponent4,"F4,"+str(i),"NWGlider0","Blinker0",47),
(fanoutComponent5,"F5,"+str(i),"Blinker0","NWGlider0",10),
(fanoutComponent4,"F6,"+str(i),"NWGlider0","Blinker0",94),
(fanoutComponent6,"F7,"+str(i),"Blinker0","NWGlider0",10),
]
fanoutDeviceSpacingsList = [3]
for i in range(15-1):
#15/12 is probably not the exact optimal value but it's fine
newN = int(math.ceil(fanoutDeviceSpacingsList[0] * 7 / 6 + 15/12))
fanoutDeviceSpacingsList.insert(0,newN)
fanoutPatSpacings = [(helix,"Helix","","H18.NWGlider1",0)]
for i in range(len(fanoutDeviceSpacingsList)):
if i == 0:
fanoutPatSpacings += fanoutPatSpacingInfo(fanoutDeviceSpacingsList[i], 0, i, True)
else:
fanoutPatSpacings += fanoutPatSpacingInfo(fanoutDeviceSpacingsList[i], fanoutDeviceSpacingsList[i-1] - fanoutDeviceSpacingsList[i], i, False)
#Cheaper last fanout
fanoutPatSpacings += [(fanoutComponent7,"F1,16","NWGlider0","Blinker0",68),(fanoutComponent8,"F2,16","Blinker0","NWGlider0",26)]
fanoutTrackPairBuilderConnections = [(trackPairBuilderCollision1, "T"+str(i), {"WLWSS0":"F1,"+str(i)+".WLWSS0", "NWGlider0":"F4,"+str(i)+".NWGlider1"}, {}) for i in range(15)]
periodDemultiplierCrawlerBlockInputs = [(block, "Block"+str(i), 31*i, Matrix([[0,6,-2]]) + Matrix([[0,-1,-13]])*i) for i in range(15)]
periodDemultiplierCrawlerGliderOutputs = [(SWGlider, "SWGlider"+str(i), 22+31*i, Matrix([[1,0,3]]) + Matrix([[0,-1,-13]])*i) for i in range(16)]
periodDemultiplierCrawler = PeriodicPattern(g.parse("2b3o$2bo2bo$bo$4b2o$o3b2o$o$2bo$2b3o$3b2o$4bo$2b2o$bobo$o3bo$2b2o!"),31*16,-1*16,-13*16,
periodDemultiplierCrawlerBlockInputs + [(NWGlider, "NWGlider0", 31*15, Matrix([[1,7,-2]]) + Matrix([[0,-1,-13]])*15)],
periodDemultiplierCrawlerGliderOutputs)
periodDemultiplierConnections = [(periodDemultiplierCrawler, "Demultiplier0", {"NWGlider0":"Main.F1,16.NWGlider1","Block0":"T0.Block0"}, {}),
(periodDemultiplierCrawler, "Demultiplier1", {"NWGlider0":"Main.F2,16.NWGlider0","Block0":"T0.Block1"}, {})]
fanoutDevice = CompoundPattern.chain(fanoutPatSpacings).addCompatibleComponents(fanoutTrackPairBuilderConnections).addCompatibleComponents(periodDemultiplierConnections)
#g.warn(str(set(fanoutDevice.outputNamesToIndexes)))
#fanoutDevice.placeWithInputs(Matrix([[0,0,0]]), 320, 3)
'''
#Crawlers on various objects
#TODO: May want to period-multiply periodic or compound patterns by 16
crawlerSWGliders = [0,0,0]
crawlerSWGliders[0] = PeriodicPattern(g.parse("2b3o$2bo2bo$bo$4b2o$o3b2o$o$2bo$2b3o$3b2o$4bo$2b2o$bobo$o3bo$2b2o!"), 31, -1, -13,
[(SWGlider, "SWGlider0", 0, Matrix([[0,6,-2]]))],
[(SWGlider, "SWGlider0", 22, Matrix([[1,0,3]]))])
crawlerSWGliders[1] = PeriodicPattern(g.parse("2b3o$2bo2bo$bo$4b2o$o3b2o$o$2bo$2b3o$3b2o$4bo$2b2o$bobo$o3bo$2b2o!"), 31, -1, -13,
[(SWGlider, "SWGlider0", 0, Matrix([[0,6,-3]]))],
[(SWGlider, "SWGlider0", 22, Matrix([[1,0,3]]))])
crawlerSWGliders[2] = PeriodicPattern(g.parse("2b3o$2bo2bo$bo$4b2o$o3b2o$o$2bo$2b3o$3b2o$4bo$2b2o$bobo$o3bo$2b2o!"), 31, -1, -13,
[(SWGlider, "SWGlider0", 0, Matrix([[1,6,-3]]))],
[(SWGlider, "SWGlider0", 22, Matrix([[1,0,3]]))])
crawlerNWGliders = PeriodicPattern(g.parse("2b3o$2bo2bo$bo$4b2o$o3b2o$o$2bo$2b3o$3b2o$4bo$2b2o$bobo$o3bo$2b2o!"), 31, -1, -13,
[(NWGlider, "NWGlider0", 0, Matrix([[1,7,-2]]))],
[(SWGlider, "SWGlider0", 22, Matrix([[1,0,3]]))])
crawlerBlocks = PeriodicPattern(g.parse("2b3o$2bo2bo$bo$4b2o$o3b2o$o$2bo$2b3o$3b2o$4bo$2b2o$bobo$o3bo$2b2o!"), 31, -1, -13,
[(block, "Block0", 0, Matrix([[0,6,-2]]))],
[(SWGlider, "SWGlider0", 22, Matrix([[1,0,3]]))])
SWGliderStreamLattice = crawlerSWGliders[0].periodLattice + SWGlider.periodLattice
SWGliderStreamLaneChangeOfBasis = -Matrix([x.terms[0] for x,y in Lattice(Matrix.id(3)).quotientGeneratorsWithTorsions(SWGliderStreamLattice)]).inverse().col(2)
#The lane shift a SW glider -> SW glider crawler shifts a glider trail by
crawlerGliderLattice = SWGlider.periodLattice + crawlerSWGliders[0].periodLattice
def getGliderShift(pattern, inputIndex = 0, outputIndex = 0):
inputLane = CosetMatrix((pattern.inputs[inputIndex][3] - Matrix([[pattern.inputs[inputIndex][2],0,0]])).rep, crawlerGliderLattice)
outputLane = CosetMatrix((pattern.outputs[inputIndex][3] - Matrix([[pattern.outputs[inputIndex][2],0,0]])).rep, crawlerGliderLattice)
return outputLane - inputLane
gliderShifts = [int((getGliderShift(crawlerSWGliders[i]).rep * SWGliderStreamLaneChangeOfBasis)[0,0]) for i in range(3)] #[69,42,28]
blockLayerTrackDisplacementGoal = int(((Matrix([[0,-12,-12]]) - Matrix([[0,-15,6]])) * SWGliderStreamLaneChangeOfBasis)[0,0]) #237
#237 = 69 + 42*4
#TODO: Would like to figure out the optimal way to do this automatically: Plugging it in manually works but feels mildly unsatisfying
startingShiftSpacings = [(crawlerSWGliders[0],"C0","SWGlider0","SWGlider0",1),
(crawlerSWGliders[1],"C1","SWGlider0","SWGlider0",1),
(crawlerSWGliders[1],"C2","SWGlider0","SWGlider0",1),
(crawlerSWGliders[1],"C3","SWGlider0","SWGlider0",1),
(crawlerSWGliders[1],"C4","SWGlider0","SWGlider0",1)]
startingShifter = CompoundPattern.chain(startingShiftSpacings)
#startingShifter.placeWithInputs(CosetMatrix(Matrix([[0,0,0]]), startingShifter.periodLattice), 10, 10)
#All three pair-track blocklayers and all three pair-track rephasers (the latter can be compound patterns)
pairTrackBlockLayers = [0,0,0]
pairTrackBlockLayers[0] = PeriodicPattern(g.parse("2b3o$2bo2bo$bo$4b2o$o3b2o$o$2bo$2b3o$3b2o$4bo7b3o$2b2o8bo2bo$bobo6bo4bo$o3bo5bo$2b2o5b2o$10b2obo$12bo5$14b2o2$12bo2bo$11bo$11bo2bo$13bo!"),31,-1,-13,
[(SWGlider, "C0.SWGlider0", 0, Matrix([[0,6,-2]])),
(SWGlider, "C1.SWGlider0", 20, Matrix([[0,16,-3]]))],
[(block, "Block0", 2, Matrix([[0,11,23]])),
(SWGlider, "C0.SWGlider0", 22, Matrix([[1,0,3]])),
(SWGlider, "C1.SWGlider0", 11, Matrix([[1,11,15]]))])
pairTrackBlockLayers[1] = PeriodicPattern(g.parse("2b3o$2bo2bo$bo$4b2o$o3b2o$o$2bo$2b3o$3b2o$4bo7b3o$2b2o8bo2bo$bobo6bo4bo$o3bo5bo$2b2o5b2o$10b2obo$12bo5$14b2o2$12bo2bo$11bo$11bo2bo$13bo!"),31,-1,-13,
[(SWGlider, "C0.SWGlider0", 0, Matrix([[0,6,-3]])),
(SWGlider, "C1.SWGlider0", 20, Matrix([[0,16,-4]]))],
[(block, "Block0", 2, Matrix([[0,11,23]])),
(SWGlider, "C0.SWGlider0", 22, Matrix([[1,0,3]])),
(SWGlider, "C1.SWGlider0", 11, Matrix([[1,11,15]]))])
pairTrackBlockLayers[2] = PeriodicPattern(g.parse("2b3o$2bo2bo$bo$4b2o$o3b2o$o$2bo$2b3o$3b2o$4bo7b3o$2b2o8bo2bo$bobo6bo4bo$o3bo5bo$2b2o5b2o$10b2obo$12bo5$14b2o2$12bo2bo$11bo$11bo2bo$13bo!"),31,-1,-13,
[(SWGlider, "C0.SWGlider0", 0, Matrix([[1,6,-3]])),
(SWGlider, "C1.SWGlider0", 20, Matrix([[1,16,-4]]))],
[(block, "Block0", 2, Matrix([[0,11,23]])),
(SWGlider, "C0.SWGlider0", 22, Matrix([[1,0,3]])),
(SWGlider, "C1.SWGlider0", 11, Matrix([[1,11,15]]))])
pairTrackRephasers = [CompoundPattern([(crawlerSWGliders[i], "C0", Matrix([[0,0,0]])),
(crawlerSWGliders[i], "C1", Matrix([[-16,11,-2]]))])
for i in range(3)]
#Signal processors
def Inverter0(signals):
multiplier = len(signals)
blockInputs = [(block, "Block"+str(i), 31*i, Matrix([[0,6,-2]]) + Matrix([[0,-1,-13]]) * i) for i in range(multiplier)]
signalInputs = [(SWGlider, "SWGlider"+str(i), 3 + 31*i, Matrix([[0,8,10]]) + Matrix([[0,-1,-13]]) * i) for i in range(multiplier) if signals[i]]
outputs = [(SWGlider, "SWGlider"+str(i), 22 + 31*i, Matrix([[1,0,3]]) + Matrix([[0,-1,-13]]) * i) for i in range(multiplier) if not signals[i]]
startPat = g.parse("2b3o$2bo2bo$bo$4b2o$o3b2o$o$2bo$2b3o$3b2o$4bo$2b2o$bobo$o3bo$2b2o!")
return PeriodicPattern(startPat, 31*multiplier, -1*multiplier, -13*multiplier, blockInputs + signalInputs, outputs)
inverter0LaneShift = int(((Matrix([[1-22,0,3]]) - Matrix([[0-3,8,10]])) * SWGliderStreamLaneChangeOfBasis)[0,0]) #601
def Inverter1(signals):
multiplier = len(signals)
blockInputs = [(block, "Block"+str(i), 31*i, Matrix([[0,6,-2]]) + Matrix([[0,-1,-13]]) * i) for i in range(multiplier)]
signalInputs = [(SWGlider, "SWGlider"+str(i), 3 + 31*i, Matrix([[3,8,10]]) + Matrix([[0,-1,-13]]) * i) for i in range(multiplier) if signals[i]]
outputs = [(SWGlider, "SWGlider"+str(i), 22 + 31*i, Matrix([[1,0,3]]) + Matrix([[0,-1,-13]]) * i) for i in range(multiplier) if not signals[i]]
#Use different start pattern if currently in the middle of a glider deletion
startPat = g.parse("2b3o$2bo2bo$bo$4b2o$o3b2o$o$2bo$2b3o$3b2o$4bo$2b2o$bobo$o3bo$2b2o!")
if signals[multiplier-1]:
startPat = g.parse("3b3o$3bo2bo$2bo$5b2o$bo3b2o$bo$3bo$3b3o$4b2o$5bo$3b2o$2bobo$bo3bo$3b2o5$4bo$o4bo$o3bo$2ob2o$6b2o$6b2o$7bo!", -1, 0)
return PeriodicPattern(startPat, 31*multiplier, -1*multiplier, -13*multiplier, blockInputs+signalInputs, outputs)
inverter1LaneShift = int(((Matrix([[1-22,0,3]]) - Matrix([[3-3,8,10]])) * SWGliderStreamLaneChangeOfBasis)[0,0]) #559
def Inverter2(signals):
multiplier = len(signals)
blockInputs = [(block, "Block"+str(i), 31*i, Matrix([[0,6,-2]]) + Matrix([[0,-1,-13]]) * i) for i in range(multiplier)]
signalInputs = [(SWGlider, "SWGlider"+str(i), 3 + 31*i, Matrix([[2,8,7]]) + Matrix([[0,-1,-13]]) * i) for i in range(multiplier) if signals[i]]
outputs = [(SWGlider, "SWGlider"+str(i), 22 + 31*i, Matrix([[1,0,3]]) + Matrix([[0,-1,-13]]) * i) for i in range(multiplier) if not signals[i]]
#Use different start pattern if currently in the middle of a glider deletion
startPat = g.parse("2b3o$2bo2bo$bo$4b2o$o3b2o$o$2bo$2b3o$3b2o$4bo$2b2o$bobo$o3bo$2b2o!")
if signals[multiplier-1]:
startPat = g.parse("3b3o$3bo2bo$2bo$5b2o$bo3b2o$bo$3bo$3b3o$4b2o$5bo$3b2o$2bobo$bo3bo$3b2o5$10b2o$o9b2o$obo3bo$2o2b2ob2o$4b2ob2o!", -1, 0)
return PeriodicPattern(startPat, 31*multiplier, -1*multiplier, -13*multiplier, blockInputs+signalInputs, outputs)
inverter2LaneShift = int(((Matrix([[1-22,0,3]]) - Matrix([[2-3,8,7]])) * SWGliderStreamLaneChangeOfBasis)[0,0]) #492
def InverterBlockLayer(signals):
multiplier = len(signals)
blockInputs = [(block, "Block"+str(i), 31*i, Matrix([[0,6,-2]]) + Matrix([[0,-1,-13]]) * i) for i in range(multiplier)]
signalInputs = [(SWGlider, "SWGlider"+str(i), 6 + 31*i, Matrix([[0,8,12]]) + Matrix([[0,-1,-13]]) * i) for i in range(multiplier) if signals[i]]
outputs = [(SWGlider, "SWGlider"+str(i), 22 + 31*i, Matrix([[1,0,3]]) + Matrix([[0,-1,-13]]) * i) for i in range(multiplier) if not signals[i]] + [
(block, "Block"+str(i), 30 + 31*i, Matrix([[0,3,6]]) + Matrix([[0,-1,-13]]) * i) for i in range(multiplier) if signals[i]]
startPat = g.parse("2b3o$2bo2bo$bo$4b2o$o3b2o$o$2bo$2b3o$3b2o$4bo$2b2o$bobo$o3bo$2b2o!")
return PeriodicPattern(startPat, 31*multiplier, -1*multiplier, -13*multiplier, blockInputs + signalInputs, outputs)
inverterBlockLayerLaneShift = int(((Matrix([[1-22,0,3]]) - Matrix([[0-6,8,12]])) * SWGliderStreamLaneChangeOfBasis)[0,0]) #697
beehiveWE = PeriodicPattern(g.parse("b2o$o2bo$b2o!"),1,0,0)
def InverterBeehiveLayer(signals):
multiplier = len(signals)
blockInputs = [(block, "Block"+str(i), 31*i, Matrix([[0,6,-2]]) + Matrix([[0,-1,-13]]) * i) for i in range(multiplier)]
signalInputs = [(SWGlider, "SWGlider"+str(i), 3 + 31*i, Matrix([[1,8,6]]) + Matrix([[0,-1,-13]]) * i) for i in range(multiplier) if signals[i]]
outputs = [(SWGlider, "SWGlider"+str(i), 22 + 31*i, Matrix([[1,0,3]]) + Matrix([[0,-1,-13]]) * i) for i in range(multiplier) if not signals[i]] + [
(beehiveWE, "BeehiveWE"+str(i), 60 + 31*(i-1), Matrix([[0,-3,8]]) + Matrix([[0,-1,-13]])*(i-1)) for i in range(multiplier) if signals[mod(i-1, multiplier)]]
startPat = g.parse("2b3o$2bo2bo$bo$4b2o$o3b2o$o$2bo$2b3o$3b2o$4bo$2b2o$bobo$o3bo$2b2o!")
if signals[multiplier-1]:
startPat = g.parse("2b3o$2bo2bo$bo$4b2o$o3b2o$o$2bo$2b3o$3b2o$4bo$2b2o$bobo$o3bo$2b2o5$obo$o3bo$5b2o3bo$3bob2o3b2o$2b4obo4bo$2bo3b2obobo$bo4bob2o$b2o4bo!")
return PeriodicPattern(startPat, 31*multiplier, -1*multiplier, -13*multiplier, blockInputs + signalInputs, outputs)
inverterBeehiveLayerLaneShift = int(((Matrix([[1-22,0,3]]) - Matrix([[1-3,8,6]])) * SWGliderStreamLaneChangeOfBasis)[0,0]) #479
#This is possibly useful because it can invert a SE glider stream
boatBlinkerTarget = PeriodicPattern(g.parse("2o$obo5bo$bo6bo$8bo!"),2,0,0)
def InverterBoatAndBlinkerLayer(signals):
multiplier = len(signals)
blockInputs = [(block, "Block"+str(i), 31*i, Matrix([[0,6,-2]]) + Matrix([[0,-1,-13]]) * i) for i in range(multiplier)]
signalInputs = [(SWGlider, "SWGlider"+str(i), 2 + 31*i, Matrix([[3,7,10]]) + Matrix([[0,-1,-13]]) * i) for i in range(multiplier) if signals[i]]
outputs = [(SWGlider, "SWGlider"+str(i), 22 + 31*i, Matrix([[1,0,3]]) + Matrix([[0,-1,-13]]) * i) for i in range(multiplier) if not signals[i]] + [
(boatBlinkerTarget, "BoatBlinkerTarget"+str(i), 26 + 31*i, Matrix([[0,-2,13]]) + Matrix([[0,-1,-13]]) * i) for i in range(multiplier) if signals[i]]
startPat = g.parse("2b3o$2bo2bo$bo$4b2o$o3b2o$o$2bo$2b3o$3b2o$4bo$2b2o$bobo$o3bo$2b2o!")
return PeriodicPattern(startPat, 31*multiplier, -1*multiplier, -13*multiplier, blockInputs + signalInputs, outputs)
inverterBoatAndBlinkerLayerLaneShift = int(((Matrix([[1-22,0,3]]) - Matrix([[2-3,7,10]])) * SWGliderStreamLaneChangeOfBasis)[0,0]) #490
#Can invert a SE or SW glider stream, and uniquely does not invert our signal stream
# This does also produce an extra 1x SE stream to clean up
#Lonboats can also reflect a SW glider stream to SE
longboatTarget = PeriodicPattern(g.parse("2bo$bobo$obo$2o!"),1,0,0)
def LongboatLayer(signals):
multiplier = len(signals)
blockInputs = [(block, "Block"+str(i), 31*i, Matrix([[0,6,-2]]) + Matrix([[0,-1,-13]]) * i) for i in range(multiplier)]
signalInputs = [(SWGlider, "SWGlider"+str(i), 6 + 31*i, Matrix([[3,10,10]]) + Matrix([[0,-1,-13]]) * i) for i in range(multiplier) if signals[i]]
outputs = [(SWGlider, "ExtraSWGlider"+str(i), 22 + 31*i, Matrix([[1,0,3]]) + Matrix([[0,-1,-13]]) * i) for i in range(multiplier)] + [
(longboatTarget, "LongboatTarget"+str(i), 28 + 31*i, Matrix([[0,9,12]]) + Matrix([[0,-1,-13]]) * i) for i in range(multiplier) if signals[i]
] + [
(SWGlider, "SWGlider"+str(i), 24 + 31*i, Matrix([[3,5,12]]) + Matrix([[0,-1,-13]]) * i) for i in range(multiplier) if signals[i]]
startPat = g.parse("2b3o$2bo2bo$bo$4b2o$o3b2o$o$2bo$2b3o$3b2o$4bo$2b2o$bobo$o3bo$2b2o!")
return PeriodicPattern(startPat, 31*multiplier, -1*multiplier, -13*multiplier, blockInputs + signalInputs, outputs)
longboatLayerLaneShift = int(((Matrix([[3-24,5,12]]) - Matrix([[3-6,10,10]])) * SWGliderStreamLaneChangeOfBasis)[0,0]) #109
#Cannot invert dense streams
def SparseInverter(signals):
multiplier = len(signals)
blockInputs = [(block, "Block"+str(i), 31*i, Matrix([[0,6,-2]]) + Matrix([[0,-1,-13]]) * i) for i in range(multiplier)]
signalInputs = [(SWGlider, "SWGlider"+str(i), 5 + 31*i, Matrix([[0,6,13]]) + Matrix([[0,-1,-13]]) * i) for i in range(multiplier) if signals[i]]
outputs = [(SWGlider, "SWGlider"+str(i), 22 + 31*i, Matrix([[1,0,3]]) + Matrix([[0,-1,-13]]) * i) for i in range(multiplier) if not signals[i]]
startPat = g.parse("2b3o$2bo2bo$bo$4b2o$o3b2o$o$2bo$2b3o$3b2o$4bo$2b2o$bobo$o3bo$2b2o!")
if signals[multiplier-1]:
startPat = g.parse("2b3o$2bo2bo$bo$4b2o$o3b2o$o$2bo$2b3o$3b2o$4bo$2b2o$bobo$o3bo$2b2o5$4b2o$3bob2o$3bo3bo$2bo2b4o$2obob2o2bo$b3o4bo$2bo!")
return PeriodicPattern(startPat, 31*multiplier, -1*multiplier, -13*multiplier, blockInputs + signalInputs, outputs)
sparseInverterLaneShift = int(((Matrix([[1-22,0,3]]) - Matrix([[0-5,6,13]])) * SWGliderStreamLaneChangeOfBasis)[0,0]) #544
#Cannot invert dense streams
# Blinker output means this is possibly useful for MWSS synthesis
def SparseInverterBlinkerLayer(signals):
multiplier = len(signals)
blockInputs = [(block, "Block"+str(i), 31*i, Matrix([[0,6,-2]]) + Matrix([[0,-1,-13]]) * i) for i in range(multiplier)]
signalInputs = [(SWGlider, "SWGlider"+str(i), 3 + 31*i, Matrix([[0,8,6]]) + Matrix([[0,-1,-13]]) * i) for i in range(multiplier) if signals[i]]
outputs = [(SWGlider, "SWGlider"+str(i), 22 + 31*i, Matrix([[1,0,3]]) + Matrix([[0,-1,-13]]) * i) for i in range(multiplier) if not signals[i]] + [
(blinker, "Blinker"+str(i), 42 + 31*(i-1), Matrix([[1,6,-2]]) + Matrix([[0,-1,-13]])*(i-1)) for i in range(multiplier) if signals[mod(i-1, multiplier)]]
startPat = g.parse("2b3o$2bo2bo$bo$4b2o$o3b2o$o$2bo$2b3o$3b2o$4bo$2b2o$bobo$o3bo$2b2o!")
if signals[multiplier-1]:
startPat = g.parse("3b3o$3bo2bo$2bo$5b2o$bo3b2o$bo$3bo$3b3o$4b2o$5bo$3b2o$2bobo$bo3bo$bobobo$3o$3o$3o$b2o$b2o$2b2o$6bo!",-1,0)
return PeriodicPattern(startPat, 31*multiplier, -1*multiplier, -13*multiplier, blockInputs + signalInputs, outputs)
sparseInverterBlinkerLayerLaneShift = int(((Matrix([[1-22,0,3]]) - Matrix([[0-3,8,6]])) * SWGliderStreamLaneChangeOfBasis)[0,0]) #493
#1x NE Rake
def NERakeSupport(i,j):
return CompoundPattern.chain([
(pairTrackBlockLayers[i], "BlockLayer0", "C0.SWGlider0", "C0.SWGlider0", 0),
(pairTrackRephasers[0], "Rephaser0", "C0.SWGlider0", "C0.SWGlider0", 4),
(pairTrackBlockLayers[0], "BlockLayer1", "C0.SWGlider0", "C0.SWGlider0", 1),
(pairTrackBlockLayers[j], "BlockLayer2", "C0.SWGlider0", "C0.SWGlider0", 4),
])
crawlerBlocksWithNEKickback = PeriodicPattern(g.parse("2b3o$2bo2bo$bo$4b2o$o3b2o$o$2bo$2b3o$3b2o$4bo$2b2o$bobo$o3bo$2b2o!"), 31, -1, -13,
[(block, "Block0", 0, Matrix([[0,6,-2]])),
(SWGlider, "SWGlider0", 1, Matrix([[3,10,-5]]))],
[(SWGlider, "SWGlider0", 22, Matrix([[1,0,3]])),
(NEGlider, "NEGlider0", 7, Matrix([[2,8,-3]]))])
crawlerImmediateCleanup = [PeriodicPattern([], 31,-1,-13,[
(block, "Block0", 0, Matrix([[0,0,3]])),
(SWGlider, "SWGlider0", 0, Matrix([[2*j,3,-j]]))]) for j in range(2)]
def NERake(j):
return CompoundPattern.chain([
(crawlerBlocks, "C0", "Block0", "SWGlider0", 0),
(crawlerBlocksWithNEKickback, "C1", "SWGlider0", "SWGlider0", 7),
(crawlerImmediateCleanup[j], "Cleanup", "SWGlider0", "", 1)
])
#1x SE rake
def SERakeSupport(i,j):
return CompoundPattern.chain([
(pairTrackBlockLayers[i], "BlockLayer0", "C0.SWGlider0", "C0.SWGlider0", 0),
(pairTrackBlockLayers[0], "BlockLayer1", "C0.SWGlider0", "C0.SWGlider0", 3),
(pairTrackRephasers[0], "Rephaser0", "C0.SWGlider0", "C0.SWGlider0", 4),
(pairTrackBlockLayers[0], "BlockLayer2", "C0.SWGlider0", "C0.SWGlider0", 1),
(pairTrackBlockLayers[1], "BlockLayer3", "C0.SWGlider0", "C0.SWGlider0", 4),
(pairTrackBlockLayers[j], "BlockLayer4", "C0.SWGlider0", "C0.SWGlider0", 3),
(pairTrackBlockLayers[0], "BlockLayer5", "C0.SWGlider0", "C0.SWGlider0", 3),
])
#Remark: The block pair output here actually has the correct spacing to immediately give a block-laying pair trail! I'm not sure how useful this is but it is funny.
SERakeCore = PeriodicPattern(g.parse("2b3o$2bo2bo$bo$4b2o$o3b2o$o$2bo$2b3o$3b2o$4bo!"), 31, -1, -13, [
(block, "Block0", 0, Matrix([[0,6,-2]])),
(NEGlider, "NEGlider0", 18, Matrix([[3,-4,6]]))],[
(block, "Block1", 6, Matrix([[0,3,8]])),
(block, "Block0", 25, Matrix([[0,-2,4]])),
(SEGlider, "SEGlider0", 25, Matrix([[3,0,-2]]))])
firstGliderDeletionCols = [PeriodicPattern([], 31, -1, -13, [
(block, "Block0", 0, Matrix([[0,0,2]])),
(SWGlider, "SWGlider0", 0, Matrix([[3,4,-1]]))]), crawlerImmediateCleanup[0]]
secondGliderDeletionCols = [PeriodicPattern([], 31, -1, -13, [
(block, "Block0", 0, Matrix([[0,0,4]])),
(SWGlider, "SWGlider0", 0, Matrix([[2-j,2-j,-1]]))]) for j in range(2)]
def SERake(j):
return CompoundPattern.tree([
(crawlerBlocks, "C0", True, "", "", "", 0),
(crawlerBlocksWithNEKickback, "C1", True, "SWGlider0", "C0", "SWGlider0", 7),
(crawlerImmediateCleanup[1], "C1Cleanup", True, "SWGlider0", "C1", "SWGlider0", 1),
(SERakeCore, "SERakeCore", True, "NEGlider0", "C1", "NEGlider0", 14),
(crawlerBlocks, "C2", True, "Block0", "SERakeCore", "Block0", 2),
(crawlerBlocks, "C3", True, "Block0", "SERakeCore", "Block1", 59 - 3*j),
(firstGliderDeletionCols[j], "C2Cleanup", True, "SWGlider0", "C2", "SWGlider0", 27+j),
(secondGliderDeletionCols[j], "C3Cleanup", True, "SWGlider0", "C3", "SWGlider0", 42+j)
])
#Variable lane shifter (also produces an inverted SE glider stream)
#Modified from the SE rake
def InlinePeriodMultiplyingSERakeSupport(i, j):
return CompoundPattern.chain([
(pairTrackBlockLayers[i], "BlockLayer0", "C0.SWGlider0", "C0.SWGlider0", 0),
(pairTrackBlockLayers[0], "BlockLayer1", "C0.SWGlider0", "C0.SWGlider0", 3),
(pairTrackRephasers[0], "Rephaser0", "C0.SWGlider0", "C0.SWGlider0", 4),
(pairTrackBlockLayers[0], "BlockLayer2", "C0.SWGlider0", "C0.SWGlider0", 1),
(pairTrackBlockLayers[1], "BlockLayer3", "C0.SWGlider0", "C0.SWGlider0", 4),
(pairTrackBlockLayers[j], "BlockLayer4", "C0.SWGlider0", "C0.SWGlider0", 3),
])
def InlinePeriodMultiplyingSERakeCore(laneShift, j):
return CompoundPattern.tree([
(crawlerBlocks, "C0", True, "", "", "", 0),
(crawlerBlocksWithNEKickback, "C1", True, "SWGlider0", "C0", "SWGlider0", 7),
(crawlerImmediateCleanup[1], "C1Cleanup", True, "SWGlider0", "C1", "SWGlider0", 1),
(SERakeCore, "SERakeCore", True, "NEGlider0", "C1", "NEGlider0", 14),
(crawlerBlocks, "C2", True, "Block0", "SERakeCore", "Block0", 2),
(crawlerBlocks, "C3", True, "Block0", "SERakeCore", "Block1", 60+laneShift*8),
(firstGliderDeletionCols[j], "C2Cleanup", True, "SWGlider0", "C2", "SWGlider0", 27+j)
])
def SWToNWKickback(signals):
multiplier = len(signals)
inputs = [(SWGlider, "SWGlider"+str(i), 0 + 31*i, Matrix([[3,2,3]]) + Matrix([[0,-1,-13]]) * i) for i in range(multiplier) if signals[i]] + [
(SEGlider, "SEGlider"+str(i), 0 + 31*i, Matrix([[0,0,0]]) + Matrix([[0,-1,-13]]) * i) for i in range(multiplier) if signals[i]]
outputs = [(NWGlider, "NWGlider"+str(i), 6 + 31*i, Matrix([[2,2,2]]) + Matrix([[0,-1,-13]]) * i) for i in range(multiplier) if signals[i]]
return PeriodicPattern([], 31*multiplier, -1*multiplier, -13*multiplier, inputs, outputs)
#TODO: Could be helpful to allow more deletion collisions here
def InlinePeriodMultiplyingSERakeGliderTerminator(signals):
multiplier = len(signals)
inputs = [(SWGlider, "SWGlider"+str(i), 0 + 31*i, Matrix([[2,1,-1]]) + Matrix([[0,-1,-13]]) * i) for i in range(multiplier) if signals[i]] + [
(NWGlider, "NWGlider"+str(i), 0 + 31*i, Matrix([[0,0,4]]) + Matrix([[0,-1,-13]]) * i) for i in range(multiplier) if signals[i]]
return PeriodicPattern([], 31*multiplier, -1*multiplier, -13*multiplier, inputs, [])
def InlinePeriodMultiplyingSERake(signals, laneShift, j):
multiplier = len(signals)
firstSignal = signals.index(True)
SERake = PeriodMultipliedPattern(InlinePeriodMultiplyingSERakeCore(laneShift, j), multiplier)
return CompoundPattern.chain([
(SERake, "SERake", "Instance0.SERakeCore.Block0", "Instance0.SERakeCore.SEGlider0", 0),
(SWToNWKickback(signals), "KB0", "SEGlider"+str(firstSignal), "NWGlider"+str(firstSignal), laneShift+15),
(InlinePeriodMultiplyingSERakeGliderTerminator(signals), "T0", "NWGlider"+str(firstSignal), "", laneShift+30)
])
NLWSSSynth16X = PeriodicPattern([], 31*16, -1*16, -13*16,[
(block, "Block0", 0, Matrix([[0,4,4]])),
(SEGlider, "SEGlider0", 0, Matrix([[3,2,-1]])),
(NEGlider, "NEGlider0", 0, Matrix([[0,0,6]]))
],[
(NLWSS, "NLWSS0", 3, Matrix([[3,4,2]]))
])
#NLWSSSynth16X.placeWithInputs(Matrix([[0,0,0]]), 16, 16)
signalsSparse = [i == 0 for i in range(16)]
signalsDense = [i != 0 for i in range(16)]
#g.warn(str(set(InlinePeriodMultiplyingSERake(signalsDense, 0, 0).outputNamesToIndexes)))
def NEGliderFilterTerminator(signals):
multiplier = len(signals)
inputs = [(SEGlider, "SEGlider"+str(i), 0 + 31*i, Matrix([[0,0,0]]) + Matrix([[0,-1,-13]]) * i) for i in range(multiplier) if signals[i]] + [
(NEGlider, "NEGlider"+str(i), 0 + 31*i, Matrix([[2,1,5]]) + Matrix([[0,-1,-13]]) * i) for i in range(multiplier) if signals[i]]
return PeriodicPattern([], 31*multiplier, -1*multiplier, -13*multiplier, inputs, [])
pat = CompoundPattern.findPositiveSolution([(NLWSSSynth16X,"LWSSSynth0"),
(InverterBlockLayer(signalsSparse),"BlockLayer0"),
(InlinePeriodMultiplyingSERake(signalsDense, 0, 0), "SERake0"),
(InlinePeriodMultiplyingSERake(signalsSparse, 0, 0), "SERake1"),
(PeriodMultipliedPattern(NERake(0), 16), "NERake0"),
(NEGliderFilterTerminator(signalsDense), "NERakeFilter")],
[("BlockLayer0","Block0","LWSSSynth0","Block0",0),
("SERake0", "SERake.Instance15.SERakeCore.SEGlider0", "LWSSSynth0", "SEGlider0",0),
("BlockLayer0","SWGlider1","SERake0","KB0.SWGlider1",0),
("SERake0", "SERake.Instance4.C3.SWGlider0", "SERake1", "KB0.SWGlider0",0),
("NERake0","Instance0.C1.NEGlider0","LWSSSynth0","NEGlider0",0),
("SERake1","SERake.Instance1.SERakeCore.SEGlider0","NERakeFilter","SEGlider1",0),
("NERake0","Instance1.C1.NEGlider0","NERakeFilter","NEGlider1",300)])
pat.placeWithInputs(Matrix([[0,0,0]]), 32, 32)EDIT: Improved the above script, it is now a. somewhat faster and b. automatically finds the minimal spacings with significantly less input required.
Nora Brown
Re: 13131: The B-Heptomino/Glider Spaceship Thread
It works with the glider one phase further forward. Known?
Code: Select all
x = 9, y = 12, rule = DoubleB3S23
7.BA$6.CA$6.B2C7$.C$3C$C.2C!