Skip to content

Commit 859fd1d

Browse files
committed
Updated FusionTree implementation to inherit from correct parent
1 parent ad8daeb commit 859fd1d

File tree

7 files changed

+255
-253
lines changed

7 files changed

+255
-253
lines changed

docs/source/pydatastructs/trees/binary_trees.rst

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,5 +18,3 @@ Binary Trees
1818
.. autoclass:: pydatastructs.RedBlackTree
1919

2020
.. autoclass:: pydatastructs.BinaryTreeTraversal
21-
22-
.. autoclass:: pydatastructs.FusionTree
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
M-ary Trees
22
===========
33

4+
.. autoclass:: pydatastructs.FusionTree

pydatastructs/trees/__init__.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,13 @@
1818
Treap,
1919
SplayTree,
2020
RedBlackTree,
21-
FusionTree
2221
)
2322
__all__.extend(binary_trees.__all__)
2423

2524
from .m_ary_trees import (
26-
MAryTreeNode, MAryTree
25+
MAryTreeNode,
26+
MAryTree,
27+
FusionTree
2728
)
2829

2930
__all__.extend(m_ary_trees.__all__)

pydatastructs/trees/binary_trees.py

Lines changed: 0 additions & 159 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import random
2-
import math
32
from collections import deque as Queue
43
from pydatastructs.utils import TreeNode, CartesianTreeNode, RedBlackTreeNode
54
from pydatastructs.miscellaneous_data_structures import Stack
@@ -19,7 +18,6 @@
1918
'Treap',
2019
'SplayTree',
2120
'RedBlackTree',
22-
'FusionTree',
2321
]
2422

