1pub mod ac_matching;
4pub mod advanced_analysis;
5pub mod advanced_rewriting;
6mod analysis;
7pub mod confluence;
8pub mod defuzzification;
9pub mod distributive_laws;
10mod domain_validation;
11pub mod ltl_ctl_utilities;
12pub mod modal_axioms;
13pub mod modal_equivalences;
14pub mod normal_forms;
15pub mod optimization;
16pub mod optimization_pipeline;
17pub mod probabilistic_reasoning;
18pub mod rewriting;
19pub mod strategy_selector;
20pub mod temporal_equivalences;
21mod validation;
22
23use serde::{Deserialize, Serialize};
24
25use crate::term::Term;
26
27#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
29pub enum AggregateOp {
30 Count,
32 Sum,
34 Average,
36 Max,
38 Min,
40 Product,
42 Any,
44 All,
46}
47
48#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
55pub enum TNormKind {
56 Minimum,
59
60 Product,
63
64 Lukasiewicz,
67
68 Drastic,
71
72 NilpotentMinimum,
74
75 Hamacher,
78}
79
80#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
83pub enum TCoNormKind {
84 Maximum,
87
88 ProbabilisticSum,
91
92 BoundedSum,
95
96 Drastic,
99
100 NilpotentMaximum,
103
104 Hamacher,
106}
107
108#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
110pub enum FuzzyNegationKind {
111 Standard,
113
114 Sugeno {
117 lambda: i32, },
120
121 Yager {
123 w: u32,
125 },
126}
127
128#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
130pub enum FuzzyImplicationKind {
131 Godel,
133
134 Lukasiewicz,
136
137 Reichenbach,
139
140 KleeneDienes,
142
143 Rescher,
145
146 Goguen,
148}
149
150#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
151pub enum TLExpr {
152 Pred {
153 name: String,
154 args: Vec<Term>,
155 },
156 And(Box<TLExpr>, Box<TLExpr>),
157 Or(Box<TLExpr>, Box<TLExpr>),
158 Not(Box<TLExpr>),
159 Exists {
160 var: String,
161 domain: String,
162 body: Box<TLExpr>,
163 },
164 ForAll {
165 var: String,
166 domain: String,
167 body: Box<TLExpr>,
168 },
169 Imply(Box<TLExpr>, Box<TLExpr>),
170 Score(Box<TLExpr>),
171
172 Add(Box<TLExpr>, Box<TLExpr>),
174 Sub(Box<TLExpr>, Box<TLExpr>),
175 Mul(Box<TLExpr>, Box<TLExpr>),
176 Div(Box<TLExpr>, Box<TLExpr>),
177 Pow(Box<TLExpr>, Box<TLExpr>),
178 Mod(Box<TLExpr>, Box<TLExpr>),
179 Min(Box<TLExpr>, Box<TLExpr>),
180 Max(Box<TLExpr>, Box<TLExpr>),
181
182 Abs(Box<TLExpr>),
184 Floor(Box<TLExpr>),
185 Ceil(Box<TLExpr>),
186 Round(Box<TLExpr>),
187 Sqrt(Box<TLExpr>),
188 Exp(Box<TLExpr>),
189 Log(Box<TLExpr>),
190 Sin(Box<TLExpr>),
191 Cos(Box<TLExpr>),
192 Tan(Box<TLExpr>),
193
194 Eq(Box<TLExpr>, Box<TLExpr>),
196 Lt(Box<TLExpr>, Box<TLExpr>),
197 Gt(Box<TLExpr>, Box<TLExpr>),
198 Lte(Box<TLExpr>, Box<TLExpr>),
199 Gte(Box<TLExpr>, Box<TLExpr>),
200
201 IfThenElse {
203 condition: Box<TLExpr>,
204 then_branch: Box<TLExpr>,
205 else_branch: Box<TLExpr>,
206 },
207
208 Constant(f64),
210
211 Aggregate {
213 op: AggregateOp,
214 var: String,
215 domain: String,
216 body: Box<TLExpr>,
217 group_by: Option<Vec<String>>,
219 },
220
221 Let {
223 var: String,
224 value: Box<TLExpr>,
225 body: Box<TLExpr>,
226 },
227
228 Box(Box<TLExpr>),
232
233 Diamond(Box<TLExpr>),
237
238 Next(Box<TLExpr>),
241
242 Eventually(Box<TLExpr>),
244
245 Always(Box<TLExpr>),
247
248 Until {
250 before: Box<TLExpr>,
251 after: Box<TLExpr>,
252 },
253
254 TNorm {
257 kind: TNormKind,
258 left: Box<TLExpr>,
259 right: Box<TLExpr>,
260 },
261
262 TCoNorm {
264 kind: TCoNormKind,
265 left: Box<TLExpr>,
266 right: Box<TLExpr>,
267 },
268
269 FuzzyNot {
271 kind: FuzzyNegationKind,
272 expr: Box<TLExpr>,
273 },
274
275 FuzzyImplication {
277 kind: FuzzyImplicationKind,
278 premise: Box<TLExpr>,
279 conclusion: Box<TLExpr>,
280 },
281
282 SoftExists {
288 var: String,
289 domain: String,
290 body: Box<TLExpr>,
291 temperature: f64,
293 },
294
295 SoftForAll {
300 var: String,
301 domain: String,
302 body: Box<TLExpr>,
303 temperature: f64,
305 },
306
307 WeightedRule {
310 weight: f64,
311 rule: Box<TLExpr>,
312 },
313
314 ProbabilisticChoice {
317 alternatives: Vec<(f64, TLExpr)>, },
319
320 Release {
324 released: Box<TLExpr>,
325 releaser: Box<TLExpr>,
326 },
327
328 WeakUntil {
330 before: Box<TLExpr>,
331 after: Box<TLExpr>,
332 },
333
334 StrongRelease {
336 released: Box<TLExpr>,
337 releaser: Box<TLExpr>,
338 },
339
340 Lambda {
346 var: String,
347 var_type: Option<String>,
349 body: Box<TLExpr>,
350 },
351
352 Apply {
354 function: Box<TLExpr>,
355 argument: Box<TLExpr>,
356 },
357
358 SetMembership {
361 element: Box<TLExpr>,
362 set: Box<TLExpr>,
363 },
364
365 SetUnion {
367 left: Box<TLExpr>,
368 right: Box<TLExpr>,
369 },
370
371 SetIntersection {
373 left: Box<TLExpr>,
374 right: Box<TLExpr>,
375 },
376
377 SetDifference {
379 left: Box<TLExpr>,
380 right: Box<TLExpr>,
381 },
382
383 SetCardinality {
385 set: Box<TLExpr>,
386 },
387
388 EmptySet,
390
391 SetComprehension {
393 var: String,
394 domain: String,
395 condition: Box<TLExpr>,
396 },
397
398 CountingExists {
402 var: String,
403 domain: String,
404 body: Box<TLExpr>,
405 min_count: usize,
407 },
408
409 CountingForAll {
412 var: String,
413 domain: String,
414 body: Box<TLExpr>,
415 min_count: usize,
417 },
418
419 ExactCount {
422 var: String,
423 domain: String,
424 body: Box<TLExpr>,
425 count: usize,
427 },
428
429 Majority {
432 var: String,
433 domain: String,
434 body: Box<TLExpr>,
435 },
436
437 LeastFixpoint {
441 var: String,
443 body: Box<TLExpr>,
445 },
446
447 GreatestFixpoint {
450 var: String,
452 body: Box<TLExpr>,
454 },
455
456 Nominal {
460 name: String,
461 },
462
463 At {
466 nominal: String,
467 formula: Box<TLExpr>,
468 },
469
470 Somewhere {
473 formula: Box<TLExpr>,
474 },
475
476 Everywhere {
479 formula: Box<TLExpr>,
480 },
481
482 AllDifferent {
485 variables: Vec<String>,
486 },
487
488 GlobalCardinality {
491 variables: Vec<String>,
492 values: Vec<TLExpr>,
493 min_occurrences: Vec<usize>,
494 max_occurrences: Vec<usize>,
495 },
496
497 Abducible {
500 name: String,
501 cost: f64, },
503
504 Explain {
506 formula: Box<TLExpr>,
507 },
508}
509
510impl TLExpr {
511 pub fn pred(name: impl Into<String>, args: Vec<Term>) -> Self {
512 TLExpr::Pred {
513 name: name.into(),
514 args,
515 }
516 }
517
518 pub fn and(left: TLExpr, right: TLExpr) -> Self {
519 TLExpr::And(Box::new(left), Box::new(right))
520 }
521
522 pub fn or(left: TLExpr, right: TLExpr) -> Self {
523 TLExpr::Or(Box::new(left), Box::new(right))
524 }
525
526 pub fn negate(expr: TLExpr) -> Self {
527 TLExpr::Not(Box::new(expr))
528 }
529
530 pub fn exists(var: impl Into<String>, domain: impl Into<String>, body: TLExpr) -> Self {
531 TLExpr::Exists {
532 var: var.into(),
533 domain: domain.into(),
534 body: Box::new(body),
535 }
536 }
537
538 pub fn forall(var: impl Into<String>, domain: impl Into<String>, body: TLExpr) -> Self {
539 TLExpr::ForAll {
540 var: var.into(),
541 domain: domain.into(),
542 body: Box::new(body),
543 }
544 }
545
546 pub fn imply(premise: TLExpr, conclusion: TLExpr) -> Self {
547 TLExpr::Imply(Box::new(premise), Box::new(conclusion))
548 }
549
550 pub fn score(expr: TLExpr) -> Self {
551 TLExpr::Score(Box::new(expr))
552 }
553
554 #[allow(clippy::should_implement_trait)]
556 pub fn add(left: TLExpr, right: TLExpr) -> Self {
557 TLExpr::Add(Box::new(left), Box::new(right))
558 }
559
560 #[allow(clippy::should_implement_trait)]
561 pub fn sub(left: TLExpr, right: TLExpr) -> Self {
562 TLExpr::Sub(Box::new(left), Box::new(right))
563 }
564
565 #[allow(clippy::should_implement_trait)]
566 pub fn mul(left: TLExpr, right: TLExpr) -> Self {
567 TLExpr::Mul(Box::new(left), Box::new(right))
568 }
569
570 #[allow(clippy::should_implement_trait)]
571 pub fn div(left: TLExpr, right: TLExpr) -> Self {
572 TLExpr::Div(Box::new(left), Box::new(right))
573 }
574
575 pub fn pow(left: TLExpr, right: TLExpr) -> Self {
576 TLExpr::Pow(Box::new(left), Box::new(right))
577 }
578
579 pub fn modulo(left: TLExpr, right: TLExpr) -> Self {
580 TLExpr::Mod(Box::new(left), Box::new(right))
581 }
582
583 pub fn min(left: TLExpr, right: TLExpr) -> Self {
584 TLExpr::Min(Box::new(left), Box::new(right))
585 }
586
587 pub fn max(left: TLExpr, right: TLExpr) -> Self {
588 TLExpr::Max(Box::new(left), Box::new(right))
589 }
590
591 pub fn abs(expr: TLExpr) -> Self {
593 TLExpr::Abs(Box::new(expr))
594 }
595
596 pub fn floor(expr: TLExpr) -> Self {
597 TLExpr::Floor(Box::new(expr))
598 }
599
600 pub fn ceil(expr: TLExpr) -> Self {
601 TLExpr::Ceil(Box::new(expr))
602 }
603
604 pub fn round(expr: TLExpr) -> Self {
605 TLExpr::Round(Box::new(expr))
606 }
607
608 pub fn sqrt(expr: TLExpr) -> Self {
609 TLExpr::Sqrt(Box::new(expr))
610 }
611
612 pub fn exp(expr: TLExpr) -> Self {
613 TLExpr::Exp(Box::new(expr))
614 }
615
616 pub fn log(expr: TLExpr) -> Self {
617 TLExpr::Log(Box::new(expr))
618 }
619
620 pub fn sin(expr: TLExpr) -> Self {
621 TLExpr::Sin(Box::new(expr))
622 }
623
624 pub fn cos(expr: TLExpr) -> Self {
625 TLExpr::Cos(Box::new(expr))
626 }
627
628 pub fn tan(expr: TLExpr) -> Self {
629 TLExpr::Tan(Box::new(expr))
630 }
631
632 pub fn eq(left: TLExpr, right: TLExpr) -> Self {
634 TLExpr::Eq(Box::new(left), Box::new(right))
635 }
636
637 pub fn lt(left: TLExpr, right: TLExpr) -> Self {
638 TLExpr::Lt(Box::new(left), Box::new(right))
639 }
640
641 pub fn gt(left: TLExpr, right: TLExpr) -> Self {
642 TLExpr::Gt(Box::new(left), Box::new(right))
643 }
644
645 pub fn lte(left: TLExpr, right: TLExpr) -> Self {
646 TLExpr::Lte(Box::new(left), Box::new(right))
647 }
648
649 pub fn gte(left: TLExpr, right: TLExpr) -> Self {
650 TLExpr::Gte(Box::new(left), Box::new(right))
651 }
652
653 pub fn if_then_else(condition: TLExpr, then_branch: TLExpr, else_branch: TLExpr) -> Self {
655 TLExpr::IfThenElse {
656 condition: Box::new(condition),
657 then_branch: Box::new(then_branch),
658 else_branch: Box::new(else_branch),
659 }
660 }
661
662 pub fn constant(value: f64) -> Self {
664 TLExpr::Constant(value)
665 }
666
667 pub fn aggregate(
669 op: AggregateOp,
670 var: impl Into<String>,
671 domain: impl Into<String>,
672 body: TLExpr,
673 ) -> Self {
674 TLExpr::Aggregate {
675 op,
676 var: var.into(),
677 domain: domain.into(),
678 body: Box::new(body),
679 group_by: None,
680 }
681 }
682
683 pub fn aggregate_with_group_by(
684 op: AggregateOp,
685 var: impl Into<String>,
686 domain: impl Into<String>,
687 body: TLExpr,
688 group_by: Vec<String>,
689 ) -> Self {
690 TLExpr::Aggregate {
691 op,
692 var: var.into(),
693 domain: domain.into(),
694 body: Box::new(body),
695 group_by: Some(group_by),
696 }
697 }
698
699 pub fn count(var: impl Into<String>, domain: impl Into<String>, body: TLExpr) -> Self {
700 Self::aggregate(AggregateOp::Count, var, domain, body)
701 }
702
703 pub fn sum(var: impl Into<String>, domain: impl Into<String>, body: TLExpr) -> Self {
704 Self::aggregate(AggregateOp::Sum, var, domain, body)
705 }
706
707 pub fn average(var: impl Into<String>, domain: impl Into<String>, body: TLExpr) -> Self {
708 Self::aggregate(AggregateOp::Average, var, domain, body)
709 }
710
711 pub fn max_agg(var: impl Into<String>, domain: impl Into<String>, body: TLExpr) -> Self {
712 Self::aggregate(AggregateOp::Max, var, domain, body)
713 }
714
715 pub fn min_agg(var: impl Into<String>, domain: impl Into<String>, body: TLExpr) -> Self {
716 Self::aggregate(AggregateOp::Min, var, domain, body)
717 }
718
719 pub fn product(var: impl Into<String>, domain: impl Into<String>, body: TLExpr) -> Self {
720 Self::aggregate(AggregateOp::Product, var, domain, body)
721 }
722
723 pub fn let_binding(var: impl Into<String>, value: TLExpr, body: TLExpr) -> Self {
725 TLExpr::Let {
726 var: var.into(),
727 value: Box::new(value),
728 body: Box::new(body),
729 }
730 }
731
732 pub fn modal_box(expr: TLExpr) -> Self {
737 TLExpr::Box(Box::new(expr))
738 }
739
740 pub fn modal_diamond(expr: TLExpr) -> Self {
744 TLExpr::Diamond(Box::new(expr))
745 }
746
747 pub fn next(expr: TLExpr) -> Self {
752 TLExpr::Next(Box::new(expr))
753 }
754
755 pub fn eventually(expr: TLExpr) -> Self {
759 TLExpr::Eventually(Box::new(expr))
760 }
761
762 pub fn always(expr: TLExpr) -> Self {
766 TLExpr::Always(Box::new(expr))
767 }
768
769 pub fn until(before: TLExpr, after: TLExpr) -> Self {
773 TLExpr::Until {
774 before: Box::new(before),
775 after: Box::new(after),
776 }
777 }
778
779 pub fn tnorm(kind: TNormKind, left: TLExpr, right: TLExpr) -> Self {
783 TLExpr::TNorm {
784 kind,
785 left: Box::new(left),
786 right: Box::new(right),
787 }
788 }
789
790 pub fn fuzzy_and(left: TLExpr, right: TLExpr) -> Self {
792 Self::tnorm(TNormKind::Minimum, left, right)
793 }
794
795 pub fn probabilistic_and(left: TLExpr, right: TLExpr) -> Self {
797 Self::tnorm(TNormKind::Product, left, right)
798 }
799
800 pub fn tconorm(kind: TCoNormKind, left: TLExpr, right: TLExpr) -> Self {
802 TLExpr::TCoNorm {
803 kind,
804 left: Box::new(left),
805 right: Box::new(right),
806 }
807 }
808
809 pub fn fuzzy_or(left: TLExpr, right: TLExpr) -> Self {
811 Self::tconorm(TCoNormKind::Maximum, left, right)
812 }
813
814 pub fn probabilistic_or(left: TLExpr, right: TLExpr) -> Self {
816 Self::tconorm(TCoNormKind::ProbabilisticSum, left, right)
817 }
818
819 pub fn fuzzy_not(kind: FuzzyNegationKind, expr: TLExpr) -> Self {
821 TLExpr::FuzzyNot {
822 kind,
823 expr: Box::new(expr),
824 }
825 }
826
827 pub fn standard_fuzzy_not(expr: TLExpr) -> Self {
829 Self::fuzzy_not(FuzzyNegationKind::Standard, expr)
830 }
831
832 pub fn fuzzy_imply(kind: FuzzyImplicationKind, premise: TLExpr, conclusion: TLExpr) -> Self {
834 TLExpr::FuzzyImplication {
835 kind,
836 premise: Box::new(premise),
837 conclusion: Box::new(conclusion),
838 }
839 }
840
841 pub fn soft_exists(
851 var: impl Into<String>,
852 domain: impl Into<String>,
853 body: TLExpr,
854 temperature: f64,
855 ) -> Self {
856 TLExpr::SoftExists {
857 var: var.into(),
858 domain: domain.into(),
859 body: Box::new(body),
860 temperature,
861 }
862 }
863
864 pub fn soft_forall(
872 var: impl Into<String>,
873 domain: impl Into<String>,
874 body: TLExpr,
875 temperature: f64,
876 ) -> Self {
877 TLExpr::SoftForAll {
878 var: var.into(),
879 domain: domain.into(),
880 body: Box::new(body),
881 temperature,
882 }
883 }
884
885 pub fn weighted_rule(weight: f64, rule: TLExpr) -> Self {
891 TLExpr::WeightedRule {
892 weight,
893 rule: Box::new(rule),
894 }
895 }
896
897 pub fn probabilistic_choice(alternatives: Vec<(f64, TLExpr)>) -> Self {
902 TLExpr::ProbabilisticChoice { alternatives }
903 }
904
905 pub fn release(released: TLExpr, releaser: TLExpr) -> Self {
911 TLExpr::Release {
912 released: Box::new(released),
913 releaser: Box::new(releaser),
914 }
915 }
916
917 pub fn weak_until(before: TLExpr, after: TLExpr) -> Self {
921 TLExpr::WeakUntil {
922 before: Box::new(before),
923 after: Box::new(after),
924 }
925 }
926
927 pub fn strong_release(released: TLExpr, releaser: TLExpr) -> Self {
931 TLExpr::StrongRelease {
932 released: Box::new(released),
933 releaser: Box::new(releaser),
934 }
935 }
936
937 pub fn lambda(var: impl Into<String>, var_type: Option<String>, body: TLExpr) -> Self {
948 TLExpr::Lambda {
949 var: var.into(),
950 var_type,
951 body: Box::new(body),
952 }
953 }
954
955 pub fn lambda_untyped(var: impl Into<String>, body: TLExpr) -> Self {
957 Self::lambda(var, None, body)
958 }
959
960 pub fn apply(function: TLExpr, argument: TLExpr) -> Self {
966 TLExpr::Apply {
967 function: Box::new(function),
968 argument: Box::new(argument),
969 }
970 }
971
972 pub fn set_membership(element: TLExpr, set: TLExpr) -> Self {
976 TLExpr::SetMembership {
977 element: Box::new(element),
978 set: Box::new(set),
979 }
980 }
981
982 pub fn set_union(left: TLExpr, right: TLExpr) -> Self {
984 TLExpr::SetUnion {
985 left: Box::new(left),
986 right: Box::new(right),
987 }
988 }
989
990 pub fn set_intersection(left: TLExpr, right: TLExpr) -> Self {
992 TLExpr::SetIntersection {
993 left: Box::new(left),
994 right: Box::new(right),
995 }
996 }
997
998 pub fn set_difference(left: TLExpr, right: TLExpr) -> Self {
1000 TLExpr::SetDifference {
1001 left: Box::new(left),
1002 right: Box::new(right),
1003 }
1004 }
1005
1006 pub fn set_cardinality(set: TLExpr) -> Self {
1008 TLExpr::SetCardinality { set: Box::new(set) }
1009 }
1010
1011 pub fn empty_set() -> Self {
1013 TLExpr::EmptySet
1014 }
1015
1016 pub fn set_comprehension(
1018 var: impl Into<String>,
1019 domain: impl Into<String>,
1020 condition: TLExpr,
1021 ) -> Self {
1022 TLExpr::SetComprehension {
1023 var: var.into(),
1024 domain: domain.into(),
1025 condition: Box::new(condition),
1026 }
1027 }
1028
1029 pub fn counting_exists(
1035 var: impl Into<String>,
1036 domain: impl Into<String>,
1037 body: TLExpr,
1038 min_count: usize,
1039 ) -> Self {
1040 TLExpr::CountingExists {
1041 var: var.into(),
1042 domain: domain.into(),
1043 body: Box::new(body),
1044 min_count,
1045 }
1046 }
1047
1048 pub fn counting_forall(
1052 var: impl Into<String>,
1053 domain: impl Into<String>,
1054 body: TLExpr,
1055 min_count: usize,
1056 ) -> Self {
1057 TLExpr::CountingForAll {
1058 var: var.into(),
1059 domain: domain.into(),
1060 body: Box::new(body),
1061 min_count,
1062 }
1063 }
1064
1065 pub fn exact_count(
1069 var: impl Into<String>,
1070 domain: impl Into<String>,
1071 body: TLExpr,
1072 count: usize,
1073 ) -> Self {
1074 TLExpr::ExactCount {
1075 var: var.into(),
1076 domain: domain.into(),
1077 body: Box::new(body),
1078 count,
1079 }
1080 }
1081
1082 pub fn majority(var: impl Into<String>, domain: impl Into<String>, body: TLExpr) -> Self {
1086 TLExpr::Majority {
1087 var: var.into(),
1088 domain: domain.into(),
1089 body: Box::new(body),
1090 }
1091 }
1092
1093 pub fn least_fixpoint(var: impl Into<String>, body: TLExpr) -> Self {
1099 TLExpr::LeastFixpoint {
1100 var: var.into(),
1101 body: Box::new(body),
1102 }
1103 }
1104
1105 pub fn greatest_fixpoint(var: impl Into<String>, body: TLExpr) -> Self {
1109 TLExpr::GreatestFixpoint {
1110 var: var.into(),
1111 body: Box::new(body),
1112 }
1113 }
1114
1115 pub fn nominal(name: impl Into<String>) -> Self {
1119 TLExpr::Nominal { name: name.into() }
1120 }
1121
1122 pub fn at(nominal: impl Into<String>, formula: TLExpr) -> Self {
1126 TLExpr::At {
1127 nominal: nominal.into(),
1128 formula: Box::new(formula),
1129 }
1130 }
1131
1132 pub fn somewhere(formula: TLExpr) -> Self {
1136 TLExpr::Somewhere {
1137 formula: Box::new(formula),
1138 }
1139 }
1140
1141 pub fn everywhere(formula: TLExpr) -> Self {
1145 TLExpr::Everywhere {
1146 formula: Box::new(formula),
1147 }
1148 }
1149
1150 pub fn all_different(variables: Vec<String>) -> Self {
1156 TLExpr::AllDifferent { variables }
1157 }
1158
1159 pub fn global_cardinality(
1163 variables: Vec<String>,
1164 values: Vec<TLExpr>,
1165 min_occurrences: Vec<usize>,
1166 max_occurrences: Vec<usize>,
1167 ) -> Self {
1168 TLExpr::GlobalCardinality {
1169 variables,
1170 values,
1171 min_occurrences,
1172 max_occurrences,
1173 }
1174 }
1175
1176 pub fn abducible(name: impl Into<String>, cost: f64) -> Self {
1182 TLExpr::Abducible {
1183 name: name.into(),
1184 cost,
1185 }
1186 }
1187
1188 pub fn explain(formula: TLExpr) -> Self {
1190 TLExpr::Explain {
1191 formula: Box::new(formula),
1192 }
1193 }
1194
1195 pub fn substitute(&self, var: &str, value: &TLExpr) -> Self {
1220 optimization::substitution::substitute(self, var, value)
1221 }
1222}