• Request for comments: Two types of float of integer division

    From Mostowski Collapse@21:1/5 to All on Wed Sep 28 16:15:34 2022
    I am playing with the idea to introduce two types
    of float of integer division:

    - a) Fast and less precise: A/B basically computes
    float(A)/float(B).

    - b) Slow and more precise: float(A rdiv B) is then
    the more precise counterpart.

    Currently there is no unity among Prolog systems.
    When (/)/2 appears, some Prolog systems implement
    a) and some implement b). And it appears

    implementing b) is hard! I get:

    /* SWI-Prolog 8.5.17 */
    ?- N9 is 370370367037037036703703703670 / 123456789012345678901234567890.
    N9 = 3.

    ?- N9 is 370370367037037036703703703671 / 123456789012345678901234567890.
    N9 = 2.9999999999999996.

    Python doesn’t have this bug:

    /* Python 3.11.0rc1 (main, Aug 8 2022, 11:30:54) */
    370370367037037036703703703670 / 123456789012345678901234567890
    3.0

    370370367037037036703703703671 / 123456789012345678901234567890
    3.0

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Mostowski Collapse@21:1/5 to Mostowski Collapse on Wed Sep 28 16:22:04 2022
    So what are the next steps. I already made the following
    step. I downgraded the (/)/2 in Dogelog Player for Python,
    which simply used the Python (/)/2.

    Originally I had:

    /* Dogelog Player 1.0.1, Python */
    ?- N9 is 370370367037037036703703703670 / 123456789012345678901234567890.
    N9 = 3.0

    Now I have downgraded it:

    /* Preview, Dogelog Player 1.0.1, Python */
    ?- N9 is 370370367037037036703703703670 / 123456789012345678901234567890.
    N9 = 3.0000000000000004.

    It now corresponds to our Java and JavaScript realization,
    all are fast and less precise. What are the next steps:

    1. Try prototyping precise float(A rdiv B) in formerly Jekejeke
    Prolog, in the rational number library. Rational numbers have
    the advantage that they already do a reduction, so I find:

    ?- N9 is 370370367037037036703703703670 rdiv 123456789012345678901234567890.
    N9 = 3.

    So float/1 doesn't have much to do. On the other hand here,
    float/1 has more work to do, to get to the right conclusion:

    ?- N9 is 370370367037037036703703703671 rdiv 123456789012345678901234567890.
    N9 = 370370367037037036703703703671#123456789012345678901234567890.

    2. Dogelog player for JavaScript and Python will only eventually
    receive the precise and slow float(A rdiv B), namely when
    they also receive rational numbers.

    Mostowski Collapse schrieb am Donnerstag, 29. September 2022 um 01:15:36 UTC+2:
    I am playing with the idea to introduce two types
    of float of integer division:

    - a) Fast and less precise: A/B basically computes
    float(A)/float(B).

    - b) Slow and more precise: float(A rdiv B) is then
    the more precise counterpart.

    Currently there is no unity among Prolog systems.
    When (/)/2 appears, some Prolog systems implement
    a) and some implement b). And it appears

    implementing b) is hard! I get:

    /* SWI-Prolog 8.5.17 */
    ?- N9 is 370370367037037036703703703670 / 123456789012345678901234567890.
    N9 = 3.

    ?- N9 is 370370367037037036703703703671 / 123456789012345678901234567890.
    N9 = 2.9999999999999996.

    Python doesn’t have this bug:

    /* Python 3.11.0rc1 (main, Aug 8 2022, 11:30:54) */
    370370367037037036703703703670 / 123456789012345678901234567890
    3.0

    370370367037037036703703703671 / 123456789012345678901234567890
    3.0

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Mostowski Collapse@21:1/5 to All on Thu Sep 29 08:38:10 2022
    Under certain circumstances, there is also an ultra fast
    rounding for rational numbers, similar like there is for bigint.
    Take this bigint approach, assuming msb(X) > 52:

    float_half_even(X,Y) :-
    M is msb(X),
    float_half_even(M, X, Y).

    float_half_even(M, X,Y) :-
    (getbit(X, M-53) =:= 0;
    getbit(X, M-52) =:= 0, M-53 =:= lsb(X)), !, mpz_get_d(X,Y). float_half_even(_, X,Y) :-
    mpz_get_d(X,H),
    Y is nexttoward(H, 1E300).

    Now we can do the same for rational numbers, namely
    we can do the following, now assuming msb(A)-msb(B) > 52,
    we convert a rational number A rdiv B to a float as follows:

    float_rat_half_even(A,B,Y) :-
    divmod(A,B,X,Z),
    M is msb(X),
    float_rat_half_even(M, X, Z, Y).

    float_rat_half_even(M, X, Z, Y) :-
    (getbit(X, M-53) =:= 0;
    getbit(X, M-52) =:= 0, M-53 =:= lsb(X), Z =:= 0), !, mpz_get_d(X,Y). float_rat_half_even(_, X, _, Y) :-
    mpz_get_d(X,H),
    Y is nexttoward(H, 1E300).

    Will do some testing. The testing would be easier if SWI-Prolog
    (/)/2 were not buggy. So I have to do some testing against
    some other Prolog system, which one?, or against Python (/)/2.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Mostowski Collapse@21:1/5 to Mostowski Collapse on Thu Sep 29 18:00:42 2022
    If we have a numerator with a high lsb/1,
    i.e. a lot of zeros in it, the algorithm
    indeed agrees, namely I find the following result:

    /* SWI-Prolog 8.5.17 */
    ?- B is 333333, between(1,1000000,N), A is N<<80, X is A/B, float_rat_half_even(A,B,Y), X =\= Y.
    false.

    Hell breaks loose if the numerator is not that
    simple, but there are only a few cases where
    things go wrong. Need to cross check with Python:

    /* SWI-Prolog 8.5.17 */
    ?- B is 333333, between(1,1000000,N), A is N<<80+123456789, X is A/B, float_rat_half_even(A,B,Y), X =\= Y, write(N), nl, fail; true.
    13
    26
    52
    8915
    458442
    791775
    true.


    Mostowski Collapse wrote:
    Under certain circumstances, there is also an ultra fast
    rounding for rational numbers, similar like there is for bigint.
    Take this bigint approach, assuming msb(X) > 52:

    float_half_even(X,Y) :-
    M is msb(X),
    float_half_even(M, X, Y).

    float_half_even(M, X,Y) :-
    (getbit(X, M-53) =:= 0;
    getbit(X, M-52) =:= 0, M-53 =:= lsb(X)), !, mpz_get_d(X,Y). float_half_even(_, X,Y) :-
    mpz_get_d(X,H),
    Y is nexttoward(H, 1E300).

    Now we can do the same for rational numbers, namely
    we can do the following, now assuming msb(A)-msb(B) > 52,
    we convert a rational number A rdiv B to a float as follows:

    float_rat_half_even(A,B,Y) :-
    divmod(A,B,X,Z),
    M is msb(X),
    float_rat_half_even(M, X, Z, Y).

    float_rat_half_even(M, X, Z, Y) :-
    (getbit(X, M-53) =:= 0;
    getbit(X, M-52) =:= 0, M-53 =:= lsb(X), Z =:= 0), !, mpz_get_d(X,Y). float_rat_half_even(_, X, _, Y) :-
    mpz_get_d(X,H),
    Y is nexttoward(H, 1E300).

    Will do some testing. The testing would be easier if SWI-Prolog
    (/)/2 were not buggy. So I have to do some testing against
    some other Prolog system, which one?, or against Python (/)/2.


    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Mostowski Collapse@21:1/5 to Mostowski Collapse on Thu Sep 29 18:02:03 2022
    Cross checking with Python tells me (/)/2 is wrong
    and float_rat_half_even/2 is correct (wao! lucky me),
    for example for N=13 I get:

    /* Python 3.11.0rc1 */
    15716035654990179394637077 / 333333
    4.7148154113124655e+19

    /* SWI-Prolog 8.5.7 */
    ?- X is 15716035654990179394637077 / 333333.
    X = 4.714815411312465e+19. /* wrong too small */

    ?- float_rat_half_even(15716035654990179394637077, 333333, Y).
    Y = 4.7148154113124655e+19.

    Mostowski Collapse wrote:

    If we have a numerator with a high lsb/1,
    i.e. a lot of zeros in it, the algorithm
    indeed agrees, namely I find the following result:

    /* SWI-Prolog 8.5.17 */
    ?- B is 333333, between(1,1000000,N), A is N<<80, X is A/B, float_rat_half_even(A,B,Y), X =\= Y.
    false.

    Hell breaks loose if the numerator is not that
    simple, but there are only a few cases where
    things go wrong. Need to cross check with Python:

    /* SWI-Prolog 8.5.17 */
    ?- B is 333333, between(1,1000000,N), A is N<<80+123456789, X is A/B, float_rat_half_even(A,B,Y), X =\= Y, write(N), nl, fail; true.
    13
    26
    52
    8915
    458442
    791775
    true.


    Mostowski Collapse wrote:
    Under certain circumstances, there is also an ultra fast
    rounding for rational numbers, similar like there is for bigint.
    Take this bigint approach, assuming msb(X) > 52:

    float_half_even(X,Y) :-
         M is msb(X),
         float_half_even(M, X, Y).

    float_half_even(M, X,Y) :-
          (getbit(X, M-53) =:= 0;
           getbit(X, M-52) =:= 0, M-53 =:= lsb(X)), !, mpz_get_d(X,Y).
    float_half_even(_, X,Y) :-
          mpz_get_d(X,H),
          Y is nexttoward(H, 1E300).

    Now we can do the same for rational numbers, namely
    we can do the following, now assuming msb(A)-msb(B) > 52,
    we convert a rational number A rdiv B to a float as follows:

    float_rat_half_even(A,B,Y) :-
         divmod(A,B,X,Z),
         M is msb(X),
         float_rat_half_even(M, X, Z, Y).

    float_rat_half_even(M, X, Z, Y) :-
          (getbit(X, M-53) =:= 0;
           getbit(X, M-52) =:= 0, M-53 =:= lsb(X), Z =:= 0), !,
    mpz_get_d(X,Y).
    float_rat_half_even(_, X, _, Y) :-
          mpz_get_d(X,H),
          Y is nexttoward(H, 1E300).

    Will do some testing. The testing would be easier if SWI-Prolog
    (/)/2 were not buggy. So I have to do some testing against
    some other Prolog system, which one?, or against Python (/)/2.



    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Mostowski Collapse@21:1/5 to Mostowski Collapse on Thu Sep 29 09:09:09 2022
    The bad news is. Cannot implement the same in JavaScript,
    the JavaScript bigints do not have (yet) bit operations such as
    msb/1, lsb/1 or getbit/1. And if there are no native and

    fast implementations of these, the algorithm is pointless.
    Maybe just wait some time till they arrive in JavaScript,
    for example one finds discussion to include bitLength,

    which can be used for msb/1. Didn't check yet Phyton, but
    in Python I don't need an algorithm, since (/)/2 can already
    do the more exact division. But now when cross checking

    with Python, I was blindly trusting Python that the rounding
    is also HALF_EVEN in Python! So the cross checking
    is a preliminary result.

    Mostowski Collapse schrieb am Donnerstag, 29. September 2022 um 18:02:06 UTC+2:
    Cross checking with Python tells me (/)/2 is wrong
    and float_rat_half_even/2 is correct (wao! lucky me),
    for example for N=13 I get:

    /* Python 3.11.0rc1 */
    15716035654990179394637077 / 333333
    4.7148154113124655e+19

    /* SWI-Prolog 8.5.7 */
    ?- X is 15716035654990179394637077 / 333333.
    X = 4.714815411312465e+19. /* wrong too small */

    ?- float_rat_half_even(15716035654990179394637077, 333333, Y).
    Y = 4.7148154113124655e+19.
    Mostowski Collapse wrote:

    If we have a numerator with a high lsb/1,
    i.e. a lot of zeros in it, the algorithm
    indeed agrees, namely I find the following result:

    /* SWI-Prolog 8.5.17 */
    ?- B is 333333, between(1,1000000,N), A is N<<80, X is A/B, float_rat_half_even(A,B,Y), X =\= Y.
    false.

    Hell breaks loose if the numerator is not that
    simple, but there are only a few cases where
    things go wrong. Need to cross check with Python:

    /* SWI-Prolog 8.5.17 */
    ?- B is 333333, between(1,1000000,N), A is N<<80+123456789, X is A/B, float_rat_half_even(A,B,Y), X =\= Y, write(N), nl, fail; true.
    13
    26
    52
    8915
    458442
    791775
    true.


    Mostowski Collapse wrote:
    Under certain circumstances, there is also an ultra fast
    rounding for rational numbers, similar like there is for bigint.
    Take this bigint approach, assuming msb(X) > 52:

    float_half_even(X,Y) :-
    M is msb(X),
    float_half_even(M, X, Y).

    float_half_even(M, X,Y) :-
    (getbit(X, M-53) =:= 0;
    getbit(X, M-52) =:= 0, M-53 =:= lsb(X)), !, mpz_get_d(X,Y).
    float_half_even(_, X,Y) :-
    mpz_get_d(X,H),
    Y is nexttoward(H, 1E300).

    Now we can do the same for rational numbers, namely
    we can do the following, now assuming msb(A)-msb(B) > 52,
    we convert a rational number A rdiv B to a float as follows:

    float_rat_half_even(A,B,Y) :-
    divmod(A,B,X,Z),
    M is msb(X),
    float_rat_half_even(M, X, Z, Y).

    float_rat_half_even(M, X, Z, Y) :-
    (getbit(X, M-53) =:= 0;
    getbit(X, M-52) =:= 0, M-53 =:= lsb(X), Z =:= 0), !,
    mpz_get_d(X,Y).
    float_rat_half_even(_, X, _, Y) :-
    mpz_get_d(X,H),
    Y is nexttoward(H, 1E300).

    Will do some testing. The testing would be easier if SWI-Prolog
    (/)/2 were not buggy. So I have to do some testing against
    some other Prolog system, which one?, or against Python (/)/2.



    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Mostowski Collapse@21:1/5 to Mostowski Collapse on Fri Oct 28 13:18:12 2022
    Here are some test results. WASM is again the best, although
    not extremly far away from WSL2. Windows is again last:

    /* SWI-Prolog 8.5.20 WASM */
    sweep1, swi: 2186
    sweep2, swi: 1242

    /* SWI-Prolog 8.5.20 WSL2 */
    sweep1, swi: 3300
    sweep2, swi: 1370

    /* SWI-Prolog 8.5.20 Windows */
    sweep1, swi: 405161
    sweep2, swi: 786699

    Mostowski Collapse schrieb am Freitag, 28. Oktober 2022 um 22:16:57 UTC+2:
    Ok, this was settled with Python mode in SWI-Prolog,
    we can switch on more precise integer division. Another
    application of Python mode, since it also applies to (**)/2,

    measure failures of the power function:

    % swi_sweep
    swi_sweep :-
    set_prolog_flag(prefer_rationals, true),
    set_prolog_flag(max_rational_size, 0), set_prolog_flag(max_rational_size_action, float),
    fail.
    swi_sweep :- % like in needle3
    L is -(1<<15), H is (1<<15)+1,
    M is -(1<<3), J is (1<<3)+1,
    aggregate_all(count,
    (between(L, H, P), P =\= 0,
    between(M, J, Q), P**Q =\= float(P)**float(Q)), C),
    write('sweep1, swi: '), write(C), nl, fail.
    swi_sweep :- % like in fuzzer6
    L is -(1<<12), H is (1<<12)+1,
    M is -(1<<6), J is (1<<6)+1,
    aggregate_all(count,
    (between(L, H, P), P =\= 0,
    between(M, J, Q), P**Q =\= float(P)**float(Q)), C),
    write('sweep2, swi: '), write(C), nl, fail.
    swi_sweep :-
    set_prolog_flag(prefer_rationals, false),
    fail.
    swi_sweep.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Mostowski Collapse@21:1/5 to All on Fri Oct 28 13:16:55 2022
    Ok, this was settled with Python mode in SWI-Prolog,
    we can switch on more precise integer division. Another
    application of Python mode, since it also applies to (**)/2,

    measure failures of the power function:

    % swi_sweep
    swi_sweep :-
    set_prolog_flag(prefer_rationals, true),
    set_prolog_flag(max_rational_size, 0),
    set_prolog_flag(max_rational_size_action, float),
    fail.
    swi_sweep :- % like in needle3
    L is -(1<<15), H is (1<<15)+1,
    M is -(1<<3), J is (1<<3)+1,
    aggregate_all(count,
    (between(L, H, P), P =\= 0,
    between(M, J, Q), P**Q =\= float(P)**float(Q)), C),
    write('sweep1, swi: '), write(C), nl, fail.
    swi_sweep :- % like in fuzzer6
    L is -(1<<12), H is (1<<12)+1,
    M is -(1<<6), J is (1<<6)+1,
    aggregate_all(count,
    (between(L, H, P), P =\= 0,
    between(M, J, Q), P**Q =\= float(P)**float(Q)), C),
    write('sweep2, swi: '), write(C), nl, fail.
    swi_sweep :-
    set_prolog_flag(prefer_rationals, false),
    fail.
    swi_sweep.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Mostowski Collapse@21:1/5 to Mostowski Collapse on Fri Oct 28 13:56:14 2022
    To bring some of my precise float emulations to Dogelog
    Playrer I need msb/1. I looking for inspiration.

    Scryer Prolog isn't some inspiration:

    test(X) :- msb(698072381837257563305573971580726935040345973 88060083583912810633489137842647022803107007382 69827592504647436506289493205329736363655295902 94743735953400982487450103250905033780625181457 49473537073305602444617606242084853904869693687
    541, X).

    ?- time((between(1,1000,_), test(_), fail; true)).
    % CPU time: 0.277s
    true.

    On the other hand Trealla Prolog does a good job:

    /* Trealla Prolog */
    test(X) :- X is msb(698072381837257563305573971580726935040345973 88060083583912810633489137842647022803107007382 69827592504647436506289493205329736363655295902 94743735953400982487450103250905033780625181457 49473537073305602444617606242084853904869693687
    541).

    ?- time((between(1,1000,_), test(_), fail; true)).
    Time elapsed 0.000384s
    true.

    Holy Cow, thats factor 721x slower. Looks like Scyer Prolog
    msb/1 is O(N) where N is the number of bits, and Trealla
    Prologs msb/1 is O(1). How comes?

    Mostowski Collapse schrieb am Freitag, 28. Oktober 2022 um 22:18:13 UTC+2:
    Here are some test results. WASM is again the best, although
    not extremly far away from WSL2. Windows is again last:

    /* SWI-Prolog 8.5.20 WASM */
    sweep1, swi: 2186
    sweep2, swi: 1242

    /* SWI-Prolog 8.5.20 WSL2 */
    sweep1, swi: 3300
    sweep2, swi: 1370

    /* SWI-Prolog 8.5.20 Windows */
    sweep1, swi: 405161
    sweep2, swi: 786699
    Mostowski Collapse schrieb am Freitag, 28. Oktober 2022 um 22:16:57 UTC+2:
    Ok, this was settled with Python mode in SWI-Prolog,
    we can switch on more precise integer division. Another
    application of Python mode, since it also applies to (**)/2,

    measure failures of the power function:

    % swi_sweep
    swi_sweep :-
    set_prolog_flag(prefer_rationals, true),
    set_prolog_flag(max_rational_size, 0), set_prolog_flag(max_rational_size_action, float),
    fail.
    swi_sweep :- % like in needle3
    L is -(1<<15), H is (1<<15)+1,
    M is -(1<<3), J is (1<<3)+1,
    aggregate_all(count,
    (between(L, H, P), P =\= 0,
    between(M, J, Q), P**Q =\= float(P)**float(Q)), C),
    write('sweep1, swi: '), write(C), nl, fail.
    swi_sweep :- % like in fuzzer6
    L is -(1<<12), H is (1<<12)+1,
    M is -(1<<6), J is (1<<6)+1,
    aggregate_all(count,
    (between(L, H, P), P =\= 0,
    between(M, J, Q), P**Q =\= float(P)**float(Q)), C),
    write('sweep2, swi: '), write(C), nl, fail.
    swi_sweep :-
    set_prolog_flag(prefer_rationals, false),
    fail.
    swi_sweep.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Mostowski Collapse@21:1/5 to Mostowski Collapse on Fri Oct 28 14:16:38 2022
    This is basically the Scryer Prolog algorithm:

    /* msb2/2, very slow */
    msb2(X, N) :-
    msb2(X, -1, N).

    msb2(0, N, M) :- !, M = N.
    msb2(X, N, M) :-
    Y is X>>1,
    K is N+1,
    msb2(Y, K, M).

    Here is a trick to make it slightly faster:

    /* msb3/2, still slow */
    msb3(X, N) :-
    msb3(X, -1, N).

    msb3(0, N, M) :- !, M = N.
    msb3(X, N, M) :-
    Y is X>>64, Y =\= 0, !,
    K is N+64,
    msb3(Y, K, M).
    msb3(X, N, M) :-
    Y is X>>1,
    K is N+1,
    msb3(Y, K, M).

    In Jekejeke Prolog I get:

    /* Scryer Algorithm */
    ?- time((between(1,10000,_), test(_), fail; true)).
    % Threads 2,547 ms, GC 25 ms, Up 2,548 ms (Current 10/28/22 23:13:11)
    true.

    /* Slightly Faster Algorithm */
    ?- time((between(1,10000,_), test2(_), fail; true)).
    % Threads 140 ms, GC 1 ms, Up 141 ms (Current 10/28/22 23:13:13)
    true.

    /* BigInteger method bitLength() */
    ?- time((between(1,10000,_), test3(_), fail; true)).
    % Threads 0 ms, GC 0 ms, Up 2 ms (Current 10/28/22 23:13:18)
    true.

    Mostowski Collapse schrieb am Freitag, 28. Oktober 2022 um 22:56:15 UTC+2:
    To bring some of my precise float emulations to Dogelog
    Playrer I need msb/1. I looking for inspiration.

    Scryer Prolog isn't some inspiration:

    test(X) :- msb(698072381837257563305573971580726935040345973 88060083583912810633489137842647022803107007382 69827592504647436506289493205329736363655295902 94743735953400982487450103250905033780625181457 49473537073305602444617606242084853904869693687
    541, X).

    ?- time((between(1,1000,_), test(_), fail; true)).
    % CPU time: 0.277s
    true.

    On the other hand Trealla Prolog does a good job:

    /* Trealla Prolog */
    test(X) :- X is msb(698072381837257563305573971580726935040345973 88060083583912810633489137842647022803107007382 69827592504647436506289493205329736363655295902 94743735953400982487450103250905033780625181457 49473537073305602444617606242084853904869693687
    541).

    ?- time((between(1,1000,_), test(_), fail; true)).
    Time elapsed 0.000384s
    true.

    Holy Cow, thats factor 721x slower. Looks like Scyer Prolog
    msb/1 is O(N) where N is the number of bits, and Trealla
    Prologs msb/1 is O(1). How comes?
    Mostowski Collapse schrieb am Freitag, 28. Oktober 2022 um 22:18:13 UTC+2:
    Here are some test results. WASM is again the best, although
    not extremly far away from WSL2. Windows is again last:

    /* SWI-Prolog 8.5.20 WASM */
    sweep1, swi: 2186
    sweep2, swi: 1242

    /* SWI-Prolog 8.5.20 WSL2 */
    sweep1, swi: 3300
    sweep2, swi: 1370

    /* SWI-Prolog 8.5.20 Windows */
    sweep1, swi: 405161
    sweep2, swi: 786699
    Mostowski Collapse schrieb am Freitag, 28. Oktober 2022 um 22:16:57 UTC+2:
    Ok, this was settled with Python mode in SWI-Prolog,
    we can switch on more precise integer division. Another
    application of Python mode, since it also applies to (**)/2,

    measure failures of the power function:

    % swi_sweep
    swi_sweep :-
    set_prolog_flag(prefer_rationals, true), set_prolog_flag(max_rational_size, 0), set_prolog_flag(max_rational_size_action, float),
    fail.
    swi_sweep :- % like in needle3
    L is -(1<<15), H is (1<<15)+1,
    M is -(1<<3), J is (1<<3)+1,
    aggregate_all(count,
    (between(L, H, P), P =\= 0,
    between(M, J, Q), P**Q =\= float(P)**float(Q)), C),
    write('sweep1, swi: '), write(C), nl, fail.
    swi_sweep :- % like in fuzzer6
    L is -(1<<12), H is (1<<12)+1,
    M is -(1<<6), J is (1<<6)+1,
    aggregate_all(count,
    (between(L, H, P), P =\= 0,
    between(M, J, Q), P**Q =\= float(P)**float(Q)), C),
    write('sweep2, swi: '), write(C), nl, fail.
    swi_sweep :-
    set_prolog_flag(prefer_rationals, false),
    fail.
    swi_sweep.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Mostowski Collapse@21:1/5 to All on Fri Oct 28 17:06:48 2022
    Could emulate msb/1. So result for (**)(2 for other Prolog systems.
    It seems PyPy and SICStus use the same pow() function:

    System sweep1 sweep2 Total Variant
    jekejeke 1756 666 2422 JDK 19
    swi 2186 1242 3428 WASM
    scryer 3300 1370 4670 WSL2
    dogelog 2930 2174 5104 PyPy
    sicstus 2930 2174 5104 Windows
    ciao 3300 324342 327642 WSL2
    eclipse 345587 482199 827786 Windows

    Ciao botched something in sweep2. ECLiPSe botched
    both sweep1 and sweep2. Trealla Prolog I couldn’t

    test because of some bigint bug. Ciao Playground
    couldn’t test because of missing auto yield i.e timeout.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Mostowski Collapse@21:1/5 to Mostowski Collapse on Sat Oct 29 07:37:46 2022
    SICStus Prolog can be also quite annoying.
    It has msb/1 but no lsb/1? Holy Cow.

    Thank god it can be easily bootstrapped:

    lsb(X, N) :- N is msb(X /\ -X).

    This might do for smallints. But is surely not
    the most efficient for bigints.

    Mostowski Collapse schrieb am Samstag, 29. Oktober 2022 um 02:06:49 UTC+2:
    Could emulate msb/1. So result for (**)(2 for other Prolog systems.
    It seems PyPy and SICStus use the same pow() function:

    System sweep1 sweep2 Total Variant
    jekejeke 1756 666 2422 JDK 19
    swi 2186 1242 3428 WASM
    scryer 3300 1370 4670 WSL2
    dogelog 2930 2174 5104 PyPy
    sicstus 2930 2174 5104 Windows
    ciao 3300 324342 327642 WSL2
    eclipse 345587 482199 827786 Windows

    Ciao botched something in sweep2. ECLiPSe botched
    both sweep1 and sweep2. Trealla Prolog I couldn’t

    test because of some bigint bug. Ciao Playground
    couldn’t test because of missing auto yield i.e timeout.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Mostowski Collapse@21:1/5 to Mostowski Collapse on Thu Nov 3 09:04:57 2022
    So what are the obstacles to such a Novacore?
    I guess there are two problems:
    a) Seems to be hard to get basic arithmetic fast
    b) Seems to be hard to integrate it with logic and
    recursion, i.e. the comparisons on bigint, and also
    stack management of predicate invocation.
    c) Seems to be hard to provide a good set of built-ins,
    for example Scryer Prolog has no speedy msb/1, which is
    used in the implementation of iroot/3. Other Prolog system
    have msb/1 but no lsb/1.

    What are the chances of such a Novacore?
    I guess there are these chances:
    a) Could implement the whole rational arithmethic like that
    b) Could implement rational to float conversion like that
    c) Extremly high portability, need only find some bigints
    on each platform, and everything concerning rational
    numbers etc.. will be automatically there.

    Mostowski Collapse schrieb am Donnerstag, 3. November 2022 um 17:04:19 UTC+1:
    Do we really need libraries such as GMP? My
    idea, a good Novacore would have fast arithmetic,
    so that one can realize many functions in pure

    Prolog itself. Like this here:

    iroot(X, Y, Z):
    The predicate succeeds in Z with the Y-th root of X.

    Here are some benchmarking results:

    /* SWI-Prolog 8.5.20 */
    ?- M is (2^32+3), X is M^3+1, time((between(1,100000,_),
    iroot(X, 3, Y), fail; true)).
    % 4,900,000 inferences, 2.172 CPU in 2.164 seconds (100% CPU, 2256115 Lips)

    /* Trealla Prolog 2.5.13 */
    ?- M is (2^32+3), X is M^3+1, time((between(1,100000,_),
    iroot(X, 3, Y), fail; true)).
    Time elapsed 1.28s

    /* Jekejeke Prolog 1.5.5 JDK 1.8 */
    ?- M is (2^32+3), X is M^3+1, time((between(1,100000,_),
    iroot(X, 3, Y), fail; true)).
    % Threads 718 ms, GC 7 ms, Up 738 ms (Current 11/03/22 16:27:11)
    Mostowski Collapse schrieb am Samstag, 29. Oktober 2022 um 16:37:47 UTC+2:
    SICStus Prolog can be also quite annoying.
    It has msb/1 but no lsb/1? Holy Cow.

    Thank god it can be easily bootstrapped:

    lsb(X, N) :- N is msb(X /\ -X).

    This might do for smallints. But is surely not
    the most efficient for bigints.
    Mostowski Collapse schrieb am Samstag, 29. Oktober 2022 um 02:06:49 UTC+2:
    Could emulate msb/1. So result for (**)(2 for other Prolog systems.
    It seems PyPy and SICStus use the same pow() function:

    System sweep1 sweep2 Total Variant
    jekejeke 1756 666 2422 JDK 19
    swi 2186 1242 3428 WASM
    scryer 3300 1370 4670 WSL2
    dogelog 2930 2174 5104 PyPy
    sicstus 2930 2174 5104 Windows
    ciao 3300 324342 327642 WSL2
    eclipse 345587 482199 827786 Windows

    Ciao botched something in sweep2. ECLiPSe botched
    both sweep1 and sweep2. Trealla Prolog I couldn’t

    test because of some bigint bug. Ciao Playground
    couldn’t test because of missing auto yield i.e timeout.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Mostowski Collapse@21:1/5 to All on Sun Nov 6 17:26:08 2022
    Now I have added a new decimal128 datatype to my formerly
    Jekejeke Prolog system. Syntactically it starts with the prefix
    0m, inspired by a the money datatype in some database systems.

    I almost created a separate division operator ('/128')/2 but now
    the ordinary division operator (/)/2 switches to decimal128, as
    soon as one of its argumemts is decimal128:

    ?- X is 1/3.
    X = 0.3333333333333333.
    ?- X is 0m1/3.
    X = 0m0.3333333333333333333333333333333333.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Mostowski Collapse@21:1/5 to Mostowski Collapse on Sun Nov 6 17:27:36 2022
    Using a little Taylor expansion of arctan can now compute π:

    ?- X is pi.
    X = 3.141592653589793.
    ?- X is pi128.
    X = 0m3.141592653589793238462643383279503.

    By implementing more trigonometric functions, can not only
    provide them to the end-user. They also can serve as a test
    case generator for ordinary float routines. I already

    found an interesting test case:

    /* SWI-Prolog 8.5.20 Windows */
    ?- X is atan(897/2048).
    X = 0.4128202041682507.

    /* SWI-Prolog 8.5.20 WSL2 */
    ?- X is atan(897/2048).
    X = 0.41282020416825077.

    The second result is more accurate, right?

    Mostowski Collapse schrieb am Montag, 7. November 2022 um 02:26:09 UTC+1:
    Now I have added a new decimal128 datatype to my formerly
    Jekejeke Prolog system. Syntactically it starts with the prefix
    0m, inspired by a the money datatype in some database systems.

    I almost created a separate division operator ('/128')/2 but now
    the ordinary division operator (/)/2 switches to decimal128, as
    soon as one of its argumemts is decimal128:

    ?- X is 1/3.
    X = 0.3333333333333333.
    ?- X is 0m1/3.
    X = 0m0.3333333333333333333333333333333333.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Mostowski Collapse@21:1/5 to Mostowski Collapse on Tue Nov 8 03:09:20 2022
    I am currently implementing unums in pure Prolog. There is
    already some progress, basic operations with HALF_EVEN
    and then an atan function realization. It can be used to compute

    pi, it has pre-defined the Euler formula 20*atan(1/7)+8*atan(3/79):

    /* Compute pi with 53 Bit Precision*/
    ?- mp_pi(53, (M,E)), P is M*(2**E).
    P = 3.141592653589793.

    I have no clue how accurate the atan is. Unlike libBF it
    doesn’t use Ziv iteration, but a dynamically estimated
    fixed number of members of the Taylor expansion in a

    Horner schema implementation.

    Mostowski Collapse schrieb am Montag, 7. November 2022 um 02:27:38 UTC+1:
    Using a little Taylor expansion of arctan can now compute π:

    ?- X is pi.
    X = 3.141592653589793.
    ?- X is pi128.
    X = 0m3.141592653589793238462643383279503.

    By implementing more trigonometric functions, can not only
    provide them to the end-user. They also can serve as a test
    case generator for ordinary float routines. I already

    found an interesting test case:
    /* SWI-Prolog 8.5.20 Windows */
    ?- X is atan(897/2048).
    X = 0.4128202041682507.
    /* SWI-Prolog 8.5.20 WSL2 */
    ?- X is atan(897/2048).
    X = 0.41282020416825077.

    The second result is more accurate, right?
    Mostowski Collapse schrieb am Montag, 7. November 2022 um 02:26:09 UTC+1:
    Now I have added a new decimal128 datatype to my formerly
    Jekejeke Prolog system. Syntactically it starts with the prefix
    0m, inspired by a the money datatype in some database systems.

    I almost created a separate division operator ('/128')/2 but now
    the ordinary division operator (/)/2 switches to decimal128, as
    soon as one of its argumemts is decimal128:

    ?- X is 1/3.
    X = 0.3333333333333333.
    ?- X is 0m1/3.
    X = 0m0.3333333333333333333333333333333333.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Mostowski Collapse@21:1/5 to Mostowski Collapse on Tue Nov 8 03:10:40 2022
    Here are some timings I get for SWI-Prolog and my Prolog
    system using the pure Prolog arbitrary floats code:

    /* Jekejeke Prolog 1.5.5 Windows JDK 1.8 */
    ?- time((between(1,1000,_), mp_pi(53, _), fail; true)).
    % Threads 375 ms, GC 2 ms, Up 401 ms (Current 11/08/22 11:48:47)
    true.

    /* SWI-Prolog 8.5.20 Windows */
    ?- time((between(1,1000,_), mp_pi(53, _), fail; true)).
    % 3,358,000 inferences, 0.391 CPU in 0.391 seconds (100% CPU, 8596480 Lips) true.

    More or less same speed. But still much slower
    then any Math.atan().

    Mostowski Collapse schrieb am Dienstag, 8. November 2022 um 12:09:21 UTC+1:
    I am currently implementing unums in pure Prolog. There is
    already some progress, basic operations with HALF_EVEN
    and then an atan function realization. It can be used to compute

    pi, it has pre-defined the Euler formula 20*atan(1/7)+8*atan(3/79):

    /* Compute pi with 53 Bit Precision*/
    ?- mp_pi(53, (M,E)), P is M*(2**E).
    P = 3.141592653589793.

    I have no clue how accurate the atan is. Unlike libBF it
    doesn’t use Ziv iteration, but a dynamically estimated
    fixed number of members of the Taylor expansion in a

    Horner schema implementation.
    Mostowski Collapse schrieb am Montag, 7. November 2022 um 02:27:38 UTC+1:
    Using a little Taylor expansion of arctan can now compute π:

    ?- X is pi.
    X = 3.141592653589793.
    ?- X is pi128.
    X = 0m3.141592653589793238462643383279503.

    By implementing more trigonometric functions, can not only
    provide them to the end-user. They also can serve as a test
    case generator for ordinary float routines. I already

    found an interesting test case:
    /* SWI-Prolog 8.5.20 Windows */
    ?- X is atan(897/2048).
    X = 0.4128202041682507.
    /* SWI-Prolog 8.5.20 WSL2 */
    ?- X is atan(897/2048).
    X = 0.41282020416825077.

    The second result is more accurate, right?
    Mostowski Collapse schrieb am Montag, 7. November 2022 um 02:26:09 UTC+1:
    Now I have added a new decimal128 datatype to my formerly
    Jekejeke Prolog system. Syntactically it starts with the prefix
    0m, inspired by a the money datatype in some database systems.

    I almost created a separate division operator ('/128')/2 but now
    the ordinary division operator (/)/2 switches to decimal128, as
    soon as one of its argumemts is decimal128:

    ?- X is 1/3.
    X = 0.3333333333333333.
    ?- X is 0m1/3.
    X = 0m0.3333333333333333333333333333333333.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Mostowski Collapse@21:1/5 to Mostowski Collapse on Fri Dec 30 20:49:01 2022
    We built the quadruple type polymorphism of (/)/2 and other
    basic arithmetic operations into the core. Question was now
    whether we can provide the same polymorphism for

    quadruple mathematical functions as well. This lead
    to a new module library(decimal/quad) which provides
    exactly this polymorphism by overloading sqrt, sin, etc..

    from the ISO core standard. Here is an example:

    ?- X is atan(1/3).
    X = 0.3217505543966422.

    ?- X is atan(1/0m3).
    X = 0m0.3217505543966421934014046143586613.

    Mostowski Collapse schrieb am Samstag, 31. Dezember 2022 um 05:38:50 UTC+1:
    Originally this request filed for two types of
    division in case the arguments are integer.
    One less precise, which converts both arguments

    first to float, and thus might loose some precision,
    and another that performs something more
    precise. Possibly the discussion led me to a

    new arithmetic for my new decimal128 type,
    which now behaves as folllows, the division operator
    (/)/2 is now polymorphic:

    ?- X is 1/3.
    X = 0.3333333333333333.

    ?- X is 1/0m3.
    X = 0m0.3333333333333333333333333333333333.

    The first division is the less precise double conversion
    based division if the arguments are integer or double.
    The second is also a less precise division, this

    time based on quadruple conversion. The prefix 0m
    is the syntax for the new upcoming quadruple type
    in formerly Jekejeke Prolog.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Mostowski Collapse@21:1/5 to Mostowski Collapse on Fri Dec 30 20:50:56 2022
    One last minute problem solution pair was the handling of
    constants. They don't have an argument which could control
    the choice of either double or quadruple precision.

    So we just defined a shorthand for the quadruple evaluator,
    basically a definition as follows, which is how the quadruple
    evaluator is effectively bootstrapped from the multi-precision

    :- virtual qp/2.
    qp(E, R) :-
    R is decimal128(mp(E, 34)).

    evaluator mp/2 evaluable function. The formerly Jekejeke
    specific virtual directive makes the first agument of the qp/1
    evaluable function lazy, so that the expression E doesn't get

    call-by-value evaluated when qp/2 is used inside the standard
    Prolog evaluator is/2. Now we can also have a quadruple
    constant like pi accessed via the standard Prolog evaluator

    is/2, even they don't have a polymorphic argument:

    ?- X is pi.
    X = 3.141592653589793.

    ?- X is qp(pi).
    X = 0m3.141592653589793238462643383279503.

    P.S.: qp is shorthand for quadruple precision.

    Mostowski Collapse schrieb am Samstag, 31. Dezember 2022 um 05:49:02 UTC+1:
    We built the quadruple type polymorphism of (/)/2 and other
    basic arithmetic operations into the core. Question was now
    whether we can provide the same polymorphism for

    quadruple mathematical functions as well. This lead
    to a new module library(decimal/quad) which provides
    exactly this polymorphism by overloading sqrt, sin, etc..

    from the ISO core standard. Here is an example:

    ?- X is atan(1/3).
    X = 0.3217505543966422.

    ?- X is atan(1/0m3).
    X = 0m0.3217505543966421934014046143586613.
    Mostowski Collapse schrieb am Samstag, 31. Dezember 2022 um 05:38:50 UTC+1:
    Originally this request filed for two types of
    division in case the arguments are integer.
    One less precise, which converts both arguments

    first to float, and thus might loose some precision,
    and another that performs something more
    precise. Possibly the discussion led me to a

    new arithmetic for my new decimal128 type,
    which now behaves as folllows, the division operator
    (/)/2 is now polymorphic:

    ?- X is 1/3.
    X = 0.3333333333333333.

    ?- X is 1/0m3.
    X = 0m0.3333333333333333333333333333333333.

    The first division is the less precise double conversion
    based division if the arguments are integer or double.
    The second is also a less precise division, this

    time based on quadruple conversion. The prefix 0m
    is the syntax for the new upcoming quadruple type
    in formerly Jekejeke Prolog.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Mostowski Collapse@21:1/5 to All on Fri Dec 30 20:38:48 2022
    Originally this request filed for two types of
    division in case the arguments are integer.
    One less precise, which converts both arguments

    first to float, and thus might loose some precision,
    and another that performs something more
    precise. Possibly the discussion led me to a

    new arithmetic for my new decimal128 type,
    which now behaves as folllows, the division operator
    (/)/2 is now polymorphic:

    ?- X is 1/3.
    X = 0.3333333333333333.

    ?- X is 1/0m3.
    X = 0m0.3333333333333333333333333333333333.

    The first division is the less precise double conversion
    based division if the arguments are integer or double.
    The second is also a less precise division, this

    time based on quadruple conversion. The prefix 0m
    is the syntax for the new upcoming quadruple type
    in formerly Jekejeke Prolog.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Mild Shock@21:1/5 to Mild Shock on Sat Sep 9 11:13:00 2023
    My newest take in formerly Jekejeke Prolog and Dogelog
    Player, now behaving the same for this test case. This
    is a preview, these versions have not yet been officially released:

    /* Jekejeke Prolog, 1.6.3 */
    ?- X is append(1,2).
    Error: Argument should have evaluable functor, found append/2.
    ?- X is append([1,2],[3]).
    Error: Argument should have evaluable functor, found append/2.

    /* Dogelog Player, 1.1.1, nodeJS */
    ?- X is append(1,2).
    Error: Argument should have evaluable functor, found append/2.
    ?- X is append([1,2],[3]).
    Error: Argument should have evaluable functor, found append/2.

    /* Dogelog Player, 1.1.1, PyPy */
    ?- X is append(1,2).
    Error: Argument should have evaluable functor, found append/2.
    ?- X is append([1,2],[3]).
    Error: Argument should have evaluable functor, found append/2.

    Mild Shock schrieb am Samstag, 9. September 2023 um 20:09:47 UTC+2:
    I am still fiddling around with (is)/2 implementation.
    Formerly Jekejeke Prolog had traditionally automatic
    bridging and tunneling. This is all going down the drain,

    we want to become more GNU Prolog compatible. Novacore
    should be as puritanical as possible, namely a Prolog core that
    has an upbringing that disapproves the suggar laced world of

    formerly Jekejeke Prolog! Funny discovery, not all Prolog
    systems throw the same evaluable errors. Here a little
    discrepancy between GNU Prolog and SWI-Prolog:

    /* GNU Prolog */
    ?- X is append(1,2).
    uncaught exception: error(type_error(evaluable,append/2),(is)/2)
    ?- X is append([1,2],[3]).
    uncaught exception: error(type_error(evaluable,append/2),(is)/2)

    /* SWI-Prolog */
    ?- X is append(1,2).
    ERROR: Arithmetic: `append/2' is not a function
    ?- X is append([1,2],[3]).
    ERROR: Type error: `[]' expected, found `[1,2]' (a list)
    ("x" must hold one character)

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Mild Shock@21:1/5 to All on Sat Sep 9 11:09:45 2023
    I am still fiddling around with (is)/2 implementation.
    Formerly Jekejeke Prolog had traditionally automatic
    bridging and tunneling. This is all going down the drain,

    we want to become more GNU Prolog compatible. Novacore
    should be as puritanical as possible, namely a Prolog core that
    has an upbringing that disapproves the suggar laced world of

    formerly Jekejeke Prolog! Funny discovery, not all Prolog
    systems throw the same evaluable errors. Here a little
    discrepancy between GNU Prolog and SWI-Prolog:

    /* GNU Prolog */
    ?- X is append(1,2).
    uncaught exception: error(type_error(evaluable,append/2),(is)/2)
    ?- X is append([1,2],[3]).
    uncaught exception: error(type_error(evaluable,append/2),(is)/2)

    /* SWI-Prolog */
    ?- X is append(1,2).
    ERROR: Arithmetic: `append/2' is not a function
    ?- X is append([1,2],[3]).
    ERROR: Type error: `[]' expected, found `[1,2]' (a list)
    ("x" must hold one character)

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Mild Shock@21:1/5 to Mild Shock on Sat Sep 9 13:18:19 2023
    The internal call is tail recursive I guess, since the functor is
    already checked, and a looked up handle, a function pointer,
    causes the evaluation. Recently GNU Prolog has moved to GitHub,

    so I can find the source code of GNU Prolog stuff more easily, things
    like Load_Math_Expression. But I think the GNU Prolog approach is
    only feasible, if you dare to rely on the native stack.

    Concerning the new Java foreign function interface. I switched
    from handles obtained by method reflection to handles that were
    populated via functional interfaces. Its an itch faster, and close

    to SWI-Prolog optimised, but only for JDK 8:

    /* Jekejeke Prolog, 1.6.3, JDK 8, Functional Interface */
    ?- time(test).
    % Time 171 ms, GC 2 ms, Wall 09/09/2023 22:04
    true.

    The above uses the native stack like GNU Prolog and no
    cycle testing nothing. But I guess it burns CPU since it uses
    two pointers to represent a term. I hope I can soon get rid of that.

    Another brake could be the varargs array allocation.

    Mild Shock schrieb am Samstag, 9. September 2023 um 22:17:13 UTC+2:
    I started using this test case:

    test :-
    between(0,1000000,N),
    _ is exp(1+N/1000000),
    fail.
    test.

    To test a new Java foreign function interface. I then
    observed that SWI-Prolog stack engine causes
    a little overhead:

    /* SWI-Prolog, 9.1.14, optimise=false */
    ?- time(test).
    % 2,000,001 inferences, 0.313 CPU in 0.315 seconds
    (99% CPU, 6400003 Lips)
    true.

    /* SWI-Prolog, 9.1.14, optimise=true */
    ?- time(test).
    % 1,000,002 inferences, 0.172 CPU in 0.176 seconds
    (98% CPU, 5818193 Lips)
    true.

    Intrestingly GNU Prolog doesn’t use a stack engine,
    just relies on the native stack. Its quite speedy without
    any optimisation:

    /* GNU Prolog 1.5.0 (64 bits) */
    ?- test.
    (125 ms) yes

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Mild Shock@21:1/5 to All on Sat Sep 9 13:17:11 2023
    I started using this test case:

    test :-
    between(0,1000000,N),
    _ is exp(1+N/1000000),
    fail.
    test.

    To test a new Java foreign function interface. I then
    observed that SWI-Prolog stack engine causes
    a little overhead:

    /* SWI-Prolog, 9.1.14, optimise=false */
    ?- time(test).
    % 2,000,001 inferences, 0.313 CPU in 0.315 seconds
    (99% CPU, 6400003 Lips)
    true.

    /* SWI-Prolog, 9.1.14, optimise=true */
    ?- time(test).
    % 1,000,002 inferences, 0.172 CPU in 0.176 seconds
    (98% CPU, 5818193 Lips)
    true.

    Intrestingly GNU Prolog doesn’t use a stack engine,
    just relies on the native stack. Its quite speedy without
    any optimisation:

    /* GNU Prolog 1.5.0 (64 bits) */
    ?- test.
    (125 ms) yes

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Mild Shock@21:1/5 to Mild Shock on Sun Sep 10 14:45:52 2023
    Ok there is a big confusion in SWI-Prolog discourse, I was
    mentioning native stack, and people think I was talking
    about native code. Holy cow! Do I speak chinese, or what?

    Just look for yourself. Step 1: Go to GNU Prolog GitHub,
    Step 2: Lookup the C function Load_Math_Expression
    Interesting find, for Dogelog Player on CPython so far:

    /* Dogelog Player 1.1.1, CPython */
    ?- X=1+X, Y is X.
    Unknown exception: 'maximum recursion depth exceeded'

    What does PyPy do? What does JavaScript do? How do we
    handle this exception. Are there more candidates than only (is)/2,
    like for example copy_term/2, etc.. This would cover Dogelog

    Player. What about formerly Jekejeke Prolog, respectively Java?

    Mild Shock schrieb am Samstag, 9. September 2023 um 22:18:21 UTC+2:
    The internal call is tail recursive I guess, since the functor is
    already checked, and a looked up handle, a function pointer,
    causes the evaluation. Recently GNU Prolog has moved to GitHub,

    so I can find the source code of GNU Prolog stuff more easily, things
    like Load_Math_Expression. But I think the GNU Prolog approach is
    only feasible, if you dare to rely on the native stack.

    Concerning the new Java foreign function interface. I switched
    from handles obtained by method reflection to handles that were
    populated via functional interfaces. Its an itch faster, and close

    to SWI-Prolog optimised, but only for JDK 8:

    /* Jekejeke Prolog, 1.6.3, JDK 8, Functional Interface */
    ?- time(test).
    % Time 171 ms, GC 2 ms, Wall 09/09/2023 22:04
    true.

    The above uses the native stack like GNU Prolog and no
    cycle testing nothing. But I guess it burns CPU since it uses
    two pointers to represent a term. I hope I can soon get rid of that.

    Another brake could be the varargs array allocation.
    Mild Shock schrieb am Samstag, 9. September 2023 um 22:17:13 UTC+2:
    I started using this test case:

    test :-
    between(0,1000000,N),
    _ is exp(1+N/1000000),
    fail.
    test.

    To test a new Java foreign function interface. I then
    observed that SWI-Prolog stack engine causes
    a little overhead:

    /* SWI-Prolog, 9.1.14, optimise=false */
    ?- time(test).
    % 2,000,001 inferences, 0.313 CPU in 0.315 seconds
    (99% CPU, 6400003 Lips)
    true.

    /* SWI-Prolog, 9.1.14, optimise=true */
    ?- time(test).
    % 1,000,002 inferences, 0.172 CPU in 0.176 seconds
    (98% CPU, 5818193 Lips)
    true.

    Intrestingly GNU Prolog doesn’t use a stack engine,
    just relies on the native stack. Its quite speedy without
    any optimisation:

    /* GNU Prolog 1.5.0 (64 bits) */
    ?- test.
    (125 ms) yes

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Mild Shock@21:1/5 to Mild Shock on Mon Sep 11 14:31:47 2023
    Is there any use case for the cycle check? It gives an error more earlier.
    If one has a resource quota, one would also get an error only a little bit later, when the stack is to large and some memory is exhausted.

    Here is a sketch of a post mortem analysis, even written in 100%
    pure Prolog, which gives an error analysis service:

    X is Y :-
    catch(eval(Y,X), error(foo,_),
    (acyclic_term(Y) -> throw(error(bar,_)); throw(error(baz,_)))).

    The single error “foo” produced by the internal eval/2 predicate
    is changed into either an error “bar” or an error “baz”, to provide the end-user some more information. Can be also implemented

    natively by the builtin is/2, making a cycle test during eval/2
    unnecessary, since acyclic_term/1 exists. Or is there a danger
    that acyclic_term/1 crashes? It probably uses less stack than eval/2.

    Mild Shock schrieb am Sonntag, 10. September 2023 um 23:45:55 UTC+2:
    Ok there is a big confusion in SWI-Prolog discourse, I was
    mentioning native stack, and people think I was talking
    about native code. Holy cow! Do I speak chinese, or what?

    Just look for yourself. Step 1: Go to GNU Prolog GitHub,
    Step 2: Lookup the C function Load_Math_Expression
    Interesting find, for Dogelog Player on CPython so far:

    /* Dogelog Player 1.1.1, CPython */
    ?- X=1+X, Y is X.
    Unknown exception: 'maximum recursion depth exceeded'

    What does PyPy do? What does JavaScript do? How do we
    handle this exception. Are there more candidates than only (is)/2,
    like for example copy_term/2, etc.. This would cover Dogelog

    Player. What about formerly Jekejeke Prolog, respectively Java?
    Mild Shock schrieb am Samstag, 9. September 2023 um 22:18:21 UTC+2:
    The internal call is tail recursive I guess, since the functor is
    already checked, and a looked up handle, a function pointer,
    causes the evaluation. Recently GNU Prolog has moved to GitHub,

    so I can find the source code of GNU Prolog stuff more easily, things
    like Load_Math_Expression. But I think the GNU Prolog approach is
    only feasible, if you dare to rely on the native stack.

    Concerning the new Java foreign function interface. I switched
    from handles obtained by method reflection to handles that were
    populated via functional interfaces. Its an itch faster, and close

    to SWI-Prolog optimised, but only for JDK 8:

    /* Jekejeke Prolog, 1.6.3, JDK 8, Functional Interface */
    ?- time(test).
    % Time 171 ms, GC 2 ms, Wall 09/09/2023 22:04
    true.

    The above uses the native stack like GNU Prolog and no
    cycle testing nothing. But I guess it burns CPU since it uses
    two pointers to represent a term. I hope I can soon get rid of that.

    Another brake could be the varargs array allocation.
    Mild Shock schrieb am Samstag, 9. September 2023 um 22:17:13 UTC+2:
    I started using this test case:

    test :-
    between(0,1000000,N),
    _ is exp(1+N/1000000),
    fail.
    test.

    To test a new Java foreign function interface. I then
    observed that SWI-Prolog stack engine causes
    a little overhead:

    /* SWI-Prolog, 9.1.14, optimise=false */
    ?- time(test).
    % 2,000,001 inferences, 0.313 CPU in 0.315 seconds
    (99% CPU, 6400003 Lips)
    true.

    /* SWI-Prolog, 9.1.14, optimise=true */
    ?- time(test).
    % 1,000,002 inferences, 0.172 CPU in 0.176 seconds
    (98% CPU, 5818193 Lips)
    true.

    Intrestingly GNU Prolog doesn’t use a stack engine,
    just relies on the native stack. Its quite speedy without
    any optimisation:

    /* GNU Prolog 1.5.0 (64 bits) */
    ?- test.
    (125 ms) yes

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)