From 9c6f4518d08ab1e9813994bde479d482578808d3 Mon Sep 17 00:00:00 2001 From: Ahmad Zafar Date: Mon, 28 Apr 2025 14:43:10 +0500 Subject: [PATCH] some bug fixes and isolated dft function added --- dftlib/storage/dft_gates.py | 2 +- dftlib/transformer/rewrite_rules.py | 11 +++-- dftlib/transformer/trimming.py | 77 +++++++++++++++++++++++++---- 3 files changed, 76 insertions(+), 14 deletions(-) diff --git a/dftlib/storage/dft_gates.py b/dftlib/storage/dft_gates.py index f147e88..c29282c 100644 --- a/dftlib/storage/dft_gates.py +++ b/dftlib/storage/dft_gates.py @@ -242,7 +242,7 @@ def compare(self, other, respect_ids): if not super().compare(other, respect_ids): return False - if not self.compare_successors(other, ordered=True, respect_ids=respect_ids): + if not self.compare_successors(other, ordered=True, respect_ids=True): return False return self.inclusive == other.inclusive diff --git a/dftlib/transformer/rewrite_rules.py b/dftlib/transformer/rewrite_rules.py index fb48ea3..8a57c00 100644 --- a/dftlib/transformer/rewrite_rules.py +++ b/dftlib/transformer/rewrite_rules.py @@ -538,6 +538,9 @@ def try_replace_fdep_by_or(dft, fdep): trigger = fdep.trigger() dependent = fdep.dependent()[0] + if dependent.relevant: + return False + # Check if both trigger and dependent are part of the top module top_module = dft.get_module(dft.top_level_element) if trigger.element_id not in top_module or dependent.element_id not in top_module: @@ -577,9 +580,6 @@ def try_remove_superfluous_fdep(dft, fdep): trigger = fdep.trigger() dependent = fdep.dependent()[0] - # Trigger is single parent of dependent (apart from fdep) - if len(dependent.parents()) > 2: - return False if trigger not in dependent.parents(): return False @@ -628,10 +628,13 @@ def try_remove_fdep_successors(dft, fdep): trigger = fdep.trigger() dependent = fdep.dependent()[0] + if dependent.relevant: + return False + # Dependent has single parent (apart from fdep) if len(dependent.parents()) > 2: return False - parent = dependent.parents()[0] if not isinstance(dependent, dft_gates.DftDependency) else dependent.parents()[1] + parent = dependent.parents()[0] if not isinstance(dependent.parents()[0], dft_gates.DftDependency) else dependent.parents()[1] # Trigger has the same parent if trigger not in parent.children(): diff --git a/dftlib/transformer/trimming.py b/dftlib/transformer/trimming.py index f285bed..49e07db 100644 --- a/dftlib/transformer/trimming.py +++ b/dftlib/transformer/trimming.py @@ -2,6 +2,20 @@ import dftlib.storage.dft_gates as dft_gates +def get_releated_parents(current, visited, related_parents_visited): + related_parents = [] + + if isinstance(current, dft_gates.DftDependency) or isinstance(current, dft_gates.DftSeq) or isinstance(current, dft_gates.DftMutex) or isinstance(current, dft_gates.DftSpare): + if current.element_id not in visited: + related_parents.append(current) + if current not in related_parents_visited: + related_parents_visited.append(current) + for parent in current.parents(): + if (isinstance(parent, dft_gates.DftDependency) or isinstance(parent, dft_gates.DftSeq) or isinstance(parent, dft_gates.DftMutex) or isinstance(parent, dft_gates.DftSpare) ) and parent.children()[0] == current: + continue + related_parents += get_releated_parents(parent, visited, related_parents_visited) + + return related_parents def trim(dft): """ @@ -25,15 +39,60 @@ def trim(dft): # Element is necessary del unused[current.element_id] - # Continue search - if current.is_be(): - # Add possible SEQ or FDEP gates - for parent in current.parents(): - if isinstance(parent, dft_gates.DftDependency) or isinstance(parent, dft_gates.DftSeq) or isinstance(parent, dft_gates.DftMutex): - if parent.element_id not in visited: - queue.append(parent) - visited.add(parent.element_id) - elif current.is_gate(): + related_parents = get_releated_parents(current, visited, []) + for related_parent in related_parents: + if related_parent.element_id not in visited: + queue.append(related_parent) + visited.add(related_parent.element_id) + + if current.is_gate(): + # Add children of gate + for child in current.children(): + if child.element_id not in visited: + queue.append(child) + visited.add(child.element_id) + + assert len(unused) == len(dft.elements) - len(visited) + + # Remove unused elements + trimmed = False + for element in unused.values(): + if not element.relevant: + dft.remove(element) + trimmed = True + return trimmed + + +def isolated(dft): + """ + Trim parts of the DFT in place which do not contribute to the top level element. + :param dft: DFT which will be modified. + :return: True iff elements were trimmed. + """ + + # List of possible unused elements to trim + unused = {elem_id: element for elem_id, element in dft.elements.items()} + visited = set() + + # Perform breadth-first search to find all necessary elements + queue = deque() + queue.append(dft.top_level_element) + visited.add(dft.top_level_element.element_id) + while len(queue) > 0: + current = queue.popleft() + + if current.element_id in unused: + # Element is necessary + del unused[current.element_id] + + if current != dft.top_level_element: + related_parents = get_releated_parents(current, visited, []) + for related_parent in related_parents: + if related_parent.element_id not in visited: + queue.append(related_parent) + visited.add(related_parent.element_id) + + if current.is_gate(): # Add children of gate for child in current.children(): if child.element_id not in visited: