Skip to content

unique fix#153

Merged
patham9 merged 1 commit into
trueagi-io:mainfrom
zariuq:fix/unique
Apr 2, 2026
Merged

unique fix#153
patham9 merged 1 commit into
trueagi-io:mainfrom
zariuq:fix/unique

Conversation

@zariuq
Copy link
Copy Markdown
Contributor

@zariuq zariuq commented Mar 29, 2026

Claude found odd behavior in unique while testing CeTTa.

Fix: unique now works on all expressions, not just (superpose ...)

The bug

rewrite_streamops only handled (unique (superpose ...)). Any other argument — let, match, if, backward chainer results — returned unreduced (unique X) wrapper atoms instead of deduplicated
results.

Before:

!(collapse (unique (let $x (superpose (1 2 1 3 2)) (pair $x $x))))
;; → ((unique (pair 1 1)) (unique (pair 2 2)) (unique (pair 1 1)) (unique (pair 3 3)) (unique (pair 2 2)))

After:
!(collapse (unique (let $x (superpose (1 2 1 3 2)) (pair $x $x))))
;; → ((pair 1 1) (pair 2 2) (pair 3 3))

The fix

Two lines in src/translator.pl:

-rewrite_streamops([unique, [superpose|Args]],
-                  [call, [superpose, ['unique-atom', [collapse, [superpose|Args]]]]]).
+rewrite_streamops([unique, Arg],
+                  [call, [superpose, ['unique-atom', [collapse, Arg]]]]).

[unique, [superpose|Args]] → [unique, Arg]. Accept any unary argument, not just superpose bodies.

Edge case testing

┌────────────────────────┬───────────────────────────────────────────────────────────────────┬────────────────────────────────────┬─────────────────────────────┐
│          Test          │                               Input                               │               Output               │           Status            │
├────────────────────────┼───────────────────────────────────────────────────────────────────┼────────────────────────────────────┼─────────────────────────────┤
│ superpose (old case)   │ (unique (superpose (a b a c b)))                                  │ a b c                              │ ✓ same as before            │
├────────────────────────┼───────────────────────────────────────────────────────────────────┼────────────────────────────────────┼─────────────────────────────┤
│ let+superpose (fixed)  │ (collapse (unique (let $x (superpose (1 2 1 3 2)) (pair $x $x)))) │ ((pair 1 1) (pair 2 2) (pair 3 3)) │ ✓ was broken                │
├────────────────────────┼───────────────────────────────────────────────────────────────────┼────────────────────────────────────┼─────────────────────────────┤
│ collapse (single list) │ (unique (collapse (superpose (a b a))))                           │ (a b a)                            │ ✓ collapse returns one atom │
├────────────────────────┼───────────────────────────────────────────────────────────────────┼────────────────────────────────────┼─────────────────────────────┤
│ single atom            │ (unique x)                                                        │ x                                  │ ✓                           │
├────────────────────────┼───────────────────────────────────────────────────────────────────┼────────────────────────────────────┼─────────────────────────────┤
│ nested unique          │ (unique (unique (superpose (a b a))))                             │ a b                                │ ✓                           │
├────────────────────────┼───────────────────────────────────────────────────────────────────┼────────────────────────────────────┼─────────────────────────────┤
│ match dedup            │ (collapse (unique (match &self (fact $x) $x)))                    │ (a b)                              │ ✓                           │
├────────────────────────┼───────────────────────────────────────────────────────────────────┼────────────────────────────────────┼─────────────────────────────┤
│ no duplicates          │ (unique (superpose (a b c)))                                      │ a b c                              │ ✓                           │
├────────────────────────┼───────────────────────────────────────────────────────────────────┼────────────────────────────────────┼─────────────────────────────┤
│ if expression          │ (collapse (unique (if True (superpose (a a b)) ...)))             │ (a b)                              │ ✓                           │
└────────────────────────┴───────────────────────────────────────────────────────────────────┴────────────────────────────────────┴─────────────────────────────┘
 Why this is safe

The rewrite produces collapse Arg → unique-atom → superpose for ANY Arg. On the old handled case (superpose body), this is identical output. On new cases, collapse captures all nondeterministic results,
unique-atom (list_to_set/2) deduplicates, superpose re-emits. The arity-1 match [unique, Arg] correctly rejects 0-arg and 2+-arg forms.

Discovered while running a WM-PLN backward chaining benchmark over 1.4M genomic atoms — unique inside collapse was returning 34 "unique" hypotheses instead of the correct 8.

Copy link
Copy Markdown
Collaborator

@patham9 patham9 left a comment

Choose a reason for hiding this comment

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

Thank you so much for this fix, and also for your systematic summary on the issue!!

@patham9 patham9 merged commit 5caeee5 into trueagi-io:main Apr 2, 2026
5 checks passed
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.

2 participants