Ann: SWI-Prolog 8.5.18

Dear SWI-Prolog user,

SWI-Prolog 8.5.18 is ready for download. Quite a few things happened.

  • @oskardrums “sweep” Prolog mode is now bundled, which should make
    it easy to obtain the shared object that is required for running
    this nice Emacs mode.

  • @j4n_bur53’s comments and @ridgeworks implementation work brought
    correct rounding and fast big integer and rational support to
    floats.

  • @peter.ludemann’s work on a new C++ interface is now included as
    SWI-cpp2.h. It is much more comprehensive and avoids many of the
    pitfalls of the old SWI-cpp.h. Unfortuantely there are still
    some problems with it. Notably we would like to see issues around
    character encodings settled. Still, if you start a new C++ project
    this should be your starting point. Porting old C++ projects is
    a good way to become future proof and evaluate the new interface.

  • Quite a few extensions to the WASM version. The basic interfaces
    should be close to stable.

  • @swi allowed help/1 to work on your own annotated predicates.

    Enjoy — Jan

SWI-Prolog Changelog since version 8.5.17

  • WASM: Do not use undocumented interfaces in test/demo.

  • WASM: Issue#1052: make output of Prolog.query().once() easier to
    handle.

  • FIXED: help/1 for normal built-in predicates (broke after support
    for user predicates). Patch by @swi.

  • ADDED: Colour test/1 and test/2 heads and classify them as tests when
    inside a unit test body.

  • ADDED: library(prolog_xref): Make aware of unit tests

  • ADDED: Allow help/1 on user predicates. Contributed by @swi

  • ADDED: make_reload_file/1 to make correct reloading of a file public.

  • TEST: Add additional float rounding test cases for various integer
    sub-types.

  • ENHANCED: New (faster) function for converting bigints (MPZ) to float
    Also includes minor adjustments for some mpz_fdiv rounding modes.

  • DOC: Fixed LaTeX errors

  • ENHANCED: Replace mpz_fdiv() with a version that rounds to nearest.

  • CLEANUP: Introduce mpz_to_double()

  • FIXED: Added missing import for pi_head/2 in library(prolog_xref).

  • PORT: swipl --abi-version: VM signature hash depended on big/little
    endian.

  • ADDED: PL_atom_mbchars() to extract text from an atom in various
    encodings.

  • ADDED: PL_cvt_i_[u]int32() for consistency.

  • PORT: Avoid false alarm warning from gcc on 32-bit Windows.

  • PORT: Windows: fixed compilation of the DDE interface after adding
    FUNCTOR_error1 to the core system.

  • FIXED: Instantiation error in cross-referencer.

  • FIXED: xref_source/1: avoid lazy definition of predicates in user
    by calling predicate_property(user:Goal, ...).

  • FIXED: prolog_set_IO/3: stderr wrapper interpreted return code from
    low-level output wrong. This causes problems if output is connected
    to a socket as used by prolog_server/2.

  • ENHANCED: Make toplevel quit nicely if the I/O streams are in error
    state.

  • ADDED: stream_property(S, error(Boolean)).

  • PORT: Msys2, fix LibDir for swipl in build env

  • ADDED: sweep package - integration with GNU Emacs

  • FIXED: Windows: directory_files/2 and other directory access for
    long paths. Fixed by @mgondan1. Thanks!

  • ENHANCED: portray_clause/1: add space after (?- goal).

  • WASM: Avoid error on HTMLCollection on node

  • FIXED: Windows: long file support was broken again.

  • FIXED: Handle reexport/1 and reexport/2 properly in multi-file
    .qlf files. Reported by @swi.

  • DOC: syntax error handling in conditional compilation.

  • ENHANCED: ^ and ** arithmetic operator optimization for small integer
    use cases to avoid relying on GMP. This patch also uses integer
    exponentiation when compiled without GMP when possible and handles
    all special cases compatible with the GMP based version.

  • ENHANCED: Use __builtin_mul_overflow() when available to do fast
    overflow-safe multiplication.

  • TEST: Silence syntax error on a rational number when compiled without
    rational support.

  • MODIFIED: When inside code fragment under conditional compilation
    where the code is ignored, do not report syntax errors.

  • WASM: Added CHAT80 demo.

  • FIXED: Prolog.Compound.toJSON()

  • WASM: Avoid dependency on HTMLCollection to run on node.

  • MODIFIED: WASM: Prolog.consult() now calls load_files/1, allowing it
    to handle a mixture of local files, URLs as well as Prolog sources
    and .qlf files. The sources are now processed sequentially and
    are no longer materialised as files.

  • DOC: Improved WASM documentation.

  • ADD: License to CBG Chords example

  • ADDED: qcompile/2: option include(user). This option allows for
    compiling an application into a single Prolog .qlf file.

  • ADDED: load_files/2: option if(Cond) is extended with exists to
    silently not load a file if it does not exist.

  • FIXED: det/1 was not declared as a proper meta-predicate.

  • WASM: Allow translation of JavaScript ArrayBuffer into a Prolog
    byte-string. This allows extracting binary data from Response.blob()
    and is used by the WASM compilation hook to allow loading .qlf
    files from URLs.

  • BUILD: Allow building with AddressSanitizer on Clang. Based on
    patches by Alessandro Bartolucci. Thanks!

