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
§1. Boolean Expressions (Recommended for most use cases)
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*bParse 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§
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§
- Cover
Builder - A cover builder with compile-time dimension checking
- Espresso
Config - 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)
- Cover
Type Marker - Marker trait for cover type specification