Python Questions

For scripts to aid with computation or simulation in cellular automata.
User avatar
The Turtle
Posts: 102
Joined: May 6th, 2015, 8:14 pm
Location: Chicago, Illinois

Python Questions

Post by The Turtle » June 23rd, 2015, 2:51 pm

I'm starting this thread for people who are learning Python (like me) and have questions about Python or Golly, as suggested by dvgrn at http://conwaylife.com/forums/viewtopic.php?f=2&t=1694.
For example: (these are my questions)

1. How can I reduce the time it takes to run a script just by modifying my code? (like without using downloadable programs to aid)

2. I'm pretty sure someone wrote a program to do this. How can I detect an escaping glider from a pattern? (and ensure the glider cannot interfere with the rest of the pattern)

3. Can the keyword "with" be used without files or the like? If so, how?

4. Something weird is happening with some of my functions. For example:

Code: Select all

def change_element(list, index, new_element):
	list[index] = new_element
	return list

example_list = [1, 2, 3]
print example_list
print change_element(example_list, 2, 4)
print example_list
Why does my function modify the list (array?) when I run the function? Shouldn't it only change the argument, not the variable? This doesn't happen with numbers. For example:

Code: Select all

def change_number(number, new_number):
	number = new_number
	return number
example_number = 1
print example_number
print change_number(example_number, 2)
print example_number
Answer: (answered by A for awesome and dvgrn)
Python (and other languages) do this because lists could be very large and copying lists could be expensive.
Here is a workaround:

Code: Select all

def change_element(list, index, new_element):
	list_copy = list[:]
	list_copy [index] = new_element
	return list_copy

