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}