simon-git: tilings (main): Simon Tatham
Commits to Tartarus hosted VCS
tartarus-commits at lists.tartarus.org
Sun Jun 30 18:51:01 BST 2024
TL;DR:
692e46e Self-test mode: report statistics and benchmarks.
9058303 dsf: make unify() say whether it changed anything.
0324f89 dsf: provide a unify_all() convenience method.
0753fae dsf: promote canonical() to an external API method.
c0dd8ab --adjmatcher: make sure to output states in sensible order.
c343917 adjmatcher: enumerate all unaccepted input prefixes.
2f30e56 New DSF-based algorithm to generate adjmatchers.
Repository: https://git.tartarus.org/simon/tilings.git
On the web: https://git.tartarus.org/?p=simon/tilings.git
Branch updated: main
Committer: Simon Tatham <anakin at pobox.com>
Date: 2024-06-30 18:51:01
commit 692e46ece4407ed1c56b928de8391fcd3cc27c04
web diff https://git.tartarus.org/?p=simon/tilings.git;a=commitdiff;h=692e46ece4407ed1c56b928de8391fcd3cc27c04;hp=72b3832067a6ec0ba531b1219c2eb2e656bdd600
Author: Simon Tatham <anakin at pobox.com>
Date: Sun Jun 30 13:52:18 2024 +0100
Self-test mode: report statistics and benchmarks.
Now we find out how many states each machine has, and also how long it
took to build.
toplevel.sage | 11 +++++++----
1 file changed, 7 insertions(+), 4 deletions(-)
commit 9058303f775676280bc329463f5819c76571eabc
web diff https://git.tartarus.org/?p=simon/tilings.git;a=commitdiff;h=9058303f775676280bc329463f5819c76571eabc;hp=692e46ece4407ed1c56b928de8391fcd3cc27c04
Author: Simon Tatham <anakin at pobox.com>
Date: Sun Jun 30 14:52:29 2024 +0100
dsf: make unify() say whether it changed anything.
This enables client code to tell whether it's iterated to a fixed
point, without having to count the number of classes separately in
each pass.
dsf.py | 3 +++
1 file changed, 3 insertions(+)
commit 0324f890468046e6e70195597486ab1f9773291a
web diff https://git.tartarus.org/?p=simon/tilings.git;a=commitdiff;h=0324f890468046e6e70195597486ab1f9773291a;hp=9058303f775676280bc329463f5819c76571eabc
Author: Simon Tatham <anakin at pobox.com>
Date: Sun Jun 30 14:53:35 2024 +0100
dsf: provide a unify_all() convenience method.
If you have more than two things you want to consider equal, it's nice
if the loop over all of them is hidden away in the implementation.
Of course, this also propagates the boolean return value from the
previous commit, indicating whether any classes were actually newly
merged.
dsf.py | 13 +++++++++++++
1 file changed, 13 insertions(+)
commit 0753fae14c029a480baf7ab887afabfdeeef3d0b
web diff https://git.tartarus.org/?p=simon/tilings.git;a=commitdiff;h=0753fae14c029a480baf7ab887afabfdeeef3d0b;hp=0324f890468046e6e70195597486ab1f9773291a
Author: Simon Tatham <anakin at pobox.com>
Date: Sun Jun 30 14:54:28 2024 +0100
dsf: promote canonical() to an external API method.
I've never been quite sure whether 'return a canonical element of this
equivalence class' ought to be part of the dsf API. The problem with
it is that the output can go stale: as soon as you merge two classes,
the canonical values you previously had for those classes aren't
necessarily valid any more (indeed, at least one _definitely_ is not).
So the argument goes: if you can instead call equivalent(a,b) then
that will always look up the _current_ canonical values.
But I've now come up with a case where there just isn't a nice way to
write it without canonical(), so I'll just have to remember to be
careful :-)
dsf.py | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
commit c0dd8ab511ca7dc2add2eb4010c68d622e9c91a4
web diff https://git.tartarus.org/?p=simon/tilings.git;a=commitdiff;h=c0dd8ab511ca7dc2add2eb4010c68d622e9c91a4;hp=0753fae14c029a480baf7ab887afabfdeeef3d0b
Author: Simon Tatham <anakin at pobox.com>
Date: Sun Jun 30 13:10:40 2024 +0100
--adjmatcher: make sure to output states in sensible order.
am.transitions is a dict with integer keys, which gives no guarantee
that iterating over its .items() will return the keys in ascending
order. Somehow it's been working anyway until now, but I think only
by luck. Sort them on purpose for display.
toplevel.sage | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
commit c34391726a76d52801eeb179ac93b72d220c3711
web diff https://git.tartarus.org/?p=simon/tilings.git;a=commitdiff;h=c34391726a76d52801eeb179ac93b72d220c3711;hp=c0dd8ab511ca7dc2add2eb4010c68d622e9c91a4
Author: Simon Tatham <anakin at pobox.com>
Date: Sun Jun 30 13:36:27 2024 +0100
adjmatcher: enumerate all unaccepted input prefixes.
The search in find_unaccepted_inputs() will deliver a finite number of
results, because it's enumerating a finite state machine (which is in
turn the product of two other machines). Each output is a prefix of an
infinite set of input strings.
This is much nicer as diagnostic output for a failed attempt to build
an adjacency matcher.
(However, it may be completely pointless. I wrote this in order to use
it in a new shinier adjmatcher-construction algorithm, but ended up
not using it, _and_ the new algorithm handles all the tilings I have.
So this may never be used! But having written it, we might as well
keep it.)
toplevel.sage | 12 ++++++++----
transducer.sage | 12 ++++++------
2 files changed, 14 insertions(+), 10 deletions(-)
commit 2f30e561c27b05a690c5e1fb8bb068f1067b59b1
web diff https://git.tartarus.org/?p=simon/tilings.git;a=commitdiff;h=2f30e561c27b05a690c5e1fb8bb068f1067b59b1;hp=c34391726a76d52801eeb179ac93b72d220c3711
Author: Simon Tatham <anakin at pobox.com>
Date: Sun Jun 30 15:30:19 2024 +0100
New DSF-based algorithm to generate adjmatchers.
This is a little bit faster than the old one: by a factor of 3 in the
worst case of the old algorithm (hats-hhtpfff.tl used to take 33.5s
and now takes 10.5s), but usually by less than that.
But much more importantly, it successfully builds adjacency matchers
for _everything_, even the hard cases: it handles the H7/H8 pair
(whose very long spurs previously defeated me), and it handles
p2-whole and p3-whole. I was previously experimenting with a geometric
approach that managed p2-whole, but not p3-whole, and was amazingly
slow besides. So I'm really pleased to have an approach that works for
everything _and_ is fast!
The p2-whole and p3-whole adjmatchers also admit transducers, so this
is the most practical algorithm I have yet for plotting Penrose tilings.
The new adjmatcher constructor works by actually running the recursive
coordinate transition algorithm to compute pairs of valid inputs and
outputs. Then it constructs an initial state machine on the suffixes
of those string pairs. E.g. if string ABC maps to DEF (where the
symbols A,D would each be a (tile,edge) pair and B,C,E,F would all
be (parent tile type, child index)), then we'd make the following
transitions:
- from START, on (A,D), go to (ABC,DEF)
- from there, on (B,E), go to (BC,EF)
- from there, on (C,F), go to an accepting state for the common tile
part of symbols C and F.
Then we incrementally build an equivalence relation on those states,
where the equivalence criterion is 'do these states specify a pair of
tiles in the same geometric relationship?' But we don't have to
actually compute any geometry to do it. We just use the idea that a
given (tile, child index) symbol specifies a fixed geometric
relationship between a tile and its parent. Therefore, if states S,S'
transition on identical symbol pairs to T,T', and S,S' are equivalent,
we can mark T,T' as also equivalent. Conversely, if the destination
states T,T' were equivalent then we can mark S,S' as equivalent too.
The only question is how long a set of input coordinate pairs we might
have to generate before iterating to closure. The answer turns out to
be finite in all cases, even the ones I previously thought of as too
hard!
One effect of this new algorithm is that the 'winnowing' step in the
previous setup isn't needed any more. The previous algorithm would
trace forward from START, constructing any states it could reach, and
some of them would turn out to be dead ends that could never reach
acceptance; the winnowing step deleted any state with that property,
so that non-adjacent inputs to the matcher could be rejected as early
as possible, and conversely, the resulting transducer would produce
every output symbol as early as possible. But this algorithm is based
entirely on input sequences of symbols that get all the way from START
to an accepting state, so dead ends are never constructed in the first
place. Therefore, I've removed --no-winnow from the command line
syntax. But AdjacencyMatcher.winnow() still exists and does nothing,
so that client code that was calling it can continue to run.
toplevel.sage | 33 ++--
transducer.sage | 528 +++++++++++++++++++++++++++++---------------------------
2 files changed, 290 insertions(+), 271 deletions(-)
More information about the tartarus-commits
mailing list