<commit_before>#   Licensed under the Apache License, Version 2.0 (the "License");
#   you may not use this file except in compliance with the License.
#   You may obtain a copy of the License at
#
#       http://www.apache.org/licenses/LICENSE-2.0
#
#   Unless required by applicable law or agreed to in writing, software
#   distributed under the License is distributed on an "AS IS" BASIS,
#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#   See the License for the specific language governing permissions and
#   limitations under the License.

"""
Contains a local optimizer engine.
"""

from copy import deepcopy as _deepcopy
from projectq.cengines import LastEngineException, BasicEngine
from projectq.ops import FlushGate, FastForwardingGate, NotMergeable


class LocalOptimizer(BasicEngine):
    """
    LocalOptimizer is a compiler engine which optimizes locally (merging
    rotations, cancelling gates with their inverse) in a local window of user-
    defined size.

    It stores all commands in a list of lists, where each qubit has its own
    gate pipeline. After adding a gate, it tries to merge / cancel successive
    gates using the get_merged and get_inverse functions of the gate (if
    available). For examples, see BasicRotationGate. Once a list corresponding
    to a qubit contains >=m gates, the pipeline is sent on to the next engine.
    """
    def __init__(self, m=5):
        """
        Initialize a LocalOptimizer object.

        Args:
            m (int): Number of gates to cache per qubit, before sending on the
                first gate.
        """
        BasicEngine.__init__(self)
        self._l = [[]]  # list of lists containing operations for each qubit
        self._m = m  # wait for m gates before sending on

    # sends n gate operations of the qubit with index idx
    def _send_qubit_pipeline(self, idx, n):
        """
        Send n gate operations of the qubit with index idx to the next engine.
        """
        il = self._l[idx]  # temporary label for readability
        for i in range(0, min(n, len(il))):  # loop over first n operations
            # send all gates before n-qubit gate for other qubits involved
            # --> recursively call send_helper
            for qreg in il[i].all_qubits:  # loop over tuples of quregs
                for qb in qreg:  # ... and qubits involved
                    Id = qb.id
                    if Id != idx:  # is a different qubit than the current one
                        try:
                            gateloc = 0
                            # find location of this gate within its list
                            while self._l[Id][gateloc] != il[i]:
                                gateloc += 1

                            gateloc = self._optimize(Id, gateloc)

                            # flush the gates before the n-qubit gate
                            self._send_qubit_pipeline(Id, gateloc)
                            # delete the n-qubit gate, we're taking care of it
                            # and don't want the other qubit to do so
                            self._l[Id] = self._l[Id][1:]
                        except IndexError:
                            print("Invalid qubit pipeline encountered (in the"
                                  " process of shutting down?).")

            # all qubits that need to be flushed have been flushed
            # --> send on the n-qubit gate
            self.send([il[i]])
        # n operations have been sent on --> resize our gate list
        self._l[idx] = self._l[idx][n:]

    def _get_gate_indices(self, idx, i, IDs):
        """
        Return all indices of a command, each index corresponding to the
        command's index in one of the qubits' command lists.

        Args:
            idx (int): qubit index
            i (int): command position in qubit idx's command list
            IDs (list<int>): IDs of all qubits involved in the command
        """
        N = len(IDs)
        # 1-qubit gate: only gate at index i in list #idx is involved
        if N == 1:
            return [i]
        indices = [0] * N

        numidentical = 0  # number of identical commands (gate & arguments)
        j = 0
        while j < i:
            # this gate would otherwise be recognized as the right one in
            # other qubits find #times this happens before the right gate
            # is found
            if self._l[idx][j] == self._l[idx][i]:
                numidentical += 1<commit_msg>Cleanup LocalOptimizer._send_qubit_pipeline a bit (#88)<commit_after>#   Licensed under the Apache License, Version 2.0 (the "License");
#   you may not use this file except in compliance with the License.
#   You may obtain a copy of the License at
#
#       http://www.apache.org/licenses/LICENSE-2.0
#
#   Unless required by applicable law or agreed to in writing, software
#   distributed under the License is distributed on an "AS IS" BASIS,
#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#   See the License for the specific language governing permissions and
#   limitations under the License.

"""
Contains a local optimizer engine.
"""

from copy import deepcopy as _deepcopy
from projectq.cengines import LastEngineException, BasicEngine
from projectq.ops import FlushGate, FastForwardingGate, NotMergeable


class LocalOptimizer(BasicEngine):
    """
    LocalOptimizer is a compiler engine which optimizes locally (merging
    rotations, cancelling gates with their inverse) in a local window of user-
    defined size.

    It stores all commands in a list of lists, where each qubit has its own
    gate pipeline. After adding a gate, it tries to merge / cancel successive
    gates using the get_merged and get_inverse functions of the gate (if
    available). For examples, see BasicRotationGate. Once a list corresponding
    to a qubit contains >=m gates, the pipeline is sent on to the next engine.
    """
    def __init__(self, m=5):
        """
        Initialize a LocalOptimizer object.

        Args:
            m (int): Number of gates to cache per qubit, before sending on the
                first gate.
        """
        BasicEngine.__init__(self)
        self._l = [[]]  # list of lists containing operations for each qubit
        self._m = m  # wait for m gates before sending on

    # sends n gate operations of the qubit with index idx
    def _send_qubit_pipeline(self, idx, n):
        """
        Send n gate operations of the qubit with index idx to the next engine.
        """
        il = self._l[idx]  # temporary label for readability
        for i in range(min(n, len(il))):  # loop over first n operations
            # send all gates before n-qubit gate for other qubits involved
            # --> recursively call send_helper
            other_involved_qubits = [qb
                                     for qreg in il[i].all_qubits
                                     for qb in qreg
                                     if qb.id != idx]
            for qb in other_involved_qubits:
                Id = qb.id
                try:
                    gateloc = 0
                    # find location of this gate within its list
                    while self._l[Id][gateloc] != il[i]:
                        gateloc += 1

                    gateloc = self._optimize(Id, gateloc)

                    # flush the gates before the n-qubit gate
                    self._send_qubit_pipeline(Id, gateloc)
                    # delete the n-qubit gate, we're taking care of it
                    # and don't want the other qubit to do so
                    self._l[Id] = self._l[Id][1:]
                except IndexError:
                    print("Invalid qubit pipeline encountered (in the"
                          " process of shutting down?).")

            # all qubits that need to be flushed have been flushed
            # --> send on the n-qubit gate
            self.send([il[i]])
        # n operations have been sent on --> resize our gate list
        self._l[idx] = self._l[idx][n:]

    def _get_gate_indices(self, idx, i, IDs):
        """
        Return all indices of a command, each index corresponding to the
        command's index in one of the qubits' command lists.

        Args:
            idx (int): qubit index
            i (int): command position in qubit idx's command list
            IDs (list<int>): IDs of all qubits involved in the command
        """
        N = len(IDs)
        # 1-qubit gate: only gate at index i in list #idx is involved
        if N == 1:
            return [i]
        indices = [0] * N

        numidentical = 0  # number of identical commands (gate & arguments)
        j = 0
        while j < i:
            # this gate would otherwise be recognized as the right one in
            # other qubits find #times this happens before the right gate
            # is found
            if self._l[idx][j] == self._l[idx][i]:
                numidentical += 1
{'fraction_non_alphanumeric': 0.06859485815602837, 'fraction_numerical': 0.0034352836879432626, 'mean_word_length': 1.8362664990571966, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 13, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 7, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6320090', 'n_tokens_mistral': 2375, 'n_tokens_neox': 2268, 'n_words': 1026}