ConwayLife.com - A community for Conway's Game of Life and related cellular automata
Home  •  LifeWiki  •  Forums  •  Download Golly

Hacking apgsearch

For scripts to aid with computation or simulation in cellular automata.

Re: Hacking apgsearch

Postby drc » December 19th, 2015, 12:14 pm

Scorbie wrote:Whoops, my bad. it's in Scripts/Python/glife.


I actually didn't have the scripts, or patterns installed, so I reinstalled it and it works now.
This post was brought to you by the letter D, for dishes that Andrew J. Wade won't do. (Also Daniel, which happens to be me.)
Current rule interest: B2ce3-ir4a5y/S2-c3-y
User avatar
drc
 
Posts: 1664
Joined: December 3rd, 2015, 4:11 pm
Location: creating useless things in OCA

Re: Hacking apgsearch

Postby drc » December 19th, 2015, 1:01 pm

I'm having trouble with the A for awesome's version of apgnano.

In this rule:

@RULE testlife
@TABLE
n_states:2
neighborhood:Moore
symmetries:rotate4reflect
0,1,1,1,0,0,0,0,0,1
0,1,1,0,1,0,0,0,0,1
0,1,1,0,0,1,0,0,0,1
0,1,1,0,0,0,1,0,0,1
0,1,1,0,0,0,0,1,0,1
0,1,1,0,0,0,0,0,1,1
0,1,0,1,0,1,0,0,0,1
0,1,0,1,0,0,1,0,0,1
0,1,0,0,1,0,1,0,0,1
0,0,1,0,1,0,1,0,0,1
0,1,1,1,1,1,1,0,0,1
1,0,0,0,0,0,0,0,0,0
1,1,0,0,0,0,0,0,0,0
1,0,1,0,0,0,0,0,0,0
1,1,1,1,1,0,0,0,0,0
1,1,1,1,0,1,0,0,0,0
1,1,1,1,0,0,1,0,0,0
1,1,1,0,1,1,0,0,0,0
1,1,1,0,1,0,1,0,0,0
1,1,1,0,1,0,0,1,0,0
1,1,1,0,1,0,0,0,1,0
1,1,1,0,0,1,1,0,0,0
1,1,1,0,0,1,0,1,0,0
1,1,1,0,0,1,0,0,1,0
1,1,1,0,0,0,1,1,0,0
1,1,0,1,0,1,0,1,0,0
1,0,1,0,1,0,1,0,1,0
1,0,0,0,1,1,1,1,1,0
1,0,0,1,0,1,1,1,1,0
1,0,0,1,1,0,1,1,1,0
1,0,0,1,1,1,0,1,1,0
1,0,0,1,1,1,1,0,1,0
1,0,0,1,1,1,1,1,0,0
1,0,1,0,1,0,1,1,1,0
1,0,1,0,1,1,0,1,1,0
1,0,1,1,0,1,0,1,1,0
1,1,0,1,0,1,0,1,1,0
1,0,0,1,1,1,1,1,1,0
1,0,1,0,1,1,1,1,1,0
1,0,1,1,0,1,1,1,1,0
1,0,1,1,1,0,1,1,1,0
1,1,0,1,0,1,1,1,1,0
1,1,0,1,1,1,0,1,1,0
1,0,1,1,1,1,1,1,1,0
1,1,0,1,1,1,1,1,1,0
1,1,1,1,1,1,1,1,1,0

@COLORS

0 0 0 0
1 255 255 255


It classifies this:

x = 5, y = 4, rule = testlife
o2bo$4bo$o3bo$b4o!


As "pathological"

For those wondering it's a regular LWSS.
This post was brought to you by the letter D, for dishes that Andrew J. Wade won't do. (Also Daniel, which happens to be me.)
Current rule interest: B2ce3-ir4a5y/S2-c3-y
User avatar
drc
 
Posts: 1664
Joined: December 3rd, 2015, 4:11 pm
Location: creating useless things in OCA

Re: Hacking apgsearch

Postby A for awesome » December 19th, 2015, 7:37 pm

drc wrote:It classifies this:

x = 5, y = 4, rule = testlife
o2bo$4bo$o3bo$b4o!


As "pathological"

For those wondering it's a regular LWSS.

That's weird; XWSS detection was working just fine in klife when I tested it.
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
A for awesome
 
Posts: 1862
Joined: September 13th, 2014, 5:36 pm
Location: 0x-1

Re: Hacking apgsearch

Postby Saka » December 20th, 2015, 2:31 am

I get an error every time I try to use dlife (from life variations thread):
Error reading APG_ContagiousLife_dlife.rule on line 242: 0,aa,ab,ba,ac,bb,bc,bd,be, -too few entries
Not sure what's going on, the script works just fine for other rules (e.g. tlife, HeptaFish)
If you're the person that uploaded to Sakagolue illegally, please PM me.
x = 17, y = 10, rule = B3/S23
b2ob2obo5b2o$11b4obo$2bob3o2bo2b3o$bo3b2o4b2o$o2bo2bob2o3b4o$bob2obo5b
o2b2o$2b2o4bobo2b3o$bo3b5ob2obobo$2bo5bob2o$4bob2o2bobobo!