example_list = [1, 2, 3]
print example_list
print change_element(example_list, 2, 4)
print example_list
The crucial line is "list_copy = list[:]". (I shouldn't use list as variable name)
list[:] (I think) is interpreted as list[0:len(list)].

5. What does foo and bar mean and why are they used?

Answer: (answered by dvgrn)
"foo" and "bar" are placeholder names for programming examples. The names originated from the 1930's, meaning "nonsense". The name was adopted to programming in the 1960's.

6. Why does raw_input() not work when running a script in Golly? How would you get a user's input?
Last edited by The Turtle on June 25th, 2015, 2:15 pm, edited 2 times in total.
Only two things are constant: change and the speed of light.

User avatar
A for awesome
Posts: 2049
Joined: September 13th, 2014, 5:36 pm
Location: 0x-1
Contact:

Re: Python Questions

Post by A for awesome » June 23rd, 2015, 7:26 pm

The Turtle wrote: 4. Something weird is happening with some of my functions. For example:

Code: Select all

code
I don't know Python, but I've encountered the same problem in JavaScript and the reason is that when you assign an object to a variable, the new variable is not a copy of the old object, but is actually a reference to the same object in memory.
x₁=ηx
V ⃰_η=c²√(Λη)
K=(Λu²)/2
Pₐ=1−1/(∫^∞_t₀(p(t)ˡ⁽ᵗ⁾)dt)

$$x_1=\eta x$$
$$V^*_\eta=c^2\sqrt{\Lambda\eta}$$
$$K=\frac{\Lambda u^2}2$$
$$P_a=1-\frac1{\int^\infty_{t_0}p(t)^{l(t)}dt}$$

http://conwaylife.com/wiki/A_for_all

Aidan F. Pierce

User avatar
The Turtle
Posts: 102
Joined: May 6th, 2015, 8:14 pm
Location: Chicago, Illinois

Re: Python Questions

Post by The Turtle » June 23rd, 2015, 7:49 pm

A for awesome wrote:
The Turtle wrote: 4. Something weird is happening with some of my functions. For example:

Code: Select all

code
I don't know Python, but I've encountered the same problem in JavaScript and the reason is that when you assign an object to a variable, the new variable is not a copy of the old object, but is actually a reference to the same object in memory.
Is there a fix for this? A workaround?
Why does Python do this?

By the way, Python is great. It is a lot easier to code than JavaScript (the only other language I know).
Only two things are constant: change and the speed of light.

User avatar
dvgrn
Moderator
Posts: 6739
Joined: May 17th, 2009, 11:00 pm
Location: Madison, WI
Contact:

Re: Python Questions

Post by dvgrn » June 23rd, 2015, 8:49 pm

The Turtle wrote:Is there a fix for this? A workaround?
Why does Python do this?
Annoying, isn't it? This is definitely one of the more common pain points, in quite a number of languages, not just Python. The reason is that lists are really useful, but they can also be really really big. Passing a pointer to a list is really fast and easy, but making and passing a copy of a [maybe multi-megabyte or even multi-gigabyte] list can get _very_ inefficient, especially if all you want to do is look up a few values in it and not change anything.

Try the code below instead. You can File > Run Clipboard directly in Golly, and it should also answer your question about what the equivalent of a "print" statement is. There's also g.show() and g.warn(), not to mention "make_text" in the glife module, if you want text to show up as part of the actual Life universe.

I changed "list" to "numlist" in the function, because "list(name_of_list)" also has a meaning in Python, as the link in the code explains. Could be confusing, though it doesn't actually cause any syntax errors or anything.

Code: Select all

import golly as g

def change_element(numlist, index, new_element):
#  newlist=numlist     #### if you set one list equal to another, or pass a list into a function,
                    ####   then both old and new lists point to the same object in memory
   newlist=numlist[:]  #### this creates a copy of the elements in the list
                    ####   list[:2] would be the first two elements,
                    ####   list[1:] would be the last two elements,
                    ####   list[:-1] would be all elements but the last one
                    ####   list[1::2] would be only the even elements
                    ####   list[::2] would be only the odd elements... etc.
                    ####   Look up "slices" on python.org; see also
                    ####   http://stackoverflow.com/questions/8744113/python-list-by-value-not-by-reference
   newlist[index] = new_element
   return newlist

example_list = [1, 2, 3]
g.note(str(example_list) + "\n"
     + str(change_element(example_list, 2, 4)) + "\n"
     + str(example_list))
EDIT: Or the minimal change from the original code:

Code: Select all

print change_element(example_list[:], 2, 4)
The Turtle wrote:By the way, Python is great. It is a lot easier to code than JavaScript (the only other language I know).
That matches my experience with Python. I've had a surprising number of cases where the very first thing I tried worked perfectly, even though I was thinking, "it _can't_ be this easy". But it was. I don't remember that happening nearly as often in other languages. It keeps getting easier with more practice, too, which is really nice.

-- Ah, and the user-input question: use g.getstring() instead of raw_input().

Another thing to try is to right-click on some of Golly's included Python scripts -- pop-plot.py, for example, uses both g.getstring() and the make_text function. Most of the sample scripts are fairly readable, and will give you lots of good clues about how to do things in the context of Golly.

User avatar
dvgrn
Moderator
Posts: 6739
Joined: May 17th, 2009, 11:00 pm
Location: Madison, WI
Contact:

Re: Python Questions

Post by dvgrn » June 24th, 2015, 10:47 pm

The Turtle wrote:1. How can I reduce the time it takes to run a script just by modifying my code? (like without using downloadable programs to aid)
In general, find ways that Python can do the same work more efficiently. There are a lot of online resources about this, but of course it's very very specific to your particular code, so I don't have any better general answer than this.
The Turtle wrote:2. I'm pretty sure someone wrote a program to do this. How can I detect an escaping glider from a pattern (and ensure the glider cannot interfere with the rest of the pattern)
There are lots of ways, and different ways are better for specific cases.

For example, if you can afford to wait a long time, just advance the pattern several thousand ticks (let's say), then write code to check whether the bounding box is increasing linearly. If only one glider has escaped, you can look in the corners of the bounding box... otherwise you might have to search along the edges, which would take a little longer.

You could also run several different orientations of the pattern, and check whether the first cell in the cell list is attached to something glider-shaped. If you then run a little farther and it behaves like a glider (same shape after four ticks) then the odds are overwhelmingly good that it is a glider and can be removed.

It takes a little more work to figure out exactly when you can safely remove it, but you can start back at the original pattern and run it forward, looking in the appropriate spot along the line where you now know the glider is going to be.

Can you be more specific about what kind of pattern you want to catch and remove gliders from?
The Turtle wrote:5. What does foo and bar mean and why are they used?
Wikipedia can tell you that, but maybe a link or two to the Jargon Files would also be appropriate.

User avatar
The Turtle
Posts: 102
Joined: May 6th, 2015, 8:14 pm
Location: Chicago, Illinois

Re: Python Questions

Post by The Turtle » June 25th, 2015, 2:17 pm

More questions:
1. What is the module glife?
2. Is make_text from glife?
Only two things are constant: change and the speed of light.

User avatar
dvgrn
Moderator
Posts: 6739
Joined: May 17th, 2009, 11:00 pm
Location: Madison, WI
Contact:

Re: Python Questions

Post by dvgrn » June 25th, 2015, 3:14 pm

The Turtle wrote:More questions:
1. What is the module glife?
2. Is make_text from glife?
Good questions. The glife module is definitely a little mysterious at first.

1) See this section in Golly Help for a brief introduction.

2) Yes. You can import make_text if you want to use just that function -- see pop-plot.py for sample code.

I used to use glife a lot, but it got to be a bother -- there are a dozen things that you have to remember to do in a slightly different way in your Python code, depending on whether or not you're using a glife "pattern" data type or just a plain cell list. You use put() instead of g.putcells(), pattern() instead of g.parse(), and so on.

And glife's "rect" data type has properties that aren't available when you're just dealing with a plain rectangle list from golly.getrect() or golly.getselrect(). Have a look at oscar.py, for example:

Code: Select all

    prect = g.getrect()
    pbox = rect(prect)
    if pbox.empty:
        g.show("The pattern is empty.")
        return True
You can't check "prect.empty" because plain four-item lists don't have the "empty" property. The glife module also adds x, y, left, right, top, bottom, width, height, and visible properties to its rect objects.

With a glife "pattern" object, you can calculate and refer to different generations of patterns using Python's array syntax. This can be pretty handy once you get used to it. If you've used a subscript like "blinker[1]" once -- or something like "cordership[90]" would be a more useful example -- the glife module caches the resulting pattern in a __phases dictionary. Golly can use it again later in the script without re-doing the calculation. The glife module even knows when it's calculating "cordership[95]" to just start at "cordership[90]" and run five ticks, instead of starting over at zero.

