5
1
Fork
You've already forked spindle-rust
2
port of spindle racket to rust
  • Rust 77%
  • Lean 21.9%
  • Python 0.5%
  • Shell 0.5%
  • Makefile 0.1%
2026年07月13日 07:24:37 +02:00
.forgejo/workflows
.hence hence: complete task 'query-soundness' 2026年03月22日 00:27:45 +11:00
.woodpecker fix(core): use injective literal keys and exact head identity in query surfaces 2026年07月12日 22:55:05 +10:00
bench
contracts/spindle/v1/schemas
crates style: format with rustfmt 1.88 to match the CI toolchain 2026年07月13日 15:03:31 +10:00
docs docs: correct tractability claim with accurate complexity analysis 2026年03月06日 10:48:25 +11:00
examples
lean fix(verify): close silent-pass holes in the difftest and axiom gate 2026年07月13日 09:27:22 +10:00
plans fix(lean): repair SemiNaive beq proofs, drop vacuous theorem; mark specs implemented 2026年07月04日 22:06:06 +10:00
scripts fix(verify): close silent-pass holes in the difftest and axiom gate 2026年07月13日 09:27:22 +10:00
specs Merge pull request 'feat: temporal projection redesign (SPEC-020) and Lean 4 formal verification (IMPL-015/016)' ( #32 ) from feat/lean-and-temporal into main 2026年07月13日 07:24:37 +02:00
.gitignore ci: run full conformance suite, build oracle exes, gate on engine changes 2026年07月06日 00:01:19 +10:00
AGENTS.md
Cargo.toml chore: bump version to 0.3.0 2026年02月26日 22:07:16 +11:00
CHANGELOG.md chore: remove dead compilation module and stale notes; document breaking changes 2026年07月13日 09:27:32 +10:00
LICENSE
Makefile fix(query): preserve exact temporal windows in abduce/what-if; close CI gaps 2026年07月06日 10:36:51 +10:00
README.md docs: fix broken SPINdle link to research.csiro.au 2026年03月06日 10:25:13 +11:00
release.sh
RELEASING.md

Spindle-Rust

Coverage License: LGPL v3

A Rust implementation of the SPINdle defeasible logic reasoning engine.

This project is part of the SPINdle family:

  • SPINdle - The original Java implementation (v2.2.4) by NICTA (now Data61/CSIRO)
  • spindle-racket - A Racket port with trust-weighted reasoning and #lang spindle
  • spindle-rust - This Rust port, based on spindle-racket v1.7.0

Features

  • Defeasible Logic Reasoning: Implements non-monotonic reasoning with four rule types:

    • Facts (>>) - Unconditional truths
    • Strict rules (->) - Must hold if antecedent is true
    • Defeasible rules (=>) - Normally hold unless defeated
    • Defeaters (~>) - Block conclusions without proving anything
  • Reasoning Mode:

    • Standard DL(d) - Traditional forward chaining
  • Temporal Reasoning: Allen interval algebra with 13 temporal relations

  • Superiority Relations: Conflict resolution via rule preferences

  • First-Order Variables: Datalog-style grounding with ?x variable syntax

  • Arithmetic Expressions: Numeric computation in rule bodies

    • Operators: +, -, *, /, div, rem, **, abs, min, max
    • Variable binding: (bind ?total (+ ?price ?tax))
    • Comparison guards: (> ?age 18), (<= ?score 100)
    • Three numeric types: Integer, Decimal (arbitrary-precision), Float
    • Cross-type matching: Integer(2) equals Decimal(2.0) equals Float(2.0)
  • Input Format:

    • SPL (Spindle Lisp) - Lisp-based DSL
  • Explanations: Proof trees with natural language and JSON output

  • Trust-Aware Reasoning: Source attribution and trust-weighted conclusions

  • Query Operators:

    • What-if: Hypothetical reasoning
    • Why-not: Explanation of failures
    • Abduction: Finding hypotheses to prove goals
  • WebAssembly Support: Run in browsers and Node.js via wasm-bindgen

Installation

cargo install --path crates/spindle-cli

Versioning Policy

This project is currently pre-1.0 and follows strict Semantic Versioning for 0.y.z releases:

  • Breaking changes bump y (for example, 0.1.3 -> 0.2.0)
  • Backward-compatible changes and fixes bump z (for example, 0.1.3 -> 0.1.4)
  • 1.0.0 will be used once API stability guarantees are in place

Usage

# Reason about a theory (SPL format)
spindle examples/penguin.spl
# Show only positive conclusions
spindle --positive examples/penguin.spl
# Validate a theory file
spindle validate examples/penguin.spl
# Show statistics
spindle stats examples/penguin.spl

SPL Format

; Facts
(given bird)
(given penguin)
; Defeasible rules
(normally r1 bird flies)
(normally r2 penguin (not flies))
; Superiority
(prefer r2 r1)
; Predicates with variables
(given (parent alice bob))
(normally r3 (parent ?x ?y) (ancestor ?x ?y))
; Arithmetic: bind and compare
(given (item widget 25))
(given (tax-rate 0.1))
(normally r4
 (and (item ?name ?price) (tax-rate ?rate)
 (bind ?total (+ ?price (* ?price ?rate))))
 (total-cost ?name ?total))
(normally r5
 (and (total-cost ?name ?t) (> ?t 20))
 (expensive ?name))

Library Usage

usespindle_core::prelude::*;letmuttheory=Theory::new();// Add facts
theory.add_fact("bird");theory.add_fact("penguin");// Add rules
letr1=theory.add_defeasible_rule(&["bird"],"flies");letr2=theory.add_defeasible_rule(&["penguin"],"~flies");// Superiority: penguins override birds
theory.add_superiority(&r2,&r1);// Reason
usespindle_core::reason::reason;letconclusions=reason(&theory);

WebAssembly Usage

Build the WASM package:

cd crates/spindle-wasm
wasm-pack build --target web --release

Use in JavaScript/TypeScript:

import init, { Spindle } from 'spindle-wasm';
await init();
const spindle = new Spindle();
// Add theory programmatically
spindle.addFact("bird");
spindle.addFact("penguin");
spindle.addDefeasibleRule(["bird"], "flies");
spindle.addDefeasibleRule(["penguin"], "~flies");
spindle.addSuperiority("r2", "r1");
// Or parse SPL
spindle.parseSpl(`
 (given bird)
 (given penguin)
 (normally r1 bird flies)
 (normally r2 penguin (not flies))
 (prefer r2 r1)
`);
// Reason
const conclusions = spindle.reason();
// => [{conclusion_type: "+D", literal: "bird", positive: true}, ...]

// Query
const result = spindle.query("~flies");
// => {status: "provable", literal: "~flies", conclusion_type: "+d"}

// What-if hypothetical reasoning
const whatIf = spindle.whatIf(["wounded"], "~flies");
// => {provable: true, new_conclusions: [...]}

// Why-not failure explanation
const whyNot = spindle.whyNot("flies");
// => {literal: "flies", would_derive: "r1", blockers: [...]}

// Abduction
const abduce = spindle.abduce("flies", 3);
// => {goal: "flies", solutions: [[...], [...]]}

Crate Structure

  • spindle-core - Core reasoning engine
    • reason/ - Standard DL(d) forward chaining with Reasoner trait
    • pipeline/ - Composable PipelineStage stages (validate, temporal, wildcard, ground)
    • query/ - Query operators with QueryOperator trait (what-if, why-not, abduction)
    • explanation/ - Proof trees with ExplanationFormatter trait (natural language, JSON, JSON-LD, DOT)
    • analysis/ - Theory analysis (conflicts, validation, superiority suggestions)
    • arith - Arithmetic expression AST, evaluation, and type promotion
    • body - Body literals with arithmetic constraints (BodyLiteral, BodyArg)
    • term - Typed term values (Symbol, Integer, Decimal, Float)
    • temporal - Allen interval algebra
    • grounding - Datalog-style variable grounding with arithmetic evaluation
    • trust - Trust-weighted reasoning
  • spindle-parser - SPL format parser
    • spl/ - Lexer, expression dispatch, literal/rule/metadata handlers
    • spl/arith - Arithmetic expression and constraint parsing
  • spindle-cli - Command-line interface
  • spindle-wasm - WebAssembly bindings for JavaScript/TypeScript

Testing

1,500+ tests covering:

  • Core reasoning (facts, rules, conflicts, superiority)
  • Arithmetic expressions, type promotion, and numeric evaluation
  • Edge cases (cycles, empty theories, defeaters)
  • Stress tests (long chains, wide theories)
  • Query operators (what-if, why-not, abduction)
  • Property-based tests (proptest)
  • Pipeline integration tests
  • Regression tests for known bugs
  • Golden explanation tests
cargo test

Documentation

Full documentation is available at docs/ or build locally:

cd docs && mdbook serve

References

  • SPINdle Project - Original Java implementation by NICTA/Data61
  • Nute, D. (1994). "Defeasible Logic" - Foundational paper
  • spindle-racket - Racket implementation

License

LGPL-3.0-or-later (same as original SPINdle)