Crate espresso_logic

Crate espresso_logic 

Source
Expand description

§Espresso Logic Minimizer

This crate provides Rust bindings to the Espresso heuristic logic minimizer (Version 2.3), a classic tool from UC Berkeley for minimizing Boolean functions.

§Overview

Espresso takes a Boolean function represented as a sum-of-products (cover) and produces a minimal or near-minimal equivalent representation. It’s particularly useful for:

  • Digital logic synthesis
  • PLA (Programmable Logic Array) minimization
  • Boolean function simplification
  • Logic optimization in CAD tools

§Three Ways to Use Espresso

Build expressions programmatically and minimize them:

use espresso_logic::{BoolExpr, expr};

let a = BoolExpr::variable("a");
let b = BoolExpr::variable("b");
let c = BoolExpr::variable("c");

// Build a redundant expression: a*b + a*b*c
let redundant = expr!(a * b + a * b * c);

// Minimize it (returns a new minimized expression)
let minimized = redundant.minimize()?;

println!("Minimized: {}", minimized);  // Output: a*b

Parse expressions from strings:

use espresso_logic::BoolExpr;

// Parse using standard operators: +, *, ~, !
let expr = BoolExpr::parse("a * b + ~a * ~b")?;

// Minimize
let minimized = expr.minimize().map_err(|e| e.to_string())?;

§2. Cover Builder (Static dimensions with compile-time checking)

Build covers with fixed dimensions known at compile time:

use espresso_logic::{Cover, CoverBuilder};

// Create a cover for a 2-input, 1-output function
let mut cover = CoverBuilder::<2, 1>::new();

// Build the ON-set (truth table)
cover.add_cube(&[Some(false), Some(true)], &[Some(true)]);  // 01 -> 1
cover.add_cube(&[Some(true), Some(false)], &[Some(true)]);  // 10 -> 1

// Minimize in-place
cover.minimize()?;

// Iterate over minimized cubes
for (inputs, outputs) in cover.cubes_iter() {
    println!("Cube: {:?} -> {:?}", inputs, outputs);
}

§3. PLA Files (Dynamic dimensions from files)

Load and minimize PLA files with dynamic dimensions:

use espresso_logic::{Cover, PLACover, PLAType};

// Read from PLA file
let mut cover = PLACover::from_pla_file(input_path)?;

// Minimize
cover.minimize()?;

// Write to PLA file
cover.to_pla_file(output_path, PLAType::F)?;

§Cover Types

The library supports different cover types for representing Boolean functions:

  • F Type - ON-set only (specifies where output is 1)
  • FD Type - ON-set + Don’t-cares (default, most flexible)
  • FR Type - ON-set + OFF-set (specifies both 1s and 0s)
  • FDR Type - ON-set + Don’t-cares + OFF-set (complete specification)
use espresso_logic::{CoverBuilder, FType, FDType, Cover};

// F type (ON-set only)
let mut f_cover = CoverBuilder::<2, 1, FType>::new();
f_cover.add_cube(&[Some(true), Some(true)], &[Some(true)]);

// FD type (ON-set + Don't-cares) - default
let mut fd_cover = CoverBuilder::<2, 1, FDType>::new();  // or just CoverBuilder::<2, 1>::new()
fd_cover.add_cube(&[Some(true), Some(true)], &[Some(true)]);  // ON
fd_cover.add_cube(&[Some(false), Some(false)], &[None]);      // Don't-care

§Thread Safety and Concurrency

This library IS thread-safe! The underlying C library uses C11 thread-local storage (_Thread_local) for all global state. Each thread gets its own independent copy of all global variables, making concurrent use completely safe without any synchronization.

§Multi-threaded Applications

Just use CoverBuilder directly - each thread executes Espresso independently:

use espresso_logic::{Cover, CoverBuilder};
use std::thread;

// Spawn threads - no synchronization needed!
let handles: Vec<_> = (0..4).map(|_| {
    thread::spawn(move || {
        let mut cover = CoverBuilder::<2, 1>::new();
        cover.add_cube(&[Some(false), Some(true)], &[Some(true)]);
        cover.add_cube(&[Some(true), Some(false)], &[Some(true)]);
         
        // Thread-safe - each thread executes with independent global state
        cover.minimize()?;
        Ok(cover.num_cubes())
    })
}).collect();

for handle in handles {
    let result: std::io::Result<usize> = handle.join().unwrap();
    println!("Result: {} cubes", result?);
}

How it works:

  • Thread-local storage: All C global variables use _Thread_local
  • Independent state: Each thread has its own copy of all globals
  • Direct calls: No process spawning or IPC overhead
  • Native safety: Uses standard C11 thread safety features

Re-exports§

pub use expression::BoolExpr;
pub use expression::ExprCover;

Modules§

expression
Boolean expression types with operator overloading and parsing support
sys
Low-level FFI bindings to the Espresso C library

Macros§

expr
Macro for building boolean expressions with clean syntax

Structs§

CoverBuilder
A cover builder with compile-time dimension checking
EspressoConfig
Configuration for the Espresso algorithm
FDRType
Marker type for FDR (ON-set + Don’t-care + OFF-set) covers
FDType
Marker type for FD (ON-set + Don’t-care) covers (default)
FRType
Marker type for FR (ON-set + OFF-set) covers
FType
Marker type for F (ON-set only) covers
PLACover
A cover with dynamic dimensions (from PLA files)

Enums§

PLAType
Represents the type of PLA output format (also used as cover type)

Traits§

Cover
Public trait for all cover types (static and dynamic dimensions)
CoverTypeMarker
Marker trait for cover type specification