The glife Help documentation was actually written fairly early on; nowadays, for simple uses, glife isn't really very much more concise than regular Golly Python. E.g., the examples given don't really need all the "0, 0" translation or "1, 0, 0, 1" affine transformation numbers -- "0, 0, 1, 0, 0, 1" is assumed as the default now, so the following is OK even without importing glife:

Code: Select all

blinker = g.parse("3o!")
g.putcells(blinker, 1, 2)
Even so, I probably should still be using glife, and remembering to take advantage of its more advanced features -- but usually in my scripts it would only save me a few characters of typing here and there.

User avatar
The Turtle
Posts: 102
Joined: May 6th, 2015, 8:14 pm
Location: Chicago, Illinois

Re: Python Questions

Post by The Turtle » June 26th, 2015, 8:43 pm

The below code prints [1, 0].

Code: Select all

var = [1]
var.append(0)
print var
This code prints None.

Code: Select all

var = [1].append(0)
print var
Why?

Answer:
append() does not return anything. It's a function that returns None.
Last edited by The Turtle on June 27th, 2015, 9:07 am, edited 1 time in total.
Only two things are constant: change and the speed of light.

User avatar
The Turtle
Posts: 102
Joined: May 6th, 2015, 8:14 pm
Location: Chicago, Illinois

Re: Python Questions

Post by The Turtle » June 26th, 2015, 8:55 pm

About the glider removal question:
Can you remove gliders based on this? (attached)
Are there some drawbacks of using this method for removing spaceships?
(It's messy writing on a computer)
Attachments
Glider Zones (and other spaceships)
Glider Zones (and other spaceships)
Glider_Zone.png (39.64 KiB) Viewed 19688 times
Only two things are constant: change and the speed of light.

User avatar
Kiran
Posts: 285
Joined: March 4th, 2015, 6:48 pm

Re: Python Questions

Post by Kiran » June 26th, 2015, 11:35 pm

?
Kiran Linsuain

chris_c
Posts: 953
Joined: June 28th, 2014, 7:15 am

Re: Python Questions

Post by chris_c » June 27th, 2015, 6:56 am

The Turtle wrote:The below code prints [1, 0].

Code: Select all

var = [1]
var.append(0)
print var
This code prints None.

Code: Select all

var = [1].append(0)
print var
Why?
Because "append" is a function that appends data to a list but has no return value itself. Here is a similar example:

Code: Select all

def my_function():
    return
var = my_function()
print var
Alternatively you could try:

Code: Select all

var = [1] + [0]
print var

User avatar
The Turtle
Posts: 102
Joined: May 6th, 2015, 8:14 pm
Location: Chicago, Illinois

Re: Python Questions

Post by The Turtle » June 27th, 2015, 9:13 am

Kiran wrote:?
Sorry. I forgot to clarify the picture.
The middle squiggle is the pattern. The dotted lines are moving spaceships, which are labeled as Glider or LWSS.
The thin black lines are the boundary between glider removal zones. The thin red lines are the boundary between LWSS removal zones.
The question is:
Let's say I'm running a pattern in a script. Can I remove spaceships that are emitted from the pattern safely based on these removal zones?
Only two things are constant: change and the speed of light.

User avatar
Kiran
Posts: 285
Joined: March 4th, 2015, 6:48 pm

Re: Python Questions

Post by Kiran » June 27th, 2015, 12:35 pm

What exactly do you mean with "safe zones," "danger zones" and "removal zones?"
Kiran Linsuain

User avatar
The Turtle
Posts: 102
Joined: May 6th, 2015, 8:14 pm
Location: Chicago, Illinois

Re: Python Questions

Post by The Turtle » June 27th, 2015, 12:47 pm

A safe-to-remove zone is a zone where a spaceship can be removed without interfering with the rest of the pattern.
A danger zone is a zone where a spaceship might change the rest of the pattern when the spaceship is removed.
Only two things are constant: change and the speed of light.

User avatar
dvgrn
Moderator
Posts: 6739
Joined: May 17th, 2009, 11:00 pm
Location: Madison, WI
Contact:

Re: Python Questions

Post by dvgrn » June 27th, 2015, 6:46 pm

The Turtle wrote:About the glider removal question:
Can you remove gliders based on this? (attached)
Sure. There are definitely safe zones where you know that a glider or spaceship can no longer possibly affect the reaction it has left behind.

It's a little tricky to define mathematically the exact boundaries of those safe zones, though. For example, you have to account for the fact that a pattern inside an MxN bounding box can theoretically send out waves that move at light speed for up to M/2 or N/2 ticks:

Code: Select all

x = 60, y = 31, rule = B3/S23
14b31o$14b31o$14b31o$14b31o$14b31o$14b31o$14b31o$14b31o$14b31o$14b31o$
14b31o$14b31o$14b31o$2b2o10b31o$b4o9b31o$2ob2o9b31o$b2o11b31o$14b31o$
14b31o$14b31o12b3o$14b31o14bo$14b31o13bo$14b31o$14b31o$14b31o$14b31o$
14b31o$14b31o$14b31o$14b31o$14b31o!
The Turtle wrote:Are there some drawbacks of using this method for removing spaceships?
Just the complexity of watching an active pattern, recognizing gliders and spaceships, and tracking them as they cross that safe-zone boundary. The funny thing about Golly is that for most purposes you can write much simpler code, and it will be just about as efficient.

Among other things, a pattern runs much more quickly in Golly once it has stabilized, especially in Hashlife -- though it usually runs faster in Quicklife before it stabilizes. So if you just want the stabilized part of a methuselah, let's say, and want to discard the gliders, it's fairly efficient to do something like this:

1) Run 2^10 ticks.
2) Check if the pattern has stabilized. If not, go to step 1, until you've passed some reasonable limit like 2^18. (In that case, which will be relatively rare, you probably have a switch engine, or maybe something more interesting.)
3) Note the bounding box of the pattern.
4) Run 2^20 ticks.
5) Copy out the part of the pattern inside the bounding box from step 3. All the gliders and spaceships will be safely somewhere else.

