## Hacking apgsearch

For scripts to aid with computation or simulation in cellular automata.
wildmyron
Posts: 1276
Joined: August 9th, 2013, 12:45 am

### Hacking apgsearch

This thread is to discuss variations of apgsearch which go beyond incremental improvements and minor changes to the program.

First off, a few ideas:
wildmyron wrote:
dvgrn wrote:
wildmyron wrote:I also have been searching for glider reactions with a collection of common ash objects. There are a lot of reactions like this (not just switch engines)...
Are you generating ash object positions with a script, and classifying them with apgsearch? I've been thinking about trying something like this, but other things keep getting in the way.
Yes, I have. I've been meaning to describe what I'm doing and I'd like to get some feedback. At this stage I haven't posted the code to do it because I'm still making changes to the soup function, and that causes the results for a given soupid to change.
In the next post I will present apgsearch-blonksoup.py
dvgrn wrote:I'm interested in a couple of possible variants of this idea for modifying apgsearch. One is an exhaustive search for switch engines in the glider+2 blonks search space, for some reasonable MxN (to be gradually increased). Another is a search for switch engines and other interesting things, starting from guaranteed glider-constructible pieces (a few well-spaced small still lifes plus some number of incoming gliders and/or *WSSes, to get an active reaction going.) That kind of thing might go in a new thread called something like "Hacking apgsearch", if you want to go that route.
dvgrn wrote:A third search project, which might be most interesting for Sparse Life early-universe analysis, is a recursive enumeration of single glider collisions into blonks. Let G+blonk settle into quiescence, then hit each possible ash pattern with every possible new G from every direction... collect all those settled ash patterns, and repeat until switch engines appear. Seems as if this should only take about four or five gliders...!
NickGotts wrote:I've uploaded to "Golly scripts" in the Scripts forum, code to test whether the current position is "quiescent", i.e. consists solely of still lifes, oscillators, gliders and *WSSs, with the gliders and *WSSs being so placed that they will never interact with each other, or with any of the still lifes or oscillators. It's much less ambitious than the stabilisation test in apgsearch, but serves my purposes (mainly, looking for switch-engines in the output of multiple patterns) well.
NickGotts posted testquiescence which could help reduce the higher incidence of error correction in apgsearch-blonksoup. This occurs because an escaping glider from a stabilised reaction can collide with a blonk placed elsewhere in the original pattern.
wildmyron wrote:
Extrementhusiast wrote:How well would the apgsearch method work on a rule like sansdomino_s13?
My impression is that it would work really well after some adaptation. There are several places where semi-totalistic rules and rule notation are assumed. In particular, the auxillary rules and various tests that check which rule is being used. Some work would be required to generate the auxillary rules and also account for assumptions about the rule string (such as the test for glider existence). You could either create custom rules for APG_CoalesceObjects, APG_ClassifyObjects, and APG_ContagiousLife; or modify the rule generator to be able to handle rules which are not semi-totalistic. My impression is that APG_ClassifyObjects would require the most work to adapt, but I haven't thought through the details. I have been thinking about similar adaptations for multi-state rules, but I suspect that's even more complicated.
I have an in-progress implementation of apgsearch for a non-totalisitic rule - auxillary rules generated by hand. APG_ClassifyObjects only needs adaptation if different common objects need to be handled with it. APG_CoalesceObjects turned out to be harder than I thought because the "bridge inductor" rules are more complicated than simply testing number of alive neighbours.

With all of these ideas for variations, it would also be nice to have the core stabilisation, object identification, and rule generation code in a separate library which each of these ideas could draw on, rather than having it incorporated into each individual variation.
Last edited by wildmyron on October 15th, 2014, 3:24 am, edited 1 time in total.
The latest version of the 5S Project contains over 221,000 spaceships. Tabulated pages up to period 160 are available on the LifeWiki.

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

### Re: Hacking apgsearch

Here is apgsearch-blonksoup.py

The main difference with the original apgsearch is that the 16x16 random soup is replaced with a random field of blocks and blinkers, and a single glider. This version creates a relatively sparse distribution of objects, placing up to 25 objects on a diagonal rectangle of size 128x256 (measured in full diagonals - I think). The glider is positioned to collide with one blonk in such a way as to produce a large explosion due to the sparsity of the field of blonks. Without this step, very many iterations result in rather boring outcomes. Each additional blonk placed is (conservatively) tested to ensure it won't interact with any other blonks.

The rate of incidence of rare objects is lower than for the original, but everything detected is easily synthesizable - although clean up for SL synthesis would be laborious if the naive approach is used.
Attachments
apgsearch-blonksoup-v0.3.zip
apgsearch-blonksoup-v0.3.py
The latest version of the 5S Project contains over 221,000 spaceships. Tabulated pages up to period 160 are available on the LifeWiki.

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

### Re: Hacking apgsearch

wildmyron wrote:
wildmyron wrote:
Extrementhusiast wrote:How well would the apgsearch method work on a rule like sansdomino_s13?
My impression is that it would work really well after some adaptation. There are several places where semi-totalistic rules and rule notation are assumed. In particular, the auxillary rules and various tests that check which rule is being used. Some work would be required to generate the auxillary rules and also account for assumptions about the rule string (such as the test for glider existence). You could either create custom rules for APG_CoalesceObjects, APG_ClassifyObjects, and APG_ContagiousLife; or modify the rule generator to be able to handle rules which are not semi-totalistic. My impression is that APG_ClassifyObjects would require the most work to adapt, but I haven't thought through the details. I have been thinking about similar adaptations for multi-state rules, but I suspect that's even more complicated.
I have an in-progress implementation of apgsearch for a non-totalisitic rule - auxillary rules generated by hand. APG_ClassifyObjects only needs adaptation if different common objects need to be handled with it. APG_CoalesceObjects turned out to be harder than I thought because the "bridge inductor" rules are more complicated than simply testing number of alive neighbours.
Attached is an implementation of apgsearch for the non-totalistic rule on a hexagonal neighbourhood - 22da, aka hex_B2/S2op.

This is a proof of concept showing the adaptability of apgsearch. I am continuing work on the non-totalistic Moore neighbourhood version, focusing on the rule generator as manually writing auxillary rules is rather tedious.

This hexagonal rule implementation was rather interesting - I had some extra spare time to devote to it but didn't get around to everything I wanted to adapt. In particular the ContagiousLife rule which psuedo_bangbang() depends on isn't included. I don't think I'll spend any more time on that because it doesn't seem to be necessary in this rule - particularly as there are no still life objects. As noted in the comments, the naturally occurring rake significantly slows down the search speed, however I did run one search to a million soups. I think all the small oscillators except for the p10 showed up and a range of puffers where detected. A few puffers have multiple descriptions due to near by gliders which seem to get caught up by linearlyse().

