Mercio’s Algorithm (2012) for Rational
Tree Compare is specified here mathematically.
It is based on computing truncations A' = (A_0,
A_1, etc..) of a rational tree A:
A < B ⟺ A′ <_lex B′
https://math.stackexchange.com/a/210730
Here is an implementation in Prolog.
First the truncation:
trunc(_, T, T) :- var(T), !.
trunc(0, T, F) :- !, functor(T, F, _).
trunc(N, T, S) :-
M is N-1,
T =.. [F|L],
maplist(trunc(M), L, R),
S =.. [F|R].
And then the iterative deepening:
mercio(N, X, Y, C) :-
trunc(N, X, A),
trunc(N, Y, B),
compare(D, A, B),
D \== (=), !, C = D.
mercio(N, X, Y, C) :-
M is N + 1,
mercio(M, X, Y, C).
The main entry first uses (==)/2 for a
terminating equality check and if the
rational trees are not equal, falls back
to the iterative deepening:
mercio(C, X, Y) :- X == Y, !, C = (=).
mercio(C, X, Y) :- mercio(0, X, Y, C).
I couldn’t find yet a triple that violates
transitivity. But I am also not much happy
with the code. Looks a little bit expensive
to create a truncation copy iteratively.
Provided there is really no counter example,
maybe we can do mit more smart and faster? It
might also stand the test of conservativity?
Now question is whether compare_rat/2 can
be extended to a total order or not. On
the positive side we find that a partial
order can always be extended:
Szpilrajn Extension Theorem https://en.wikipedia.org/wiki/Szpilrajn_extension_theorem
But what if compare_rat/2 by @kuniaki.mukai
is not a partial order? What if it is only a
preorder, or even worse only a binary relation.
Returning 4 values doesn’t guarantee that it
is a partial order. We have help from here:
Szpilrajn, Arrow and Suzumura https://onlinelibrary.wiley.com/doi/abs/10.1111/j.1467-999X.2011.04130.x
A binary relation needs to be Suzumura
consistent, so that it can be extended
into a total order. And compare_rat/2 is
not Suzumura consistent, as the following
cycle a < c < b < a shows:
/* Not SWI, Windows Console is SNAFU */
?- repeat, fuzzy(A), fuzzy(C),
compare_rat(_X, A, C), _X = (<),
fuzzy(B), compare_rat(_Y, C, B), _Y = (<),
compare_rat(_Z, B, A), _Z = (<).
A = s(s(A, A), 1), _A = s(_A, s(_, 1)), C = s(_A, _),
_B = s(1, _B), B = s(B, s(1, _B))
Was only testing with compare_rat/3, but
the theorem applies also to other compare
proposals, and can be used to exclude
them, as soon as a Suzumura inconsistency is found.
Mercio’s Algorithm (2012) for Rational
Tree Compare is specified here mathematically.
It is based on computing truncations A' = (A_0,
A_1, etc..) of a rational tree A:
A < B ⟺ A′ <_lex B′
https://math.stackexchange.com/a/210730
Here is an implementation in Prolog.
First the truncation:
trunc(_, T, T) :- var(T), !.
trunc(0, T, F) :- !, functor(T, F, _).
trunc(N, T, S) :-
M is N-1,
T =.. [F|L],
maplist(trunc(M), L, R),
S =.. [F|R].
And then the iterative deepening:
mercio(N, X, Y, C) :-
trunc(N, X, A),
trunc(N, Y, B),
compare(D, A, B),
D \== (=), !, C = D.
mercio(N, X, Y, C) :-
M is N + 1,
mercio(M, X, Y, C).
The main entry first uses (==)/2 for a
terminating equality check and if the
rational trees are not equal, falls back
to the iterative deepening:
mercio(C, X, Y) :- X == Y, !, C = (=).
mercio(C, X, Y) :- mercio(0, X, Y, C).
I couldn’t find yet a triple that violates
transitivity. But I am also not much happy
with the code. Looks a little bit expensive
to create a truncation copy iteratively.
Provided there is really no counter example,
maybe we can do mit more smart and faster? It
might also stand the test of conservativity?
I see it as fuzzy testing of the community.
It is certainly beneficial if used correctly
You can use Fuzzy Testing also for
benchmarking. Not only to find faults.
For example when I benchmark mercio/3 via
fuzzy/1, I find it doesn’t fare extremly bad:
?- time((between(1,100,_), mercio, fail; true)).
% 4,386,933 inferences, 0.375 CPU in 0.376 seconds (100% CPU, 11698488
Lips)
true.
And I am not using some of the optimization
that @kuniaki.mukai posted elsewhere and that
I posted 06.08.2025 on comp.lang.prolog. Fact is,
it only ca. 20% slower than SWI-Prologs compare/3:
?- time((between(1,100,_), swi, fail; true)).
% 3,786,880 inferences, 0.312 CPU in 0.325 seconds (96% CPU, 12118016 Lips) true.
The test harness was:
swi :-
between(1,1000,_),
fuzzy(X), fuzzy(Y),
swi(_, X, Y), fail; true.
mercio :-
between(1,1000,_),
fuzzy(X), fuzzy(Y),
mercio(_, X, Y), fail; true.
The difficulty was to find a 100% Prolog compare/3
that corresponds to SWI-Prolog. But you find a
fresh implementation in 100% Prolog using a Union
Find structure in the below:
% swi(-Atom, +Term, +Term)
swi(C, X, Y) :-
swi(X, Y, C, [], _).
% swi( -Atom, +Term, +Term,+List, -List)
swi(C, X, Y, L, R) :- compound(X), compound(Y), !,
sys_union_find(X, L, Z),
sys_union_find(Y, L, T),
swi_found(C, Z, T, L, R).
swi(X, Y, C, L, L) :- compare(C, X, Y).
% swi_found(-Atom, +Term, +Term, +List, -List)
swi_found(C, X, Y, L, L) :-
same_term(X, Y), !, C = (=).
swi_found(C, X, Y, _, _) :-
functor(X, F, N),
functor(Y, G, M),
compare(D, N/F, M/G),
D \== (=), !, C = D.
swi_found(C, X, Y, L, R) :-
X =.. [_|P],
Y =.. [_|Q],
foldl(swi(C), P, Q, [X-Y|L], R).
% sys_union_find(+Term, +List, -Term)
sys_union_find(X, L, T) :-
member(Y-Z, L),
same_term(X, Y), !,
sys_union_find(Z, L, T).
sys_union_find(X, _, X).
I like the vibe, clearing the mind of everything
existing has a touch of a mystic human being living
an eremitic solitary vocation on a far out mountain
top. Using the internet only to emit his wisdom,
but not to ingest the outer world, just as in
Thus Spoke Zarathustra (*). Another name for Fuzzy Testing,
if the outcome is not finding the needle in the haystack,
but rather producing quantitative outcomes is,
unless of course you were living in a submerged pineapple (**):
Monte Carlo methods
or Monte Carlo experiments, are a broad class of
computational algorithms that rely on repeated random
sampling to obtain numerical results https://en.wikipedia.org/wiki/Monte_Carlo_method
(*)
Also Sprach Zarathustra, Op. 30 - Strauss https://www.youtube.com/watch?v=dfe8tCcHnKY
(**)
Every Time Patrick Was Actually Smart https://www.youtube.com/watch?v=siBRUuDxU1E
I see it as fuzzy testing of the community.
It is certainly beneficial if used correctly
Fuzzy Testing goes also by the name QuickCheck.
You can use Fuzzy Testing also for benchmarking.
Mathematically it uses the Law of Large Numbers:
Law of large numbers
https://en.wikipedia.org/wiki/Law_of_large_numbers
Means you even don’t need a random generator
with a programmable seed, so that a comparison
involves the exact same random number sequences.
Just assume that your results have a variation σ.
Then most likely the overall variation decreases
proportionally to the number n of experiments,
i.e. gets washed out:
VAR(X) = σ^2 / n
A third use case of Fuzzy Testing is to determine
frequentist probabilities . Like when I determined
that 25% of a variant of @kuniaki.mukai compare/3
triples are not transitive.
Mild Shock schrieb:
You can use Fuzzy Testing also for
benchmarking. Not only to find faults.
For example when I benchmark mercio/3 via
fuzzy/1, I find it doesn’t fare extremly bad:
?- time((between(1,100,_), mercio, fail; true)).
% 4,386,933 inferences, 0.375 CPU in 0.376 seconds (100% CPU, 11698488
Lips)
true.
And I am not using some of the optimization
that @kuniaki.mukai posted elsewhere and that
I posted 06.08.2025 on comp.lang.prolog. Fact is,
it only ca. 20% slower than SWI-Prologs compare/3:
?- time((between(1,100,_), swi, fail; true)).
% 3,786,880 inferences, 0.312 CPU in 0.325 seconds (96% CPU, 12118016
Lips)
true.
The test harness was:
swi :-
between(1,1000,_),
fuzzy(X), fuzzy(Y),
swi(_, X, Y), fail; true.
mercio :-
between(1,1000,_),
fuzzy(X), fuzzy(Y),
mercio(_, X, Y), fail; true.
The difficulty was to find a 100% Prolog compare/3
that corresponds to SWI-Prolog. But you find a
fresh implementation in 100% Prolog using a Union
Find structure in the below:
% swi(-Atom, +Term, +Term)
swi(C, X, Y) :-
swi(X, Y, C, [], _).
% swi( -Atom, +Term, +Term,+List, -List)
swi(C, X, Y, L, R) :- compound(X), compound(Y), !,
sys_union_find(X, L, Z),
sys_union_find(Y, L, T),
swi_found(C, Z, T, L, R).
swi(X, Y, C, L, L) :- compare(C, X, Y).
% swi_found(-Atom, +Term, +Term, +List, -List)
swi_found(C, X, Y, L, L) :-
same_term(X, Y), !, C = (=).
swi_found(C, X, Y, _, _) :-
functor(X, F, N),
functor(Y, G, M),
compare(D, N/F, M/G),
D \== (=), !, C = D.
swi_found(C, X, Y, L, R) :-
X =.. [_|P],
Y =.. [_|Q],
foldl(swi(C), P, Q, [X-Y|L], R).
% sys_union_find(+Term, +List, -Term)
sys_union_find(X, L, T) :-
member(Y-Z, L),
same_term(X, Y), !,
sys_union_find(Z, L, T).
sys_union_find(X, _, X).
| Sysop: | Keyop |
|---|---|
| Location: | Huddersfield, West Yorkshire, UK |
| Users: | 716 |
| Nodes: | 16 (2 / 14) |
| Uptime: | 52:11:49 |
| Calls: | 12,115 |
| Calls today: | 6 |
| Files: | 15,010 |
| Messages: | 6,518,584 |
| Posted today: | 1 |