示例#1
0
def test_send_possible_commands_allocate():
    mapper = lm.LinearMapper(num_qubits=4, cyclic=False)
    backend = DummyEngine(save_commands=True)
    backend.is_last_engine = True
    mapper.next_engine = backend
    qb0 = WeakQubitRef(engine=None, idx=0)
    cmd0 = Command(engine=None, gate=Allocate, qubits=([qb0],), controls=[], tags=[])
    mapper._stored_commands = [cmd0]
    mapper._currently_allocated_ids = {10}
    # not in mapping:
    mapper.current_mapping = {}
    assert len(backend.received_commands) == 0
    mapper._send_possible_commands()
    assert len(backend.received_commands) == 0
    assert mapper._stored_commands == [cmd0]
    # in mapping:
    mapper.current_mapping = {0: 3}
    mapper._send_possible_commands()
    assert len(mapper._stored_commands) == 0
    assert len(backend.received_commands) == 1
    assert backend.received_commands[0].gate == Allocate
    assert backend.received_commands[0].qubits[0][0].id == 3
    assert backend.received_commands[0].tags == [LogicalQubitIDTag(0)]
    assert mapper._currently_allocated_ids == {10, 0}
示例#2
0
def test_run_infinite_loop_detection():
    mapper = two_d.GridMapper(num_rows=2, num_columns=2)
    backend = DummyEngine(save_commands=True)
    backend.is_last_engine = True
    mapper.next_engine = backend
    qb0 = WeakQubitRef(engine=None, idx=0)
    qb1 = WeakQubitRef(engine=None, idx=1)
    qb2 = WeakQubitRef(engine=None, idx=2)
    qb3 = WeakQubitRef(engine=None, idx=3)
    qb4 = WeakQubitRef(engine=None, idx=4)
    cmd0 = Command(engine=None, gate=Allocate, qubits=([qb0],))
    cmd1 = Command(engine=None, gate=Allocate, qubits=([qb1],))
    cmd2 = Command(engine=None, gate=Allocate, qubits=([qb2],))
    cmd3 = Command(engine=None, gate=Allocate, qubits=([qb3],))
    cmd4 = Command(engine=None, gate=Allocate, qubits=([qb4],))
    cmd5 = Command(None, X, qubits=([qb0],), controls=[qb1])
    qb2 = WeakQubitRef(engine=None, idx=-1)
    cmd_flush = Command(engine=None, gate=FlushGate(), qubits=([qb2],))
    with pytest.raises(RuntimeError):
        mapper.receive([cmd0, cmd1, cmd2, cmd3, cmd4, cmd5, cmd_flush])
def test_run_and_receive():
    mapper = lm.LinearMapper(num_qubits=3, cyclic=False)
    backend = DummyEngine(save_commands=True)
    backend.is_last_engine = True
    mapper.next_engine = backend
    qb0 = WeakQubitRef(engine=None, idx=0)
    qb1 = WeakQubitRef(engine=None, idx=1)
    qb2 = WeakQubitRef(engine=None, idx=2)
    cmd0 = Command(engine=None, gate=Allocate, qubits=([qb0],))
    cmd1 = Command(engine=None, gate=Allocate, qubits=([qb1],))
    cmd2 = Command(engine=None, gate=Allocate, qubits=([qb2],))
    cmd3 = Command(None, X, qubits=([qb0],), controls=[qb1])
    cmd4 = Command(None, X, qubits=([qb1],), controls=[qb2])
    cmd5 = Command(engine=None, gate=Deallocate, qubits=([qb1],))
    mapper.receive([cmd0, cmd1, cmd2, cmd3, cmd4, cmd5])
    assert mapper._stored_commands == [cmd0, cmd1, cmd2, cmd3, cmd4, cmd5]
    qb3 = WeakQubitRef(engine=None, idx=-1)
    cmd_flush = Command(engine=None, gate=FlushGate(), qubits=([qb3],))
    mapper.receive([cmd_flush])
    assert mapper._stored_commands == []
    assert len(backend.received_commands) == 7
    assert mapper._currently_allocated_ids == set([0, 2])
    assert (mapper.current_mapping == {0: 2, 2: 0} or
            mapper.current_mapping == {0: 0, 2: 2})
    cmd6 = Command(None, X, qubits=([qb0],), controls=[qb2])
    mapper.storage = 1
    mapper.receive([cmd6])
    assert mapper._currently_allocated_ids == set([0, 2])
    assert mapper._stored_commands == []
    assert len(mapper.current_mapping) == 2
    assert 0 in mapper.current_mapping
    assert 2 in mapper.current_mapping
    assert len(backend.received_commands) == 11
    for cmd in backend.received_commands:
        print(cmd)
    assert (backend.received_commands[-1] == Command(None, X,
            qubits=([WeakQubitRef(engine=None,
                                  idx=mapper.current_mapping[qb0.id])],),
            controls=[WeakQubitRef(engine=None,
                                   idx=mapper.current_mapping[qb2.id])]))
    assert mapper.num_mappings == 1