The IdentifyGliders_22da rule may be useful elsewhere, and it shows how similar techniques can be used to detect other small gliders. I chose to only detect the glider in one phase, as this reduced the potential for misidentification of other objects. As a result, CoalesceObjects_22da requires 17 states so that it can be used to step the pattern and identify all gliders in each phase.

Edit: I forgot to mention that the common objects list has only been populated with a few objects, and as such the scoring is pretty much useless. Given the lack of diversity of naturally occurring objects in 22da I don't think I'll put any more work into it.

Edit: I cut a few corners in designing the IdentifyGliders_22da rule - it was no where near as rigorous as the original. This is entirely due to the size of the 22da glider and the choice to retain the 4 step process by using two central nodes to detect the glider rather than one. The result of this is that some almost glider patterns - particularly gliders which are not yet quite fully emitted by a puffer - are partly identified as a glider which may then be evolved into incorrect patterns during the rest of the glider detection.

In two of its phases, the 22da glider fits within a size two hexagonal neighbourhood of a central cell, so a similar rigorous process is possible in 7 steps rather than 4. However, my current estimate for how many states are required is 33 and I don't have the motivation at the moment to repair the situation by implementing the rule.
Attachments
apgsearch-hex-22da.zip
apgsearch implementation for 22da
The latest version of the 5S Project contains over 221,000 spaceships. Tabulated pages up to period 160 are available on the LifeWiki.

dvgrn
Moderator
Posts: 5904
Joined: May 17th, 2009, 11:00 pm
Contact:

### Re: Hacking apgsearch

wildmyron wrote:The main difference with the original apgsearch is that the 16x16 random soup is replaced with a random field of blocks and blinkers, and a single glider.
I'm getting ready to adjust apgsearch-blonksoup to run an exhaustive search on small constellations of common ash objects -- no random sampling, just every possible single-glider collision with every possible well-spaced m-by-n constellation.
TestPage-10x7.mc.gz
Exhaustive enumeration of 10x7 constellations of common still lifes (and all smaller rectangles)
Here's the rather suboptimal code that generated the above stamp collection:

build-constellation-v10.py: [fair warning: this script clobbers the clipboard with output statistics]

Code: Select all

# build-constellation-v10.py
import golly as g
from time import sleep
from glife.text import make_text

MAXOBJ=10
xsize,ysize=10,7

def getinp(s):
###########################
temp=g.getcell(x,y)
g.setcell(x,y,5)
g.show(s+"Ptr:"+str(ptr)+" x:" +str(x)+" y:"+str(y))
g.fit()
g.update()
g.setcell(x,y,temp)
# return
k=g.getevent()
count=0
while k=="":
sleep(.01)
k=g.getevent()
count+=1
if k=="key q none": g.exit()
return
###########################

