def test_cnot_4(self):
        """
        Test with a different input type
        """
        q_map = {
            'QPU_1': ['q_1'],
            'QPU_2': ['q_2'],
            'QPU_3': ['q_3']}

        q_1 = Qubit(computing_host_id="QPU_1", q_id="q_1")
        q_2 = Qubit(computing_host_id="QPU_2", q_id="q_2")
        q_3 = Qubit(computing_host_id="QPU_3", q_id="q_3")

        q_1.single(gate=Operation.X)
        q_1.two_qubit(gate=Operation.CNOT, target_qubit=q_2)

        q_2.two_qubit(gate=Operation.CNOT, target_qubit=q_3)

        q_1.measure(bit_id=q_1.q_id)
        q_2.measure(bit_id=q_2.q_id)
        q_3.measure(bit_id=q_3.q_id)

        circuit = Circuit(q_map, qubits=[q_1, q_2, q_3])

        def controller_host_protocol(host):
            host.generate_and_send_schedules(circuit)
            host.receive_results()

        def computing_host_protocol(host):
            host.receive_schedule()
            host.send_results()

        for i in range(1):
            self.controller_host.run_protocol(controller_host_protocol)
            self.computing_host_1.run_protocol(computing_host_protocol)
            self.computing_host_2.run_protocol(computing_host_protocol)
            self.computing_host_3.run_protocol(computing_host_protocol)
            time.sleep(20)

        self.assertEqual(self.clock._maximum_ticks, 23)

        self.assertEqual(self.computing_host_1._bits['q_1'], 1)
        self.assertEqual(self.computing_host_2._bits['q_2'], 1)
        self.assertEqual(self.computing_host_3._bits['q_3'], 1)

        results = self.controller_host._results
        self.assertEqual(results['QPU_1']['type'], 'measurement_result')
        self.assertEqual(results['QPU_1']['val']['q_1'], 1)
        self.assertEqual(results['QPU_2']['val']['q_2'], 1)
    def test_distributed_scheduler(self):
        self.controller_host.connect_host("QPU_2")

        q_map = {
            'QPU_1': ['qubit_1', 'qubit_2'],
            'QPU_2': ['qubit_2', 'qubit_4']
        }

        # Form layer 1
        op_1 = Operation(name="SINGLE",
                         qids=["qubit_1"],
                         gate=Operation.H,
                         computing_host_ids=["QPU_1"])

        op_2 = Operation(name="SEND_ENT",
                         qids=["qubit_2"],
                         computing_host_ids=["QPU_1", "QPU_2"])

        op_3 = Operation(name="REC_ENT",
                         qids=["qubit_2"],
                         computing_host_ids=["QPU_2", "QPU_1"])

        layer_1 = Layer([op_1, op_2, op_3])

        # Form layer 2
        op_1 = Operation(name="TWO_QUBIT",
                         qids=["qubit_2", "qubit_4"],
                         gate=Operation.CNOT,
                         computing_host_ids=["QPU_2"])

        layer_2 = Layer([op_1])

        # Form layer 3
        op_1 = Operation(name="MEASURE",
                         qids=["qubit_2"],
                         cids=["bit_1"],
                         computing_host_ids=["QPU_2"])

        layer_3 = Layer([op_1])

        # Form layer 4
        op_1 = Operation(name="SEND_CLASSICAL",
                         cids=["bit_1"],
                         computing_host_ids=["QPU_2", "QPU_1"])

        op_2 = Operation(name="REC_CLASSICAL",
                         cids=["bit_1"],
                         computing_host_ids=["QPU_1", "QPU_2"])

        layer_4 = Layer([op_1, op_2])

        # Form layer 5
        op_1 = Operation(name="CLASSICAL_CTRL_GATE",
                         qids=["qubit_1"],
                         cids=["bit_1"],
                         gate=Operation.X,
                         computing_host_ids=["QPU_1"])

        layer_5 = Layer([op_1])

        layers = [layer_1, layer_2, layer_3, layer_4, layer_5]
        circuit = Circuit(q_map, layers)

        computing_host_schedules, max_execution_time = self.controller_host._create_distributed_schedules(
            circuit)

        self.assertEqual(len(computing_host_schedules), 2)
        self.assertEqual(len(computing_host_schedules['QPU_1']), 4)
        self.assertEqual(len(computing_host_schedules['QPU_2']), 4)

        self.assertEqual(max_execution_time, 5)

        self.assertEqual(computing_host_schedules['QPU_1'][0]['name'],
                         "SINGLE")
        self.assertEqual(computing_host_schedules['QPU_1'][0]['layer_end'], 0)
        self.assertEqual(computing_host_schedules['QPU_1'][1]['name'],
                         "SEND_ENT")
        self.assertEqual(computing_host_schedules['QPU_1'][1]['layer_end'], 0)
        self.assertEqual(computing_host_schedules['QPU_1'][2]['name'],
                         "REC_CLASSICAL")
        self.assertEqual(computing_host_schedules['QPU_1'][2]['layer_end'], 3)
        self.assertEqual(computing_host_schedules['QPU_1'][3]['name'],
                         "CLASSICAL_CTRL_GATE")
        self.assertEqual(computing_host_schedules['QPU_1'][3]['layer_end'], 4)

        self.assertEqual(computing_host_schedules['QPU_2'][0]['name'],
                         "REC_ENT")
        self.assertEqual(computing_host_schedules['QPU_2'][0]['layer_end'], 0)
        self.assertEqual(computing_host_schedules['QPU_2'][1]['name'],
                         "TWO_QUBIT")
        self.assertEqual(computing_host_schedules['QPU_2'][1]['layer_end'], 1)
        self.assertEqual(computing_host_schedules['QPU_2'][2]['name'],
                         "MEASURE")
        self.assertEqual(computing_host_schedules['QPU_2'][2]['layer_end'], 2)
        self.assertEqual(computing_host_schedules['QPU_2'][3]['name'],
                         "SEND_CLASSICAL")
        self.assertEqual(computing_host_schedules['QPU_2'][3]['layer_end'], 3)
    def test_monolithic_to_distributed_circuit_algorithm_2(self):
        self.controller_host.connect_hosts(
            ["QPU_2", "QPU_3", "QPU_4", "QPU_5"])

        q_map = {
            'QPU_1': ['qubit_1', 'qubit_3', 'qubit_4'],
            'QPU_2': ['qubit_2'],
            'QPU_3': ['qubit_5'],
            'QPU_4': ['qubit_6'],
            'QPU_5': ['qubit_7']
        }

        # Form layer 1
        op_1 = Operation(name="SINGLE",
                         qids=["qubit_1"],
                         gate=Operation.H,
                         computing_host_ids=["QPU_1"])

        layer_1 = Layer([op_1])

        # Form layer 2
        op_1 = Operation(name="TWO_QUBIT",
                         qids=["qubit_2", "qubit_1"],
                         gate=Operation.CNOT,
                         computing_host_ids=["QPU_2", "QPU_1"])

        op_2 = Operation(name="TWO_QUBIT",
                         qids=["qubit_5", "qubit_6"],
                         gate=Operation.CNOT,
                         computing_host_ids=["QPU_3", "QPU_4"])

        op_3 = Operation(name="SINGLE",
                         qids=["qubit_7"],
                         gate=Operation.H,
                         computing_host_ids=["QPU_5"])

        layer_2 = Layer([op_1, op_2, op_3])

        # Form layer 3
        op_1 = Operation(name="TWO_QUBIT",
                         qids=["qubit_2", "qubit_3"],
                         gate=Operation.CNOT,
                         computing_host_ids=["QPU_2", "QPU_1"])

        layer_3 = Layer([op_1])

        # Form layer 4
        op_1 = Operation(name="TWO_QUBIT",
                         qids=["qubit_2", "qubit_4"],
                         gate=Operation.CNOT,
                         computing_host_ids=["QPU_2", "QPU_1"])

        layer_4 = Layer([op_1])

        # Form layer 5
        op_1 = Operation(name="TWO_QUBIT",
                         qids=["qubit_1", "qubit_6"],
                         gate=Operation.CNOT,
                         computing_host_ids=["QPU_1", "QPU_4"])

        layer_5 = Layer([op_1])

        layers = [layer_1, layer_2, layer_3, layer_4, layer_5]
        circuit = Circuit(q_map, layers)

        distributed_circuit = self.controller_host._generate_distributed_circuit(
            circuit)

        layers = distributed_circuit.layers
        self.assertEqual(len(layers), 23)

        self.assertEqual(layers[0].operations[0].name, "SINGLE")

        layer_op_names = [i.name for i in layers[1].operations]
        self.assertEqual(
            layer_op_names,
            ['SINGLE', 'SEND_ENT', 'REC_ENT', 'SEND_ENT', 'REC_ENT'])

        layer_op_names = [i.name for i in layers[2].operations]
        self.assertEqual(layer_op_names, ["TWO_QUBIT", "TWO_QUBIT"])

        self.assertEqual(layers[6].operations[0].name, "TWO_QUBIT")
        self.assertEqual(layers[6].operations[1].name, "TWO_QUBIT")
        self.assertEqual(layers[7].operations[0].name, "TWO_QUBIT")
        self.assertEqual(layers[7].operations[1].name, "SINGLE")
        self.assertEqual(layers[8].operations[0].name, "TWO_QUBIT")

        layer_op_names = [i.name for i in layers[11].operations]
        self.assertEqual(layer_op_names, ['SEND_CLASSICAL', 'REC_CLASSICAL'])

        layer_op_names = [i.name for i in layers[13].operations]
        self.assertEqual(layer_op_names, ['SEND_ENT', 'REC_ENT'])

        self.assertEqual(layers[22].operations[0].name, "CLASSICAL_CTRL_GATE")
    def test_monolithic_to_distributed_circuit_algorithm_1(self):
        self.controller_host.connect_host("QPU_2")

        q_map = {
            'QPU_1': ['qubit_1', 'qubit_2'],
            'QPU_2': ['qubit_3', 'qubit_4'],
            'QPU_3': ['qubit_5']
        }

        # Form layer 1
        op_1 = Operation(name="SINGLE",
                         qids=["qubit_1"],
                         gate=Operation.H,
                         computing_host_ids=["QPU_1"])

        op_2 = Operation(name="SINGLE",
                         qids=["qubit_3"],
                         gate=Operation.H,
                         computing_host_ids=["QPU_2"])

        op_3 = Operation(name="SINGLE",
                         qids=["qubit_3"],
                         gate=Operation.H,
                         computing_host_ids=["QPU_3"])

        layer_1 = Layer([op_1, op_2, op_3])

        # Form layer 2
        op_1 = Operation(name="TWO_QUBIT",
                         qids=["qubit_3", "qubit_1"],
                         gate=Operation.CNOT,
                         computing_host_ids=["QPU_2", "QPU_1"])

        op_2 = Operation(name="SINGLE",
                         qids=["qubit_3"],
                         gate=Operation.X,
                         computing_host_ids=["QPU_3"])

        layer_2 = Layer([op_1, op_2])

        # Form layer 3
        op_1 = Operation(name="MEASURE",
                         qids=["qubit_3"],
                         cids=["bit_1"],
                         computing_host_ids=["QPU_2"])

        layer_3 = Layer([op_1])

        layers = [layer_1, layer_2, layer_3]
        circuit = Circuit(q_map, layers)

        distributed_circuit = self.controller_host._generate_distributed_circuit(
            circuit)

        self.assertEqual(len(distributed_circuit.layers), 12)

        self.assertEqual(len(distributed_circuit.layers[0].operations), 3)
        self.assertEqual(len(distributed_circuit.layers[1].operations), 3)

        self.assertEqual(distributed_circuit.layers[1].operations[0].name,
                         "SINGLE")
        self.assertEqual(distributed_circuit.layers[1].operations[1].name,
                         "SEND_ENT")
        self.assertEqual(distributed_circuit.layers[1].operations[2].name,
                         "REC_ENT")

        self.assertEqual(distributed_circuit.layers[2].operations[0].name,
                         "TWO_QUBIT")
        self.assertEqual(distributed_circuit.layers[10].operations[0].name,
                         "CLASSICAL_CTRL_GATE")

        self.assertEqual(distributed_circuit.layers[11].operations[0].name,
                         "MEASURE")
