def test_receive_multiple_flush(self, function_mock): function_mock.return_value = 1 command_alloc0 = MagicMock(gate=Allocate, qubits=[[MagicMock(id=0)]]) command_alloc1 = MagicMock(gate=Allocate, qubits=[[MagicMock(id=1)]]) command = MagicMock(gate=NOT, qubits=[[MagicMock(id=0)]], control_qubits=[MagicMock(id=1)]) command_list = [command_alloc0, command_alloc1, command, MagicMock(gate=FlushGate()), MagicMock(gate=FlushGate())] self.qi_backend.main_engine = MagicMock() with patch('sys.stdout', new_callable=io.StringIO): self.qi_backend.receive(command_list) self.assertEqual(self.qi_backend.qasm, "") self.assertTrue(self.qi_backend.clear)
def receive(self, command_list): """ Receive a list of commands. Receive commands from the previous engine and cache them. If a flush gate arrives, the entire buffer is sent on. """ for cmd in command_list: if cmd.gate == FlushGate(): # flush gate --> optimize and flush # NB: self.optimize(i) modifies self._l for idx in self._l: # pylint: disable=consider-using-dict-items self._optimize(idx) self._send_qubit_pipeline(idx, len(self._l[idx])) new_dict = {} for idx, _l in self._l.items(): if len(_l) > 0: # pragma: no cover new_dict[idx] = _l self._l = new_dict if self._l != {}: # pragma: no cover raise RuntimeError( 'Internal compiler error: qubits remaining in LocalOptimizer after a flush!' ) self.send([cmd]) else: self._cache_cmd(cmd)
def test_loop_unrolling_with_ancillas(): backend = DummyEngine(save_commands=True) eng = MainEngine(backend=backend, engine_list=[DummyEngine()]) qubit = eng.allocate_qubit() qubit_id = deepcopy(qubit[0].id) with _loop.Loop(eng, 3): ancilla = eng.allocate_qubit() H | ancilla CNOT | (ancilla, qubit) del ancilla eng.flush(deallocate_qubits=True) assert len(backend.received_commands) == 15 assert backend.received_commands[0].gate == Allocate for ii in range(3): assert backend.received_commands[ii * 4 + 1].gate == Allocate assert backend.received_commands[ii * 4 + 2].gate == H assert backend.received_commands[ii * 4 + 3].gate == X assert backend.received_commands[ii * 4 + 4].gate == Deallocate # Check qubit ids assert (backend.received_commands[ii * 4 + 1].qubits[0][0].id == backend.received_commands[ii * 4 + 2].qubits[0][0].id) assert (backend.received_commands[ii * 4 + 1].qubits[0][0].id == backend.received_commands[ii * 4 + 3].control_qubits[0].id) assert (backend.received_commands[ii * 4 + 3].qubits[0][0].id == qubit_id) assert (backend.received_commands[ii * 4 + 1].qubits[0][0].id == backend.received_commands[ii * 4 + 4].qubits[0][0].id) assert backend.received_commands[13].gate == Deallocate assert backend.received_commands[14].gate == FlushGate() assert (backend.received_commands[1].qubits[0][0].id != backend.received_commands[5].qubits[0][0].id) assert (backend.received_commands[1].qubits[0][0].id != backend.received_commands[9].qubits[0][0].id) assert (backend.received_commands[5].qubits[0][0].id != backend.received_commands[9].qubits[0][0].id)
def test_receive_multiple_flush(self, function_mock): function_mock.return_value = 1 command = MagicMock(gate=NOT, qubits=[[MagicMock(id=0)], [MagicMock(id=1)]]) command_list = [ command, MagicMock(gate=FlushGate()), MagicMock(gate=FlushGate()) ] api = MockApiClient() backend = QIBackend(quantum_inspire_api=api) backend.main_engine = MagicMock() with patch('sys.stdout', new_callable=io.StringIO): backend.receive(command_list) self.assertEqual(backend.qasm, "") self.assertTrue(backend._clear)
def test_basic_mapper_engine_send_cmd_with_mapped_ids(): mapper = _basicmapper.BasicMapperEngine() mapper.current_mapping = {0: 3, 1: 2, 2: 1, 3: 0} backend = DummyEngine(save_commands=True) backend.is_last_engine = True mapper.next_engine = backend # generate a few commands 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], ), controls=[], tags=[]) cmd1 = Command(engine=None, gate=Deallocate, qubits=([qb1], ), controls=[], tags=[]) cmd2 = Command(engine=None, gate=Measure, qubits=([qb2], ), controls=[], tags=["SomeTag"]) cmd3 = Command( engine=None, gate=BasicGate(), qubits=([qb0, qb1], [qb2]), controls=[qb3], tags=[], ) cmd4 = Command(None, FlushGate(), ([WeakQubitRef(None, -1)], )) mapper._send_cmd_with_mapped_ids(cmd0) mapper._send_cmd_with_mapped_ids(cmd1) mapper._send_cmd_with_mapped_ids(cmd2) mapper._send_cmd_with_mapped_ids(cmd3) mapper._send_cmd_with_mapped_ids(cmd4) rcmd0 = backend.received_commands[0] rcmd1 = backend.received_commands[1] rcmd2 = backend.received_commands[2] rcmd3 = backend.received_commands[3] rcmd4 = backend.received_commands[4] assert rcmd0.gate == Allocate assert rcmd0.qubits == ([qb3], ) assert rcmd1.gate == Deallocate assert rcmd1.qubits == ([qb2], ) assert rcmd2.gate == Measure assert rcmd2.qubits == ([qb1], ) assert rcmd2.tags == ["SomeTag", LogicalQubitIDTag(2)] assert rcmd3.gate == BasicGate() assert rcmd3.qubits == ([qb3, qb2], [qb1]) assert rcmd3.control_qubits == [qb0] assert len(rcmd4.qubits) == 1 assert len(rcmd4.qubits[0]) == 1 assert rcmd4.qubits[0][0].id == -1
def test_PermutePi4Front(): eng = projectq.MainEngine() perm = PermutePi4Front() qubit = eng.allocate_qubit() perm.next_engine = A() perm.receive([X.generate_command(qubit)]) perm.receive([Y.generate_command(qubit)]) perm.receive([T.generate_command(qubit)]) perm.receive([FlushGate().generate_command(qubit)]) return
def test_dummy_engine(): dummy_eng = _testengine.DummyEngine(save_commands=True) eng = MainEngine(backend=dummy_eng, engine_list=[]) assert dummy_eng.is_available("Anything") qubit = eng.allocate_qubit() H | qubit eng.flush() assert len(dummy_eng.received_commands) == 3 assert dummy_eng.received_commands[0].gate == Allocate assert dummy_eng.received_commands[1].gate == H assert dummy_eng.received_commands[2].gate == FlushGate()
def test_reuse_after_flush_raises_runtime_error(self, function_mock): function_mock.return_value = 1 command_alloc0 = MagicMock(gate=Allocate, qubits=[[MagicMock(id=0)]]) command_alloc1 = MagicMock(gate=Allocate, qubits=[[MagicMock(id=1)]]) command = MagicMock(gate=NOT, qubits=[[MagicMock(id=0)]], control_qubits=[MagicMock(id=1)]) command_list = [command_alloc0, command_alloc1, command, MagicMock(gate=FlushGate()), command] api = MockApiClient() backend = QIBackend(quantum_inspire_api=api) backend.main_engine = MagicMock() with patch('sys.stdout', new_callable=io.StringIO): self.assertRaisesRegex(RuntimeError, "Same instance of QIBackend used for circuit after Flush.", backend.receive, command_list)
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()
def receive(self, command_list): """ Receives a command list and, for each command, stores it until completion. Args: command_list: List of commands to execute """ for cmd in command_list: if not cmd.gate == FlushGate(): self._store(cmd) else: self._run() self._reset()
def receive(self, command_list): """ Receive commands from the previous engine and cache them. If a flush gate arrives, the entire buffer is sent on. """ for cmd in command_list: if cmd.gate == FlushGate(): # flush gate --> optimize and flush for i in range(len(self._l)): self._optimize(i) self._send_qubit_pipeline(i, len(self._l[i])) self.send([cmd]) else: self._cache_cmd(cmd)
def receive(self, command_list: List[Command]) -> None: """ Receives a command list and, for each command, stores it until completion. :param command_list: List of commands to execute. """ for cmd in command_list: if not cmd.gate == FlushGate(): self._store(cmd) else: self._run() self._flushed = True self._reset()
def flush(self, deallocate_qubits=False): """ Flush the entire circuit down the pipeline, clearing potential buffers (of, e.g., optimizers). Args: deallocate_qubits (bool): If True, deallocates all qubits that are still alive (invalidating references to them by setting their id to -1) """ if deallocate_qubits: for qb in self.active_qubits: qb.__del__() self.active_qubits = weakref.WeakSet() self.receive([Command(self, FlushGate(), ([WeakQubitRef(self, -1)],))])
def test_run_infinite_loop_detection(): mapper = lm.LinearMapper(num_qubits=1, 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) cmd0 = Command(engine=None, gate=Allocate, qubits=([qb0],)) cmd1 = Command(engine=None, gate=Allocate, qubits=([qb1],)) cmd2 = 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, cmd_flush])
def test_flush_with_no_measurements_but_nfsp(self, function_mock): function_mock.return_value = 1 command_alloc0 = MagicMock(gate=Allocate, qubits=[[MagicMock(id=0)]]) command_alloc1 = MagicMock(gate=Allocate, qubits=[[MagicMock(id=1)]]) command_alloc2 = MagicMock(gate=Allocate, qubits=[[MagicMock(id=1)]]) command_dealloc1 = MagicMock(gate=Deallocate, qubits=[[MagicMock(id=1)]]) command = MagicMock(gate=NOT, qubits=[[MagicMock(id=0)]], control_qubits=[MagicMock(id=1)]) command_list = [command_alloc0, command_alloc1, command_dealloc1, command_alloc2, command, MagicMock(gate=FlushGate())] api = MockApiClient() backend = QIBackend(quantum_inspire_api=api, verbose=1) backend.main_engine = MagicMock() with patch('sys.stdout', new_callable=io.StringIO): backend.receive(command_list) self.assertEqual(backend.qasm, "")
def test_send_possible_cmds_before_new_mapping(): mapper = two_d.GridMapper(num_rows=3, num_columns=1) backend = DummyEngine(save_commands=True) backend.is_last_engine = True mapper.next_engine = backend def dont_call_mapping(): raise Exception mapper._return_new_mapping = dont_call_mapping mapper.current_mapping = {0: 1} qb0 = WeakQubitRef(engine=None, idx=0) cmd0 = Command(engine=None, gate=Allocate, qubits=([qb0],)) qb2 = WeakQubitRef(engine=None, idx=-1) cmd_flush = Command(engine=None, gate=FlushGate(), qubits=([qb2],)) mapper.receive([cmd0, cmd_flush])
def receive(self, command_list): """ Receive a list of commands. Receive a command list and, for each command, stores it inside the cache before sending it to the next compiler engine. Args: command_list (list of Command objects): list of commands to receive. """ for cmd in command_list: if not cmd.gate == FlushGate(): self.cache_cmd(cmd) if not self.is_last_engine: self.send(command_list)
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
def receive(self, command_list): """ Receive a list of commands from the previous engine, print the commands, and then send them on to the next engine. Args: command_list (list<Command>): List of Commands to print (and potentially send on to the next engine). """ for cmd in command_list: if not cmd.gate == FlushGate(): self._print_cmd(cmd) # (try to) send on if not self.is_last_engine: self.send([cmd])
def receive(self, command_list): """ Receive a list of commands from the previous engine and handle them (simulate them classically) prior to sending them on to the next engine. Args: command_list (list<Command>): List of commands to execute on the simulator. """ for cmd in command_list: if not cmd.gate == FlushGate(): self._handle(cmd) else: self._simulator.run() # flush gate --> run all saved gates if not self.is_last_engine: self.send([cmd])
def receive(self, command_list): """ Receive a list of commands. Receive a command list and, for each command, stores it until completion. Upon flush, send the data to the IBM QE API. Args: command_list: List of commands to execute """ for cmd in command_list: if not cmd.gate == FlushGate(): self._store(cmd) else: self._run() self._reset()
def receive(self, command_list): """ Receive a list of commands from the previous engine, increases the counters of the received commands, and then send them on to the next engine. Args: command_list (list<Command>): List of commands to receive (and count). """ for cmd in command_list: if not cmd.gate == FlushGate(): self._add_cmd(cmd) # (try to) send on if not self.is_last_engine: self.send([cmd])
def receive(self, command_list): """ Converts each instruction in the input into its Jaqal equivalent and saves it. This should rarely be called directly by users; usually it will be called by ``projectq.cengines.MainEngine``. :param command_list: The ProjectQ program to convert. :type command_list: list(projectq.ops.Command) """ for cmd in command_list: if cmd.gate == FlushGate(): if self.outfile is not None: from jaqalpaq.generator import generate_jaqal_program with open(self.outfile, "w+") as f: f.write(generate_jaqal_program(self.circuit)) else: self._store(cmd)
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 == {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 == {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
def my_receive(self, command_list): """ Receive commands from the previous engine and cache them. If a flush gate arrives, the entire buffer is sent on. """ command_list = self.add_swap(command_list) for cmd in command_list: if cmd.gate == FlushGate(): # flush gate --> optimize and flush for idx in self._l: self._optimize(idx) self._send_qubit_pipeline(idx, len(self._l[idx])) new_dict = dict() for idx in self._l: if len(self._l[idx]) > 0: new_dict[idx] = self._l[idx] self._l = new_dict self.send([cmd]) else: self._cache_cmd(cmd)
def _call_cluster_scheduler(self): self._prepare_ctrlz() local_qubits = self._get_local_ids_list_from_backend() global_qubits = self._get_global_ids_list_from_backend() while True: gate, gate_ctrl, gate_diag = self._get_commands() cluster_scheduler = ClusterScheduler(gate, gate_ctrl, gate_diag, local_qubits, global_qubits, self.CLUSTER_SIZE) avail = cluster_scheduler.ScheduleCluster() if len(avail) == 0: return for i in avail: self.send([self._cmd_list[i]]) self.send( [Command(self, FlushGate(), ([WeakQubitRef(self, -1)], ))]) for i in reversed(sorted(avail)): del self._cmd_list[i]
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 _store(self, cmd): """ Store a command and handle CNOTs. Args: cmd (Command): A command to store """ if not cmd.gate == FlushGate(): target = cmd.qubits[0][0].id if _is_cnot(cmd): # CNOT encountered ctrl = cmd.control_qubits[0].id if not (ctrl, target) in self._interactions: self._interactions[(ctrl, target)] = 0 self._interactions[(ctrl, target)] += 1 elif cmd.gate == Allocate: if target not in self.current_mapping: new_max = 0 if len(self.current_mapping) > 0: new_max = max(self.current_mapping.values()) + 1 self._current_mapping[target] = new_max self._cmds.append(cmd)
def test_correct_stats(): # Should test stats for twice same mapping but depends on heuristic mapper = two_d.GridMapper(num_rows=3, num_columns=1) 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(None, X, qubits=([qb0],), controls=[qb2]) cmd6 = Command(None, X, qubits=([qb2],), controls=[qb1]) cmd7 = Command(None, X, qubits=([qb0],), controls=[qb1]) cmd8 = Command(None, X, qubits=([qb1],), controls=[qb2]) qb_flush = WeakQubitRef(engine=None, idx=-1) cmd_flush = Command(engine=None, gate=FlushGate(), qubits=([qb_flush],)) mapper.receive([cmd0, cmd1, cmd2, cmd3, cmd4, cmd5, cmd6, cmd7, cmd8, cmd_flush]) assert mapper.num_mappings == 2
def _store(self, cmd): """ Store a command and handle CNOTs. Args: cmd (Command): A command to store """ if not cmd.gate == FlushGate(): apply_to = cmd.qubits[0][0].id if apply_to not in self._interactions: self._interactions[apply_to] = set() self._num_cnot_target[apply_to] = 0 if self._is_cnot(cmd): # CNOT encountered ctrl = cmd.control_qubits[0].id if ctrl not in self._interactions: self._interactions[ctrl] = set() self._num_cnot_target[ctrl] = 0 self._interactions[ctrl].add(apply_to) self._interactions[apply_to].add(ctrl) self._num_cnot_target[apply_to] += 1 self._cmds.append(cmd)