Then if you want to know what gliders and spaceships were generated, you can do pattern-matching on all the cells outside that bounding box, and you'll know everything about them. You could re-run the pattern and see where each one first appeared, if you wanted to. All of this can be done with much less code, and in about the same amount of time, as a script that worries about eight different safe zones and analyzes every generation of an evolving pattern.

Another possibility: the apgsearch Python script that feeds the Catagolue project does a fairly efficient job of recognizing when patterns have stabilized, so with a little work you could just borrow some code from that script. Depends on how much you want to know about the escaping gliders and spaceships -- if their exact location matters, it might be simpler to write your own code. Also, glider- and object-recognition code has been posted here and there on various forum threads over the years, so let me know if you want another sample-code link or two.

About the appending-to-a-list question, in case it's not completely clear:
chris_c wrote:Because "append" is a function that appends data to a list but has no return value itself.
Here's one more sample:

Code: Select all

var1 = [1]
var2=var1.append(0)
print var1
print var2
When Python executes "[1].append(0)" in your original example, it briefly produces a new extended list [1,0]... but the list that got modified wasn't ever stored in a variable, so it gets discarded, and the variable (originally "var", now "var2") just gets the nonexistent return value from the append operation.

User avatar
The Turtle
Posts: 102
Joined: May 6th, 2015, 8:14 pm
Location: Chicago, Illinois

Re: Python Questions

Post by The Turtle » June 28th, 2015, 5:55 pm

How does apgsearch remove gliders?
It is efficient?
Only two things are constant: change and the speed of light.

User avatar
dvgrn
Moderator
Posts: 6739
Joined: May 17th, 2009, 11:00 pm
Location: Madison, WI
Contact:

Re: Python Questions

Post by dvgrn » June 28th, 2015, 10:05 pm

The Turtle wrote:How does apgsearch remove gliders?
It is efficient?
Incredibly efficient -- but it only lets you retain information about how many gliders there are, not where they are. And the trick doesn't work on spaceships.

The big insight for apgsearch was that it was possible to define custom rules that would effectively allow all the most common Life objects to be counted and removed automatically. No matter where gliders are or how many there are, one custom rule evolves them into a cell with a particular state, and another custom rule removes cells with that state.

(I may have something not quite exactly right, but this is definitely the general idea.)

If you've been running apgsearch, you'll probably have the rules installed in Golly's root directory: APG_CoalesceObjects, APG_IdentifyGliders, APG_ClassifyObjects, and APG_ExpungeGliders.rule are the relevant ones for your question.

You have to run the pattern in APG_CoalesceObjects first. Then run the result in the APG_IdentifyGliders rule for two ticks, then run that result in APG_ClassifyObjects for a few ticks -- has to be more than the highest-period oscillator in your pattern, I think.

Finally you're supposed to be able to run the pattern in the APG_ExpungeGliders rule for two more ticks, and all the gliders will be gone. I had trouble getting this rule to do anything when I tried it just now -- probably I missed a step somewhere. A close reading of apgsearch code would find the problem.

Anyway, if you only want to remove gliders, it's definitely possible to adapt this idea and come up with a single rule that would remove all the isolated gliders in, say, ten or a dozen generations, without damaging anything else. If you tried to use apgsearch rules, you'd probably have to set up yet another another rule to get the rest of your original pattern back into two-state form...!

wildmyron
Posts: 1402
Joined: August 9th, 2013, 12:45 am

Re: Python Questions

Post by wildmyron » June 28th, 2015, 11:47 pm

dvgrn wrote:
The Turtle wrote:How does apgsearch remove gliders?
It is efficient?
Incredibly efficient -- but it only lets you retain information about how many gliders there are, not where they are. And the trick doesn't work on spaceships.
APG_IdentifyGliders actually works quite well without running APG_CoalesceObjects first, nor is APG_ClassifyObjects needed. To use:
* Optionally, run APG_CoalesceObjects_B3S23 for longer than the period of the highest period object
* Run APG_IdentifyGliders for four ticks
* Run APG_ExpungeGliders for two ticks and record population after each tick (pop1 and pop2)
* # Gliders removed = (pop2 - pop1) / 5

