Source code for bqskit.passes.control.predicates.change

"""This module implements the ChangePredicate class."""
from __future__ import annotations

import logging
from typing import TYPE_CHECKING

from bqskit.passes.control.predicate import PassPredicate

if TYPE_CHECKING:
    from bqskit.compiler.passdata import PassData
    from bqskit.ir.circuit import Circuit


_logger = logging.getLogger(__name__)


[docs] class ChangePredicate(PassPredicate): """ The ChangePredicate class. The ChangePredicate returns true if the circuit has changed since the last call. On the first call, the predicate returns true. """ key = 'ChangePredicate_circuit_hash'
[docs] def get_truth_value(self, circuit: Circuit, data: PassData) -> bool: """Call this predicate, see :class:`PassPredicate` for more info.""" # If first call, record data and return true if self.key not in data: _logger.debug(f'Could not find {self.key} key.') data[self.key] = self.get_hash(circuit) return True # Otherwise, check for a change and return accordingly new_hash = self.get_hash(circuit) if data[self.key] == new_hash: # TODO: hash collisions? _logger.debug('Hashes match; no change detected.') return False data[self.key] = new_hash _logger.debug('Hashes do not match; change detected.') return True
[docs] def get_hash(self, circuit: Circuit) -> int: """Retreive hash associated with `circuit`.""" _logger.debug('Calculating hash for circuit...') if len(circuit) == 0: return hash(tuple()) hashes: list[int] = [] for op in circuit: hashes.append(hash(repr(op))) # Don't let the hash list grow too large. if len(hashes) >= 100: hashes = [hash(tuple(hashes))] hash_val = hash(tuple(hashes)) if len(hashes) > 1 else hashes[0] _logger.debug(f'Hash: {hash_val}') return hash_val