示例#4
0
    def _run(self):
        """
        Run the circuit.

        Send the circuit via the AQT API using the provided user token / ask for the user token.
        """
        # finally: measurements
        # NOTE AQT DOESN'T SEEM TO HAVE MEASUREMENT INSTRUCTIONS (no
        # intermediate measurements are allowed, so implicit at the end)
        # return if no operations.
        if self._circuit == []:
            return

        n_qubit = max(self._allocated_qubits) + 1
        info = {}
        # Hack: AQT instructions specifically need "GATE" string representation
        # instead of 'GATE'
        info['circuit'] = str(self._circuit).replace("'", '"')
        info['nq'] = n_qubit
        info['shots'] = self._num_runs
        info['backend'] = {'name': self.device}
        if self._num_runs > 200:
            raise Exception("Number of shots limited to 200")
        try:
            if self._retrieve_execution is None:
                res = send(
                    info,
                    device=self.device,
                    token=self._token,
                    num_retries=self._num_retries,
                    interval=self._interval,
                    verbose=self._verbose,
                )
            else:
                res = retrieve(
                    device=self.device,
                    token=self._token,
                    jobid=self._retrieve_execution,
                    num_retries=self._num_retries,
                    interval=self._interval,
                    verbose=self._verbose,
                )
            self._num_runs = len(res)
            counts = _format_counts(res, n_qubit)
            # Determine random outcome
            random_outcome = random.random()
            p_sum = 0.0
            measured = ""
            for state in counts:
                probability = counts[state] * 1.0 / self._num_runs
                p_sum += probability
                star = ""
                if p_sum >= random_outcome and measured == "":
                    measured = state
                    star = "*"
                self._probabilities[state] = probability
                if self._verbose and probability > 0:
                    print(str(state) + " with p = " + str(probability) + star)

            # register measurement result from AQT
            for qubit_id in self._measured_ids:
                location = self._logical_to_physical(qubit_id)
                result = int(measured[location])
                self.main_engine.set_measurement_result(
                    WeakQubitRef(self, qubit_id), result)
            self._reset()
        except TypeError as err:
            raise Exception("Failed to run the circuit. Aborting.") from err
def test_invalid_arguments():
    qb0 = WeakQubitRef(engine=None, idx=0)
    qb1 = WeakQubitRef(engine=None, idx=1)
    cmd = Command(None, StatePreparation([0, 1j]), qubits=([qb0], [qb1]))
    with pytest.raises(ValueError):
        stateprep2cnot._decompose_state_preparation(cmd)
示例#6
0
def test_qubitop2singlequbit_invalid():
    qb0 = WeakQubitRef(None, idx=0)
    qb1 = WeakQubitRef(None, idx=1)
    with pytest.raises(ValueError):
        qubitop2onequbit._decompose_qubitop(
            Command(None, QubitOperator(), ([qb0], [qb1])))
示例#7
0
    def _handle(self, cmd):
        """
        Handle all commands, i.e., call the member functions of the C++-
        simulator object corresponding to measurement, allocation/
        deallocation, and (controlled) single-qubit gate.

        Args:
            cmd (Command): Command to handle.

        Raises:
            Exception: If a non-single-qubit gate needs to be processed
                (which should never happen due to is_available).
        """
        if cmd.gate == Measure:
            assert (get_control_count(cmd) == 0)
            ids = [qb.id for qr in cmd.qubits for qb in qr]
            out = self._simulator.measure_qubits(ids)
            i = 0
            for qr in cmd.qubits:
                for qb in qr:
                    # Check if a mapper assigned a different logical id
                    logical_id_tag = None
                    for tag in cmd.tags:
                        if isinstance(tag, LogicalQubitIDTag):
                            logical_id_tag = tag
                    if logical_id_tag is not None:
                        qb = WeakQubitRef(qb.engine,
                                          logical_id_tag.logical_qubit_id)
                    self.main_engine.set_measurement_result(qb, out[i])
                    i += 1
        elif cmd.gate == Allocate:
            ID = cmd.qubits[0][0].id
            self._simulator.allocate_qubit(ID)
        elif cmd.gate == Deallocate:
            ID = cmd.qubits[0][0].id
            self._simulator.deallocate_qubit(ID)
        elif isinstance(cmd.gate, BasicMathGate):
            # improve performance by using C++ code for some commomn gates
            from projectq.libs.math import (AddConstant, AddConstantModN,
                                            MultiplyByConstantModN)
            qubitids = []
            for qr in cmd.qubits:
                qubitids.append([])
                for qb in qr:
                    qubitids[-1].append(qb.id)
            if FALLBACK_TO_PYSIM:
                math_fun = cmd.gate.get_math_function(cmd.qubits)
                self._simulator.emulate_math(
                    math_fun, qubitids, [qb.id for qb in cmd.control_qubits])
            else:
                # individual code for different standard gates to make it faster!
                if isinstance(cmd.gate, AddConstant):
                    self._simulator.emulate_math_addConstant(
                        cmd.gate.a, qubitids,
                        [qb.id for qb in cmd.control_qubits])
                elif isinstance(cmd.gate, AddConstantModN):
                    self._simulator.emulate_math_addConstantModN(
                        cmd.gate.a, cmd.gate.N, qubitids,
                        [qb.id for qb in cmd.control_qubits])
                elif isinstance(cmd.gate, MultiplyByConstantModN):
                    self._simulator.emulate_math_multiplyByConstantModN(
                        cmd.gate.a, cmd.gate.N, qubitids,
                        [qb.id for qb in cmd.control_qubits])
                else:
                    math_fun = cmd.gate.get_math_function(cmd.qubits)
                    self._simulator.emulate_math(
                        math_fun, qubitids,
                        [qb.id for qb in cmd.control_qubits])
        elif isinstance(cmd.gate, TimeEvolution):
            op = [(list(term), coeff)
                  for (term, coeff) in cmd.gate.hamiltonian.terms.items()]
            t = cmd.gate.time
            qubitids = [qb.id for qb in cmd.qubits[0]]
            ctrlids = [qb.id for qb in cmd.control_qubits]
            self._simulator.emulate_time_evolution(op, t, qubitids, ctrlids)
        elif len(cmd.gate.matrix) <= 2**5:
            matrix = cmd.gate.matrix
            ids = [qb.id for qr in cmd.qubits for qb in qr]
            if not 2**len(ids) == len(cmd.gate.matrix):
                raise Exception("Simulator: Error applying {} gate: "
                                "{}-qubit gate applied to {} qubits.".format(
                                    str(cmd.gate),
                                    int(math.log(len(cmd.gate.matrix), 2)),
                                    len(ids)))
            self._simulator.apply_controlled_gate(
                matrix.tolist(), ids, [qb.id for qb in cmd.control_qubits])
            if not self._gate_fusion:
                self._simulator.run()
        else:
            raise Exception("This simulator only supports controlled k-qubit"
                            " gates with k < 6!\nPlease add an auto-replacer"
                            " engine to your list of compiler engines.")
