boolean_circuit/
circuit.rs

1use std::collections::HashSet;
2
3use crate::{
4    gate::{GraphIterator, PostVisitIterator},
5    Gate,
6};
7
8/// A boolean circuit with named inputs and outputs.
9/// Input variables are identified by their name.
10/// The gates in the circuit are [`Gate`]s.
11#[derive(Default)]
12pub struct Circuit {
13    /// The output gates of the circuit. They contain their predecessors.
14    outputs: Vec<Gate>,
15    /// The names of the output gates. Unnamed outputs use the empty string.
16    output_names: Vec<String>,
17}
18
19impl From<Gate> for Circuit {
20    fn from(gate: Gate) -> Self {
21        Circuit {
22            outputs: vec![gate],
23            output_names: vec![String::new()],
24        }
25    }
26}
27
28impl Circuit {
29    /// Creates a circuit from unnamed outputs. Note that the [`Gate`]s can
30    /// share predecessors. Any two input gates in the circuit with the same
31    /// name are considered identical.
32    pub fn from_unnamed_outputs(outputs: impl IntoIterator<Item = Gate>) -> Self {
33        Self::from_named_outputs(outputs.into_iter().map(|n| (n, String::new())))
34    }
35
36    /// Creates a circuit from (uniquely) named outputs.  Note that the [`Gate`]s can
37    /// share predecessors. Any two input gates in the circuit with the same
38    /// name are considered identical.
39    ///
40    /// The empty string can be used to not name outputs.
41    ///
42    /// Panics if the output names are not unique.
43    pub fn from_named_outputs(items: impl IntoIterator<Item = (Gate, String)>) -> Self {
44        let mut seen_names: HashSet<_> = Default::default();
45        let mut circuit = Self::default();
46        for (gate, name) in items {
47            if !name.is_empty() && !seen_names.insert(name.clone()) {
48                panic!("Duplicate output name {name}");
49            }
50            circuit.outputs.push(gate);
51            circuit.output_names.push(name);
52        }
53        circuit
54    }
55
56    /// Returns the output gates.
57    pub fn outputs(&self) -> &[Gate] {
58        &self.outputs
59    }
60
61    /// Returns the names of the output gates, where unnamed output gates use the empty String.
62    pub fn output_names(&self) -> &[String] {
63        &self.output_names
64    }
65
66    /// Creates an iterator over the graph (the output gates and all their predecessors)
67    /// that returns each gate exactly once.
68    pub fn iter(&self) -> impl Iterator<Item = &Gate> {
69        GraphIterator::new(&self.outputs)
70    }
71
72    /// Creates an iterator over the graph (the output gates and all their predecessors)
73    /// with post-visit order, visiting each gate exactly once.
74    /// This means that the predecessors of each gate are always visited before the gate itself.
75    pub fn post_visit_iter(&self) -> impl Iterator<Item = &Gate> {
76        PostVisitIterator::new(self.outputs.iter())
77    }
78}