Cyclops Storm / Lab notes

Prolog features: SWI-Prolog and the rewrite

The rewrite supports a useful subset of Prolog, with important differences in defaults, recursion and available libraries. This comparison records 34 executable probes against the September 2026 rewrite and SWI-Prolog 10.0.2. It describes observed behavior on those examples, not complete ISO conformance or a general correctness score.

Raw programs, answers and errors · Reproduction script · Engine design and known gaps · Performance measurements.

How to read the comparison

Match means the tested behavior agrees. Different default means ordinary use differs, sometimes with an option to change it. Restricted means the rewrite rejects a program SWI can run. Unavailable in probe means the feature did not work through the tested syntax or predicate; the row records whether it failed quietly or raised an error. A quiet failure marked complete is especially easy to mistake for a meaningful negative answer.

Each row names its probe ID in the linked raw results. SWI links explain the reference behavior; the transcripts establish what the installed version actually did. Multiple predicates in one row are only checked in the modes shown in the probe. A match does not establish every argument mode, edge case, or interaction with tabling.

Terms, syntax and answers

Feature SWI-Prolog Rewrite: observed behavior Evidence
Facts, rules and conjunction Infers g(a,c) through two related facts. Control Match: the same inference succeeds. rules
Cyclic unification X = f(X) succeeds with the default occurs-check setting. Unification Different default: returns no answers; occurs checking is enabled. occurs-check
Integer versus float 1 does not unify with 1.0. Unification Match: 1 \= 1.0 succeeds. numeric-types
Double-quoted text atom("abc") is false under the default string syntax. Strings Different default: succeeds; double quotes produce an atom. double-quotes
Character-code literal 0'a evaluates to 97. Syntax Unavailable in probe: query parsing raises SyntaxErrorInSource. character-code
Defining operators op(500,xfy,likes) succeeds. op/3 Unavailable in probe: no answers, status complete. operators
Duplicate answers Two p(a) clauses yield two answers to p(X). Collecting solutions Different default: ask returns one; ask(..., distinct=False) returns two for this untabled predicate. duplicates, duplicates-opt-out

The duplicate comparison concerns the Python query boundary: it does not mean duplicates disappear inside every Prolog construct. The findall/3 probe below preserves them.

Control, recursion and errors

Feature SWI-Prolog Rewrite: observed behavior Evidence
Cut in an untabled predicate A cut in the first clause removes the later alternative. Cut Match: returns only a, not b. cut
If-then-else A failing condition selects the else branch. Control Match on the tested branch. if-then-else
Soft cut (*->) Preserves both successful condition bindings in the example. Control Match: returns a and b. soft-cut
Negation as failure Failed inner search leaves X unbound. Negation Match on the binding-isolation example. negation
Calling goals and taking one solution call/3 and once/1 succeed in the example. Meta-calls Match for these forms; higher call arities are not covered here. meta-call
Left recursion with tabling With an explicit table path/2 directive, finds both reachable nodes. Tabling Different default: automatically tables the recursive predicate and finds the same two nodes without a directive. left-recursion
Cut in a recursive predicate The untabled example succeeds and prunes its recursive alternative. Cut Restricted: automatic tabling causes a SemanticConflict. This does not compare cuts inside SWI tables. recursive-cut
Recursion through negation The finite win(b) example succeeds under ordinary execution. Negation Restricted: rejects the predicate's dependency on its own negation with SemanticConflict. recursive-negation
Undefined predicate Raises an existence error. Prolog flags Different default: no answers, status complete. With unknown_fails=False, raises UnknownPredicateError. unknown, unknown-strict
Prolog exception handling catch(throw(ball),ball,true) succeeds. Exceptions Unavailable in probe: no answers, status complete. Python exceptions from the engine are a separate mechanism. exceptions

The left-recursion probe has a finite set of calls and answers. It establishes neither unrestricted termination nor full equivalence with SWI's SLG tabling and well-founded negation. Resource limits and the rewrite's static restrictions remain relevant; see Tabling and Negation.

Arithmetic and data predicates

