1use crate::alphabet::{Alphabet, CharRange};
5
6use super::{det::determinize, TransitionType, NFA};
7
8pub fn complement(nfa: &NFA) -> NFA {
15 let mut det = if !nfa.is_det() {
16 determinize(nfa)
17 } else {
18 nfa.clone()
19 };
20
21 if det.is_empty() {
22 return NFA::universal();
23 }
24
25 let sink = det.new_state();
27 det.add_transition(sink, sink, TransitionType::Range(CharRange::all()))
28 .unwrap(); for state in det.states() {
33 let mut alph = Alphabet::default();
34 for t in det.transitions_from(state).unwrap() {
35 match t.get_type() {
36 &TransitionType::Range(r) => alph.insert(r),
37 &TransitionType::NotRange(r) => {
38 r.complement().into_iter().for_each(|r| alph.insert(r))
39 }
40 TransitionType::Epsilon => unreachable!("DFA cannot have epsilon transitions"),
41 }
42 }
43 let comp = alph.complement();
45 for r in comp.iter_ranges() {
46 det.add_transition(state, sink, TransitionType::Range(r))
47 .unwrap();
48 }
49 }
50
51 det.finals = det.states().filter(|s| !det.finals.contains(s)).collect();
52 det.trim()
53}
54
55#[cfg(test)]
56mod tests {
57 use super::*;
58
59 #[test]
60 fn test_complement_basic() {
61 let mut nfa = NFA::new();
62 let q0 = nfa.new_state();
63 let q1 = nfa.new_state();
64
65 nfa.set_initial(q0).unwrap();
66 nfa.add_final(q1).unwrap();
67
68 nfa.add_transition(q0, q1, TransitionType::Range(CharRange::new('a', 'a')))
69 .unwrap();
70
71 let complement_dfa = complement(&nfa);
72
73 assert!(!complement_dfa.accepts(&"a".into())); assert!(complement_dfa.accepts(&"b".into())); assert!(complement_dfa.accepts(&"z".into())); }
77
78 #[test]
79 fn test_complement_handles_determinization() {
80 let mut nfa = NFA::new();
81 let q0 = nfa.new_state();
82 let q1 = nfa.new_state();
83 let q2 = nfa.new_state();
84
85 nfa.set_initial(q0).unwrap();
86 nfa.add_final(q2).unwrap();
87
88 nfa.add_transition(q0, q1, TransitionType::Range(CharRange::new('a', 'a')))
90 .unwrap();
91 nfa.add_transition(q0, q2, TransitionType::Range(CharRange::new('a', 'a')))
92 .unwrap();
93
94 let complement_dfa = complement(&nfa);
95
96 assert!(!complement_dfa.accepts(&"a".into())); assert!(complement_dfa.accepts(&"b".into())); }
99
100 #[test]
101 fn test_complement_universal_automaton() {
102 let nfa = NFA::universal();
103
104 let complement_dfa = complement(&nfa).trim();
105 assert_eq!(complement_dfa.num_states(), 0); }
107
108 #[test]
109 fn test_complement_empty_automaton() {
110 let nfa = NFA::new(); let complement_dfa = complement(&nfa);
113
114 assert!(complement_dfa.num_states() == 1); assert!(complement_dfa.accepts(&"x".into())); }
117
118 #[test]
119 fn test_complement_handles_sink_correctly() {
120 let mut nfa = NFA::new();
121 let q0 = nfa.new_state();
122 let q1 = nfa.new_state();
123
124 nfa.set_initial(q0).unwrap();
125 nfa.add_final(q1).unwrap();
126
127 nfa.add_transition(q0, q1, TransitionType::Range(CharRange::new('x', 'x')))
128 .unwrap();
129
130 let complement_dfa = complement(&nfa);
131
132 assert!(!complement_dfa.accepts(&"x".into())); assert!(complement_dfa.accepts(&"y".into())); }
135
136 #[test]
137 fn test_complement_multiple_transitions() {
138 let mut nfa = NFA::new();
139 let q0 = nfa.new_state();
140 let q1 = nfa.new_state();
141 let q2 = nfa.new_state();
142
143 nfa.set_initial(q0).unwrap();
144 nfa.add_final(q2).unwrap();
145
146 nfa.add_transition(q0, q1, TransitionType::Range(CharRange::new('a', 'c')))
147 .unwrap();
148 nfa.add_transition(q1, q2, TransitionType::Range(CharRange::new('d', 'f')))
149 .unwrap();
150
151 let complement_dfa = complement(&nfa);
152
153 assert!(!complement_dfa.accepts(&"ad".into())); assert!(complement_dfa.accepts(&"az".into())); assert!(complement_dfa.accepts(&"bq".into())); }
157}