From 7fe374b3afed0d25771d75df066bae14d9d91d6a Mon Sep 17 00:00:00 2001 From: GeorgeM Date: Tue, 11 Jul 2023 19:23:48 +0100 Subject: [PATCH 1/4] make hashing algorithm faster by doing a direct bit -> int conversion in c with numpy --- cubes.py | 39 +++++++++++++-------------------------- 1 file changed, 13 insertions(+), 26 deletions(-) diff --git a/cubes.py b/cubes.py index 18e6fb5..3e8a856 100644 --- a/cubes.py +++ b/cubes.py @@ -151,40 +151,27 @@ def generate_polycubes(n, use_cache=False): def rle(polycube): """ - Computes a simple run-length encoding of a given polycube. This function allows cubes to be more quickly compared via hashing. + Computes a simple hash of a given polycube. + It does this by converting the polycube into a 1d array and then interpreting those bits as a unsigned integer + This function allows cubes to be more quickly compared via hashing. - Converts a {0,1} nd array into a tuple that encodes the same shape. The array is first flattened, and then the following algorithm is applied: - - 1) The first three values in tuple contain the x,y,z dimension sizes of the array - 2) Each string of zeros of length n is replaced with a single value -n - 3) Each string of ones of length m is replaced with a single value +m + Converts a {0,1} nd array into a single unique large integer Parameters: polycube (np.array): 3D Numpy byte array where 1 values indicate polycube positions Returns: - tuple(int): Run length encoded polycube in the form (X, Y, Z, a, b, c, ...) + int: a unique integer hash """ - r = [] - r.extend(polycube.shape) - current = None - val = 0 - for x in polycube.flat: - if current is None: - current = x - val = 1 - pass - elif current == x: - val += 1 - elif current != x: - r.append(val if current == 1 else -val) - current = x - val = 1 - - r.append(val if current == 1 else -val) - - return tuple(r) + + pack_cube = np.packbits(polycube.flatten()) + out = 0 + for part in pack_cube: + out = out * 256 + out += int(part) + return out + def cube_exists_rle(polycube, polycubes_rle): """ From 1c2f044cc4c3fa69ab2bff6baa01cd16ca6875dc Mon Sep 17 00:00:00 2001 From: GeorgeM Date: Tue, 11 Jul 2023 19:51:01 +0100 Subject: [PATCH 2/4] fix bug where dimensiuons of space wherent included in hash causing misscount --- cubes.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cubes.py b/cubes.py index 3e8a856..6b38f85 100644 --- a/cubes.py +++ b/cubes.py @@ -149,7 +149,7 @@ def generate_polycubes(n, use_cache=False): return polycubes -def rle(polycube): +def rle(polycube: np.ndarray): """ Computes a simple hash of a given polycube. It does this by converting the polycube into a 1d array and then interpreting those bits as a unsigned integer @@ -166,10 +166,10 @@ def rle(polycube): """ pack_cube = np.packbits(polycube.flatten()) - out = 0 + data = 0 for part in pack_cube: - out = out * 256 - out += int(part) + data = (data << 8) + int(part) + out = (data * 100000) + (polycube.shape[0] * 1000) + (polycube.shape[1] * 10) + (polycube.shape[2]) # add volume dimensions to lower bits of hash return out From dd05504268521f84cde92a1f7ea016d80722b61a Mon Sep 17 00:00:00 2001 From: GeorgeM Date: Tue, 11 Jul 2023 19:53:46 +0100 Subject: [PATCH 3/4] remove type hinting to conform with rest of codebase --- cubes.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cubes.py b/cubes.py index 6b38f85..7cb1a63 100644 --- a/cubes.py +++ b/cubes.py @@ -149,7 +149,7 @@ def generate_polycubes(n, use_cache=False): return polycubes -def rle(polycube: np.ndarray): +def rle(polycube): """ Computes a simple hash of a given polycube. It does this by converting the polycube into a 1d array and then interpreting those bits as a unsigned integer From 42fbab972e96dec49db4c58c5870c42200e7e9bb Mon Sep 17 00:00:00 2001 From: GeorgeM Date: Wed, 12 Jul 2023 02:05:42 +0100 Subject: [PATCH 4/4] fix for possible hash collisions in n>10 --- cubes.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cubes.py b/cubes.py index 7cb1a63..530816b 100644 --- a/cubes.py +++ b/cubes.py @@ -169,7 +169,7 @@ def rle(polycube): data = 0 for part in pack_cube: data = (data << 8) + int(part) - out = (data * 100000) + (polycube.shape[0] * 1000) + (polycube.shape[1] * 10) + (polycube.shape[2]) # add volume dimensions to lower bits of hash + out = (data * 100000000) + (polycube.shape[0] * 100000) + (polycube.shape[1] * 100) + (polycube.shape[2]) # add volume dimensions to lower bits of hash return out