コード例 #1
0
ファイル: _main_test.py プロジェクト: Takishima/ProjectQ
def test_main_engine_atexit_no_error():
    # Clear previous exceptions of other tests
    sys.last_type = None
    del sys.last_type
    backend = DummyEngine(save_commands=True)
    eng = _main.MainEngine(backend=backend, engine_list=[])
    qb = eng.allocate_qubit()  # noqa: F841
    eng._delfun(weakref.ref(eng))
    assert len(backend.received_commands) == 3
    assert backend.received_commands[0].gate == AllocateQubitGate()
    assert backend.received_commands[1].gate == DeallocateQubitGate()
    assert backend.received_commands[2].gate == FlushGate()
コード例 #2
0
ファイル: _main_test.py プロジェクト: silky/ProjectQ
def test_main_engine_flush():
    backend = DummyEngine(save_commands=True)
    eng = _main.MainEngine(backend=backend, engine_list=[DummyEngine()])
    qubit = eng.allocate_qubit()
    H | qubit
    eng.flush()
    assert len(backend.received_commands) == 3
    assert backend.received_commands[0].gate == AllocateQubitGate()
    assert backend.received_commands[1].gate == H
    assert backend.received_commands[2].gate == FlushGate()
    eng.flush(deallocate_qubits=True)
    assert len(backend.received_commands) == 5
    assert backend.received_commands[3].gate == DeallocateQubitGate()
    #keep the qubit alive until at least here
    assert len(str(qubit)) != 0
コード例 #3
0
    def _process_cmd(self, cmd):
        current_mapping = self.current_mapping
        if current_mapping is None:
            current_mapping = {}

        if isinstance(cmd.gate, AllocateQubitGate):
            qubit_id = cmd.qubits[0][0].id
            if qubit_id in current_mapping:
                raise RuntimeError(
                    "Qubit with id {} has already been allocated!".format(
                        qubit_id))

            if self._qubit_idx >= self.max_qubits:
                raise RuntimeError(
                    "Cannot allocate more than {} qubits!".format(
                        self.max_qubits))

            new_id = self._qubit_idx
            self._qubit_idx += 1
            current_mapping[qubit_id] = new_id
            qb = WeakQubitRef(engine=self, idx=new_id)
            new_cmd = Command(
                engine=self,
                gate=AllocateQubitGate(),
                qubits=([qb], ),
                tags=[LogicalQubitIDTag(qubit_id)],
            )
            self.current_mapping = current_mapping
            self.send([new_cmd])
        elif isinstance(cmd.gate, DeallocateQubitGate):
            qubit_id = cmd.qubits[0][0].id
            if qubit_id not in current_mapping:
                raise RuntimeError(
                    "Cannot deallocate a qubit that is not already allocated!")
            qb = WeakQubitRef(engine=self, idx=current_mapping[qubit_id])
            new_cmd = Command(
                engine=self,
                gate=DeallocateQubitGate(),
                qubits=([qb], ),
                tags=[LogicalQubitIDTag(qubit_id)],
            )
            current_mapping.pop(qubit_id)
            self.current_mapping = current_mapping
            self.send([new_cmd])
        else:
            self._send_cmd_with_mapped_ids(cmd)
コード例 #4
0
def test_cannot_deallocate_same_qubit():
    mapper = BoundedQubitMapper(1)
    engine = MainEngine(
        Simulator(),
        engine_list=[mapper],
        verbose=True,
    )
    qureg = engine.allocate_qubit()
    qubit_id = qureg[0].id
    engine.deallocate_qubit(qureg[0])

    with pytest.raises(RuntimeError) as excinfo:
        deallocate_cmd = Command(
            engine=engine,
            gate=DeallocateQubitGate(),
            qubits=([WeakQubitRef(engine=engine, idx=qubit_id)], ),
            tags=[LogicalQubitIDTag(qubit_id)],
        )
        engine.send([deallocate_cmd])

    assert str(excinfo.value
               ) == "Cannot deallocate a qubit that is not already allocated!"