This will leave the universe with three states [Vacuum, On, Off] and you can switch back to APG_CoalesceObjects_B3S23 and continue running the pattern, or as dvgrn mentioned: use another rule to convert back to two state Life (change state 2 to state 0).

In addition to not having any other information about where the gliders were, apgsearch does not check if gliders will interact with the rest of the pattern before removing them.

The other script to look at which tests for stability and is more rigorous about testing for future interaction is NickGotts' testquiescence

Edited for punctuation
Last edited by wildmyron on June 29th, 2015, 4:05 am, edited 2 times in total.
The latest version of the 5S Project contains over 226,000 spaceships. There is also a GitHub mirror of the collection. Tabulated pages up to period 160 (out of date) are available on the LifeWiki.

User avatar
calcyman
Posts: 2203
Joined: June 1st, 2009, 4:32 pm

Re: Python Questions

Post by calcyman » June 29th, 2015, 2:27 am

APG_IdentifyGliders actually works quite well without running APG_CoalesceObjects first
It has the drawback that it could remove gliders from within a larger oscillator (for instance a loop of glider reflectors, or a gun+eater combination). If you run the rules in the correct order, then this cannot happen:
  • Run APG_CoalesceObjects_B3S23 until stabilisation;
  • Run APG_IdentifyGliders for four ticks;
  • Run APG_ClassifyObjects_B3S23 until stabilisation;
  • Run APG_ExpungeGliders for two ticks, noting the population as wildmyron mentioned.
Try it on the following pattern from Golly's pattern library:

Code: Select all

