rustfst/fst_properties/
mutate_properties.rs1use crate::algorithms::ProjectType;
2use crate::fst_properties::FstProperties;
3use crate::semirings::Semiring;
4use crate::{Label, Tr};
5use crate::{StateId, EPS_LABEL};
6
7pub fn set_start_properties(inprops: FstProperties) -> FstProperties {
8 let mut outprops = inprops & FstProperties::set_start_properties();
9 if inprops.contains(FstProperties::ACYCLIC) {
10 outprops |= FstProperties::INITIAL_ACYCLIC;
11 }
12 outprops
13}
14
15pub fn set_final_properties<W: Semiring>(
16 inprops: FstProperties,
17 old_weight: Option<&W>,
18 new_weight: Option<&W>,
19) -> FstProperties {
20 let mut outprops = inprops;
21 if let Some(w) = old_weight {
22 if !w.is_zero() && !w.is_one() {
23 outprops &= !FstProperties::WEIGHTED;
24 }
25 }
26
27 if let Some(w) = new_weight {
28 if !w.is_zero() && !w.is_one() {
29 outprops |= FstProperties::WEIGHTED;
30 outprops &= !FstProperties::UNWEIGHTED;
31 }
32 }
33
34 outprops &=
35 FstProperties::set_final_properties() | FstProperties::WEIGHTED | FstProperties::UNWEIGHTED;
36 outprops
37}
38
39pub fn add_state_properties(inprops: FstProperties) -> FstProperties {
40 inprops & FstProperties::add_state_properties()
41}
42
43pub fn add_tr_properties<W: Semiring>(
44 inprops: FstProperties,
45 state: StateId,
46 tr: &Tr<W>,
47 prev_tr: Option<&Tr<W>>,
48) -> FstProperties {
49 let mut outprops = inprops;
50
51 if tr.ilabel != tr.olabel {
52 outprops |= FstProperties::NOT_ACCEPTOR;
53 outprops &= !FstProperties::ACCEPTOR;
54 }
55 if tr.ilabel == EPS_LABEL {
56 outprops |= FstProperties::I_EPSILONS;
57 outprops &= !FstProperties::NO_I_EPSILONS;
58 if tr.olabel == EPS_LABEL {
59 outprops |= FstProperties::EPSILONS;
60 outprops &= !FstProperties::NO_EPSILONS;
61 }
62 }
63 if tr.olabel == EPS_LABEL {
64 outprops |= FstProperties::O_EPSILONS;
65 outprops &= !FstProperties::NO_O_EPSILONS;
66 }
67 if let Some(prev_tr) = prev_tr {
68 if prev_tr.ilabel > tr.ilabel {
69 outprops |= FstProperties::NOT_I_LABEL_SORTED;
70 outprops &= !FstProperties::I_LABEL_SORTED;
71 }
72 if prev_tr.olabel > tr.olabel {
73 outprops |= FstProperties::NOT_O_LABEL_SORTED;
74 outprops &= !FstProperties::O_LABEL_SORTED;
75 }
76 }
77 if !tr.weight.is_zero() && !tr.weight.is_one() {
78 outprops |= FstProperties::WEIGHTED;
79 outprops &= !FstProperties::UNWEIGHTED;
80 }
81 if tr.nextstate <= state {
82 outprops |= FstProperties::NOT_TOP_SORTED;
83 outprops &= !FstProperties::TOP_SORTED;
84 }
85 outprops &= FstProperties::add_arc_properties()
86 | FstProperties::ACCEPTOR
87 | FstProperties::NO_EPSILONS
88 | FstProperties::NO_I_EPSILONS
89 | FstProperties::NO_O_EPSILONS
90 | FstProperties::I_LABEL_SORTED
91 | FstProperties::O_LABEL_SORTED
92 | FstProperties::UNWEIGHTED
93 | FstProperties::TOP_SORTED;
94
95 if outprops.contains(FstProperties::TOP_SORTED) {
96 outprops |= FstProperties::ACYCLIC | FstProperties::INITIAL_ACYCLIC;
97 }
98
99 outprops
100}
101
102pub fn delete_states_properties(inprops: FstProperties) -> FstProperties {
103 inprops & FstProperties::delete_states_properties()
104}
105
106pub fn delete_all_states_properties() -> FstProperties {
107 FstProperties::null_properties()
108}
109
110pub fn delete_trs_properties(inprops: FstProperties) -> FstProperties {
111 inprops & FstProperties::delete_arcs_properties()
112}
113
114pub fn closure_properties(inprops: FstProperties, delayed: bool) -> FstProperties {
115 let mut outprops =
116 (FstProperties::ACCEPTOR | FstProperties::UNWEIGHTED | FstProperties::ACCESSIBLE) & inprops;
117 if inprops.contains(FstProperties::UNWEIGHTED) {
118 outprops |= FstProperties::UNWEIGHTED_CYCLES;
119 }
120 if !delayed {
121 outprops |= (FstProperties::COACCESSIBLE
122 | FstProperties::NOT_TOP_SORTED
123 | FstProperties::NOT_STRING)
124 & inprops;
125 }
126 if !delayed || inprops.contains(FstProperties::ACCESSIBLE) {
127 outprops |= (FstProperties::NOT_ACCEPTOR
128 | FstProperties::NOT_I_DETERMINISTIC
129 | FstProperties::NOT_O_DETERMINISTIC
130 | FstProperties::NOT_I_LABEL_SORTED
131 | FstProperties::NOT_O_LABEL_SORTED
132 | FstProperties::WEIGHTED
133 | FstProperties::WEIGHTED_CYCLES
134 | FstProperties::NOT_ACCESSIBLE
135 | FstProperties::NOT_COACCESSIBLE)
136 & inprops;
137 if inprops.contains(FstProperties::WEIGHTED)
138 && inprops.contains(FstProperties::ACCESSIBLE)
139 && inprops.contains(FstProperties::COACCESSIBLE)
140 {
141 outprops |= FstProperties::WEIGHTED_CYCLES;
142 }
143 }
144 outprops
145}
146
147pub fn complement_properties(_inprops: FstProperties) -> FstProperties {
148 unimplemented!()
149}
150
151pub fn compose_properties(inprops1: FstProperties, inprops2: FstProperties) -> FstProperties {
152 let mut outprops = FstProperties::empty();
153 if inprops1.contains(FstProperties::ACCEPTOR) && inprops2.contains(FstProperties::ACCEPTOR) {
154 outprops |= FstProperties::ACCEPTOR | FstProperties::ACCESSIBLE;
155 outprops |= (FstProperties::NO_EPSILONS
156 | FstProperties::NO_I_EPSILONS
157 | FstProperties::NO_O_EPSILONS
158 | FstProperties::ACYCLIC
159 | FstProperties::INITIAL_ACYCLIC)
160 & inprops1
161 & inprops2;
162 if inprops1.contains(FstProperties::NO_I_EPSILONS)
163 && inprops2.contains(FstProperties::NO_I_EPSILONS)
164 {
165 outprops |= (FstProperties::I_DETERMINISTIC | FstProperties::O_DETERMINISTIC)
166 & inprops1
167 & inprops2;
168 }
169 } else {
170 outprops |= FstProperties::ACCESSIBLE;
171 outprops |= (FstProperties::ACCEPTOR
172 | FstProperties::NO_I_EPSILONS
173 | FstProperties::ACYCLIC
174 | FstProperties::INITIAL_ACYCLIC)
175 & inprops1
176 & inprops2;
177 if inprops1.contains(FstProperties::NO_I_EPSILONS)
178 && inprops2.contains(FstProperties::NO_I_EPSILONS)
179 {
180 outprops |= FstProperties::I_DETERMINISTIC & inprops1 & inprops2;
181 }
182 }
183 outprops
184}
185
186pub fn concat_properties(
187 inprops1: FstProperties,
188 inprops2: FstProperties,
189 delayed: bool,
190) -> FstProperties {
191 let mut outprops = (FstProperties::ACCEPTOR
192 | FstProperties::UNWEIGHTED
193 | FstProperties::UNWEIGHTED_CYCLES
194 | FstProperties::ACYCLIC)
195 & inprops1
196 & inprops2;
197 let empty1 = delayed; let empty2 = delayed; if !delayed {
200 outprops |= (FstProperties::NOT_TOP_SORTED | FstProperties::NOT_STRING) & inprops1;
201 outprops |= (FstProperties::NOT_TOP_SORTED | FstProperties::NOT_STRING) & inprops2;
202 }
203 if !empty1 {
204 outprops |= (FstProperties::INITIAL_ACYCLIC | FstProperties::INITIAL_CYCLIC) & inprops1;
205 }
206 if !delayed || inprops1.contains(FstProperties::ACCESSIBLE) {
207 outprops |= (FstProperties::NOT_ACCEPTOR
208 | FstProperties::NOT_I_DETERMINISTIC
209 | FstProperties::NOT_O_DETERMINISTIC
210 | FstProperties::EPSILONS
211 | FstProperties::I_EPSILONS
212 | FstProperties::O_EPSILONS
213 | FstProperties::NOT_I_LABEL_SORTED
214 | FstProperties::NOT_O_LABEL_SORTED
215 | FstProperties::WEIGHTED
216 | FstProperties::WEIGHTED_CYCLES
217 | FstProperties::CYCLIC
218 | FstProperties::NOT_ACCESSIBLE
219 | FstProperties::NOT_COACCESSIBLE)
220 & inprops1;
221 }
222 if (inprops1.contains(FstProperties::ACCESSIBLE | FstProperties::COACCESSIBLE)) && !empty1 {
223 outprops |= FstProperties::ACCESSIBLE & inprops2;
224 if !empty2 {
225 outprops |= FstProperties::COACCESSIBLE & inprops2;
226 }
227 if !delayed || inprops2.contains(FstProperties::ACCESSIBLE) {
228 outprops |= (FstProperties::NOT_ACCEPTOR
229 | FstProperties::NOT_I_DETERMINISTIC
230 | FstProperties::NOT_O_DETERMINISTIC
231 | FstProperties::EPSILONS
232 | FstProperties::I_EPSILONS
233 | FstProperties::O_EPSILONS
234 | FstProperties::NOT_I_LABEL_SORTED
235 | FstProperties::NOT_O_LABEL_SORTED
236 | FstProperties::WEIGHTED
237 | FstProperties::WEIGHTED_CYCLES
238 | FstProperties::CYCLIC
239 | FstProperties::NOT_ACCESSIBLE
240 | FstProperties::NOT_COACCESSIBLE)
241 & inprops2;
242 }
243 }
244 outprops
245}
246
247pub fn determinize_properties(
248 inprops: FstProperties,
249 has_subsequential_label: bool,
250 distinct_psubsequential_labels: bool,
251) -> FstProperties {
252 let mut outprops = FstProperties::ACCESSIBLE;
253 if inprops.contains(FstProperties::ACCEPTOR)
254 || (inprops.contains(FstProperties::NO_I_EPSILONS) && distinct_psubsequential_labels)
255 || (has_subsequential_label && distinct_psubsequential_labels)
256 {
257 outprops |= FstProperties::I_DETERMINISTIC;
258 }
259 outprops |= (FstProperties::ACCEPTOR
260 | FstProperties::ACYCLIC
261 | FstProperties::INITIAL_ACYCLIC
262 | FstProperties::COACCESSIBLE
263 | FstProperties::STRING)
264 & inprops;
265 if inprops.contains(FstProperties::NO_I_EPSILONS) && distinct_psubsequential_labels {
266 outprops |= FstProperties::NO_EPSILONS & inprops;
267 }
268 if inprops.contains(FstProperties::ACCESSIBLE) {
269 outprops |= (FstProperties::I_EPSILONS | FstProperties::O_EPSILONS | FstProperties::CYCLIC)
270 & inprops;
271 }
272 if inprops.contains(FstProperties::ACCEPTOR) {
273 outprops |= (FstProperties::NO_I_EPSILONS | FstProperties::NO_O_EPSILONS) & inprops;
274 }
275 if inprops.contains(FstProperties::NO_I_EPSILONS) && has_subsequential_label {
276 outprops |= FstProperties::NO_I_EPSILONS;
277 }
278 outprops
279}
280
281pub fn factor_weight_properties(inprops: FstProperties) -> FstProperties {
282 let mut outprops = (FstProperties::ACCEPTOR
283 | FstProperties::ACYCLIC
284 | FstProperties::ACCESSIBLE
285 | FstProperties::COACCESSIBLE)
286 & inprops;
287 if inprops.contains(FstProperties::ACCESSIBLE) {
288 outprops |= (FstProperties::NOT_ACCEPTOR
289 | FstProperties::NOT_I_DETERMINISTIC
290 | FstProperties::NOT_O_DETERMINISTIC
291 | FstProperties::EPSILONS
292 | FstProperties::I_EPSILONS
293 | FstProperties::O_EPSILONS
294 | FstProperties::CYCLIC
295 | FstProperties::NOT_I_LABEL_SORTED
296 | FstProperties::NOT_O_LABEL_SORTED)
297 & inprops;
298 }
299 outprops
300}
301
302pub fn invert_properties(inprops: FstProperties) -> FstProperties {
303 let mut outprops = (FstProperties::ACCEPTOR
304 | FstProperties::NOT_ACCEPTOR
305 | FstProperties::EPSILONS
306 | FstProperties::NO_EPSILONS
307 | FstProperties::WEIGHTED
308 | FstProperties::UNWEIGHTED
309 | FstProperties::WEIGHTED_CYCLES
310 | FstProperties::UNWEIGHTED_CYCLES
311 | FstProperties::CYCLIC
312 | FstProperties::ACYCLIC
313 | FstProperties::INITIAL_CYCLIC
314 | FstProperties::INITIAL_ACYCLIC
315 | FstProperties::TOP_SORTED
316 | FstProperties::NOT_TOP_SORTED
317 | FstProperties::ACCESSIBLE
318 | FstProperties::NOT_ACCESSIBLE
319 | FstProperties::COACCESSIBLE
320 | FstProperties::NOT_COACCESSIBLE
321 | FstProperties::STRING
322 | FstProperties::NOT_STRING)
323 & inprops;
324 if inprops.contains(FstProperties::I_DETERMINISTIC) {
325 outprops |= FstProperties::O_DETERMINISTIC;
326 }
327 if inprops.contains(FstProperties::NOT_I_DETERMINISTIC) {
328 outprops |= FstProperties::NOT_O_DETERMINISTIC;
329 }
330 if inprops.contains(FstProperties::O_DETERMINISTIC) {
331 outprops |= FstProperties::I_DETERMINISTIC;
332 }
333 if inprops.contains(FstProperties::NOT_O_DETERMINISTIC) {
334 outprops |= FstProperties::NOT_I_DETERMINISTIC;
335 }
336
337 if inprops.contains(FstProperties::I_EPSILONS) {
338 outprops |= FstProperties::O_EPSILONS;
339 }
340 if inprops.contains(FstProperties::NO_I_EPSILONS) {
341 outprops |= FstProperties::NO_O_EPSILONS;
342 }
343 if inprops.contains(FstProperties::O_EPSILONS) {
344 outprops |= FstProperties::I_EPSILONS;
345 }
346 if inprops.contains(FstProperties::NO_O_EPSILONS) {
347 outprops |= FstProperties::NO_I_EPSILONS;
348 }
349
350 if inprops.contains(FstProperties::I_LABEL_SORTED) {
351 outprops |= FstProperties::O_LABEL_SORTED;
352 }
353 if inprops.contains(FstProperties::NOT_I_LABEL_SORTED) {
354 outprops |= FstProperties::NOT_O_LABEL_SORTED;
355 }
356 if inprops.contains(FstProperties::O_LABEL_SORTED) {
357 outprops |= FstProperties::I_LABEL_SORTED;
358 }
359 if inprops.contains(FstProperties::NOT_O_LABEL_SORTED) {
360 outprops |= FstProperties::NOT_I_LABEL_SORTED;
361 }
362 outprops
363}
364
365pub fn project_properties(inprops: FstProperties, project_type: ProjectType) -> FstProperties {
366 let mut outprops = FstProperties::ACCEPTOR;
367 outprops |= (FstProperties::WEIGHTED
368 | FstProperties::UNWEIGHTED
369 | FstProperties::WEIGHTED_CYCLES
370 | FstProperties::UNWEIGHTED_CYCLES
371 | FstProperties::CYCLIC
372 | FstProperties::ACYCLIC
373 | FstProperties::INITIAL_CYCLIC
374 | FstProperties::INITIAL_ACYCLIC
375 | FstProperties::TOP_SORTED
376 | FstProperties::NOT_TOP_SORTED
377 | FstProperties::ACCESSIBLE
378 | FstProperties::NOT_ACCESSIBLE
379 | FstProperties::COACCESSIBLE
380 | FstProperties::NOT_COACCESSIBLE
381 | FstProperties::STRING
382 | FstProperties::NOT_STRING)
383 & inprops;
384 match project_type {
385 ProjectType::ProjectInput => {
386 outprops |= (FstProperties::I_DETERMINISTIC
387 | FstProperties::NOT_I_DETERMINISTIC
388 | FstProperties::I_EPSILONS
389 | FstProperties::NO_I_EPSILONS
390 | FstProperties::I_LABEL_SORTED
391 | FstProperties::NOT_I_LABEL_SORTED)
392 & inprops;
393
394 if inprops.contains(FstProperties::I_DETERMINISTIC) {
395 outprops |= FstProperties::O_DETERMINISTIC;
396 }
397 if inprops.contains(FstProperties::NOT_I_DETERMINISTIC) {
398 outprops |= FstProperties::NOT_O_DETERMINISTIC;
399 }
400
401 if inprops.contains(FstProperties::I_EPSILONS) {
402 outprops |= FstProperties::O_EPSILONS | FstProperties::EPSILONS;
403 }
404 if inprops.contains(FstProperties::NO_I_EPSILONS) {
405 outprops |= FstProperties::NO_O_EPSILONS | FstProperties::NO_EPSILONS;
406 }
407
408 if inprops.contains(FstProperties::I_LABEL_SORTED) {
409 outprops |= FstProperties::O_LABEL_SORTED;
410 }
411 if inprops.contains(FstProperties::NOT_I_LABEL_SORTED) {
412 outprops |= FstProperties::NOT_O_LABEL_SORTED;
413 }
414 }
415 ProjectType::ProjectOutput => {
416 outprops |= (FstProperties::O_DETERMINISTIC
417 | FstProperties::NOT_O_DETERMINISTIC
418 | FstProperties::O_EPSILONS
419 | FstProperties::NO_O_EPSILONS
420 | FstProperties::O_LABEL_SORTED
421 | FstProperties::NOT_O_LABEL_SORTED)
422 & inprops;
423
424 if inprops.contains(FstProperties::O_DETERMINISTIC) {
425 outprops |= FstProperties::I_DETERMINISTIC;
426 }
427 if inprops.contains(FstProperties::NOT_O_DETERMINISTIC) {
428 outprops |= FstProperties::NOT_I_DETERMINISTIC;
429 }
430
431 if inprops.contains(FstProperties::O_EPSILONS) {
432 outprops |= FstProperties::I_EPSILONS | FstProperties::EPSILONS;
433 }
434 if inprops.contains(FstProperties::NO_O_EPSILONS) {
435 outprops |= FstProperties::NO_I_EPSILONS | FstProperties::NO_EPSILONS;
436 }
437
438 if inprops.contains(FstProperties::O_LABEL_SORTED) {
439 outprops |= FstProperties::I_LABEL_SORTED;
440 }
441 if inprops.contains(FstProperties::NOT_O_LABEL_SORTED) {
442 outprops |= FstProperties::NOT_I_LABEL_SORTED;
443 }
444 }
445 };
446 outprops
447}
448
449pub fn rand_gen_properties(inprops: FstProperties, weighted: bool) -> FstProperties {
450 let mut outprops = FstProperties::ACYCLIC
451 | FstProperties::INITIAL_ACYCLIC
452 | FstProperties::ACCESSIBLE
453 | FstProperties::UNWEIGHTED_CYCLES;
454 if weighted {
455 outprops |= FstProperties::TOP_SORTED;
456 outprops |= (FstProperties::ACCEPTOR
457 | FstProperties::NO_EPSILONS
458 | FstProperties::NO_I_EPSILONS
459 | FstProperties::NO_O_EPSILONS
460 | FstProperties::I_DETERMINISTIC
461 | FstProperties::O_DETERMINISTIC
462 | FstProperties::I_LABEL_SORTED
463 | FstProperties::O_LABEL_SORTED)
464 & inprops;
465 } else {
466 outprops |= FstProperties::UNWEIGHTED;
467 outprops |= (FstProperties::ACCEPTOR
468 | FstProperties::I_LABEL_SORTED
469 | FstProperties::O_LABEL_SORTED)
470 & inprops;
471 }
472 outprops
473}
474
475pub fn relabel_properties(inprops: FstProperties) -> FstProperties {
476 let outprops = FstProperties::WEIGHTED
477 | FstProperties::UNWEIGHTED
478 | FstProperties::WEIGHTED_CYCLES
479 | FstProperties::UNWEIGHTED_CYCLES
480 | FstProperties::CYCLIC
481 | FstProperties::ACYCLIC
482 | FstProperties::INITIAL_CYCLIC
483 | FstProperties::INITIAL_ACYCLIC
484 | FstProperties::TOP_SORTED
485 | FstProperties::NOT_TOP_SORTED
486 | FstProperties::ACCESSIBLE
487 | FstProperties::NOT_ACCESSIBLE
488 | FstProperties::COACCESSIBLE
489 | FstProperties::NOT_COACCESSIBLE
490 | FstProperties::STRING
491 | FstProperties::NOT_STRING;
492 outprops & inprops
493}
494
495#[allow(clippy::too_many_arguments)]
496pub fn replace_properties(
497 inprops: &[FstProperties],
498 root: Label,
499 epsilon_on_call: bool,
500 epsilon_on_return: bool,
501 out_epsilon_on_call: bool,
502 out_epsilon_on_return: bool,
503 replace_transducer: bool,
504 no_empty_fsts: bool,
505 all_ilabel_sorted: bool,
506 all_olabel_sorted: bool,
507 all_negative_or_dense: bool,
508) -> FstProperties {
509 if inprops.is_empty() {
510 return FstProperties::null_properties();
511 }
512 let mut outprops = FstProperties::empty();
513 let mut access_props = if no_empty_fsts {
514 FstProperties::ACCESSIBLE | FstProperties::COACCESSIBLE
515 } else {
516 FstProperties::empty()
517 };
518
519 for inprop in inprops {
520 access_props &= *inprop & (FstProperties::ACCESSIBLE | FstProperties::COACCESSIBLE);
521 }
522
523 if access_props == (FstProperties::ACCESSIBLE | FstProperties::COACCESSIBLE) {
524 outprops |= access_props;
525 if inprops[root as usize].contains(FstProperties::INITIAL_CYCLIC) {
526 outprops |= FstProperties::INITIAL_CYCLIC;
527 }
528 let mut props = FstProperties::empty();
529 let mut string = true;
530 for inprop in inprops {
531 if replace_transducer {
532 props |= FstProperties::NOT_ACCEPTOR & *inprop;
533 }
534 props |= (FstProperties::NOT_I_DETERMINISTIC
535 | FstProperties::NOT_O_DETERMINISTIC
536 | FstProperties::EPSILONS
537 | FstProperties::I_EPSILONS
538 | FstProperties::O_EPSILONS
539 | FstProperties::WEIGHTED
540 | FstProperties::WEIGHTED_CYCLES
541 | FstProperties::CYCLIC
542 | FstProperties::NOT_TOP_SORTED
543 | FstProperties::NOT_STRING)
544 & *inprop;
545 if !inprop.contains(FstProperties::STRING) {
546 string = false;
547 }
548 }
549 outprops |= props;
550 if string {
551 outprops |= FstProperties::STRING;
552 }
553 }
554 let mut acceptor = !replace_transducer;
555 let mut ideterministic = !epsilon_on_call && epsilon_on_return;
556 let mut no_iepsilons = !epsilon_on_call && !epsilon_on_return;
557 let mut acyclic = true;
558 let mut unweighted = true;
559 for (i, inprop) in inprops.iter().enumerate() {
560 if !inprop.contains(FstProperties::ACCEPTOR) {
561 acceptor = false;
562 }
563 if !inprop.contains(FstProperties::I_DETERMINISTIC) {
564 ideterministic = false;
565 }
566 if !inprop.contains(FstProperties::NO_I_EPSILONS) {
567 no_iepsilons = false;
568 }
569 if !inprop.contains(FstProperties::ACYCLIC) {
570 acyclic = false;
571 }
572 if !inprop.contains(FstProperties::UNWEIGHTED) {
573 unweighted = false;
574 }
575 if i != root as usize && !inprop.contains(FstProperties::NO_I_EPSILONS) {
576 ideterministic = false;
577 }
578 }
579 if acceptor {
580 outprops |= FstProperties::ACCEPTOR;
581 }
582 if ideterministic {
583 outprops |= FstProperties::I_DETERMINISTIC;
584 }
585 if no_iepsilons {
586 outprops |= FstProperties::NO_I_EPSILONS;
587 }
588 if acyclic {
589 outprops |= FstProperties::ACYCLIC;
590 }
591 if unweighted {
592 outprops |= FstProperties::UNWEIGHTED;
593 }
594 if inprops[root as usize].contains(FstProperties::INITIAL_ACYCLIC) {
595 outprops |= FstProperties::INITIAL_ACYCLIC;
596 }
597 if all_ilabel_sorted && epsilon_on_return && (!epsilon_on_call || all_negative_or_dense) {
606 outprops |= FstProperties::I_LABEL_SORTED;
607 }
608 if all_olabel_sorted && out_epsilon_on_return && (!out_epsilon_on_call || all_negative_or_dense)
616 {
617 outprops |= FstProperties::O_LABEL_SORTED;
618 }
619 outprops
620}
621
622pub fn reverse_properties(inprops: FstProperties, has_superinitial: bool) -> FstProperties {
623 let mut outprops = (FstProperties::ACCEPTOR
624 | FstProperties::NOT_ACCEPTOR
625 | FstProperties::EPSILONS
626 | FstProperties::I_EPSILONS
627 | FstProperties::O_EPSILONS
628 | FstProperties::UNWEIGHTED
629 | FstProperties::CYCLIC
630 | FstProperties::ACYCLIC
631 | FstProperties::WEIGHTED_CYCLES
632 | FstProperties::UNWEIGHTED_CYCLES)
633 & inprops;
634 if has_superinitial {
635 outprops |= FstProperties::WEIGHTED & inprops;
636 }
637 outprops
638}
639
640pub fn reweight_properties(inprops: FstProperties) -> FstProperties {
641 let mut outprops = inprops & FstProperties::weight_invariant_properties();
642 outprops &= !FstProperties::COACCESSIBLE;
643 outprops
644}
645
646pub fn rmepsilon_properties(inprops: FstProperties, delayed: bool) -> FstProperties {
647 let mut outprops = FstProperties::NO_EPSILONS;
648 outprops |= (FstProperties::ACCEPTOR | FstProperties::ACYCLIC | FstProperties::INITIAL_ACYCLIC)
649 & inprops;
650 if inprops.contains(FstProperties::ACCEPTOR) {
651 outprops |= FstProperties::NO_I_EPSILONS | FstProperties::NO_O_EPSILONS;
652 }
653 if !delayed {
654 outprops |= FstProperties::TOP_SORTED & inprops;
655 }
656 if !delayed || inprops.contains(FstProperties::ACCESSIBLE) {
657 outprops |= FstProperties::NOT_ACCEPTOR & inprops;
658 }
659 outprops
660}
661
662pub fn shortest_path_properties(props: FstProperties, tree: bool) -> FstProperties {
663 let mut outprops = props
664 | FstProperties::ACYCLIC
665 | FstProperties::INITIAL_ACYCLIC
666 | FstProperties::ACCESSIBLE
667 | FstProperties::UNWEIGHTED_CYCLES;
668 if !tree {
669 outprops |= FstProperties::COACCESSIBLE;
670 }
671 outprops
672}
673
674pub fn synchronization_properties(inprops: FstProperties) -> FstProperties {
675 let mut outprops = (FstProperties::ACCEPTOR
676 | FstProperties::ACYCLIC
677 | FstProperties::ACCESSIBLE
678 | FstProperties::COACCESSIBLE
679 | FstProperties::UNWEIGHTED
680 | FstProperties::UNWEIGHTED_CYCLES)
681 & inprops;
682 if inprops.contains(FstProperties::ACCESSIBLE) {
683 outprops |= (FstProperties::CYCLIC
684 | FstProperties::NOT_COACCESSIBLE
685 | FstProperties::WEIGHTED
686 | FstProperties::WEIGHTED_CYCLES)
687 & inprops;
688 }
689 outprops
690}
691
692pub fn union_properties(
693 inprops1: FstProperties,
694 inprops2: FstProperties,
695 delayed: bool,
696) -> FstProperties {
697 let mut outprops = (FstProperties::ACCEPTOR
698 | FstProperties::UNWEIGHTED
699 | FstProperties::UNWEIGHTED_CYCLES
700 | FstProperties::ACYCLIC
701 | FstProperties::ACCESSIBLE)
702 & inprops1
703 & inprops2;
704 outprops |= FstProperties::INITIAL_ACYCLIC;
705 let empty1 = delayed; let empty2 = delayed; if !delayed {
708 outprops |= FstProperties::NOT_TOP_SORTED & inprops1;
709 outprops |= FstProperties::NOT_TOP_SORTED & inprops2;
710 }
711 if !empty1 && !empty2 {
712 outprops |= FstProperties::EPSILONS | FstProperties::I_EPSILONS | FstProperties::O_EPSILONS;
713 outprops |= FstProperties::COACCESSIBLE & inprops1 & inprops2;
714 }
715 if !delayed || inprops1.contains(FstProperties::ACCESSIBLE) {
717 outprops |= (FstProperties::NOT_ACCEPTOR
718 | FstProperties::NOT_I_DETERMINISTIC
719 | FstProperties::NOT_O_DETERMINISTIC
720 | FstProperties::EPSILONS
721 | FstProperties::I_EPSILONS
722 | FstProperties::O_EPSILONS
723 | FstProperties::NOT_I_LABEL_SORTED
724 | FstProperties::NOT_O_LABEL_SORTED
725 | FstProperties::WEIGHTED
726 | FstProperties::WEIGHTED_CYCLES
727 | FstProperties::CYCLIC
728 | FstProperties::NOT_ACCESSIBLE)
729 & inprops1;
730 }
731 if !delayed || inprops2.contains(FstProperties::ACCESSIBLE) {
732 outprops |= (FstProperties::NOT_ACCEPTOR
733 | FstProperties::NOT_I_DETERMINISTIC
734 | FstProperties::NOT_O_DETERMINISTIC
735 | FstProperties::EPSILONS
736 | FstProperties::I_EPSILONS
737 | FstProperties::O_EPSILONS
738 | FstProperties::NOT_I_LABEL_SORTED
739 | FstProperties::NOT_O_LABEL_SORTED
740 | FstProperties::WEIGHTED
741 | FstProperties::WEIGHTED_CYCLES
742 | FstProperties::CYCLIC
743 | FstProperties::NOT_ACCESSIBLE
744 | FstProperties::NOT_COACCESSIBLE)
745 & inprops2;
746 }
747 outprops
748}