1use core::fmt;
5use std::{collections::HashMap, error, ops};
6
7use crate::expressions::{IntegerExpression, Location, Variable};
8
9use super::{Atomic, ComparisonOp, Parameter};
10use super::{BooleanConnective, BooleanExpression, IntegerOp};
11
12impl<T: Atomic> IntegerExpression<T> {
13 pub fn is_atomic(&self) -> bool {
30 match self {
31 IntegerExpression::Param(_) => true,
32 IntegerExpression::Atom(_) => true,
33 IntegerExpression::Const(_) => false,
34 IntegerExpression::BinaryExpr(_, _, _) => false,
35 IntegerExpression::Neg(_) => false,
36 }
37 }
38
39 pub fn contains_atom(&self) -> bool {
57 match self {
58 IntegerExpression::Atom(_) => true,
59 IntegerExpression::Const(_) => false,
60 IntegerExpression::Param(_) => false,
61 IntegerExpression::Neg(ex) => ex.contains_atom(),
62 IntegerExpression::BinaryExpr(lhs, _, rhs) => {
63 lhs.contains_atom() || rhs.contains_atom()
64 }
65 }
66 }
67
68 pub fn contains_atom_a(&self, a: &T) -> bool {
88 match self {
89 IntegerExpression::Atom(at) => at == a,
90 IntegerExpression::Const(_) => false,
91 IntegerExpression::Param(_) => false,
92 IntegerExpression::Neg(ex) => ex.contains_atom_a(a),
93 IntegerExpression::BinaryExpr(lhs, _, rhs) => {
94 lhs.contains_atom_a(a) || rhs.contains_atom_a(a)
95 }
96 }
97 }
98
99 pub fn try_to_evaluate_to_const(&self) -> Option<i64> {
124 self.try_to_evaluate_to_const_with_env(
125 &HashMap::<T, u32>::new(),
126 &HashMap::<Parameter, u32>::new(),
127 )
128 .ok()
129 }
130
131 pub fn try_to_evaluate_to_const_with_env(
166 &self,
167 env: &HashMap<T, u32>,
168 param_env: &HashMap<Parameter, u32>,
169 ) -> Result<i64, EvaluationError<T>> {
170 match self {
171 IntegerExpression::Const(c) => Ok(*c as i64),
172 IntegerExpression::Param(p) => {
173 if param_env.contains_key(p) {
174 Ok(*param_env.get(p).unwrap() as i64)
175 } else {
176 Err(EvaluationError::ParameterNotFound(p.clone()))
177 }
178 }
179 IntegerExpression::Atom(a) => {
180 if env.contains_key(a) {
181 Ok(*env.get(a).unwrap() as i64)
182 } else {
183 Err(EvaluationError::AtomicNotFound(a.clone()))
184 }
185 }
186 IntegerExpression::BinaryExpr(lhs, op, rhs) => {
187 let lhs = lhs.try_to_evaluate_to_const_with_env(env, param_env)?;
188 let rhs = rhs.try_to_evaluate_to_const_with_env(env, param_env)?;
189 match op {
190 IntegerOp::Add => Ok(lhs + rhs),
191 IntegerOp::Sub => Ok(lhs - rhs),
192 IntegerOp::Mul => Ok(lhs * rhs),
193 IntegerOp::Div => Ok(lhs / rhs),
194 }
195 }
196 IntegerExpression::Neg(ex) => ex
197 .try_to_evaluate_to_const_with_env(env, param_env)
198 .map(|c| -c),
199 }
200 }
201
202 pub fn substitute_atom_with(&mut self, to_replace: &T, replace_with: &Self) {
219 match self {
220 IntegerExpression::Atom(a) => {
221 if *a == *to_replace {
222 *self = replace_with.clone();
223 }
224 }
225
226 IntegerExpression::BinaryExpr(lhs, _, rhs) => {
227 lhs.substitute_atom_with(to_replace, replace_with);
228 rhs.substitute_atom_with(to_replace, replace_with);
229 }
230 IntegerExpression::Neg(e) => e.substitute_atom_with(to_replace, replace_with),
231
232 IntegerExpression::Const(_) | IntegerExpression::Param(_) => (),
233 }
234 }
235
236 pub fn contains_parameter(&self) -> bool {
262 match self {
263 IntegerExpression::Atom(_) | IntegerExpression::Const(_) => false,
264 IntegerExpression::Param(_) => true,
265 IntegerExpression::BinaryExpr(lhs, _op, rhs) => {
266 lhs.contains_parameter() || rhs.contains_parameter()
267 }
268 IntegerExpression::Neg(expr) => expr.contains_parameter(),
269 }
270 }
271}
272
273impl From<IntegerExpression<Parameter>> for IntegerExpression<Location> {
274 fn from(value: IntegerExpression<Parameter>) -> Self {
275 match value {
276 IntegerExpression::Param(p) | IntegerExpression::Atom(p) => IntegerExpression::Param(p),
277 IntegerExpression::Const(c) => IntegerExpression::Const(c),
278 IntegerExpression::BinaryExpr(lhs, op, rhs) => {
279 let lhs = Box::new((*lhs).into());
280 let rhs = Box::new((*rhs).into());
281
282 IntegerExpression::BinaryExpr(lhs, op, rhs)
283 }
284 IntegerExpression::Neg(integer_expression) => {
285 IntegerExpression::Neg(Box::new((*integer_expression).into()))
286 }
287 }
288 }
289}
290
291impl From<IntegerExpression<Parameter>> for IntegerExpression<Variable> {
292 fn from(value: IntegerExpression<Parameter>) -> Self {
293 match value {
294 IntegerExpression::Param(p) | IntegerExpression::Atom(p) => IntegerExpression::Param(p),
295 IntegerExpression::Const(c) => IntegerExpression::Const(c),
296 IntegerExpression::BinaryExpr(lhs, op, rhs) => {
297 let lhs = Box::new((*lhs).into());
298 let rhs = Box::new((*rhs).into());
299
300 IntegerExpression::BinaryExpr(lhs, op, rhs)
301 }
302 IntegerExpression::Neg(integer_expression) => {
303 IntegerExpression::Neg(Box::new((*integer_expression).into()))
304 }
305 }
306 }
307}
308
309#[derive(Debug, Clone, PartialEq)]
314pub enum EvaluationError<T: fmt::Display + PartialEq + fmt::Debug> {
315 AtomicNotFound(T),
317 ParameterNotFound(Parameter),
319}
320
321impl<T: fmt::Display + PartialEq + fmt::Debug> error::Error for EvaluationError<T> {}
322
323impl<T: fmt::Display + PartialEq + fmt::Debug> fmt::Display for EvaluationError<T> {
324 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
325 match self {
326 EvaluationError::AtomicNotFound(t) => {
327 write!(f, "Atomic {t} not found in environment")
328 }
329 EvaluationError::ParameterNotFound(p) => {
330 write!(f, "Parameter {p} not found in environment")
331 }
332 }
333 }
334}
335
336impl<T: Atomic> BooleanExpression<T> {
337 pub fn check_satisfied(
381 &self,
382 env: &HashMap<T, u32>,
383 param_env: &HashMap<Parameter, u32>,
384 ) -> Result<bool, EvaluationError<T>> {
385 match self {
386 BooleanExpression::ComparisonExpression(rhs, op, lhs) => {
387 let rhs = rhs
388 .as_ref()
389 .try_to_evaluate_to_const_with_env(env, param_env)?;
390 let lhs = lhs
391 .as_ref()
392 .try_to_evaluate_to_const_with_env(env, param_env)?;
393 match op {
394 ComparisonOp::Eq => Ok(rhs == lhs),
395 ComparisonOp::Neq => Ok(rhs != lhs),
396 ComparisonOp::Lt => Ok(rhs < lhs),
397 ComparisonOp::Leq => Ok(rhs <= lhs),
398 ComparisonOp::Gt => Ok(rhs > lhs),
399 ComparisonOp::Geq => Ok(rhs >= lhs),
400 }
401 }
402 BooleanExpression::BinaryExpression(rhs, op, lhs) => {
403 let rhs = rhs.check_satisfied(env, param_env)?;
404 let lhs = lhs.check_satisfied(env, param_env)?;
405 match op {
406 BooleanConnective::And => Ok(rhs && lhs),
407 BooleanConnective::Or => Ok(rhs || lhs),
408 }
409 }
410 BooleanExpression::Not(expr) => Ok(!expr.check_satisfied(env, param_env)?),
411 BooleanExpression::True => Ok(true),
412 BooleanExpression::False => Ok(false),
413 }
414 }
415
416 pub fn contains_atom_a(&self, a: &T) -> bool {
432 match self {
433 BooleanExpression::ComparisonExpression(lhs, _, rhs) => {
434 lhs.contains_atom_a(a) || rhs.contains_atom_a(a)
435 }
436 BooleanExpression::BinaryExpression(lhs, _, rhs) => {
437 lhs.contains_atom_a(a) || rhs.contains_atom_a(a)
438 }
439 BooleanExpression::Not(expr) => expr.contains_atom_a(a),
440 BooleanExpression::True => false,
441 BooleanExpression::False => false,
442 }
443 }
444
445 pub fn substitute_atom_with(&mut self, to_replace: &T, replace_with: &IntegerExpression<T>) {
468 match self {
469 BooleanExpression::ComparisonExpression(lhs, _, rhs) => {
470 lhs.substitute_atom_with(to_replace, replace_with);
471 rhs.substitute_atom_with(to_replace, replace_with);
472 }
473 BooleanExpression::BinaryExpression(lhs, _, rhs) => {
474 lhs.substitute_atom_with(to_replace, replace_with);
475 rhs.substitute_atom_with(to_replace, replace_with);
476 }
477 BooleanExpression::Not(expr) => expr.substitute_atom_with(to_replace, replace_with),
478 BooleanExpression::True | BooleanExpression::False => (),
479 }
480 }
481
482 pub fn try_check_expr_constraints_to_zero(&self, atom: &T) -> bool {
532 match self {
533 BooleanExpression::ComparisonExpression(lhs, op, rhs) => {
534 let mut atom_expr = lhs;
535 let mut const_expr = rhs;
536 let mut op = *op;
537
538 if matches!(rhs.as_ref(), IntegerExpression::Atom(_)) {
539 atom_expr = rhs;
540 const_expr = lhs;
541 op = op.get_swap_side();
542 }
543
544 if let (IntegerExpression::Atom(a), Some(c)) =
545 (atom_expr.as_ref(), const_expr.try_to_evaluate_to_const())
546 && a == atom
547 {
548 return match op {
549 ComparisonOp::Eq | ComparisonOp::Leq => c == 0,
550 ComparisonOp::Lt => c == 1,
551 _ => false,
552 };
553 }
554
555 false
556 }
557 BooleanExpression::BinaryExpression(rhs, BooleanConnective::And, lhs) => {
558 lhs.try_check_expr_constraints_to_zero(atom)
559 || rhs.try_check_expr_constraints_to_zero(atom)
560 }
561 BooleanExpression::BinaryExpression(rhs, BooleanConnective::Or, lhs) => {
562 lhs.try_check_expr_constraints_to_zero(atom)
563 && rhs.try_check_expr_constraints_to_zero(atom)
564 }
565 BooleanExpression::Not(_) | BooleanExpression::True | BooleanExpression::False => false,
566 }
567 }
568}
569
570impl<T> From<Parameter> for IntegerExpression<T>
571where
572 T: Atomic,
573{
574 fn from(value: Parameter) -> Self {
575 IntegerExpression::Param(value)
576 }
577}
578
579impl From<Variable> for IntegerExpression<Variable> {
580 fn from(value: Variable) -> Self {
581 IntegerExpression::Atom(value)
582 }
583}
584
585impl From<Location> for IntegerExpression<Location> {
586 fn from(value: Location) -> Self {
587 IntegerExpression::Atom(value)
588 }
589}
590
591impl<S> From<u32> for IntegerExpression<S>
592where
593 S: Atomic,
594{
595 fn from(value: u32) -> Self {
596 IntegerExpression::Const(value)
597 }
598}
599
600impl From<BooleanExpression<Parameter>> for BooleanExpression<Location> {
601 fn from(value: BooleanExpression<Parameter>) -> Self {
602 match value {
603 BooleanExpression::ComparisonExpression(lhs, op, rhs) => {
604 let lhs = Box::new((*lhs).into());
605 let rhs = Box::new((*rhs).into());
606 BooleanExpression::ComparisonExpression(lhs, op, rhs)
607 }
608 BooleanExpression::BinaryExpression(lhs, conn, rhs) => {
609 let lhs = Box::new((*lhs).into());
610 let rhs = Box::new((*rhs).into());
611 BooleanExpression::BinaryExpression(lhs, conn, rhs)
612 }
613 BooleanExpression::Not(expr) => BooleanExpression::Not(Box::new((*expr).into())),
614 BooleanExpression::True => BooleanExpression::True,
615 BooleanExpression::False => BooleanExpression::False,
616 }
617 }
618}
619
620impl From<BooleanExpression<Parameter>> for BooleanExpression<Variable> {
621 fn from(value: BooleanExpression<Parameter>) -> Self {
622 match value {
623 BooleanExpression::ComparisonExpression(lhs, op, rhs) => {
624 let lhs = Box::new((*lhs).into());
625 let rhs = Box::new((*rhs).into());
626 BooleanExpression::ComparisonExpression(lhs, op, rhs)
627 }
628 BooleanExpression::BinaryExpression(lhs, conn, rhs) => {
629 let lhs = Box::new((*lhs).into());
630 let rhs = Box::new((*rhs).into());
631 BooleanExpression::BinaryExpression(lhs, conn, rhs)
632 }
633 BooleanExpression::Not(expr) => BooleanExpression::Not(Box::new((*expr).into())),
634 BooleanExpression::True => BooleanExpression::True,
635 BooleanExpression::False => BooleanExpression::False,
636 }
637 }
638}
639
640impl<T> ops::Add for IntegerExpression<T>
643where
644 T: Atomic,
645{
646 type Output = IntegerExpression<T>;
647
648 fn add(self, other: IntegerExpression<T>) -> IntegerExpression<T> {
649 IntegerExpression::BinaryExpr(Box::new(self), IntegerOp::Add, Box::new(other))
650 }
651}
652
653impl<T> ops::Sub for IntegerExpression<T>
654where
655 T: Atomic,
656{
657 type Output = IntegerExpression<T>;
658
659 fn sub(self, other: IntegerExpression<T>) -> IntegerExpression<T> {
660 IntegerExpression::BinaryExpr(Box::new(self), IntegerOp::Sub, Box::new(other))
661 }
662}
663
664impl<T> ops::Mul for IntegerExpression<T>
665where
666 T: Atomic,
667{
668 type Output = IntegerExpression<T>;
669
670 fn mul(self, other: IntegerExpression<T>) -> IntegerExpression<T> {
671 IntegerExpression::BinaryExpr(Box::new(self), IntegerOp::Mul, Box::new(other))
672 }
673}
674
675impl<T> ops::Div for IntegerExpression<T>
676where
677 T: Atomic,
678{
679 type Output = IntegerExpression<T>;
680
681 fn div(self, other: IntegerExpression<T>) -> IntegerExpression<T> {
682 IntegerExpression::BinaryExpr(Box::new(self), IntegerOp::Div, Box::new(other))
683 }
684}
685
686impl<T> ops::Neg for IntegerExpression<T>
687where
688 T: Atomic,
689{
690 type Output = IntegerExpression<T>;
691
692 fn neg(self) -> IntegerExpression<T> {
693 IntegerExpression::Neg(Box::new(self))
694 }
695}
696
697impl<T> ops::Not for BooleanExpression<T>
698where
699 T: Atomic,
700{
701 type Output = BooleanExpression<T>;
702
703 fn not(self) -> BooleanExpression<T> {
704 BooleanExpression::Not(Box::new(self))
705 }
706}
707
708impl<T> ops::BitAnd for BooleanExpression<T>
709where
710 T: Atomic,
711{
712 type Output = BooleanExpression<T>;
713
714 fn bitand(self, other: BooleanExpression<T>) -> BooleanExpression<T> {
716 BooleanExpression::BinaryExpression(
717 Box::new(self),
718 super::BooleanConnective::And,
719 Box::new(other),
720 )
721 }
722}
723
724impl<T> ops::BitOr for BooleanExpression<T>
725where
726 T: Atomic,
727{
728 type Output = BooleanExpression<T>;
729
730 fn bitor(self, other: BooleanExpression<T>) -> BooleanExpression<T> {
732 BooleanExpression::BinaryExpression(
733 Box::new(self),
734 super::BooleanConnective::Or,
735 Box::new(other),
736 )
737 }
738}
739
740impl ComparisonOp {
741 pub fn invert(self) -> Self {
755 match self {
756 ComparisonOp::Eq => ComparisonOp::Neq,
757 ComparisonOp::Neq => ComparisonOp::Eq,
758 ComparisonOp::Lt => ComparisonOp::Geq,
759 ComparisonOp::Leq => ComparisonOp::Gt,
760 ComparisonOp::Gt => ComparisonOp::Leq,
761 ComparisonOp::Geq => ComparisonOp::Lt,
762 }
763 }
764
765 pub fn get_swap_side(self) -> Self {
778 match self {
779 ComparisonOp::Gt => ComparisonOp::Lt,
780 ComparisonOp::Geq => ComparisonOp::Leq,
781 ComparisonOp::Eq => ComparisonOp::Eq,
782 ComparisonOp::Neq => ComparisonOp::Neq,
783 ComparisonOp::Leq => ComparisonOp::Geq,
784 ComparisonOp::Lt => ComparisonOp::Gt,
785 }
786 }
787}
788
789impl BooleanConnective {
790 pub fn invert(self) -> Self {
801 match self {
802 BooleanConnective::And => BooleanConnective::Or,
803 BooleanConnective::Or => BooleanConnective::And,
804 }
805 }
806}
807
808#[cfg(test)]
809mod tests {
810 use std::collections::HashMap;
811
812 use crate::expressions::{
813 BooleanConnective, BooleanExpression, ComparisonOp, IntegerExpression, IntegerOp, Location,
814 Parameter, Variable, properties::EvaluationError,
815 };
816
817 #[test]
818 fn test_is_atomic() {
819 let expr: IntegerExpression<Variable> = IntegerExpression::Param(Parameter::new("x"));
820 assert!(expr.is_atomic());
821
822 let expr: IntegerExpression<Variable> = IntegerExpression::Atom(Variable::new("x"));
823 assert!(expr.is_atomic());
824
825 let expr: IntegerExpression<Variable> = IntegerExpression::Const(1);
826 assert!(!expr.is_atomic());
827
828 let expr: IntegerExpression<Variable> = IntegerExpression::BinaryExpr(
829 Box::new(IntegerExpression::Const(1)),
830 IntegerOp::Add,
831 Box::new(IntegerExpression::Const(1)),
832 );
833 assert!(!expr.is_atomic());
834
835 let expr: IntegerExpression<Variable> =
836 IntegerExpression::Neg(Box::new(IntegerExpression::Const(1)));
837 assert!(!expr.is_atomic());
838 }
839
840 #[test]
841 fn test_is_param_to_var() {
842 let expr: IntegerExpression<Parameter> = IntegerExpression::Atom(Parameter::new("x"));
843 let expected_expr: IntegerExpression<Variable> =
844 IntegerExpression::Param(Parameter::new("x"));
845 assert_eq!(
846 Into::<IntegerExpression<Variable>>::into(expr),
847 expected_expr
848 );
849
850 let expr: IntegerExpression<Parameter> = IntegerExpression::Param(Parameter::new("x"));
851 let expected_expr: IntegerExpression<Variable> =
852 IntegerExpression::Param(Parameter::new("x"));
853 assert_eq!(
854 Into::<IntegerExpression<Variable>>::into(expr),
855 expected_expr
856 );
857
858 let expr: IntegerExpression<Parameter> =
859 IntegerExpression::Neg(Box::new(IntegerExpression::Atom(Parameter::new("x"))));
860 let expected_expr: IntegerExpression<Variable> =
861 IntegerExpression::Neg(Box::new(IntegerExpression::Param(Parameter::new("x"))));
862 assert_eq!(
863 Into::<IntegerExpression<Variable>>::into(expr),
864 expected_expr
865 );
866
867 let expr: IntegerExpression<Parameter> = IntegerExpression::BinaryExpr(
868 Box::new(IntegerExpression::Atom(Parameter::new("x"))),
869 IntegerOp::Add,
870 Box::new(IntegerExpression::Const(1)),
871 );
872 let expected_expr: IntegerExpression<Variable> = IntegerExpression::BinaryExpr(
873 Box::new(IntegerExpression::Param(Parameter::new("x"))),
874 IntegerOp::Add,
875 Box::new(IntegerExpression::Const(1)),
876 );
877 assert_eq!(
878 Into::<IntegerExpression<Variable>>::into(expr),
879 expected_expr
880 );
881 }
882
883 #[test]
884 fn test_is_param_to_loc() {
885 let expr: IntegerExpression<Parameter> = IntegerExpression::Atom(Parameter::new("x"));
886 let expected_expr: IntegerExpression<Location> =
887 IntegerExpression::Param(Parameter::new("x"));
888 assert_eq!(
889 Into::<IntegerExpression<Location>>::into(expr),
890 expected_expr
891 );
892
893 let expr: IntegerExpression<Parameter> = IntegerExpression::Param(Parameter::new("x"));
894 let expected_expr: IntegerExpression<Location> =
895 IntegerExpression::Param(Parameter::new("x"));
896 assert_eq!(
897 Into::<IntegerExpression<Location>>::into(expr),
898 expected_expr
899 );
900
901 let expr: IntegerExpression<Parameter> =
902 IntegerExpression::Neg(Box::new(IntegerExpression::Atom(Parameter::new("x"))));
903 let expected_expr: IntegerExpression<Location> =
904 IntegerExpression::Neg(Box::new(IntegerExpression::Param(Parameter::new("x"))));
905 assert_eq!(
906 Into::<IntegerExpression<Location>>::into(expr),
907 expected_expr
908 );
909
910 let expr: IntegerExpression<Parameter> = IntegerExpression::BinaryExpr(
911 Box::new(IntegerExpression::Atom(Parameter::new("x"))),
912 IntegerOp::Add,
913 Box::new(IntegerExpression::Const(1)),
914 );
915 let expected_expr: IntegerExpression<Location> = IntegerExpression::BinaryExpr(
916 Box::new(IntegerExpression::Param(Parameter::new("x"))),
917 IntegerOp::Add,
918 Box::new(IntegerExpression::Const(1)),
919 );
920 assert_eq!(
921 Into::<IntegerExpression<Location>>::into(expr),
922 expected_expr
923 );
924 }
925
926 #[test]
927 fn test_integer_expression_addition() {
928 let expr1: IntegerExpression<Variable> = IntegerExpression::Const(1);
929 let expr2: IntegerExpression<Variable> = IntegerExpression::Const(2);
930 let result = expr1 + expr2;
931 assert_eq!(
932 result,
933 IntegerExpression::BinaryExpr(
934 Box::new(IntegerExpression::Const(1)),
935 IntegerOp::Add,
936 Box::new(IntegerExpression::Const(2)),
937 )
938 );
939 }
940
941 #[test]
942 fn test_integer_expression_subtraction() {
943 let expr1: IntegerExpression<Variable> = IntegerExpression::Const(3);
944 let expr2: IntegerExpression<Variable> = IntegerExpression::Const(2);
945 let result = expr1 - expr2;
946 assert_eq!(
947 result,
948 IntegerExpression::BinaryExpr(
949 Box::new(IntegerExpression::Const(3)),
950 IntegerOp::Sub,
951 Box::new(IntegerExpression::Const(2)),
952 )
953 );
954 }
955
956 #[test]
957 fn test_integer_expression_multiplication() {
958 let expr1: IntegerExpression<Variable> = IntegerExpression::Const(4);
959 let expr2: IntegerExpression<Variable> = IntegerExpression::Const(5);
960 let result = expr1 * expr2;
961 assert_eq!(
962 result,
963 IntegerExpression::BinaryExpr(
964 Box::new(IntegerExpression::Const(4)),
965 IntegerOp::Mul,
966 Box::new(IntegerExpression::Const(5)),
967 )
968 );
969 }
970
971 #[test]
972 fn test_integer_expression_division() {
973 let expr1: IntegerExpression<Variable> = IntegerExpression::Const(10);
974 let expr2: IntegerExpression<Variable> = IntegerExpression::Const(2);
975 let result = expr1 / expr2;
976 assert_eq!(
977 result,
978 IntegerExpression::BinaryExpr(
979 Box::new(IntegerExpression::Const(10)),
980 IntegerOp::Div,
981 Box::new(IntegerExpression::Const(2)),
982 )
983 );
984 }
985
986 #[test]
987 fn test_integer_expression_negation() {
988 let expr: IntegerExpression<Variable> = IntegerExpression::Const(5);
989 let result = -expr;
990 assert_eq!(
991 result,
992 IntegerExpression::Neg(Box::new(IntegerExpression::Const(5)))
993 );
994 }
995
996 #[test]
997 fn test_boolean_expression_negation() {
998 let expr: BooleanExpression<Variable> = BooleanExpression::True;
999 let result = !expr;
1000 assert_eq!(
1001 result,
1002 BooleanExpression::Not(Box::new(BooleanExpression::True))
1003 );
1004 }
1005
1006 #[test]
1007 fn test_boolean_expression_and() {
1008 let expr1: BooleanExpression<Variable> = BooleanExpression::True;
1009 let expr2: BooleanExpression<Variable> = BooleanExpression::True;
1010 let result = expr1 & expr2;
1011 assert_eq!(
1012 result,
1013 BooleanExpression::BinaryExpression(
1014 Box::new(BooleanExpression::True),
1015 BooleanConnective::And,
1016 Box::new(BooleanExpression::True),
1017 )
1018 );
1019 }
1020
1021 #[test]
1022 fn test_boolean_expression_or() {
1023 let expr1: BooleanExpression<Variable> = BooleanExpression::True;
1024 let expr2: BooleanExpression<Variable> = BooleanExpression::True;
1025 let result = expr1 | expr2;
1026 assert_eq!(
1027 result,
1028 BooleanExpression::BinaryExpression(
1029 Box::new(BooleanExpression::True),
1030 BooleanConnective::Or,
1031 Box::new(BooleanExpression::True),
1032 )
1033 );
1034 }
1035
1036 #[test]
1037 fn test_boolean_expr_param_to_loc() {
1038 let expr: BooleanExpression<Parameter> = BooleanExpression::True;
1039 let expected_expr: BooleanExpression<Location> = BooleanExpression::True;
1040 assert_eq!(
1041 Into::<BooleanExpression<Location>>::into(expr),
1042 expected_expr
1043 );
1044
1045 let expr: BooleanExpression<Parameter> = BooleanExpression::False;
1046 let expected_expr: BooleanExpression<Location> = BooleanExpression::False;
1047 assert_eq!(
1048 Into::<BooleanExpression<Location>>::into(expr),
1049 expected_expr
1050 );
1051
1052 let expr: BooleanExpression<Parameter> =
1053 BooleanExpression::Not(Box::new(BooleanExpression::True));
1054 let expected_expr: BooleanExpression<Location> =
1055 BooleanExpression::Not(Box::new(BooleanExpression::True));
1056 assert_eq!(
1057 Into::<BooleanExpression<Location>>::into(expr),
1058 expected_expr
1059 );
1060
1061 let expr: BooleanExpression<Parameter> = BooleanExpression::BinaryExpression(
1062 Box::new(BooleanExpression::True),
1063 BooleanConnective::And,
1064 Box::new(BooleanExpression::False),
1065 );
1066 let expected_expr: BooleanExpression<Location> = BooleanExpression::BinaryExpression(
1067 Box::new(BooleanExpression::True),
1068 BooleanConnective::And,
1069 Box::new(BooleanExpression::False),
1070 );
1071 assert_eq!(
1072 Into::<BooleanExpression<Location>>::into(expr),
1073 expected_expr
1074 );
1075
1076 let expr: BooleanExpression<Parameter> = BooleanExpression::ComparisonExpression(
1077 Box::new(IntegerExpression::Const(42)),
1078 ComparisonOp::Leq,
1079 Box::new(IntegerExpression::Atom(Parameter::new("n"))),
1080 );
1081 let expected_expr: BooleanExpression<Location> = BooleanExpression::ComparisonExpression(
1082 Box::new(IntegerExpression::Const(42)),
1083 ComparisonOp::Leq,
1084 Box::new(IntegerExpression::Param(Parameter::new("n"))),
1085 );
1086 assert_eq!(
1087 Into::<BooleanExpression<Location>>::into(expr),
1088 expected_expr
1089 );
1090 }
1091
1092 #[test]
1093 fn test_boolean_expr_param_to_var() {
1094 let expr: BooleanExpression<Parameter> = BooleanExpression::True;
1095 let expected_expr: BooleanExpression<Variable> = BooleanExpression::True;
1096 assert_eq!(
1097 Into::<BooleanExpression<Variable>>::into(expr),
1098 expected_expr
1099 );
1100
1101 let expr: BooleanExpression<Parameter> = BooleanExpression::False;
1102 let expected_expr: BooleanExpression<Variable> = BooleanExpression::False;
1103 assert_eq!(
1104 Into::<BooleanExpression<Variable>>::into(expr),
1105 expected_expr
1106 );
1107
1108 let expr: BooleanExpression<Parameter> =
1109 BooleanExpression::Not(Box::new(BooleanExpression::True));
1110 let expected_expr: BooleanExpression<Variable> =
1111 BooleanExpression::Not(Box::new(BooleanExpression::True));
1112 assert_eq!(
1113 Into::<BooleanExpression<Variable>>::into(expr),
1114 expected_expr
1115 );
1116
1117 let expr: BooleanExpression<Parameter> = BooleanExpression::BinaryExpression(
1118 Box::new(BooleanExpression::True),
1119 BooleanConnective::And,
1120 Box::new(BooleanExpression::False),
1121 );
1122 let expected_expr: BooleanExpression<Variable> = BooleanExpression::BinaryExpression(
1123 Box::new(BooleanExpression::True),
1124 BooleanConnective::And,
1125 Box::new(BooleanExpression::False),
1126 );
1127 assert_eq!(
1128 Into::<BooleanExpression<Variable>>::into(expr),
1129 expected_expr
1130 );
1131
1132 let expr: BooleanExpression<Parameter> = BooleanExpression::ComparisonExpression(
1133 Box::new(IntegerExpression::Const(42)),
1134 ComparisonOp::Leq,
1135 Box::new(IntegerExpression::Atom(Parameter::new("n"))),
1136 );
1137 let expected_expr: BooleanExpression<Variable> = BooleanExpression::ComparisonExpression(
1138 Box::new(IntegerExpression::Const(42)),
1139 ComparisonOp::Leq,
1140 Box::new(IntegerExpression::Param(Parameter::new("n"))),
1141 );
1142 assert_eq!(
1143 Into::<BooleanExpression<Variable>>::into(expr),
1144 expected_expr
1145 );
1146 }
1147
1148 #[test]
1149 fn test_integer_expression_contains_atom() {
1150 let expr1: IntegerExpression<Variable> = IntegerExpression::Atom(Variable::new("x"));
1151 assert!(expr1.contains_atom());
1152
1153 let expr2: IntegerExpression<Variable> = IntegerExpression::Const(1);
1154 assert!(!expr2.contains_atom());
1155
1156 let expr3: IntegerExpression<Variable> = IntegerExpression::Param(Parameter::new("y"));
1157 assert!(!expr3.contains_atom());
1158
1159 let expr4: IntegerExpression<Variable> =
1160 IntegerExpression::Neg(Box::new(IntegerExpression::Atom(Variable::new("z"))));
1161 assert!(expr4.contains_atom());
1162
1163 let expr5: IntegerExpression<Variable> = IntegerExpression::BinaryExpr(
1164 Box::new(IntegerExpression::Atom(Variable::new("a"))),
1165 IntegerOp::Add,
1166 Box::new(IntegerExpression::Const(1)),
1167 );
1168 assert!(expr5.contains_atom());
1169 }
1170
1171 #[test]
1172 fn test_swap_side_comp_op() {
1173 assert_eq!(ComparisonOp::Eq.get_swap_side(), ComparisonOp::Eq);
1174 assert_eq!(ComparisonOp::Neq.get_swap_side(), ComparisonOp::Neq);
1175 assert_eq!(ComparisonOp::Lt.get_swap_side(), ComparisonOp::Gt);
1176 assert_eq!(ComparisonOp::Leq.get_swap_side(), ComparisonOp::Geq);
1177 assert_eq!(ComparisonOp::Gt.get_swap_side(), ComparisonOp::Lt);
1178 assert_eq!(ComparisonOp::Geq.get_swap_side(), ComparisonOp::Leq);
1179 }
1180
1181 #[test]
1182 fn test_invert_comp_op() {
1183 assert_eq!(ComparisonOp::Eq.invert(), ComparisonOp::Neq);
1184 assert_eq!(ComparisonOp::Neq.invert(), ComparisonOp::Eq);
1185 assert_eq!(ComparisonOp::Lt.invert(), ComparisonOp::Geq);
1186 assert_eq!(ComparisonOp::Leq.invert(), ComparisonOp::Gt);
1187 assert_eq!(ComparisonOp::Gt.invert(), ComparisonOp::Leq);
1188 assert_eq!(ComparisonOp::Geq.invert(), ComparisonOp::Lt);
1189 }
1190
1191 #[test]
1192 fn test_invert_boolean_connective() {
1193 assert_eq!(BooleanConnective::And.invert(), BooleanConnective::Or);
1194 assert_eq!(BooleanConnective::Or.invert(), BooleanConnective::And);
1195 }
1196
1197 #[test]
1198 fn test_try_to_evaluate_to_const() {
1199 let expr = IntegerExpression::<Location>::Const(5) + IntegerExpression::Const(3);
1200 assert_eq!(expr.try_to_evaluate_to_const(), Some(8));
1201
1202 let expr = IntegerExpression::<Location>::Const(5) - IntegerExpression::Const(3);
1203 assert_eq!(expr.try_to_evaluate_to_const(), Some(2));
1204
1205 let expr = IntegerExpression::<Location>::Const(10) / IntegerExpression::Const(5);
1206 assert_eq!(expr.try_to_evaluate_to_const(), Some(2));
1207
1208 let expr = -IntegerExpression::Const(42) / IntegerExpression::<Location>::Const(2);
1209 assert_eq!(expr.try_to_evaluate_to_const(), Some(-21));
1210
1211 let expr = -IntegerExpression::<Location>::Const(42) * IntegerExpression::Const(2);
1212 assert_eq!(expr.try_to_evaluate_to_const(), Some(-84));
1213
1214 let expr = IntegerExpression::<Location>::Param(Parameter::new("n"));
1215 assert_eq!(expr.try_to_evaluate_to_const(), None);
1216
1217 let expr = -IntegerExpression::Const(42) / IntegerExpression::Atom(Location::new("loc"));
1218 assert_eq!(expr.try_to_evaluate_to_const(), None);
1219 }
1220
1221 #[test]
1222 fn test_try_to_evaluate_to_const_with_env() {
1223 let env = HashMap::from([(Location::new("loc"), 1)]);
1224 let param_env = HashMap::from([(Parameter::new("n"), 1)]);
1225
1226 let expr = IntegerExpression::<Location>::Const(5) + IntegerExpression::Const(3);
1227 assert_eq!(
1228 expr.try_to_evaluate_to_const_with_env(&env, ¶m_env),
1229 Ok(8)
1230 );
1231
1232 let expr = IntegerExpression::<Location>::Const(5) - IntegerExpression::Const(3);
1233 assert_eq!(
1234 expr.try_to_evaluate_to_const_with_env(&env, ¶m_env),
1235 Ok(2)
1236 );
1237
1238 let expr = IntegerExpression::<Location>::Const(10) / IntegerExpression::Const(5);
1239 assert_eq!(
1240 expr.try_to_evaluate_to_const_with_env(&env, ¶m_env),
1241 Ok(2)
1242 );
1243
1244 let expr = -IntegerExpression::Const(42) / IntegerExpression::<Location>::Const(2);
1245 assert_eq!(
1246 expr.try_to_evaluate_to_const_with_env(&env, ¶m_env),
1247 Ok(-21)
1248 );
1249
1250 let expr = -IntegerExpression::<Location>::Const(42) * IntegerExpression::Const(2);
1251 assert_eq!(
1252 expr.try_to_evaluate_to_const_with_env(&env, ¶m_env),
1253 Ok(-84)
1254 );
1255
1256 let expr = IntegerExpression::Atom(Location::new("loc"));
1257 assert_eq!(
1258 expr.try_to_evaluate_to_const_with_env(&env, ¶m_env),
1259 Ok(1)
1260 );
1261
1262 let expr = -IntegerExpression::Const(42) / IntegerExpression::Atom(Location::new("loc"));
1263 assert_eq!(
1264 expr.try_to_evaluate_to_const_with_env(&env, ¶m_env),
1265 Ok(-42)
1266 );
1267
1268 let expr = IntegerExpression::<Location>::Param(Parameter::new("n"));
1269 assert_eq!(
1270 expr.try_to_evaluate_to_const_with_env(&HashMap::new(), ¶m_env),
1271 Ok(1)
1272 );
1273
1274 let expr = IntegerExpression::<Location>::Param(Parameter::new("n"));
1275 assert_eq!(
1276 expr.try_to_evaluate_to_const_with_env(&env, &HashMap::new()),
1277 Err(EvaluationError::ParameterNotFound(Parameter::new("n")))
1278 );
1279
1280 let expr = IntegerExpression::Atom(Location::new("loc"));
1281 assert_eq!(
1282 expr.try_to_evaluate_to_const_with_env(&HashMap::new(), ¶m_env),
1283 Err(EvaluationError::AtomicNotFound(Location::new("loc")))
1284 );
1285 }
1286
1287 #[test]
1288 fn test_boolean_expr_check_satisfied() {
1289 let env = HashMap::from([(Location::new("loc"), 1)]);
1290 let param_env = HashMap::from([(Parameter::new("n"), 1)]);
1291
1292 let expr = BooleanExpression::ComparisonExpression(
1293 Box::new(IntegerExpression::Const(5)),
1294 ComparisonOp::Eq,
1295 Box::new(IntegerExpression::Const(5)),
1296 );
1297 assert_eq!(expr.check_satisfied(&env, ¶m_env), Ok(true));
1298
1299 let expr = BooleanExpression::ComparisonExpression(
1300 Box::new(IntegerExpression::Const(5)),
1301 ComparisonOp::Eq,
1302 Box::new(IntegerExpression::Const(3)),
1303 );
1304 assert_eq!(expr.check_satisfied(&env, ¶m_env), Ok(false));
1305
1306 let expr = BooleanExpression::ComparisonExpression(
1307 Box::new(IntegerExpression::Const(5)),
1308 ComparisonOp::Lt,
1309 Box::new(IntegerExpression::Const(3)),
1310 );
1311 assert_eq!(expr.check_satisfied(&env, ¶m_env), Ok(false));
1312
1313 let expr = BooleanExpression::ComparisonExpression(
1314 Box::new(IntegerExpression::Const(5)),
1315 ComparisonOp::Lt,
1316 Box::new(IntegerExpression::Const(10)),
1317 );
1318 assert_eq!(expr.check_satisfied(&env, ¶m_env), Ok(true));
1319
1320 let expr = BooleanExpression::ComparisonExpression(
1321 Box::new(IntegerExpression::Const(5)),
1322 ComparisonOp::Leq,
1323 Box::new(IntegerExpression::Const(5)),
1324 );
1325 assert_eq!(expr.check_satisfied(&env, ¶m_env), Ok(true));
1326
1327 let expr = BooleanExpression::ComparisonExpression(
1328 Box::new(IntegerExpression::Const(5)),
1329 ComparisonOp::Leq,
1330 Box::new(IntegerExpression::Const(3)),
1331 );
1332 assert_eq!(expr.check_satisfied(&env, ¶m_env), Ok(false));
1333
1334 let expr = BooleanExpression::ComparisonExpression(
1335 Box::new(IntegerExpression::Const(5)),
1336 ComparisonOp::Gt,
1337 Box::new(IntegerExpression::Const(3)),
1338 );
1339 assert_eq!(expr.check_satisfied(&env, ¶m_env), Ok(true));
1340
1341 let expr = BooleanExpression::ComparisonExpression(
1342 Box::new(IntegerExpression::Const(5)),
1343 ComparisonOp::Gt,
1344 Box::new(IntegerExpression::Const(10)),
1345 );
1346 assert_eq!(expr.check_satisfied(&env, ¶m_env), Ok(false));
1347
1348 let expr = BooleanExpression::ComparisonExpression(
1349 Box::new(IntegerExpression::Const(5)),
1350 ComparisonOp::Neq,
1351 Box::new(IntegerExpression::Const(5)),
1352 );
1353 assert_eq!(expr.check_satisfied(&env, ¶m_env), Ok(false));
1354
1355 let expr = BooleanExpression::ComparisonExpression(
1356 Box::new(IntegerExpression::Const(5)),
1357 ComparisonOp::Neq,
1358 Box::new(IntegerExpression::Const(3)),
1359 );
1360 assert_eq!(expr.check_satisfied(&env, ¶m_env), Ok(true));
1361
1362 let expr = BooleanExpression::ComparisonExpression(
1363 Box::new(IntegerExpression::Const(5)),
1364 ComparisonOp::Geq,
1365 Box::new(IntegerExpression::Const(3)),
1366 );
1367 assert_eq!(expr.check_satisfied(&env, ¶m_env), Ok(true));
1368
1369 let expr = BooleanExpression::ComparisonExpression(
1370 Box::new(IntegerExpression::Const(5)),
1371 ComparisonOp::Geq,
1372 Box::new(IntegerExpression::Const(10)),
1373 );
1374 assert_eq!(expr.check_satisfied(&env, ¶m_env), Ok(false));
1375
1376 let expr = BooleanExpression::BinaryExpression(
1377 Box::new(BooleanExpression::True),
1378 BooleanConnective::And,
1379 Box::new(BooleanExpression::True),
1380 );
1381 assert_eq!(expr.check_satisfied(&env, ¶m_env), Ok(true));
1382
1383 let expr = BooleanExpression::BinaryExpression(
1384 Box::new(BooleanExpression::True),
1385 BooleanConnective::Or,
1386 Box::new(BooleanExpression::False),
1387 );
1388 assert_eq!(expr.check_satisfied(&env, ¶m_env), Ok(true));
1389
1390 let expr = !BooleanExpression::False;
1391 assert_eq!(expr.check_satisfied(&env, ¶m_env), Ok(true));
1392
1393 let expr = BooleanExpression::False;
1394 assert_eq!(expr.check_satisfied(&env, ¶m_env), Ok(false));
1395 }
1396
1397 #[test]
1398 fn test_display_evaluation_error() {
1399 let error = EvaluationError::AtomicNotFound(Location::new("loc"));
1400 assert!(
1401 error
1402 .to_string()
1403 .contains(&Location::new("loc").to_string())
1404 );
1405
1406 let error: EvaluationError<Location> =
1407 EvaluationError::ParameterNotFound(Parameter::new("n"));
1408 assert!(error.to_string().contains("n"));
1409 }
1410
1411 #[test]
1412 fn test_contains_atom_a_integer_expr() {
1413 let atom = Variable::new("x");
1414
1415 let expr1: IntegerExpression<Variable> = IntegerExpression::Atom(atom.clone());
1416 assert!(expr1.contains_atom_a(&atom));
1417
1418 let expr2: IntegerExpression<Variable> = IntegerExpression::Const(1);
1419 assert!(!expr2.contains_atom_a(&atom));
1420
1421 let expr3: IntegerExpression<Variable> = IntegerExpression::Param(Parameter::new("y"));
1422 assert!(!expr3.contains_atom_a(&atom));
1423
1424 let expr4: IntegerExpression<Variable> =
1425 IntegerExpression::Neg(Box::new(IntegerExpression::Atom(atom.clone())));
1426 assert!(expr4.contains_atom_a(&atom));
1427
1428 let expr5: IntegerExpression<Variable> = IntegerExpression::BinaryExpr(
1429 Box::new(IntegerExpression::Atom(atom.clone())),
1430 IntegerOp::Add,
1431 Box::new(IntegerExpression::Const(1)),
1432 );
1433 assert!(expr5.contains_atom_a(&atom));
1434
1435 let expr6: IntegerExpression<Variable> = IntegerExpression::BinaryExpr(
1436 Box::new(IntegerExpression::Const(1)),
1437 IntegerOp::Add,
1438 Box::new(IntegerExpression::Const(2)),
1439 );
1440 assert!(!expr6.contains_atom_a(&atom));
1441 }
1442
1443 #[test]
1444 fn test_contains_atom_a_boolean_expr() {
1445 let atom = Variable::new("x");
1446
1447 let expr1: BooleanExpression<Variable> = BooleanExpression::ComparisonExpression(
1448 Box::new(IntegerExpression::Atom(atom.clone())),
1449 ComparisonOp::Eq,
1450 Box::new(IntegerExpression::Const(1)),
1451 );
1452 assert!(expr1.contains_atom_a(&atom));
1453
1454 let expr2: BooleanExpression<Variable> = BooleanExpression::ComparisonExpression(
1455 Box::new(IntegerExpression::Atom(Variable::new("y"))),
1456 ComparisonOp::Eq,
1457 Box::new(IntegerExpression::Const(2)),
1458 );
1459 assert!(!expr2.contains_atom_a(&atom));
1460
1461 let expr3: BooleanExpression<Variable> = BooleanExpression::BinaryExpression(
1462 Box::new(BooleanExpression::ComparisonExpression(
1463 Box::new(IntegerExpression::Atom(atom.clone())),
1464 ComparisonOp::Eq,
1465 Box::new(IntegerExpression::Const(1)),
1466 )),
1467 BooleanConnective::And,
1468 Box::new(BooleanExpression::True),
1469 );
1470 assert!(expr3.contains_atom_a(&atom));
1471
1472 let expr4: BooleanExpression<Variable> =
1473 BooleanExpression::Not(Box::new(BooleanExpression::ComparisonExpression(
1474 Box::new(IntegerExpression::Atom(atom.clone())),
1475 ComparisonOp::Eq,
1476 Box::new(IntegerExpression::Const(1)),
1477 )));
1478 assert!(expr4.contains_atom_a(&atom));
1479
1480 let expr5: BooleanExpression<Variable> = BooleanExpression::True;
1481 assert!(!expr5.contains_atom_a(&atom));
1482
1483 let expr6: BooleanExpression<Variable> = BooleanExpression::False;
1484 assert!(!expr6.contains_atom_a(&atom));
1485 }
1486
1487 #[test]
1488 fn test_boolean_expression_complex() {
1489 let env = HashMap::from([(Location::new("loc"), 1)]);
1490 let param_env = HashMap::from([(Parameter::new("n"), 1)]);
1491
1492 let expr = BooleanExpression::BinaryExpression(
1493 Box::new(BooleanExpression::ComparisonExpression(
1494 Box::new(IntegerExpression::Const(5)),
1495 ComparisonOp::Eq,
1496 Box::new(IntegerExpression::Const(5)),
1497 )),
1498 BooleanConnective::And,
1499 Box::new(BooleanExpression::ComparisonExpression(
1500 Box::new(IntegerExpression::Const(3)),
1501 ComparisonOp::Lt,
1502 Box::new(IntegerExpression::Const(10)),
1503 )),
1504 );
1505 assert_eq!(expr.check_satisfied(&env, ¶m_env), Ok(true));
1506
1507 let expr = BooleanExpression::BinaryExpression(
1508 Box::new(BooleanExpression::ComparisonExpression(
1509 Box::new(IntegerExpression::Const(5)),
1510 ComparisonOp::Eq,
1511 Box::new(IntegerExpression::Const(3)),
1512 )),
1513 BooleanConnective::Or,
1514 Box::new(BooleanExpression::ComparisonExpression(
1515 Box::new(IntegerExpression::Const(3)),
1516 ComparisonOp::Lt,
1517 Box::new(IntegerExpression::Const(10)),
1518 )),
1519 );
1520 assert_eq!(expr.check_satisfied(&env, ¶m_env), Ok(true));
1521
1522 let expr = BooleanExpression::Not(Box::new(BooleanExpression::ComparisonExpression(
1523 Box::new(IntegerExpression::Const(5)),
1524 ComparisonOp::Eq,
1525 Box::new(IntegerExpression::Const(3)),
1526 )));
1527 assert_eq!(expr.check_satisfied(&env, ¶m_env), Ok(true));
1528 }
1529
1530 #[test]
1531 fn test_integer_expression_substitute_atom() {
1532 let atom = Variable::new("x");
1533 let replacement = IntegerExpression::Const(42);
1534
1535 let expr1: IntegerExpression<Variable> = IntegerExpression::Atom(atom.clone());
1536 let mut result = expr1.clone();
1537 result.substitute_atom_with(&atom, &replacement);
1538 assert_eq!(result, replacement);
1539
1540 let expr2: IntegerExpression<Variable> = IntegerExpression::Const(1);
1541 let mut result = expr2.clone();
1542 result.substitute_atom_with(&atom, &replacement);
1543 assert_eq!(result, expr2);
1544
1545 let expr3: IntegerExpression<Variable> = IntegerExpression::Param(Parameter::new("y"));
1546 let mut result = expr3.clone();
1547 result.substitute_atom_with(&atom, &replacement);
1548 assert_eq!(result, expr3);
1549
1550 let expr4: IntegerExpression<Variable> =
1551 IntegerExpression::Neg(Box::new(IntegerExpression::Atom(atom.clone())));
1552 let expected = IntegerExpression::Neg(Box::new(replacement.clone()));
1553 let mut result = expr4;
1554 result.substitute_atom_with(&atom, &replacement);
1555 assert_eq!(result, expected);
1556
1557 let expr5: IntegerExpression<Variable> = IntegerExpression::BinaryExpr(
1558 Box::new(IntegerExpression::Atom(atom.clone())),
1559 IntegerOp::Add,
1560 Box::new(IntegerExpression::Const(1)),
1561 );
1562 let expected = IntegerExpression::BinaryExpr(
1563 Box::new(replacement.clone()),
1564 IntegerOp::Add,
1565 Box::new(IntegerExpression::Const(1)),
1566 );
1567 let mut result = expr5.clone();
1568 result.substitute_atom_with(&atom, &replacement);
1569 assert_eq!(result, expected);
1570
1571 let expr6: IntegerExpression<Variable> = IntegerExpression::BinaryExpr(
1572 Box::new(IntegerExpression::Const(1)),
1573 IntegerOp::Add,
1574 Box::new(IntegerExpression::Const(2)),
1575 );
1576 let mut result = expr6.clone();
1577 result.substitute_atom_with(&atom, &replacement);
1578 assert_eq!(result, expr6);
1579 }
1580
1581 #[test]
1582 fn test_boolean_expr_substitute_atom() {
1583 let atom = Variable::new("x");
1584 let replacement = IntegerExpression::Const(42);
1585
1586 let expr1: BooleanExpression<Variable> = BooleanExpression::ComparisonExpression(
1587 Box::new(IntegerExpression::Atom(atom.clone())),
1588 ComparisonOp::Eq,
1589 Box::new(IntegerExpression::Const(1)),
1590 );
1591 let expected = BooleanExpression::ComparisonExpression(
1592 Box::new(replacement.clone()),
1593 ComparisonOp::Eq,
1594 Box::new(IntegerExpression::Const(1)),
1595 );
1596 let mut result = expr1.clone();
1597 result.substitute_atom_with(&atom, &replacement);
1598 assert_eq!(result, expected);
1599
1600 let expr2: BooleanExpression<Variable> = BooleanExpression::BinaryExpression(
1601 Box::new(BooleanExpression::ComparisonExpression(
1602 Box::new(IntegerExpression::Atom(atom.clone())),
1603 ComparisonOp::Eq,
1604 Box::new(IntegerExpression::Const(1)),
1605 )),
1606 BooleanConnective::And,
1607 Box::new(BooleanExpression::True),
1608 );
1609 let expected = BooleanExpression::BinaryExpression(
1610 Box::new(BooleanExpression::ComparisonExpression(
1611 Box::new(replacement.clone()),
1612 ComparisonOp::Eq,
1613 Box::new(IntegerExpression::Const(1)),
1614 )),
1615 BooleanConnective::And,
1616 Box::new(BooleanExpression::True),
1617 );
1618 let mut result = expr2.clone();
1619 result.substitute_atom_with(&atom, &replacement);
1620 assert_eq!(result, expected);
1621
1622 let expr3: BooleanExpression<Variable> =
1623 BooleanExpression::Not(Box::new(BooleanExpression::ComparisonExpression(
1624 Box::new(IntegerExpression::Atom(atom.clone())),
1625 ComparisonOp::Eq,
1626 Box::new(IntegerExpression::Const(1)),
1627 )));
1628 let expected = BooleanExpression::Not(Box::new(BooleanExpression::ComparisonExpression(
1629 Box::new(replacement.clone()),
1630 ComparisonOp::Eq,
1631 Box::new(IntegerExpression::Const(1)),
1632 )));
1633 let mut result = expr3.clone();
1634 result.substitute_atom_with(&atom, &replacement);
1635 assert_eq!(result, expected);
1636
1637 let expr4: BooleanExpression<Variable> = BooleanExpression::True;
1638 let mut result = expr4.clone();
1639 result.substitute_atom_with(&atom, &replacement);
1640 assert_eq!(result, expr4);
1641
1642 let expr5: BooleanExpression<Variable> = BooleanExpression::False;
1643 let mut result = expr5.clone();
1644 result.substitute_atom_with(&atom, &replacement);
1645 assert_eq!(result, expr5);
1646 }
1647
1648 #[test]
1649 fn test_try_check_expr_constraints_to_zero() {
1650 let atom = Location::new("loc");
1651 let expr = BooleanExpression::ComparisonExpression(
1652 Box::new(IntegerExpression::Atom(atom.clone())),
1653 ComparisonOp::Eq,
1654 Box::new(IntegerExpression::Const(0)),
1655 );
1656 assert!(expr.try_check_expr_constraints_to_zero(&atom));
1657
1658 let expr = BooleanExpression::ComparisonExpression(
1659 Box::new(IntegerExpression::Atom(atom.clone())),
1660 ComparisonOp::Leq,
1661 Box::new(IntegerExpression::Const(0)),
1662 );
1663 assert!(expr.try_check_expr_constraints_to_zero(&atom));
1664
1665 let expr = BooleanExpression::ComparisonExpression(
1666 Box::new(IntegerExpression::Atom(atom.clone())),
1667 ComparisonOp::Lt,
1668 Box::new(IntegerExpression::Const(1)),
1669 );
1670 assert!(expr.try_check_expr_constraints_to_zero(&atom));
1671
1672 let expr = BooleanExpression::ComparisonExpression(
1673 Box::new(IntegerExpression::Atom(atom.clone())),
1674 ComparisonOp::Geq,
1675 Box::new(IntegerExpression::Const(0)),
1676 );
1677 assert!(!expr.try_check_expr_constraints_to_zero(&atom));
1678
1679 let expr = BooleanExpression::ComparisonExpression(
1680 Box::new(IntegerExpression::Atom(Location::new("otherloc"))),
1681 ComparisonOp::Eq,
1682 Box::new(IntegerExpression::Const(0)),
1683 );
1684 assert!(!expr.try_check_expr_constraints_to_zero(&atom));
1685
1686 let expr = !BooleanExpression::ComparisonExpression(
1687 Box::new(IntegerExpression::Atom(atom.clone())),
1688 ComparisonOp::Gt,
1689 Box::new(IntegerExpression::Const(1)),
1690 );
1691 assert!(!expr.try_check_expr_constraints_to_zero(&atom));
1692
1693 let atom = Location::new("loc");
1694 let expr = BooleanExpression::ComparisonExpression(
1695 Box::new(IntegerExpression::Const(0)),
1696 ComparisonOp::Eq,
1697 Box::new(IntegerExpression::Atom(atom.clone())),
1698 );
1699 assert!(expr.try_check_expr_constraints_to_zero(&atom));
1700 }
1701
1702 #[test]
1703 fn test_try_const_from_integer() {
1704 let expr: IntegerExpression<Location> = 1_u32.into();
1705 assert_eq!(expr, IntegerExpression::Const(1));
1706 }
1707
1708 #[test]
1709 fn test_integer_expr_from_location() {
1710 let loc = Location::new("loc");
1711 let expected_expr = IntegerExpression::Atom(Location::new("loc"));
1712 assert_eq!(IntegerExpression::from(loc), expected_expr);
1713 }
1714
1715 #[test]
1716 fn test_contains_parameter() {
1717 let expr1: IntegerExpression<Variable> = IntegerExpression::Param(Parameter::new("x"));
1719 assert!(expr1.contains_parameter());
1720
1721 let expr2: IntegerExpression<Variable> = IntegerExpression::Const(1);
1723 assert!(!expr2.contains_parameter());
1724
1725 let expr3: IntegerExpression<Variable> =
1727 IntegerExpression::Param(Parameter::new("n")) + IntegerExpression::Const(2);
1728 assert!(expr3.contains_parameter());
1729
1730 let expr4: IntegerExpression<Variable> =
1732 IntegerExpression::Const(2) + IntegerExpression::Param(Parameter::new("n"));
1733 assert!(expr4.contains_parameter());
1734
1735 let expr5: IntegerExpression<Variable> =
1737 IntegerExpression::Const(2) + IntegerExpression::Const(2);
1738 assert!(!expr5.contains_parameter());
1739
1740 let expr6: IntegerExpression<Variable> =
1742 IntegerExpression::Neg(Box::new(IntegerExpression::Param(Parameter::new("n"))));
1743 assert!(expr6.contains_parameter());
1744
1745 let expr7: IntegerExpression<Variable> =
1747 IntegerExpression::Neg(Box::new(IntegerExpression::Const(1)));
1748 assert!(!expr7.contains_parameter());
1749
1750 let expr8: IntegerExpression<Parameter> = IntegerExpression::Atom(Parameter::new("x"));
1753 assert!(!expr8.contains_parameter());
1754
1755 let expr9: IntegerExpression<Parameter> = IntegerExpression::Param(Parameter::new("y"));
1757 assert!(expr9.contains_parameter());
1758 }
1759}