cfg_symbol_bit_matrix/
symbol_bit_matrix.rs

1use std::ops::{self, Deref, DerefMut};
2
3use bit_matrix::BitMatrix;
4
5use cfg_grammar::Cfg;
6use cfg_symbol::{Symbol, SymbolSource};
7
8/// A matrix that represents a relation `R(A, B)` between two symbols.
9#[derive(Debug)]
10pub struct SymbolBitMatrix {
11    bit_matrix: BitMatrix,
12}
13
14/// A direct derivation matrix.
15pub struct DirectDerivationMatrix(SymbolBitMatrix);
16/// A reachability matrix.
17pub struct ReachabilityMatrix(SymbolBitMatrix);
18/// A unit derivation matrix.
19pub struct UnitDerivationMatrix(SymbolBitMatrix);
20
21impl SymbolBitMatrix {
22    fn new(num_syms: usize) -> Self {
23        SymbolBitMatrix {
24            bit_matrix: BitMatrix::new(num_syms, num_syms),
25        }
26    }
27
28    fn set(&mut self, row: Symbol, col: Symbol, included: bool) {
29        self.bit_matrix.set(row.usize(), col.usize(), included);
30    }
31
32    /// Creates an iterator over symbols which appear in the given row.
33    pub fn iter_row_syms(&self, row: Symbol) -> impl Iterator<Item = Symbol> + '_ {
34        self.bit_matrix
35            .iter_row(row.usize())
36            .zip(SymbolSource::generate_fresh())
37            .filter_map(|(present, sym)| if present { Some(sym) } else { None })
38    }
39}
40
41impl Deref for SymbolBitMatrix {
42    type Target = BitMatrix;
43    fn deref(&self) -> &Self::Target {
44        &self.bit_matrix
45    }
46}
47
48impl DerefMut for SymbolBitMatrix {
49    fn deref_mut(&mut self) -> &mut Self::Target {
50        &mut self.bit_matrix
51    }
52}
53
54impl Deref for DirectDerivationMatrix {
55    type Target = SymbolBitMatrix;
56    fn deref(&self) -> &Self::Target {
57        &self.0
58    }
59}
60
61impl DerefMut for DirectDerivationMatrix {
62    fn deref_mut(&mut self) -> &mut Self::Target {
63        &mut self.0
64    }
65}
66
67impl Deref for ReachabilityMatrix {
68    type Target = SymbolBitMatrix;
69    fn deref(&self) -> &Self::Target {
70        &self.0
71    }
72}
73
74impl DerefMut for ReachabilityMatrix {
75    fn deref_mut(&mut self) -> &mut Self::Target {
76        &mut self.0
77    }
78}
79
80impl Deref for UnitDerivationMatrix {
81    type Target = SymbolBitMatrix;
82    fn deref(&self) -> &Self::Target {
83        &self.0
84    }
85}
86
87impl DerefMut for UnitDerivationMatrix {
88    fn deref_mut(&mut self) -> &mut Self::Target {
89        &mut self.0
90    }
91}
92
93impl From<DirectDerivationMatrix> for SymbolBitMatrix {
94    fn from(value: DirectDerivationMatrix) -> Self {
95        value.0
96    }
97}
98
99impl From<ReachabilityMatrix> for SymbolBitMatrix {
100    fn from(value: ReachabilityMatrix) -> Self {
101        value.0
102    }
103}
104
105impl From<UnitDerivationMatrix> for SymbolBitMatrix {
106    fn from(value: UnitDerivationMatrix) -> Self {
107        value.0
108    }
109}
110
111static TRUE: bool = true;
112static FALSE: bool = false;
113
114impl ops::Index<(Symbol, Symbol)> for SymbolBitMatrix {
115    type Output = bool;
116    fn index(&self, index: (Symbol, Symbol)) -> &Self::Output {
117        if self.bit_matrix[(index.0.usize(), index.1.usize())] {
118            &TRUE
119        } else {
120            &FALSE
121        }
122    }
123}
124
125impl TryFrom<BitMatrix> for SymbolBitMatrix {
126    type Error = ();
127
128    fn try_from(bit_matrix: BitMatrix) -> Result<Self, Self::Error> {
129        let (rows, cols) = bit_matrix.size();
130        if rows == cols {
131            Ok(SymbolBitMatrix { bit_matrix })
132        } else {
133            Err(())
134        }
135    }
136}
137
138impl From<SymbolBitMatrix> for BitMatrix {
139    fn from(value: SymbolBitMatrix) -> Self {
140        value.bit_matrix
141    }
142}
143
144impl ReachabilityMatrix {
145    /// A symbol is reachable from itself.
146    pub fn reflexive(mut self) -> Self {
147        self.reflexive_closure();
148        self
149    }
150}
151
152impl DirectDerivationMatrix {
153    /// Returns the derivation matrix.
154    pub fn reachability(mut self) -> ReachabilityMatrix {
155        self.transitive_closure();
156        ReachabilityMatrix(self.into())
157    }
158}
159
160/// Extension traits for building matrices that represent relation between symbols,
161/// `R(A, B)` where `A`: [`Symbol`], `B`: [`Symbol`].
162pub trait CfgSymbolBitMatrixExt {
163    /// Creates the empty matrix of size `|S|x|S|` where `S`: set of symbols.
164    fn empty_matrix(&self) -> SymbolBitMatrix;
165    /// Computes the direct derivation matrix.
166    fn direct_derivation_matrix(&self) -> DirectDerivationMatrix;
167    /// Computes the reachability matrix.
168    fn reachability_matrix(&self) -> ReachabilityMatrix;
169    /// Computes the unit derivation matrix.
170    ///
171    /// A unit derivation is defined with a grammar rule such as:
172    /// ```ignore
173    /// A ::= B;
174    /// ```
175    fn unit_derivation_matrix(&self) -> UnitDerivationMatrix;
176}
177
178impl CfgSymbolBitMatrixExt for Cfg {
179    fn empty_matrix(&self) -> SymbolBitMatrix {
180        SymbolBitMatrix::new(self.num_syms())
181    }
182
183    fn direct_derivation_matrix(&self) -> DirectDerivationMatrix {
184        let mut derivation = self.empty_matrix();
185
186        for rule in self.rules() {
187            for &sym in rule.rhs.iter() {
188                derivation.set(rule.lhs, sym, true);
189            }
190        }
191
192        DirectDerivationMatrix(derivation)
193    }
194
195    fn reachability_matrix(&self) -> ReachabilityMatrix {
196        self.direct_derivation_matrix().reachability()
197    }
198
199    fn unit_derivation_matrix(&self) -> UnitDerivationMatrix {
200        let mut unit_derivation = self.empty_matrix();
201
202        for rule in self.rules() {
203            // A rule of form `A ::= A` is not a cycle. We can represent unit rules in the form of
204            // a directed graph. The rule `A ::= A` is then presented as a self-loop. Self-loops
205            // aren't cycles.
206            if rule.rhs.len() == 1 && rule.lhs != rule.rhs[0] {
207                unit_derivation.set(rule.lhs, rule.rhs[0], true);
208            }
209        }
210
211        unit_derivation.transitive_closure();
212        UnitDerivationMatrix(unit_derivation)
213    }
214}