x = 420, y = 141, rule = B3/S23
41bob2o84b2obo75bob2o96b2obo77b2o5bob2o$41b2obo84bob2o75b2obo96bob2o
78bo5b2obo$39b2o86b2o83b2o92b2o4b2o75bo4b2o$40bo86bo85bo92bo5bo76b2o4b
o$39bo88bo83bo94bo5bo80bo$39b2o86b2o83b2o92b2o4b2o75b2o3b2o$41bob2o84b
2obo77b2o96b2obo78bo5bob2o$41b2obo84bob2o78bo96bob2o77bo6b2obo$45b2o
80b2o4b2o75bo95b2o4b2o75b2o9b2o$46bo80bo5bo76b2o94bo5bo88bo$45bo82bo5b
o73b2o97bo5bo75b2o9bo$45b2o80b2o4b2o74bo96b2o4b2o76bo9b2o$41bob2o84b2o
bo75bo99b2obo77bo6bob2o$41b2obo84bob2o75b2o98bob2o77b2o5b2obo7$216b2o$
215bo2bo$215bobo3bo$216bob6o101b3o$218bo5bo100b3o$216bo2b4obo89bo10b3o
$127bo88b2obobobo90b3o5b3o$46b2o79b3o10b2o77bobo95bo4b3o$45bo2bo81bo8b
o2bo73b2obob2o93b2o4b3o78b2o6b2o$40b2o2bob2obo79b2o8bobobo73bo5bo93b2o
83bo2bo4bo2bo$40bo3bo2bobo88b2obobo61bo9bo2bobobo2bo82bo9b2o82bo2bo4bo
2bo$41b3obo3b2o81bo3bo3bobob2o59b3o7b2obobobob2o81b3o8b3o72bo8bo2bo4bo
2bo$43bo3bo2bo80bobo2bob2o2bo2bo62bo8bo4bobo81bob3o3b2o77b3o7b2o6b2o$
44bob4o77b2o2b2o3bo4bobobob2o42b2o14b2o8bobob2obo71bo8bo3bo4bo2bo78bo$
46bo80b2o9b2obo2b2o2bo36b2o5b3o21b2obo3bo72b3o5bo3bo9bo76b2o$34b2o11b
3o2b2o59b2o24bo2bo3b2o36bo2bo2bo4bo14bo8b4o76bo3b3obo7bo4bo85bo2bo$34b
o8bob3o2bo2bo59bobo14bo8bob2ob2o38bobo2bob4obob2o9bobob2o2b2o79b2o4b3o
9bo3bo77bo5b3o2b3o$37b2o5b2o3b2obo62bo14b2o8bo4bo37b2ob4o4bobobo6b2o2b
2o8b4o82bo13b2o52b3o21bobo3bo8bo$36b3o5b2o5bob3o55b4ob2o2b2o7bobo9b4o
39bobo4b2o3bobo6b2o9b2obo2bo78bo71b3o5bo11b2o2b2o5b2o4b2o$36b3o2b2o8bo
4bo54bo4bobo2bo21bo40bob4o4b3ob2ob2o14bo82bobo71bo5bobo10b2o10bo4bo$
36bo4b2o7b2ob2ob3o50b2o2bo2bob2o25bo36bob2o5b2o4bo4bo14bobo76b2o2b2o
72bo4bo3bo$36b2o12bo2bobo3bo48bo2b2o3bobo19bo5b2o35bobo3bob2o2b3obob3o
16b2o76b2o13b2o61bo4bobobo$44bo6bo5bo2bo46bob2o2bob2obo17bobo42bo2bob
2obo2bo2bo3bo112b2o59bobo19b2o$43bobo5b2o3b3obo46bo4bo4bo19b2o43b2o7b
2o118bo16bo67b2o$39b2o2b2o5bo2b3o4bobo45b3obob3o80bo6b2o120bobo66bo$
39b2o10bobobo2b2ob2o47b5o82bo7b2o97bo22b2o44bobo27bo$50bo2bobo3bo144bo
11bo79bo8bo68bo4bobobo20bo4b2o5b2o$51b2o2bobobo89b2o5b2o39bo19b2o77b2o
5b3o68bo4bo3bo18b3o4b2o5bo$52bobobobo59bo30b2o5bo39bobo17b2o77bobo76bo
5bobo31bobo$52bobo2bo60b2o34bobo40b2o73b2o99b3o5bo6bo25b2o$53b2o57bo4b
obo34b2o37b2o106b2o70b3o12b2o20b2o$49bo61bobo36b2o40bobo32b2o5b2o34bo
3bo26b2o2b2o29bo4b2o5b2o37bobo20bobo$17b2o31bo61b2o36bobo39bo5b2o27b2o
5bo35bo4bo29bobo26bobo4b2o5bo32bo29bo$18bo29b3o57b2o34bobo4bo39b2o5b2o
32bobo37bobobo29bo2b2o24b2o9bobo31bobo20bobo$15b3o89bobo34b2o86b2o39bo
bobo10bo57b2o33b2o20b2o12b3o$14bo3b3o86bo5b2o30bo82b2o44bo4bo8b2o13b2o
2bo3bo30b2o33b2o25bo6bo5b3o$13bo2bobo2bo84b2o5b2o94b2o17bobo44bo3bo7bo
bo14bo2bo4bo29bobo31bobo31bobo5bo$13bob2o3bobo185b2o19bo71b3o5bobobo8b
o20bo2b2o28bo5b2o4b3o18bo3bo4bo$12b2o2bo4bo127b5o56bo11bo53b2o2bo20bo
8bobobo5b3o52b2o5b2o4bo20bobobo4bo$11bo2bo2b4o126b3obob3o64b2o7bo49bob
o29bo4bo2bo14bobo7bo3bo40bo27bobo$11bobo3bo3b3o101b2o19bo4bo4bo64b2o6b
o50b2o30bo3bo2b2o13b2o8bo4bo47bo$8b2obob2o2b3o3bo54b2o45bobo17bob2obo
2b2obo77b2o7b2o31b2o57bo10bobobo44b2o$8bobo5bo3b3o56bo38b2o5bo19bobo3b
2o2bo71bo3bo2bo2bob2obo2bo29bobo9b2o24b2o2bo29bobobo44b2o19bobo$11b3ob
2obobo52b4o41bo25b2obo2bo2b2o52b2o16b3obob3o2b2obo3bobo29bo5b2o4bobo
26bobo29bo4bo55bobobo4bo$4b2o3b2o2b2o2bobo5b2o46bob3o42bo21bo2bobo4bo
54bobo14bo4bo4b2o5b2obo29b2o5b2o4bo29b2o2b2o26bo3bo55bo3bo4bo$2b3obobo
bo13bobo48b3o41b4o9bobo7b2o2b2ob4o56bo14b2ob2ob3o4b4obo78b2o59bo4bo10b
2o10bobo5bo$bo4bobo17bo42b2o47bo4bo8b2o14bo55bo2bob2o9b2o6bobo3b2o4bob
o107b2o29b2o4b2o5b2o2b2o11bo5b3o$ob2ob2ob2o59b2o13b2o32b2ob2obo8bo14bo
bo53b4o8b2o2b2o6bobobo4b4ob2o82bobo51bo8bo3bobo21b3o$obo3b2obo64b2o7bo
bo30b2o3bo2bo24b2o57b2o2b2obobo9b2obob4obo2bobo75b3o5b2o53b3o2b3o5bo$b
o2bo4b3o4bo50bo6b2o7bo31bo2b2o2bob2o9b2o67b4o8bo14bo4bo2bo2bo75bo8bo
55bo2bo$2b2o2bo3b2o3bobo2b2o43bobo2b2o6bo3b2o31b2obobobo4bo3b2o2b2o66b
o3bob2o21b3o5b2o53b2o22bo76b2o$4b2o3bo6b2o2bobo43b2o2bobo3b2o3bo2b2o
32bo2bo2b2obo2bobo69bob2obobo8b2o14b2o59bobo98bo$4bo7b2o6bo50bo4b3o4bo
2bo31b2obobo3bo3bo70bobo4bo8bo76bo16bo67b2o6b2o7b3o$2bobo7b2o64bob2o3b
obo32bobob2o75b2obobobob2o7b3o88b2o67bo2bo4bo2bo8bo$2b2o13b2o59b2ob2ob
2obo32bobobo8b2o66bo2bobobo2bo9bo89b2o13b2o51bo2bo4bo2bo$17b2o42bo17bo
bo4bo34bo2bo8bo69bo5bo112b2o2b2o51bo2bo4bo2bo$10b3o48bobo13bobobob3o
36b2o10b3o67b2obob2o110bobo56b2o6b2o$10b3obo46b2o5bobo2b2o2b2o3b2o52bo
68bobo114bo$11b4o52bobob2ob3o126bobobob2o92b2o13bo$8bo56b3o3bo5bobo
122bob4o2bo92bo3bo9b3o4b2o$8b2o54bo3b3o2b2obob2o122bo5bo94bo4bo7bob3o
3bo$64b3o3bo3bobo126b6obo94bo9bo3bo5b3o$67b4o2bo2bo128bo3bobo94bo2bo4b
o3bo8bo$66bo4bo2b2o132bo2bo96b2o3b3obo$65bobo3b2obo134b2o92b3o8b3o$66b
o2bobo2bo229b2o9bo$67b3o3bo231b2o$70b3o226b3o4b2o$37b3o29bo229b3o4bo$
37bo31b2o56bo12b2o157b3o5b3o$38bo88b3o9bo2bo153b3o10bo$33b2o95bo8bobob
o152b3o$30bo2bobo93b2o7b2obobo152b3o$29bobobobo100bo3bobob2o$28bobobo
2b2o95bo3bob2o2bo2bo$28bo3bobo2bo93bobo2bo4bobobob2o$25b2ob2o2bobobo
10b2o78b2o2b2o5b2obo2b2o2bo$25bobo4b3o2bo5b2o2b2o78b2o10bo2bo3b2o$27bo
b3o3b2o5bobo67b2o25bob2ob2o$27bo2bo5bo6bo68bobo15bo9bo4bo$28bo3bobo2bo
12b2o62bo15b2o9b4o$29b3ob2ob2o7b2o4bo58b4ob2o2b2o8bobo11bo$31bo4bo8b2o
2b3o58bo4bobo2bo24bo$32b3obo5b2o5b3o56b2o2bo2bob2o25b2o$35bob2o3b2o5b
2o56bo2b2o3bobo20bo$34bo2bo2b3obo8bo52bob2o2bob2obo18bobo$34b2o2b3o11b
2o52bo4bo4bo20b2o$41bo65b3obob3o$38b4obo65b5o$37bo2bo3bo$37b2o3bob3o
102b2o5b2o$38bobo2bo3bo70bo30b2o5bo$38bob2obo2b2o70b2o34bobo$39bo2bo
69bo4bobo34b2o$40b2o69bobo36b2o$112b2o36bobo$108b2o34bobo4bo$107bobo
34b2o$107bo5b2o30bo$106b2o5b2o2$150b5o$148b3obob3o$125b2o20bo4bo4bo$
125bobo18bob2obo2b2obo$125bo20bobo3b2o2bo$118b2o25b2obo2bo2b2o$118bo
24bo2bobo4bo$120bo11bobo8b2o2b2ob4o$119b4o9b2o15bo$118bo4bo9bo15bobo$
118b2ob2obo25b2o$116b2o3bo2bo10b2o$115bo2b2o2bob2o5b2o2b2o$115b2obobob
o4bo2bobo$118bo2bo2b2obo3bo$118b2obobo3bo$120bobob2o7b2o$120bobobo8bo$
121bo2bo9b3o$122b2o12bo!
So when you say:
apgsearch does not check if gliders will interact with the rest of the pattern before removing them.
it actually does, by taking running APG_CoalesceObjects_B3S23 before identifying gliders.
What do you do with ill crystallographers? Take them to the mono-clinic!