Example #5
0
class TestCircuit(unittest.TestCase):

    # Runs before all tests
    @classmethod
    def setUpClass(self) -> None:
        pass

    # Runs after all tests
    @classmethod
    def tearDownClass(self) -> None:
        pass

    def setUp(self):
        q_map = {'QPU_1': ['qubit_1', 'qubit_3'], 'QPU_2': ['qubit_2']}
        self._circuit = Circuit(q_map, layers=[])
        self._q_map = q_map

    def tearDown(self):
        del self._circuit

    def test_instantiation(self):
        self.assertEqual(self._circuit.total_qubits(), 3)
        self.assertEqual(self._circuit.q_map, self._q_map)
        self.assertEqual(self._circuit.layers, [])

        self._circuit.add_new_qubit({'QPU_2': ['qubit_4']})

        self.assertEqual(self._circuit.total_qubits(), 4)

        operations = [
            Operation(name="SINGLE",
                      qids=["qubit_1"],
                      gate=Operation.X,
                      computing_host_ids=["QPU_1"])
        ]
        layer = Layer(operations)
        self._circuit.add_layer_to_circuit(layer)

        self.assertNotEqual(self._circuit.layers, [])
        self.assertEqual(self._circuit.layers[0].operations[0].name, "SINGLE")

    def test_control_gate_info(self):
        self._circuit.add_new_qubit({'QPU_1': ['qubit_4']})
        self._circuit.add_new_qubit({'QPU_3': ['qubit_5']})
        self._circuit.add_new_qubit({'QPU_4': ['qubit_6']})

        self.assertEqual(self._circuit.total_qubits(), 6)

        op_1 = Operation(name="TWO_QUBIT",
                         qids=["qubit_2", "qubit_1"],
                         gate=Operation.CNOT,
                         computing_host_ids=["QPU_2", "QPU_1"])

        op_2 = Operation(name="TWO_QUBIT",
                         qids=["qubit_5", "qubit_6"],
                         gate=Operation.CNOT,
                         computing_host_ids=["QPU_3", "QPU_4"])

        layer_1 = Layer([op_1, op_2])

        op_1 = Operation(name="TWO_QUBIT",
                         qids=["qubit_2", "qubit_3"],
                         gate=Operation.CNOT,
                         computing_host_ids=["QPU_2", "QPU_1"])

        layer_2 = Layer([op_1])

        op_1 = Operation(name="TWO_QUBIT",
                         qids=["qubit_2", "qubit_4"],
                         gate=Operation.CNOT,
                         computing_host_ids=["QPU_2", "QPU_1"])

        layer_3 = Layer([op_1])

        op_1 = Operation(name="TWO_QUBIT",
                         qids=["qubit_6", "qubit_1"],
                         gate=Operation.CNOT,
                         computing_host_ids=["QPU_4", "QPU_1"])

        layer_4 = Layer([op_1])

        self._circuit.add_layer_to_circuit(layer_1)
        self._circuit.add_layer_to_circuit(layer_2)
        self._circuit.add_layer_to_circuit(layer_3)
        self._circuit.add_layer_to_circuit(layer_4)

        control_gate_info = self._circuit.control_gate_info()

        self.assertEqual(len(control_gate_info[0]), 2)
        self.assertEqual(control_gate_info[0][0]['computing_hosts'],
                         ['QPU_2', 'QPU_1'])
        self.assertEqual(control_gate_info[1], [])
        self.assertEqual(control_gate_info[2], [])

        self.assertEqual(len(control_gate_info[0][1]['operations']), 1)

        test_operations = control_gate_info[0][0]['operations']
        self.assertEqual(len(test_operations), 3)
        self.assertEqual(test_operations[0].get_target_qubit(), 'qubit_4')
        self.assertEqual(test_operations[1].get_target_qubit(), 'qubit_3')
        self.assertEqual(test_operations[2].get_target_qubit(), 'qubit_1')

        self.assertEqual(control_gate_info[0][0]['control_qubit'], 'qubit_2')
        self.assertEqual(control_gate_info[3][0]['control_qubit'], 'qubit_6')

    def test_creating_layers(self):
        q_1 = Qubit(computing_host_id='QPU_1', q_id='qubit_1')
        q_2 = Qubit(computing_host_id='QPU_2', q_id='qubit_2')
        q_3 = Qubit(computing_host_id='QPU_1', q_id='qubit_3')

        q_1.single(gate=Operation.X)
        q_2.single(gate=Operation.X)

        q_1.single(gate=Operation.H)
        q_3.single(gate=Operation.H)

        q_1.two_qubit(gate=Operation.CNOT, target_qubit=q_3)

        self._circuit.create_layers(qubits=[q_1, q_2, q_3])
        layers = self._circuit.layers

        op_names = [op.name for op in layers[0].operations]
        self.assertEqual(
            op_names, ['PREPARE_QUBITS', 'PREPARE_QUBITS', 'PREPARE_QUBITS'])

        op_names = [op.name for op in layers[1].operations]
        self.assertEqual(op_names, ['SINGLE', 'SINGLE', 'SINGLE'])

        op_names = [op.name for op in layers[2].operations]
        self.assertEqual(op_names, ['SINGLE'])

        op_names = [op.name for op in layers[3].operations]
        self.assertEqual(op_names, ['TWO_QUBIT'])