2523
class BinaryTree(object):
@@ -1889,160 +1887,3 @@ def get_sum(self, left_index, right_index):
18891887
self.get_prefix_sum(left_index - 1)
18901888
else:
18911889
return self.get_prefix_sum(right_index)
1892-
1893-
class FusionTree(object):
1894-
"""
1895-
Implements a Fusion Tree, a multi-way search tree optimized for integer keys.
1896-
1897-
Parameters
1898-
==========
1899-
1900-
key: int
1901-
The integer key to insert.
1902-
root_data: Any
1903-
Optional data to store with the key.
1904-
backend: pydatastructs.Backend
1905-
The backend to be used. Available backends: Python and C++
1906-
Optional, by default, the Python backend is used. For faster execution, use the C++ backend.
1907-
word_size: int
1908-
The size of the integer keys in bits.
1909-
Optional, by default, set to 64.
1910-
1911-
Examples
1912-
========
1913-
1914-
>>> from pydatastructs import FusionTree
1915-
>>> ft = FusionTree()
1916-
>>> ft.insert(1, 1)
1917-
>>> ft.insert(2, 2)
1918-
>>> ft.search(1)
1919-
0
1920-
>>> ft.delete(1)
1921-
True
1922-
>>> ft.search(1)
1923-
1924-
1925-
References:
1926-
- https://en.wikipedia.org/wiki/Fusion_tree
1927-
- Fredman & Willard (1990): "Fusion Trees"
1928-
"""
1929-
1930-
__slots__ = ['root_idx', 'tree', 'size', 'B',
1931-
'sketch_mask', 'fingerprint_multiplier']
1932-
1933-
def __new__(cls, key=None, root_data=None, **kwargs):
1934-
backend = kwargs.get('backend', Backend.PYTHON)
1935-
raise_if_backend_is_not_python(cls, backend)
1936-
1937-
obj = object.__new__(cls)
1938-
key = None if root_data is None else key
1939-
root = TreeNode(key, root_data)
1940-
root.is_root = True
1941-
obj.root_idx = 0
1942-
obj.tree, obj.size = ArrayForTrees(TreeNode, [root]), 1
1943-
obj.B = int(math.log2(kwargs.get('word_size', 64))
1944-
** (1/5)) # Multi-way branching factor
1945-
obj.sketch_mask = 0 # Computed dynamically
1946-
obj.fingerprint_multiplier = 2654435761 # Prime multiplier for fingerprinting
1947-
return obj
1948-
1949-
def _compute_sketch_mask(self):
1950-
"""
1951-
Computes a sketch mask for efficient parallel comparisons.
1952-
"""
1953-
keys = [node.key for node in self.tree if node is not None]
1954-
if len(keys) > 1:
1955-
significant_bits = [max(k.bit_length() for k in keys)]
1956-
self.sketch_mask = sum(1 << b for b in significant_bits)
1957-
1958-
def insert(self, key, data=None):
1959-
"""
1960-
Inserts a key into the Fusion Tree.
1961-
1962-
Parameters
1963-
==========
1964-
1965-
key: int
1966-
The integer key to insert.
1967-
data: Any
1968-
Optional data to store with the key.
1969-
"""
1970-
# Edge case for root node if not intially inserted
1971-
if self.size == 1 and self.tree[0].key is None:
1972-
self.tree[0] = TreeNode(key, data)
1973-
self.tree[0].is_root = True
1974-
return
1975-
1976-
node = TreeNode(key, data)
1977-
self.tree.append(node)
1978-
self.size += 1
1979-
if self.size > 1:
1980-
self._compute_sketch_mask()
1981-
1982-
def _sketch_key(self, key):
1983-
"""
1984-
Applies the sketch mask to compress the key for fast comparison.
1985-
"""
1986-
return key & self.sketch_mask
1987-
1988-
def _fingerprint(self, key):
1989-
"""
1990-
Uses multiplication-based fingerprinting to create a unique identifier
1991-
for the key, allowing fast parallel searches.
1992-
"""
1993-
return (key * self.fingerprint_multiplier) & ((1 << 64) - 1)
1994-
1995-
def search(self, key):
1996-
"""
1997-
Searches for a key in the Fusion Tree using bitwise sketching and fingerprinting.
1998-
1999-
Parameters
2000-
==========
2001-
2002-
key: int
2003-
The integer key to search.
2004-
2005-
Returns
2006-
=======
2007-
2008-
int: The index of the key in the tree, or None if not found.
2009-
"""
2010-
sketch = self._sketch_key(key)
2011-
fingerprint = self._fingerprint(key)
2012-
for i in range(self.size):
2013-
if self._sketch_key(self.tree[i].key) == sketch and self._fingerprint(self.tree[i].key) == fingerprint:
2014-
return i
2015-
return None
2016-
2017-
def delete(self, key):
2018-
"""
2019-
Deletes a key from the Fusion Tree.
2020-
2021-
Parameters
2022-
==========
2023-
2024-
key: int
2025-
The integer key to delete.
2026-
2027-
Returns
2028-
=======
2029-
2030-
bool: True if the key was successfully deleted, False otherwise.
2031-
2032-
"""
2033-
index = self.search(key)
2034-
if index is not None:
2035-
self.tree[index] = None # Soft delete
2036-
# Compact tree
2037-
self.tree = [node for node in self.tree if node is not None]
2038-
self.size -= 1
2039-
if self.size > 1:
2040-
self._compute_sketch_mask()
2041-
return True
2042-
return False
2043-
2044-
def __str__(self):
2045-
"""
2046-
Returns a string representation of the Fusion Tree.
2047-
"""
2048-
return str([(node.key, node.data) for node in self.tree if node is not None])

pydatastructs/trees/m_ary_trees.py

Lines changed: 161 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
1+
import math
12
from pydatastructs.utils import MAryTreeNode
23
from pydatastructs.linear_data_structures.arrays import ArrayForTrees
34
from pydatastructs.utils.misc_util import (
45
Backend, raise_if_backend_is_not_python)
56

67
__all__ = [
7-
'MAryTree'
8+
'MAryTree',
9+
'FusionTree'
810
]
911