示例#8
0
    def _handle(self, cmd):
        """
        Handle all commands.

        Args:
            cmd (Command): Command to handle.

        Raises:
            RuntimeError: If a measurement is performed before flush gate.
        """
        if isinstance(cmd.gate, AllocateQubitGate):
            self._qubit_map[cmd.qubits[0][0].id] = self._num_qubits
            self._num_qubits += 1
            self._unitary = np.kron(np.identity(2), self._unitary)
            self._state.extend([0] * len(self._state))

        elif isinstance(cmd.gate, DeallocateQubitGate):
            pos = self._qubit_map[cmd.qubits[0][0].id]
            self._qubit_map = {
                key: value - 1 if value > pos else value
                for key, value in self._qubit_map.items()
            }
            self._num_qubits -= 1
            self._is_valid = False

        elif isinstance(cmd.gate, MeasureGate):
            self._is_valid = False

            if not self._is_flushed:
                raise RuntimeError(
                    'Please make sure all previous gates are flushed before measurement so the state gets updated'
                )

            if get_control_count(cmd) != 0:
                raise ValueError(
                    'Cannot have control qubits with a measurement gate!')

            all_qubits = [qb for qr in cmd.qubits for qb in qr]
            measurements = self.measure_qubits([qb.id for qb in all_qubits])

            for qb, res in zip(all_qubits, measurements):
                # Check if a mapper assigned a different logical id
                for tag in cmd.tags:
                    if isinstance(tag, LogicalQubitIDTag):
                        qb = WeakQubitRef(qb.engine, tag.logical_qubit_id)
                        break
                self.main_engine.set_measurement_result(qb, res)

        elif isinstance(cmd.gate, FlushGate):
            self._flush()
        else:
            if not self._is_valid:
                self._flush()

                warnings.warn(
                    "Processing of other gates after a qubit deallocation or measurement will reset the unitary,"
                    "previous unitary can be accessed in history")
                self._history.append(self._unitary)
                self._unitary = np.identity(2**self._num_qubits, dtype=complex)
                self._state = np.array([1] + ([0] * (2**self._num_qubits - 1)),
                                       dtype=complex)
                self._is_valid = True

            self._is_flushed = False
            mask_list = _qidmask(
                [self._qubit_map[qb.id] for qr in cmd.qubits for qb in qr],
                [self._qubit_map[qb.id] for qb in cmd.control_qubits],
                self._num_qubits,
            )
            for mask in mask_list:
                cache = np.identity(2**self._num_qubits, dtype=complex)
                cache[np.ix_(mask, mask)] = cmd.gate.matrix
                self._unitary = cache @ self._unitary