(Check gen 2)
User avatar
Saka
 
Posts: 3077
Joined: June 19th, 2015, 8:50 pm
Location: In the kingdom of Sultan Hamengkubuwono X

Re: Hacking apgsearch

Postby drc » December 20th, 2015, 11:38 am

Saka wrote:I get an error every time I try to use dlife (from life variations thread):
Error reading APG_ContagiousLife_dlife.rule on line 242: 0,aa,ab,ba,ac,bb,bc,bd,be, -too few entries
Not sure what's going on, the script works just fine for other rules (e.g. tlife, HeptaFish)


There's a typo on that line. There are 9 entries and an empty one after
This post was brought to you by the letter D, for dishes that Andrew J. Wade won't do. (Also Daniel, which happens to be me.)
Current rule interest: B2ce3-ir4a5y/S2-c3-y
User avatar
drc
 
Posts: 1664
Joined: December 3rd, 2015, 4:11 pm
Location: creating useless things in OCA

Re: Hacking apgsearch

Postby A for awesome » December 20th, 2015, 11:59 am

Saka wrote:I get an error every time I try to use dlife (from life variations thread):
Error reading APG_ContagiousLife_dlife.rule on line 242: 0,aa,ab,ba,ac,bb,bc,bd,be, -too few entries
Not sure what's going on, the script works just fine for other rules (e.g. tlife, HeptaFish)

It's because I was stupid and didn't test the script enough before releasing it. The line 0,1,1,0,1,0,0,0,0,0 in the dlife rule table wasn't accounted for in the last two conditionals in the function that produces the ContagiousLife table. To fix it, just replace the RuleGenerator.saveContagiousLife() function with
    def saveContagiousLife(self):

        comments = """
A variant of HistoricalLife used for detecting dependencies between
islands.

state 0:  vacuum
state 1:  ON
state 2:  OFF
"""
        table = "n_states:7\n"
        table += "neighborhood:Moore\n"
       
        if ruletype:
            table += "symmetries:permute\n\n"

            table += self.newvars(["a","b","c","d","e","f","g","h","i"], range(0, 7, 1))
            table += self.newvars(["la","lb","lc","ld","le","lf","lg","lh","li"], range(1, 7, 2))
            table += self.newvars(["da","db","dc","dd","de","df","dg","dh","di"], range(0, 7, 2))
            table += self.newvar("p",[3, 4])
            table += self.newvars(["ta","tb","tc","td","te","tf","tg","th","ti"], [3])
            table += self.newvars(["qa","qb","qc","qd","qe","qf","qg","qh","qi"], [0, 1, 2, 4, 5, 6])

            for i in xrange(9):
                if (self.bee[i]):
                    table += self.scoline("l","d",4,3,i)
                    table += self.scoline("l","d",2,1,i)
                    table += self.scoline("l","d",0,1,i)
                    table += self.scoline("l","d",6,5,i)
                    table += self.scoline("t","q",0,4,i)
                if (self.ess[i]):
                    table += self.scoline("l","d",3,3,i)
                    table += self.scoline("l","d",5,5,i)
                    table += self.scoline("l","d",1,1,i)

            table += "# Default behaviour (death):\n"
            table += self.scoline("","",1,2,0)
            table += self.scoline("","",5,6,0)
            table += self.scoline("","",3,4,0)
        else:
            rule1 = open(g.getdir("app") + "Rules/" + self.slashed + ".rule", "r")
            lines1 = rule1.read().split("\n")
            rule1.close()
            for q in xrange(len(lines1)-1):
                if lines1[q].startswith("@TABLE"):
                    lines1 = lines1[q:]
                    break
            vars = []
            for q in xrange(len(lines1)-1): #Copy symmetries and vars
                i = lines1[q]
                if i[:2] == "sy" or i[:1] == "sy":
                    table += i + "\n\n"
                if i[:2] == "va" or i[:1] == "va":
                    table += self.newvar(i[4:5].replace("=", ""), [0, 1, 2])
                    vars.append(i[4:5].replace("=", ""))
                if i != "":
                    if i[0] == "0" or i[0] == "1":
                        break
            alpha = "abcdefghijklmnopqrstuvwxyz"
            ovars = []
            for i in alpha:
                if not i in [n[0] for n in vars]: #Create new set of vars for ON cells
                    table += self.newvars([i + j for j in alpha[:9]], [1, 3, 5])
                    ovars = [i + j for j in alpha[:9]]
                    break
            dvars = []
            for i in alpha:
                if not i in [n[0] for n in vars] and not i in [n[0] for n in ovars]: #Create new set of vars for OFF cells
                    table += self.newvars([i + j for j in alpha[:9]], [0, 2, 4, 6])
                    dvars = [i + j for j in alpha[:9]]
                    break
                   
            for i in alpha:
                if not i in [n[0] for n in vars] and not i in [n[0] for n in ovars] and not i in [n[0] for n in dvars]:
                    for j in xrange(8-len(vars)):
                        table += self.newvar(i + alpha[j], [0, 1, 2, 3, 4, 5, 6])
                        vars.append(i + alpha[j])
                    break
           
            qvars = []
            for i in alpha:
                if not i in [n[0] for n in vars] and not i in [n[0] for n in ovars] and not i in [n[0] for n in dvars]:
                    table += self.newvars([i + j for j in alpha[:9]], [0, 1, 2, 4, 5, 6])
                    qvars = [i + j for j in alpha[:9]]
                    break
           
            for i in lines1:
                q = i.split("#")[0].replace(" ", "").split(",")
                if len(q) > 1 and not i.startswith("var"):
                    vn = 0
                    ovn = 0
                    dvn = 0
                    qvn = 0
                    table += str(2-int(q[0])) + ","
                    for j in q[1:-1]:
                        if j == "0":
                            table += dvars[dvn]
                            dvn += 1
                        elif j == "1":
                            table += ovars[ovn]
                            ovn += 1
                        elif j != "#":
                            table += vars[vn]
                            vn += 1
                        table += ","
                    if q[len(q)-1] == "0":
                        table += "2"
                    if q[len(q)-1] == "1":
                        table += "1"
                    table += "\n"
                    vn = 0
                    ovn = 0
                    dvn = 0
                    qvn = 0
                    table += str(4-int(q[0])) + ","
                    for j in q[1:-1]:
                        if j == "0":
                            table += dvars[dvn]
                            dvn += 1
                        elif j == "1":
                            table += ovars[ovn]
                            ovn += 1
                        elif j != "#":
                            table += vars[vn]
                            vn += 1
                        table += ","
                    if q[len(q)-1] == "0":
                        table += "4"
                    if q[len(q)-1] == "1":
                        table += "3"
                    table += "\n"
                    vn = 0
                    ovn = 0
                    dvn = 0
                    qvn = 0
                    table += str(6-int(q[0])) + ","
                    for j in q[1:-1]:
                        if j == "0":
                            table += dvars[dvn]
                            dvn += 1
                        elif j == "1":
                            table += ovars[ovn]
                            ovn += 1
                        elif j != "#":
                            table += vars[vn]
                            vn += 1
                        table += ","
                    if q[len(q)-1] == "0":
                        table += "6"
                    if q[len(q)-1] == "1":
                        table += "5"
                    table += "\n"
                   
            for i in lines1:
                q = i.split("#")[0].replace(" ", "").split(",")
                if len(q) > 1:
                    vn = 0
                    ovn = 0
                    dvn = 0
                    qvn = 0
                    if q[0] == "0":
                        table += "0,"
                        for j in q[1:-1]:
                            if j == "0":
                                table += dvars[dvn]
                                dvn += 1
                            elif j == "1":
                                table += ovars[ovn]
                                ovn += 1
                            elif j != "#":
                                table += vars[vn]
                                vn += 1
                            table += ","
                        if q[len(q)-1] == "1":
                            table += "1"
                        else:
                            table += "0"
                        table += "\n"
                       
            for i in lines1:
                q = i.split("#")[0].replace(" ", "").split(",")
                if len(q) > 1:
                    vn = 0
                    ovn = 0
                    dvn = 0
                    qvn = 0
                    if q[0] == "0":
                        table += "0,"
                        for j in q[1:-1]:
                            if j == "0":
                                table += qvars[qvn]
                                qvn += 1
                            elif j == "1":
                                table += "3"
                            elif j != "#":
                                table += vars[vn]
                                vn += 1
                            table += ","
                        if q[len(q)-1] == "1":
                            table += "4"
                        else:
                            table += "0"
                        table += "\n"

        colours = """
0    0    0    0
1    0    0  255
2    0    0  127
3  255    0    0
4  127    0    0
5    0  255    0
6    0  127    0
"""
        self.saverule("APG_ContagiousLife_"+self.alphanumeric, comments, table, colours)
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
A for awesome
 
