1#![deny(rustdoc::broken_intra_doc_links)]
2
3use crate::{
4 Contains, Interval, IntervalTrait,
5 intervals::{
6 IntervalBoundsRuntime, LowerBoundRuntime, UpperBoundRuntime,
7 bounded::{IntervalFiniteLength, IntervalFinitePositiveLength},
8 unbounded::{IntervalInfiniteLength, IntervalLowerUnboundedUpperUnbounded},
9 },
10};
11use duplicate::duplicate_item;
12use num_valid::RealScalar;
13use serde::{Deserialize, Serialize};
14
15pub trait IntervalOperations: Contains {
80 fn intersection<IntervalType: IntervalTrait<RealType = Self::RealType>>(
166 &self,
167 other: &IntervalType,
168 ) -> Option<Interval<Self::RealType>> {
169 let lb_max = self.max_lower_bound(other);
171
172 let ub_min = self.min_upper_bound(other);
174
175 match (lb_max, ub_min) {
176 (Some(lower_bound), Some(upper_bound)) => {
177 IntervalFiniteLength::try_new(lower_bound, upper_bound)
181 .ok()
182 .map(|interval| interval.into())
183 }
184 (None, Some(upper_bound)) => {
185 Some(IntervalInfiniteLength::new_lower_unbounded(upper_bound).into())
186 }
187 (Some(lower_bound), None) => {
188 Some(IntervalInfiniteLength::new_upper_unbounded(lower_bound).into())
189 }
190 (None, None) => {
191 Some(IntervalLowerUnboundedUpperUnbounded::new().into())
193 }
194 }
195 }
196
197 fn union<IntervalType: IntervalTrait<RealType = Self::RealType>>(
274 &self,
275 other: &IntervalType,
276 ) -> IntervalUnion<Self::RealType>
277 where
278 Interval<Self::RealType>: From<Self> + From<IntervalType>,
279 {
280 let self_lb = self.lower_bound_runtime();
281 let self_ub = self.upper_bound_runtime();
282
283 let other_lb = other.lower_bound_runtime();
284 let other_ub = other.upper_bound_runtime();
285
286 if self_lb == other_lb && self_ub == other_ub {
287 IntervalUnion::SingleConnected(self.clone().into())
289 } else {
290 let self_is_on_the_left = self_lb <= other_lb;
293
294 let a = (self_lb, self_ub);
295 let b = (other_lb, other_ub);
296
297 let (left, right) = if self_is_on_the_left { (a, b) } else { (b, a) };
299
300 let upper_bound_left = &left.1;
302 let lower_bound_right = &right.0;
303
304 let intervals_touch_or_overlap = match (upper_bound_left, lower_bound_right) {
305 (None, _) | (_, None) => true,
306 (Some(UpperBoundRuntime::Open(ub)), Some(LowerBoundRuntime::Open(lb))) => {
310 ub.as_ref() > lb.as_ref()
311 }
312 (Some(UpperBoundRuntime::Open(ub)), Some(LowerBoundRuntime::Closed(lb))) => {
314 ub.as_ref() >= lb.as_ref()
315 }
316 (Some(UpperBoundRuntime::Closed(ub)), Some(LowerBoundRuntime::Open(lb))) => {
317 ub.as_ref() >= lb.as_ref()
318 }
319 (Some(UpperBoundRuntime::Closed(ub)), Some(LowerBoundRuntime::Closed(lb))) => {
320 ub.as_ref() >= lb.as_ref()
321 }
322 };
323
324 if intervals_touch_or_overlap {
325 let lower_bound = left.0;
326 let upper_bound = match (left.1, right.1) {
327 (None, _) | (_, None) => {
328 None
330 }
331 (Some(ub_left), Some(ub_right)) => {
332 Some(crate::bounds::max_upper_bound(ub_left, ub_right))
333 }
334 };
335
336 IntervalUnion::SingleConnected(
337 Interval::try_new(lower_bound, upper_bound)
338 .expect("Failed to create interval for union"),
339 )
340 } else if self_is_on_the_left {
341 IntervalUnion::TwoDisjoint {
342 left: self.clone().into(),
343 right: other.clone().into(),
344 }
345 } else {
346 IntervalUnion::TwoDisjoint {
347 left: other.clone().into(),
348 right: self.clone().into(),
349 }
350 }
351 }
352 }
353
354 fn difference<IntervalType: IntervalTrait<RealType = Self::RealType>>(
521 &self,
522 other: &IntervalType,
523 ) -> Option<IntervalDifference<Self::RealType>>
524 where
525 Interval<Self::RealType>: From<Self> + From<IntervalType>,
526 {
527 let intersection = self.intersection(other);
529
530 if intersection.is_none() {
531 return Some(IntervalDifference::SingleConnected(self.clone().into()));
533 }
534
535 let self_lb = self.lower_bound_runtime();
537 let self_ub = self.upper_bound_runtime();
538 let other_lb = other.lower_bound_runtime();
539 let other_ub = other.upper_bound_runtime();
540
541 let other_contains_self_lower = match (&other_lb, &self_lb) {
543 (None, _) => true, (_, None) => false, (Some(other_lb_val), Some(self_lb_val)) => other_lb_val <= self_lb_val,
546 };
547
548 let other_contains_self_upper = match (&other_ub, &self_ub) {
549 (None, _) => true, (_, None) => false, (Some(other_ub_val), Some(self_ub_val)) => other_ub_val >= self_ub_val,
552 };
553
554 if other_contains_self_lower && other_contains_self_upper {
555 return None;
557 }
558
559 let has_left_part = match (&self_lb, &other_lb) {
561 (None, None) => false, (None, Some(_)) => true, (Some(_), None) => false, (Some(self_lb_val), Some(other_lb_val)) => self_lb_val < other_lb_val,
565 };
566
567 let has_right_part = match (&self_ub, &other_ub) {
568 (None, None) => false, (None, Some(_)) => true, (Some(_), None) => false, (Some(self_ub_val), Some(other_ub_val)) => self_ub_val > other_ub_val,
572 };
573
574 match (has_left_part, has_right_part) {
575 (false, false) => {
576 unreachable!(
577 "Invariant violation: if no intersection exists, we return early at line ~1161; \
578 if other completely contains self, we return None at line ~1188. \
579 Therefore, at least one of has_left_part or has_right_part must be true."
580 )
581 }
582 (true, false) => {
583 let left_ub = other_lb
589 .as_ref()
590 .map(|lb| lb.clone().flip_bound_side_and_type());
591
592 Some(IntervalDifference::SingleConnected(
594 Interval::try_new(self_lb, left_ub)
595 .expect("Failed to create interval difference"),
596 ))
597 }
598 (false, true) => {
599 let right_lb = other_ub
605 .as_ref()
606 .map(|ub| ub.clone().flip_bound_side_and_type());
607
608 Some(IntervalDifference::SingleConnected(
609 Interval::try_new(right_lb, self_ub)
610 .expect("Failed to create interval difference"),
611 ))
612 }
613 (true, true) => {
614 let left_ub = other_lb
622 .as_ref()
623 .map(|lb| lb.clone().flip_bound_side_and_type());
624 let right_lb = other_ub
625 .as_ref()
626 .map(|ub| ub.clone().flip_bound_side_and_type());
627
628 let left = Interval::try_new(self_lb.clone(), left_ub)
632 .expect("Left interval is guaranteed valid when has_left_part = true");
633 let right = Interval::try_new(right_lb, self_ub.clone())
634 .expect("Right interval is guaranteed valid when has_right_part = true");
635 Some(IntervalDifference::TwoDisjoint { left, right })
636 }
637 }
638 }
639}
640#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
715#[serde(bound(deserialize = "RealType: for<'a> Deserialize<'a>"))]
716pub enum IntervalUnion<RealType: RealScalar> {
717 SingleConnected(Interval<RealType>),
722
723 TwoDisjoint {
729 left: Interval<RealType>,
731 right: Interval<RealType>,
733 },
734}
735
736#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
816#[serde(bound(deserialize = "RealType: for<'a> Deserialize<'a>"))]
817pub enum IntervalDifference<RealType: RealScalar> {
818 SingleConnected(Interval<RealType>),
823
824 TwoDisjoint {
830 left: Interval<RealType>,
832 right: Interval<RealType>,
834 },
835}
836
837#[duplicate_item(
839 EnumName contains_doc;
840 [IntervalUnion] ["contained in this union"];
841 [IntervalDifference] ["contained in this difference result"];
842)]
843impl<RealType: RealScalar> EnumName<RealType> {
844 pub fn is_single_connected(&self) -> bool {
846 matches!(self, Self::SingleConnected(_))
847 }
848
849 pub fn is_two_disjoint(&self) -> bool {
851 matches!(self, Self::TwoDisjoint { .. })
852 }
853
854 pub fn as_single_connected(&self) -> Option<&Interval<RealType>> {
856 match self {
857 Self::SingleConnected(interval) => Some(interval),
858 _ => None,
859 }
860 }
861
862 pub fn as_two_disjoint(&self) -> Option<(&Interval<RealType>, &Interval<RealType>)> {
864 match self {
865 Self::TwoDisjoint { left, right } => Some((left, right)),
866 _ => None,
867 }
868 }
869
870 #[doc = concat!("Checks if a point is ", contains_doc, ".")]
871 pub fn contains_point(&self, x: &RealType) -> bool {
872 match self {
873 Self::SingleConnected(interval) => interval.contains_point(x),
874 Self::TwoDisjoint { left, right } => left.contains_point(x) || right.contains_point(x),
875 }
876 }
877
878 pub fn gap(&self) -> Option<IntervalFinitePositiveLength<RealType>> {
884 match self {
885 Self::SingleConnected(_) => None,
886 Self::TwoDisjoint { left, right } => {
887 let left_ub = left
889 .upper_bound_runtime()
890 .expect("The left interval in a disjoint union cannot be unbounded above");
891 let right_lb = right
892 .lower_bound_runtime()
893 .expect("The right interval in a disjoint union cannot be unbounded below");
894
895 let lb = left_ub.flip_bound_side_and_type();
902 let ub = right_lb.flip_bound_side_and_type();
903
904 Some(
906 IntervalFinitePositiveLength::try_new(lb, ub)
907 .expect("Failed to create the interval representing the gap!"),
908 )
909 }
910 }
911 }
912
913 pub fn to_intervals(self) -> Vec<Interval<RealType>> {
940 match self {
941 Self::SingleConnected(interval) => vec![interval],
942 Self::TwoDisjoint { left, right } => vec![left, right],
943 }
944 }
945}
946
947impl<RealType: RealScalar> IntervalDifference<RealType> {}
1015#[cfg(test)]
1018mod tests {
1019 use super::*;
1020 use crate::{
1021 SubIntervalInPartition,
1022 intervals::{
1023 GetLowerBoundValue, GetUpperBoundValue, Interval, IntervalClosed,
1024 IntervalFinitePositiveLengthTrait, IntervalLowerClosedUpperOpen,
1025 IntervalLowerClosedUpperUnbounded, IntervalLowerOpenUpperClosed,
1026 IntervalLowerOpenUpperUnbounded, IntervalLowerUnboundedUpperClosed,
1027 IntervalLowerUnboundedUpperOpen, IntervalLowerUnboundedUpperUnbounded, IntervalOpen,
1028 IntervalSingleton,
1029 },
1030 };
1031 use num_valid::scalars::PositiveRealScalar;
1032 use try_create::{New, TryNew};
1033
1034 mod difference {
1035 use super::*;
1036
1037 #[test]
1038 fn difference_no_overlap() {
1039 let a = IntervalClosed::new(0.0, 2.0);
1042 let b = IntervalClosed::new(3.0, 5.0);
1043 let diff = a.difference(&b);
1044
1045 assert!(diff.is_some());
1046 match diff.unwrap() {
1047 IntervalDifference::SingleConnected(result) => {
1048 let expected: Interval<f64> = IntervalClosed::new(0.0, 2.0).into();
1049 assert_eq!(result, expected);
1050 }
1051 _ => panic!("Expected single interval"),
1052 }
1053 }
1054
1055 #[test]
1056 fn difference_partial_overlap_right() {
1057 let a = IntervalClosed::new(0.0, 3.0);
1060 let b = IntervalClosed::new(2.0, 5.0);
1061 let diff = a.difference(&b);
1062
1063 assert!(diff.is_some());
1064 match diff.unwrap() {
1065 IntervalDifference::SingleConnected(result) => {
1066 let expected: Interval<f64> =
1067 IntervalLowerClosedUpperOpen::new(0.0, 2.0).into();
1068 assert_eq!(result, expected);
1069 }
1070 _ => panic!("Expected single interval"),
1071 }
1072 }
1073
1074 #[test]
1075 fn difference_partial_overlap_left() {
1076 let a = IntervalClosed::new(2.0, 5.0);
1079 let b = IntervalClosed::new(0.0, 3.0);
1080 let diff = a.difference(&b);
1081
1082 assert!(diff.is_some());
1083 match diff.unwrap() {
1084 IntervalDifference::SingleConnected(result) => {
1085 let expected: Interval<f64> =
1086 IntervalLowerOpenUpperClosed::new(3.0, 5.0).into();
1087 assert_eq!(result, expected);
1088 }
1089 _ => panic!("Expected single interval"),
1090 }
1091 }
1092
1093 #[test]
1094 fn difference_complete_containment() {
1095 let a = IntervalClosed::new(1.0, 2.0);
1098 let b = IntervalClosed::new(0.0, 3.0);
1099 let diff = a.difference(&b);
1100
1101 assert!(diff.is_none());
1102 }
1103
1104 #[test]
1105 fn difference_interior_removal() {
1106 let a = IntervalClosed::new(0.0, 4.0);
1109 let b = IntervalOpen::new(1.0, 3.0);
1110 let diff = a.difference(&b);
1111
1112 assert!(diff.is_some());
1113 match diff.unwrap() {
1114 IntervalDifference::TwoDisjoint { left, right } => {
1115 let expected_left: Interval<f64> = IntervalClosed::new(0.0, 1.0).into();
1116 let expected_right: Interval<f64> = IntervalClosed::new(3.0, 4.0).into();
1117 assert_eq!(left, expected_left);
1118 assert_eq!(right, expected_right);
1119 }
1120 _ => panic!("Expected two disjoint intervals"),
1121 }
1122 }
1123
1124 #[test]
1125 fn difference_boundary_subtlety_open_closed() {
1126 let a = IntervalClosed::new(0.0, 2.0);
1129 let b = IntervalLowerOpenUpperClosed::new(1.0, 2.0);
1130 let diff = a.difference(&b);
1131
1132 assert!(diff.is_some());
1133 match diff.unwrap() {
1134 IntervalDifference::SingleConnected(result) => {
1135 let expected: Interval<f64> = IntervalClosed::new(0.0, 1.0).into();
1136 assert_eq!(result, expected);
1137 }
1138 _ => panic!("Expected single interval"),
1139 }
1140 }
1141
1142 #[test]
1143 fn difference_boundary_subtlety_closed_open() {
1144 let a = IntervalClosed::new(0.0, 2.0);
1147 let b = IntervalLowerClosedUpperOpen::new(1.0, 2.0);
1148 let diff = a.difference(&b);
1149
1150 assert!(diff.is_some());
1151 match diff.unwrap() {
1152 IntervalDifference::TwoDisjoint { left, right } => {
1153 let expected_left: Interval<f64> =
1154 IntervalLowerClosedUpperOpen::new(0.0, 1.0).into();
1155 let expected_right: Interval<f64> = IntervalSingleton::new(2.0).into();
1156 assert_eq!(left, expected_left);
1157 assert_eq!(right, expected_right);
1158 }
1159 _ => panic!("Expected two disjoint intervals"),
1160 }
1161 }
1162
1163 #[test]
1164 fn difference_with_unbounded_intervals() {
1165 let a = IntervalLowerClosedUpperUnbounded::new(0.0);
1168 let b = IntervalClosed::new(5.0, 10.0);
1169 let diff = a.difference(&b);
1170
1171 assert!(diff.is_some());
1172 match diff.unwrap() {
1173 IntervalDifference::TwoDisjoint { left, right } => {
1174 let expected_left: Interval<f64> =
1175 IntervalLowerClosedUpperOpen::new(0.0, 5.0).into();
1176 let expected_right: Interval<f64> =
1177 IntervalLowerOpenUpperUnbounded::new(10.0).into();
1178 assert_eq!(left, expected_left);
1179 assert_eq!(right, expected_right);
1180 }
1181 _ => panic!("Expected two disjoint intervals"),
1182 }
1183 }
1184
1185 #[test]
1186 fn difference_unbounded_minus_unbounded() {
1187 let a = IntervalLowerUnboundedUpperUnbounded::new();
1190 let b = IntervalClosed::new(0.0, 10.0);
1191 let diff = a.difference(&b);
1192
1193 assert!(diff.is_some());
1194 match diff.unwrap() {
1195 IntervalDifference::TwoDisjoint { left, right } => {
1196 let expected_left: Interval<f64> =
1197 IntervalLowerUnboundedUpperOpen::new(0.0).into();
1198 let expected_right: Interval<f64> =
1199 IntervalLowerOpenUpperUnbounded::new(10.0).into();
1200 assert_eq!(left, expected_left);
1201 assert_eq!(right, expected_right);
1202 }
1203 _ => panic!("Expected two disjoint intervals"),
1204 }
1205 }
1206
1207 #[test]
1208 fn difference_unbounded_complete_containment() {
1209 let a = IntervalClosed::new(5.0, 10.0);
1212 let b = IntervalLowerUnboundedUpperUnbounded::new();
1213 let diff = a.difference(&b);
1214
1215 assert!(diff.is_none());
1216 }
1217
1218 #[test]
1219 fn difference_unbounded_no_overlap() {
1220 let a = IntervalClosed::new(0.0, 5.0);
1223 let b = IntervalLowerClosedUpperUnbounded::new(10.0);
1224 let diff = a.difference(&b);
1225
1226 assert!(diff.is_some());
1227 match diff.unwrap() {
1228 IntervalDifference::SingleConnected(result) => {
1229 let expected: Interval<f64> = IntervalClosed::new(0.0, 5.0).into();
1230 assert_eq!(result, expected);
1231 }
1232 _ => panic!("Expected single interval"),
1233 }
1234 }
1235
1236 #[test]
1237 fn difference_with_singleton() {
1238 let a = IntervalClosed::new(0.0, 2.0);
1241 let b = IntervalSingleton::new(1.0);
1242 let diff = a.difference(&b);
1243
1244 assert!(diff.is_some());
1245 match diff.unwrap() {
1246 IntervalDifference::TwoDisjoint { left, right } => {
1247 let expected_left: Interval<f64> =
1248 IntervalLowerClosedUpperOpen::new(0.0, 1.0).into();
1249 let expected_right: Interval<f64> =
1250 IntervalLowerOpenUpperClosed::new(1.0, 2.0).into();
1251 assert_eq!(left, expected_left);
1252 assert_eq!(right, expected_right);
1253 }
1254 _ => panic!("Expected two disjoint intervals"),
1255 }
1256 }
1257
1258 #[test]
1259 fn difference_singleton_minus_interval() {
1260 let a = IntervalSingleton::new(1.0);
1263 let b = IntervalClosed::new(0.0, 2.0);
1264 let diff = a.difference(&b);
1265
1266 assert!(diff.is_none());
1267 }
1268
1269 #[test]
1270 fn difference_singleton_minus_non_overlapping() {
1271 let a = IntervalSingleton::new(5.0);
1274 let b = IntervalClosed::new(0.0, 2.0);
1275 let diff = a.difference(&b);
1276
1277 assert!(diff.is_some());
1278 match diff.unwrap() {
1279 IntervalDifference::SingleConnected(result) => {
1280 let expected: Interval<f64> = IntervalSingleton::new(5.0).into();
1281 assert_eq!(result, expected);
1282 }
1283 _ => panic!("Expected single interval"),
1284 }
1285 }
1286
1287 #[test]
1288 fn difference_identical_intervals() {
1289 let a = IntervalClosed::new(0.0, 1.0);
1292 let b = IntervalClosed::new(0.0, 1.0);
1293 let diff = a.difference(&b);
1294
1295 assert!(diff.is_none());
1296 }
1297
1298 #[test]
1299 fn difference_open_vs_closed_same_values() {
1300 let a = IntervalClosed::new(0.0, 2.0);
1303 let b = IntervalOpen::new(0.0, 2.0);
1304 let diff = a.difference(&b);
1305
1306 assert!(diff.is_some());
1307 match diff.unwrap() {
1308 IntervalDifference::TwoDisjoint { left, right } => {
1309 let expected_left: Interval<f64> = IntervalSingleton::new(0.0).into();
1310 let expected_right: Interval<f64> = IntervalSingleton::new(2.0).into();
1311 assert_eq!(left, expected_left);
1312 assert_eq!(right, expected_right);
1313 }
1314 _ => panic!("Expected two disjoint intervals (singletons at boundaries)"),
1315 }
1316 }
1317
1318 #[test]
1319 fn difference_contains_point_test() {
1320 let a = IntervalClosed::new(0.0, 4.0);
1323 let b = IntervalOpen::new(1.0, 3.0);
1324 let diff = a.difference(&b).unwrap();
1325
1326 assert!(diff.contains_point(&0.0));
1328 assert!(diff.contains_point(&0.5));
1329 assert!(diff.contains_point(&1.0));
1330
1331 assert!(!diff.contains_point(&1.5));
1333 assert!(!diff.contains_point(&2.0));
1334 assert!(!diff.contains_point(&2.5));
1335
1336 assert!(diff.contains_point(&3.0));
1338 assert!(diff.contains_point(&3.5));
1339 assert!(diff.contains_point(&4.0));
1340
1341 assert!(!diff.contains_point(&-1.0));
1343 assert!(!diff.contains_point(&5.0));
1344 }
1345
1346 #[test]
1347 fn difference_to_intervals_test() {
1348 let a = IntervalClosed::new(1.0, 2.0);
1350 let b = IntervalClosed::new(0.0, 3.0);
1351 let diff = a.difference(&b);
1352 assert!(diff.is_none());
1353
1354 let a = IntervalClosed::new(0.0, 2.0);
1356 let b = IntervalClosed::new(3.0, 5.0);
1357 let diff = a.difference(&b);
1358 assert!(diff.is_some());
1359 assert_eq!(diff.unwrap().to_intervals().len(), 1);
1360
1361 let a = IntervalClosed::new(0.0, 4.0);
1363 let b = IntervalOpen::new(1.0, 3.0);
1364 let diff = a.difference(&b);
1365 assert!(diff.is_some());
1366 assert_eq!(diff.unwrap().to_intervals().len(), 2);
1367 }
1368
1369 #[test]
1370 fn difference_helper_methods_test() {
1371 let a = IntervalClosed::new(0.0, 4.0);
1372 let b = IntervalOpen::new(1.0, 3.0);
1373 let diff = a.difference(&b).unwrap();
1374
1375 assert!(!diff.is_single_connected());
1376 assert!(diff.is_two_disjoint());
1377
1378 assert!(diff.as_single_connected().is_none());
1379 assert!(diff.as_two_disjoint().is_some());
1380
1381 let (left, right) = diff.as_two_disjoint().unwrap();
1382 assert!(left.contains_point(&0.5));
1383 assert!(right.contains_point(&3.5));
1384 }
1385
1386 #[test]
1387 fn difference_lower_unbounded_partial() {
1388 let a = IntervalLowerUnboundedUpperClosed::new(5.0);
1391 let b = IntervalClosed::new(0.0, 3.0);
1392 let diff = a.difference(&b);
1393
1394 assert!(diff.is_some());
1395 match diff.unwrap() {
1396 IntervalDifference::TwoDisjoint { left, right } => {
1397 let expected_left: Interval<f64> =
1398 IntervalLowerUnboundedUpperOpen::new(0.0).into();
1399 let expected_right: Interval<f64> =
1400 IntervalLowerOpenUpperClosed::new(3.0, 5.0).into();
1401 assert_eq!(left, expected_left);
1402 assert_eq!(right, expected_right);
1403 }
1404 _ => panic!("Expected two disjoint intervals"),
1405 }
1406 }
1407
1408 #[test]
1410 fn difference_open_open_no_overlap() {
1411 let a = IntervalOpen::new(0.0, 2.0);
1414 let b = IntervalOpen::new(3.0, 5.0);
1415 let diff = a.difference(&b);
1416
1417 assert!(diff.is_some());
1418 match diff.unwrap() {
1419 IntervalDifference::SingleConnected(result) => {
1420 let expected: Interval<f64> = IntervalOpen::new(0.0, 2.0).into();
1421 assert_eq!(result, expected);
1422 }
1423 _ => panic!("Expected single interval"),
1424 }
1425 }
1426
1427 #[test]
1429 fn difference_open_open_partial_overlap() {
1430 let a = IntervalOpen::new(0.0, 4.0);
1433 let b = IntervalOpen::new(2.0, 6.0);
1434 let diff = a.difference(&b);
1435
1436 assert!(diff.is_some());
1437 match diff.unwrap() {
1438 IntervalDifference::SingleConnected(result) => {
1439 let expected: Interval<f64> =
1440 IntervalLowerOpenUpperClosed::new(0.0, 2.0).into();
1441 assert_eq!(result, expected);
1442 }
1443 _ => panic!("Expected single interval"),
1444 }
1445 }
1446
1447 #[test]
1450 fn difference_degenerate_left_valid_right() {
1451 let a = IntervalClosed::new(0.0, 4.0);
1455 let b = IntervalLowerClosedUpperOpen::new(0.0, 2.0);
1456 let diff = a.difference(&b);
1457
1458 assert!(diff.is_some());
1459 match diff.unwrap() {
1460 IntervalDifference::SingleConnected(result) => {
1461 let expected: Interval<f64> = IntervalClosed::new(2.0, 4.0).into();
1462 assert_eq!(
1463 result, expected,
1464 "Should only have right part, left is degenerate"
1465 );
1466 }
1467 _ => panic!("Expected single interval (right part only)"),
1468 }
1469 }
1470
1471 #[test]
1474 fn difference_valid_left_degenerate_right() {
1475 let a = IntervalClosed::new(0.0, 4.0);
1479 let b = IntervalLowerOpenUpperClosed::new(2.0, 4.0);
1480 let diff = a.difference(&b);
1481
1482 assert!(diff.is_some());
1483 match diff.unwrap() {
1484 IntervalDifference::SingleConnected(result) => {
1485 let expected: Interval<f64> = IntervalClosed::new(0.0, 2.0).into();
1486 assert_eq!(
1487 result, expected,
1488 "Should only have left part, right is degenerate"
1489 );
1490 }
1491 _ => panic!("Expected single interval (left part only)"),
1492 }
1493 }
1494
1495 #[test]
1497 fn difference_singleton_same_value() {
1498 let a = IntervalSingleton::new(5.0);
1501 let b = IntervalSingleton::new(5.0);
1502 let diff = a.difference(&b);
1503
1504 assert!(
1505 diff.is_none(),
1506 "Expected None when subtracting identical singletons ({{5}} \\ {{5}} = ∅)"
1507 );
1508 }
1509
1510 #[test]
1512 fn difference_singleton_different_values() {
1513 let a = IntervalSingleton::new(3.0);
1516 let b = IntervalSingleton::new(7.0);
1517 let diff = a.difference(&b);
1518
1519 assert!(diff.is_some());
1520 match diff.unwrap() {
1521 IntervalDifference::SingleConnected(interval) => {
1522 let expected: Interval<f64> = IntervalSingleton::new(3.0).into();
1523 assert_eq!(
1524 interval, expected,
1525 "Expected {{3}} when singletons are disjoint"
1526 );
1527 }
1528 _ => panic!("Expected single singleton interval"),
1529 }
1530 }
1531
1532 #[test]
1534 fn difference_singleton_contained_in_interval() {
1535 let a = IntervalSingleton::new(5.0);
1538 let b = IntervalClosed::new(0.0, 10.0);
1539 let diff = a.difference(&b);
1540
1541 assert!(
1542 diff.is_none(),
1543 "Expected None when singleton is contained in interval"
1544 );
1545 }
1546
1547 #[test]
1549 fn difference_interval_minus_singleton_at_endpoint() {
1550 let a = IntervalClosed::new(0.0, 10.0);
1553 let b = IntervalSingleton::new(0.0);
1554 let diff = a.difference(&b);
1555
1556 assert!(diff.is_some());
1557 match diff.unwrap() {
1558 IntervalDifference::SingleConnected(interval) => {
1559 let expected: Interval<f64> =
1560 IntervalLowerOpenUpperClosed::new(0.0, 10.0).into();
1561 assert_eq!(
1562 interval, expected,
1563 "Expected (0, 10] when removing left endpoint singleton"
1564 );
1565 }
1566 _ => panic!("Expected single interval"),
1567 }
1568 }
1569
1570 #[test]
1572 fn difference_interval_minus_singleton_interior() {
1573 let a = IntervalClosed::new(0.0, 10.0);
1576 let b = IntervalSingleton::new(5.0);
1577 let diff = a.difference(&b);
1578
1579 assert!(diff.is_some());
1580 match diff.unwrap() {
1581 IntervalDifference::TwoDisjoint { left, right } => {
1582 let expected_left: Interval<f64> =
1583 IntervalLowerClosedUpperOpen::new(0.0, 5.0).into();
1584 let expected_right: Interval<f64> =
1585 IntervalLowerOpenUpperClosed::new(5.0, 10.0).into();
1586 assert_eq!(left, expected_left, "Expected [0, 5) as left part");
1587 assert_eq!(right, expected_right, "Expected (5, 10] as right part");
1588 }
1589 _ => panic!("Expected two disjoint intervals"),
1590 }
1591 }
1592
1593 #[test]
1595 fn difference_open_interval_minus_singleton_at_boundary() {
1596 let a = IntervalOpen::new(0.0, 10.0);
1599 let b = IntervalSingleton::new(0.0);
1600 let diff = a.difference(&b);
1601
1602 assert!(diff.is_some());
1603 match diff.unwrap() {
1604 IntervalDifference::SingleConnected(interval) => {
1605 let expected: Interval<f64> = IntervalOpen::new(0.0, 10.0).into();
1606 assert_eq!(
1607 interval, expected,
1608 "Expected (0, 10) unchanged since {{0}} is not in (0, 10)"
1609 );
1610 }
1611 _ => panic!("Expected single interval"),
1612 }
1613 }
1614
1615 #[test]
1617 fn difference_open_interior_removal() {
1618 let a = IntervalOpen::new(0.0, 6.0);
1621 let b = IntervalClosed::new(2.0, 4.0);
1622 let diff = a.difference(&b);
1623
1624 assert!(diff.is_some());
1625 match diff.unwrap() {
1626 IntervalDifference::TwoDisjoint { left, right } => {
1627 let expected_left: Interval<f64> = IntervalOpen::new(0.0, 2.0).into();
1628 let expected_right: Interval<f64> = IntervalOpen::new(4.0, 6.0).into();
1629 assert_eq!(left, expected_left);
1630 assert_eq!(right, expected_right);
1631 }
1632 _ => panic!("Expected two disjoint open intervals"),
1633 }
1634 }
1635
1636 #[test]
1638 fn difference_half_open_intervals() {
1639 let a = IntervalLowerClosedUpperOpen::new(0.0, 5.0);
1642 let b = IntervalLowerOpenUpperClosed::new(2.0, 4.0);
1643 let diff = a.difference(&b);
1644
1645 assert!(diff.is_some());
1646 match diff.unwrap() {
1647 IntervalDifference::TwoDisjoint { left, right } => {
1648 let expected_left: Interval<f64> = IntervalClosed::new(0.0, 2.0).into();
1649 let expected_right: Interval<f64> = IntervalOpen::new(4.0, 5.0).into();
1650 assert_eq!(left, expected_left);
1651 assert_eq!(right, expected_right);
1652 }
1653 _ => panic!("Expected two disjoint intervals with mixed bounds"),
1654 }
1655 }
1656
1657 #[test]
1659 fn difference_with_fully_unbounded_other() {
1660 let a = IntervalClosed::new(0.0, 5.0);
1663 let b = IntervalLowerUnboundedUpperUnbounded::new();
1664 let diff = a.difference(&b);
1665
1666 assert!(
1667 diff.is_none(),
1668 "Finite interval minus universal interval should be empty"
1669 );
1670 }
1671
1672 #[test]
1674 fn difference_unbounded_partial_overlap() {
1675 let a = IntervalLowerClosedUpperUnbounded::new(0.0);
1678 let b = IntervalLowerUnboundedUpperClosed::new(5.0);
1679 let diff = a.difference(&b);
1680
1681 assert!(diff.is_some());
1682 match diff.unwrap() {
1683 IntervalDifference::SingleConnected(result) => {
1684 let expected: Interval<f64> = IntervalLowerOpenUpperUnbounded::new(5.0).into();
1685 assert_eq!(result, expected);
1686 }
1687 _ => panic!("Expected single unbounded interval"),
1688 }
1689 }
1690
1691 #[test]
1692 fn difference_open_lower_unbounded_minus_finite() {
1693 let a = IntervalLowerUnboundedUpperOpen::new(5.0);
1696 let b = IntervalClosed::new(0.0, 3.0);
1697 let diff = a.difference(&b);
1698
1699 assert!(diff.is_some());
1700 match diff.unwrap() {
1701 IntervalDifference::TwoDisjoint { left, right } => {
1702 let expected_left: Interval<f64> =
1703 IntervalLowerUnboundedUpperOpen::new(0.0).into();
1704 let expected_right: Interval<f64> = IntervalOpen::new(3.0, 5.0).into();
1705 assert_eq!(left, expected_left);
1706 assert_eq!(right, expected_right);
1707 }
1708 _ => panic!("Expected two disjoint intervals"),
1709 }
1710 }
1711
1712 #[test]
1713 fn difference_open_upper_unbounded_minus_finite() {
1714 let a = IntervalLowerOpenUpperUnbounded::new(0.0);
1717 let b = IntervalClosed::new(5.0, 10.0);
1718 let diff = a.difference(&b);
1719
1720 assert!(diff.is_some());
1721 match diff.unwrap() {
1722 IntervalDifference::TwoDisjoint { left, right } => {
1723 let expected_left: Interval<f64> = IntervalOpen::new(0.0, 5.0).into();
1724 let expected_right: Interval<f64> =
1725 IntervalLowerOpenUpperUnbounded::new(10.0).into();
1726 assert_eq!(left, expected_left);
1727 assert_eq!(right, expected_right);
1728 }
1729 _ => panic!("Expected two disjoint intervals"),
1730 }
1731 }
1732
1733 #[test]
1734 fn difference_lower_unbounded_minus_open_finite() {
1735 let a = IntervalLowerUnboundedUpperClosed::new(10.0);
1738 let b = IntervalOpen::new(2.0, 5.0);
1739 let diff = a.difference(&b);
1740
1741 assert!(diff.is_some());
1742 match diff.unwrap() {
1743 IntervalDifference::TwoDisjoint { left, right } => {
1744 let expected_left: Interval<f64> =
1745 IntervalLowerUnboundedUpperClosed::new(2.0).into();
1746 let expected_right: Interval<f64> = IntervalClosed::new(5.0, 10.0).into();
1747 assert_eq!(left, expected_left);
1748 assert_eq!(right, expected_right);
1749 }
1750 _ => panic!("Expected two disjoint intervals"),
1751 }
1752 }
1753
1754 #[test]
1755 fn difference_upper_unbounded_minus_open_finite() {
1756 let a = IntervalLowerClosedUpperUnbounded::new(0.0);
1759 let b = IntervalOpen::new(5.0, 10.0);
1760 let diff = a.difference(&b);
1761
1762 assert!(diff.is_some());
1763 match diff.unwrap() {
1764 IntervalDifference::TwoDisjoint { left, right } => {
1765 let expected_left: Interval<f64> = IntervalClosed::new(0.0, 5.0).into();
1766 let expected_right: Interval<f64> =
1767 IntervalLowerClosedUpperUnbounded::new(10.0).into();
1768 assert_eq!(left, expected_left);
1769 assert_eq!(right, expected_right);
1770 }
1771 _ => panic!("Expected two disjoint intervals"),
1772 }
1773 }
1774
1775 #[test]
1776 fn difference_same_direction_upper_unbounded_disjoint() {
1777 let a = IntervalLowerClosedUpperUnbounded::new(0.0);
1780 let b = IntervalLowerClosedUpperUnbounded::new(10.0);
1781 let diff = a.difference(&b);
1782
1783 assert!(diff.is_some());
1784 match diff.unwrap() {
1785 IntervalDifference::SingleConnected(interval) => {
1786 let expected: Interval<f64> =
1787 IntervalLowerClosedUpperOpen::new(0.0, 10.0).into();
1788 assert_eq!(interval, expected);
1789 }
1790 _ => panic!("Expected single connected interval"),
1791 }
1792 }
1793
1794 #[test]
1795 fn difference_same_direction_upper_unbounded_overlap() {
1796 let a = IntervalLowerClosedUpperUnbounded::new(5.0);
1799 let b = IntervalLowerClosedUpperUnbounded::new(0.0);
1800 let diff = a.difference(&b);
1801
1802 assert!(diff.is_none());
1803 }
1804
1805 #[test]
1806 fn difference_same_direction_lower_unbounded_disjoint() {
1807 let a = IntervalLowerUnboundedUpperClosed::new(10.0);
1810 let b = IntervalLowerUnboundedUpperClosed::new(5.0);
1811 let diff = a.difference(&b);
1812
1813 assert!(diff.is_some());
1814 match diff.unwrap() {
1815 IntervalDifference::SingleConnected(interval) => {
1816 let expected: Interval<f64> =
1817 IntervalLowerOpenUpperClosed::new(5.0, 10.0).into();
1818 assert_eq!(interval, expected);
1819 }
1820 _ => panic!("Expected single connected interval"),
1821 }
1822 }
1823
1824 #[test]
1825 fn difference_same_direction_lower_unbounded_overlap() {
1826 let a = IntervalLowerUnboundedUpperClosed::new(5.0);
1829 let b = IntervalLowerUnboundedUpperClosed::new(10.0);
1830 let diff = a.difference(&b);
1831
1832 assert!(diff.is_none());
1833 }
1834
1835 #[test]
1836 fn difference_universal_minus_upper_unbounded() {
1837 let a = IntervalLowerUnboundedUpperUnbounded::new();
1840 let b = IntervalLowerClosedUpperUnbounded::new(5.0);
1841 let diff = a.difference(&b);
1842
1843 assert!(diff.is_some());
1844 match diff.unwrap() {
1845 IntervalDifference::SingleConnected(interval) => {
1846 let expected: Interval<f64> = IntervalLowerUnboundedUpperOpen::new(5.0).into();
1847 assert_eq!(interval, expected);
1848 }
1849 _ => panic!("Expected single connected interval"),
1850 }
1851 }
1852
1853 #[test]
1854 fn difference_universal_minus_lower_unbounded() {
1855 let a = IntervalLowerUnboundedUpperUnbounded::new();
1858 let b = IntervalLowerUnboundedUpperClosed::new(5.0);
1859 let diff = a.difference(&b);
1860
1861 assert!(diff.is_some());
1862 match diff.unwrap() {
1863 IntervalDifference::SingleConnected(interval) => {
1864 let expected: Interval<f64> = IntervalLowerOpenUpperUnbounded::new(5.0).into();
1865 assert_eq!(interval, expected);
1866 }
1867 _ => panic!("Expected single connected interval"),
1868 }
1869 }
1870
1871 #[test]
1872 fn difference_universal_minus_open_finite() {
1873 let a = IntervalLowerUnboundedUpperUnbounded::new();
1876 let b = IntervalOpen::new(0.0, 10.0);
1877 let diff = a.difference(&b);
1878
1879 assert!(diff.is_some());
1880 match diff.unwrap() {
1881 IntervalDifference::TwoDisjoint { left, right } => {
1882 let expected_left: Interval<f64> =
1883 IntervalLowerUnboundedUpperClosed::new(0.0).into();
1884 let expected_right: Interval<f64> =
1885 IntervalLowerClosedUpperUnbounded::new(10.0).into();
1886 assert_eq!(left, expected_left);
1887 assert_eq!(right, expected_right);
1888 }
1889 _ => panic!("Expected two disjoint intervals"),
1890 }
1891 }
1892
1893 #[test]
1894 fn difference_universal_minus_universal() {
1895 let a: IntervalLowerUnboundedUpperUnbounded<f64> =
1898 IntervalLowerUnboundedUpperUnbounded::new();
1899 let b: IntervalLowerUnboundedUpperUnbounded<f64> =
1900 IntervalLowerUnboundedUpperUnbounded::new();
1901 let diff = a.difference(&b);
1902
1903 assert!(diff.is_none());
1904 }
1905
1906 #[test]
1907 fn difference_finite_closed_minus_lower_unbounded_disjoint() {
1908 let a = IntervalClosed::new(10.0, 20.0);
1911 let b = IntervalLowerUnboundedUpperClosed::new(5.0);
1912 let diff = a.difference(&b);
1913
1914 assert!(diff.is_some());
1915 match diff.unwrap() {
1916 IntervalDifference::SingleConnected(interval) => {
1917 let expected: Interval<f64> = IntervalClosed::new(10.0, 20.0).into();
1918 assert_eq!(interval, expected);
1919 }
1920 _ => panic!("Expected single connected interval"),
1921 }
1922 }
1923
1924 #[test]
1925 fn difference_finite_closed_minus_lower_unbounded_overlap() {
1926 let a = IntervalClosed::new(0.0, 10.0);
1929 let b = IntervalLowerUnboundedUpperClosed::new(5.0);
1930 let diff = a.difference(&b);
1931
1932 assert!(diff.is_some());
1933 match diff.unwrap() {
1934 IntervalDifference::SingleConnected(interval) => {
1935 let expected: Interval<f64> =
1936 IntervalLowerOpenUpperClosed::new(5.0, 10.0).into();
1937 assert_eq!(interval, expected);
1938 }
1939 _ => panic!("Expected single connected interval"),
1940 }
1941 }
1942
1943 #[test]
1944 fn difference_finite_open_minus_upper_unbounded_disjoint() {
1945 let a = IntervalOpen::new(0.0, 5.0);
1948 let b = IntervalLowerClosedUpperUnbounded::new(10.0);
1949 let diff = a.difference(&b);
1950
1951 assert!(diff.is_some());
1952 match diff.unwrap() {
1953 IntervalDifference::SingleConnected(interval) => {
1954 let expected: Interval<f64> = IntervalOpen::new(0.0, 5.0).into();
1955 assert_eq!(interval, expected);
1956 }
1957 _ => panic!("Expected single connected interval"),
1958 }
1959 }
1960
1961 #[test]
1962 fn difference_finite_open_minus_lower_unbounded_overlap() {
1963 let a = IntervalOpen::new(0.0, 10.0);
1966 let b = IntervalLowerUnboundedUpperClosed::new(5.0);
1967 let diff = a.difference(&b);
1968
1969 assert!(diff.is_some());
1970 match diff.unwrap() {
1971 IntervalDifference::SingleConnected(interval) => {
1972 let expected: Interval<f64> = IntervalOpen::new(5.0, 10.0).into();
1973 assert_eq!(interval, expected);
1974 }
1975 _ => panic!("Expected single connected interval"),
1976 }
1977 }
1978
1979 #[test]
1980 fn difference_lower_unbounded_minus_upper_unbounded_disjoint() {
1981 let a = IntervalLowerUnboundedUpperClosed::new(5.0);
1984 let b = IntervalLowerClosedUpperUnbounded::new(10.0);
1985 let diff = a.difference(&b);
1986
1987 assert!(diff.is_some());
1988 match diff.unwrap() {
1989 IntervalDifference::SingleConnected(interval) => {
1990 let expected: Interval<f64> =
1991 IntervalLowerUnboundedUpperClosed::new(5.0).into();
1992 assert_eq!(interval, expected);
1993 }
1994 _ => panic!("Expected single connected interval"),
1995 }
1996 }
1997
1998 #[test]
1999 fn difference_lower_unbounded_minus_upper_unbounded_overlap() {
2000 let a = IntervalLowerUnboundedUpperClosed::new(10.0);
2003 let b = IntervalLowerClosedUpperUnbounded::new(5.0);
2004 let diff = a.difference(&b);
2005
2006 assert!(diff.is_some());
2007 match diff.unwrap() {
2008 IntervalDifference::SingleConnected(interval) => {
2009 let expected: Interval<f64> = IntervalLowerUnboundedUpperOpen::new(5.0).into();
2010 assert_eq!(interval, expected);
2011 }
2012 _ => panic!("Expected single connected interval"),
2013 }
2014 }
2015
2016 #[test]
2017 fn difference_none_half_open_contained() {
2018 let a = IntervalLowerClosedUpperOpen::new(1.0, 5.0);
2021 let b = IntervalClosed::new(0.0, 10.0);
2022 let diff = a.difference(&b);
2023
2024 assert!(
2025 diff.is_none(),
2026 "Expected None when interval is completely contained"
2027 );
2028 }
2029
2030 #[test]
2031 fn difference_none_open_interval_contained() {
2032 let a = IntervalOpen::new(2.0, 4.0);
2035 let b = IntervalClosed::new(2.0, 4.0);
2036 let diff = a.difference(&b);
2037
2038 assert!(
2039 diff.is_none(),
2040 "Expected None when open interval is contained in closed interval"
2041 );
2042 }
2043
2044 #[test]
2045 fn difference_none_identical_intervals() {
2046 let a = IntervalClosed::new(3.0, 7.0);
2049 let b = IntervalClosed::new(3.0, 7.0);
2050 let diff = a.difference(&b);
2051
2052 assert!(diff.is_none(), "Expected None when A = B (A \\ A = ∅)");
2053 }
2054
2055 #[test]
2056 fn difference_none_open_interval_subset() {
2057 let a = IntervalOpen::new(1.0, 3.0);
2060 let b = IntervalOpen::new(0.0, 5.0);
2061 let diff = a.difference(&b);
2062
2063 assert!(
2064 diff.is_none(),
2065 "Expected None when open interval is subset of another"
2066 );
2067 }
2068
2069 #[test]
2070 fn difference_none_lower_unbounded_contained() {
2071 let a = IntervalLowerUnboundedUpperClosed::new(5.0);
2074 let b = IntervalLowerUnboundedUpperClosed::new(10.0);
2075 let diff = a.difference(&b);
2076
2077 assert!(
2078 diff.is_none(),
2079 "Expected None when lower unbounded interval is subset"
2080 );
2081 }
2082
2083 #[test]
2084 fn difference_none_upper_unbounded_contained() {
2085 let a = IntervalLowerClosedUpperUnbounded::new(10.0);
2088 let b = IntervalLowerClosedUpperUnbounded::new(5.0);
2089 let diff = a.difference(&b);
2090
2091 assert!(
2092 diff.is_none(),
2093 "Expected None when upper unbounded interval is subset"
2094 );
2095 }
2096
2097 #[test]
2098 fn difference_none_mixed_boundaries_contained() {
2099 let a = IntervalOpen::new(2.0, 8.0);
2102 let b = IntervalClosed::new(1.0, 9.0);
2103 let diff = a.difference(&b);
2104
2105 assert!(
2106 diff.is_none(),
2107 "Expected None when interval with open boundaries is contained"
2108 );
2109 }
2110 }
2111
2112 mod intersection {
2113 use super::*;
2114
2115 #[test]
2116 fn intersection_closed_closed() {
2117 let a = IntervalClosed::new(0.0, 2.0);
2118 let b = IntervalClosed::new(1.0, 3.0);
2119 let intersection = a.intersection(&b).unwrap();
2120 let expected_intersection =
2121 Interval::FiniteLength(IntervalFiniteLength::PositiveLength(
2122 IntervalFinitePositiveLength::from(IntervalClosed::new(1.0, 2.0)),
2123 ));
2124 assert_eq!(intersection, expected_intersection);
2125 }
2126
2127 #[test]
2128 fn intersection_closed_open() {
2129 let a = IntervalClosed::new(0.0, 2.0);
2130 let b = IntervalOpen::new(1.0, 3.0);
2131 let intersection = a.intersection(&b).unwrap();
2132 let expected_intersection =
2133 Interval::FiniteLength(IntervalFiniteLength::PositiveLength(
2134 IntervalFinitePositiveLength::from(IntervalLowerOpenUpperClosed::new(1.0, 2.0)),
2135 ));
2136 assert_eq!(intersection, expected_intersection);
2137 }
2138
2139 #[test]
2140 fn intersection_open_open() {
2141 let a = IntervalOpen::new(0.0, 2.0);
2142 let b = IntervalOpen::new(1.0, 3.0);
2143 let intersection = a.intersection(&b).unwrap();
2144 let expected_intersection =
2145 Interval::FiniteLength(IntervalFiniteLength::PositiveLength(
2146 IntervalFinitePositiveLength::from(IntervalOpen::new(1.0, 2.0)),
2147 ));
2148 assert_eq!(intersection, expected_intersection);
2149 }
2150
2151 #[test]
2152 fn intersection_closed_left_half_open() {
2153 let a = IntervalClosed::new(0.0, 2.0);
2154 let b = IntervalLowerOpenUpperClosed::new(1.0, 3.0);
2155 let intersection = a.intersection(&b).unwrap();
2156 let expected_intersection =
2157 Interval::FiniteLength(IntervalFiniteLength::PositiveLength(
2158 IntervalFinitePositiveLength::from(IntervalLowerOpenUpperClosed::new(1.0, 2.0)),
2159 ));
2160 assert_eq!(intersection, expected_intersection);
2161 }
2162
2163 #[test]
2164 fn intersection_closed_right_half_open() {
2165 let a = IntervalClosed::new(0.0, 2.0);
2166 let b = IntervalLowerClosedUpperOpen::new(1.0, 3.0);
2167 let intersection = a.intersection(&b).unwrap();
2168 let expected_intersection =
2169 Interval::FiniteLength(IntervalFiniteLength::PositiveLength(
2170 IntervalFinitePositiveLength::from(IntervalClosed::new(1.0, 2.0)),
2171 ));
2172 assert_eq!(intersection, expected_intersection);
2173 }
2174
2175 #[test]
2176 fn intersection_singleton_closed() {
2177 let a = IntervalSingleton::new(1.0);
2178 let b = IntervalClosed::new(0.0, 2.0);
2179 let intersection = a.intersection(&b).unwrap();
2180 let expected_intersection = Interval::FiniteLength(IntervalFiniteLength::from(a));
2181 assert_eq!(intersection, expected_intersection);
2182 }
2183
2184 #[test]
2185 fn intersection_open_left_half_open() {
2186 let a = IntervalOpen::new(0.0, 2.0);
2187 let b = IntervalLowerOpenUpperClosed::new(1.0, 3.0);
2188 let intersection = a.intersection(&b).unwrap();
2189 let expected_intersection =
2190 Interval::FiniteLength(IntervalFiniteLength::PositiveLength(
2191 IntervalFinitePositiveLength::from(IntervalOpen::new(1.0, 2.0)),
2192 ));
2193 assert_eq!(intersection, expected_intersection);
2194 }
2195
2196 #[test]
2197 fn intersection_left_half_open_right_half_open() {
2198 let a = IntervalLowerOpenUpperClosed::new(0.0, 2.0);
2199 let b = IntervalLowerClosedUpperOpen::new(1.0, 3.0);
2200 let intersection = a.intersection(&b).unwrap();
2201 let expected_intersection =
2202 Interval::FiniteLength(IntervalFiniteLength::PositiveLength(
2203 IntervalFinitePositiveLength::from(IntervalClosed::new(1.0, 2.0)),
2204 ));
2205 assert_eq!(intersection, expected_intersection);
2206 }
2207
2208 #[test]
2209 fn intersection_disjoint() {
2210 let a = IntervalClosed::new(0.0, 1.0);
2211 let b = IntervalClosed::new(2.0, 3.0);
2212 let intersection = a.intersection(&b);
2213 assert!(intersection.is_none());
2214 }
2215
2216 #[test]
2219 fn intersection_disjoint_open_open() {
2220 let a = IntervalOpen::new(0.0, 1.0);
2222 let b = IntervalOpen::new(2.0, 3.0);
2223 let intersection = a.intersection(&b);
2224 assert!(
2225 intersection.is_none(),
2226 "Disjoint open intervals should have empty intersection"
2227 );
2228 }
2229
2230 #[test]
2233 fn intersection_open_open_touching_boundary() {
2234 let a = IntervalOpen::new(0.0, 1.0);
2236 let b = IntervalOpen::new(1.0, 2.0);
2237 let intersection = a.intersection(&b);
2238 assert!(
2239 intersection.is_none(),
2240 "Open intervals touching at boundary should have empty intersection"
2241 );
2242 }
2243
2244 #[test]
2245 fn intersection_singleton_open() {
2246 let a = IntervalSingleton::new(1.0);
2247 let b = IntervalOpen::new(0.0, 2.0);
2248 let intersection = a.intersection(&b).unwrap();
2249 let expected_intersection = Interval::FiniteLength(IntervalFiniteLength::from(a));
2250 assert_eq!(intersection, expected_intersection);
2251 }
2252
2253 #[test]
2254 fn intersection_unbounded_closed() {
2255 let a = IntervalInfiniteLength::LowerUnboundedUpperUnbounded(
2256 IntervalLowerUnboundedUpperUnbounded::new(),
2257 );
2258 let b = IntervalClosed::new(0.0, 2.0);
2259 let intersection = a.intersection(&b).unwrap();
2260 let expected_intersection = Interval::FiniteLength(
2261 IntervalFiniteLength::PositiveLength(IntervalFinitePositiveLength::from(b)),
2262 );
2263 assert_eq!(intersection, expected_intersection);
2264 }
2265
2266 #[test]
2267 fn intersection_unbounded_unbounded() {
2268 let a = IntervalInfiniteLength::<f64>::LowerUnboundedUpperUnbounded(
2269 IntervalLowerUnboundedUpperUnbounded::new(),
2270 );
2271 let b = IntervalInfiniteLength::<f64>::LowerUnboundedUpperUnbounded(
2272 IntervalLowerUnboundedUpperUnbounded::new(),
2273 );
2274 let intersection = a.intersection(&b).unwrap();
2275 let expected_intersection =
2276 Interval::InfiniteLength(IntervalInfiniteLength::LowerUnboundedUpperUnbounded(
2277 IntervalLowerUnboundedUpperUnbounded::new(),
2278 ));
2279 assert_eq!(intersection, expected_intersection);
2280 }
2281
2282 #[test]
2283 fn intersection_subintervals() {
2284 let a =
2285 SubIntervalInPartition::<IntervalClosed<f64>>::First(IntervalClosed::new(0.0, 2.0));
2286 let b = SubIntervalInPartition::<IntervalClosed<f64>>::Last(
2287 IntervalLowerOpenUpperClosed::new(1.0, 2.0),
2288 );
2289 let intersection = a.intersection(&b).unwrap();
2290 let expected_intersection =
2291 Interval::FiniteLength(IntervalFiniteLength::PositiveLength(
2292 IntervalFinitePositiveLength::from(IntervalLowerOpenUpperClosed::new(1.0, 2.0)),
2293 ));
2294 assert_eq!(intersection, expected_intersection);
2295 }
2296
2297 #[test]
2298 fn intersection_none() {
2299 let i1 = IntervalClosed::new(0.0, 1.0);
2300 let i2 = IntervalClosed::new(2.0, 3.0);
2301 assert!(i1.intersection(&i2).is_none());
2302 }
2303
2304 #[test]
2305 fn intersection_singleton() {
2306 let i1 = IntervalClosed::new(0.0, 1.0);
2307 let i2 = IntervalClosed::new(1.0, 2.0);
2308 let intersection = i1.intersection(&i2).unwrap();
2309 let expected_intersection =
2310 Interval::FiniteLength(IntervalFiniteLength::from(IntervalSingleton::new(1.0)));
2311 assert_eq!(intersection, expected_intersection);
2312 }
2313
2314 #[test]
2315 fn intersection_01() {
2316 let lower_bound = 0.;
2317 let upper_bound_0 = 1.;
2318 let upper_bound_1 = 0.5;
2319
2320 let closed_0 = IntervalClosed::new(lower_bound, upper_bound_0); let closed_1 = IntervalClosed::new(lower_bound, upper_bound_1); let i0: IntervalFinitePositiveLength<_> = closed_0
2324 .intersection(&closed_1)
2325 .unwrap()
2326 .try_into()
2327 .unwrap(); assert_eq!(i0.lower_bound_value(), &0.);
2329 assert_eq!(i0.upper_bound_value(), &0.5);
2330
2331 let open_1 = IntervalOpen::new(lower_bound, upper_bound_1); let i1: IntervalFinitePositiveLength<_> =
2334 closed_0.intersection(&open_1).unwrap().try_into().unwrap(); assert_eq!(i1.lower_bound_value(), &0.);
2336 assert_eq!(i1.upper_bound_value(), &0.5);
2337
2338 let singleton_1 = IntervalSingleton::new(lower_bound); let i2 = singleton_1.intersection(&closed_1).unwrap();
2341 match i2 {
2342 Interval::InfiniteLength(_) => panic!("The interval should be a singleton!"),
2343 Interval::FiniteLength(interval_finite_length) => match interval_finite_length {
2344 IntervalFiniteLength::PositiveLength(_) => {
2345 panic!("The interval should be a singleton!")
2346 }
2347 IntervalFiniteLength::ZeroLength(ref singleton) => {
2348 assert_eq!(singleton.value(), &0.);
2349 }
2350 },
2351 };
2352
2353 let i3 = singleton_1.intersection(&open_1);
2354 assert!(i3.is_none());
2355 }
2356
2357 #[test]
2358 fn intersection_02() {
2359 let lower_bound = 0.;
2360 let upper_bound = 0.5;
2361
2362 let open_1 = IntervalOpen::new(lower_bound, upper_bound);
2363 let singleton_1 = IntervalSingleton::new(lower_bound);
2364
2365 let i3 = singleton_1.intersection(&open_1);
2366 assert!(i3.is_none());
2367 }
2368
2369 #[test]
2372 fn intersection_unbounded_lower_open_upper() {
2373 let a = IntervalLowerUnboundedUpperOpen::new(5.0);
2375 let b = IntervalClosed::new(0.0, 10.0);
2376
2377 let intersection = a.intersection(&b).unwrap();
2378
2379 match intersection {
2380 Interval::FiniteLength(IntervalFiniteLength::PositiveLength(
2381 IntervalFinitePositiveLength::LowerClosedUpperOpen(interval),
2382 )) => {
2383 assert_eq!(interval.lower_bound_value(), &0.0);
2384 assert_eq!(interval.upper_bound_value(), &5.0);
2385 }
2386 _ => panic!("Expected [0.0, 5.0) interval"),
2387 }
2388 }
2389
2390 #[test]
2392 fn intersection_unbounded_lower_open_upper_disjoint() {
2393 let a = IntervalLowerUnboundedUpperOpen::new(0.0);
2395 let b = IntervalClosed::new(1.0, 10.0);
2396
2397 let intersection = a.intersection(&b);
2398 assert!(intersection.is_none());
2399 }
2400
2401 #[test]
2404 fn intersection_unbounded_lower_closed_upper() {
2405 let a = IntervalLowerUnboundedUpperClosed::new(5.0);
2407 let b = IntervalClosed::new(0.0, 10.0);
2408
2409 let intersection = a.intersection(&b).unwrap();
2410
2411 match intersection {
2412 Interval::FiniteLength(IntervalFiniteLength::PositiveLength(
2413 IntervalFinitePositiveLength::Closed(interval),
2414 )) => {
2415 assert_eq!(interval.lower_bound_value(), &0.0);
2416 assert_eq!(interval.upper_bound_value(), &5.0);
2417 }
2418 _ => panic!("Expected [0.0, 5.0] interval"),
2419 }
2420 }
2421
2422 #[test]
2425 fn intersection_open_lower_unbounded_upper() {
2426 let a = IntervalLowerOpenUpperUnbounded::new(3.0);
2428 let b = IntervalClosed::new(0.0, 10.0);
2429
2430 let intersection = a.intersection(&b).unwrap();
2431
2432 match intersection {
2433 Interval::FiniteLength(IntervalFiniteLength::PositiveLength(
2434 IntervalFinitePositiveLength::LowerOpenUpperClosed(interval),
2435 )) => {
2436 assert_eq!(interval.lower_bound_value(), &3.0);
2437 assert_eq!(interval.upper_bound_value(), &10.0);
2438 }
2439 _ => panic!("Expected (3.0, 10.0] interval"),
2440 }
2441 }
2442
2443 #[test]
2445 fn intersection_open_lower_unbounded_upper_disjoint() {
2446 let a = IntervalLowerOpenUpperUnbounded::new(10.0);
2448 let b = IntervalClosed::new(0.0, 5.0);
2449
2450 let intersection = a.intersection(&b);
2451 assert!(intersection.is_none());
2452 }
2453
2454 #[test]
2457 fn intersection_closed_lower_unbounded_upper() {
2458 let a = IntervalLowerClosedUpperUnbounded::new(3.0);
2460 let b = IntervalClosed::new(0.0, 10.0);
2461
2462 let intersection = a.intersection(&b).unwrap();
2463
2464 match intersection {
2465 Interval::FiniteLength(IntervalFiniteLength::PositiveLength(
2466 IntervalFinitePositiveLength::Closed(interval),
2467 )) => {
2468 assert_eq!(interval.lower_bound_value(), &3.0);
2469 assert_eq!(interval.upper_bound_value(), &10.0);
2470 }
2471 _ => panic!("Expected [3.0, 10.0] interval"),
2472 }
2473 }
2474
2475 #[test]
2477 fn intersection_half_unbounded_both() {
2478 let a = IntervalLowerClosedUpperUnbounded::new(3.0);
2480 let b = IntervalLowerUnboundedUpperClosed::new(10.0);
2481
2482 let intersection = a.intersection(&b).unwrap();
2483
2484 match intersection {
2485 Interval::FiniteLength(IntervalFiniteLength::PositiveLength(
2486 IntervalFinitePositiveLength::Closed(interval),
2487 )) => {
2488 assert_eq!(interval.lower_bound_value(), &3.0);
2489 assert_eq!(interval.upper_bound_value(), &10.0);
2490 }
2491 _ => panic!("Expected [3.0, 10.0] interval"),
2492 }
2493 }
2494
2495 #[test]
2497 fn intersection_half_unbounded_both_open() {
2498 let a = IntervalLowerOpenUpperUnbounded::new(3.0);
2500 let b = IntervalLowerUnboundedUpperOpen::new(10.0);
2501
2502 let intersection = a.intersection(&b).unwrap();
2503
2504 match intersection {
2505 Interval::FiniteLength(IntervalFiniteLength::PositiveLength(
2506 IntervalFinitePositiveLength::Open(interval),
2507 )) => {
2508 assert_eq!(interval.lower_bound_value(), &3.0);
2509 assert_eq!(interval.upper_bound_value(), &10.0);
2510 }
2511 _ => panic!("Expected (3.0, 10.0) interval"),
2512 }
2513 }
2514
2515 #[test]
2517 fn intersection_half_unbounded_disjoint() {
2518 let a = IntervalLowerClosedUpperUnbounded::new(10.0);
2520 let b = IntervalLowerUnboundedUpperClosed::new(5.0);
2521
2522 let intersection = a.intersection(&b);
2523 assert!(intersection.is_none());
2524 }
2525
2526 #[test]
2528 fn intersection_preserves_unbounded_lower_closed() {
2529 let a = IntervalLowerUnboundedUpperClosed::new(10.0);
2531 let b = IntervalLowerUnboundedUpperClosed::new(5.0);
2532
2533 let intersection = a.intersection(&b).unwrap();
2534
2535 match intersection {
2536 Interval::InfiniteLength(IntervalInfiniteLength::LowerUnboundedUpperClosed(
2537 interval,
2538 )) => {
2539 assert_eq!(interval.upper_bound_value(), &5.0);
2540 }
2541 _ => panic!("Expected (-∞, 5.0] interval"),
2542 }
2543 }
2544
2545 #[test]
2547 fn intersection_preserves_unbounded_lower_open() {
2548 let a = IntervalLowerUnboundedUpperOpen::new(10.0);
2550 let b = IntervalLowerUnboundedUpperOpen::new(5.0);
2551
2552 let intersection = a.intersection(&b).unwrap();
2553
2554 match intersection {
2555 Interval::InfiniteLength(IntervalInfiniteLength::LowerUnboundedUpperOpen(
2556 interval,
2557 )) => {
2558 assert_eq!(interval.upper_bound_value(), &5.0);
2559 }
2560 _ => panic!("Expected (-∞, 5.0) interval"),
2561 }
2562 }
2563
2564 #[test]
2566 fn intersection_preserves_closed_lower_unbounded() {
2567 let a = IntervalLowerClosedUpperUnbounded::new(5.0);
2569 let b = IntervalLowerClosedUpperUnbounded::new(3.0);
2570
2571 let intersection = a.intersection(&b).unwrap();
2572
2573 match intersection {
2574 Interval::InfiniteLength(IntervalInfiniteLength::LowerClosedUpperUnbounded(
2575 interval,
2576 )) => {
2577 assert_eq!(interval.lower_bound_value(), &5.0);
2578 }
2579 _ => panic!("Expected [5.0, +∞) interval"),
2580 }
2581 }
2582
2583 #[test]
2585 fn intersection_preserves_open_lower_unbounded() {
2586 let a = IntervalLowerOpenUpperUnbounded::new(5.0);
2588 let b = IntervalLowerOpenUpperUnbounded::new(3.0);
2589
2590 let intersection = a.intersection(&b).unwrap();
2591
2592 match intersection {
2593 Interval::InfiniteLength(IntervalInfiniteLength::LowerOpenUpperUnbounded(
2594 interval,
2595 )) => {
2596 assert_eq!(interval.lower_bound_value(), &5.0);
2597 }
2598 _ => panic!("Expected (5.0, +∞) interval"),
2599 }
2600 }
2601 }
2602
2603 mod union {
2604 use super::*;
2605 use crate::intervals::{
2606 Interval, IntervalClosed, IntervalLowerClosedUpperOpen, IntervalLowerOpenUpperClosed,
2607 IntervalOpen, IntervalSingleton,
2608 };
2609 use try_create::New;
2610
2611 #[test]
2612 fn union_disjoint() {
2613 let i1 = IntervalClosed::new(0.0, 1.0);
2614 let i2 = IntervalClosed::new(2.0, 3.0);
2615 let union = i1.union(&i2);
2616 if let IntervalUnion::TwoDisjoint { left, right } = union {
2617 assert_eq!(left, i1.into());
2618 assert_eq!(right, i2.into());
2619 } else {
2620 panic!("Expected disjoint union");
2621 }
2622 }
2623
2624 #[test]
2627 fn union_disjoint_self_on_right() {
2628 let i1 = IntervalClosed::new(3.0, 4.0); let i2 = IntervalClosed::new(0.0, 1.0); let union = i1.union(&i2);
2633
2634 let i1_interval: Interval<_> = i1.into();
2636 let i2_interval: Interval<_> = i2.into();
2637
2638 if let IntervalUnion::TwoDisjoint {
2640 ref left,
2641 ref right,
2642 } = union
2643 {
2644 assert_eq!(left, &i2_interval, "Left should be the interval [0.0, 1.0]");
2646 assert_eq!(
2648 right, &i1_interval,
2649 "Right should be the interval [3.0, 4.0]"
2650 );
2651 } else {
2652 panic!("Expected disjoint union");
2653 }
2654
2655 let i1 = IntervalClosed::new(3.0, 4.0);
2657 let i2 = IntervalClosed::new(0.0, 1.0);
2658 let union_reversed = i2.union(&i1);
2659 assert_eq!(union, union_reversed, "Union should be commutative");
2660 }
2661
2662 #[test]
2664 fn union_disjoint_open_self_on_right() {
2665 let i1 = IntervalOpen::new(5.0, 6.0); let i2 = IntervalOpen::new(1.0, 2.0); let union = i1.union(&i2);
2669
2670 assert!(union.is_two_disjoint(), "Should be two disjoint intervals");
2671
2672 let gap = union.gap();
2674 assert!(gap.is_some(), "Should have a gap");
2675 if let Some(ref gap_interval) = gap {
2676 assert!(gap_interval.contains_point(&3.0), "Gap should contain 3.0");
2677 assert!(
2678 gap_interval.contains_point(&2.0),
2679 "Gap should include lower boundary"
2680 );
2681 assert!(
2682 gap_interval.contains_point(&5.0),
2683 "Gap should include upper boundary"
2684 );
2685 }
2686
2687 let i1_interval: Interval<_> = i1.into();
2689 let i2_interval: Interval<_> = i2.into();
2690
2691 if let IntervalUnion::TwoDisjoint { left, right } = union {
2692 assert_eq!(left, i2_interval, "Left should be (1.0, 2.0)");
2694 assert_eq!(right, i1_interval, "Right should be (5.0, 6.0)");
2695 } else {
2696 panic!("Expected TwoDisjoint variant");
2697 }
2698 }
2699
2700 #[test]
2701 fn union_overlapping() {
2702 let i1 = IntervalClosed::new(0.0, 2.0);
2703 let i2 = IntervalClosed::new(1.0, 3.0);
2704 let union = i1.union(&i2);
2705 let expected: Interval<f64> = IntervalClosed::new(0.0, 3.0).into();
2706 if let IntervalUnion::SingleConnected(connected) = union {
2707 assert_eq!(connected, expected);
2708 } else {
2709 panic!("Expected connected union");
2710 }
2711 }
2712
2713 #[test]
2714 fn union_adjacent_closed_open() {
2715 let i1 = IntervalClosed::new(0.0, 1.0);
2716 let i2 = IntervalOpen::new(1.0, 2.0);
2717 let union = i1.union(&i2);
2718 assert!(union.is_single_connected());
2719
2720 let expected: Interval<f64> = IntervalLowerClosedUpperOpen::new(0.0, 2.0).into();
2721 if let IntervalUnion::SingleConnected(connected) = union {
2722 assert_eq!(connected, expected);
2723 } else {
2724 panic!("Expected connected union");
2725 }
2726 }
2727
2728 #[test]
2729 fn union_adjacent_open_closed() {
2730 let i1 = IntervalOpen::new(0.0, 1.0);
2731 let i2 = IntervalClosed::new(1.0, 2.0);
2732 let union = i1.union(&i2);
2733 assert!(union.is_single_connected());
2734
2735 let expected: Interval<f64> = IntervalLowerOpenUpperClosed::new(0.0, 2.0).into();
2736 if let IntervalUnion::SingleConnected(ref connected) = union {
2737 assert_eq!(connected, &expected);
2738 } else {
2739 panic!("Expected connected union");
2740 }
2741
2742 let connected = union.as_single_connected().unwrap();
2743 assert_eq!(connected, &expected);
2744
2745 assert!(union.as_two_disjoint().is_none());
2746
2747 assert!(union.contains_point(&1.0));
2748 }
2749
2750 #[test]
2751 fn union_adjacent_open_open() {
2752 let i1 = IntervalOpen::new(0.0, 1.0);
2753 let i2 = IntervalOpen::new(1.0, 2.0);
2754 let union = i1.union(&i2);
2755 assert!(union.is_two_disjoint());
2756
2757 let i1: Interval<_> = i1.into();
2758 let i2: Interval<_> = i2.into();
2759
2760 if let IntervalUnion::TwoDisjoint {
2761 ref left,
2762 ref right,
2763 } = union
2764 {
2765 assert_eq!(left, &i1);
2766 assert_eq!(right, &i2);
2767 } else {
2768 panic!("Expected disjoint union because of the gap at 1.0");
2769 }
2770
2771 let (left, right) = union.as_two_disjoint().unwrap();
2772 assert_eq!(left, &i1);
2773 assert_eq!(right, &i2);
2774
2775 assert!(union.as_single_connected().is_none());
2776
2777 assert!(!union.contains_point(&1.0));
2778 }
2779
2780 #[test]
2783 fn union_disjoint_open_open() {
2784 let i1 = IntervalOpen::new(0.0, 1.0);
2786 let i2 = IntervalOpen::new(3.0, 4.0);
2787 let union = i1.union(&i2);
2788
2789 assert!(union.is_two_disjoint(), "Expected two disjoint intervals");
2790
2791 let gap = union.gap();
2793 assert!(
2794 gap.is_some(),
2795 "Should have a gap between disjoint intervals"
2796 );
2797
2798 if let Some(ref gap_interval) = gap {
2799 assert!(
2801 gap_interval.contains_point(&2.0),
2802 "Gap should contain point 2.0"
2803 );
2804 assert!(
2805 gap_interval.contains_point(&1.0),
2806 "Gap should include lower boundary 1.0"
2807 );
2808 assert!(
2809 gap_interval.contains_point(&3.0),
2810 "Gap should include upper boundary 3.0"
2811 );
2812 assert!(
2813 !gap_interval.contains_point(&0.5),
2814 "Gap should not contain points in left interval"
2815 );
2816 assert!(
2817 !gap_interval.contains_point(&3.5),
2818 "Gap should not contain points in right interval"
2819 );
2820 }
2821
2822 let i1_interval: Interval<_> = i1.into();
2824 let i2_interval: Interval<_> = i2.into();
2825
2826 if let IntervalUnion::TwoDisjoint { left, right } = union {
2827 assert_eq!(left, i1_interval);
2828 assert_eq!(right, i2_interval);
2829 } else {
2830 panic!("Expected TwoDisjoint variant");
2831 }
2832
2833 let i1 = IntervalOpen::new(0.0, 1.0);
2835 let i2 = IntervalOpen::new(3.0, 4.0);
2836 let union = i1.union(&i2);
2837 assert!(
2838 union.contains_point(&0.5),
2839 "Should contain point in first interval"
2840 );
2841 assert!(
2842 union.contains_point(&3.5),
2843 "Should contain point in second interval"
2844 );
2845 assert!(
2846 !union.contains_point(&2.0),
2847 "Should not contain point in gap"
2848 );
2849 assert!(
2850 !union.contains_point(&1.0),
2851 "Should not contain excluded boundary"
2852 );
2853 assert!(
2854 !union.contains_point(&3.0),
2855 "Should not contain excluded boundary"
2856 );
2857 }
2858
2859 #[test]
2861 fn union_disjoint_open_half_open() {
2862 let i1 = IntervalOpen::new(0.0, 1.0);
2864 let i2 = IntervalLowerClosedUpperOpen::new(2.0, 3.0);
2865 let union = i1.union(&i2);
2866
2867 assert!(union.is_two_disjoint());
2868
2869 if let IntervalUnion::TwoDisjoint { left, right } = union {
2870 assert_eq!(left, i1.into());
2871 assert_eq!(right, i2.into());
2872 } else {
2873 panic!("Expected disjoint union");
2874 }
2875 }
2876
2877 #[test]
2878 fn union_one_contains_other() {
2879 let i1 = IntervalClosed::new(0.0, 3.0);
2880 let i2 = IntervalClosed::new(1.0, 2.0);
2881 let union = i1.union(&i2);
2882 if let IntervalUnion::SingleConnected(connected) = union {
2883 assert_eq!(connected, i1.into());
2884 } else {
2885 panic!("Expected connected union");
2886 }
2887 }
2888
2889 #[test]
2890 fn union_with_singleton_inside() {
2891 let i1 = IntervalClosed::new(0.0, 2.0);
2892 let i2 = IntervalSingleton::new(1.0);
2893 let union = i1.union(&i2);
2894 if let IntervalUnion::SingleConnected(connected) = union {
2895 assert_eq!(connected, i1.into());
2896 } else {
2897 panic!("Expected connected union");
2898 }
2899 }
2900
2901 #[test]
2902 fn union_with_singleton_at_boundary_closed() {
2903 let i1 = IntervalClosed::new(0.0, 1.0);
2904 let i2 = IntervalSingleton::new(1.0);
2905 let union = i1.union(&i2);
2906 if let IntervalUnion::SingleConnected(connected) = union {
2907 assert_eq!(connected, i1.into());
2908 } else {
2909 panic!("Expected connected union");
2910 }
2911 }
2912
2913 #[test]
2914 fn union_with_singleton_at_boundary_open() {
2915 let i1 = IntervalLowerClosedUpperOpen::new(0.0, 1.0);
2916 let i2 = IntervalSingleton::new(1.0);
2917 let union = i1.union(&i2);
2918 let expected: Interval<f64> = IntervalClosed::new(0.0, 1.0).into();
2919 if let IntervalUnion::SingleConnected(connected) = union {
2920 assert_eq!(connected, expected);
2921 } else {
2922 panic!("Expected connected union");
2923 }
2924 }
2925
2926 #[test]
2927 fn union_with_singleton_outside() {
2928 let i1 = IntervalClosed::new(0.0, 1.0);
2929 let i2 = IntervalSingleton::new(2.0);
2930 let union = i1.union(&i2);
2931 if let IntervalUnion::TwoDisjoint { left, right } = union {
2932 assert_eq!(left, i1.into());
2933 assert_eq!(right, i2.into());
2934 } else {
2935 panic!("Expected disjoint union");
2936 }
2937 }
2938
2939 #[test]
2940 fn union_unbounded_overlapping() {
2941 let i1 = IntervalLowerClosedUpperUnbounded::new(0.0);
2942 let i2 = IntervalLowerClosedUpperUnbounded::new(1.0);
2943 let union = i1.union(&i2);
2944 if let IntervalUnion::SingleConnected(connected) = union {
2945 assert_eq!(connected, i1.into());
2946 } else {
2947 panic!("Expected connected union");
2948 }
2949 }
2950
2951 #[test]
2952 fn union_lower_unbounded_with_upper_unbounded() {
2953 let i1 = IntervalLowerUnboundedUpperClosed::new(0.0);
2954 let i2 = IntervalLowerClosedUpperUnbounded::new(1.0);
2955 let union = i1.union(&i2);
2956 if let IntervalUnion::TwoDisjoint { left, right } = union {
2957 assert_eq!(left, i1.into());
2958 assert_eq!(right, i2.into());
2959 } else {
2960 panic!("Expected disjoint union for (-inf, 0] U [1, inf)");
2961 }
2962 }
2963
2964 #[test]
2965 fn union_lower_unbounded_with_upper_unbounded_overlapping() {
2966 let i1 = IntervalLowerUnboundedUpperClosed::new(2.0);
2967 let i2 = IntervalLowerClosedUpperUnbounded::new(1.0);
2968 let union = i1.union(&i2);
2969 let expected: Interval<f64> = IntervalLowerUnboundedUpperUnbounded::new().into();
2970 if let IntervalUnion::SingleConnected(connected) = union {
2971 assert_eq!(connected, expected);
2972 } else {
2973 panic!("Expected connected union resulting in (-inf, inf)");
2974 }
2975 }
2976
2977 #[test]
2978 fn union_finite_with_unbounded() {
2979 let i1 = IntervalClosed::new(0.0, 5.0);
2980 let i2 = IntervalLowerClosedUpperUnbounded::new(3.0);
2981 let union = i1.union(&i2);
2982 let expected: Interval<f64> = IntervalLowerClosedUpperUnbounded::new(0.0).into();
2983 if let IntervalUnion::SingleConnected(connected) = union {
2984 assert_eq!(connected, expected);
2985 } else {
2986 panic!("Expected connected union");
2987 }
2988 }
2989
2990 #[test]
2991 fn union_identical_intervals() {
2992 let i1 = IntervalClosed::new(0.0, 1.0);
2993 let i2 = IntervalClosed::new(0.0, 1.0);
2994 let union = i1.union(&i2);
2995 if let IntervalUnion::SingleConnected(connected) = union {
2996 assert_eq!(connected, i1.into());
2997 } else {
2998 panic!("Expected connected union");
2999 }
3000 }
3001
3002 #[test]
3003 fn union_different_bound_types_contained() {
3004 let i1 = IntervalClosed::new(0.0, 2.0);
3005 let i2 = IntervalOpen::new(0.0, 2.0);
3006 let union = i1.union(&i2);
3007 if let IntervalUnion::SingleConnected(connected) = union {
3008 assert_eq!(connected, i1.into());
3009 } else {
3010 panic!("Expected connected union");
3011 }
3012 }
3013
3014 #[test]
3015 fn union_different_bound_types_overlapping() {
3016 let i1 = IntervalLowerClosedUpperOpen::new(0.0, 2.0); let i2 = IntervalLowerOpenUpperClosed::new(1.0, 3.0); let union = i1.union(&i2);
3019 let expected: Interval<f64> = IntervalClosed::new(0.0, 3.0).into();
3020 if let IntervalUnion::SingleConnected(connected) = union {
3021 assert_eq!(connected, expected);
3022 } else {
3023 panic!("Expected connected union");
3024 }
3025 }
3026
3027 #[test]
3028 fn union_with_fully_unbounded() {
3029 let i1 = IntervalClosed::new(0.0, 1.0);
3030 let i2 = IntervalLowerUnboundedUpperUnbounded::new();
3031 let union = i1.union(&i2);
3032 if let IntervalUnion::SingleConnected(connected) = union {
3033 assert_eq!(connected, i2.into());
3034 } else {
3035 panic!("Expected connected union");
3036 }
3037 }
3038
3039 mod gap {
3040 use super::*;
3041 use num_valid::{RealNative64StrictFinite, functions::Abs};
3042
3043 type Real = RealNative64StrictFinite;
3044
3045 #[test]
3046 fn gap_with_disjoint_intervals_positive_gap() {
3047 let interval1 =
3049 IntervalClosed::new(Real::try_new(1.0).unwrap(), Real::try_new(2.0).unwrap());
3050 let interval2 =
3051 IntervalClosed::new(Real::try_new(4.0).unwrap(), Real::try_new(5.0).unwrap());
3052
3053 let union = interval1.union(&interval2);
3054
3055 let gap = union.gap().unwrap();
3056
3057 match gap {
3059 IntervalFinitePositiveLength::Open(open_gap) => {
3060 assert_eq!(open_gap.lower_bound_value(), &2.0);
3061 assert_eq!(open_gap.upper_bound_value(), &4.0);
3062 assert_eq!(open_gap.length().as_ref(), &2.0);
3063 }
3064 _ => panic!("Expected open interval for gap"),
3065 }
3066 }
3067
3068 #[test]
3069 fn gap_with_disjoint_intervals_small_gap() {
3070 let interval1 =
3072 IntervalClosed::new(Real::try_new(0.0).unwrap(), Real::try_new(1.0).unwrap());
3073 let interval2 =
3074 IntervalClosed::new(Real::try_new(1.5).unwrap(), Real::try_new(2.0).unwrap());
3075
3076 let union = interval1.union(&interval2);
3077
3078 let gap = union.gap().unwrap();
3079
3080 match gap {
3081 IntervalFinitePositiveLength::Open(open_gap) => {
3082 assert_eq!(open_gap.lower_bound_value(), &1.0);
3083 assert_eq!(open_gap.upper_bound_value(), &1.5);
3084 assert_eq!(open_gap.length().as_ref(), &0.5);
3085 }
3086 _ => panic!("Expected open interval for gap"),
3087 }
3088 }
3089
3090 #[test]
3091 fn gap_with_disjoint_half_open_intervals() {
3092 let interval1 = IntervalLowerClosedUpperOpen::new(
3094 Real::try_new(0.0).unwrap(),
3095 Real::try_new(1.0).unwrap(),
3096 );
3097 let interval2 = IntervalLowerOpenUpperClosed::new(
3098 Real::try_new(2.0).unwrap(),
3099 Real::try_new(3.0).unwrap(),
3100 );
3101
3102 let union = interval1.union(&interval2);
3103
3104 let gap = union.gap().unwrap();
3105
3106 match gap {
3107 IntervalFinitePositiveLength::Closed(closed_gap) => {
3108 assert_eq!(closed_gap.lower_bound_value(), &1.0);
3109 assert_eq!(closed_gap.upper_bound_value(), &2.0);
3110 assert_eq!(closed_gap.length().as_ref(), &1.0);
3111 }
3112 _ => panic!("Expected closed interval for gap"),
3113 }
3114 }
3115
3116 #[test]
3117 fn gap_with_touching_intervals_no_gap() {
3118 let interval1 =
3120 IntervalClosed::new(Real::try_new(1.0).unwrap(), Real::try_new(2.0).unwrap());
3121 let interval2 =
3122 IntervalClosed::new(Real::try_new(2.0).unwrap(), Real::try_new(3.0).unwrap());
3123
3124 let union = interval1.union(&interval2);
3125
3126 assert!(union.gap().is_none());
3127 }
3128
3129 #[test]
3130 fn gap_with_overlapping_intervals_no_gap() {
3131 let interval1 =
3133 IntervalClosed::new(Real::try_new(1.0).unwrap(), Real::try_new(3.0).unwrap());
3134 let interval2 =
3135 IntervalClosed::new(Real::try_new(2.0).unwrap(), Real::try_new(4.0).unwrap());
3136
3137 let union = interval1.union(&interval2);
3138
3139 assert!(union.gap().is_none());
3140 }
3141
3142 #[test]
3143 fn gap_with_open_intervals_disjoint() {
3144 let interval1 =
3146 IntervalOpen::new(Real::try_new(0.0).unwrap(), Real::try_new(1.0).unwrap());
3147 let interval2 =
3148 IntervalOpen::new(Real::try_new(2.0).unwrap(), Real::try_new(3.0).unwrap());
3149
3150 let union = interval1.union(&interval2);
3151
3152 let gap = union.gap().unwrap();
3153
3154 match gap {
3155 IntervalFinitePositiveLength::Closed(closed_gap) => {
3156 assert_eq!(closed_gap.lower_bound_value(), &1.0);
3157 assert_eq!(closed_gap.upper_bound_value(), &2.0);
3158 assert_eq!(closed_gap.length().as_ref(), &1.0);
3159 }
3160 _ => panic!("Expected closed interval for gap"),
3161 }
3162 }
3163
3164 #[test]
3165 fn gap_with_single_connected_interval() {
3166 let interval =
3168 IntervalClosed::new(Real::try_new(1.0).unwrap(), Real::try_new(5.0).unwrap());
3169
3170 let union = interval.union(&interval);
3171
3172 assert!(union.gap().is_none());
3173 }
3174
3175 #[test]
3176 fn gap_with_very_small_gap() {
3177 let epsilon = PositiveRealScalar::try_new(Real::try_new(1e-10).unwrap()).unwrap();
3179 let interval1 =
3180 IntervalClosed::new(Real::try_new(0.0).unwrap(), Real::try_new(1.0).unwrap());
3181 let interval2 = IntervalClosed::new(
3182 Real::try_new(1.0).unwrap() + epsilon.as_ref(),
3183 Real::try_new(2.0).unwrap(),
3184 );
3185
3186 let union = interval1.union(&interval2);
3187
3188 let gap = union.gap().unwrap();
3189
3190 match gap {
3191 IntervalFinitePositiveLength::Open(open_gap) => {
3192 assert_eq!(open_gap.lower_bound_value(), &1.0);
3193 assert_eq!(
3194 open_gap.upper_bound_value(),
3195 &(Real::try_new(1.0).unwrap() + epsilon.as_ref())
3196 );
3197 more_asserts::assert_lt!(
3198 (open_gap.length().into_inner() - epsilon.as_ref()).abs(),
3199 1.0e-16
3200 );
3201 }
3202 _ => panic!("Expected open interval for very small gap"),
3203 }
3204 }
3205
3206 #[test]
3207 fn gap_with_negative_intervals() {
3208 let interval1 =
3210 IntervalClosed::new(Real::try_new(-5.0).unwrap(), Real::try_new(-3.0).unwrap());
3211 let interval2 =
3212 IntervalClosed::new(Real::try_new(-1.0).unwrap(), Real::try_new(1.0).unwrap());
3213
3214 let union = IntervalUnion::TwoDisjoint {
3215 left: interval1.into(),
3216 right: interval2.into(),
3217 };
3218
3219 let gap = union.gap().unwrap();
3220
3221 match gap {
3222 IntervalFinitePositiveLength::Open(open_gap) => {
3223 assert_eq!(open_gap.lower_bound_value(), &-3.0);
3224 assert_eq!(open_gap.upper_bound_value(), &-1.0);
3225 assert_eq!(open_gap.length().as_ref(), &2.0);
3226 }
3227 _ => panic!("Expected open interval for gap"),
3228 }
3229 }
3230
3231 #[test]
3232 fn gap_with_mixed_boundary_types() {
3233 let interval1 = IntervalLowerOpenUpperClosed::new(
3235 Real::try_new(0.0).unwrap(),
3236 Real::try_new(1.0).unwrap(),
3237 );
3238 let interval2 = IntervalLowerClosedUpperOpen::new(
3239 Real::try_new(3.0).unwrap(),
3240 Real::try_new(4.0).unwrap(),
3241 );
3242
3243 let union = IntervalUnion::TwoDisjoint {
3244 left: interval1.into(),
3245 right: interval2.into(),
3246 };
3247
3248 let gap = union.gap().unwrap();
3249
3250 match gap {
3251 IntervalFinitePositiveLength::Open(open_gap) => {
3252 assert_eq!(open_gap.lower_bound_value(), &1.0);
3253 assert_eq!(open_gap.upper_bound_value(), &3.0);
3254 assert_eq!(open_gap.length().as_ref(), &2.0);
3255 }
3256 _ => panic!("Expected open interval for gap"),
3257 }
3258 }
3259
3260 #[test]
3261 fn gap_preserves_boundary_semantics() {
3262 let interval1 = IntervalLowerClosedUpperOpen::new(
3267 Real::try_new(0.0).unwrap(),
3268 Real::try_new(1.0).unwrap(),
3269 );
3270 let interval2 = IntervalLowerOpenUpperClosed::new(
3271 Real::try_new(2.0).unwrap(),
3272 Real::try_new(3.0).unwrap(),
3273 );
3274
3275 let union = IntervalUnion::TwoDisjoint {
3276 left: interval1.into(),
3277 right: interval2.into(),
3278 };
3279
3280 let gap = union.gap().unwrap();
3281
3282 match gap {
3284 IntervalFinitePositiveLength::Closed(closed_gap) => {
3285 assert_eq!(closed_gap.lower_bound_value(), &1.0);
3286 assert_eq!(closed_gap.upper_bound_value(), &2.0);
3287 assert!(closed_gap.contains_point(&Real::try_new(1.0).unwrap()));
3288 assert!(closed_gap.contains_point(&Real::try_new(2.0).unwrap()));
3289 }
3290 _ => panic!("Expected closed interval for gap"),
3291 }
3292 }
3293
3294 #[test]
3295 fn gap_with_singleton_intervals() {
3296 let singleton1 = IntervalSingleton::new(Real::try_new(1.0).unwrap());
3298 let singleton2 = IntervalSingleton::new(Real::try_new(3.0).unwrap());
3299
3300 let union = IntervalUnion::TwoDisjoint {
3301 left: singleton1.into(),
3302 right: singleton2.into(),
3303 };
3304
3305 let gap = union.gap().unwrap();
3306
3307 match gap {
3308 IntervalFinitePositiveLength::Open(open_gap) => {
3309 assert_eq!(open_gap.lower_bound_value(), &1.0);
3310 assert_eq!(open_gap.upper_bound_value(), &3.0);
3311 assert_eq!(open_gap.length().as_ref(), &2.0);
3312 assert!(!open_gap.contains_point(&Real::try_new(1.0).unwrap()));
3314 assert!(!open_gap.contains_point(&Real::try_new(3.0).unwrap()));
3315 }
3316 _ => panic!("Expected open interval for gap between singletons"),
3317 }
3318 }
3319 }
3320 }
3321}