wildmyron
Posts: 1402
Joined: August 9th, 2013, 12:45 am

Re: Python Questions

Post by wildmyron » June 29th, 2015, 4:01 am

calcyman wrote:
wildmyron wrote:APG_IdentifyGliders actually works quite well without running APG_CoalesceObjects first
It has the drawback that it could remove gliders from within a larger oscillator (for instance a loop of glider reflectors, or a gun+eater combination). If you run the rules in the correct order, then this cannot happen:
My apologies, I neglected to consider this case in my explanation above.
calcyman wrote:So when you say:
wildmyron wrote:apgsearch does not check if gliders will interact with the rest of the pattern before removing them.
it actually does, by taking running APG_CoalesceObjects_B3S23 before identifying gliders.
Indeed, it does in that case. What I meant to say is that in the event that the pattern has not stabilised (as unlikely as that is) any gliders which are not part of oscillators as noted above but will interact with the rest of the pattern at some point in the future (beyond the time for which APG_CoalesceObjects_B3S23 is run) will be incorrectly removed.

That doesn't seem very clear - what I'm really trying to say is that for the purpose that The Turtle is describing apgsearch doesn't use properties of the gliders to determine if they are safe to remove, but instead relies on the entire pattern being stabilised before removing them.
The latest version of the 5S Project contains over 226,000 spaceships. There is also a GitHub mirror of the collection. Tabulated pages up to period 160 (out of date) are available on the LifeWiki.

User avatar
The Turtle
Posts: 102
Joined: May 6th, 2015, 8:14 pm
Location: Chicago, Illinois

Re: Python Questions

Post by The Turtle » June 29th, 2015, 12:21 pm

Apgsearch questions

How does apgsearch define "stabilized"?
How does apgsearch tell whether or not a pattern is "stable"?