Posts: 1862
Joined: September 13th, 2014, 5:36 pm
Location: 0x-1

Re: Hacking apgsearch

Postby gameoflifeboy » December 21st, 2015, 12:52 am

I just modified "A for awesome"'s version of apgsearch to read rule tables from your custom rules folder (g.getdata('rules')) instead of Golly's rules folder.

I call it "apgsearch-2015-12-20-v0.54+0.1i+0.1j.py":
Attachments
apgsearch-2015-12-20-v0.54+0.1i+0.1j.zip
(154.99 KiB) Downloaded 271 times
User avatar
gameoflifeboy
 
Posts: 474
Joined: January 15th, 2015, 2:08 am

Re: Hacking apgsearch

Postby wildmyron » December 21st, 2015, 1:29 am

drc wrote:I'm having trouble with the A for awesome's version of apgnano.

In this rule:
@RULE testlife
@TABLE
[snip]

It classifies this:
x = 5, y = 4, rule = testlife
o2bo$4bo$o3bo$b4o!

As "pathological"

I tried this out and it seems to work fine. Is every soup with an LWSS triggering the Pathological detection? It seems more likely to me that an LWSS is colliding with something after the soup was determined to be stable.
Can you provide the seed, symmetry and soup number where this occurs?
The latest version of the 5S Project contains over 196,000 spaceships. Tabulated pages up to period 160 are available on the LifeWiki.
wildmyron
 
Posts: 1209
Joined: August 9th, 2013, 12:45 am

