Skip to main content

cobra/
lib.rs

1//! Public API for the `CoBRA` mixed Boolean-arithmetic simplifier.
2//!
3//! The package emits both a normal Rust `rlib` and a Rust `dylib`. Static
4//! linking remains the default; development builds can select the DLL with
5//! `RUSTFLAGS="-C prefer-dynamic"` to reduce relinking in consumers.
6//!
7//! ```toml
8//! [dependencies]
9//! cobra = { package = "cobra-mba", version = "0.4" }
10//! ```
11//!
12//! ```rust
13//! use cobra::{parse_to_ast, render, simplify_expr, Options};
14//!
15//! let parsed = parse_to_ast("(x ^ y) + 2 * (x & y)", 64)?;
16//! let outcome = simplify_expr(&parsed.expr, &parsed.vars, Options::default())?;
17//! let simplified = outcome.expr.as_deref().unwrap_or(&parsed.expr);
18//! assert_eq!(render(simplified, &parsed.vars, 64), "x + y");
19//! # Ok::<(), cobra::ErrorInfo>(())
20//! ```
21
22#![forbid(unsafe_code)]
23
24// The implementation remains split into focused source trees, but all of
25// these modules are compiled and published as one Cargo package.
26#[path = "../../cobra-core/src/lib.rs"]
27pub mod core;
28#[path = "../../cobra-ir/src/lib.rs"]
29pub mod ir;
30#[path = "../../cobra-orchestrator/src/lib.rs"]
31pub mod orchestrator;
32#[path = "../../cobra-parser/src/lib.rs"]
33pub mod parser;
34#[path = "../../cobra-passes/src/lib.rs"]
35pub mod passes;
36#[path = "../../cobra-simd/src/lib.rs"]
37pub mod simd;
38#[doc(hidden)]
39#[path = "../../cobra-testkit/src/lib.rs"]
40pub mod testkit;
41#[path = "../../cobra-verify/src/lib.rs"]
42pub mod verify;
43
44/// Expression types and rendering helpers.
45pub mod expression {
46    pub use crate::core::expr::{render, Expr, Kind};
47    pub use crate::core::expr_rewrite::build_var_support;
48    pub use crate::core::expr_utils::remap_var_indices;
49}
50
51/// Simplifier entry points, options, outcomes, and diagnostics.
52pub mod simplify {
53    pub use crate::core::simplify_outcome::{
54        Diagnostic, Options, ProofLevel, SimplifyOutcome, SimplifyOutcomeKind, SimplifyTelemetry,
55    };
56    pub use crate::passes::{simplify, simplify_expr, MAX_INPUT_VARS};
57}
58
59/// Map a finished outcome's expression back into the caller's variable
60/// namespace.
61///
62/// A result that dropped variables is indexed against
63/// [`SimplifyOutcome::real_vars`], not the table the caller passed in, so
64/// rendering it against the caller's table without this step prints the wrong
65/// names. Returns `None` when the outcome carries no expression.
66#[must_use]
67pub fn outcome_expr_in_original_space(
68    outcome: &SimplifyOutcome,
69    original_vars: &[String],
70) -> Option<std::sync::Arc<Expr>> {
71    let mut owned = outcome.expr.as_ref()?.clone();
72    if !outcome.real_vars.is_empty() && outcome.real_vars.len() < original_vars.len() {
73        if let Some(index_map) =
74            crate::core::expr_rewrite::try_build_var_support(original_vars, &outcome.real_vars)
75        {
76            remap_var_indices(std::sync::Arc::make_mut(&mut owned), &index_map);
77        }
78    }
79    Some(owned)
80}
81
82pub use crate::core::{is_valid_bitwidth, CobraError, ErrorInfo, Result};
83pub use crate::expression::{build_var_support, remap_var_indices, render, Expr, Kind};
84pub use crate::parser::{parse_to_ast, AstResult, MAX_VARIABLES};
85pub use crate::simplify::{
86    simplify, simplify_expr, Diagnostic, Options, ProofLevel, SimplifyOutcome, SimplifyOutcomeKind,
87    SimplifyTelemetry, MAX_INPUT_VARS,
88};
89
90#[cfg(test)]
91mod tests {
92    use super::*;
93
94    #[test]
95    fn public_api_simplifies_an_expression() {
96        let parsed = parse_to_ast("(x ^ y) + 2 * (x & y)", 64).expect("parse input");
97        let outcome =
98            simplify_expr(&parsed.expr, &parsed.vars, Options::default()).expect("simplify input");
99        let simplified = outcome.expr.as_deref().unwrap_or(&parsed.expr);
100
101        assert_eq!(render(simplified, &parsed.vars, 64), "x + y");
102    }
103}