示例#9
0
    def _run(self):  # pylint: disable=too-many-locals
        """
        Run the circuit.

        Send the circuit via a non documented IBM API (using JSON written
        circuits) using the provided user data / ask for the user token.
        """
        # finally: add measurements (no intermediate measurements are allowed)
        for measured_id in self._measured_ids:
            qb_loc = self.main_engine.mapper.current_mapping[measured_id]
            self.qasm += "\nmeasure q[{0}] -> c[{0}];".format(qb_loc)
            self._json.append({
                'qubits': [qb_loc],
                'name': 'measure',
                'memory': [qb_loc]
            })
        # return if no operations / measurements have been performed.
        if self.qasm == "":
            return
        max_qubit_id = max(self._allocated_qubits) + 1
        info = {}
        info['json'] = self._json
        info['nq'] = max_qubit_id

        info['shots'] = self._num_runs
        info['maxCredits'] = 10
        info['backend'] = {'name': self.device}
        try:
            if self._retrieve_execution is None:
                res = send(
                    info,
                    device=self.device,
                    token=self._token,
                    num_retries=self._num_retries,
                    interval=self._interval,
                    verbose=self._verbose,
                )
            else:
                res = retrieve(
                    device=self.device,
                    token=self._token,
                    jobid=self._retrieve_execution,
                    num_retries=self._num_retries,
                    interval=self._interval,
                    verbose=self._verbose,
                )
            counts = res['data']['counts']
            # Determine random outcome
            random_outcome = random.random()
            p_sum = 0.0
            measured = ""
            for state in counts:
                probability = counts[state] * 1.0 / self._num_runs
                state = "{0:b}".format(int(state, 0))
                state = state.zfill(max_qubit_id)
                # states in ibmq are right-ordered, so need to reverse state string
                state = state[::-1]
                p_sum += probability
                star = ""
                if p_sum >= random_outcome and measured == "":
                    measured = state
                    star = "*"
                self._probabilities[state] = probability
                if self._verbose and probability > 0:
                    print(str(state) + " with p = " + str(probability) + star)

            # register measurement result from IBM
            for qubit_id in self._measured_ids:
                location = self._logical_to_physical(qubit_id)
                result = int(measured[location])
                self.main_engine.set_measurement_result(
                    WeakQubitRef(self, qubit_id), result)
            self._reset()
        except TypeError as err:
            raise Exception("Failed to run the circuit. Aborting.") from err
示例#10
0
    def _send_possible_commands(self):
        """
        Sends the stored commands possible without changing the mapping.

        Note: self.current_mapping must exist already
        """
        active_ids = deepcopy(self._currently_allocated_ids)
        for logical_id in self.current_mapping:
            active_ids.add(logical_id)

        new_stored_commands = []
        for i in range(len(self._stored_commands)):
            cmd = self._stored_commands[i]
            if len(active_ids) == 0:
                new_stored_commands += self._stored_commands[i:]
                break
            if isinstance(cmd.gate, AllocateQubitGate):
                if cmd.qubits[0][0].id in self.current_mapping:
                    self._currently_allocated_ids.add(cmd.qubits[0][0].id)
                    qb = WeakQubitRef(
                        engine=self,
                        idx=self.current_mapping[cmd.qubits[0][0].id])
                    new_cmd = Command(
                        engine=self,
                        gate=AllocateQubitGate(),
                        qubits=([qb], ),
                        tags=[LogicalQubitIDTag(cmd.qubits[0][0].id)])
                    self.send([new_cmd])
                else:
                    new_stored_commands.append(cmd)
            elif isinstance(cmd.gate, DeallocateQubitGate):
                if cmd.qubits[0][0].id in active_ids:
                    qb = WeakQubitRef(
                        engine=self,
                        idx=self.current_mapping[cmd.qubits[0][0].id])
                    new_cmd = Command(
                        engine=self,
                        gate=DeallocateQubitGate(),
                        qubits=([qb], ),
                        tags=[LogicalQubitIDTag(cmd.qubits[0][0].id)])
                    self._currently_allocated_ids.remove(cmd.qubits[0][0].id)
                    active_ids.remove(cmd.qubits[0][0].id)
                    self._current_mapping.pop(cmd.qubits[0][0].id)
                    self.send([new_cmd])
                else:
                    new_stored_commands.append(cmd)
            else:
                send_gate = True
                mapped_ids = set()
                for qureg in cmd.all_qubits:
                    for qubit in qureg:
                        if qubit.id not in active_ids:
                            send_gate = False
                            break
                        mapped_ids.add(self.current_mapping[qubit.id])
                # Check that mapped ids are nearest neighbour
                if len(mapped_ids) == 2:
                    mapped_ids = list(mapped_ids)
                    diff = abs(mapped_ids[0] - mapped_ids[1])
                    if self.cyclic:
                        if diff != 1 and diff != self.num_qubits - 1:
                            send_gate = False
                    else:
                        if diff != 1:
                            send_gate = False
                if send_gate:
                    self._send_cmd_with_mapped_ids(cmd)
                else:
                    for qureg in cmd.all_qubits:
                        for qubit in qureg:
                            active_ids.discard(qubit.id)
                    new_stored_commands.append(cmd)
        self._stored_commands = new_stored_commands
示例#11
0
def test_run_and_receive(num_optimization_steps, different_backend_ids):
    if different_backend_ids:
        map_to_backend_ids = {0: 21, 1: 32, 2: 3, 3: 0}
    else:
        map_to_backend_ids = None

    def choose_last_permutation(swaps):
        choose_last_permutation.counter -= 1
        return choose_last_permutation.counter

    choose_last_permutation.counter = 100
    mapper = two_d.GridMapper(
        num_rows=2,
        num_columns=2,
        mapped_ids_to_backend_ids=map_to_backend_ids,
        optimization_function=choose_last_permutation,
        num_optimization_steps=num_optimization_steps,
    )
    backend = DummyEngine(save_commands=True)
    backend.is_last_engine = True
    mapper.next_engine = backend
    qb0 = WeakQubitRef(engine=None, idx=0)
    qb1 = WeakQubitRef(engine=None, idx=1)
    qb2 = WeakQubitRef(engine=None, idx=2)
    qb3 = WeakQubitRef(engine=None, idx=3)
    cmd0 = Command(engine=None, gate=Allocate, qubits=([qb0],))
    cmd1 = Command(engine=None, gate=Allocate, qubits=([qb1],))
    cmd2 = Command(engine=None, gate=Allocate, qubits=([qb2],))
    cmd3 = Command(engine=None, gate=Allocate, qubits=([qb3],))
    cmd4 = Command(None, X, qubits=([qb0],), controls=[qb1])
    cmd5 = Command(None, X, qubits=([qb1],), controls=[qb3])
    cmd6 = Command(None, X, qubits=([qb3],), controls=[qb2])
    cmd7 = Command(None, X, qubits=([qb0],), controls=[qb2])
    cmd8 = Command(engine=None, gate=Deallocate, qubits=([qb1],))
    all_cmd = [cmd0, cmd1, cmd2, cmd3, cmd4, cmd5, cmd6, cmd7, cmd8]
    mapper.receive(all_cmd)
    assert mapper._stored_commands == all_cmd
    qb4 = WeakQubitRef(engine=None, idx=-1)
    cmd_flush = Command(engine=None, gate=FlushGate(), qubits=([qb4],))
    mapper.receive([cmd_flush])
    assert mapper._stored_commands == []
    assert len(backend.received_commands) == 10
    assert mapper._currently_allocated_ids == {0, 2, 3}
    if different_backend_ids:
        assert (
            mapper.current_mapping == {0: 21, 2: 3, 3: 0}
            or mapper.current_mapping == {0: 32, 2: 0, 3: 21}
            or mapper.current_mapping == {0: 3, 2: 21, 3: 32}
            or mapper.current_mapping == {0: 0, 2: 32, 3: 3}
        )
    else:
        assert (
            mapper.current_mapping == {0: 0, 2: 2, 3: 3}
            or mapper.current_mapping == {0: 1, 2: 3, 3: 0}
            or mapper.current_mapping == {0: 2, 2: 0, 3: 1}
            or mapper.current_mapping == {0: 3, 2: 1, 3: 2}
        )
    cmd9 = Command(None, X, qubits=([qb0],), controls=[qb3])
    mapper.storage = 1
    mapper.receive([cmd9])
    assert mapper._currently_allocated_ids == {0, 2, 3}
    assert mapper._stored_commands == []
    assert len(mapper.current_mapping) == 3
    assert 0 in mapper.current_mapping
    assert 2 in mapper.current_mapping
    assert 3 in mapper.current_mapping
    assert mapper.num_mappings == 1
示例#12
0
    def _run(self):  # pylint: disable=too-many-locals.too-many-branches,too-many-statements
        """
        Create a new mapping and executes possible gates.

        It first allocates all 0, ..., self.num_qubits-1 mapped qubit ids, if they are not already used because we
        might need them all for the swaps. Then it creates a new map, swaps all the qubits to the new map, executes
        all possible gates, and finally deallocates mapped qubit ids which don't store any information.
        """
        num_of_stored_commands_before = len(self._stored_commands)
        if not self.current_mapping:
            self.current_mapping = {}
        else:
            self._send_possible_commands()
            if len(self._stored_commands) == 0:
                return
        new_row_major_mapping = self._return_new_mapping()
        # Find permutation of matchings with lowest cost
        swaps = None
        lowest_cost = None
        matchings_numbers = list(range(self.num_rows))
        if self.num_optimization_steps <= math.factorial(self.num_rows):
            permutations = itertools.permutations(matchings_numbers,
                                                  self.num_rows)
        else:
            permutations = []
            for _ in range(self.num_optimization_steps):
                permutations.append(
                    self._rng.sample(matchings_numbers, self.num_rows))
        for permutation in permutations:
            trial_swaps = self.return_swaps(
                old_mapping=self._current_row_major_mapping,
                new_mapping=new_row_major_mapping,
                permutation=permutation,
            )
            if swaps is None:
                swaps = trial_swaps
                lowest_cost = self.optimization_function(trial_swaps)
            elif lowest_cost > self.optimization_function(trial_swaps):
                swaps = trial_swaps
                lowest_cost = self.optimization_function(trial_swaps)
        if swaps:  # first mapping requires no swaps
            # Allocate all mapped qubit ids (which are not already allocated,
            # i.e., contained in self._currently_allocated_ids)
            mapped_ids_used = set()
            for logical_id in self._currently_allocated_ids:
                mapped_ids_used.add(
                    self._current_row_major_mapping[logical_id])
            not_allocated_ids = set(range(
                self.num_qubits)).difference(mapped_ids_used)
            for mapped_id in not_allocated_ids:
                qb = WeakQubitRef(
                    engine=self,
                    idx=self._mapped_ids_to_backend_ids[mapped_id])
                cmd = Command(engine=self,
                              gate=AllocateQubitGate(),
                              qubits=([qb], ))
                self.send([cmd])
            # Send swap operations to arrive at new_mapping:
            for qubit_id0, qubit_id1 in swaps:
                qb0 = WeakQubitRef(
                    engine=self,
                    idx=self._mapped_ids_to_backend_ids[qubit_id0])
                qb1 = WeakQubitRef(
                    engine=self,
                    idx=self._mapped_ids_to_backend_ids[qubit_id1])
                cmd = Command(engine=self, gate=Swap, qubits=([qb0], [qb1]))
                self.send([cmd])
            # Register statistics:
            self.num_mappings += 1
            depth = return_swap_depth(swaps)
            if depth not in self.depth_of_swaps:
                self.depth_of_swaps[depth] = 1
            else:
                self.depth_of_swaps[depth] += 1
            if len(swaps) not in self.num_of_swaps_per_mapping:
                self.num_of_swaps_per_mapping[len(swaps)] = 1
            else:
                self.num_of_swaps_per_mapping[len(swaps)] += 1
            # Deallocate all previously mapped ids which we only needed for the
            # swaps:
            mapped_ids_used = set()
            for logical_id in self._currently_allocated_ids:
                mapped_ids_used.add(new_row_major_mapping[logical_id])
            not_needed_anymore = set(range(
                self.num_qubits)).difference(mapped_ids_used)
            for mapped_id in not_needed_anymore:
                qb = WeakQubitRef(
                    engine=self,
                    idx=self._mapped_ids_to_backend_ids[mapped_id])
                cmd = Command(engine=self,
                              gate=DeallocateQubitGate(),
                              qubits=([qb], ))
                self.send([cmd])
        # Change to new map:
        self._current_row_major_mapping = new_row_major_mapping
        new_mapping = {}
        for logical_id, mapped_id in new_row_major_mapping.items():
            new_mapping[logical_id] = self._mapped_ids_to_backend_ids[
                mapped_id]
        self.current_mapping = new_mapping
        # Send possible gates:
        self._send_possible_commands()
        # Check that mapper actually made progress
        if len(self._stored_commands) == num_of_stored_commands_before:
            raise RuntimeError(
                "Mapper is potentially in an infinite loop. It is likely that the algorithm requires too"
                "many qubits. Increase the number of qubits for this mapper.")