Re: Hacking apgsearch

Postby gameoflifeboy » December 23rd, 2015, 9:16 pm

In Move variants, apgsearch v0.54 + v0.1i reports gliders, even though the rule doesn't support them. I suspect the "gliders" it's reporting are actually "spinning gliders", a p4 oscillator in Move-like rules. In fact, the phase of the glider given by its apgcode is different from the spinning glider, which means apgsearch is recognizing the gliders by their wrong phase.
EDIT: I now think this is happening because glidersexist() doesn't get called on non-Life-like rules, but the gliders are getting detected anyway.
Attachments
apgsearch_error.png
Screenshot of move_rep census, with "glider" reported as a spaceship
apgsearch_error.png (12.47 KiB) Viewed 15929 times
Last edited by gameoflifeboy on December 23rd, 2015, 9:31 pm, edited 1 time in total.
User avatar
gameoflifeboy
 
Posts: 474
Joined: January 15th, 2015, 2:08 am

Re: Hacking apgsearch

Postby drc » December 23rd, 2015, 9:19 pm

gameoflifeboy wrote:In Move variants, apgsearch v0.54 + v0.1i reports gliders, even though the rule doesn't support them. I suspect the "gliders" it's reporting are actually "spinning gliders", a p4 oscillator in Move-like rules. In fact, the phase of the glider given by its apgcode is different from the spinning glider, which means apgsearch is recognizing the gliders by their wrong phase.

I noticed that too, its weird
This post was brought to you by the letter D, for dishes that Andrew J. Wade won't do. (Also Daniel, which happens to be me.)
Current rule interest: B2ce3-ir4a5y/S2-c3-y
User avatar
drc
 
Posts: 1664
Joined: December 3rd, 2015, 4:11 pm
Location: creating useless things in OCA

Re: Hacking apgsearch

Postby A for awesome » December 26th, 2015, 8:57 pm

drc wrote:
gameoflifeboy wrote:In Move variants, apgsearch v0.54 + v0.1i reports gliders, even though the rule doesn't support them. I suspect the "gliders" it's reporting are actually "spinning gliders", a p4 oscillator in Move-like rules. In fact, the phase of the glider given by its apgcode is different from the spinning glider, which means apgsearch is recognizing the gliders by their wrong phase.

I noticed that too, its weird

Sorry about that; that will be fixed in the next version.
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
A for awesome
 
Posts: 1862
Joined: September 13th, 2014, 5:36 pm
Location: 0x-1

Re: Hacking apgsearch

Postby A for awesome » December 27th, 2015, 11:27 am

apgsearch-2015-12-27-v0.54+0.12i.py.zip
(152.24 KiB) Downloaded 279 times

Changes since the previous version:
  • Numerous bug fixes, including the ones for x-rule-pre and dlife.
  • Gliders are now tested on a rule-by-rule basis.
  • Added rules to identify and expunge T's.
  • Adapted Gameoflifeboy's modification to allow rules from your Rules folder.
  • Minor changes to object scores.

Changes (hopefully) coming (sometime) soon:
  • More accurate scores for a multitude of rules.
  • Rule to separate non-interacting combinations of high-period oscillators.
  • Modifications to countxwsses() that add support for other, rule-specific p4 spaceships.

Changes that are not coming soon, but hopefully I (or anyone else that wants to) can eventually figure out how to do:
  • Bounded grids (for exploding rules.)
  • Support for Generations, Plus-Minus, or custom 3-state rules.
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
A for awesome
 
Posts: 1862
Joined: September 13th, 2014, 5:36 pm
Location: 0x-1

Re: Hacking apgsearch

Postby A for awesome » December 28th, 2015, 3:17 pm

Found a bug in the T identification; a fix is to insert the line
1,1,2,1,2,1,12,2,0,3
after the line
1,1,o,1,oa,1,io,ioa,io,3
in RuleGenerator.saveIdentifyTs() and the line
o,oa,13,ob,oc,od,13,oe,of,o
before the line
#Survival
in RuleGenerator.saveAdvanceTs().
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
A for awesome
 
Posts: 1862
Joined: September 13th, 2014, 5:36 pm
Location: 0x-1

Re: Hacking apgsearch

Postby A for awesome » December 29th, 2015, 5:06 pm

Another (very dirtily) hacked variant of apgsearch, which enumerates all patterns within a given bounding box, runs them to completion, and censuses the result:
apgsearch-MxNrect-0.1.py.zip
(147.84 KiB) Downloaded 279 times

There isn't much to explain. Just run it like you would normal apgsearch and enter in the number of soups (preferably a number higher than the total number of patterns that fit within the bounding box you're searching), the dimensions of the box you're searching, and the rule.
P.S. Don't be alarmed by the weird error message that shows up right after the results are displayed. As far as I know, it's inconsequential.
Last edited by A for awesome on December 29th, 2015, 6:57 pm, edited 1 time in total.
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
A for awesome
 
Posts: 1862
Joined: September 13th, 2014, 5:36 pm
Location: 0x-1

Re: Hacking apgsearch

Postby dvgrn » December 29th, 2015, 6:39 pm