1012
class MAryTree(object):
@@ -170,3 +172,161 @@ def __str__(self):
170172
if j is not None:
171173
to_be_printed[i].append(j)
172174
return str(to_be_printed)
175+
176+
177+
class FusionTree(MAryTree):
178+
"""
179+
Implements a Fusion Tree, a multi-way search tree optimized for integer keys.
180+
181+
Parameters
182+
==========
183+
184+
key: int
185+
The integer key to insert.
186+
root_data: Any
187+
Optional data to store with the key.
188+
backend: pydatastructs.Backend
189+
The backend to be used. Available backends: Python and C++
190+
Optional, by default, the Python backend is used. For faster execution, use the C++ backend.
191+
word_size: int
192+
The size of the integer keys in bits.
193+
Optional, by default, set to 64.
194+
195+
Examples
196+
========
197+
198+
>>> from pydatastructs import FusionTree
199+
>>> ft = FusionTree()
200+
>>> ft.insert(1, 1)
201+
>>> ft.insert(2, 2)
202+
>>> ft.search(1)
203+
0
204+
>>> ft.delete(1)
205+
True
206+
>>> ft.search(1)
207+
208+
209+
References:
210+
- https://en.wikipedia.org/wiki/Fusion_tree
211+
- Fredman & Willard (1990): "Fusion Trees"
212+
"""
213+
214+
__slots__ = ['root_idx', 'tree', 'size', 'B',
215+
'sketch_mask', 'fingerprint_multiplier']
216+
217+
def __new__(cls, key=None, root_data=None, **kwargs):
218+
backend = kwargs.get('backend', Backend.PYTHON)
219+
raise_if_backend_is_not_python(cls, backend)
220+
221+
obj = object.__new__(cls)
222+
key = None if root_data is None else key
223+
root = MAryTreeNode(key, root_data)
224+
root.is_root = True
225+
obj.root_idx = 0
226+
obj.tree, obj.size = ArrayForTrees(MAryTreeNode, [root]), 1
227+
obj.B = int(math.log2(kwargs.get('word_size', 64))
228+
** (1/5)) # Multi-way branching factor
229+
obj.sketch_mask = 0 # Computed dynamically
230+
obj.fingerprint_multiplier = 2654435761 # Prime multiplier for fingerprinting
231+
return obj
232+
233+
def _compute_sketch_mask(self):
234+
"""
235+
Computes a sketch mask for efficient parallel comparisons.
236+
"""
237+
keys = [node.key for node in self.tree if node is not None]
238+
if len(keys) > 1:
239+
significant_bits = [max(k.bit_length() for k in keys)]
240+
self.sketch_mask = sum(1 << b for b in significant_bits)
241+
242+
def insert(self, key, data=None):
243+
"""
244+
Inserts a key into the Fusion Tree.
245+
246+
Parameters
247+
==========
248+
249+
key: int
250+
The integer key to insert.
251+
data: Any
252+
Optional data to store with the key.
253+
"""
254+
# Edge case for root node if not intially inserted
255+
if self.size == 1 and self.tree[0].key is None:
256+
self.tree[0] = MAryTreeNode(key, data)
257+
self.tree[0].is_root = True
258+
return
259+
260+
node = MAryTreeNode(key, data)
261+
self.tree.append(node)
262+
self.size += 1
263+
if self.size > 1:
264+
self._compute_sketch_mask()
265+
266+
def _sketch_key(self, key):
267+
"""
268+
Applies the sketch mask to compress the key for fast comparison.
269+
"""
270+
return key & self.sketch_mask
271+
272+
def _fingerprint(self, key):
273+
"""
274+
Uses multiplication-based fingerprinting to create a unique identifier
275+
for the key, allowing fast parallel searches.
276+
"""
277+
return (key * self.fingerprint_multiplier) & ((1 << 64) - 1)
278+
279+
def search(self, key):
280+
"""
281+
Searches for a key in the Fusion Tree using bitwise sketching and fingerprinting.
282+
283+
Parameters
284+
==========
285+
286+
key: int
287+
The integer key to search.
288+
289+
Returns
290+
=======
291+
292+
int: The index of the key in the tree, or None if not found.
293+
"""
294+
sketch = self._sketch_key(key)
295+
fingerprint = self._fingerprint(key)
296+
for i in range(self.size):
297+
if self._sketch_key(self.tree[i].key) == sketch and self._fingerprint(self.tree[i].key) == fingerprint:
298+
return i
299+
return None
300+
301+
def delete(self, key):
302+
"""
303+
Deletes a key from the Fusion Tree.
304+
305+
Parameters
306+
==========
307+
308+
key: int
309+
The integer key to delete.
310+
311+
Returns
312+
=======
313+
314+
bool: True if the key was successfully deleted, False otherwise.
315+
316+
"""
317+
index = self.search(key)
318+
if index is not None:
319+
self.tree[index] = None # Soft delete
320+
# Compact tree
321+
self.tree = [node for node in self.tree if node is not None]
322+
self.size -= 1
323+
if self.size > 1:
324+
self._compute_sketch_mask()
325+
return True
326+
return False
327+
328+
def __str__(self):
329+
"""
330+
Returns a string representation of the Fusion Tree.
331+
"""
332+
return str([(node.key, node.data) for node in self.tree if node is not None])

0 commit comments

Comments
 (0)