## Chase-rs An implementation of the chase algorithm in Rust for reasoning engines. ### Overview The chase algorithm is a technique in context of database theory and knowledge representation used for: - Query answering under tuple-generating dependencies (TGDs) - Computing universal models - Datalog with existential rules This implementation provides a restricted-chase style materialization with active-trigger checks. The default entrypoints use a `10_000` step safeguard and report incomplete results with `terminated == false` if that limit is reached. ### Features - **Core Data Types**: Terms, Atoms, Rules, and Instances - **Existential Quantification**: Automatic generation of labeled nulls - **Restricted Chase Style**: Active-trigger checks for existential rules - **Configurable Step Limit**: `chase_with_config` exposes the step bound - **Fluent API**: `RuleBuilder` for readable rule construction - **Interactive Frontends**: REPL, script runner, and a local GUI - **Zero Dependencies**: Pure Rust with no external runtime dependencies See [ROADMAP.md](ROADMAP.md) for the list of implemented and planned features. > [!IMPORTANT] > This project is still in early development, so bugs and breaking changes are expected. > Please use the [issues page](https://code.obsidian.systems/habedi-work/chase-rs/issues) to report bugs or request features. --- ### Quickstart #### Example ```rust use chase_rs::{chase, Atom, Instance, Term}; use chase_rs::chase::rule::RuleBuilder; // Create initial facts let instance: Instance = vec![ Atom::new("Parent", vec![Term::constant("alice"), Term::constant("bob")]), Atom::new("Parent", vec![Term::constant("bob"), Term::constant("carol")]), ].into_iter().collect(); // Define rules // Parent(X, Y) -> Ancestor(X, Y) let rule1 = RuleBuilder::new() .when("Parent", vec![Term::var("X"), Term::var("Y")]) .then("Ancestor", vec![Term::var("X"), Term::var("Y")]) .build(); // Ancestor(X, Y), Parent(Y, Z) -> Ancestor(X, Z) let rule2 = RuleBuilder::new() .when("Ancestor", vec![Term::var("X"), Term::var("Y")]) .when("Parent", vec![Term::var("Y"), Term::var("Z")]) .then("Ancestor", vec![Term::var("X"), Term::var("Z")]) .build(); // Run the chase let result = chase(instance, &[rule1, rule2]); assert!(result.terminated); println!("Derived {} facts", result.instance.len()); ``` Use `chase_with_config` to change the default step bound: ```rust use chase_rs::{Atom, ChaseConfig, Instance, Term, chase_with_config}; use chase_rs::chase::rule::RuleBuilder; let instance: Instance = vec![Atom::new("P", vec![Term::constant("a")])] .into_iter() .collect(); let rule = RuleBuilder::new() .when("P", vec![Term::var("X")]) .then("Q", vec![Term::var("X")]) .build(); let result = chase_with_config( instance, &[rule], ChaseConfig { max_steps: 100 }, ); assert!(result.terminated); ``` #### Existential Rules Rules with head-only variables (existential quantification) automatically generate fresh labeled nulls: ```rust // Every person has an SSN: Person(X) -> HasSSN(X, Y) let rule = RuleBuilder::new() .when("Person", vec![Term::var("X")]) .then("HasSSN", vec![Term::var("X"), Term::var("Y")]) // Y is existential .build(); ``` #### Frontends The binary now supports three entrypoints: ```bash # Start the interactive REPL cargo run -- repl # Start the local GUI at http://127.0.0.1:7878 cargo run -- gui # Run a script file cargo run -- script examples/scripts/ancestor.chase ``` The REPL and GUI share a minimal command language: ```text fact Parent(alice, bob). rule Parent(?X, ?Y) -> Ancestor(?X, ?Y). run. query Ancestor(?X, ?Y)? explain Ancestor(alice, carol)? show facts show rules reset help ``` Rules: - facts and rules end with `.` - queries end with `?` - `explain ... ?` shows one derivation tree per matching answer - variables are prefixed with `?` - quoted constants are supported, for example `"alice smith"` #### Useful Commands ```bash # Install dependencies nix develop -c make install-deps # Run all tests make test # Run linter checks make lint # Run with optimizations make build # Run CLI make run ``` --- ### License This project is licensed under [BSD-3](LICENSE).