A for awesome wrote:Another (very dirtily) hacked variant of apgsearch, which enumerates all patterns within a given bounding box, runs them to completion, and censuses the result...

Works better on my system with a small change to line 50. I got the error

File "apgsearch-MxNrect-0.1.py", line 50, in hashsoup
    for i in xrange(math.floor(math.log(sym+1, 2))+1):
TypeError: integer argument expected, got float

Wrapping math.floor() in an int() seemed to solve the problem:

for i in xrange(int(math.floor(math.log(sym+1, 2)))+1):

math.floor() is rumored to return a float in Python 2.x but not in 3.x. Is there a Python 2.x version that works with Golly but doesn't throw the above error?

Also, if you specify a number larger than the total possible number of MxN patterns, does the script stop when it has enumerated every possible pattern once? I'm trying a 5x5 run in B3/S23, so it will be a while before I get to 33554432 to see for myself.

I don't quite understand your line 11252; seems as if the min() calculation cuts the number of iterations down to the right size, but if I put in a really big number, the script would go round and round because the limit power-of-two value isn't being divided by the number of soups per page. Looks like it should be

for i in xrange(min(int((number-1)/spp)+1, int((2**(c.x*c.y)-1)/spp)+1)):

For example, that successfully runs just 2^9=512 3x3 soups, instead of going through 64x512 = 32768 of them before stopping.

Another random thought: the current script doesn't account for rotations and reflections, so in a 5x5 search it will eventually census all eight orientations of 2obo$b2obo$2ob2o$b3o! (for example).

Have you considered generating all orientations of each candidate pattern, and letting apgsearch run a candidate only if no other orientation sorts lower? Pretty much any sort criterion would work.

With all that extra flipping/rotating/sorting work, it might not save much time in the end, but you wouldn't end up with identical census results in lots of groups of two or four or eight.
User avatar
dvgrn
Moderator
 
Posts: 5751
Joined: May 17th, 2009, 11:00 pm
Location: Madison, WI

Re: Hacking apgsearch

Postby A for awesome » December 29th, 2015, 7:04 pm

dvgrn wrote:
A for awesome wrote:Another (very dirtily) hacked variant of apgsearch, which enumerates all patterns within a given bounding box, runs them to completion, and censuses the result...

Works better on my system with a small change to line 50. I got the error

File "apgsearch-MxNrect-0.1.py", line 50, in hashsoup
    for i in xrange(math.floor(math.log(sym+1, 2))+1):
TypeError: integer argument expected, got float

Wrapping math.floor() in an int() seemed to solve the problem:

for i in xrange(int(math.floor(math.log(sym+1, 2)))+1):

math.floor() is rumored to return a float in Python 2.x but not in 3.x. Is there a Python 2.x version that works with Golly but doesn't throw the above error?

Also, if you specify a number larger than the total possible number of MxN patterns, does the script stop when it has enumerated every possible pattern once? I'm trying a 5x5 run in B3/S23, so it will be a while before I get to 33554432 to see for myself.

I don't quite understand your line 11252; seems as if the min() calculation cuts the number of iterations down to the right size, but if I put in a really big number, the script would go round and round because the limit power-of-two value isn't being divided by the number of soups per page. Looks like it should be

for i in xrange(min(int((number-1)/spp)+1, int((2**(c.x*c.y)-1)/spp)+1)):

For example, that successfully runs just 2^9=512 3x3 soups, instead of going through 64x512 = 32768 of them before stopping.

Another random thought: the current script doesn't account for rotations and reflections, so in a 5x5 search it will eventually census all eight orientations of 2obo$b2obo$2ob2o$b3o! (for example).

Have you considered generating all orientations of each candidate pattern, and letting apgsearch run a candidate only if no other orientation sorts lower? Pretty much any sort criterion would work.

With all that extra flipping/rotating/sorting work, it might not save much time in the end, but you wouldn't end up with identical census results in lots of groups of two or four or eight.

Thanks for the pointers and suggestions. I have just fixed the original version to accommodate your fixes. No, the version you have does not stop when it has enumerated all possible MxN patterns; it instead enumerates them 64 times, except for the last page, which it enumerates only 63 times. This should be fixed in the updated version.

Generating only one orientation of each pattern would probably be efficient enough by far to produce an increase in performance, but I have no idea how to do that.
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
A for awesome
 
Posts: 1862
Joined: September 13th, 2014, 5:36 pm
Location: 0x-1

Re: Hacking apgsearch

Postby drc » December 29th, 2015, 7:35 pm

A for awesome wrote:Another (very dirtily) hacked variant of apgsearch, which enumerates all patterns within a given bounding box, runs them to completion, and censuses the result:
apgsearch-MxNrect-0.1.py.zip

There isn't much to explain. Just run it like you would normal apgsearch and enter in the number of soups (preferably a number higher than the total number of patterns that fit within the bounding box you're searching), the dimensions of the box you're searching, and the rule.
P.S. Don't be alarmed by the weird error message that shows up right after the results are displayed. As far as I know, it's inconsequential.


Nice!

x = 5, y = 3, rule = B3/S23
o2b2o$ob2o$4o!


Edit: Also, you should add something in the script to actually fill up the entire bounding box (for example 16x1 soups fitting in 17x1) so it is faster to search.