Feature SWI-Prolog Rewrite: observed behavior Evidence
Negative integer division -10 // 3 is -3; -10 div 3 is -4. Arithmetic Match: truncation and floor division differ correctly. arithmetic
Invalid arithmetic X is a + 1 raises an evaluable-type error. Arithmetic Match in error category: raises Python TypeCheckError; the exception representation differs. arithmetic-error
List operations Append, membership and length satisfy the example's exact constraints. Lists Match for append/3, member/2, length/2 in the tested modes. lists
findall/3 Collects [a,a] from duplicate clauses. All solutions Match: preserves multiplicity inside the collected list. findall
bagof/3 and setof/3 Produces [b,a,a] and [a,b], respectively. All solutions Match on this example; free-variable grouping and existential qualification are not exercised. bagof-setof
Sorting sort/2 removes duplicates; msort/2 retains them. Term ordering and sorting Match on the tested atom list. Mixed-type ordering is not tested here. sort
Term inspection Decomposes f(a,b) and reads its functor, arity and second argument. Terms Match for =../2, functor/3, arg/3 in these modes. term-inspection
Atom operations Concatenation, length and atom-to-number conversion succeed. Atoms Match for the tested calls to atom_concat/3, atom_length/2, atom_number/2. atom-conversion

Database, libraries and extensions

Feature SWI-Prolog Rewrite: observed behavior Evidence
Updating facts from a Prolog goal Asserts, queries and retracts a fact. assertz/1 Unavailable in probe: the conjunction fails quietly at assertz/1; later goals are not reached. The Python update API is separate. dynamic-database
DCG grammars Expands s --> [a] and recognizes [a] with phrase/2. DCGs Unavailable in probe: loading does not raise an error, but phrase(s,[a]) returns no answers, complete. Accepted syntax alone does not demonstrate DCG support. dcg
Module-qualified calls lists:member(a,[a]) succeeds. Modules Unavailable in probe: returns no answers, complete. modules
Integer constraints With library(clpfd) loaded, X #= 2, X #> 1 succeeds. CLP(FD) Unavailable in probe: constraint syntax raises SyntaxErrorInSource. constraints
Disequality constraint dif(X,a), X=b succeeds. dif/2 Unavailable in probe: returns no answers, complete. dif
Delayed goals freeze(X,X=b), X=b succeeds. Coroutining Unavailable in probe: returns no answers, complete. freeze
Prolog output write(probe_output) prints text and succeeds. write/1 Unavailable in probe: no output and no answers, complete. io

These probes cover selected Prolog-facing operations. They do not evaluate the Python embedding API, story-time reasoning, source-sentence provenance, or explanation quality. Those are documented separately in Engine and the migration comparison. The older 21 shared cross-checks compare the two Python engines; this feature inventory is a separate experiment and does not change their scores.

Verification and reproduction

Run September 25, 2026 in America/New_York (September 26 UTC), using Python 3.12.10 on Windows 11, SWI-Prolog 10.0.2, and clean rewrite commit 9be7804c933cc8a3c51af3d8a5e4f54b012c8be6. The SWI documentation links are live reference pages and may describe a newer release; version-specific observations come from the saved run.

Each of the 34 probes runs in a fresh subprocess for each engine, with a ten-second external deadline. No probe timed out. The rewrite uses a new KnowledgeBase and default ask settings, except the explicitly labeled duplicate and strict-unknown probes. SWI starts with -f none; only the left-recursion probe adds a table directive and only the constraint probe adds a library directive. Standard SWI autoloading remains enabled.

The script records source programs, query strings, options, rewrite statuses and native answers, SWI canonical answer transcripts, errors, environment, timestamps and the script hash. The SWI wrapper collects instantiated copies of the whole goal; the rewrite records variable bindings. These representations are deliberately retained separately. The table's comparisons were reviewed against both transcripts; the script does not compute a compatibility percentage. Several queries contain exact-value constraints, while others expose values or duplicate counts for inspection.

python -B evidence/probe-prolog-features.py --repo "C:/path/to/AkiyaBlocks-CyclopsStorm" --output "prolog-features.json"

The clean pinned private checkout is required. The script defaults to C:/Program Files/swipl/bin/swipl.exe; use --swipl for another installation. It changes neither engine. These examples are a reproducible starting point for compatibility work, not an exhaustive feature specification: threads, transactions, foreign interfaces, every built-in, and combinations of features remain outside this run.