Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixed recursive operations (and/or/sub) in hyper cube set, to not ch… #369

Merged
merged 6 commits into from
Nov 29, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 32 additions & 20 deletions nca/CoreDS/CanonicalHyperCubeSet.py
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,9 @@ def __iand__(self, other):
self._override_by_other(other.copy())
return self
other_copy = self._prepare_common_active_dimensions(other)
self._and_aux(other_copy)
res = self._and_aux(other_copy)
self.layers = res.layers
self.active_dimensions = res.active_dimensions
self._reduce_active_dimensions()
return self

Expand All @@ -272,17 +274,19 @@ def _and_aux(self, other):
Recursive function to compute 'and' between two CanonicalHyperCubeSet objects.
Assuming that self and other have common active dimensions.
:type other: CanonicalHyperCubeSet
:return: self
:return: CanonicalHyperCubeSet representing 'and' between self and the other object
"""
assert self.active_dimensions == other.active_dimensions
res = CanonicalHyperCubeSet(self.all_dimensions_list)
res.active_dimensions = self.active_dimensions
res_layers = dict()
for self_layer in self.layers:
for other_layer in other.layers:
common_elem = self_layer & other_layer
if not common_elem:
continue
if self._is_last_dimension():
res_layers[common_elem] = self.layers[self_layer]
res_layers[common_elem] = CanonicalHyperCubeSet.empty_interval
continue
# TODO: use type hint to avoid warning on access to a protected member?
# self_sub_elem: CanonicalHyperCubeSet = self.layers[self_layer]
Expand All @@ -291,9 +295,9 @@ def _and_aux(self, other):
if new_sub_elem:
res_layers[common_elem] = new_sub_elem

self.layers = res_layers
self._apply_layer_elements_union()
return self
res.layers = res_layers
res._apply_layer_elements_union()
return res

def __or__(self, other):
res = self.copy()
Expand All @@ -310,7 +314,9 @@ def __ior__(self, other):
self._override_by_other(other.copy())
return self
other_copy = self._prepare_common_active_dimensions(other)
self.or_aux(other_copy)
res = self.or_aux(other_copy)
self.layers = res.layers
self.active_dimensions = res.active_dimensions
self._reduce_active_dimensions()
return self

Expand All @@ -319,9 +325,11 @@ def or_aux(self, other):
Recursive function to compute 'or' between two CanonicalHyperCubeSet objects.
Assuming that self and other have common active dimensions.
:type other: CanonicalHyperCubeSet
:return: self
:return: CanonicalHyperCubeSet representing 'or' between self and the other object
"""
assert self.active_dimensions == other.active_dimensions
res = CanonicalHyperCubeSet(self.all_dimensions_list)
res.active_dimensions = self.active_dimensions
res_layers = dict()
remaining_other_layers = dict() # map from layer_0 elems in orig "other", to remaining parts to be added
for layer_elem in other.layers:
Expand All @@ -337,16 +345,16 @@ def or_aux(self, other):
if self._is_last_dimension():
res_layers[common_elem] = CanonicalHyperCubeSet.empty_interval
continue
new_sub_elem = (self.layers[self_layer].copy()).or_aux(other.layers[other_layer])
new_sub_elem = self.layers[self_layer].or_aux(other.layers[other_layer])
res_layers[common_elem] = new_sub_elem
if remaining_self_layer:
res_layers[remaining_self_layer] = self.layers[self_layer]
res_layers[remaining_self_layer] = self.layers[self_layer].copy()
for layer_elem, remaining_layer_elem in remaining_other_layers.items():
if remaining_layer_elem:
res_layers[remaining_layer_elem] = other.layers[layer_elem].copy()
self.layers = res_layers
self._apply_layer_elements_union()
return self
res.layers = res_layers
res._apply_layer_elements_union()
return res

def __sub__(self, other):
res = self.copy()
Expand All @@ -359,7 +367,9 @@ def __isub__(self, other):
if not other:
return self
other_copy = self._prepare_common_active_dimensions(other)
self.sub_aux(other_copy)
res = self.sub_aux(other_copy)
self.layers = res.layers
self.active_dimensions = res.active_dimensions
self._reduce_active_dimensions()
return self

Expand All @@ -368,9 +378,11 @@ def sub_aux(self, other):
Recursive function to compute 'sub' between two CanonicalHyperCubeSet objects.
Assuming that self and other have common active dimensions.
:type other: CanonicalHyperCubeSet
:return: self
:return: CanonicalHyperCubeSet representing 'sub' between self and the other object
"""
assert self.active_dimensions == other.active_dimensions
res = CanonicalHyperCubeSet(self.all_dimensions_list)
res.active_dimensions = self.active_dimensions
res_layers = dict()
for self_layer in self.layers:
remaining_self_layer = self._copy_layer_elem(self_layer)
Expand All @@ -383,15 +395,15 @@ def sub_aux(self, other):
# do not add common_elem to self.layers here because result is empty
continue
# sub-elements subtraction
new_sub_elem = (self.layers[self_layer].copy()).sub_aux(other.layers[other_layer])
new_sub_elem = self.layers[self_layer].sub_aux(other.layers[other_layer])
if bool(new_sub_elem):
# add remaining new_sub_elem if not empty, under common
res_layers[common_elem] = new_sub_elem
if remaining_self_layer:
res_layers[remaining_self_layer] = self.layers[self_layer]
self.layers = res_layers
self._apply_layer_elements_union()
return self
res_layers[remaining_self_layer] = self.layers[self_layer].copy()
res.layers = res_layers
res._apply_layer_elements_union()
return res

def _prepare_common_active_dimensions(self, other):
"""
Expand Down
154 changes: 154 additions & 0 deletions tests/classes_unit_tests/testCanonicalHyperCubeSet.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,19 @@
dimensions2 = ["ports", "src_ports", "methods_dfa", "paths"]
dimensions3 = ["src_ports", "ports", "methods_dfa", "paths", "hosts"]
dimensions4 = ["x", "y", "z"]
dimensions5 = ["src_peers", "dst_peers", "protocols", "ports"]

dim_manager = DimensionsManager()
dim_manager.set_domain("methods_dfa", DimensionsManager.DimensionType.DFA)
dim_manager.set_domain("ports", DimensionsManager.DimensionType.IntervalSet, (1, 65535))
dim_manager.set_domain("x", DimensionsManager.DimensionType.IntervalSet, (1, 65535))
dim_manager.set_domain("y", DimensionsManager.DimensionType.IntervalSet, (1, 65535))
dim_manager.set_domain("z", DimensionsManager.DimensionType.IntervalSet, (1, 65535))

dim_manager.set_domain("src_peers", DimensionsManager.DimensionType.IntervalSet, (0, 10000))
dim_manager.set_domain("dst_peers", DimensionsManager.DimensionType.IntervalSet, (0, 10000))
dim_manager.set_domain("protocols", DimensionsManager.DimensionType.IntervalSet, (0, 139))


def get_str_dfa(s):
return MinDFA.dfa_from_regex(s)
Expand Down Expand Up @@ -1252,6 +1258,154 @@ def test_basic_new(self):
self.assertEqual(b - c, a)
self.assertEqual(b - a, c)

def test_complex_intersection(self):
"""
cubes in x:
[0-15, 6, 6, 8080]
[0-15, 0-5,7-15, 0-139, 1-65535]
[16-10000, 0-5,7-15, 0-139, 1-65535]

cubes in y:
[6, 1, 6, 9555]
[6, 2, 6, 7070]
[6, 3, 6, 5050]
[6, 4, 6, 7000]
[6, 9, 6, 3550]
[6, 10, 6, 8080]
[6, 12, 6, 50051]
[6, 13-14, 17, 53]
[0-5,7-15, 0-10000, 0-139, 1-65535]

cubes in res = x & Y:
[6, 1, 6, 9555]
[6, 2, 6, 7070]
[6, 3, 6, 5050]
[6, 4, 6, 7000]
[6, 9, 6, 3550]
[6, 10, 6, 8080]
[6, 12, 6, 50051]
[6, 13-14, 17, 53]
[0-5,7-15, 6, 6, 8080]
[0-5,7-15, 0-5,7-15, 0-139, 1-65535]
"""
x = CanonicalHyperCubeSet(dimensions5)
x.add_cube([CanonicalIntervalSet.get_interval_set(0, 15),
CanonicalIntervalSet.get_interval_set(6, 6),
CanonicalIntervalSet.get_interval_set(6, 6),
CanonicalIntervalSet.get_interval_set(8080, 8080)])

x.add_cube([CanonicalIntervalSet.get_interval_set(0, 15),
CanonicalIntervalSet.get_interval_set(0, 5) | CanonicalIntervalSet.get_interval_set(7, 15),
CanonicalIntervalSet.get_interval_set(0, 139),
CanonicalIntervalSet.get_interval_set(1, 65535)])

x.add_cube([CanonicalIntervalSet.get_interval_set(16, 10000),
CanonicalIntervalSet.get_interval_set(0, 5) | CanonicalIntervalSet.get_interval_set(7, 15),
CanonicalIntervalSet.get_interval_set(0, 139),
CanonicalIntervalSet.get_interval_set(1, 65535)])

y = CanonicalHyperCubeSet(dimensions5)

y.add_cube([CanonicalIntervalSet.get_interval_set(6, 6),
CanonicalIntervalSet.get_interval_set(1, 1),
CanonicalIntervalSet.get_interval_set(6, 6),
CanonicalIntervalSet.get_interval_set(9555, 9555)])

y.add_cube([CanonicalIntervalSet.get_interval_set(6, 6),
CanonicalIntervalSet.get_interval_set(2, 2),
CanonicalIntervalSet.get_interval_set(6, 6),
CanonicalIntervalSet.get_interval_set(7070, 7070)])

