Skip to content

Commit

Permalink
Add the infrastructure to change the segment tree's query function
Browse files Browse the repository at this point in the history
  • Loading branch information
bennett-nguyen committed Sep 7, 2024
1 parent c4cebdd commit 9fc2dbf
Show file tree
Hide file tree
Showing 6 changed files with 87 additions and 20 deletions.
2 changes: 1 addition & 1 deletion src/MVC/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
class Model:
def __init__(self):
self.theme_manager = ThemeManager()
self.tree_manager = TreeManager([1, 3, -2, 8, -7], 0, lambda x, y: x + y)
self.tree_manager = TreeManager([1, 3, -2, 8, -7])

self.visibility_dict: dict[Visibility, bool] = {
Visibility.ARRAY_FIELD: True,
Expand Down
24 changes: 20 additions & 4 deletions src/MVC/model_helpers/tree_manager.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
from collections import deque

from typing import Callable
from src.preload.tree.segment_tree import SegmentTree
from src.preload.tree.node import Node
import src.preload.system.constants as const
from src.preload.system.app_enum import Contour

from src.preload.function import Function
from src.preload.exports.segment_tree_functions import exported_functions as st_exported_functions

class TreeManager:
def __init__(self, data: list[int], invalid_query_val: int, function: Callable[[int, int], int]):
self.segment_tree = SegmentTree(data, invalid_query_val, function)
def __init__(self, data: list[int]):
self.available_functions: dict[str, Function] = {}
self.load_functions(st_exported_functions)

self.current_function: Function = self.available_functions["add_f"]
self.segment_tree = SegmentTree(data, self.current_function)

def generate_node_position(self):
"""Generate the position of nodes in a tree structure.
Expand All @@ -19,6 +23,18 @@ def generate_node_position(self):
self._compute_prelim_x(self.segment_tree.root)
self._compute_final_coordinates(self.segment_tree.root, 0)

def switch_function(self, name: str):
self.current_function = self.available_functions[name]
self.segment_tree.switch_function(self.current_function)

def load_functions(self, exported_functions: list[Function]):
for function in exported_functions:
if function in self.available_functions:
print(f"Function <{function.name}> already existed! Skipping...")
continue

self.available_functions[function.name] = function

def move_tree_by_delta_pos(self, delta_x: int, delta_y: int):
"""Move a tree and its children by specified delta values.
Expand Down
42 changes: 42 additions & 0 deletions src/preload/exports/segment_tree_functions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import math

from src.preload.function import Function

_lcm = lambda x, y: x * y / math.gcd(x, y)

min_f = Function("min_f", min, -1)
max_f = Function("max_f", max, -1)

add_f = Function("add_f", lambda x, y: x + y, -1)
sub_f = Function("sub_f", lambda x, y: x - y, -1)
mul_f = Function("mul_f", lambda x, y: x * y, -1)
exp_f = Function("exp_f", lambda x, y: x ** y, -1)
mod_f = Function("mod_f", lambda x, y: x % y, -1)

and_f = Function("and_f", lambda x, y: x & y, -1)
or_f = Function("or_f", lambda x, y: x | y, -1)
xor_f = Function("xor_f", lambda x, y: x ^ y, -1)

lcm_f = Function("lcm_f", _lcm, -1)
gcd_f = Function("gcd_f", math.gcd, 1)

avg_f = Function("avg_f", lambda x, y: int((x+y)/2), 0)

exported_functions: list[Function] = [
min_f,
max_f,

add_f,
sub_f,
mul_f,
exp_f,
mod_f,

and_f,
or_f,
xor_f,

lcm_f,
gcd_f,
avg_f,
]
9 changes: 9 additions & 0 deletions src/preload/function.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
from typing import Callable

class Function:
__slots__ = ("name", "fn", "invalid_query_val")

def __init__(self, name: str, fn: Callable[[int, int], int], invalid_query_val: int):
self.name = name
self.fn = fn
self.invalid_query_val = invalid_query_val
6 changes: 3 additions & 3 deletions src/preload/tree/node.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from typing import Optional, Tuple
from typing import Optional

import src.preload.system.constants as const

Expand Down Expand Up @@ -43,7 +43,7 @@ def construct(self, low: int, high: int, ID: int) -> None:
self.high = high

@property
def children(self) -> Tuple['Node', 'Node']:
def children(self) -> tuple['Node', 'Node']:
return (self.left, self.right)

@property
Expand All @@ -52,7 +52,7 @@ def previous_sibling(self) -> Optional['Node']:
else self.parent.left

@property
def coordinates(self) -> Tuple[int, int]:
def coordinates(self) -> tuple[int, int]:
return (self.x, self.y)

def is_leaf(self) -> bool:
Expand Down
24 changes: 12 additions & 12 deletions src/preload/tree/segment_tree.py
Original file line number Diff line number Diff line change
@@ -1,25 +1,21 @@
from typing import Callable, List

from src.preload.tree.node import Node

from src.preload.function import Function

class SegmentTree:
def __init__(self, array: List[int], invalid_query_val: int, function: Callable[[int, int], int]):
"""Initialize a segment tree with the given array and query function.
def __init__(self, array: list[int], function_obj: Function):
"""Initialize a segment tree with the given array and function object.
This constructor sets up the segment tree by storing the input array, defining the function used for queries, and initializing the root node. It also builds the segment tree structure based on the provided array.
This constructor sets up the segment tree by storing the input array and defining the function used for queries. It initializes the root node and builds the segment tree structure based on the provided array.
Args:
array (List[int]): The array of integers to be represented in the segment tree.
invalid_query_val (int): The value to return for invalid queries.
function (Callable[[int, int], int]): The function used to combine values in the segment tree.
array (list[int]): The array of integers to be represented in the segment tree.
function_obj (Function): An object containing the function used for combining values and the value to return for invalid queries.
"""
self.array = array
self.root = Node()

self._fn = function
self._INVALID_QUERY = invalid_query_val
self._fn = function_obj.fn
self._INVALID_QUERY = function_obj.invalid_query_val
self._build(self.root, 0, self.array_length-1)

@property
Expand All @@ -33,6 +29,10 @@ def array_length(self) -> int:
"""
return len(self.array)

def switch_function(self, function_obj: Function):
self._fn = function_obj._fn
self._INVALID_QUERY = function_obj.invalid_query_val

def query(self, q_low: int, q_high: int) -> int:
"""Retrieve the result of a query on the segment tree for a specified range.
Expand Down

0 comments on commit 9fc2dbf

Please sign in to comment.