Golly module questions

Is the golly module written in Python?
If so, is the source code available?
Which functions run fastest? slowest? How about others?
Only two things are constant: change and the speed of light.

User avatar
dvgrn
Moderator
Posts: 6739
Joined: May 17th, 2009, 11:00 pm
Location: Madison, WI
Contact:

Re: Python Questions

Post by dvgrn » June 29th, 2015, 3:20 pm

The Turtle wrote:Apgsearch questions

How does apgsearch define "stabilized"?
How does apgsearch tell whether or not a pattern is "stable"?
The first attempt involves running stabilise_soups_parallel, which runs stabilise3(), which as a first attempt runs naivestab() for around 6000 ticks, looking for the population to stabilize:

Naive stabilization subroutine:

Code: Select all

    def naivestab(self, period, security, length):

        depth = 0
        prevpop = 0
        for i in xrange(length):
            g.run(period)
            currpop = int(g.getpop())
            if (currpop == prevpop):
                depth += 1
            else:
                depth = 0
            prevpop = currpop
            if (depth == security):
                # Population is periodic.
                return True

        return False
-- called from stabilize3():

Code: Select all

    def stabilise3(self):

        # Phase I of stabilisation detection, designed to weed out patterns
        # that stabilise into a cluster of low-period oscillators within
        # about 6000 generations.

        if (self.naivestab2(12, 10)):
            return 4;

        if (self.naivestab(12, 30, 200)):
            return 4;

        if (self.naivestab(30, 30, 200)):
            return 5;

        # Phase II of stabilisation detection, which is much more rigorous
        # and based on oscar.py... 
There are quite a few comments in apgsearch code, and not all of them are bad puns... Try following the logic through the various subroutines, and post any specific questions that come up.
The Turtle wrote:Golly module questions

Is the golly module written in Python?
If so, is the source code available?
Yes to both -- installed with Golly, in a 'glife' subfolder under /Scripts/Python/. Most functionality is in the code file called __init__.py, but there are also several subsidiary files like text.py.

EDIT: My apologies -- as wildmyrn points out below, I was answering the wrong question here. The golly module functionality is part of Golly's application code, written in C++ -- so it can currently be found in various subfiles in Sourceforge's code tree, mostly in gollybase if I recall correctly.
The Turtle wrote:Which functions run fastest? slowest? How about others?
Even if I knew what benchmark to measure against, I wouldn't have any answers to these last questions. Try the functions out, and time whatever specific tasks you're interested in optimizing.

In general, using the extra properties and methods provided by glife probably won't slow down your code in any measurable way. Sometimes, as I mentioned, it might make it significantly faster, such as asking for gottsdots[100001] after you've already asked for gottsdots[100000].

Your mileage may vary, though -- in some cases, storing too many phases of a pattern may use up available memory and make everything slower after all.

wildmyron
Posts: 1402
Joined: August 9th, 2013, 12:45 am

Re: Python Questions

Post by wildmyron » June 30th, 2015, 4:15 am

dvgrn wrote:
The Turtle wrote:Golly module questions

Is the golly module written in Python?
If so, is the source code available?
Yes to both -- installed with Golly, in a 'glife' subfolder under /Scripts/Python/. Most functionality is in the code file called __init__.py, but there are also several subsidiary files like text.py.
I think this question was about Golly's builtin Python module, i.e.

Code: Select all

import golly
rather than the glife module. I don't know anything about the implementation beyond what is in the Help File - Golly -> Help -> Python Scripting
dvgrn wrote:
The Turtle wrote:Which functions run fastest? slowest? How about others?
Even if I knew what benchmark to measure against, I wouldn't have any answers to these last questions. Try the functions out, and time whatever specific tasks you're interested in optimizing.
I'd say that anywhere repeated use of a Golly scripting command can be replaced by modifying cell lists in Python and using a small number of commands which transfer data from Golly to Python will provide a significant speed boost. An example is replacing repeated use of:

Code: Select all

cell = golly.getcell(x,y)
# Do something with single cell
golly.setcell(x,y,state)
inside a loop to modify or create a pattern with:

Code: Select all

cell_list = golly.getcells(rect)
# Do something with the pattern in cell_list
golly.putcells(cell_list,x,y)
to operate on the pattern as a whole.
The latest version of the 5S Project contains over 226,000 spaceships. There is also a GitHub mirror of the collection. Tabulated pages up to period 160 (out of date) are available on the LifeWiki.

User avatar
The Turtle
Posts: 102
Joined: May 6th, 2015, 8:14 pm
Location: Chicago, Illinois

Re: Python Questions

Post by The Turtle » July 1st, 2015, 10:52 am

Code: Select all

import golly
That's what I meant. I was wondering why "import golly" was in the module...
Only two things are constant: change and the speed of light.

User avatar
The Turtle
Posts: 102
Joined: May 6th, 2015, 8:14 pm
Location: Chicago, Illinois

Re: Python Questions

Post by The Turtle » July 5th, 2015, 11:15 am

Also, how exactly does QuickLife and HashLife work? Why are they extremely fast? Is it the programming language or something else?
Only two things are constant: change and the speed of light.

Post Reply