Package clib

  • ENHANCED: prolog_server/2: ensure the server thread terminates,
    also if the client disappears with an error. Improved docs.

Package cpp

  • TEST: Remove .as_string.c_str() as this is unsafe.

  • DOC: Document both version 1 and version 2.

  • DOC: Setup for documenting both SWI-cpp.h and SWI-cpp2.h

  • ENHANCED: added PlTerm::record(), PlTerm::write(), PlTerm_recorded,
    PlRewindOnFail(), PlStringBuffers Removed PlTerm::unify_check()
    Added example code for backtracking predicate that gets info on int
    types Fixing integer overloading for win32, MacOS - remove many of the
    overloaded methods and instead use names derived from the underlying
    SWI-Prolog PL_put
    () and PL_unify*()

  • DOC: Added a porting section

  • PORT: Make SWI-cpp2.h compile on systems where long int is 32 bits
    (Win64). Patch by Peter Ludemann.

  • CLEANUP: better reuse of Prolog exceptions.

  • ENHANCED: Version 2 of C++ interface - removed some implicit
    conversions and constructors whose use can cause subtle bugs -
    made most conversions and constructors explicit - added subclass
    constructors to make Prolog types explicit and avoid some subtle bugs

    • added copy constructors, assignment operators - renamed handle_,
      ref_ to C_, for simplified “getter/setter” - added PlCheck() for
      easier calling of SWI-Prolog.h functions - removed conversion
      (cast) operator - added pseudo-exception PlFail for returning
      failure from a PREDICATE - also used by the unify_XXX_ex() methods -
      deprecated assignment operator for term unification - replaced by
      unify_XXX() and unify_XXX_ex() methods - added some support for
      std::string, std::wstring - and additional support for wchar_t -
      added some more methods that allow using PlTerm:xxx(…) instead of
      PL_xxx(t.get_term_t(), …); also for PlAtom - added PlTerm::type(),
      PlTerm::is_variable(), etc. methods - moved atom_t handle into private
      PlAtom, term_t into private PlTerm - added get_atom_t(), get_term_t() -
      added verify(), is_valid(), reset() methods - some refactoring, e.g.,
      PlTerm::check(), PlTerm::null - refactored the integer “getters”
      to get around problems with C++ built-in conversions and integer
      promotion. - refactored comparison methods, added PlTerm::compare() -
      replaced “int” as return type by “bool” in many places - use common
      C++ naming practice for class fields (suffixed by “_”) - added unit
      tests - moved examples from test.cpp to unit tests file (cpp4pl.cpp,
      test_cpp.pl) - used C++ initializer lists where possible - added
      [[nodiscard]] to many methods - added [[deprecated]] to some methods -
      (internal: used a template class to handle some boilerplate)

Package http

  • FIXED: term//2 from library(http/term_html) left a choicepoint.

Package semweb

  • DOC: Fixed LaTeX errors.

Package xpce

  • ENHANCED: PceEmacs: properties of predicates in status line (better
    text and ignore more irrelevant).

  • ADDED: pce_xref_gui:gxref_called/2 hook into gxref/0 to allow silencing
    predicates that are called by means of hooks or some other mechanism.

  • FIXED: gxref/0: edit predicate on click to properly handling included
    files.

  • PORT: suppress uninitialized warning in msys2 gcc

  • PORT: msys2-compatible mkdir and wildcards

4 Likes

Minor nit-pick for those who might care:

I think it’s better than that. mpz_fdiv() now rounds according to the current IEEE rounding mode; “to nearest” is the default.

2 Likes

Didn’t start testing yet of the new release. But a question, shouldn’t
HALF_EVEN be the default. Or are “to nearest” and HALF_EVEN

synonymous? Wiki tells me there are at least two “to nearest”:

  • Round to nearest, ties to even – rounds to the nearest value; if the number falls midway, it is rounded to the nearest value with an even least significant digit.
  • Round to nearest, ties away from zero (or ties to away) – rounds to the nearest value; if the number falls midway, it is rounded to the nearest value above (for positive numbers) or below (for negative numbers).

https://en.wikipedia.org/wiki/IEEE_754#Roundings_to_nearest

But then in Java BigDecimal there are even 3 “to nearest”,
HALF_EVEN, HALF_UP and HALF_DOWN.

Edit 10.10.2022
This one doesn’t work:

?- case2(N, X, Y), Z is float(X), Y =\= Z.
N = 56,
X = -1190359501396335678156200476672,
Y = -1.1903595013963357e+30,
Z = -1.1903595013963356e+30 ;
false.

From this test suite:

cases.p.log (14,6 KB)

MSYS2: I get an error in the unit tests for package cpp because the winsock function gethostbyname failed. The error code is 10093, winsock is not initialized. The problem can be fixed by calling WSAStartup beforehand and WSACleanup afterwards.

I guess this would go into the initialization and cleanup of cpp4pl.

1 Like

