Skip to content

Fix TypeError sorting Orderless patterns that mix atoms and literal expressions - #1991

Open
tombouctou wants to merge 1 commit into
Mathics3:masterfrom
tombouctou:fix-orderless-literal-pattern-sort
Open

tombouctou wants to merge 1 commit into
Mathics3:masterfrom
tombouctou:fix-orderless-literal-pattern-sort

Conversation

@tombouctou

Copy link
Copy Markdown
Collaborator

Since #1987, a literal ExpressionPattern sorts by (MAGIC_ATOM_SORT_KEY, element_order), while an atom pattern uses BASIC_ATOM_PATTERN_SORT_KEY = (MAGIC_ATOM_SORT_KEY, 0, 0). The two keys share the same first element, so sorting the elements of an Orderless pattern that contains both compares 0 with a tuple:

In[1]:= MatchQ[2 x[3], 2 x[3]]
TypeError: '<' not supported between instances of 'tuple' and 'int'

The same crash happens for any assignment or replacement whose left-hand side contains such a pattern, e.g. f[2 x[3]] = 1 or f[x[3] + 2] = 1. On 10.0.1 these work.

This PR keeps the literal-expression key in the shape (magic, int, ...), with 1 in the second slot. Atoms (0) still sort before literal expressions, and two literal expressions are still ordered by element_order, as #1987 intended.

Tests: new cases in test/builtin/test_testing_expressions.py (test_matchq) and test/builtin/test_patterns.py (test_pattern). They fail on current master and pass with this change.

🤖 Generated with Claude Code

…xpressions

Since Mathics3#1987 a literal ExpressionPattern sorts by
(MAGIC_ATOM_SORT_KEY, element_order), while atoms use
(MAGIC_ATOM_SORT_KEY, 0, 0). Both share the magic number, so sorting
the elements of an Orderless pattern such as 2 x[3] compares 0 with a
tuple: MatchQ[2 x[3], 2 x[3]] raises TypeError.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@rocky

rocky commented Oct 16, 2026 •

Copy link
Copy Markdown
Member

This bug is clearly something I introduced when removing numeric-only methods on an element.
Correction: I was thinking of #1992. But similar idea.

The only reason I hesitate is that this is the first batch of Claude Code-generated PRs. Or at least of this number and magnitude; and we've not said anything publicly about the policy.

My own take is that using Claude Code is okay, provided that, as before, people (and reviewers) take responsibility for the results produced. But I was holding off until hearing from @mmatera

@mmatera: your thoughts?

I'll be going over each PR, which may take a little time. (This one was immediately obvious, though.)

And thanks for all of the fixes.

@tombouctou

Copy link
Copy Markdown
Collaborator Author

Thanks for looking at it so quickly, and for being open about the policy question. That's fair.

To be clear on our side: I take responsibility for these PRs as the person submitting them. Claude Code does much of the work and every PR says so, but what goes out is something we have checked and stand behind. We put particular effort into validating each change:

  • A minimal reproduction first. Every fix starts from a small example written from scratch, never from the code that exposed it. It goes into the tests, and we confirm the new tests fail on master and pass with the fix.
  • The full suites on every PR. pytest and the doctests are run before each PR; we only open it when the results are the same as on master.
  • WMA behavior from the documentation. We have no Mathematica here. Where the expected behavior is in question, we take it from the WMA reference pages, and any differences we don't resolve are listed in the PR rather than glossed over.
  • One topic per PR, kept small, so each can be reviewed on its own.
  • End-to-end checks against an independent implementation. All the fixes are also merged on a branch of our fork, and real code runs on it there.

That last check comes from what these PRs are for. We are trying to run Neil Strickland's Mathematica package for Toda's tables of unstable homotopy groups of spheres (strickland1.org/toda) unmodified in Mathics3. Toda.m builds a rule base of about 960 relations, LambdaAlgebra.m computes in the lambda algebra, and LambdaData.m is a 10 MB file written by Save. We also wrote an independent Python port of the package, so Mathics3's answers can be checked against it.

With the fixes from the open PRs:

The lambda algebra homology, computed with the new Modulus option, matches Strickland's own Mathematica results exactly in every tridegree checked so far.

There's no rush on our side; please review at whatever pace suits you. If you'd prefer them in a different form, say fewer at a time or grouped differently, just tell us.

And thanks for Mathics3; the package was a good fit for it.

@mmatera

mmatera commented Oct 16, 2026

Copy link
Copy Markdown
Contributor

This bug is clearly something I introduced when removing numeric-only methods on an element. Correction: I was thinking of #1992. But similar idea.

The only reason I hesitate is that this is the first batch of Claude Code-generated PRs. Or at least of this number and magnitude; and we've not said anything publicly about the policy.

My own take is that using Claude Code is okay, provided that, as before, people (and reviewers) take responsibility for the results produced. But I was holding off until hearing from @mmatera

@mmatera: your thoughts?

I'll be going over each PR, which may take a little time. (This one was immediately obvious, though.)

And thanks for all of the fixes.

I join in the thanks for trying the code and for looking for ways to improve it.

Regarding the AI code, in particular, I am fine with using Claude, Deepseek, or any other AI-generated code, as long as humans (us) review it. The main risk would be flooding our reviewing capacity (which is something that is happening in many other areas), but in this case, most of the proposed changes are relatively small and self-contained, so I think we can handle it.

("f[10]", None, "100", None),
("f[10, Power -> 3]", None, "1000", None),
("Clear[f]", None, None, None),
# Orderless literal pattern mixing an atom and an expression

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here and on 179, it would be nice to put this comment inside the assert fail message (fail_msg or last argument). That way, when something fails, the message indicates the kind of thing that failed.

# here too, or sorting an Orderless pattern mixing both fails.
return (
BASIC_LITERAL_EXPRESSION_PATTERN_SORT_KEY,
1,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of magic number 1, we should define a constant like BASIC_LITERAL_EXPRESSION_SECOND_SLOT = 1 in mathics.core.keycomparable

def _build_pattern_sort_key(self) -> tuple:
if self.isliteral:
return (BASIC_LITERAL_EXPRESSION_PATTERN_SORT_KEY, self.expr.element_order)
# Keep the shape of BASIC_ATOM_PATTERN_SORT_KEY (magic, int, ...):

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense.

@mmatera

mmatera commented Oct 16, 2026

Copy link
Copy Markdown
Contributor

Probably the implementation of the fix would be changed when I finish with the rule ordering refactor. But the new tests are good, so I am happy to merge this.
LGTM

This branch has not been deployed

No deployments
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

Successfully merging this pull request may close these issues.

3 participants