patdict={}
# for i in range(2,xsize+1):
#   for j in range(2,ysize+1):
#     patdict[str([i,j])]=[]
objs=["2o$2o!","2o$obo$bo!","b2o$obo$bo!","bo$obo$b2o!","bo$obo$2o!", # block and boat "b2o$o2bo$b2o!","bo$obo$obo$bo!","bo$obo$bo!","b2o$o2bo$o2bo$b2o!", # beehive, tub, pond "2o$obo$b2o!", "b2o$obo$2o!", "b2o$o2bo$obo$bo!", # ship, loaf1
"b2o$o2bo$bobo$2bo!","2bo$bobo$o2bo$b2o!","bo$obo$o2bo$b2o!"] # other loaves objlist=[] for i in range(len(objs)): # normalize so that the first ON cell in the list is always (0,0) templist=g.parse(objs[i]) objlist+=[g.transform(templist,-templist[0],-templist[1])] numobjs=len(objlist) zonelist=[] for item in objlist: g.setrule("B12345678/S012345678") neighbors=g.evolve(item,1) g.setrule("B2345678/S012345678") zone=g.evolve(neighbors,1) zonelist+=[zone] # includes cells for object also g.setrule("LifeHistory") nearlist=[[i,j] for i in range(-1,xsize+1) for j in range(-1,ysize+1) if i<0 or i>=xsize or j<0 or j>=ysize] count,x,y,ptr,filledlist,searchlist=0,0,0,0,[],[] while y==0 or len(searchlist)>0: overlap=([x,y] in nearlist) # place current object ############################################# # TODO: if there's an overlap, set ptr to max value, then handle all cases with same code at the bottom if overlap==0: # g.show(str(ptr)) obj=g.transform(objlist[ptr],x,y) objpairs=[[obj[i],obj[i+1]] for i in range(0,len(obj),2)] for item in objpairs: if item in nearlist: overlap=1 break if overlap==0: zone=g.transform(zonelist[ptr],x,y) zonepairs=[[zone[i],zone[i+1]] for i in range(0,len(zone),2)] for item in zonepairs: if item in filledlist: overlap=2 break if overlap==0: g.new("TestPage") newptr,newx,newy=ptr+1,x,y if newptr>=len(objlist): newptr,newx=0,newx+1 if newx>=xsize-1: newptr,newx,newy=0,0,y+1 searchlist.append([newx,newy,newptr,nearlist[:],filledlist[:]]) # add next state to search to the stack nearlist+=zonepairs filledlist+=objpairs for i,j in nearlist: g.setcell(i,j,2) minx, maxx, miny, maxy = 999,-999,999,-999 for i,j in filledlist: g.setcell(i,j,1) if i<minx:minx=i elif i>maxx:maxx=i if j<miny: miny=j elif j>maxy: maxy=j # Take a snapshot of the current successful placement # [e.g., successful if two objects placed, etc.] if minx==0 and miny==0: keystr=str(maxx+1)+"x"+str(maxy+1) if keystr not in patdict: patdict[keystr]=[] if filledlist not in patdict[keystr]: patdict[keystr]+=[filledlist[:]] # Now continue searching from where we are count+=1 if count%100==0: g.show(str(count)) g.update() ptr,x=0,x+4 else: # the neighbor zone for this object overlaps some already placed object ptr+=1 if ptr>=len(objlist): ptr,x=0,x+1 else: # the object itself overlaps some already placed object's neighborhood ptr+=1 if ptr>=len(objlist): ptr,x=0,x+1 else: ptr,x=0,x+1 # getinp("Overlap type " + str(overlap) + ". Lenlist="+str(len(searchlist))+".") if x>=xsize-1: ptr,x,y=0,0,y+1 if y>=ysize-1 or len(searchlist)>=MAXOBJ: # we've reached the end of the frame. # Time to clear the last placed object, go back to that x,y if searchlist==[]: g.new("TestPage") g.exit("Search is complete.") x,y,ptr,nearlist,filledlist=searchlist.pop() # no point in looking at configurations with no object on the first line g.new("TestPage") outstr="Total count = " + str(count) t=make_text(outstr,"mono") g.putcells(t,0,-20) for item in sorted(patdict): y=0 t = make_text(item + " ("+str(len(patdict[item]))+")","mono") outstr+="\n" + item + " ("+str(len(patdict[item]))+")" g.putcells(t,x-6,y) y+=30 for pat in patdict[item]: for cell in pat: g.setcell(cell[0]+x,cell[1]+y,1) y+=20 x+=100 g.setclipstr(outstr) g.exit("Search is complete.") So according to this script, there are 226059 different ways to pack blocks, boats, beehives, tubs, ponds, ships and loaves into a 10x7 or smaller rectangle, with no induction allowed (I have to be clear about that, because otherwise the list is much longer, but then constellations are a good bit harder to find a glider recipe for in general, especially a slow recipe). Rotations and reflections count, but translations of smaller bounding boxes inside 10x7 are only counted once, of course. This way it's only necessary to hit all these constellations with gliders from one direction, and we'll have tried everything in this particular search space. If someone could prove me wrong and locate well-spaced packing #226060, I would be most grateful (and I'd fix my script before I try any longer runs.) Also if someone feels like adding blinkers and/or long boats, barges, aircraft carriers, eaters, etc., please go ahead -- it should mostly be a trivial change to the object list, though P2 objects would require a little more work to get the right neighborlist and zonelist. EDIT: Come to think of it, it's just a preliminary objp2 = g.evolve(item, 1) with a rule of B3/S123, before the other two g.evolve steps. Then the patterns would have to be built using objp2list instead of objlist, and the blinkers would come out looking like plus signs and would need some post-processing to produce all 2^(N-1) phase options for N blinkers. Or with a little more work you could get all the phases listed as separate constellation, by adding both blinker phases to the object list but constraining the system to add only phase-0 P2 objects unless a P2 object has previously been added. ---------------------------------------- I doubt I'll attempt anything as big as a 10x10 search -- too many ways to arrange blocks once you can get up to nine of them into the frame. 9x9 might not be too unreasonable, but at some point very soon the script should be altered to dump constellations to a file or files, instead of keeping them all in memory. The primary purpose of all this is to look for a very large volume of cheap glider splitters and glider turners with different timings -- probably using something like a 9x16 rectangle with MAXOBJ=2 or 3. As a byproduct, we might improve a scattering of glider recipes for high-bit-count still lifes, and maybe see a few interesting switch engines as well. I suppose it would be nice to include a check for the same constellation reappearing, unmoved or moved or rotated or with extra junk -- but I think someone else will have to take care of that part of the coding. codeholic Moderator Posts: 1142 Joined: September 13th, 2011, 8:23 am Location: Hamburg, Germany ### Re: Hacking apgsearch I tried to run a dirtily hacked version of apgsearch in the hope to find alternative backends for the pufferfish. Code: Select all diff --git a/apgsearch-2014-10-14-v0.5.py.bak b/apgsearch-2014-10-14-v0.5.py index d06562f..a9a52ab 100755 --- a/apgsearch-2014-10-14-v0.5.py.bak +++ b/apgsearch-2014-10-14-v0.5.py @@ -40,6 +40,8 @@ import hashlib import datetime import os +PUFFERFISH = g.parse('3bo7bo$2b3o5b3o$b2o2bo3bo2b2o$3b3o3b3o2$4bo5bo$2bo2bo3bo2bo$o5bobo5bo$2o4bobo4b2o$6bobo$3bobo3bobo$4bo5bo!') + # Takes approximately 350 microseconds to construct a 16-by-16 soup based # on a SHA-256 cryptographic hash in the obvious way. def hashsoup(instring): @@ -59,7 +61,9 @@ def hashsoup(instring): thesoup.append(k + 8*(j % 2)) thesoup.append(int(j / 2)) - g.putcells(thesoup, -8, -8) + g.putcells(thesoup, 0, 0) + g.putcells(g.transform(thesoup, 0, 0, -1), 0, 0) + g.putcells(PUFFERFISH, -7, -12) # Obtains a canonical representation of any oscillator/spaceship that (in @@ -1180,6 +1184,7 @@ class Soup: "xp46_330279cx1aad3zx4e93x855bcy8cc": ("trans-twin-bees-shuttle", 35), "yl144_1_16_afb5f3db909e60548f086e22ee3353ac": ("block-laying switch engine", 16), "yl384_1_59_7aeb1999980c43b4945fb7fcdb023326": ("glider-producing switch engine", 17), + "yl12_1_8_c7310da81295b6611e6e4e34a80a5523": ("pufferfish", 0), "xp10_9hr": ("[HighLife] p10", 6), "xp7_13090c8": ("[HighLife] p7", 9), "xq48_07z8ca7zy1e531": ("[HighLife] bomber", 9),  Unfortunately, large amount of pufferfish makes it prohibitedly slow (approx. 2 soups per second). Is it possible to tweak it in a way that it would run faster? Ivan Fomichev wildmyron Posts: 1276 Joined: August 9th, 2013, 12:45 am ### Re: Hacking apgsearch codeholic wrote:Unfortunately, large amount of pufferfish makes it prohibitedly slow (approx. 2 soups per second). Is it possible to tweak it in a way that it would run faster? I haven't tried running your version, so my comments are just guesses. Any soup in which the pufferfish survives will run until stabilisation fails, and from your description I imagine that a significant fraction of soups result in an unscathed pufferfish. In this scenario all of the stabilisation tests are time consuming and you're probably better off running the soup for some predetermined number of generations, say 2^15. You can do this by replacing stabilise3() with a single g.step() (with appropriate rule, base and step of course). If this results in a large number of pathological objects being detected, it's because the rest of the soup hasn't stabilised yet and you'll need to increase the step, or disable error correction (set skipErrorCorrection to True). Then, when APGCoalesceObjects and APGClassifyObjects are run, they would run for the maximum allowed which is 2^12. This is completely unnecessary because they only need to run long enough to connect up isolated parts of oscillators and ships, which is guaranteed to happen within one period of the highest period object in the combined ashes (and perhaps a bit longer for APGClassifyObjects where very large objects are present). You could safely reduce stepsize to around 7 and you should get equivalent results. With the replacement of stabilise3() above, you'll need to manually set stepsize instead, so just set it to 6, 7 or 8. You'll also want to remove the conditional test for infinite growth in census() seeing as it's pretty much guaranteed to be present. If you seem to be getting lots of partial objects, you can increase the stepsize to improve object detection. The latest version of the 5S Project contains over 221,000 spaceships. Tabulated pages up to period 160 are available on the LifeWiki. codeholic Moderator Posts: 1142 Joined: September 13th, 2011, 8:23 am Location: Hamburg, Germany ### Re: Hacking apgsearch Thank you for advice! I'll try it out. Ivan Fomichev wildmyron Posts: 1276 Joined: August 9th, 2013, 12:45 am ### Re: Hacking apgsearch codeholic wrote:Thank you for advice! I'll try it out. You're welcome. On reflection, I think that evolving the pattern for 2^12 or 2^13 gen is almost certain to be sufficient, in place of the 2^15 I mentioned above. -------- dvgrn wrote:I'm getting ready to adjust apgsearch-blonksoup to run an exhaustive search on small constellations of common ash objects -- no random sampling, just every possible single-glider collision with every possible well-spaced m-by-n constellation. I'm very interested to see the results of this search when you get to the point of running it. Having less than a million constellations I imagine that it will be pretty quick to run through apgsearch. Might be a different story with additional components / larger area allowed. Have you had any thought to dividing the workload? dvgrn wrote:If someone could prove me wrong and locate well-spaced packing #226060, I would be most grateful (and I'd fix my script before I try any longer runs.) I had a careful look through the output for blocks only, and the output for blocks and beehives in a smaller area. Looks to me as though you've comprehensively enumerated all possible constellations. I also like the way you generate the mask. You may have noticed the block mask in apgsearch-blonksoup is larger than it needs to be. The reason for this is that I didn't see a way to place a new block near an existing blinker using the minimal mask, while ensuring that the blinker in its alternate phase didn't interact with the block. As you allude to above, using a pattern with all active cells (plus sign for the blinker) to check against mask for new objects is a solution to that problem. -------- My work on the version of apgsearch for isotropic, semi-totalistic rules has stalled, but the rule generator is complete. I do intend to get back to this and post the completed project, but in the meantime if anyone is interested I can post the rule generator on its own. The latest version of the 5S Project contains over 221,000 spaceships. Tabulated pages up to period 160 are available on the LifeWiki. dvgrn Moderator Posts: 5904 Joined: May 17th, 2009, 11:00 pm Location: Madison, WI Contact: ### Re: Hacking apgsearch wildmyron wrote: dvgrn wrote:I'm getting ready to adjust apgsearch-blonksoup to run an exhaustive search on small constellations of common ash objects -- no random sampling, just every possible single-glider collision with every possible well-spaced m-by-n constellation. I'm very interested to see the results of this search when you get to the point of running it. Having less than a million constellations I imagine that it will be pretty quick to run through apgsearch. Might be a different story with additional components / larger area allowed. Have you had any thought to dividing the workload? Yes, I did the exhaustive enumeration specifically to make it possible to distribute the work for larger m-by-n. The "easy" way to subdivide the workload would be to do a preliminary run to list all starting constellations with MAXOBJ=1 or 2 or 3 (depending on how many subtasks we want). Then the search from each starting constellation can be run on a separate computer, with the results sent back to a central server. This is just the kind of job that it would be nice to be able to post somewhere as a list of reasonable-sized tasks, along with an associated script. The script could download the next available task, process it, and return the results to the server, which would verify it and remove that task from the list. The server would need the usual reset for stranded jobs -- if a result doesn't come back for a particular task in a reasonable amount of time, make it available again. Probably it wouldn't be worth producing an enumeration of actual constellations this way -- for even moderate-sized m and n, this would be too many gigabytes of data getting collected at one point. Better to report back only the tiny fraction of collisions that are interesting in some way, along the same general lines as apgsearch. ------------------------------ For now, it's a lot easier to keep everything on one computer -- it looks as if with a little patience it will be possible to generate a very nice collection of glider turners and splitters, with the assurance that there are no others that fit inside a given m-by-n rectangle. Part of my motivation for finishing this project has just disappeared, though -- simsim314 just posted a really nice collection of sub-10x10 two-still-life glider splitters on another thread. A for awesome Posts: 1906 Joined: September 13th, 2014, 5:36 pm Location: 0x-1 Contact: ### Re: Hacking apgsearch Hello everyone, I made a hacked version of apgsearch that works on all 2-state isotropic Moore-neighborhood cellular automata (tlife, SansDomino rules, etc.). Here it is: apgsearch-2015-12-17-v0.54+0.1i.py.zip (150.75 KiB) Downloaded 698 times Instructions on how to use it: First, decompress the file (on Mac, clicking on it should work; on Windows, I'm not sure; maybe try right-clicking?). Save a .rule file for the rule you want to census in Golly's Rules folder (the filename minus extension and the rulename must match exactly, even capitalization; trees do not work, only tables). Either drag and drop the icon for the script out of Downloads onto Golly's icon or an open window of Golly; go to the File menu on Golly and select "Run Script..." and find its location; or copy it into Golly's Scripts folder and click on it in a window of Golly. Then, input the number of soups, the seed, the rule (capitalization matters), and the symmetry. It is important that the .rule file be manually put into Golly's Rules folder, otherwise Golly won't be able to find it, and that the table contain no lines that start with variables (don't be fooled by the extraneous code in saveClassifyObjects). Apart from that, not much has changed from the regular apgsearch versions. NOTE: This version does NOT report its findings to Catagolue, as it might break Catagolue's safety measures (I figured I shouldn't test it). The only parts of the code I changed were the comments, the RuleGenerator class (to handle non-totalistic rules), the common_names dict (to recognize some tlife objects), and the object-scoring code (to filter out 2xp160s and possibly p320s in tlife). If there are any bugs, tell me and I will try to fix them. It does run slower than the other versions of apgsearch, because it cannot use HashLife, so has to opt for the (comparatively slower) RuleLoader algorithm. Also, do not try to run it on the rule butterfly, because all of the puffers result in it running about 2 or 3 soups per second. Last edited by A for awesome on December 17th, 2015, 10:29 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 drc Posts: 1664 Joined: December 3rd, 2015, 4:11 pm Location: creating useless things in OCA ### Re: Hacking apgsearch A for awesome wrote:Hello everyone, I made a hacked version of apgsearch that works on all 2-state isotropic Moore-neighborhood cellular automata (tlife, SansDomino rules, etc.). Here it is: apgsearch-2015-12-17-v0.54+0.1i.py.zip Instructions on how to use it: First, decompress the file (on Mac, clicking on it should work; on Windows, I'm not sure; maybe try right-clicking?). Save a .rule file for the rule you want to census in Golly's Rules folder (the filename minus extension and the rulename must match exactly, even capitalization; trees do not work, only tables). Either drag and drop the icon for the script out of Downloads onto Golly's icon or an open window of Golly; go to the File menu on Golly and select "Run Script..." and find its location; or copy it into Golly's Scripts folder and click on it in a window of Golly. Then, input the number of soups, the seed, the rule (capitalization matters), and the symmetry. It is important that the .rule file be manually put into Golly's Rules folder, otherwise Golly won't be able to find it. Apart from that, not much has changed from the regular apgsearch versions. NOTE: This version does NOT report its findings to Catagolue, as it might break Catagolue's safety measures (I figured I shouldn't test it). The only parts of the code I changed were the comments, the RuleGenerator class (to handle non-totalistic rules), the common_names dict (to recognize some tlife objects), and the object-scoring code (to filter out 2xp160s and possibly p320s in tlife). If there are any bugs, tell me and I will try to fix them. It does run slower than the other versions of apgsearch, because it cannot use HashLife, so has to opt for the (comparatively slower) RuleLoader algorithm. Also, do not try to run it on the rule butterfly, because all of the puffers result in it running about 2 or 3 soups per second. I still get the error: line 37 in <module> from glife import rect, pattern ImportError: No module named glife 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 A for awesome Posts: 1906 Joined: September 13th, 2014, 5:36 pm Location: 0x-1 Contact: ### Re: Hacking apgsearch drc wrote: I still get the error: line 37 in <module> from glife import rect, pattern ImportError: No module named glife I don't know exactly what's going on, but my suggestion would be to randomly click on one of Golly's built-in scripts before running the hacked apgsearch, because I remember reading in some other topic about a similar error and that was the solution given. 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 Scorbie Posts: 1389 Joined: December 7th, 2013, 1:05 am ### Re: Hacking apgsearch drc wrote:I still get the error: line 37 in <module> from glife import rect, pattern ImportError: No module named glife That's related to python's importing system. As a permanent fix, copy the glife folder (and its files) to where your script is in. Like this: Code: Select all My_Script_Directory ㄴapgsearch ㄴglife ㄴ__init__.py ㄴ.... Best wishes to you, Scorbie Saka Posts: 3138 Joined: June 19th, 2015, 8:50 pm Location: In the kingdom of Sultan Hamengkubuwono X ### Re: Hacking apgsearch A for awesome wrote:Hello everyone, I made a hacked version of apgsearch that works on all 2-state isotropic Moore-neighborhood cellular automata (tlife, SansDomino rules, etc.). Here it is:(attachment) MAN that is useful! Does it upload the haul to the server? EDIT: It renders this: Code: Select all x = 38, y = 87, rule = tlife 16bo$6b2o7bobo$5bo2bo6bobo$5bobo8bo$6bo7$28b2o$28b2o6$b2o13b3o17bo$o2b o13bo17bobo$b2o32bobo$9b2o25bo$9b2o7$25b2o$25b2o55$17b3o$18bo!

