Flowlog is an ISO-style Prolog system implemented as
a single,
portable C file (flowlog.c), with a focus on
running unmodified Prolog search faster on multicore
CPUs.
It provides:
- A small, self-contained Prolog runtime (no external libraries required beyond libc + pthreads)
- Multiple execution engines (
wamvm,wam,interp/tree) - Optional OR-parallelism (parallel exploration of choicepoints) and conservative AND-parallelism (parallel execution of independent subgoals when safe)
- A practical REPL with history and line editing
- An ISO conformance workflow (INRIA suite + regression tests)
Why it exists
Prolog is a great fit for search problems, constraint-style programming, and symbolic manipulation, but classic implementations tend to exploit only limited parallelism automatically. Flowlog’s goal is to keep Prolog’s familiar ISO semantics while also making it easy to:
- Use all available CPU cores during nondeterministic search
- Trade strict, classic “left-to-right” solution ordering for throughput when desired
- Keep a simple “one C file” implementation that is easy to build and embed
Quick start
git clone:
git clone https://git.liminal.cafe/byakuren/flowlog.gitBuild:
Or compile directly:
cd flowlog
cc -O2 -Wall -Wextra -pthread flowlog.c -lm -o flowlogRun the REPL:
Load a file and run a goal:
./flowlog program.pl -g 'main.'Control the number of worker threads:
./flowlog --threads 12 program.pl -g 'goal(X).'Engines (and defaults)
Flowlog ships three execution engines:
wamvm- bytecode WAM VM (default). Designed to be fast and parallel-friendly; may fall back towam/interpif a feature is not supported in VM-only mode.wam- a “WAM-lite” direct solver (still a Prolog engine, but not a classic WAM bytecode VM).interp/tree- a full tree-walking interpreter (useful as the most conservative reference behavior).
Select an engine:
./flowlog --engine wamvm program.pl -g 'goal.'
./flowlog --engine wam program.pl -g 'goal.'
./flowlog --engine interp program.pl -g 'goal.'Parallelism
Flowlog’s parallel features are opt-in/controllable so you can choose between classic behavior and maximum throughput:
- OR-parallelism: splits choicepoints across workers (best for large search spaces)
- AND-parallelism: runs proven-safe independent subgoals in parallel (conservative by design)
The main user-facing switch is the parallel profile:
fast- prefer throughput; may return solutions in a different order than classic Prologiso- prioritize classic ordering/behavior where possibleoff- disable Flowlog parallelism features
./flowlog --parallel-profile fast program.pl -g 'goal.'
./flowlog --parallel-profile iso program.pl -g 'goal.'
./flowlog --parallel-profile off program.pl -g 'goal.'Flowlog also supports the same controls as Prolog flags (so an ISO Prolog program can enable them explicitly when running under Flowlog):
:- set_prolog_flag(flowlog_parallel_profile, fast).Parse diagnostics (with context)
Flowlog’s parser reports errors with file/line/column, a one-line source excerpt, and a caret pointing at the offending token:
flowlog: fatal error (240): flowlog: parse error: unexpected token after term: ) (TOK_RPAREN); expected '.' (TOK_DOT)
at incorrect-syntax.pl:6:12
(unexpected token after a complete term; check for a missing ',' between goals or a missing operator)
6 | N is X + 1).
| ^
...
flowlog: fatal error (240): flowlog: unexpected token while parsing term: ) (TOK_RPAREN)
at program.pl:1:6
expected one of: '(', '[', atom, string, number, variable
(')' closes a group/call; a term was expected before it)
1 | p :- ).
| ^
See docs/TROUBLESHOOTING.md
for more examples (including read_term/2,3 lexer errors
like illegal_character_escape).
ISO conformance
Flowlog targets ISO/IEC 13211-1 behavior for the core language and built-in predicates. The recommended way to check conformance in this repo:
make test # run regression tests
make inria # run the inria test suite
make quad # run all existing quad testsTo lock in that the INRIA suite runs entirely in the
wamvm VM (no fallback):
Documentation
to-do file:
Start here:
README.md- high-level overviewQUICKSTART.md- build + first runUSER_GUIDE.md- using Flowlog as a Prolog system (REPL, loading, running)CLI.md- CLI flags and environment variables
Core references:
PREDICATES.md- built-in predicates and evaluable functorsISO_CHECKLIST.md- checklist of ISO predicate coverageCONFORMANCE.md- conformance strategy + test suites
Parallel/runtime internals:
PARALLELISM.md- OR/AND parallelism model, profiles, tradeoffsIMPLEMENTATION.md- overall architecture (parser -> program -> engine -> runtime)TECHNICAL_DETAILS.md- data structures, memory model, low-level notesWAM_ROADMAP.md- notes/roadmap for engine coverage and performance work
Contributing:
DEVELOPMENT.md- development workflow and conventionsTROUBLESHOOTING.md- common build/runtime issues
Benchmarks and tests:
BENCHMARKS.md- benchmark harnesses and reference programs (includes full source)TESTS.md- regression tests and ISO suite runners (includes full source)QUAD_TESTS.md- quad conformance tests (format, runners, logs)
Performance comparison
These tables are derived from the raw timing logs in this repo: magic_square_timings.txt
and nqueens_timings.txt.
Times are wall-clock real seconds (lower is better), sorted
fastest -> slowest.
Magic square timings (magic_square(4, _)):
| program | engine | profile | time |
|---|---|---|---|
magic_square(4) |
flowlog-wamvm |
fast |
34.76s |
magic_square(4) |
flowlog-wam |
fast |
37.28s |
magic_square(4) |
flowlog-wamvm |
iso |
115.27s |
magic_square(4) |
flowlog-wam |
iso |
125.12s |
magic_square(4) |
flowlog-tree |
fast |
271.67s |
magic_square(4) |
flowlog-tree |
iso |
637.05s |
magic_square(4) |
scryer-prolog |
- |
1815.01s |
magic_square(4) |
tpl |
- |
2636.00s |
N-queens timings (nqueens(13, _)):
| program | engine | profile | time |
|---|---|---|---|
nqueens(13) |
flowlog-wamvm |
fast |
1.82s |
nqueens(13) |
flowlog-wam |
fast |
6.95s |
nqueens(13) |
flowlog-wamvm |
iso |
7.57s |
nqueens(13) |
flowlog-wam |
iso |
7.71s |
nqueens(13) |
flowlog-tree |
fast |
14.19s |
nqueens(13) |
flowlog-tree |
iso |
25.00s |
nqueens(13) |
scryer-prolog |
- |
30.39s |
nqueens(13) |
tpl |
- |
41.42s |
A short history of parallel Prolog (and what’s different here)
Parallel execution in Prolog has a long research lineage:
- OR-parallelism (splitting different clause alternatives/choicepoints across workers) appeared in systems like Muse and Aurora.
- AND-parallelism (running independent subgoals in parallel) was explored in systems like &-Prolog and related work on dependency analysis.
- Practical systems often combine these ideas with other features (tabling, indexing, compilation, constraints) but typically require either explicit parallel constructs or careful programming patterns to get consistent wins.
Flowlog’s approach is:
- Keep the surface language close to ISO Prolog.
- Provide a fast-by-default runtime profile for search workloads (unordered when permitted).
- Make parallelism a runtime policy (flags/profiles), not a separate language.
- Keep the whole system small, hackable, and easy to build as a single C source file.
If you’re new: start with QUICKSTART.md, then skim USER_GUIDE.md and PARALLELISM.md.
Version history
Flowlog has gone through a few distinct implementation phases. This is a high-level timeline of the ideas that shaped the current system:
- v4 - WAMVM engine: Added a bytecode-based WAM VM
(
wamvm) as the default engine, aiming for higher instruction-cache locality and tighter inner loops while still supporting Flowlog’s OR/AND parallel policies. VM-only conformance runs (no fallback) make it easier to track and close remaining feature gaps. - v2 - WAM-lite engine: Introduced a faster execution core than the interpreter, keeping the same surface language while improving clause selection, unification, and backtracking hot paths. This was the first “compiled-ish” step toward closing the performance gap with established Prolog systems while preserving Flowlog’s parallel hooks.
- v1 - tree-walking engine (pure C + pthreads): A standalone implementation that removed BMDFM constraints and made it easier to reason about performance, memory layout, and scheduling. This phase focused on correctness (ISO-style behavior), a practical REPL, and making OR-parallelism a first-class runtime policy.
- v0 - BMDFM-based prototype: The original Flowlog experiments were built on top of the BMDFM runtime, using its flow/parallel model to explore how Prolog search could map onto a graph-like execution substrate (especially OR-parallel search and “run independent work at once” ideas).
The best way to contact me with any feedback, or even just to chat is on IRC
- server:
irc.libera.chat - channel:
#flowlog - my nick:
byakuren
see you there!