Edit: And eliminate 1 and 2 cell islands.
This post was brought to you by the letter D, for dishes that Andrew J. Wade won't do. (Also Daniel, which happens to be me.)
Current rule interest: B2ce3-ir4a5y/S2-c3-y
User avatar
drc
 
Posts: 1664
Joined: December 3rd, 2015, 4:11 pm
Location: creating useless things in OCA

Re: Hacking apgsearch

Postby Kazyan » December 29th, 2015, 10:34 pm

A for awesome wrote:Generating only one orientation of each pattern would probably be efficient enough by far to produce an increase in performance, but I have no idea how to do that.


Derive each pattern from a seed integer, in the same way that the official apgsearch derives a pattern from a SHA256 hash. Before running the pattern, take all of its reflections and rotations, and reverse-engineer their respective seeds. Run the pattern only if its seed is the lowest among its orientations.

A further performance speedup could be gained by considering the corner cells of the pattern. Try the above paragraph on 2x2 bounding boxes, and it turns out that you can throw out 10 of every 16 seed integers automatically. So, if you derive the corner cells of a pattern from the last four binary digits of a seed, you know that certain seed integers modulo 16 will be automatically invalid, and you can skip them.

EDIT: Correction; 10 of 16 patterns cannot be discarded for M=/=N, but some still can.
Tanner Jacobi
User avatar
Kazyan
 
Posts: 844
Joined: February 6th, 2014, 11:02 pm

Re: Hacking apgsearch

Postby A for awesome » December 30th, 2015, 10:28 am

Kazyan wrote:
A for awesome wrote:Generating only one orientation of each pattern would probably be efficient enough by far to produce an increase in performance, but I have no idea how to do that.


Derive each pattern from a seed integer, in the same way that the official apgsearch derives a pattern from a SHA256 hash. Before running the pattern, take all of its reflections and rotations, and reverse-engineer their respective seeds. Run the pattern only if its seed is the lowest among its orientations.

A further performance speedup could be gained by considering the corner cells of the pattern. Try the above paragraph on 2x2 bounding boxes, and it turns out that you can throw out 10 of every 16 seed integers automatically. So, if you derive the corner cells of a pattern from the last four binary digits of a seed, you know that certain seed integers modulo 16 will be automatically invalid, and you can skip them.

EDIT: Correction; 10 of 16 patterns cannot be discarded for M=/=N, but some still can.

That's not what I meant. I don't know how to do that and then incorporate that algorithm into the script without ruining the other modifications I made. There are some restrictions in the script with the loop variable being used as the soup counter, and I can't really just skip some soups or it doesn't know when to stop. As I said, it's a dirty hack, so I'm not too invested in adding that implementation; it would take too much time and there's a very good chance I would just make a very big mess of things.
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
A for awesome
 
Posts: 1862
Joined: September 13th, 2014, 5:36 pm
Location: 0x-1

Re: Hacking apgsearch

Postby drc » January 9th, 2016, 12:34 pm

Is there any apgsearch variant that you can run and it tallies objects of the current pattern? like:

x = 9, y = 8, rule = B3/S23
2o$2o$6b2o$6bobo$7bo3$3b3o!


Would return:

xp2_7 1
xs4_33 1
xs5_253 1
This post was brought to you by the letter D, for dishes that Andrew J. Wade won't do. (Also Daniel, which happens to be me.)
Current rule interest: B2ce3-ir4a5y/S2-c3-y
User avatar
drc
 
Posts: 1664
Joined: December 3rd, 2015, 4:11 pm
Location: creating useless things in OCA

Re: Hacking apgsearch

Postby drc » January 9th, 2016, 2:15 pm

With apgsearch hacked 12-27-15

What's error-correcting phase?It seems to be screwing up the search and making it slower, things like still lifes and oscillators classed as gliders under xq1_(code), and xq1_0, which is impossible. It only seems to occur when no commas occur in the rule nodes.
This post was brought to you by the letter D, for dishes that Andrew J. Wade won't do. (Also Daniel, which happens to be me.)
Current rule interest: B2ce3-ir4a5y/S2-c3-y
User avatar
drc
 
Posts: 1664
Joined: December 3rd, 2015, 4:11 pm
Location: creating useless things in OCA

Re: Hacking apgsearch

Postby A for awesome » January 10th, 2016, 4:26 pm

drc wrote:With apgsearch hacked 12-27-15

What's error-correcting phase?It seems to be screwing up the search and making it slower, things like still lifes and oscillators classed as gliders under xq1_(code), and xq1_0, which is impossible. It only seems to occur when no commas occur in the rule nodes.

Oh, sorry; that's a case I forgot to deal with. I'll fix that in the next version.
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
A for awesome
 
Posts: 1862
Joined: September 13th, 2014, 5:36 pm
Location: 0x-1

Re: Hacking apgsearch

Postby gameoflifeboy » January 16th, 2016, 10:54 pm

drc wrote:Is there any apgsearch variant that you can run and it tallies objects of the current pattern?

Nathaniel once made a program that did something like this.
It became the Online Life-Like CA Soup Search, and you know what happened to that.
User avatar
gameoflifeboy
 
