Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Random crashing when compiling rule #18

Open
dragoncoder047 opened this issue May 4, 2022 · 6 comments
Open

Random crashing when compiling rule #18

dragoncoder047 opened this issue May 4, 2022 · 6 comments

Comments

@dragoncoder047
Copy link

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
Copy link
Owner

supposedly commented May 5, 2022

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 added a commit to dragoncoder047/wiki that referenced this issue May 5, 2022
@dragoncoder047
Copy link
Author

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

@dragoncoder047
Copy link
Author

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 😄

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
Copy link
Author

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
Copy link
Author

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
Copy link
Owner

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:

class AlternatingPermute(ExplicitPermute):
"""
Permutational symmetry, but only between cells perpendicular to one
another in the Moore neighborhood. (both orthogonal and diag cells)
e.g. `0,1,2,3,4,5,6,7` is "symmetric" to `2,5,0,1,4,7,6,3`
More specifically, this is permutational symmetry between two groups
of cells, one group being every second cell in a napkin and the other
the rest.
In vonNeumann neighborhood, permutes between opposing cells.
"""
RECENTS = {}
HASHES = {}
neighborhoods = Any
fallback = {Any: Rotate4Reflect, hexagonal: NoSymmetry}
@LazyProperty
def expanded(self):
t = orth, diag = map(tuple, map(sorted, (self[::2], self[1::2])))
if t in self.RECENTS:
self._hash = self.HASHES[t]
return self.RECENTS[t]
self.RECENTS[t] = ret = [tuple(chain.from_iterable(zip(i, j))) for i in permutations(orth) for j in permutations(diag)]
self.HASHES[t] = self._hash = hash(tuple(sorted(ret)))
return ret
@staticmethod
def special(values, length):
permute_sp, length = ExplicitPermute.special, length // 2
orth, diag = values[::2], values[1::2]
return chain.from_iterable(zip(permute_sp(orth, length), permute_sp(diag, length)))

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 added a commit to dragoncoder047/wiki that referenced this issue May 10, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants