• Scryer Prolog has the most useless max_depth (Re: Novacore goes Bisimulation: Scryer Prolog is Slow!)

    From Mild Shock@janburse@fastmail.fm to comp.lang.prolog on Sat Aug 2 13:43:23 2025
    From Newsgroup: comp.lang.prolog


    Take this cute example:

    ?- [user].
    dfa(Q0, [Q3,Q4]) :-
    Q0 = f(Q1, Q2),
    Q1 = f(Q3, Q2),
    Q2 = f(Q1, Q4),
    Q4 = f(Q1, Q4),
    Q3 = f(Q3, Q2).

    Try this example in Scryer-Prolog:

    /* Scryer Prolog 0.9.4-547 */
    ?- dfa(X, Y).
    %%% tons and tons of print out (...)))),f(f(f(...,f(...)),f(f(...),...)),f(f(...,...), f(f(...),...)))),f(f(f(f(...,f(...)),f(...,...)), f(f(...,f(...)),f(f(...),...))),f(f(f(...,f(...)),f(...,...)), f(f(...,f(...)),f(f(...),...)))))))))))))))))))].

    Was more expecting something like

    /* SWI-Prolog 9.3.26 */
    ?- dfa(X, Y).
    X = f(f(_S1, _S3), _S3), % where
    _S1 = f(_S1, _S3),
    _S2 = f(f(_S1, _S3), _S2),
    _S3 = f(f(_S1, _S3), _S2),
    Y = [_S1, _S2].

    Mild Shock schrieb:
    Hi,

    Having fun with Bisimulation, and a new test
    suite of nasty circular pairs. But how store
    circular pairs, if clauses do not support

    circular terms. Well chop it up into equations,
    I create 1000 such equation pairs:

    test([A = c(A, B), C = c(A, D), E = n, _ = c(F, B),
    -a-a-a-a-a F = c(C, C), G = c(G, D), D = c(E, C), B = n],
    -a-a-a-a [H = c(H, I), J = c(K, I), L = c(L, I), I = c(M, N),
    -a-a-a-a-a O = c(K, J), N = n, K = c(K, J), M = c(K, O)]).
    Etc..

    The pairs are nasty because the usual compare_with_stack/2
    chokes on them. Here some results:

    /* SWI-Prolog 9.3.26 */
    ?- time((between(1,30,_), part, fail; true)).
    % 540,118 inferences, 0.047 CPU in 0.041 seconds (115% CPU, 11522517 Lips) true.

    /* Trealla Prolog 2.78.40 */
    ?- time((between(1,30,_), part, fail; true)).
    % Time elapsed 0.113s, 1143903 Inferences, 10.157 MLips
    -a-a true.

    /* Scryer Prolog 0.9.4-417 */
    ?- time((between(1,30,_), part, fail; true)).
    -a-a % CPU time: 0.226s, 1_117_809 inferences
    -a-a true.

    /* Dogelog Player 1.3.5 */
    ?- time((between(1,30,_), part2, fail; true)).
    % Zeit 309 ms, GC 0 ms, Lips 8693718, Uhr 25.07.2025 13:47
    true.

    The amazing thing is, I compared a 100% Prolog
    implementation, so there is a lot of head room
    for improvement:

    part2 :-
    -a-a bitest(X,Y), X ~~ Y, fail; true.

    The operator (~~)/2 is part of library(math),
    and has been implemented with same_term/2 so far.

    Bye


    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From Mild Shock@janburse@fastmail.fm to comp.lang.prolog on Sat Aug 2 14:45:45 2025
    From Newsgroup: comp.lang.prolog

    Hi,

    Since the pairs example doesn't really feature
    deep unification, going native gives only a speed-up
    of a factor two. The reason is that for small

    examples the linear search association map in the
    100% Prolog implementation, fares as good as a
    hash table based associaton map in a native

    implementation. We nevertheless traded (~)/2 and
    (~~)/2 for native implementations (=)/2 and (==)/2
    which is are ca 2-times faster in the given examples.

    Some fine tuning in the future might maybe give better results,
    but here are the newest comparisons for your enjoyment.
    It seems we clearly beat Scryer Prolog, but stiil have

    SWI-Prolog and Trealla Prolog in front of us:

    /* SWI-Prolog 1.3.5 */

    ?- time((between(1,30,_), unify, fail; true)).
    % 570,118 inferences, 0.047 CPU in 0.042 seconds (113% CPU, 12162517 Lips)
    ?- time((between(1,30,_), equals, fail; true)).
    % 570,118 inferences, 0.031 CPU in 0.042 seconds (75% CPU, 18243776 Lips)

    /* Trealla Prolog 2.79.26 */

    ?- time((between(1,30,_), unify, fail; true)).
    % Time elapsed 0.126s, 1173903 Inferences, 9.347 MLips
    ?- time((between(1,30,_), equals, fail; true)).
    % Time elapsed 0.126s, 1173903 Inferences, 9.319 MLips

    /* Dogelog Player 1.3.5 for Java */

    ?- time((between(1,30,_), unify, fail; true)).
    % Zeit 167 ms, GC 0 ms, Lips 6850113, Uhr 01.08.2025 22:41
    ?- time((between(1,30,_), equals, fail; true)).
    % Zeit 165 ms, GC 0 ms, Lips 6933145, Uhr 01.08.2025 22:38

    /* Scryer Prolog 0.9.4-547 */

    ?- time((between(1,30,_), unify, fail; true)).
    % CPU time: 0.222s, 1_174_119 inferences
    ?- time((between(1,30,_), equals, fail; true)).
    % CPU time: 0.221s, 1_147_809 inferences

    Bye

    Mild Shock schrieb:

    Take this cute example:

    ?- [user].
    dfa(Q0, [Q3,Q4]) :-
    -a-a Q0 = f(Q1, Q2),
    -a-a Q1 = f(Q3, Q2),
    -a-a Q2 = f(Q1, Q4),
    -a-a Q4 = f(Q1, Q4),
    -a-a Q3 = f(Q3, Q2).

    Try this example in Scryer-Prolog:

    /* Scryer Prolog 0.9.4-547 */
    ?- dfa(X, Y).
    %%% tons and tons of print out (...)))),f(f(f(...,f(...)),f(f(...),...)),f(f(...,...), f(f(...),...)))),f(f(f(f(...,f(...)),f(...,...)), f(f(...,f(...)),f(f(...),...))),f(f(f(...,f(...)),f(...,...)), f(f(...,f(...)),f(f(...),...)))))))))))))))))))].

    Was more expecting something like

    /* SWI-Prolog-a 9.3.26 */
    ?- dfa(X, Y).
    X = f(f(_S1, _S3), _S3), % where
    -a-a-a _S1 = f(_S1, _S3),
    -a-a-a _S2 = f(f(_S1, _S3), _S2),
    -a-a-a _S3 = f(f(_S1, _S3), _S2),
    Y = [_S1, _S2].

    Mild Shock schrieb:
    Hi,

    Having fun with Bisimulation, and a new test
    suite of nasty circular pairs. But how store
    circular pairs, if clauses do not support

    circular terms. Well chop it up into equations,
    I create 1000 such equation pairs:

    test([A = c(A, B), C = c(A, D), E = n, _ = c(F, B),
    -a-a-a-a-a-a F = c(C, C), G = c(G, D), D = c(E, C), B = n],
    -a-a-a-a-a [H = c(H, I), J = c(K, I), L = c(L, I), I = c(M, N),
    -a-a-a-a-a-a O = c(K, J), N = n, K = c(K, J), M = c(K, O)]).
    Etc..

    The pairs are nasty because the usual compare_with_stack/2
    chokes on them. Here some results:

    /* SWI-Prolog 9.3.26 */
    ?- time((between(1,30,_), part, fail; true)).
    % 540,118 inferences, 0.047 CPU in 0.041 seconds (115% CPU, 11522517
    Lips)
    true.

    /* Trealla Prolog 2.78.40 */
    ?- time((between(1,30,_), part, fail; true)).
    % Time elapsed 0.113s, 1143903 Inferences, 10.157 MLips
    -a-a-a true.

    /* Scryer Prolog 0.9.4-417 */
    ?- time((between(1,30,_), part, fail; true)).
    -a-a-a % CPU time: 0.226s, 1_117_809 inferences
    -a-a-a true.

    /* Dogelog Player 1.3.5 */
    ?- time((between(1,30,_), part2, fail; true)).
    % Zeit 309 ms, GC 0 ms, Lips 8693718, Uhr 25.07.2025 13:47
    true.

    The amazing thing is, I compared a 100% Prolog
    implementation, so there is a lot of head room
    for improvement:

    part2 :-
    -a-a-a bitest(X,Y), X ~~ Y, fail; true.

    The operator (~~)/2 is part of library(math),
    and has been implemented with same_term/2 so far.

    Bye



    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From Mild Shock@janburse@fastmail.fm to comp.lang.prolog on Sat Aug 16 13:02:04 2025
    From Newsgroup: comp.lang.prolog


    I like your 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.

    It is not accidential that there is a resemblage
    to the ivory tower of academics. Which might create
    incestual orthodoxical knowledge, with very less value.

    Prolog systems development is especially susceptible
    to this fallacy, since it has a long tradition
    going always the same paths, like WAM, etc.. etc..

    The pointer swizzling algorithms of SWI-Prolog,
    in connection with cyclic terms are a little
    problematic. What if a Prolog term sits in a

    read-only memory, or is shared among multiple threads.
    How do you do pointer swizzling of ROM and not RAM?
    We might indeed see the The End of Deutsch-Schorr-Waite,

    although it made it still into Scryer Prolog:

    **cycle_detection.rs**
    Use the pointer reversal technique of the Deutsch-Schorr-
    Waite algorithm to detect cycles in Prolog terms. https://github.com/mthom/scryer-prolog/blob/master/src/machine/cycle_detection.rs

    To enter the age of rational trees, it is probably
    advisable to arm oneself not only with Fuzzy Testing,
    but unlike the dislike of @kuniaki.mukai , one needs

    to probably also study all the goodies from 1970's
    computer science. But add a salt of scepticism, since
    hardware and programming languages look different now.

    Its not ALGOL anymore.

    Mild Shock schrieb:
    Hi,

    Assume that we live in a world where we
    have excess memory. So we can afford stacks!
    And then make the crucial observation,

    we can use the stack of the Prolog engine,
    no need to create an artificial stack in C,
    or use the native stack of C.

    I guess SWI-Prolog has already groked the
    first we can "afford stacks". But did anybody
    already grok the "100% Prolog" idea?

    Well we are not yet there 100% Prolog
    has still an overhead. Here is a little
    test acyclic_term/2:

    /* SWI-Prolog 9.3.26, C Stacks and/or Agendas */
    ?- time((between(1,30,_), acyclic2, fail; true)).
    % 330,150 inferences, 0.016 CPU in 0.023 seconds
    (69% CPU, 21129600 Lips)
    true.

    /* Trealla Prolog 2.79.6, ?? */
    ?- time((between(1,30,_), acyclic2, fail; true)).
    % Time elapsed 0.063s, 643413 Inferences, 10.166 MLips
    -a-a true.

    /* Dogelog Player 1.3.5, 100% Prolog */
    ?- time((between(1,30,_), acyclic2, fail; true)).
    % Zeit 115 ms, GC 0 ms, Lips 11803904, Uhr 28.07.2025 10:03
    true.

    /* Scryer Prolog 0.9.4-417, Deutsch-Schorr-Waite-a */
    ?- time((between(1,30,_), acyclic2, fail; true)).
    % CPU time: 0.130s, 626_829 inferences
    true.

    Bye

    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From Mild Shock@janburse@fastmail.fm to comp.lang.prolog on Sun Aug 24 14:44:11 2025
    From Newsgroup: comp.lang.prolog

    Hi,

    While I had an allocator that was reusing
    slots. But for release 1.3.6 I rejected it,
    and went back to a different solution.

    The new solution is more interesting, since
    it allows to have exec_unify() and exec_build()
    to be commutative with itself and each other,

    they do not have to be called in input order
    anymore. The generated code shows a trait of
    relocatability consisting of blocks that can

    be executed in varying order. The following
    things went out of the window:

    - Old Take: 3 variable instructions,
    1 intruction for annonymous variable,
    1 instruction for first variable,
    1 instruction for non-first variable.
    The first variable instruction did the
    slot reuse via an overwrite.

    - New Take: 2 variable instructions,
    1 instruction for annonymous variable
    1 instruction for non-annonymous variable.
    The non-annonymous variable is clever, uses the
    state of the slot to dynamically figure out whether
    it is first or not. We loose slot overwriting.

    That we cannnot overwrite slots anymore makes
    the var displays bigger. But unlike in the Debray Allocator
    for the WAM. The display is not WAM registers,

    it is more volatile. Only used during neck optimized
    built-ins and when creating the clause rest.
    The bigger displays causes a small performance

    penality, they have to be also initialized
    particularly to make the algorithm work. But
    the host programming language allocators do

    that for us. The extra effort is compensated
    that we are now more flexible in code generation,
    and also more flexible in the builtin implementation.

    As a first result, we removed the '$EVAL'/2 cludge,
    to compile is/2. Possibly more things are to come.
    Especially in the domain of static variable shunting.

    Bye

    Mild Shock schrieb:
    Hi,

    Assume that we live in a world where we
    have excess memory. So we can afford stacks!
    And then make the crucial observation,

    we can use the stack of the Prolog engine,
    no need to create an artificial stack in C,
    or use the native stack of C.

    I guess SWI-Prolog has already groked the
    first we can "afford stacks". But did anybody
    already grok the "100% Prolog" idea?

    Well we are not yet there 100% Prolog
    has still an overhead. Here is a little
    test acyclic_term/2:

    /* SWI-Prolog 9.3.26, C Stacks and/or Agendas */
    ?- time((between(1,30,_), acyclic2, fail; true)).
    % 330,150 inferences, 0.016 CPU in 0.023 seconds
    (69% CPU, 21129600 Lips)
    true.

    /* Trealla Prolog 2.79.6, ?? */
    ?- time((between(1,30,_), acyclic2, fail; true)).
    % Time elapsed 0.063s, 643413 Inferences, 10.166 MLips
    -a-a true.

    /* Dogelog Player 1.3.5, 100% Prolog */
    ?- time((between(1,30,_), acyclic2, fail; true)).
    % Zeit 115 ms, GC 0 ms, Lips 11803904, Uhr 28.07.2025 10:03
    true.

    /* Scryer Prolog 0.9.4-417, Deutsch-Schorr-Waite-a */
    ?- time((between(1,30,_), acyclic2, fail; true)).
    % CPU time: 0.130s, 626_829 inferences
    true.

    Bye

    --- Synchronet 3.21a-Linux NewsLink 1.2