Skip to content

Commit fae6bc0

Browse files
tanyaveksleradisos
andauthored
Fixed corner-case bug in CanonicalHyperCubeSet. (#546)
* Fixed corner-case bug in CanonicalHyperCubeSet. Signed-off-by: Tanya <[email protected]> * additional updates Signed-off-by: adisos <[email protected]> * Removed unnecessary data from the test. Signed-off-by: Tanya <[email protected]> --------- Signed-off-by: Tanya <[email protected]> Signed-off-by: adisos <[email protected]> Co-authored-by: adisos <[email protected]>
1 parent 941034d commit fae6bc0

File tree

3 files changed

+81
-6
lines changed

3 files changed

+81
-6
lines changed

nca/CoreDS/CanonicalHyperCubeSet.py

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -541,20 +541,23 @@ def _contained_in_aux(self, other, all_active_dims): # noqa: C901
541541
common_part = current_layer_0 & other_layer
542542
has_common_part = bool(common_part)
543543
if has_common_part:
544+
# if it's not last dim for both self and other, determine containment recursively
544545
if not self._is_last_dimension() and not other._is_last_dimension() and \
545546
not (self.layers[layer])._contained_in_aux(other_sub_elem, all_active_dims[1:]):
546547
return False
548+
# if it's last dim for self but not for other: the remaining of other should be entire cube
549+
if self._is_last_dimension() and not other._is_last_dimension() and \
550+
not other_sub_elem._is_sub_elem_entire_sub_space():
551+
return False
552+
# if it's the last dim for other but not for self -> containment is satisfied on this part
553+
# at this point, sub-object from common_part is contained
547554
remaining = current_layer_0 - common_part
548555
if remaining:
549556
# continue exploring other's cubes for containment of the remaining part from self
550557
current_layer_0 = remaining
551558
else:
552-
if self._is_last_dimension() and not other._is_last_dimension():
553-
# if it's last dim for self but not for other: the remaining of other should be entire cube
554-
if other_sub_elem._is_sub_elem_entire_sub_space():
555-
is_subset_count += 1
556-
else:
557-
is_subset_count += 1
559+
# count current cube (from current_layer_0) as contained in other
560+
is_subset_count += 1
558561
break
559562
return is_subset_count == len(self.layers)
560563

tests/classes_unit_tests/testCanonicalHyperCubeSet.py

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1434,6 +1434,50 @@ def tearDown(self):
14341434
# undo changes this test did to DimensionsManager singleton
14351435
DimensionsManager.reset()
14361436

1437+
def test_contained_in_issue(self):
1438+
my_dimensions1 = ["x", "y"]
1439+
my_dimensions2 = ["x", "y", "z"]
1440+
cube_values_1 = [CanonicalIntervalSet.get_interval_set(2, 2),
1441+
CanonicalIntervalSet.get_interval_set(1, 3)]
1442+
conns1 = CanonicalHyperCubeSet.create_from_cube(my_dimensions2, cube_values_1, my_dimensions1)
1443+
cube_values_2 = [
1444+
CanonicalIntervalSet.get_interval_set(3, 3),
1445+
CanonicalIntervalSet.get_interval_set(1, 1)
1446+
]
1447+
conns1.add_cube(cube_values_2, my_dimensions1)
1448+
1449+
cube_values_3 = [
1450+
CanonicalIntervalSet.get_interval_set(2, 2),
1451+
CanonicalIntervalSet.get_interval_set(2, 3),
1452+
CanonicalIntervalSet.get_interval_set(1, 100),
1453+
]
1454+
conns2 = CanonicalHyperCubeSet.create_from_cube(my_dimensions2, cube_values_3, my_dimensions2)
1455+
conns3 = CanonicalHyperCubeSet.create_from_cube(my_dimensions2, cube_values_3, my_dimensions2)
1456+
1457+
cube_values_4 = [
1458+
CanonicalIntervalSet.get_interval_set(2, 2),
1459+
CanonicalIntervalSet.get_interval_set(1, 1)
1460+
]
1461+
cube_values_5 = [
1462+
CanonicalIntervalSet.get_interval_set(3, 3),
1463+
CanonicalIntervalSet.get_interval_set(1, 1)
1464+
]
1465+
cube_values_6 = [
1466+
CanonicalIntervalSet.get_interval_set(2, 3),
1467+
CanonicalIntervalSet.get_interval_set(1, 1)
1468+
]
1469+
conns2.add_cube(cube_values_4, my_dimensions1)
1470+
conns2.add_cube(cube_values_5, my_dimensions1)
1471+
conns3.add_cube(cube_values_6, my_dimensions1)
1472+
1473+
# conns2 should be contained in conns1
1474+
self.assertFalse(conns1.contained_in(conns2))
1475+
self.assertTrue(conns2.contained_in(conns1))
1476+
1477+
self.assertEqual(conns2, conns3)
1478+
1479+
1480+
14371481
def test_basic(self):
14381482
a = CanonicalHyperCubeSet(dimensions4)
14391483
a.add_cube([CanonicalIntervalSet.get_interval_set(1, 2)], ["x"])

tests/classes_unit_tests/testCanonicalHyperCubeSetNew.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
from nca.CoreDS.MinDFA import MinDFA
55
from nca.CoreDS.CanonicalHyperCubeSet import CanonicalHyperCubeSet
66
from nca.CoreDS.DimensionsManager import DimensionsManager
7+
from nca.CoreDS.Peer import BasePeerSet, IpBlock
8+
from nca.CoreDS.ProtocolSet import ProtocolSet
79

810
dimensions = ["src_ports", "ports", "methods", "paths"]
911
dimensions2 = ["ports", "src_ports", "methods", "paths"]
@@ -971,6 +973,32 @@ def test_contained_in_new(self):
971973
d = CanonicalHyperCubeSet.create_from_cube(dimensions, [get_str_dfa("x|y|z")], ["paths"])
972974
self.assertTrue(c.contained_in(d))
973975

976+
def test_bug_in_contained(self):
977+
BasePeerSet.reset()
978+
BasePeerSet().add_peer("A")
979+
BasePeerSet().add_peer("B")
980+
BasePeerSet().add_peer("C")
981+
my_dimensions1 = ["src_peers", "dst_peers"]
982+
my_dimensions2 = ["src_peers", "dst_peers", "protocols"]
983+
conns1 = CanonicalHyperCubeSet.create_from_cube(my_dimensions2,
984+
[BasePeerSet().get_peer_interval_of({"B"}),
985+
BasePeerSet().get_peer_interval_of({"A", "B", "C"})],
986+
my_dimensions1)
987+
conns1.add_cube([BasePeerSet().get_peer_interval_of({"C"}),
988+
BasePeerSet().get_peer_interval_of({"A"})], my_dimensions1)
989+
990+
conns2 = CanonicalHyperCubeSet.create_from_cube(my_dimensions2,
991+
[BasePeerSet().get_peer_interval_of({"B"}),
992+
BasePeerSet().get_peer_interval_of({"B", "C"}),
993+
ProtocolSet.get_non_tcp_protocols()],
994+
my_dimensions2)
995+
conns2.add_cube([BasePeerSet().get_peer_interval_of({"B"}),
996+
BasePeerSet().get_peer_interval_of({"A"})], my_dimensions1)
997+
conns2.add_cube([BasePeerSet().get_peer_interval_of({"C"}),
998+
BasePeerSet().get_peer_interval_of({"A"})], my_dimensions1)
999+
self.assertFalse(conns1.contained_in(conns2))
1000+
self.assertTrue(conns2.contained_in(conns1))
1001+
9741002
def test_subtract_basic(self):
9751003
x = CanonicalHyperCubeSet(dimensions)
9761004
y = CanonicalHyperCubeSet(dimensions)

0 commit comments

Comments
 (0)