As "oversized"
Airy Clave White It Nay

Code: Select all

x = 17, y = 10, rule = B3/S23
b2ob2obo5b2o$11b4obo$2bob3o2bo2b3o$bo3b2o4b2o$o2bo2bob2o3b4o$bob2obo5b o2b2o$2b2o4bobo2b3o$bo3b5ob2obobo$2bo5bob2o$4bob2o2bobobo!  (Check gen 2) Scorbie Posts: 1389 Joined: December 7th, 2013, 1:05 am ### Re: Hacking apgsearch A for awesome wrote:Hello everyone, I made a hacked version of apgsearch that works on all 2-state isotropic Moore-neighborhood cellular automata (tlife, SansDomino rules, etc.). Here it is: Glad to see this Thanks for your work! (I think wildmyron worked on somthing similar too...?) For some reason, x-rule-pre is REALLY slow... (0 soups/second, took about two hours to process 600 soups.) Is it just my really old computer? Some strange things: 1 )Most of the time apgsearch behaves just like normal apgsearch (I mean flickering), but the screen is empty. (pop=0) 2) There were a whole lot of beehives in the unidentified objects page that shows up after the search is finished. 3) There's xq1_0 that is saved as the following: Code: Select all x = 40, y = 40, rule = x-rule-pre b$
b$b$
b$b$
!
Which comes out empty when opened in golly.

