pub struct Arc<W: Semiring> {
pub ilabel: Label,
pub olabel: Label,
pub weight: W,
pub nextstate: StateId,
}Expand description
A weighted arc (transition) in a finite-state transducer.
Arcs are the fundamental building blocks of FSTs, representing labeled, weighted transitions between states. Each arc specifies:
- An input symbol to consume (or epsilon if
ilabel == 0) - An output symbol to produce (or epsilon if
olabel == 0) - A weight from the semiring
W - The destination state
§Type Parameters
W- The semiring type for arc weights (e.g.,TropicalWeight,LogWeight)
§Fields
| Field | Type | Description |
|---|---|---|
ilabel | Label | Input symbol (0 = epsilon) |
olabel | Label | Output symbol (0 = epsilon) |
weight | W | Transition weight |
nextstate | StateId | Destination state ID |
§Examples
Creating different types of arcs:
use arcweight::prelude::*;
// Regular arc with different input/output labels
let arc1 = Arc::new(1, 2, TropicalWeight::new(0.5), 3);
// Acceptor arc (same input/output)
let arc2 = Arc::new(1, 1, TropicalWeight::one(), 2);
// Epsilon arc (input=0, output=0)
let epsilon = Arc::epsilon(TropicalWeight::new(0.1), 1);
assert_eq!(arc1.ilabel, 1);
assert_eq!(arc1.olabel, 2);
assert!(epsilon.is_epsilon());Using arcs in FST construction:
use arcweight::prelude::*;
let mut fst = VectorFst::<TropicalWeight>::new();
let s0 = fst.add_state();
let s1 = fst.add_state();
// Add a transducer arc
fst.add_arc(s0, Arc::new(1, 2, TropicalWeight::new(0.5), s1));Fields§
§ilabel: LabelInput label consumed by this transition.
A value of 0 indicates an epsilon transition on the input tape, meaning no symbol is consumed.
olabel: LabelOutput label produced by this transition.
A value of 0 indicates an epsilon transition on the output tape, meaning no symbol is produced.
weight: WWeight of this transition in the semiring W.
The weight represents the cost, probability, or other measure associated with taking this transition, as defined by the semiring.
nextstate: StateIdDestination state ID.
The state that becomes current after taking this transition.
Implementations§
Source§impl<W: Semiring> Arc<W>
impl<W: Semiring> Arc<W>
Sourcepub fn new(ilabel: Label, olabel: Label, weight: W, nextstate: StateId) -> Self
pub fn new(ilabel: Label, olabel: Label, weight: W, nextstate: StateId) -> Self
Creates a new arc with the specified labels, weight, and destination.
This is the primary constructor for arcs in FST construction.
§Arguments
ilabel- Input label (0 for epsilon)olabel- Output label (0 for epsilon)weight- Arc weight in the semiringnextstate- Destination state ID
§Returns
A new Arc with the specified components.
§Examples
use arcweight::prelude::*;
let arc = Arc::new(1, 2, TropicalWeight::new(0.5), 3);
assert_eq!(arc.ilabel, 1);
assert_eq!(arc.olabel, 2);
assert_eq!(arc.weight, TropicalWeight::new(0.5));
assert_eq!(arc.nextstate, 3);Examples found in repository?
714fn build_morphotactic_fst() -> VectorFst<TropicalWeight> {
715 let mut fst = VectorFst::new();
716 let start = fst.add_state();
717 let noun_stem = fst.add_state();
718 let noun_inflected = fst.add_state();
719 let final_state = fst.add_state();
720
721 fst.set_start(start);
722 fst.set_final(final_state, TropicalWeight::one());
723
724 // Simplified morphotactic FST structure
725 // Start → NounStem → NounInflected → Final
726
727 // Add noun stem "cat"
728 for ch in "cat".chars() {
729 let next = fst.add_state();
730 fst.add_arc(
731 start,
732 Arc::new(ch as u32, ch as u32, TropicalWeight::one(), next),
733 );
734 }
735
736 // Add morpheme boundary
737 fst.add_arc(
738 noun_stem,
739 Arc::new(
740 '+' as u32,
741 0, // epsilon output
742 TropicalWeight::one(),
743 noun_inflected,
744 ),
745 );
746
747 // Add plural suffix "s"
748 fst.add_arc(
749 noun_inflected,
750 Arc::new('s' as u32, 's' as u32, TropicalWeight::one(), final_state),
751 );
752
753 fst
754}More examples
33fn build_dictionary_fst(words: &[&str]) -> VectorFst<TropicalWeight> {
34 let mut fst = VectorFst::new();
35 let start = fst.add_state();
36 fst.set_start(start);
37
38 // Build a trie structure
39 let mut state_map: HashMap<Vec<char>, u32> = HashMap::new();
40 state_map.insert(vec![], start);
41
42 for word in words {
43 let chars: Vec<char> = word.chars().collect();
44 let mut prefix = vec![];
45
46 for (i, &ch) in chars.iter().enumerate() {
47 let current_state = *state_map.get(&prefix).unwrap();
48 prefix.push(ch);
49
50 if !state_map.contains_key(&prefix) {
51 let new_state = fst.add_state();
52 state_map.insert(prefix.clone(), new_state);
53 fst.add_arc(
54 current_state,
55 Arc::new(ch as u32, ch as u32, TropicalWeight::one(), new_state),
56 );
57 }
58
59 // If this is the last character, mark as final
60 if i == chars.len() - 1 {
61 let final_state = *state_map.get(&prefix).unwrap();
62 fst.set_final(final_state, TropicalWeight::one());
63 }
64 }
65 }
66
67 fst
68}
69
70/// Creates an FST that accepts all words within edit distance k of a target word
71///
72/// # Arguments
73/// * `target` - The target word to match against
74/// * `k` - Maximum allowed edit distance
75///
76/// # Returns
77/// An FST that accepts words within edit distance k of target
78fn build_edit_distance_fst(target: &str, k: usize) -> VectorFst<TropicalWeight> {
79 let mut fst = VectorFst::new();
80 let target_chars: Vec<char> = target.chars().collect();
81 let n = target_chars.len();
82
83 // Create states: (position in target, edits used)
84 let mut states = vec![vec![]; n + 1];
85 for (i, state_row) in states.iter_mut().enumerate().take(n + 1) {
86 for _j in 0..=k.min(i + k) {
87 state_row.push(fst.add_state());
88 }
89 }
90
91 // Start state
92 fst.set_start(states[0][0]);
93
94 // Final states - at end of target with <= k edits
95 for j in 0..=k.min(n + k) {
96 if j < states[n].len() {
97 fst.set_final(states[n][j], TropicalWeight::new(j as f32));
98 }
99 }
100
101 // Add transitions
102 for i in 0..n {
103 for j in 0..states[i].len() {
104 if j > i + k {
105 continue; // Skip impossible states
106 }
107
108 let current = states[i][j];
109
110 // Match (no cost)
111 if j < states[i + 1].len() {
112 fst.add_arc(
113 current,
114 Arc::new(
115 target_chars[i] as u32,
116 target_chars[i] as u32,
117 TropicalWeight::one(),
118 states[i + 1][j],
119 ),
120 );
121 }
122
123 // If we can still make edits
124 if j < k {
125 // Substitution (cost 1)
126 if j + 1 < states[i + 1].len() {
127 for c in b'a'..=b'z' {
128 if c as char != target_chars[i] {
129 fst.add_arc(
130 current,
131 Arc::new(
132 c as u32,
133 c as u32,
134 TropicalWeight::new(1.0),
135 states[i + 1][j + 1],
136 ),
137 );
138 }
139 }
140 }
141
142 // Deletion in target (consume target char with epsilon)
143 if j + 1 < states[i + 1].len() {
144 fst.add_arc(
145 current,
146 Arc::new(
147 0, // epsilon
148 0, // epsilon
149 TropicalWeight::new(1.0),
150 states[i + 1][j + 1],
151 ),
152 );
153 }
154
155 // Insertion (consume input char)
156 if j + 1 < states[i].len() {
157 for c in b'a'..=b'z' {
158 fst.add_arc(
159 current,
160 Arc::new(
161 c as u32,
162 c as u32,
163 TropicalWeight::new(1.0),
164 states[i][j + 1],
165 ),
166 );
167 }
168 }
169 }
170 }
171 }
172
173 // Handle insertions at the end
174 for j in 0..states[n].len() {
175 if j < k && j + 1 < states[n].len() {
176 let current = states[n][j];
177 for c in b'a'..=b'z' {
178 fst.add_arc(
179 current,
180 Arc::new(
181 c as u32,
182 c as u32,
183 TropicalWeight::new(1.0),
184 states[n][j + 1],
185 ),
186 );
187 }
188 }
189 }
190
191 fst
192}357fn build_number_normalization_fst() -> VectorFst<TropicalWeight> {
358 let mut fst = VectorFst::new();
359 let start = fst.add_state();
360 fst.set_start(start);
361 fst.set_final(start, TropicalWeight::one());
362
363 // Add some simple number transformations
364 let number_rules = vec![
365 ("one", "1"),
366 ("two", "2"),
367 ("three", "3"),
368 ("four", "4"),
369 ("five", "5"),
370 ];
371
372 for (word, digit) in number_rules {
373 let mut current = start;
374
375 // Accept the word
376 for ch in word.chars() {
377 let next = fst.add_state();
378 fst.add_arc(
379 current,
380 Arc::new(
381 ch as u32,
382 0, // epsilon output during word
383 TropicalWeight::one(),
384 next,
385 ),
386 );
387 current = next;
388 }
389
390 // Output the digit
391 for ch in digit.chars() {
392 let next = fst.add_state();
393 fst.add_arc(
394 current,
395 Arc::new(
396 0, // epsilon input
397 ch as u32,
398 TropicalWeight::one(),
399 next,
400 ),
401 );
402 current = next;
403 }
404
405 // Connect back to start for more normalizations
406 fst.add_arc(
407 current,
408 Arc::new(
409 0, // epsilon
410 0, // epsilon
411 TropicalWeight::one(),
412 start,
413 ),
414 );
415 }
416
417 fst
418}176fn build_simple_lexicon(entries: &[LexiconEntry]) -> VectorFst<TropicalWeight> {
177 let mut fst = VectorFst::new();
178 let start = fst.add_state();
179 fst.set_start(start);
180
181 for entry in entries {
182 // For each pronunciation, create a separate path
183 for pronunciation in &entry.pronunciations {
184 let mut states = vec![start];
185
186 // Create states for each character in the word
187 for _ in 0..entry.word.len() {
188 states.push(fst.add_state());
189 }
190
191 // Add transitions for each character
192 for (i, ch) in entry.word.chars().enumerate() {
193 fst.add_arc(
194 states[i],
195 Arc::new(
196 ch as u32,
197 ch as u32, // Output the same character for now
198 TropicalWeight::one(),
199 states[i + 1],
200 ),
201 );
202 }
203
204 // At the end of the word, output the pronunciation
205 let mut current = states[entry.word.len()];
206 for phoneme in pronunciation {
207 let next = fst.add_state();
208 fst.add_arc(
209 current,
210 Arc::new(
211 0, // epsilon input
212 phoneme.to_label(),
213 TropicalWeight::one(),
214 next,
215 ),
216 );
217 current = next;
218 }
219
220 fst.set_final(current, TropicalWeight::one());
221 }
222 }
223
224 fst
225}
226
227/// Build an FST that accepts a single word
228fn word_acceptor(word: &str) -> VectorFst<TropicalWeight> {
229 let mut fst = VectorFst::new();
230 let mut current = fst.add_state();
231 fst.set_start(current);
232
233 for ch in word.chars() {
234 let next = fst.add_state();
235 fst.add_arc(
236 current,
237 Arc::new(ch as u32, ch as u32, TropicalWeight::one(), next),
238 );
239 current = next;
240 }
241
242 fst.set_final(current, TropicalWeight::one());
243 fst
244}
245
246/// Look up pronunciations for a word using the lexicon
247fn lookup_word_in_lexicon(entries: &[LexiconEntry], word: &str) -> Option<Vec<Vec<Phoneme>>> {
248 for entry in entries {
249 if entry.word == word {
250 return Some(entry.pronunciations.clone());
251 }
252 }
253 None
254}
255
256/// Build a G2P (Grapheme-to-Phoneme) FST for unknown words
257fn build_g2p_rules() -> VectorFst<TropicalWeight> {
258 let mut fst = VectorFst::new();
259 let start = fst.add_state();
260 fst.set_start(start);
261 fst.set_final(start, TropicalWeight::one());
262
263 // Simple G2P rules - in practice this would be much more sophisticated
264 let rules = vec![
265 ('a', Phoneme::AE),
266 ('e', Phoneme::EH),
267 ('i', Phoneme::IH),
268 ('o', Phoneme::AO),
269 ('u', Phoneme::AH),
270 ('b', Phoneme::B),
271 ('c', Phoneme::K),
272 ('d', Phoneme::D),
273 ('f', Phoneme::F),
274 ('g', Phoneme::G),
275 ('h', Phoneme::HH),
276 ('j', Phoneme::JH),
277 ('k', Phoneme::K),
278 ('l', Phoneme::L),
279 ('m', Phoneme::M),
280 ('n', Phoneme::N),
281 ('p', Phoneme::P),
282 ('r', Phoneme::R),
283 ('s', Phoneme::S),
284 ('t', Phoneme::T),
285 ('v', Phoneme::V),
286 ('w', Phoneme::W),
287 ('y', Phoneme::Y),
288 ('z', Phoneme::Z),
289 ];
290
291 for (grapheme, phoneme) in rules {
292 fst.add_arc(
293 start,
294 Arc::new(
295 grapheme as u32,
296 phoneme.to_label(),
297 TropicalWeight::new(1.0),
298 start,
299 ),
300 );
301 }
302
303 fst
304}982fn build_transliteration_fst(rules: &[TransliterationRule]) -> VectorFst<TropicalWeight> {
983 let mut fst = VectorFst::new();
984 let start = fst.add_state();
985 fst.set_start(start);
986 fst.set_final(start, TropicalWeight::one());
987
988 // Sort rules by source length (longest first) to handle digraphs
989 let mut sorted_rules = rules.to_vec();
990 sorted_rules.sort_by(|a, b| b.source.len().cmp(&a.source.len()));
991
992 for rule in &sorted_rules {
993 let mut current = start;
994
995 // Process each character in the source
996 let source_chars: Vec<char> = rule.source.chars().collect();
997 for (i, &ch) in source_chars.iter().enumerate() {
998 if i == source_chars.len() - 1 {
999 // Last character - output the target
1000 let target_chars: Vec<char> = rule.target.chars().collect();
1001 let _target_state = start;
1002
1003 for &target_ch in &target_chars {
1004 let next = fst.add_state();
1005 fst.add_arc(
1006 current,
1007 Arc::new(ch as u32, target_ch as u32, TropicalWeight::one(), next),
1008 );
1009 current = next;
1010 }
1011
1012 // Connect back to start for more characters
1013 fst.add_arc(
1014 current,
1015 Arc::new(
1016 0, // epsilon
1017 0, // epsilon
1018 TropicalWeight::one(),
1019 start,
1020 ),
1021 );
1022 } else {
1023 // Intermediate character
1024 let next = fst.add_state();
1025 fst.add_arc(
1026 current,
1027 Arc::new(
1028 ch as u32,
1029 0, // epsilon output
1030 TropicalWeight::one(),
1031 next,
1032 ),
1033 );
1034 current = next;
1035 }
1036 }
1037 }
1038
1039 // Add pass-through for unknown characters
1040 for ch in 0..=127u8 {
1041 if ch.is_ascii() {
1042 fst.add_arc(
1043 start,
1044 Arc::new(ch as u32, ch as u32, TropicalWeight::one(), start),
1045 );
1046 }
1047 }
1048
1049 fst
1050}88fn build_vowel_harmony_fst() -> VectorFst<TropicalWeight> {
89 let mut fst = VectorFst::new();
90 let start = fst.add_state();
91 let back_state = fst.add_state();
92 let front_state = fst.add_state();
93
94 fst.set_start(start);
95 fst.set_final(start, TropicalWeight::one());
96 fst.set_final(back_state, TropicalWeight::one());
97 fst.set_final(front_state, TropicalWeight::one());
98
99 // Back vowels trigger back harmony
100 let back_vowels = ['a', 'o', 'u'];
101 let front_vowels = ['e', 'i'];
102
103 for &vowel in &back_vowels {
104 fst.add_arc(
105 start,
106 Arc::new(
107 vowel as u32,
108 vowel as u32,
109 TropicalWeight::one(),
110 back_state,
111 ),
112 );
113 fst.add_arc(
114 back_state,
115 Arc::new(
116 vowel as u32,
117 vowel as u32,
118 TropicalWeight::one(),
119 back_state,
120 ),
121 );
122 }
123
124 for &vowel in &front_vowels {
125 fst.add_arc(
126 start,
127 Arc::new(
128 vowel as u32,
129 vowel as u32,
130 TropicalWeight::one(),
131 front_state,
132 ),
133 );
134 fst.add_arc(
135 front_state,
136 Arc::new(
137 vowel as u32,
138 vowel as u32,
139 TropicalWeight::one(),
140 front_state,
141 ),
142 );
143 }
144
145 // Harmonizing vowel: 'E' becomes 'e' in front context, 'a' in back context
146 fst.add_arc(
147 back_state,
148 Arc::new('E' as u32, 'a' as u32, TropicalWeight::one(), back_state),
149 );
150
151 fst.add_arc(
152 front_state,
153 Arc::new('E' as u32, 'e' as u32, TropicalWeight::one(), front_state),
154 );
155
156 // Consonants are transparent
157 let consonants = "bcdfghjklmnpqrstvwxyz";
158 for ch in consonants.chars() {
159 fst.add_arc(
160 start,
161 Arc::new(ch as u32, ch as u32, TropicalWeight::one(), start),
162 );
163 fst.add_arc(
164 back_state,
165 Arc::new(ch as u32, ch as u32, TropicalWeight::one(), back_state),
166 );
167 fst.add_arc(
168 front_state,
169 Arc::new(ch as u32, ch as u32, TropicalWeight::one(), front_state),
170 );
171 }
172
173 fst
174}
175
176/// Build FST for consonant cluster simplification
177/// Example: /kt/ -> /t/ (cluster reduction)
178fn build_cluster_simplification_fst() -> VectorFst<TropicalWeight> {
179 let mut fst = VectorFst::new();
180 let start = fst.add_state();
181 let k_state = fst.add_state();
182
183 fst.set_start(start);
184 fst.set_final(start, TropicalWeight::one());
185
186 // /k/ followed by /t/ becomes just /t/
187 fst.add_arc(
188 start,
189 Arc::new(
190 'k' as u32,
191 0, // epsilon output (delete k)
192 TropicalWeight::one(),
193 k_state,
194 ),
195 );
196
197 fst.add_arc(
198 k_state,
199 Arc::new('t' as u32, 't' as u32, TropicalWeight::one(), start),
200 );
201
202 // All other characters pass through unchanged
203 for ch in b'a'..=b'z' {
204 let ch = ch as char;
205 if ch != 'k' {
206 fst.add_arc(
207 start,
208 Arc::new(ch as u32, ch as u32, TropicalWeight::one(), start),
209 );
210 }
211 }
212
213 // k in other contexts passes through
214 for ch in b'a'..=b'z' {
215 let ch = ch as char;
216 if ch != 't' {
217 fst.add_arc(
218 k_state,
219 Arc::new(
220 ch as u32,
221 'k' as u32, // output the k we held
222 TropicalWeight::one(),
223 start,
224 ),
225 );
226 // Then process the current character
227 fst.add_arc(
228 start,
229 Arc::new(ch as u32, ch as u32, TropicalWeight::one(), start),
230 );
231 }
232 }
233
234 fst
235}
236
237/// Build FST for vowel epenthesis (insertion)
238/// Example: Insert 'i' to break consonant clusters
239fn build_epenthesis_fst() -> VectorFst<TropicalWeight> {
240 let mut fst = VectorFst::new();
241 let start = fst.add_state();
242 let consonant_state = fst.add_state();
243
244 fst.set_start(start);
245 fst.set_final(start, TropicalWeight::one());
246 fst.set_final(consonant_state, TropicalWeight::one());
247
248 let vowels = "aeiou";
249 let consonants = "bcdfghjklmnpqrstvwxyz";
250
251 // Vowels pass through and reset to start
252 for ch in vowels.chars() {
253 fst.add_arc(
254 start,
255 Arc::new(ch as u32, ch as u32, TropicalWeight::one(), start),
256 );
257 fst.add_arc(
258 consonant_state,
259 Arc::new(ch as u32, ch as u32, TropicalWeight::one(), start),
260 );
261 }
262
263 // First consonant goes to consonant state
264 for ch in consonants.chars() {
265 fst.add_arc(
266 start,
267 Arc::new(ch as u32, ch as u32, TropicalWeight::one(), consonant_state),
268 );
269 }
270
271 // Second consonant triggers epenthesis
272 for ch in consonants.chars() {
273 fst.add_arc(
274 consonant_state,
275 Arc::new(
276 ch as u32,
277 'i' as u32, // insert epenthetic vowel
278 TropicalWeight::one(),
279 start,
280 ),
281 );
282 // Then output the consonant
283 fst.add_arc(
284 start,
285 Arc::new(
286 0, // epsilon input
287 ch as u32,
288 TropicalWeight::one(),
289 consonant_state,
290 ),
291 );
292 }
293
294 fst
295}
296
297/// Build FST for final devoicing (German-style)
298/// Example: /d/ -> /t/ / _#
299fn build_final_devoicing_fst() -> VectorFst<TropicalWeight> {
300 let mut fst = VectorFst::new();
301 let start = fst.add_state();
302 let voiced_state = fst.add_state();
303
304 fst.set_start(start);
305 fst.set_final(start, TropicalWeight::one());
306
307 // Final voiced consonants become voiceless
308 fst.set_final(voiced_state, TropicalWeight::new(0.0)); // Cost for devoicing
309
310 let voiced_obstruents = ['b', 'd', 'g', 'z', 'v'];
311 let voiceless_obstruents = ['p', 't', 'k', 's', 'f'];
312
313 // Map voiced to voiceless at word end
314 for (&voiced, &voiceless) in voiced_obstruents.iter().zip(voiceless_obstruents.iter()) {
315 fst.add_arc(
316 start,
317 Arc::new(
318 voiced as u32,
319 voiceless as u32,
320 TropicalWeight::one(),
321 voiced_state,
322 ),
323 );
324 }
325
326 // All other characters pass through
327 for ch in b'a'..=b'z' {
328 let ch = ch as char;
329 if !voiced_obstruents.contains(&ch) {
330 fst.add_arc(
331 start,
332 Arc::new(ch as u32, ch as u32, TropicalWeight::one(), start),
333 );
334 }
335 }
336
337 // Non-final voiced consonants pass through unchanged
338 for ch in b'a'..=b'z' {
339 let ch = ch as char;
340 fst.add_arc(
341 voiced_state,
342 Arc::new(ch as u32, ch as u32, TropicalWeight::one(), start),
343 );
344 }
345
346 fst
347}
348
349/// Build FST that accepts a word
350fn build_word_fst(word: &str) -> VectorFst<TropicalWeight> {
351 let mut fst = VectorFst::new();
352 let mut current = fst.add_state();
353 fst.set_start(current);
354
355 for ch in word.chars() {
356 let next = fst.add_state();
357 fst.add_arc(
358 current,
359 Arc::new(ch as u32, ch as u32, TropicalWeight::one(), next),
360 );
361 current = next;
362 }
363
364 fst.set_final(current, TropicalWeight::one());
365 fst
366}Sourcepub fn epsilon(weight: W, nextstate: StateId) -> Self
pub fn epsilon(weight: W, nextstate: StateId) -> Self
Creates an epsilon arc (no input or output symbol).
Epsilon arcs have input and output labels of 0, representing transitions that neither consume nor produce symbols. These are commonly used in NFA-to-DFA conversions and composition algorithms.
§Arguments
weight- Arc weight in the semiringnextstate- Destination state ID
§Returns
A new Arc with ilabel = 0 and olabel = 0.
§Examples
use arcweight::prelude::*;
let epsilon = Arc::epsilon(TropicalWeight::one(), 2);
assert_eq!(epsilon.ilabel, 0);
assert_eq!(epsilon.olabel, 0);
assert!(epsilon.is_epsilon());
assert!(epsilon.is_epsilon_input());
assert!(epsilon.is_epsilon_output());Sourcepub fn is_epsilon_input(&self) -> bool
pub fn is_epsilon_input(&self) -> bool
Returns true if the input label is epsilon (0).
An epsilon input means this transition does not consume any symbol from the input tape.
§Returns
true if ilabel == 0, false otherwise.
§Examples
use arcweight::prelude::*;
let eps = Arc::new(0, 5, TropicalWeight::one(), 1);
let regular = Arc::new(1, 5, TropicalWeight::one(), 1);
assert!(eps.is_epsilon_input());
assert!(!regular.is_epsilon_input());Sourcepub fn is_epsilon_output(&self) -> bool
pub fn is_epsilon_output(&self) -> bool
Returns true if the output label is epsilon (0).
An epsilon output means this transition does not produce any symbol on the output tape.
§Returns
true if olabel == 0, false otherwise.
§Examples
use arcweight::prelude::*;
let eps = Arc::new(5, 0, TropicalWeight::one(), 1);
let regular = Arc::new(5, 1, TropicalWeight::one(), 1);
assert!(eps.is_epsilon_output());
assert!(!regular.is_epsilon_output());Sourcepub fn is_epsilon(&self) -> bool
pub fn is_epsilon(&self) -> bool
Returns true if both input and output labels are epsilon.
A fully epsilon arc neither consumes input nor produces output, representing a “free” transition between states. Such arcs are commonly removed during epsilon removal optimization.
§Returns
true if both ilabel == 0 and olabel == 0, false otherwise.
§Examples
use arcweight::prelude::*;
let full_eps = Arc::epsilon(TropicalWeight::one(), 1);
let input_eps = Arc::new(0, 5, TropicalWeight::one(), 1);
let regular = Arc::new(1, 2, TropicalWeight::one(), 1);
assert!(full_eps.is_epsilon());
assert!(!input_eps.is_epsilon()); // Only input is epsilon
assert!(!regular.is_epsilon());Trait Implementations§
Source§impl<'de, W> Deserialize<'de> for Arc<W>where
W: Deserialize<'de> + Semiring,
impl<'de, W> Deserialize<'de> for Arc<W>where
W: Deserialize<'de> + Semiring,
Source§fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
impl<W: Eq + Semiring> Eq for Arc<W>
impl<W: PartialEq + Semiring> StructuralPartialEq for Arc<W>
Auto Trait Implementations§
impl<W> Freeze for Arc<W>where
W: Freeze,
impl<W> RefUnwindSafe for Arc<W>where
W: RefUnwindSafe,
impl<W> Send for Arc<W>
impl<W> Sync for Arc<W>
impl<W> Unpin for Arc<W>where
W: Unpin,
impl<W> UnsafeUnpin for Arc<W>where
W: UnsafeUnpin,
impl<W> UnwindSafe for Arc<W>where
W: UnwindSafe,
Blanket Implementations§
Source§impl<T> ArchivePointee for T
impl<T> ArchivePointee for T
Source§type ArchivedMetadata = ()
type ArchivedMetadata = ()
Source§fn pointer_metadata(
_: &<T as ArchivePointee>::ArchivedMetadata,
) -> <T as Pointee>::Metadata
fn pointer_metadata( _: &<T as ArchivePointee>::ArchivedMetadata, ) -> <T as Pointee>::Metadata
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> DeserializeOwned for Twhere
T: for<'de> Deserialize<'de>,
Source§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
Source§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
Source§fn equivalent(&self, key: &K) -> bool
fn equivalent(&self, key: &K) -> bool
key and return true if they are equal.Source§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§impl<T> LayoutRaw for T
impl<T> LayoutRaw for T
Source§fn layout_raw(_: <T as Pointee>::Metadata) -> Result<Layout, LayoutError>
fn layout_raw(_: <T as Pointee>::Metadata) -> Result<Layout, LayoutError>
Source§impl<T, N1, N2> Niching<NichedOption<T, N1>> for N2
impl<T, N1, N2> Niching<NichedOption<T, N1>> for N2
Source§unsafe fn is_niched(niched: *const NichedOption<T, N1>) -> bool
unsafe fn is_niched(niched: *const NichedOption<T, N1>) -> bool
Source§fn resolve_niched(out: Place<NichedOption<T, N1>>)
fn resolve_niched(out: Place<NichedOption<T, N1>>)
out indicating that a T is niched.