Skip to content
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
20 changes: 13 additions & 7 deletions cirbo/minimization/simplification/cleanup.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,21 +16,27 @@
logger = logging.getLogger(__name__)


def cleanup(circuit: Circuit) -> Circuit:
def cleanup(circuit: Circuit, *, use_heavy: bool = False) -> Circuit:
"""
Applies several simplification algorithms from this module consecutively in order to
simplify provided circuit.

:param circuit: the original circuit to be simplified
:param use_heavy: if True, then heavier cleanups (e.g. `MergeEquivalentGates`)
will also be used.
:return: new simplified version of the circuit

"""
_strategies = [
RemoveRedundantGates(),
MergeUnaryOperators(),
MergeDuplicateGates(),
]

if use_heavy:
_strategies += [MergeEquivalentGates()]

return Transformer.apply_transformers(
circuit,
[
RemoveRedundantGates(),
MergeUnaryOperators(),
MergeDuplicateGates(),
MergeEquivalentGates(),
],
_strategies,
)
34 changes: 29 additions & 5 deletions cirbo/minimization/simplification/merge_equivalent_gates.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import collections
import dataclasses
import logging
import typing as tp

Expand Down Expand Up @@ -66,6 +67,25 @@ def _find_equivalent_gates_groups(circuit: Circuit) -> list[list[Label]]:
return equivalent_groups


@dataclasses.dataclass
class _Keep:
"""
A representative element for the group.

If holds None, then no elements of the group were reconstructed yet. When the first
element of the group is rebuild, It will be set as Keep.

"""

value: tp.Optional[str] = None

def set_or_get_existing(self, label: str) -> str:
if self.value is None:
self.value = label

return self.value


def _replace_equivalent_gates(
circuit: Circuit,
equivalent_groups: tp.Iterable[tp.Collection[Label]],
Expand All @@ -92,15 +112,19 @@ def _replace_equivalent_gates(
)
continue

_group_iter = iter(group)
keep = next(_group_iter)
for gate_to_replace in _group_iter:
keep = _Keep()
for gate_to_replace in group:
_old_to_new_gate[gate_to_replace] = keep

# map gate label to its new name.
# map gate label to its new name and sets Keep when needed.
def _get_gate_new_name(_label: Label):
nonlocal _old_to_new_gate
return _old_to_new_gate.get(_label, _label)

if _label not in _old_to_new_gate:
return _label

_keep = _old_to_new_gate[_label]
return _keep.set_or_get_existing(_label)

# rebuild circuit from inputs to outputs with remapping.
def _process_gate(_gate: Gate, _: tp.Mapping):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,10 +76,10 @@ def test_find_equivalent_gates(original_circuit: Circuit, expected_groups):
expected_circuit_3.add_gate(Gate('input4', gate.INPUT))
expected_circuit_3.emplace_gate('AND2', gate.AND, ('input1', 'input2'))
expected_circuit_3.add_gate(Gate('OR2', gate.OR, ('AND2', 'input3')))
expected_circuit_3.add_gate(Gate('XOR2', gate.XOR, ('AND2', 'OR2')))
expected_circuit_3.add_gate(Gate('XOR1', gate.XOR, ('AND2', 'OR2')))
expected_circuit_3.mark_as_output('AND2')
expected_circuit_3.mark_as_output('XOR2')
expected_circuit_3.mark_as_output('XOR2')
expected_circuit_3.mark_as_output('XOR1')
expected_circuit_3.mark_as_output('XOR1')


@pytest.mark.parametrize(
Expand Down
2 changes: 1 addition & 1 deletion tutorial/cleaning_majority7_circuit.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,5 @@
*_, b2 = add_sum_n_bits(ckt, ckt.inputs)
ckt.mark_as_output(b2)
print(ckt.gates_number())
ckt = cleanup(ckt)
ckt = cleanup(ckt, use_heavy=True)
print(ckt.gates_number())
5 changes: 5 additions & 0 deletions tutorial/simple_cleanup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
from cirbo.core import Circuit, Gate
from cirbo.minimization import cleanup

circ = Circuit.from_bench_file("../data/circuit.bench")
circ = cleanup(circ)