:frowning: @peter.ludemann , maybe we better backtrack and remove the gethostname() example. I know it comes from the documentation, but having a test that is not easily portable might not be a good idea. You could simply use get_test_hostname() to simply return "example.org"

1 Like

Or maybe return the string-ified version of one of the predefined macros? It seems that __TIMESTAMP__ is safe across compilers, for example:

For example, this has the same parameters as gethostname():

int gettimestamp(char* buf, size_t len)
{ if ( len <= 0 )
    return -1;
  strncpy(buf, __TIMESTAMP__, len);
  if ( buf[len - 1] )
    return -1; /* buf is too small */
  return 0;
}
1 Like

For now I pushed a14d19a37a193019a6061bd6295020e5d4b8d3a5 to cpp which replaces gethostname() simply by a dummy no_gethostname() with the same calling conventions. Now we do not depend on anything.

Note that using __TIMESTAMP__ gives us a binary that cannot be produced reproducible and that also causes some package managers to start complaining :slight_smile:

From IEEE 754 - Wikipedia

Round to nearest, ties to even is the default for binary floating point and the recommended default for decimal. Round to nearest, ties to away is only required for decimal implementations.

I believe the C floating point API only supports the default.

Maybe, maybe not. At least you seem to exercise more control
on the rounding than other Prolog systems do. Do you know
a test case to figure out what rounding a system, Prolog or not,

does, for its floating point numbers, independent of some bigint
conversion issues? Was trying the folllowing test and got
some surprise. There was first quite some agreement:

/* SWI-Prolog 8.5.18 */
?- X is 665723957508124892951320985600.0+26388279066624.0.
X = 6.65723957508125e+29.

/* Ciao Prolog 1.22.0 */
?- X is 665723957508124892951320985600.0+26388279066624.0.
X = 6.65723957508125e29 ?

/* Trealla Prolog 2.4.3 */
?- X is 665723957508124892951320985600.0+26388279066624.0.
   X = 6.65723957508125e+29.

/* Jekejeke Prolog 1.5.5 */
?- X is 665723957508124892951320985600.0+26388279066624.0.
X = 6.65723957508125E29.

But then suddently:

/* Scryer Prolog 0.9.0 */
?- X is 665723957508124892951320985600.0+26388279066624.0.
   X = 6.657239575081248e29.

/* ECLiPSe Prolog 7.0.61 */
?- X is 665723957508124892951320985600.0+26388279066624.0.
X = 6.6572395750812482e+29

?- X is 6.6572395750812482e+29-6.65723957508125E29.
X = -140737488355328.0.

Maybe this also explains the divergence in bigint to float conversion.
Maybe they have by accident a misconfigured FPU? Some init call
to the runtime system missing? Or a cheap floating point library?

But one is WSL2 and the other Windows!

The C specification API for rounding mode control <fenv.h> can be found in section 7.6 of https://www.open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf .In particular:

Each of the macros
FE_DOWNWARD
FE_TONEAREST
FE_TOWARDZERO
FE_UPWARD
is defined if and only if the implementation supports getting and setting the represented rounding direction by means of the fegetround and fesetround functions.

Evidence to the contrary, I would expect most computer language implementations would use the default round to nearest mode, since that’s what C does.

Among other things, SWIP provides an arithmetic function roundtoward/2 to control rounding mode during arithmetic evaluation. But I think this is uncharted territory for most Prologs. Eclipse supports bounded reals so there must be some control over rounding at some level, but I’m unfamiliar with the details.

Have to dig deeper, could be a parsing problem.
For the first summand, I get:

/* SWI-Prolog */
?- X is 665723957508124892951320985600.0.
X = 6.65723957508125e+29.

/* ECLiPSe Prolog */
?- X is 665723957508124892951320985600.0.
X = 6.6572395750812482e+29

I am not yet at a test case, which would give me
some information about rounding.

Or output? Seems to manufacture bogus output digits on demand:

?- X is float(665723957508124892951320985600), format("~18e",[X]).
6.657239575081249633e+29
X = 6.65723957508125e+29.

What can you trust?

It is still ok (not sure whether SWI-Prolog has integer/1 that can
deliver the same and atom_integer/3, what would you use format/2?):

?- X is integer(6.657239575081249633e+29), atom_integer(A, 2, X), write(A), nl.
10000110011100010001111100110111001001001100001111
11000000000000000000000000000000000000000000000000

The other decimal float number hits somewhere else binarily:

?- X is integer(6.6572395750812482e+29), atom_integer(A, 2, X), write(A), nl.
10000110011100010001111100110111001001001100001111
10100000000000000000000000000000000000000000000000

SWI-Prolog gives the same two different binaries with format('~2r',...)

4 ?- X is integer(6.657239575081249633e+29), format('~2r',[X]).
10000110011100010001111100110111001001001100001111  %added nl here
11000000000000000000000000000000000000000000000000
X = 665723957508124963320065163264.

5 ?- X is integer(6.6572395750812482e+29), format('~2r',[X]).
10000110011100010001111100110111001001001100001111  % added nl here
10100000000000000000000000000000000000000000000000
X = 665723957508124822582576807936.