supposedly / nutshell

[alpha!] [dormant!] An advanced cellular-automaton-specification language that transpiles to Golly's.
GNU General Public License v3.0
16 stars 4 forks source link

Random crashing when compiling rule #18

Open dragoncoder047 opened 2 years ago

dragoncoder047 commented 2 years ago

Github actions run: https://github.com/dragoncoder047/wiki/runs/6294632444?check_suite_focus=true#step:5:46 Nutshell file: https://github.com/dragoncoder047/wiki/blob/deadc2fc9702ebc98649487d18e433b8c1ef035e/Fusion.ruel

Traceback (most recent call last):
  ... 4 frames omitted ...
  File "/opt/hostedtoolcache/Python/3.9.12/x64/lib/python3.9/site-packages/nutshell/main.py", line 60, in _main
    for val in res:
  File "/opt/hostedtoolcache/Python/3.9.12/x64/lib/python3.9/site-packages/nutshell/main.py", line 33, in _transpile
    finished = transpile(infp, find=args.find)
  File "/opt/hostedtoolcache/Python/3.9.12/x64/lib/python3.9/site-packages/nutshell/main.py", line 19, in transpile
    parsed = segmentor.parse(fp)
  File "/opt/hostedtoolcache/Python/3.9.12/x64/lib/python3.9/site-packages/nutshell/segmentor.py", line 66, in parse
    segments[label] = converter(seg, seg_lno, **(annot and {'dep': [segments.get(i) for i in annot]}))
  File "/opt/hostedtoolcache/Python/3.9.12/x64/lib/python3.9/site-packages/nutshell/segment_types/table/table.py", line 111, in __init__.<listcomp>
    self.final = [new_tr for tr in self._data for new_tr in tr.in_symmetry(MinSym)]
  File "/opt/hostedtoolcache/Python/3.9.12/x64/lib/python3.9/site-packages/nutshell/segment_types/table/_classes.py", line 376, in in_symmetry.<listcomp>
    return [self.fix_final([initial, *i, resultant]) for i in distinct(NewSymmetry(j) for j in self.symmetries(napkin).expand())]
  File "/opt/hostedtoolcache/Python/3.9.12/x64/lib/python3.9/site-packages/nutshell/common/utils.py", line 89, in distinct
    if i not in seen:
  File "/opt/hostedtoolcache/Python/3.9.12/x64/lib/python3.9/site-packages/nutshell/segment_types/table/_napkins.py", line 51, in __hash__
    self._hash = hash(tuple(sorted(self.expanded_unique)))
  File "/opt/hostedtoolcache/Python/3.9.12/x64/lib/python3.9/site-packages/nutshell/common/utils.py", line 25, in __get__
    ret = self.method(obj)
  File "/opt/hostedtoolcache/Python/3.9.12/x64/lib/python3.9/site-packages/nutshell/segment_types/table/_napkins.py", line 65, in expanded_unique
    return distinct(self.expanded)
  File "/opt/hostedtoolcache/Python/3.9.12/x64/lib/python3.9/site-packages/nutshell/segment_types/table/_napkins.py", line 158, in expanded
    return (tup for i in self.rotated4() for tup in self.reflection_of(i))
  File "/opt/hostedtoolcache/Python/3.9.12/x64/lib/python3.9/site-packages/nutshell/segment_types/table/_napkins.py", line 78, in rotated4
    return sorted(self.rotate(4))
  File "/opt/hostedtoolcache/Python/3.9.12/x64/lib/python3.9/site-packages/nutshell/segment_types/table/_napkins.py", line 61, in rotate
    return map(self.rotate_by, range(0, len(self), len(self) // n))
ValueError: range() arg 3 must not be zero

Interesting how the commit hash starts with dead, because that's what Nutshell is. I have no idea why Nutshell crashed and need a little help fixing my ruel file if the problem is in there.

supposedly commented 2 years ago

Hi, thanks for opening this! Nutshell's definitely dead or dormant until I rewrite it in a statically-typed language one of these days, but I still try my best to address issues in the meantime. This looks like an error Nutshell was supposed to intercept and explain in a friendly manner, but it slipped through for some reason or another (so that's on me, my bad).

The crash comes from lines 62 and 63 of Fusion.ruel, where it's complaining that the neighborhood (or specifically the "napkin", in my old terminology...) hasn't been filled out all the way. When it interprets those two lines, Nutshell won't use any to fill in the cellstates you haven't specified. It'll only do that if you specifically tell it to, as in:

NTAAWire, (anyhead - anyNTAA) ~ 1, any; NTAAHead0
NTAAWire, (anyhead - anyNTAA) ~ 2, any; NTAAHead1

That should fix it. Let me know if it still doesn't compile and I'll take a look again.

This sort of explicitness definitely isn't a main design principle of Nutshell's (regrettably!), so I understand if this feels inconsistent or arbitrary. If that mythical rewrite ever materializes, it'll cut down considerably on all the weird+inconsistent shorthands and magical/implicit screwery. In its absence, though, feel free to ask stuff like this on here or on Discord as much as you need.

dragoncoder047 commented 2 years ago

Great, it compiled okay. (The little red X is because I had a typo. I fixed it and now it works.)

dragoncoder047 commented 2 years ago

Nutshell's definitely dead or dormant until I rewrite it in a statically-typed language one of these days

While I'm thinking of it, no, I don't think you'll need to rewrite Nutshell in a statically typed language. Python has "type annotations" that are completely ignored by CPython when it runs the code, but a static type checker like Mypy can catch type mismatches and complain before you even run the code. And that way all you'll have to rewrite is the type annotations :smile:

def foo(bar: int, baz: str):
    pass

# This runs okay, but Mypy complains
foo('not a number', 23)

Full disclosure: I've never used Mypy before, so I have no idea how it actually works. But all it would probably entail is setting up a Github Action that runs Mypy whenever you push new changes, and then shows a check or an X next to the commit if there are type mismatch errors.

dragoncoder047 commented 2 years ago

Oh, jeez, I made some more changes and broke Nutshell again:

https://github.com/dragoncoder047/wiki/blob/dce04d365c5119f2cc20c56252b92646cebc6ebe/Fusion.ruel

https://github.com/dragoncoder047/wiki/runs/6305775977?check_suite_focus=true#step:5:7


Traceback (most recent call last):
    ... 4 frames omitted ...
  File "/opt/hostedtoolcache/Python/3.9.12/x64/lib/python3.9/site-packages/nutshell/main.py", line 66, in main
    _main()
  File "/opt/hostedtoolcache/Python/3.9.12/x64/lib/python3.9/site-packages/nutshell/main.py", line 60, in _main
    for val in res:
  File "/opt/hostedtoolcache/Python/3.9.12/x64/lib/python3.9/site-packages/nutshell/main.py", line 33, in _transpile
    finished = transpile(infp, find=args.find)
Parsing...
  File "/opt/hostedtoolcache/Python/3.9.12/x64/lib/python3.9/site-packages/nutshell/main.py", line 19, in transpile
    parsed = segmentor.parse(fp)
  File "/opt/hostedtoolcache/Python/3.9.12/x64/lib/python3.9/site-packages/nutshell/segmentor.py", line 66, in parse
    segments[label] = converter(seg, seg_lno, **(annot and {'dep': [segments.get(i) for i in annot]}))
  File "/opt/hostedtoolcache/Python/3.9.12/x64/lib/python3.9/site-packages/nutshell/segment_types/table/table.py", line 99, in __init__
    self._data = transformer.transform(_parsed)
  File "/opt/hostedtoolcache/Python/3.9.12/x64/lib/python3.9/site-packages/nutshell/segment_types/table/lark_assets/parser.py", line 436, in transform
    return self._transform_tree(tree)
  File "/opt/hostedtoolcache/Python/3.9.12/x64/lib/python3.9/site-packages/nutshell/segment_types/table/lark_assets/parser.py", line 432, in _transform_tree
    children = list(self._transform_children(tree.children))
  File "/opt/hostedtoolcache/Python/3.9.12/x64/lib/python3.9/site-packages/nutshell/segment_types/table/lark_assets/parser.py", line 423, in _transform_children
    yield self._transform_tree(c)
  File "/opt/hostedtoolcache/Python/3.9.12/x64/lib/python3.9/site-packages/nutshell/segment_types/table/lark_assets/parser.py", line 432, in _transform_tree
    children = list(self._transform_children(tree.children))
  File "/opt/hostedtoolcache/Python/3.9.12/x64/lib/python3.9/site-packages/nutshell/segment_types/table/lark_assets/parser.py", line 423, in _transform_children
    yield self._transform_tree(c)
  File "/opt/hostedtoolcache/Python/3.9.12/x64/lib/python3.9/site-packages/nutshell/segment_types/table/lark_assets/parser.py", line 433, in _transform_tree
    return self._call_userfunc(tree, children)
  File "/opt/hostedtoolcache/Python/3.9.12/x64/lib/python3.9/site-packages/nutshell/segment_types/table/lark_assets/parser.py", line 397, in _call_userfunc
    return f.visit_wrapper(f, tree.data, children, tree.meta)
  File "/opt/hostedtoolcache/Python/3.9.12/x64/lib/python3.9/site-packages/nutshell/segment_types/table/lark_assets/parser.py", line 680, in _vargs_meta
    return f(children, meta)   # TODO swap these for consistency? Backwards incompatible!
  File "/opt/hostedtoolcache/Python/3.9.12/x64/lib/python3.9/site-packages/nutshell/segment_types/table/lark_assets/parser.py", line 660, in f
    return _f(self, *args, **kwargs)
  File "/opt/hostedtoolcache/Python/3.9.12/x64/lib/python3.9/site-packages/nutshell/segment_types/table/_transformer.py", line 255, in main.<listcomp>
    seq = [self.unravel_permute(i, meta) for i in children]
  File "/opt/hostedtoolcache/Python/3.9.12/x64/lib/python3.9/site-packages/nutshell/segment_types/table/lark_assets/parser.py", line 660, in f
    return _f(self, *args, **kwargs)
  File "/opt/hostedtoolcache/Python/3.9.12/x64/lib/python3.9/site-packages/nutshell/segment_types/table/_transformer.py", line 102, in unravel_permute
    fix(tree.loc.ctx),
AttributeError: 'TransitionState' object has no attribute 'loc'
dragoncoder047 commented 2 years ago

Made some more changes and I am still getting the same AttributeError: 'TransitionState' object has no attribute 'loc' error. What does this mean is wrong with my Nutshell file?

supposedly commented 2 years ago

Hi, just got the chance to look at this. It's the same thing again where it was trying to throw a formatted error but ran into a Python exception first :( In this case, the error it was trying to throw is:

  SyntaxErr in @TABLE, line 46:
      NTAAWire, N NTAATail; NTAAWire
               ^^^
  Cannot specify compass directions under nutshell.AlternatingPermute symmetries

This is just bad design, hah... that error was originally used for the normal symmetries: permute, which makes sense because permute is directionless, so the compass-direction notation doesn't make as much sense as for non-permute symmetries. But copying that logic over unthinkingly to AlternatingPermute is nonsense...

In keeping with that theme, AlternatingPermute as a whole is designed kind of confusingly. In the neighborhood/napkin part of an AlternatingPermute transition, the index of a cellstate determines what cells it covers: odd indices cover the orthogonal cells (considering the first cellstate in the neighborhood/napkin to be #1), meaning the von-Neumann neighborhood, and even indices cover the diagonal cells. In other words, every second cellstate starting from the beginning covers the orthogonal cells, and every second cellstate starting from the next one covers the diagonal ones. But you can still use the tilde shorthand on top of this: for example, an AlternatingPermute transition that goes 0, 1 ~ 4, 2 ~ 4, 3; 0 means...

2 1 2
1 0 1
2 1 2

...and an AlternatingPermute transition that goes 0, 1 ~ 2, 2 ~ 3, 3 ~ 2, 4; 0 might look like...

4 1 2
3 0 1
2 3 2

Hope that makes it less impenetrable. With that said, I have two workarounds for now. The first would be to play by AlternatingPermute's rules:

## replaces lines 42–72 of the Fusion.rule from commit 686f0e1 ##

symmetries: nutshell.AlternatingPermute

# NEVER put a head where there would be an adjacent tail
# w, t, any ~ 3; w
NTAAWire, NTAATail, any ~ 4, any ~ 3; NTAAWire
# this will cover the napkins:
# . t .    . . .    . . .    . . .
# . w .    . w t    . w .    t w .
# . . .    . . .    . t .    . . .
# the `NTAATail` and the `any ~ 3` are together: they cover the orthogonal cells
# the `any ~ 4`'s domain is the diagonal cells

symmetries: rotate4reflect

# Split at T
# w, w, h, w, --wht; [2]
NTAAWire, N NTAAWire, E anyNTAAHead, S NTAAWire, W --anyNTAA; [E]

symmetries: nutshell.AlternatingPermute

# Signals wait at intersections
# w, w ~ 2, any ~ 2; w
NTAAWire, NTAAWire ~ 2, any ~ 4, any ~ 2; NTAAWire
# this will cover the napkins:
# . w .    . . .    . . .    . w .    . w .    . . .
# . w w    . w w    w w .    w w .    . w .    w w w
# . . .    . w .    . w .    . . .    . w .    . . .
# the `NTAAWire ~ 2` and the `any ~ 2` are together: they cover the orthogonal cells
# the `any ~ 4`'s domain is the diagonal cells

# Sum=1 signal combination

# w, h1, h1, any ~ 2; h0
NTAAWire, NTAAHead1 ~ 2, any ~ 4, any ~ 2; NTAAHead0
# this will cover the napkins:
#  .  h1 .        .  .  .        .  .  .        .  h1 .        .  h1 .        .  .  .
#  .  w  h1       .  w  h1       h1 w  .        h1 w  .        .  w  .        h1 w  h1
#  .  .  .        .  h1 .        .  h1 .        .  .  .        .  h1 .        .  .  .
# the `NTAAHead1 ~ 2` and the `any ~ 2` are together: they cover the orthogonal cells
# the `any ~ 4`'s domain is the diagonal cells

# w, h, h0, --h1 ~ 2; [1]
NTAAWire, anyNTAAHead, any ~ 2, NTAAHead0, any ~ 2, --NTAAHead1 ~ 2; [1]
# the `anyNTAAHead`, `NTAAHead0`, and `--NTAAHead1 ~ 2` are together: they cover the orthogonal cells
# then the `any ~ 2`s' domain is the diagonal cells, and we had to have two of them to
# be able to specify different values for the orthogonal cells
# (we could've also replaced the first `any ~ 2` with `any` and the second one with `any ~ 3`,
# or the first with `any ~ 3` and the second with `any`, etc. -- important thing for AlternatingPermute
# is just to have *something* at those indices in the transition)

# Signals
# w, h, --h ~ 3; [1]
NTAAWire, anyNTAAHead, any ~ 2, --anyNTAAHead ~ 3, any ~ 2; [1]
# h, --w ~ 4; t
anyNTAAHead, --NTAAWire ~ 4, any ~ 4; NTAATail
# t, --h ~ 4; w
NTAATail, --anyNTAAHead ~ 4, any ~ 4; NTAAWire

Note that applying these changes makes way for another transpiler error later on in the file, which Nutshell is also unfortunately unable to actually format/display correctly, but it's:

  SyntaxErr in @TABLE, line 121:
      (NTAAWire, NTAATail), N --anyNTAA, E --anyNTAA, S --anyNTAA, W --anyNTAA; NTAAHead0
                            ^^^^^^^^^^^
  Cannot specify compass directions under permute symmetries

Let me know if I should take a look at it too or if it's easier for you to fix now.

The second workaround I had in mind would be to follow these instructions to create your own AlternatingPermute symmetry that works with compass directions by removing the special() method from the original: https://github.com/supposedly/nutshell/blob/ddd9aff37ab6e32ab86ae380c44533c5d8542f47/nutshell/common/symmetries.py#L79-L110

Once you remove that method, Nutshell will stop thinking of it as a symmetry type you have to use tildes rather than compass directions for. If you'd like to go with this rather than the above, let me know and I'll try it out myself so I can provide better help.

dragoncoder047 commented 1 week ago

old issue but now all I can get is this error, nothing works:

Traceback (most recent call last):
  File "/opt/hostedtoolcache/Python/3.10.15/x64/lib/python3.10/runpy.py", line 187, in _run_module_as_main
    mod_name, mod_spec, code = _get_module_details(mod_name, _Error)
  File "/opt/hostedtoolcache/Python/3.10.15/x64/lib/python3.10/runpy.py", line 146, in _get_module_details
    return _get_module_details(pkg_main_name, error)
  File "/opt/hostedtoolcache/Python/3.10.15/x64/lib/python3.10/runpy.py", line 110, in _get_module_details
    __import__(pkg_name)
  File "/opt/hostedtoolcache/Python/3.10.15/x64/lib/python3.10/site-packages/nutshell/__init__.py", line 3, in <module>
    from .segment_types.table import _napkins as napkin
  File "/opt/hostedtoolcache/Python/3.10.15/x64/lib/python3.10/site-packages/nutshell/segment_types/__init__.py", line 3, in <module>
    from .table import TableSegment
  File "/opt/hostedtoolcache/Python/3.10.15/x64/lib/python3.10/site-packages/nutshell/segment_types/table/__init__.py", line 1, in <module>
    from .table import *
  File "/opt/hostedtoolcache/Python/3.10.15/x64/lib/python3.10/site-packages/nutshell/segment_types/table/table.py", line 29, in <module>
    class Bidict(bidict.bidict):
  File "/opt/hostedtoolcache/Python/3.10.15/x64/lib/python3.10/site-packages/nutshell/segment_types/table/table.py", line 30, in Bidict
    on_dup = bidict.OnDup(val=bidict.DROP_NEW, kv=bidict.DROP_NEW)
TypeError: OnDup.__new__() got an unexpected keyword argument 'kv'

from the stack, it happens when you run import nutshell. I guess a dependency got updated and broke stuff?

supposedly commented 1 week ago

I guess a dependency got updated and broke stuff

I don't know why I never thought to pin any of the deps in requirements.txt. That would fix it, if you want to look into what the right version strings are and open a PR I'd appreciate it but otherwise I'll get to it this week

supposedly commented 1 week ago

Does this work?

dragoncoder047 commented 1 week ago

funny, I reran the GitHub action and the command literally does git clone https://github.com/supposedly/nutshell.git && cd nutshell && pip install -U . and it installed bidict 0.23.1.

Will investigate tomorrow