y.add_cube([CanonicalIntervalSet.get_interval_set(6, 6),
CanonicalIntervalSet.get_interval_set(3, 3),
CanonicalIntervalSet.get_interval_set(6, 6),
CanonicalIntervalSet.get_interval_set(5050, 5050)])

y.add_cube([CanonicalIntervalSet.get_interval_set(6, 6),
CanonicalIntervalSet.get_interval_set(4, 4),
CanonicalIntervalSet.get_interval_set(6, 6),
CanonicalIntervalSet.get_interval_set(7000, 7000)])

y.add_cube([CanonicalIntervalSet.get_interval_set(6, 6),
CanonicalIntervalSet.get_interval_set(9, 9),
CanonicalIntervalSet.get_interval_set(6, 6),
CanonicalIntervalSet.get_interval_set(3550, 3550)])

y.add_cube([CanonicalIntervalSet.get_interval_set(6, 6),
CanonicalIntervalSet.get_interval_set(10, 10),
CanonicalIntervalSet.get_interval_set(6, 6),
CanonicalIntervalSet.get_interval_set(8080, 8080)])

y.add_cube([CanonicalIntervalSet.get_interval_set(6, 6),
CanonicalIntervalSet.get_interval_set(12, 12),
CanonicalIntervalSet.get_interval_set(6, 6),
CanonicalIntervalSet.get_interval_set(50051, 50051)])

y.add_cube([CanonicalIntervalSet.get_interval_set(6, 6),
CanonicalIntervalSet.get_interval_set(13, 14),
CanonicalIntervalSet.get_interval_set(17, 17),
CanonicalIntervalSet.get_interval_set(53, 53)])

y.add_cube([CanonicalIntervalSet.get_interval_set(0, 5) | CanonicalIntervalSet.get_interval_set(7, 15),
CanonicalIntervalSet.get_interval_set(0, 10000),
CanonicalIntervalSet.get_interval_set(0, 139),
CanonicalIntervalSet.get_interval_set(1, 65535)])

z = CanonicalHyperCubeSet(dimensions5)
z.add_cube([CanonicalIntervalSet.get_interval_set(6, 6),
CanonicalIntervalSet.get_interval_set(1, 1),
CanonicalIntervalSet.get_interval_set(6, 6),
CanonicalIntervalSet.get_interval_set(9555, 9555)])

z.add_cube([CanonicalIntervalSet.get_interval_set(6, 6),
CanonicalIntervalSet.get_interval_set(2, 2),
CanonicalIntervalSet.get_interval_set(6, 6),
CanonicalIntervalSet.get_interval_set(7070, 7070)])

z.add_cube([CanonicalIntervalSet.get_interval_set(6, 6),
CanonicalIntervalSet.get_interval_set(3, 3),
CanonicalIntervalSet.get_interval_set(6, 6),
CanonicalIntervalSet.get_interval_set(5050, 5050)])

z.add_cube([CanonicalIntervalSet.get_interval_set(6, 6),
CanonicalIntervalSet.get_interval_set(4, 4),
CanonicalIntervalSet.get_interval_set(6, 6),
CanonicalIntervalSet.get_interval_set(7000, 7000)])

z.add_cube([CanonicalIntervalSet.get_interval_set(6, 6),
CanonicalIntervalSet.get_interval_set(9, 9),
CanonicalIntervalSet.get_interval_set(6, 6),
CanonicalIntervalSet.get_interval_set(3550, 3550)])

z.add_cube([CanonicalIntervalSet.get_interval_set(6, 6),
CanonicalIntervalSet.get_interval_set(10, 10),
CanonicalIntervalSet.get_interval_set(6, 6),
CanonicalIntervalSet.get_interval_set(8080, 8080)])

z.add_cube([CanonicalIntervalSet.get_interval_set(6, 6),
CanonicalIntervalSet.get_interval_set(12, 12),
CanonicalIntervalSet.get_interval_set(6, 6),
CanonicalIntervalSet.get_interval_set(50051, 50051)])

z.add_cube([CanonicalIntervalSet.get_interval_set(6, 6),
CanonicalIntervalSet.get_interval_set(13, 14),
CanonicalIntervalSet.get_interval_set(17, 17),
CanonicalIntervalSet.get_interval_set(53, 53)])

z.add_cube([CanonicalIntervalSet.get_interval_set(0, 5) | CanonicalIntervalSet.get_interval_set(7, 15),
CanonicalIntervalSet.get_interval_set(6, 6),
CanonicalIntervalSet.get_interval_set(6, 6),
CanonicalIntervalSet.get_interval_set(8080, 8080)])

z.add_cube([CanonicalIntervalSet.get_interval_set(0, 5) | CanonicalIntervalSet.get_interval_set(7, 15),
CanonicalIntervalSet.get_interval_set(0, 5) | CanonicalIntervalSet.get_interval_set(7, 15),
CanonicalIntervalSet.get_interval_set(0, 139),
CanonicalIntervalSet.get_interval_set(1, 65535)])

res = x & y
self.assertEqual(z, res)



class TestCanonicalHyperCubeSetMethodsIntervals(unittest.TestCase):
"""
Expand Down