Example #6
0
 def setUp(self):
     q_map = {'QPU_1': ['qubit_1', 'qubit_3'], 'QPU_2': ['qubit_2']}
     self._circuit = Circuit(q_map, layers=[])
     self._q_map = q_map
    def test_cnot_1(self):
        q_map = {
            'QPU_1': ['qubit_1'],
            'QPU_2': ['qubit_2']}

        # TODO: Maybe layer one is always like this
        # Form layer 1
        op_1 = Operation(
            name="PREPARE_QUBITS",
            qids=["qubit_1"],
            computing_host_ids=["QPU_1"])

        op_2 = Operation(
            name="PREPARE_QUBITS",
            qids=["qubit_2"],
            computing_host_ids=["QPU_2"])

        layer_1 = Layer([op_1, op_2])

        # TODO: For operations, can the name and computing host ids be found from
        #       the gate name and qubit id? That would simplify the inputs
        #       We could have an OperationFactory object that takes the topology as input
        #       and then it can generate the operations using those two points

        # Form layer 2
        op_1 = Operation(
            name="SINGLE",
            qids=["qubit_1"],
            gate=Operation.X,
            computing_host_ids=["QPU_1"])

        op_2 = Operation(
            name="SINGLE",
            qids=["qubit_2"],
            gate=Operation.X,
            computing_host_ids=["QPU_2"])

        layer_2 = Layer([op_1, op_2])

        # Form layer 3
        op_1 = Operation(
            name="TWO_QUBIT",
            qids=["qubit_1", "qubit_2"],
            gate=Operation.CNOT,
            computing_host_ids=["QPU_1", "QPU_2"])

        layer_3 = Layer([op_1])

        # Form layer 4
        op_1 = Operation(
            name="MEASURE",
            qids=["qubit_1"],
            cids=["qubit_1"],
            computing_host_ids=["QPU_1"])

        op_2 = Operation(
            name="MEASURE",
            qids=["qubit_2"],
            cids=["qubit_2"],
            computing_host_ids=["QPU_2"])

        layer_4 = Layer([op_1, op_2])

        layers = [layer_1, layer_2, layer_3, layer_4]
        circuit = Circuit(q_map, layers)

        def controller_host_protocol(host):
            host.generate_and_send_schedules(circuit)
            host.receive_results()

        def computing_host_protocol(host):
            host.receive_schedule()
            host.send_results()

        for i in range(1):
            self.controller_host.run_protocol(controller_host_protocol)
            self.computing_host_1.run_protocol(computing_host_protocol)
            self.computing_host_2.run_protocol(computing_host_protocol)
            time.sleep(12)

        self.assertEqual(self.clock._maximum_ticks, 13)

        self.assertEqual(self.computing_host_1._bits['qubit_1'], 1)
        self.assertEqual(self.computing_host_2._bits['qubit_2'], 0)

        self.assertEqual(self.controller_host._results['QPU_1']['qubit_1'], 1)
        self.assertEqual(self.controller_host._results['QPU_2']['qubit_2'], 0)
    def test_cnot_3(self):
        q_map = {
            'QPU_1': ['qubit_1'],
            'QPU_2': ['qubit_2'],
            'QPU_3': ['qubit_3']}

        # Form layer 1
        op_1 = Operation(
            name="PREPARE_QUBITS",
            qids=["qubit_1"],
            computing_host_ids=["QPU_1"])

        op_2 = Operation(
            name="PREPARE_QUBITS",
            qids=["qubit_2"],
            computing_host_ids=["QPU_2"])

        op_3 = Operation(
            name="PREPARE_QUBITS",
            qids=["qubit_3"],
            computing_host_ids=["QPU_3"])

        layer_1 = Layer([op_1, op_2, op_3])

        # Form layer 2
        op_1 = Operation(
            name="SINGLE",
            qids=["qubit_1"],
            gate=Operation.X,
            computing_host_ids=["QPU_1"])

        layer_2 = Layer([op_1])

        # Form layer 3
        op_1 = Operation(
            name="TWO_QUBIT",
            qids=["qubit_1", "qubit_2"],
            gate=Operation.CNOT,
            computing_host_ids=["QPU_1", "QPU_2"])

        layer_3 = Layer([op_1])

        # Form layer 4
        op_1 = Operation(
            name="TWO_QUBIT",
            qids=["qubit_2", "qubit_3"],
            gate=Operation.CNOT,
            computing_host_ids=["QPU_2", "QPU_3"])

        layer_4 = Layer([op_1])

        # Form layer 4
        op_1 = Operation(
            name="MEASURE",
            qids=["qubit_1"],
            cids=["qubit_1"],
            computing_host_ids=["QPU_1"])

        op_2 = Operation(
            name="MEASURE",
            qids=["qubit_2"],
            cids=["qubit_2"],
            computing_host_ids=["QPU_2"])

        op_3 = Operation(
            name="MEASURE",
            qids=["qubit_3"],
            cids=["qubit_3"],
            computing_host_ids=["QPU_3"])

        layer_5 = Layer([op_1, op_2, op_3])

        layers = [layer_1, layer_2, layer_3, layer_4, layer_5]
        circuit = Circuit(q_map, layers)

        def controller_host_protocol(host):
            host.generate_and_send_schedules(circuit)
            host.receive_results()

        def computing_host_protocol(host):
            host.receive_schedule()
            host.send_results()

        for i in range(1):
            self.controller_host.run_protocol(controller_host_protocol)
            self.computing_host_1.run_protocol(computing_host_protocol)
            self.computing_host_2.run_protocol(computing_host_protocol)
            self.computing_host_3.run_protocol(computing_host_protocol)
            time.sleep(18)

        self.assertEqual(self.clock._maximum_ticks, 23)

        self.assertEqual(self.computing_host_1._bits['qubit_1'], 1)
        self.assertEqual(self.computing_host_2._bits['qubit_2'], 1)
        self.assertEqual(self.computing_host_3._bits['qubit_3'], 1)

        results = self.controller_host._results
        self.assertEqual(results['QPU_1']['type'], 'measurement_result')
        self.assertEqual(results['QPU_1']['val']['qubit_1'], 1)
        self.assertEqual(results['QPU_2']['val']['qubit_2'], 1)
        self.assertEqual(results['QPU_3']['val']['qubit_3'], 1)