示例#13
0
    def _send_possible_commands(self):  # pylint: disable=too-many-branches
        """
        Send the stored commands possible without changing the mapping.

        Note: self._current_row_major_mapping (hence also self.current_mapping) must exist already
        """
        active_ids = deepcopy(self._currently_allocated_ids)
        for logical_id in self._current_row_major_mapping:
            # So that loop doesn't stop before AllocateGate applied
            active_ids.add(logical_id)

        new_stored_commands = []
        for i, cmd in enumerate(self._stored_commands):
            if len(active_ids) == 0:
                new_stored_commands += self._stored_commands[i:]
                break
            if isinstance(cmd.gate, AllocateQubitGate):
                if cmd.qubits[0][0].id in self._current_row_major_mapping:
                    self._currently_allocated_ids.add(cmd.qubits[0][0].id)

                    mapped_id = self._current_row_major_mapping[cmd.qubits[0]
                                                                [0].id]
                    qb = WeakQubitRef(
                        engine=self,
                        idx=self._mapped_ids_to_backend_ids[mapped_id])
                    new_cmd = Command(
                        engine=self,
                        gate=AllocateQubitGate(),
                        qubits=([qb], ),
                        tags=[LogicalQubitIDTag(cmd.qubits[0][0].id)],
                    )
                    self.send([new_cmd])
                else:
                    new_stored_commands.append(cmd)
            elif isinstance(cmd.gate, DeallocateQubitGate):
                if cmd.qubits[0][0].id in active_ids:
                    mapped_id = self._current_row_major_mapping[cmd.qubits[0]
                                                                [0].id]
                    qb = WeakQubitRef(
                        engine=self,
                        idx=self._mapped_ids_to_backend_ids[mapped_id])
                    new_cmd = Command(
                        engine=self,
                        gate=DeallocateQubitGate(),
                        qubits=([qb], ),
                        tags=[LogicalQubitIDTag(cmd.qubits[0][0].id)],
                    )
                    self._currently_allocated_ids.remove(cmd.qubits[0][0].id)
                    active_ids.remove(cmd.qubits[0][0].id)
                    self._current_row_major_mapping.pop(cmd.qubits[0][0].id)
                    self._current_mapping.pop(cmd.qubits[0][0].id)
                    self.send([new_cmd])
                else:
                    new_stored_commands.append(cmd)
            else:
                send_gate = True
                mapped_ids = set()
                for qureg in cmd.all_qubits:
                    for qubit in qureg:
                        if qubit.id not in active_ids:
                            send_gate = False
                            break
                        mapped_ids.add(
                            self._current_row_major_mapping[qubit.id])
                # Check that mapped ids are nearest neighbour on 2D grid
                if len(mapped_ids) == 2:
                    qb0, qb1 = sorted(mapped_ids)
                    send_gate = False
                    if qb1 - qb0 == self.num_columns:
                        send_gate = True
                    elif qb1 - qb0 == 1 and qb1 % self.num_columns != 0:
                        send_gate = True
                if send_gate:
                    # Note: This sends the cmd correctly with the backend ids as it looks up the mapping in
                    #       self.current_mapping and not our internal mapping self._current_row_major_mapping
                    self._send_cmd_with_mapped_ids(cmd)
                else:
                    for qureg in cmd.all_qubits:
                        for qubit in qureg:
                            active_ids.discard(qubit.id)
                    new_stored_commands.append(cmd)
        self._stored_commands = new_stored_commands
