2.7 KiB
2.7 KiB
Chase-rs
An implementation of the chase algorithm in Rust for advanced reasoning engines.
Overview
The chase algorithm is a fundamental technique in context of database theory and knowledge representation used for:
- Query answering under tuple-generating dependencies (TGDs)
- Computing universal models
- Ontology-based data access (OBDA)
- Datalog with existential rules
This implementation provides a restricted chase that guarantees termination even with existential rules by tracking applied triggers.
Features
- Core Data Types: Terms, Atoms, Rules, and Instances
- Existential Quantification: Automatic generation of labeled nulls
- Restricted Chase: Termination guarantees via trigger tracking
- Fluent API:
RuleBuilderfor readable rule construction - Zero Dependencies: Pure Rust with no external runtime dependencies
See 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 to report bugs or request features.
Quick Start
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());
Existential Rules
Rules with head-only variables (existential quantification) automatically generate fresh labeled nulls:
// 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();
Building and Testing
## Run all tests
cargo test
## Run with optimizations
cargo build --release
## Check for lint warnings
cargo clippy
License
This project is licensed under BSD-3.