Title: Benchmark: C-based pair-stack vs. Automaton-based comparison for rational trees
Hi all,
I would like to share a brief benchmark comparison between different rational tree comparison implementations on SWI-Prolog.
Benchmark Setup
% ===================================================================
% Benchmark: fast_rt_compare vs fast_rt_min_compare vs rt_compare
% ===================================================================
% ?- benchmark_compare(1000000).
%@ Generating test terms...
%@ @(S_1,[S_1=h(h(h(h(S_1,S_1,S_1),h(S_1,S_1,S_1),g(S_1,S_1,S_1),h(S_1,S_1,S_1,S_1))),h(h(f(S_1,S_1,S_1),h(S_1)),f(g(S_1,S_1,S_1,S_1,S_1)),h(g(S_1,S_1),g(S_1,S_1,S_1,S_1,S_1))),h(h(h(S_1),h(S_1,S_1,S_1),f(S_1,S_1,S_1),h(S_1,S_1,S_1,S_1,S_1),h(S_1,S_1,S_1,S_1)),f(h(S_1,S_1),g(S_1),h(S_1,S_1,S_1))),h(h(g(S_1,S_1,S_1),g(S_1,S_1,S_1,S_1,S_1)),f(f(S_1,S_1,S_1),h(S_1),h(S_1,S_1,S_1,S_1,S_1)),h(f(S_1,S_1,S_1))),g(g(h(S_1,S_1,S_1,S_1,S_1),h(S_1,S_1,S_1,S_1,S_1),g(S_1,S_1,S_1,S_1),f(S_1),f(S_1,S_1)),h(f(S_1),h(S_1,S_1,S_1,S_1,S_1),f(S_1,S_1,S_1),f(S_1,S_1)),h(h(S_1,S_1,S_1,S_1,S_1),h(S_1,S_1,S_1,S_1,S_1),g(S_1,S_1),h(S_1,S_1,S_1),f(S_1)),h(f(S_1,S_1),f(S_1),g(S_1,S_1,S_1),g(S_1,S_1,S_1)),h(g(S_1),h(S_1,S_1,S_1,S_1),f(S_1,S_1))))])
%@ @(S_1,[S_1=f(h(f(g(S_1,S_1,S_1)),h(g(S_1,S_1,S_1),f(S_1,S_1))),f(f(f(S_1,S_1,S_1),g(S_1,S_1,S_1)),g(f(S_1,S_1,S_1,S_1)),h(h(S_1,S_1,S_1),g(S_1,S_1,S_1,S_1),f(S_1,S_1,S_1),f(S_1)),h(g(S_1,S_1),f(S_1,S_1),f(S_1,S_1,S_1,S_1),f(S_1,S_1)),f(g(S_1,S_1,S_1),f(S_1,S_1,S_1,S_1))),f(f(g(S_1,S_1,S_1,S_1)),f(h(S_1),g(S_1,S_1),f(S_1,S_1,S_1),g(S_1,S_1,S_1,S_1)),h(g(S_1,S_1,S_1,S_1,S_1),f(S_1,S_1),g(S_1,S_1)),g(f(S_1,S_1,S_1),f(S_1,S_1),h(S_1,S_1,S_1,S_1),f(S_1,S_1,S_1))),h(h(h(S_1,S_1),g(S_1,S_1)),f(g(S_1,S_1,S_1,S_1,S_1),h(S_1),f(S_1,S_1)),g(h(S_1,S_1),h(S_1,S_1,S_1,S_1),f(S_1,S_1),h(S_1,S_1),h(S_1)),f(g(S_1,S_1,S_1,S_1,S_1))))])
%@
%@ --- 1. fast_rt_compare (C stack, raw terms) [1000000 iterations] ---
%@ % 11,999,999 inferences, 5.831 CPU in 5.853 seconds (100% CPU, 2057990 Lips)
%@
%@ --- 2. fast_rt_min_compare (C stack, with minimization) [1000000 iterations] ---
%@ % 17,999,999 inferences, 16.863 CPU in 16.918 seconds (100% CPU, 1067431 Lips)
%@
%@ --- 3. rt_compare (raw automaton) [1000000 iterations] ---
%@ % 2,999,999 inferences, 0.296 CPU in 0.297 seconds (99% CPU, 10142019 Lips)
%@
%@ --- 4. rt_compare (minimized automaton) [1000000 iterations] ---
%@ % 2,999,999 inferences, 0.294 CPU in 0.296 seconds (100% CPU, 10189349 Lips)
%@ true.
```
### Notes
* Once converted into automaton tables outside the loop, `rt_compare/5` runs very fast (\~0.34s / 1M calls), with essentially no speed difference between raw and minimized tables.
* For direct term comparison, `fast_rt_compare/3` (without prior minimization) runs about 2x faster than `fast_rt_min_compare/3`.
* In a separate consistency test over 1,000,000 random cyclic term pairs, `fast_rt_compare/3` and `fast_rt_min_compare/3` produced identical ordering results in all cases.
Just sharing the benchmark data for reference.
Best regards,
Kuniaki Mukai
EDIT 2026/10
I would like to report the results of this experiment on the rational tree ordering:
Minimization via Jan's automaton_minimal/3 turned out to be strictly essential.
I have not yet analyzed why term_automaton/2 alone unexpectedly fails transitivity.
This update is a C implementation of my earlier Prolog prototypes that satisfied transitivity.
The algorithm uses cycle length information, though it remains unclear to me why incorporating cycle length is so effective.