Active logic meets Prolog — three-valued reasoning engine
Project description
Proact
Prolog has two truth values: succeed and fail. Proact adds a third: cont — work/reasoning in progress.
Every goal returns a status. Conjunction is a sequence. Disjunction is a selector. Backtracking only triggers on failure — cont and done cut the search. Between ticks, queries returning cont are automatically re-evaluated while the database persists, giving you a stateless tick loop for free.
Applications:
-
Reasoning under uncertainty. The three values map onto epistemic states: verified, undetermined, refuted. A conjunction of checks naturally implements iterative deepening — work focuses on the earliest unresolved premise. Unary operators give you cognitive control:
demotemeans "don't commit yet" (done→cont);promotemeans "don't give up yet" (fail→cont). This is relevant to validation layers for LLM reasoning, where forcing every check into true/false is lossy compression of the actual epistemic state. -
Behavior modeling. Reactive agents, planners, robot controllers — anything where logic meets time. Prolog gives you unification, backtracking, and pattern matching. Active logic adds temporal flow. You get behavior trees with the expressiveness of logic programming, without the trees.
Install
pip install git+https://github.com/eelstork/proact.git
Requires a C compiler (gcc, clang, or MSVC).
from proact import Proact
p = Proact()
p.add("mortal(X) :- human(X). human(socrates).")
print(p.query("mortal(socrates)")) # Result(status='done')
Tutorials
- Reasoning under uncertainty — from predicate logic to three-valued epistemics
- Behavior modeling — behavior trees via logic programming
Build
make
Usage
./proact # REPL
./proact file.pa # consult file, then REPL
./proact file.pa -e "goal." # evaluate goal and exit
./proact --max-ticks 100 -e "g." # limit tick count
The Transform
Conjunction (,) — Active logic AND / Sequence
fail cont done
fail fail fail fail
cont cont cont cont
done fail cont done
If the left goal is cont, the whole conjunction is cont — don't evaluate the right side yet.
Disjunction (;) — Active logic OR / Selector
fail cont done
fail fail cont done
cont cont cont cont
done done done done
If the left goal is done or cont, don't try alternatives.
Clause resolution
Multiple clauses for the same predicate provide choice points. Backtracking occurs only on fail — if a clause body returns cont or done, stop searching.
Tick loop
Queries returning cont are automatically re-evaluated on the next tick with a fresh environment. The database (asserted facts) persists between ticks.
Built-ins
| Predicate | Status | Description |
|---|---|---|
done / true |
done | Always succeeds |
fail / false |
fail | Always fails |
cont |
cont | Always continues |
inv(G) / \+ G |
swap done/fail, keep cont | Inverter |
condone(G) |
fail→done | Forgive failure |
promote(G) |
fail→cont, cont→done | Optimistic |
demote(G) |
done→cont, cont→fail | Pessimistic |
par_any(A,B) |
max(A,B) | Lenient parallel |
par_all(A,B) |
min(A,B) | Strict parallel |
tick(N) |
done | Unify N with current tick |
Plus standard Prolog: write/1, writeln/1, nl, assert/1, retract/1, is/2, =/2, \=/2, </2, >/2, >=/2, =</2, call/1, consult/1.
Examples
Wait N ticks, then succeed
wait(N) :- tick(T), T >= N.
wait(N) :- tick(T), T < N, cont.
?- wait(3), writeln(hello).
[tick 0] cont
[tick 1] cont
[tick 2] cont
hello
done.
Counter (stateful, using assert/retract)
:- assert(count(0)).
count_to(Target) :- count(N), N >= Target.
count_to(Target) :-
count(N), N < Target,
retract(count(N)), N1 is N + 1, assert(count(N1)),
cont.
Reactive behavior (condition-gated sequence)
:- assert(agent_pos(0)).
move_to(X) :- agent_pos(P), P =:= X.
move_to(X) :- agent_pos(P), P < X,
retract(agent_pos(P)), P1 is P + 1, assert(agent_pos(P1)), cont.
patrol :-
agent_pos(P), P < 3, move_to(3), cont.
patrol :-
agent_pos(P), P >= 3, P < 5, move_to(5), cont.
patrol :-
agent_pos(P), P >= 5.
Reasoning under uncertainty
% reason.pa — three-valued validation for multi-step arguments
:- assert(known(premise_a)).
:- assert(investigation(premise_b, 2)).
:- assert(investigation(premise_c, 1)).
check(P) :- known(P).
check(P) :- known_false(P), fail.
check(P) :-
investigation(P, N), N > 0,
retract(investigation(P, N)), N1 is N - 1,
(N1 > 0 -> assert(investigation(P, N1)) ; assert(known(P))),
cont.
argument :- check(premise_a), check(premise_b), check(premise_c).
The conjunction is the search strategy — it focuses work on the earliest unresolved premise and doesn't waste computation on steps whose preconditions haven't been met:
[tick 0] a=done, b=cont → cont (c never reached)
[tick 1] a=done, b=done, c=cont → cont (work shifts to c)
[tick 2] a=done, b=done, c=done → done
The epistemic operators give cognitive control over the validation:
cautious(X) :- demote(check(X)). % "verified but needs review" (done→cont)
keep_exploring(X) :- promote(check(X)). % "refuted but try harder" (fail→cont)
viable_theory :- par_any(hyp_a, hyp_b). % first hypothesis verified wins
Relation to active-logic
This prototype implements the core operators from activelogic-cs in a logic programming context:
| C# (activelogic-cs) | Proact | BT equivalent |
|---|---|---|
status && status |
Goal, Goal |
Sequence |
status || status |
Goal ; Goal |
Selector |
+ (lenient) |
par_any(A, B) |
Parallel (any) |
* (strict) |
par_all(A, B) |
Parallel (all) |
!status |
inv(G) |
Inverter |
~status |
condone(G) |
Condone |
+status (unary) |
promote(G) |
Promoter |
-status (unary) |
demote(G) |
Demoter |
cont |
cont |
Running |
The key addition over Prolog is cont — a single built-in that bridges logic programming with reactive, tick-based behavior.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distributions
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file proact_py-0.1.0.tar.gz.
File metadata
- Download URL: proact_py-0.1.0.tar.gz
- Upload date:
- Size: 18.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
df75099415ceaf942327555a0b28bb8ed5dc6c76529be8df65ee1cc1ec5dcac0
|
|
| MD5 |
74de37fcb09600c9dee5dcc32f195839
|
|
| BLAKE2b-256 |
0c95baf12f778aa955509fe65e3b698595419708316cfa3fcad335b254700b2c
|
Provenance
The following attestation bundles were made for proact_py-0.1.0.tar.gz:
Publisher:
release.yml on eelstork/proact
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
proact_py-0.1.0.tar.gz -
Subject digest:
df75099415ceaf942327555a0b28bb8ed5dc6c76529be8df65ee1cc1ec5dcac0 - Sigstore transparency entry: 1155357530
- Sigstore integration time:
-
Permalink:
eelstork/proact@a0572c10f23713a9f2e546efe3705e681ff666a4 -
Branch / Tag:
refs/tags/v0.1.11 - Owner: https://github.com/eelstork
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@a0572c10f23713a9f2e546efe3705e681ff666a4 -
Trigger Event:
push
-
Statement type:
File details
Details for the file proact_py-0.1.0-py3-none-win_amd64.whl.
File metadata
- Download URL: proact_py-0.1.0-py3-none-win_amd64.whl
- Upload date:
- Size: 100.9 kB
- Tags: Python 3, Windows x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b2cca34cf6c331594a27999f70b958309d9576155fb041c4262a3c94c9292f91
|
|
| MD5 |
da7e9fce5aa81823a714d816884dbb59
|
|
| BLAKE2b-256 |
0f9dc289c3f23062f0ff2e34c20a49078476bf9478e6e5fecb31927de6b7e017
|
Provenance
The following attestation bundles were made for proact_py-0.1.0-py3-none-win_amd64.whl:
Publisher:
release.yml on eelstork/proact
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
proact_py-0.1.0-py3-none-win_amd64.whl -
Subject digest:
b2cca34cf6c331594a27999f70b958309d9576155fb041c4262a3c94c9292f91 - Sigstore transparency entry: 1155361104
- Sigstore integration time:
-
Permalink:
eelstork/proact@45b96947536f56b097a77b90593c549e608662f1 -
Branch / Tag:
refs/tags/v0.1.12 - Owner: https://github.com/eelstork
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@45b96947536f56b097a77b90593c549e608662f1 -
Trigger Event:
push
-
Statement type:
File details
Details for the file proact_py-0.1.0-cp311-cp311-win_amd64.whl.
File metadata
- Download URL: proact_py-0.1.0-cp311-cp311-win_amd64.whl
- Upload date:
- Size: 100.9 kB
- Tags: CPython 3.11, Windows x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
35922e93ffd162529602e3603b01fa27665e8c0514dd36e4bb7db0676582048a
|
|
| MD5 |
78120138b8acd1ea05aa2df08839507b
|
|
| BLAKE2b-256 |
53b84c6606428aac030573cc81595973c78d651400c2d4141e4ebfeed14c59d8
|
Provenance
The following attestation bundles were made for proact_py-0.1.0-cp311-cp311-win_amd64.whl:
Publisher:
release.yml on eelstork/proact
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
proact_py-0.1.0-cp311-cp311-win_amd64.whl -
Subject digest:
35922e93ffd162529602e3603b01fa27665e8c0514dd36e4bb7db0676582048a - Sigstore transparency entry: 1155357536
- Sigstore integration time:
-
Permalink:
eelstork/proact@a0572c10f23713a9f2e546efe3705e681ff666a4 -
Branch / Tag:
refs/tags/v0.1.11 - Owner: https://github.com/eelstork
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@a0572c10f23713a9f2e546efe3705e681ff666a4 -
Trigger Event:
push
-
Statement type: