Skip to content

Latest commit

 

History

History
241 lines (173 loc) · 10.4 KB

File metadata and controls

241 lines (173 loc) · 10.4 KB

DeepCausality Core

Crates.io Docs.rs MIT licensed Tests

Core types and abstractions for the DeepCausality project.

This crate provides the foundational building blocks for causal reasoning, effect propagation, and mission-critical control flow construction. It is designed for high-assurance systems, supporting no_std, zero-allocation execution, and embedded requirements.

Architecture

deep_causality_core provides two distinct, powerful abstractions for structuring complex logic. They can be used independently.

1. The ControlFlowBuilder: For Correct-by-Construction Systems

  • What It Is: A tool for defining a static, compile-time verified execution graph. Nodes are functions, and edges are data flows between them.
  • Key Feature: Safety. The Rust compiler ensures you can only connect an output of type T to an input of type T. This eliminates an entire class of runtime integration errors.
  • Best For:
    • Safety-Critical & Embedded Systems: With the strict-zst feature, it guarantees zero heap allocations and no dynamic dispatch in the execution path, making it suitable for environments requiring formal verification and WCET analysis (Worst-Case Execution Time).
    • ETL Pipelines: Defining fixed data transformation pipelines where the flow is static and reliability is paramount.
  • Independence: It has no dependency on the monadic effect system. It is a standalone tool for building robust, static graphs.

2. The Monadic Effect System: For Dynamic Causal Reasoning

  • What It Is: A flexible, functional foundation for modeling processes using monadic types like PropagatingEffect (stateless) and PropagatingProcess (stateful).
  • Key Feature: Flexibility & Composability. It allows for dynamic chaining of operations (bind), state propagation, context-awareness, and causal interventions.
  • Best For:
    • The foundation of the main deep_causality library.
    • Complex simulations where state and context evolve.
    • Systems that need to reason about and dynamically respond to events.
  • Relationship: This system is the foundation that enables the advanced causal reasoning capabilities of the wider DeepCausality ecosystem.

How to Choose:

  • If you need to a fixed, static, and ultra-reliable data-flow graph and cannot tolerate runtime errors or allocations, use the ControlFlowBuilder.
  • If you are building a system that requires dynamic, stateful, and context-aware reasoning, use the Monadic Effect System. For more advanced reasoning capabilities refer to the main deep_causality crate.

Core Capabilities

1. Causal Effect Systems

The crate defines the core types for modeling causal systems using Monadic Effect Systems.

  • CausalEffectSystem: The central runtime for managing causal models.
  • CausalMonad: A monadic interface for chaining causal effects, allowing for composable and testable logic.
  • PropagatingEffect / PropagatingProcess: Types that model how effects ripple through a system, integrated with Higher-Kinded Types (HKT) via deep_causality_haft.

2. Mission-Critical Control Flow Builder

The Control Flow Builder is a specialized tool for constructing Correct-by-Construction execution graphs. It is designed for safety-critical applications where runtime wiring errors are unacceptable.

  • Type-Safe Topology: The builder uses Rust's type system to enforce that nodes can only be connected if their input/output protocols match. Invalid connections are rejected at compile time.
  • Zero-Fault Execution: The execution engine is designed to be panic-free and allocation-free (in the hot loop). Errors are returned as static enums, not Strings.
  • Zero-Allocation Loop: The execute method accepts a pre-allocated queue, ensuring deterministic execution timing suitable for real-time control loops.

Feature Flags & Safety Implications

This crate is designed to scale from research prototypes to certified flight control systems. The feature flags control the trade-off between flexibility and strict safety guarantees.

Feature Default Description Safety & Regulatory Implication
std Yes Enables standard library support. General Purpose. Suitable for servers, desktops, and research. Not for bare-metal embedded.
alloc Yes Enables heap allocation (Vec, Box). Embedded Linux / RTOS. Required for dynamic graph construction. Most embedded systems use this.
strict-zst No Certification Mode. Enforces Zero-Sized Types. Safety-Critical / Hard Real-Time. See below.

The strict-zst Feature

When strict-zst is enabled, the ControlFlowBuilder enforces that all user-provided logic must be Zero-Sized Types (ZSTs) (i.e., static function items).

  • Implication: You cannot use closures that capture environment variables. You must use plain functions.
  • Benefit:
    • No Hidden State: The logic is guaranteed to be pure and stateless (or explicitly state-passing).
    • No Vtables: Eliminates dynamic dispatch (dyn Fn), simplifying WCET (Worst-Case Execution Time) analysis.
    • Formal Verification: The resulting graph topology is static and easier to model in formal verification tools.
    • Zero-Allocation Nodes: Nodes are stored as function pointers, requiring no heap allocation for the logic itself.

Recommendation:

  • Use default features for prototyping and general applications.
  • Enable strict-zst for final deployment in safety-critical environments where dynamic allocation and hidden state are impermissible.

Usage Examples

Control Flow Builder (Mission Critical)

use deep_causality_core::{ControlFlowBuilder, ControlFlowProtocol, FromProtocol, ToProtocol};
use std::collections::VecDeque;

// 1. Define your Domain Protocol
#[derive(Clone, Debug)]
enum MyProtocol {
    Signal(bool),
    Command(u8),
}
// ... impl ControlFlowProtocol, FromProtocol, ToProtocol ...

fn sensor_read(input: bool) -> u8 {
    if input { 100 } else { 0 }
}

fn main() {
    let mut builder = ControlFlowBuilder::<MyProtocol>::default();

    // 2. Add Nodes (Type-checked!)
    let n_sensor = builder.add_node(sensor_read);
    
    // 3. Build Graph
    let graph = builder.build();

    // 4. Execute (Zero-Allocation Loop)
    let mut queue = VecDeque::with_capacity(10); // Pre-allocate memory
    let input = true.to_protocol();
    
    let result = graph.execute(input, 0, 10, &mut queue);
    println!("Result: {:?}", result);
}

PropagatingEffect (Stateless)

PropagatingEffect is a monadic container for stateless causal effects. It supports standard functional transformations (map, bind) via the Functor and Monad traits.

use deep_causality_core::{PropagatingEffect, PropagatingEffectWitness};
use deep_causality_haft::{Functor, Applicative};

fn main() {
    // Create a pure effect
    let effect = PropagatingEffectWitness::pure(10);
    
    // Transform value (Functor)
    let mapped = PropagatingEffectWitness::fmap(effect, |x| x * 2);
    
    println!("Result: {:?}", mapped.value); // Value(20)
}

PropagatingProcess (Stateful)

PropagatingProcess extends PropagatingEffect with State and Context. It allows you to model Markovian processes where each step can read/write state and access configuration context.

use deep_causality_core::{PropagatingProcess, PropagatingEffectWitness, EffectValue};
use deep_causality_haft::Applicative;

#[derive(Clone, Default, Debug)]
struct State { count: i32 }

fn main() {
    // Lift a pure effect into a stateful process
    let effect = PropagatingEffectWitness::pure(10);
    let process = PropagatingProcess::with_state(effect, State::default(), None);

    // Chain stateful computation
    let next = process.bind(|val, mut state, ctx| {
        state.count += 1;
        deep_causality_core::CausalEffectPropagationProcess {
            value: EffectValue::Value(val.into_value().unwrap() + 1),
            state,
            context: ctx,
            error: None,
            logs: Default::default(),
        }
    });

    println!("State: {:?}", next.state); // State { count: 1 }
}

Intervention & Counterfactuals

DeepCausality Core supports Causal Interventions (Pearl's "Do-calculus"). You can intervene on a running process to override values and simulate counterfactual scenarios ("What if X had been Y?").

The Intervenable trait adds the .intervene(value) method to both PropagatingEffect and PropagatingProcess.

use deep_causality_core::{PropagatingEffectWitness, Intervenable};

// 1. Create a factual effect
let effect = PropagatingEffectWitness::pure(10);

// 2. Intervene to force a new value (Counterfactual)
// This preserves logs and error states but overrides the value.
let counterfactual = effect.intervene(42);

non-std Support

To use this crate in a bare-metal no_std environment:

[dependencies]
deep_causality_core = { version = "...", default-features = false, features = ["alloc"] }

If you need absolute strictness (no Box<dyn Fn>):

[dependencies]
deep_causality_core = { version = "...", default-features = false, features = ["alloc", "strict-zst"] }

License

This project is licensed under the MIT license.

Security

For details about security, please read the security policy.

Author

  • Marvin Hansen.
  • Github GPG key ID: 369D5A0B210D39BC
  • GPG Fingerprint: 4B18 F7B2 04B9 7A72 967E 663E 369D 5A0B 210D 39BC