From e8bcbd323776640039ff2f4c4818addb3b98d4af Mon Sep 17 00:00:00 2001 From: Oliver Huettenhofer Date: Sat, 30 Nov 2024 09:15:10 +0100 Subject: [PATCH] Improve circuit compilation performance --- src/tequila/circuit/circuit.py | 35 +++++++++++-------- src/tequila/utils/bitstrings.py | 6 ++++ .../wavefunction/qubit_wavefunction.py | 2 +- 3 files changed, 27 insertions(+), 16 deletions(-) diff --git a/src/tequila/circuit/circuit.py b/src/tequila/circuit/circuit.py index de47b77a..57bd3d99 100644 --- a/src/tequila/circuit/circuit.py +++ b/src/tequila/circuit/circuit.py @@ -9,6 +9,7 @@ from .qpic import export_to + class QCircuit(): """ Fundamental class representing an abstract circuit. @@ -254,8 +255,8 @@ def replace_gates(self, positions: list, circuits: list, replace: list = None): the gates to add at the corresponding positions replace: list of bool: (Default value: None) Default is None which corresponds to all true - decide if gates shall be replaces or if the new parts shall be inserted without replacement - if replace[i] = true: gate at position [i] will be replaces by gates[i] + decide if gates shall be replaced or if the new parts shall be inserted without replacement + if replace[i] = true: gate at position [i] will be replaced by gates[i] if replace[i] = false: gates[i] circuit will be inserted at position [i] (beaming before gate previously at position [i]) Returns ------- @@ -271,8 +272,9 @@ def replace_gates(self, positions: list, circuits: list, replace: list = None): dataset = zip(positions, circuits, replace) dataset = sorted(dataset, key=lambda x: x[0]) - offset = 0 - new_gatelist = self.gates + new_gatelist = [] + last_idx = -1 + for idx, circuit, do_replace in dataset: # failsafe @@ -283,13 +285,14 @@ def replace_gates(self, positions: list, circuits: list, replace: list = None): else: gatelist = [circuit] - pos = idx + offset - if do_replace: - new_gatelist = new_gatelist[:pos] + gatelist + new_gatelist[pos + 1:] - offset += len(gatelist) - 1 - else: - new_gatelist = new_gatelist[:pos] + gatelist + new_gatelist[pos:] - offset += len(gatelist) + new_gatelist += self.gates[last_idx + 1:idx] + new_gatelist += gatelist + if not do_replace: + new_gatelist.append(self.gates[idx]) + + last_idx = idx + + new_gatelist += self.gates[last_idx + 1:] result = QCircuit(gates=new_gatelist) result.n_qubits = max(result.n_qubits, self.n_qubits) @@ -386,7 +389,7 @@ def __iadd__(self, other): for k, v in other._parameter_map.items(): self._parameter_map[k] += [(x[0] + offset, x[1]) for x in v] - self._gates += copy.deepcopy(other.gates) + self._gates += other.gates self._min_n_qubits = max(self._min_n_qubits, other._min_n_qubits) return self @@ -593,7 +596,7 @@ def _inpl_control_circ(self, control) -> None: This is an in-place method, so it mutates self and doesn't return any value. - Raise TequilaWarning if there any qubits in common between self and control. + Raise TequilaWarning if there are any qubits in common between self and control. """ gates = self.gates control = list_assignment(control) @@ -610,8 +613,10 @@ def _inpl_control_circ(self, control) -> None: if len(control_lst) < len(gate.control) + len(control): # warnings.warn("Some of the controls {} were already included in the control " # "of a gate {}.".format(control, gate), TequilaWarning) - raise TequilaWarning(f'Some of the controls {control} were already included ' - f'in the control of a gate {gate}.') + raise TequilaWarning(f"Some of the controls {control} were already included " + f"in the control of a gate {gate}. " + f"This might be because the same instance of a gate is used in multiple places, " + f"e.g. because the same circuit was appended twice.") else: control_lst, not_control = list(control), list() diff --git a/src/tequila/utils/bitstrings.py b/src/tequila/utils/bitstrings.py index 9ae7cb20..3db1293d 100644 --- a/src/tequila/utils/bitstrings.py +++ b/src/tequila/utils/bitstrings.py @@ -69,6 +69,12 @@ def integer(self, other: int): self.update_nbits() return self + def to_integer(self, numbering: BitNumbering): + if numbering == self.numbering: + return self.integer + else: + return reverse_int_bits(self.integer, self.nbits) + @property def array(self): return [int(i) for i in self.binary] diff --git a/src/tequila/wavefunction/qubit_wavefunction.py b/src/tequila/wavefunction/qubit_wavefunction.py index e7f48ad9..1c700d1c 100644 --- a/src/tequila/wavefunction/qubit_wavefunction.py +++ b/src/tequila/wavefunction/qubit_wavefunction.py @@ -365,7 +365,7 @@ def normalize(self, inplace: bool = False) -> QubitWaveFunction: # because the __mul__ implementation of the number tries to perform some sort of array # operation. def length(self): - return sum(1 for _ in self.raw_items()) + return sum(1 for (k, v) in self.raw_items() if abs(v) > 1e-6) def __repr__(self): result = str()