Posts: 474
Joined: January 15th, 2015, 2:08 am

Re: Hacking apgsearch

Postby drc » January 16th, 2016, 11:46 pm

gameoflifeboy wrote:
drc wrote:Is there any apgsearch variant that you can run and it tallies objects of the current pattern?

Nathaniel once made a program that did something like this.
It became the Online Life-Like CA Soup Search, and you know what happened to that.

Yeah, I wish it had an output file though.
This post was brought to you by the letter D, for dishes that Andrew J. Wade won't do. (Also Daniel, which happens to be me.)
Current rule interest: B2ce3-ir4a5y/S2-c3-y
User avatar
drc
 
Posts: 1664
Joined: December 3rd, 2015, 4:11 pm
Location: creating useless things in OCA

Re: Hacking apgsearch

Postby A for awesome » January 25th, 2016, 9:50 pm

The latest update to apgsearch-v0.54+0.Ni:

apgsearch-2016-1-21-v0.54+0.2i.py.zip
(157.15 KiB) Downloaded 289 times

Changes since the previous version:
  • Optionally uploads results to Catagolue (using Alan Hensel's rule notation; a new function RuleGenerator.testHensel determines the rule notation), but still displays results in the original format locally.
  • Pseudo-pattern separation can now be turned off (i.e. the script can census pseudo-still-lives and oscillators now) when not uploading results.
  • Somewhat-updated common-names dict, with the names of the most common pseudo-SLs and pseudo-oscillators in Life and dots, dominoes, and duoplets included.
Known shortcomings, likely to be fixed soon:
  • Sqrtspp optimization is buggy, often alternates between 9, 10, and 11 before settling on 10.
  • Glider tagalongs (such as this one:
    x = 6, y = 5, rule = B3/S23-a
    2o$obo$o$3bo$3b3o!
    ) are sometimes erroneously separated, resulting in their being classified as pathological objects.
  • Results in no visible errors but many pathological objects detected when a rule table has been modified after apgsearch has already been run in that rule.

A point of clarification: Even though it uploads hauls to Catagolue in Hensel's notation, there is no need to enter the rule name in that notation. In fact, it does not yet support this, and it will give you errors if you try. For now, just keep entering the name of the .rule files.

The RuleGenerator.testHensel function is also useful for stand-alone use:
#Hensel-test.py
#To setup, copy this into a file, name it "hensel-test.py",
# and put the file in Golly's scripts folder.
#Enter the name of the rule whose Hensel notation you want
# to determine, and this script copies the result to the clipboard.

import golly as g
class Foo:
    slashed = g.getstring("Enter name of rule to test", "Life")
    def testHensel(self):
        #Dict containing all possible transitions:
        dict = {
                 "0"  : "0,0,0,0,0,0,0,0",
                 "1e" : "1,0,0,0,0,0,0,0",  #   N
                 "1c" : "0,1,0,0,0,0,0,0",  #   NE
                 "2a" : "1,1,0,0,0,0,0,0",  #   N,  NE
                 "2e" : "1,0,1,0,0,0,0,0",  #   N,  E
                 "2k" : "1,0,0,1,0,0,0,0",  #   N,  SE
                 "2i" : "1,0,0,0,1,0,0,0",  #   N,  S
                 "2c" : "0,1,0,1,0,0,0,0",  #   NE, SE
                 "2n" : "0,1,0,0,0,1,0,0",  #   NE, SW
                 "3a" : "1,1,1,0,0,0,0,0",  #   N,  NE, E
                 "3n" : "1,1,0,1,0,0,0,0",  #   N,  NE, SE
                 "3r" : "1,1,0,0,1,0,0,0",  #   N,  NE, S     
                 "3q" : "1,1,0,0,0,1,0,0",  #   N,  NE, SW
                 "3j" : "1,1,0,0,0,0,1,0",  #   N,  NE, W
                 "3i" : "1,1,0,0,0,0,0,1",  #   N,  NE, NW
                 "3e" : "1,0,1,0,1,0,0,0",  #   N,  E,  S
                 "3k" : "1,0,1,0,0,1,0,0",  #   N,  E,  SW
                 "3y" : "1,0,0,1,0,1,0,0",  #   N,  SE, SW     
                 "3c" : "0,1,0,1,0,1,0,0",  #   NE, SE, SW
                 "4a" : "1,1,1,1,0,0,0,0",  #   N,  NE, E,  SE
                 "4r" : "1,1,1,0,1,0,0,0",  #   N,  NE, E,  S 
                 "4q" : "1,1,1,0,0,1,0,0",  #   N,  NE, E,  SW
                 "4i" : "1,1,0,1,1,0,0,0",  #   N,  NE, SE, S
                 "4y" : "1,1,0,1,0,1,0,0",  #   N,  NE, SE, SW
                 "4k" : "1,1,0,1,0,0,1,0",  #   N,  NE, SE, W
                 "4n" : "1,1,0,1,0,0,0,1",  #   N,  NE, SE, NW
                 "4z" : "1,1,0,0,1,1,0,0",  #   N,  NE, S,  SW
                 "4j" : "1,1,0,0,1,0,1,0",  #   N,  NE, S,  W
                 "4t" : "1,1,0,0,1,0,0,1",  #   N,  NE, S,  NW
                 "4w" : "1,1,0,0,0,1,1,0",  #   N,  NE, SW, W
                 "4e" : "1,0,1,0,1,0,1,0",  #   N,  E,  S,  W
                 "4c" : "0,1,0,1,0,1,0,1",  #   NE, SE, SW, NW
                 "5a" : "0,0,0,1,1,1,1,1",  #   SE, S,  SW, W,  NW
                 "5n" : "0,0,1,0,1,1,1,1",  #   E,  S,  SW, W,  NW
                 "5r" : "0,0,1,1,0,1,1,1",  #   E,  SE, SW, W, 
                 "5q" : "0,0,1,1,1,0,1,1",  #   E,  SE, S,  W,  NW
                 "5j" : "0,0,1,1,1,1,0,1",  #   E,  SE, S,  SW, NW
                 "5i" : "0,0,1,1,1,1,1,0",  #   E,  SE, S,  SW, W
                 "5e" : "0,1,0,1,0,1,1,1",  #   NE, SE, SW, W,  NW,
                 "5k" : "0,1,0,1,1,0,1,1",  #   NE, SE, S,  W,  NW
                 "5y" : "0,1,1,0,1,0,1,1",  #   NE, E,  S,  W, NW
                 "5c" : "1,0,1,0,1,0,1,1",  #   N,  E,  S,  W,  NW
                 "6a" : "0,0,1,1,1,1,1,1",  #   E,  SE, S,  SW, W,  NW
                 "6e" : "0,1,0,1,1,1,1,1",  #   NE, SE, S,  SW, W,  NW
                 "6k" : "0,1,1,0,1,1,1,1",  #   NE, E,  S,  SW, W,  NW
                 "6i" : "0,1,1,1,0,1,1,1",  #   NE, E,  SE, SW, W,  NW
                 "6c" : "1,0,1,0,1,1,1,1",  #   N,  E,  S,  SW, W,  NW
                 "6n" : "1,0,1,1,1,0,1,1",  #   N,  E,  SE, S,  W,  NW
                 "7e" : "0,1,1,1,1,1,1,1",  #   NE, E,  SE, S,  SW, W,  NW
                 "7c" : "1,0,1,1,1,1,1,1",  #   N,  E,  SE, S,  SW, W,  NW
                 "8"  : "1,1,1,1,1,1,1,1",
                }
       
        #Represents the encoding in dict:
        neighbors = [(-1,0),(-1,1),(0,1),(1,1),(1,0),(1,-1),(0,-1),(-1,-1)]
       
        #Will store transitions temporarily:
        d2 = [{},{}]
       
        #Used to help a conversion later:
        lnums = []
        for i in xrange(9):
            lnums.append([j for j in dict if int(j[0]) == i])
       
        #Self-explanatory:
        g.setrule(self.slashed)
       
        #Test each transition in turn:
        for i in xrange(2):
            for j in dict:
                j2 = dict[j].split(",")
                g.new("Testing Hensel notation...")
                for k in xrange(len(j2)):
                    k2 = int(j2[k])
                    g.setcell(neighbors[k][0], neighbors[k][1], k2)
                g.setcell(0, 0, i)
                g.run(1)
                d2[i][j] = int(g.getcell(0, 0)) == 1
       
        #Will become the main table of transitions:
        trans_ = [[],[]]
       
        #Will become the final output string:
        not_ = "B"
        for i in xrange(2):
            #Convert d2 to a more usable form
            for j in xrange(9):
                trans_[i].append({})
                for k in lnums[j]:
                    trans_[i][j][k] = d2[i][k]
                   
            #Make each set of transitions:
            for j in xrange(9):
               
                #Number of present transitions for B/S[[j]]
                sum = 0
                for k in trans_[i][j]:
                    if trans_[i][j][k]:
                        sum += 1
               
                #No transitions present:
                if sum == 0:
                    continue
               
                #All transitions present:
                if sum == len(trans_[i][j]):
                    not_ += str(j)
                    continue
                   
                str_ = str(j) #Substring for current set of transitions
               
                #Minus sign needed if more than half of
                #current transition set is present.
                minus = (sum >= len(trans_[i][j])/2)
                if minus:
                    str_ += "-"
               
                str2 = "" #Another substring for current transition set
               
                #Write transitions:
                for k in trans_[i][j]:
                    if trans_[i][j][k] != minus:
                        str2 += k[1:]
               
                #Append transitions:
                not_ += str_ + "".join(sorted(str2))
               
            if i == 0:
                not_ += "/S"
               
        g.new("Test finished.")
        return not_
foo = Foo()
q = foo.testHensel()
g.setclipstr(q)
g.show(q + " copied to clipboard")

Update 2-6-16:
Updated Hensel-test.py, changing v to n.
Last edited by A for awesome on February 6th, 2016, 3:40 pm, edited 1 time in total.
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
A for awesome
 
Posts: 1862
Joined: September 13th, 2014, 5:36 pm
Location: 0x-1

PreviousNext

Return to Scripts

Who is online

Users browsing this forum: No registered users and 0 guests