示例#14
0
    def _run(self):
        """
        Run the circuit.

        Send the circuit via the AWS Boto3 SDK. Use the provided Access Key and Secret key or ask for them if not
        provided
        """
        # NB: the AWS Braket API does not require explicit measurement commands at the end of a circuit; after running
        # any circuit, all qubits are implicitly measured.  Also, AWS Braket currently does not support intermediate
        # measurements.

        # If the clear flag is set, nothing to do here...
        if self._clear:
            return

        # In Braket the results for the jobs are stored in S3.  You can recover the results from previous jobs using
        # the TaskArn (self._retrieve_execution).
        if self._retrieve_execution is not None:
            res = retrieve(
                credentials=self._credentials,
                task_arn=self._retrieve_execution,
                num_retries=self._num_retries,
                interval=self._interval,
                verbose=self._verbose,
            )
        else:
            # Return if no operations have been added.
            if not self._circuit:
                return

            n_qubit = len(self._allocated_qubits)
            info = {}
            info['circuit'] = self._circuithead + self._circuit.rstrip(
                ', ') + self._circuittail
            info['nq'] = n_qubit
            info['shots'] = self._num_runs
            info['backend'] = {'name': self.device}
            res = send(
                info,
                device=self.device,
                credentials=self._credentials,
                s3_folder=self._s3_folder,
                num_retries=self._num_retries,
                interval=self._interval,
                verbose=self._verbose,
            )

        counts = res

        # Determine random outcome
        random_outcome = random.random()
        p_sum = 0.0
        measured = ""
        for state in counts:
            probability = counts[state]
            p_sum += probability
            star = ""
            if p_sum >= random_outcome and measured == "":
                measured = state
                star = "*"
            self._probabilities[state] = probability
            if self._verbose and probability > 0:
                print(state + " with p = " + str(probability) + star)

        # register measurement result
        for qubit_id in self._measured_ids:
            result = int(measured[self._logical_to_physical(qubit_id)])
            self.main_engine.set_measurement_result(
                WeakQubitRef(self.main_engine, qubit_id), result)
        self._reset()
示例#15
0
def workspace(cmd):
    touched = set(q.id for reg in cmd.all_qubits for q in reg)
    avail = set(q.id for q in cmd.engine.main_engine.active_qubits)
    untouched = avail - touched
    result = list(WeakQubitRef(cmd.engine, qid) for qid in untouched)
    return sorted(result, key=lambda q: q.id)
示例#16
0
    def _run(self):  # pylint: disable=too-many-locals
        """Run the circuit this object has built during engine execution."""
        # Nothing to do with an empty circuit.
        if len(self._circuit) == 0:
            return

        if self._retrieve_execution is None:
            qubit_mapping = self.main_engine.mapper.current_mapping
            measured_ids = self._measured_ids[:]
            info = {
                'circuit':
                self._circuit,
                'nq':
                len(qubit_mapping.keys()),
                'shots':
                self._num_runs,
                'meas_mapped':
                [qubit_mapping[qubit_id] for qubit_id in measured_ids],
                'meas_qubit_ids':
                measured_ids,
            }
            res = http_client.send(
                info,
                device=self.device,
                token=self._token,
                num_retries=self._num_retries,
                interval=self._interval,
                verbose=self._verbose,
            )
            if res is None:
                raise RuntimeError('Failed to submit job to the server!')
        else:
            res = http_client.retrieve(
                device=self.device,
                token=self._token,
                jobid=self._retrieve_execution,
                num_retries=self._num_retries,
                interval=self._interval,
                verbose=self._verbose,
            )
            if res is None:
                raise RuntimeError(
                    "Failed to retrieve job with id: '{}'!".format(
                        self._retrieve_execution))
            self._measured_ids = measured_ids = res['meas_qubit_ids']

        # Determine random outcome from probable states.
        random_outcome = random.random()
        p_sum = 0.0
        measured = ""
        star = ""
        num_measured = len(measured_ids)
        probable_outcomes = res['output_probs']
        states = probable_outcomes.keys()
        self._probabilities = {}
        for idx, state_int in enumerate(states):
            state = _rearrange_result(int(state_int), num_measured)
            probability = probable_outcomes[state_int]
            p_sum += probability
            if p_sum >= random_outcome and measured == "" or (idx
                                                              == len(states) -
                                                              1):
                measured = state
                star = "*"
            self._probabilities[state] = probability
            if self._verbose and probability > 0:  # pragma: no cover
                print(state + " with p = " + str(probability) + star)

        # Register measurement results
        for idx, qubit_id in enumerate(measured_ids):
            result = int(measured[idx])
            qubit_ref = WeakQubitRef(self.main_engine, qubit_id)
            self.main_engine.set_measurement_result(qubit_ref, result)