コード例 #5
0
def test_cannot_deallocate_unknown_qubit():
    engine = MainEngine(
        Simulator(),
        engine_list=[BoundedQubitMapper(1)],
        verbose=True,
    )
    qureg = engine.allocate_qubit()
    with pytest.raises(RuntimeError) as excinfo:
        deallocate_cmd = Command(
            engine=engine,
            gate=DeallocateQubitGate(),
            qubits=([WeakQubitRef(engine=engine, idx=1)], ),
            tags=[LogicalQubitIDTag(1)],
        )
        engine.send([deallocate_cmd])
    assert str(excinfo.value
               ) == "Cannot deallocate a qubit that is not already allocated!"

    # but we can still deallocate an already allocated one
    engine.deallocate_qubit(qureg[0])
    del qureg
    del engine
コード例 #6
0
ファイル: _basics_test.py プロジェクト: pwhitter1/ProjectQ
def test_basic_engine_allocate_and_deallocate_qubit_and_qureg():
    eng = _basics.BasicEngine()
    # custom receive function which checks that main_engine does not send
    # any allocate or deallocate gates
    cmd_sent_by_main_engine = []

    def receive(self, cmd_list):
        cmd_sent_by_main_engine.append(cmd_list)

    eng.receive = types.MethodType(receive, eng)
    # Create test engines:
    saving_backend = DummyEngine(save_commands=True)
    main_engine = MainEngine(backend=saving_backend,
                             engine_list=[eng, DummyEngine()])
    # Allocate and deallocate qubits
    qubit = eng.allocate_qubit()
    # Try to allocate dirty qubit but it should give a non dirty qubit
    not_dirty_qubit = eng.allocate_qubit(dirty=True)

    # Allocate an actual dirty qubit
    def allow_dirty_qubits(self, meta_tag):
        if meta_tag == DirtyQubitTag:
            return True
        return False

    saving_backend.is_meta_tag_handler = types.MethodType(allow_dirty_qubits,
                                                          saving_backend)
    dirty_qubit = eng.allocate_qubit(dirty=True)
    qureg = eng.allocate_qureg(2)
    # Test qubit allocation
    assert isinstance(qubit, list)
    assert len(qubit) == 1 and isinstance(qubit[0], Qubit)
    assert qubit[0] in main_engine.active_qubits
    assert id(qubit[0].engine) == id(eng)
    # Test non dirty qubit allocation
    assert isinstance(not_dirty_qubit, list)
    assert len(not_dirty_qubit) == 1 and isinstance(not_dirty_qubit[0], Qubit)
    assert not_dirty_qubit[0] in main_engine.active_qubits
    assert id(not_dirty_qubit[0].engine) == id(eng)
    # Test dirty_qubit allocation
    assert isinstance(dirty_qubit, list)
    assert len(dirty_qubit) == 1 and isinstance(dirty_qubit[0], Qubit)
    assert dirty_qubit[0] in main_engine.active_qubits
    assert dirty_qubit[0].id in main_engine.dirty_qubits
    assert id(dirty_qubit[0].engine) == id(eng)
    # Test qureg allocation
    assert isinstance(qureg, list)
    assert len(qureg) == 2
    for tmp_qubit in qureg:
        assert tmp_qubit in main_engine.active_qubits
        assert id(tmp_qubit.engine) == id(eng)
    # Test uniqueness of ids
    assert len(set([qubit[0].id, not_dirty_qubit[0].id, dirty_qubit[0].id,
                    qureg[0].id, qureg[1].id])) == 5
    # Test allocate gates were sent
    assert len(cmd_sent_by_main_engine) == 0
    assert len(saving_backend.received_commands) == 5
    for cmd in saving_backend.received_commands:
        assert cmd.gate == AllocateQubitGate()
    assert saving_backend.received_commands[2].tags == [DirtyQubitTag()]
    # Test deallocate gates were sent
    eng.deallocate_qubit(qubit[0])
    eng.deallocate_qubit(not_dirty_qubit[0])
    eng.deallocate_qubit(dirty_qubit[0])
    eng.deallocate_qubit(qureg[0])
    eng.deallocate_qubit(qureg[1])
    assert len(cmd_sent_by_main_engine) == 0
    assert len(saving_backend.received_commands) == 10
    for cmd in saving_backend.received_commands[5:]:
        assert cmd.gate == DeallocateQubitGate()
    assert saving_backend.received_commands[7].tags == [DirtyQubitTag()]
コード例 #7
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
コード例 #8
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.")
コード例 #9
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