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