示例#17
0
def test_return_new_mapping(different_backend_ids):
    if different_backend_ids:
        map_to_backend_ids = {
            0: 21,
            1: 32,
            2: 1,
            3: 4,
            4: 5,
            5: 6,
            6: 10,
            7: 7,
            8: 0,
            9: 56,
            10: 55,
            11: 9,
        }
    else:
        map_to_backend_ids = None
    mapper = two_d.GridMapper(num_rows=4, num_columns=3, mapped_ids_to_backend_ids=map_to_backend_ids)
    eng = projectq.MainEngine(DummyEngine(), [mapper])
    linear_chain_ids = [33, 22, 11, 2, 3, 0, 6, 7, 9, 12, 4, 88]
    mapper._stored_commands = []
    for i in range(12):
        qb = WeakQubitRef(engine=None, idx=linear_chain_ids[i])
        cmd = Command(None, Allocate, ([qb],))
        mapper._stored_commands.append(cmd)
    for i in range(11):
        qb0 = WeakQubitRef(engine=None, idx=linear_chain_ids[i])
        qb1 = WeakQubitRef(engine=None, idx=linear_chain_ids[i + 1])
        cmd = Command(None, X, qubits=([qb0],), controls=[qb1])
        mapper._stored_commands.append(cmd)
    new_mapping = mapper._return_new_mapping()
    possible_solution_1 = {
        33: 0,
        22: 1,
        11: 2,
        2: 5,
        3: 4,
        0: 3,
        6: 6,
        7: 7,
        9: 8,
        12: 11,
        4: 10,
        88: 9,
    }
    possible_solution_2 = {
        88: 0,
        4: 1,
        12: 2,
        9: 5,
        7: 4,
        6: 3,
        0: 6,
        3: 7,
        2: 8,
        11: 11,
        22: 10,
        33: 9,
    }
    assert new_mapping == possible_solution_1 or new_mapping == possible_solution_2
    eng.flush()
    if different_backend_ids:
        transformed_sol1 = {}
        for logical_id, mapped_id in possible_solution_1.items():
            transformed_sol1[logical_id] = map_to_backend_ids[mapped_id]
        transformed_sol2 = {}
        for logical_id, mapped_id in possible_solution_2.items():
            transformed_sol2[logical_id] = map_to_backend_ids[mapped_id]
        assert mapper.current_mapping == transformed_sol1 or mapper.current_mapping == transformed_sol2
    else:
        assert mapper.current_mapping == possible_solution_1 or mapper.current_mapping == possible_solution_2
示例#18
0
    def _run(self):
        """
        Creates a new mapping and executes possible gates.

        It first allocates all 0, ..., self.num_qubits-1 mapped qubit ids, if
        they are not already used because we might need them all for the
        swaps. Then it creates a new map, swaps all the qubits to the new map,
        executes all possible gates, and finally deallocates mapped qubit ids
        which don't store any information.
        """
        num_of_stored_commands_before = len(self._stored_commands)
        if not self.current_mapping:
            self.current_mapping = dict()
        else:
            self._send_possible_commands()
            if len(self._stored_commands) == 0:
                return
        new_mapping = self.return_new_mapping(self.num_qubits, self.cyclic,
                                              self._currently_allocated_ids,
                                              self._stored_commands,
                                              self.current_mapping)
        swaps = self._odd_even_transposition_sort_swaps(
            old_mapping=self.current_mapping, new_mapping=new_mapping)
        if swaps:  # first mapping requires no swaps
            # Allocate all mapped qubit ids (which are not already allocated,
            # i.e., contained in self._currently_allocated_ids)
            mapped_ids_used = set()
            for logical_id in self._currently_allocated_ids:
                mapped_ids_used.add(self.current_mapping[logical_id])
            not_allocated_ids = set(range(
                self.num_qubits)).difference(mapped_ids_used)
            for mapped_id in not_allocated_ids:
                qb = WeakQubitRef(engine=self, idx=mapped_id)
                cmd = Command(engine=self, gate=Allocate, qubits=([qb], ))
                self.send([cmd])
            # Send swap operations to arrive at new_mapping:
            for qubit_id0, qubit_id1 in swaps:
                q0 = WeakQubitRef(engine=self, idx=qubit_id0)
                q1 = WeakQubitRef(engine=self, idx=qubit_id1)
                cmd = Command(engine=self, gate=Swap, qubits=([q0], [q1]))
                self.send([cmd])
            # Register statistics:
            self.num_mappings += 1
            depth = return_swap_depth(swaps)
            if depth not in self.depth_of_swaps:
                self.depth_of_swaps[depth] = 1
            else:
                self.depth_of_swaps[depth] += 1
            if len(swaps) not in self.num_of_swaps_per_mapping:
                self.num_of_swaps_per_mapping[len(swaps)] = 1
            else:
                self.num_of_swaps_per_mapping[len(swaps)] += 1
            # Deallocate all previously mapped ids which we only needed for the
            # swaps:
            mapped_ids_used = set()
            for logical_id in self._currently_allocated_ids:
                mapped_ids_used.add(new_mapping[logical_id])
            not_needed_anymore = set(range(
                self.num_qubits)).difference(mapped_ids_used)
            for mapped_id in not_needed_anymore:
                qb = WeakQubitRef(engine=self, idx=mapped_id)
                cmd = Command(engine=self, gate=Deallocate, qubits=([qb], ))
                self.send([cmd])
        # Change to new map:
        self.current_mapping = new_mapping
        # Send possible gates:
        self._send_possible_commands()
        # Check that mapper actually made progress
        if len(self._stored_commands) == num_of_stored_commands_before:
            raise RuntimeError("Mapper is potentially in an infinite loop. "
                               "It is likely that the algorithm requires "
                               "too many qubits. Increase the number of "
                               "qubits for this mapper.")
 def remap_qureg(self, qureg, id_map):
     return Qureg(WeakQubitRef(q.engine, id_map[q.id]) for q in qureg)