EDIT: More things to note:
No gliders marked as xq
No oscilators noted other than the blinker, which itself is unstable.
Best wishes to you, Scorbie

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

### Re: Hacking apgsearch

Scorbie wrote: For some reason, x-rule-pre is REALLY slow... (0 soups/second, took about two hours to process 600 soups.) Is it just my really old computer? Some strange things:
1 )Most of the time apgsearch behaves just like normal apgsearch (I mean flickering), but the screen is empty. (pop=0)
2) There were a whole lot of beehives in the unidentified objects page that shows up after the search is finished.
3) There's xq1_0 that is saved as the following:

Code: Select all

x = 40, y = 40, rule = x-rule-pre
b$b$
b$b$
b$! Which comes out empty when opened in golly. 1. Wow, that's weird... Maybe I should include a rule to expunge dominoes and duoplets in the next version (maybe also the common x-pre gliders)? 2. No idea what that's about; will try to figure out what's going on. 3. What does the sample soup produce? Is there an unusual oscillator produced? If so, it probably got separated improperly. Would you check whether the rule table is correct? (Same as the one in your Rules folder; no lines starting with variables.) There might be an error pertaining to the ClassifyObjects or ContagiousLife rules; either of those issues could cause that error. 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 Scorbie Posts: 1389 Joined: December 7th, 2013, 1:05 am ### Re: Hacking apgsearch Before any diagnosis, I may have done something wrong when I made that profile thingy. I'll get a new version and run it again... Please wait for a moment... A for awesome wrote:Would you check whether the rule table is correct? (Same as the one in your Rules folder; no lines starting with variables.) There might be an error pertaining to the ClassifyObjects or ContagiousLife rules; either of those issues could cause that erro Yikes. Didn't know that a rule file should not have a line starting with variables... But any variable declaration should start with a variable isn't it? Do you mean that the rule file should have no variables? Best wishes to you, Scorbie Scorbie Posts: 1389 Joined: December 7th, 2013, 1:05 am ### Re: Hacking apgsearch Stripped the last post for clarity. Moved x-rule-pre to Golly's Rules folder instead of my custom rule folder, used vanilla apgsearch hack and umm... Code: Select all Traceback (most recent call last): File "<string>", line 1, in <module> File "/home/scorbie/Apps/golly/Scripts/Perl/apgsearch-2015-12-17-v0.54+0.1i.py", line 11807, in <module> soup.rg.saveAllRules() File "/home/scorbie/Apps/golly/Scripts/Perl/apgsearch-2015-12-17-v0.54+0.1i.py", line 602, in saveAllRules self.saveClassifyObjects() File "/home/scorbie/Apps/golly/Scripts/Perl/apgsearch-2015-12-17-v0.54+0.1i.py", line 1225, in saveClassifyObjects i = lines1[q] IndexError: list index out of range Whoops... Best wishes to you, Scorbie A for awesome Posts: 1906 Joined: September 13th, 2014, 5:36 pm Location: 0x-1 Contact: ### Re: Hacking apgsearch Scorbie wrote:Yikes. Didn't know that a rule file should not have a line starting with variables... But any variable declaration should start with a variable isn't it? Do you mean that the rule file should have no variables? Variable declarations are allowed; and they start with "var", not a variable name. Transitions in the rule table were too hard to implement (I may allow them in the next version). Scorbie wrote:Stripped the last post for clarity. Moved x-rule-pre to Golly's Rules folder instead of my custom rule folder, used vanilla apgsearch hack and umm... Code: Select all Traceback (most recent call last): File "<string>", line 1, in <module> File "/home/scorbie/Apps/golly/Scripts/Perl/apgsearch-2015-12-17-v0.54+0.1i.py", line 11807, in <module> soup.rg.saveAllRules() File "/home/scorbie/Apps/golly/Scripts/Perl/apgsearch-2015-12-17-v0.54+0.1i.py", line 602, in saveAllRules self.saveClassifyObjects() File "/home/scorbie/Apps/golly/Scripts/Perl/apgsearch-2015-12-17-v0.54+0.1i.py", line 1225, in saveClassifyObjects i = lines1[q] IndexError: list index out of range Whoops... No idea what that's about; could you post your .rule file? I will get on it as soon as I have access to a non-school computer; probably about 4 hours from now. P.S. Why did you put it in your Perl scripts folder? It's a Python script! (I don't think it makes any real difference, though.) 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 wildmyron Posts: 1276 Joined: August 9th, 2013, 12:45 am ### Re: Hacking apgsearch Scorbie wrote: A for awesome wrote:Hello everyone, I made a hacked version of apgsearch that works on all 2-state isotropic Moore-neighborhood cellular automata (tlife, SansDomino rules, etc.). Here it is: Glad to see this Thanks for your work! (I think wildmyron worked on somthing similar too...?) Indeed, great to see some interest in this. I have indeed worked on something similar and despite much hesitation I'm just going to post it in it's current state in the hope that it can help further development. I took a different approach to the rule generating - it's quite interesting to see the way this version interprets an existing rule file and generates the auxillary rules from that. Instead I based the rule generator on EricG's rule table generating script for non-totalistic rules "Hensel-TableGen.py". The rule generator class is actually in a separate file which makes it easier to use parts of it for other purposes (e.g. isotropicRulegen.py does basically the same as Hensel-TableGen.py but using the http://www.ibiblio.org/lifepatterns/neighbors2.html version of Hensel's notation. I had intended to seperate the soup generating and censusing code into a separate file as well and then have a totalistic and non-totalistic version of apgsearch with custom code for each and all the common code in separate files, but I'm not very good at finishing off such projects. I have a different version of APG_ExpungeObjects - named APG_ExpungeSmallSL - which handles dominoes and I-trominoes as well as blocks. This file has to be manually copied to the rules folder because it's not created by the rule generator. Another version of that identifies SL checkers instead of I-trominoes. Using the most appropriate expunge rule for the rule being searched is one of the stumbling blocks on my TODO list. Another stumbling block was how to deal with rules with common puffers. As a stop gap I've reduced the maximum step that the auxillary rules run for which reduces the size of the puffers that need to be censused and disabled error correction. Additionally, I believe the stabilisation detection should also be customised for the rule being searched - particularly so that the common oscillator periods don't thwart the stabilisation detection. Those p160 oscillators in tlife are a real headache in that regard. As far as object scoring goes - that's currently a real mess. I was very tempted to remove it completely and just focus on the census results rather than the soups. I've also tried to improve the non-interacting spaceship separation somewhat, but that's still unreliable. As for performance - it's usable for butterfly. I see about 20-30 soups/sec with C1 soups and more for D8_4. Other rules / symmetries are variable in their performance depending on puffer frequency and common oscillator periods. Attachments apgsearch-isotropic-v0.2.zip WIP (20.65 KiB) Downloaded 639 times The latest version of the 5S Project contains over 221,000 spaceships. Tabulated pages up to period 160 are available on the LifeWiki. A for awesome Posts: 1906 Joined: September 13th, 2014, 5:36 pm Location: 0x-1 Contact: ### Re: Hacking apgsearch A for awesome wrote: Scorbie wrote:Moved x-rule-pre to Golly's Rules folder instead of my custom rule folder, used vanilla apgsearch hack and umm... Code: Select all Traceback (most recent call last): File "<string>", line 1, in <module> File "/home/scorbie/Apps/golly/Scripts/Perl/apgsearch-2015-12-17-v0.54+0.1i.py", line 11807, in <module> soup.rg.saveAllRules() File "/home/scorbie/Apps/golly/Scripts/Perl/apgsearch-2015-12-17-v0.54+0.1i.py", line 602, in saveAllRules self.saveClassifyObjects() File "/home/scorbie/Apps/golly/Scripts/Perl/apgsearch-2015-12-17-v0.54+0.1i.py", line 1225, in saveClassifyObjects i = lines1[q] IndexError: list index out of range Whoops... No idea what that's about; could you post your .rule file? I will get on it as soon as I have access to a non-school computer; probably about 4 hours from now. Here's a dirty patch for the errors you are getting: Replace lines 1054 to the end of RuleGenerator.saveContagiousLife() with this: Code: Select all  def saveCoalesceObjects(self): comments = """ A variant of HistoricalLife which separates a field of ash into distinct objects. state 0: vacuum state 1: ON state 2: OFF """ table = "n_states:3\n" table += "neighborhood:Moore\n" if ruletype: #Outer-totalistic table += "symmetries:permute\n\n" table += self.newvars(["a","b","c","d","e","f","g","h","i"], [0, 1, 2]) table += self.newvars(["da","db","dc","dd","de","df","dg","dh","di"], [0, 2]) table += self.newvars(["la","lb","lc","ld","le","lf","lg","lh","li"], [1]) minperc = 10 for i in xrange(9): if (self.bee[i]): if (minperc == 10): minperc = i table += self.scoline("l","d",0,1,i) table += self.scoline("l","d",2,1,i) if (self.ess[i]): table += self.scoline("l","d",1,1,i) table += "\n# Bridge inductors\n" for i in xrange(9): if (i >= minperc): table += self.scoline("l","d",0,2,i) table += self.scoline("","",1,2,0) else: #Isotropic non-totalistic 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" vars2 = [] for i in alpha: if not i in [n[0] for n in vars]: #Create new set of vars for OFF cells table += self.newvars([i + j for j in alpha[:9]], [0, 2]) vars2 = [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 vars2]: for j in xrange(5-len(vars)): table += self.newvar(i + alpha[j], [0, 1, 2]) vars.append(i + alpha[j]) break for i in lines1: q = i.split("#")[0].replace(" ", "").split(",") if len(q) > 1 and not i.startswith("var"): vn = 0 vn2 = 0 for j in q[:-1]: if j == "0": table += vars2[vn2] vn2 += 1 elif j == "1": table += "1" elif j != "#": g.show(str(len(vars))) table += vars[vn] vn += 1 table += "," table += str(2-int(q[len(q)-1])) table += "\n" for i in xrange(256): #Get all B3+ rules ncells = 0 for j in xrange(8): if (i & 2**j) > 0: ncells += 1 if ncells == 3: q = "0," vn = 0 for j in xrange(8): if i & 2**j > 0: q += str((i & 2**j)/2**j) + "," else: q += vars[vn] + "," vn += 1 q += "2\n" table += q colours = """ 0 0 0 0 1 255 255 255 2 127 127 127 """ self.saverule("APG_CoalesceObjects_"+self.alphanumeric, comments, table, colours) def saveClassifyObjects(self): comments = """ This passively classifies objects as either still-lifes, p2 oscillators or higher-period oscillators. It is mandatory that one first runs the rule CoalesceObjects. state 0: vacuum state 1: input ON state 2: input OFF state 3: ON, will die state 4: OFF, will remain off state 5: ON, will survive state 6: OFF, will become alive state 7: ON, still-life state 8: OFF, still-life state 9: ON, p2 oscillator state 10: OFF, p2 oscillator state 11: ON, higher-period object state 12: OFF, higher-period object """ table = "n_states:17\n" table += "neighborhood:Moore\n" if ruletype: #Outer-totalistic table += "symmetries:permute\n\n" table += self.newvars(["a","b","c","d","e","f","g","h","i"], range(0, 17, 1)) table += self.newvars(["la","lb","lc","ld","le","lf","lg","lh","li"], range(1, 17, 2)) table += self.newvars(["da","db","dc","dd","de","df","dg","dh","di"], range(0, 17, 2)) table += self.newvars(["pa","pb","pc","pd","pe","pf","pg","ph","pi"], [0, 3, 4]) table += self.newvars(["qa","qb","qc","qd","qe","qf","qg","qh","qi"], [5, 6]) #Serious modifications necessary: for i in xrange(9): if (self.bee[i]): table += self.scoline("l","d",2,6,i) table += self.scoline("q","p",3,9,i) table += self.scoline("q","p",4,12,i) if (self.ess[i]): table += self.scoline("l","d",1,5,i) table += self.scoline("q","p",5,7,i) table += self.scoline("q","p",6,12,i) table += self.scoline("","",2,4,0) table += self.scoline("","",1,3,0) table += self.scoline("","",5,11,0) table += self.scoline("","",3,11,0) table += self.scoline("","",4,8,0) table += self.scoline("","",6,10,0) else: #Isotropic non-totalistic 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 if lines1[0].startswith("@TREE"): g.warn("apgsearch v.0.54+0.1i does not support rule trees") 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, 5, 6]) 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, 3, 4]) 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 for i in lines1: q = i.split("#")[0].replace(" ", "").split(",") if len(q) > 1: vn = 0 ovn = 0 dvn = 0 if q[0] == "0" or q[0] == "1": if q[0] == "0": table += "2" elif q[0] == "1": table += "1" elif q[0] != "#": table += vars[vn] vn += 1 table += "," for j in q[1:-1]: if j == "0": table += dvars[dvn] dvn += 1 elif j == "1": table += "1" elif j != "#": table += vars[vn] vn += 1 table += "," table += str(4-int(q[0])+2*int(q[len(q)-1])) table += "\n" elif not i.startswith("var"): #Line starts with a variable. table += vars[vn] + "," vn += 1 for j in q[1:-1]: if j == "0": table += dvars[dvn] dvn += 1 elif j == "1": table += "1" elif j != "#": table += vars[vn] vn += 1 table += "," table += str(4+2*int(q[len(q)-1])) table += "\n1," vn = 0 for j in q[1:-1]: if j == "0": table += "2" elif j == "1": table += "1" elif j != "#": table += vars[vn] vn += 1 table += "," table += str(3+2*int(q[len(q)-1])) table += "\n" table += "2," + ",".join(vars[:8]) + ",4\n" table += "1," + ",".join(vars[:8]) + ",5\n" for i in lines1: q = i.split("#")[0].replace(" ", "").split(",") if len(q) > 1: vn = 0 ovn = 0 dvn = 0 if q[0] == "0" or q[0] == "1": table += str(4+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[0] == "0" and q[len(q)-1] == "0": table += "8" if q[0] == "1" and q[len(q)-1] == "0": table += "10" if q[0] == "0" and q[len(q)-1] == "1": table += "12" if q[0] == "1" and q[len(q)-1] == "1": table += "12" table += "\n" elif not i.startswith("var"): #Line starts with a variable. table += "5," 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 += "7" if q[len(q)-1] == "1": table += "11" table += "\n3," 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 += "9" if q[len(q)-1] == "1": table += "11" table += "\n" for i in lines1: q = i.split("#")[0].replace(" ", "").split(",") if len(q) > 1: vn = 0 ovn = 0 dvn = 0 if q[0] == "0" or q[0] == "1": table += str(3+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[0] == "0" and q[len(q)-1] == "0": table += "11" if q[0] == "1" and q[len(q)-1] == "0": table += "11" if q[0] == "0" and q[len(q)-1] == "1": table += "9" if q[0] == "1" and q[len(q)-1] == "1": table += "7" table += "\n" elif not i.startswith("var"): #Line starts with a variable. table += "6," 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 += "12" if q[len(q)-1] == "1": table += "10" table += "\n4," 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 += "8" if q[len(q)-1] == "1": table += "12" table += "\n" table += "4," + ",".join(vars[:8]) + ",8\n" table += "3," + ",".join(vars[:8]) + ",11\n" table += "6," + ",".join(vars[:8]) + ",12\n" table += "5," + ",".join(vars[:8]) + ",7\n" colours = """ 0 0 0 0 1 255 255 255 2 127 127 127 7 0 0 255 8 0 0 127 9 255 0 0 10 127 0 0 11 0 255 0 12 0 127 0 13 255 255 0 14 127 127 0 """ self.saverule("APG_ClassifyObjects_"+self.alphanumeric, comments, table, colours) def savePropagateClassifications(self): comments = """This propagates the result of running ClassifyObjects for two generations. """ table = "n_states:17\n" table += "neighborhood:Moore\n" table += "symmetries:permute\n\n" table += self.newvars(["a","b","c","d","e","f","g","h","i"], range(0, 17, 1)) table += """ 7,11,b,c,d,e,f,g,h,11 7,12,b,c,d,e,f,g,h,11 7,9,b,c,d,e,f,g,h,9 7,10,b,c,d,e,f,g,h,9 8,11,b,c,d,e,f,g,h,12 8,12,b,c,d,e,f,g,h,12 8,9,b,c,d,e,f,g,h,10 8,10,b,c,d,e,f,g,h,10 7,13,b,c,d,e,f,g,h,11 7,14,b,c,d,e,f,g,h,11 8,13,b,c,d,e,f,g,h,14 8,14,b,c,d,e,f,g,h,14 9,13,b,c,d,e,f,g,h,11 9,14,b,c,d,e,f,g,h,11 10,13,b,c,d,e,f,g,h,14 10,14,b,c,d,e,f,g,h,14 9,11,b,c,d,e,f,g,h,11 9,12,b,c,d,e,f,g,h,11 10,11,b,c,d,e,f,g,h,12 10,12,b,c,d,e,f,g,h,12 13,11,b,c,d,e,f,g,h,11 13,12,b,c,d,e,f,g,h,11 14,11,b,c,d,e,f,g,h,12 14,12,b,c,d,e,f,g,h,12 13,9,b,c,d,e,f,g,h,11 14,9,b,c,d,e,f,g,h,12 """ colours = """ 0 0 0 0 1 255 255 255 2 127 127 127 7 0 0 255 8 0 0 127 9 255 0 0 10 127 0 0 11 0 255 0 12 0 127 0 13 255 255 0 14 127 127 0 """ self.saverule("APG_PropagateClassification", comments, table, colours) #foo = "" + 2 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" 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" 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) Frankly, I don't know why that error only showed up in x-rule-pre. Still don't know what else is going on with x-rule-pre, too. 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 drc Posts: 1664 Joined: December 3rd, 2015, 4:11 pm Location: creating useless things in OCA ### Re: Hacking apgsearch Scorbie wrote: drc wrote:I still get the error: line 37 in <module> from glife import rect, pattern ImportError: No module named glife That's related to python's importing system. As a permanent fix, copy the glife folder (and its files) to where your script is in. Like this: Code: Select all My_Script_Directory ㄴapgsearch ㄴglife ㄴ__init__.py ㄴ.... I don't have a glife folder. Mabye somebody can provide it? 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 Scorbie Posts: 1389 Joined: December 7th, 2013, 1:05 am ### Re: Hacking apgsearch Whoops, my bad. it's in Scripts/Python/glife. Best wishes to you, Scorbie Saka Posts: 3138 Joined: June 19th, 2015, 8:50 pm Location: In the kingdom of Sultan Hamengkubuwono X ### Re: Hacking apgsearch wildmyron wrote: Scorbie wrote: A for awesome wrote:Hello everyone, I made a hacked version of apgsearch that works on all 2-state isotropic Moore-neighborhood cellular automata (tlife, SansDomino rules, etc.). Here it is: Glad to see this Thanks for your work! (I think wildmyron worked on somthing similar too...?) Indeed, great to see some interest in this. I have indeed worked on something similar and despite much hesitation I'm just going to post it in it's current state in the hope that it can help further development. I took a different approach to the rule generating - it's quite interesting to see the way this version interprets an existing rule file and generates the auxillary rules from that. Instead I based the rule generator on EricG's rule table generating script for non-totalistic rules "Hensel-TableGen.py". The rule generator class is actually in a separate file which makes it easier to use parts of it for other purposes (e.g. isotropicRulegen.py does basically the same as Hensel-TableGen.py but using the http://www.ibiblio.org/lifepatterns/neighbors2.html version of Hensel's notation. I had intended to seperate the soup generating and censusing code into a separate file as well and then have a totalistic and non-totalistic version of apgsearch with custom code for each and all the common code in separate files, but I'm not very good at finishing off such projects. I have a different version of APG_ExpungeObjects - named APG_ExpungeSmallSL - which handles dominoes and I-trominoes as well as blocks. This file has to be manually copied to the rules folder because it's not created by the rule generator. Another version of that identifies SL checkers instead of I-trominoes. Using the most appropriate expunge rule for the rule being searched is one of the stumbling blocks on my TODO list. I tried it and it said err.png (233.44 KiB) Viewed 33767 times Any fix? Airy Clave White It Nay Code: Select all x = 17, y = 10, rule = B3/S23 b2ob2obo5b2o$11b4obo$2bob3o2bo2b3o$bo3b2o4b2o$o2bo2bob2o3b4o$bob2obo5b
o2b2o$2b2o4bobo2b3o$bo3b5ob2obobo$2bo5bob2o$4bob2o2bobobo!

(Check gen 2)

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

### Re: Hacking apgsearch

Saka wrote:I tried it and it said
Python Error msg wrote:...
g.setrule("APG_ExpungeSmallSL")
RuntimeError: Given rule is not valid in any algorithm.
Any fix?
Earlier, I wrote:...
I have a different version of APG_ExpungeObjects - named APG_ExpungeSmallSL - which handles dominoes and I-trominoes as well as blocks. This file has to be manually copied to the rules folder because it's not created by the rule generator.
...
The rule file is in the zip file. Copy it to your rules folder and try again.
The latest version of the 5S Project contains over 221,000 spaceships. Tabulated pages up to period 160 are available on the LifeWiki.