Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 59 additions & 0 deletions examples/test_alpha_unique_atom.metta
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
; Strong test suite for alpha-unique-atom

; 1 Basic duplicates with different variables
!(test (=alpha (alpha-unique-atom ((link $x human) (link $y human) (link $z human)))
((link $a human)))
True)

!(test (=alpha (alpha-unique-atom ((parent $a human) (parent $b human) (child $c human)))
((parent $d human) (child $e human)))
True)

; 2 Different functors (should all remain)
!(test (=alpha (alpha-unique-atom ((parent $x human) (child $y human) (friend $z human)))
((parent $a human) (child $b human) (friend $c human)))
True)

!(test (=alpha (alpha-unique-atom ((likes $x) (hates $y) (knows $z)))
((likes $a) (hates $b) (knows $c)))
True)

; 3 Nested structures
!(test (=alpha (alpha-unique-atom ((link (foo $x) human) (link (foo $y) human) (link (bar $z) human)))
((link (foo $a) human) (link (bar $b) human)))
True)

!(test (=alpha (alpha-unique-atom ((parent (child $x) human) (parent (child $y) human) (parent (child $x) human)))
((parent (child $a) human)))
True)

; 4 Mix of unique and duplicates
!(test (=alpha (alpha-unique-atom ((link $x human) (parent $x human) (link $y human) (parent $z human) (link $x human)))
((parent $a human) (link $b human)))
True)

!(test (=alpha (alpha-unique-atom ((foo $x) (foo $y) (bar $x) (foo $x) (bar $y)))
((foo $a) (bar $b)))
True)

; 5 Numbers and atoms
!(test (=alpha (alpha-unique-atom (1 2 2 3 1 4 4 5))
(2 3 1 4 5))
True)

!(test (=alpha (alpha-unique-atom (a b a c b d e a))
(c b d e a))
True)
Comment on lines +40 to +46
Copy link

Copilot AI Mar 27, 2026

Choose a reason for hiding this comment

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

The expected results here (e.g., (1 2 2 3 1 4 4 5) -> (2 3 1 4 5) and (a b a c b d e a) -> (c b d e a)) encode “keep last occurrence” semantics. If alpha-unique-atom is meant to mirror unique-atom and only change the equality notion (as described in the PR), these expectations should be updated to match first-occurrence preservation instead.

Copilot uses AI. Check for mistakes.

; 6 Empty and single-element lists
!(test (=alpha (alpha-unique-atom ())
())
True)

!(test (=alpha (alpha-unique-atom (1))
(1))
True)

!(test (=alpha (alpha-unique-atom ((link $x human)))
((link $a human)))
True)
16 changes: 15 additions & 1 deletion src/metta.pl
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,20 @@
first([A, _], A).
'second-from-pair'([_, A], A).
'unique-atom'(A, B) :- list_to_set(A, B).
'alpha-unique-atom'(A, B) :- alpha_list_to_set(A, B).
Copy link

Copilot AI Mar 27, 2026

Choose a reason for hiding this comment

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

Unlike unique-atom/2 (list_to_set/2), alpha-unique-atom/2 will simply fail if A is not a proper list (because alpha_list_to_set/2 only matches []/[H|T]) rather than raising a type error. If callers rely on the existing error behavior for invalid inputs, consider adding explicit list validation (e.g., must_be(list, A)) so alpha-unique-atom behaves consistently with unique-atom.

Suggested change
'alpha-unique-atom'(A, B) :- alpha_list_to_set(A, B).
'alpha-unique-atom'(A, B) :- must_be(list, A), alpha_list_to_set(A, B).

Copilot uses AI. Check for mistakes.
% Helper: like list_to_set/2 but uses =@= (structural equality)
alpha_list_to_set([], []).
alpha_list_to_set([H|T], R) :-
( alpha_member_eq(H, T) ->
alpha_list_to_set(T, R)
;
alpha_list_to_set(T, RT),
Comment on lines +118 to +122
Copy link

Copilot AI Mar 27, 2026

Choose a reason for hiding this comment

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

alpha_list_to_set/2 currently removes an element if an alpha-equivalent one exists later in the list, which means it keeps the last occurrence of each equivalence class. This differs from unique-atom (list_to_set/2), which keeps the first occurrence, and it contradicts the PR description that “only the equality notion” changes. Consider rewriting alpha_list_to_set/2 to scan left-to-right while tracking already-seen alpha-variants so the first representative is preserved (or update the docs/tests if last-occurrence semantics are intended).

Copilot uses AI. Check for mistakes.
R = [H|RT]
).
Comment on lines +117 to +124
Copy link

Copilot AI Mar 27, 2026

Choose a reason for hiding this comment

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

alpha_list_to_set/2 performs an O(n^2) pairwise scan (alpha_member_eq/2 for each element). If alpha-unique-atom is expected to run on large atom lists (e.g., reasoning outputs), this could become a hot spot compared to the built-in list_to_set/2. Consider using a canonicalized representation for alpha-equivalence (e.g., copy_term + numbervars) and tracking seen keys in an assoc/dict to get closer to O(n).

Copilot uses AI. Check for mistakes.

% Checks if X is structurally equal to any element in the list
alpha_member_eq(X, [H|_]) :- X =@= H, !.
alpha_member_eq(X, [_|T]) :- alpha_member_eq(X, T).
'sort-atom'(List, Sorted) :- msort(List, Sorted).
'size-atom'(List, Size) :- length(List, Size).
'car-atom'([H|_], H).
Expand Down Expand Up @@ -271,7 +285,7 @@
register_fun(N) :- (fun(N) -> true ; assertz(fun(N))).
:- maplist(register_fun, [superpose, empty, let, 'let*', '+','-','*','/', '%', min, max, 'change-state!', 'get-state', 'bind!',
'<','>','==', '!=', '=', '=?', '<=', '>=', and, or, xor, implies, not, sqrt, exp, log, cos, sin,
'first-from-pair', 'second-from-pair', 'car-atom', 'cdr-atom', 'unique-atom',
'first-from-pair', 'second-from-pair', 'car-atom', 'cdr-atom', 'unique-atom', 'alpha-unique-atom',
repr, repra, parse, 'println!', 'readln!', test, assert, 'mm2-exec', atom_concat, atom_chars, copy_term, term_hash,
foldl, first, last, append, length, 'size-atom', sort, msort, member, 'is-member', 'exclude-item', list_to_set, maplist, eval, reduce, 'import!',
'add-atom', 'remove-atom', 'get-atoms', match, 'is-var', 'is-expr', 'is-space', 'get-mettatype',
Expand Down
Loading