Ejemplo n.º 1
0
 def test_two_qubit_kak_from_paulis(self):
     """Verify decomposing Paulis with KAK
     """
     pauli_xz = Pauli(label='XZ')
     unitary = Unitary(Operator(pauli_xz).data)
     decomp_circuit = two_qubit_kak(unitary)
     result = execute(decomp_circuit, UnitarySimulatorPy()).result()
     decomp_unitary = Unitary(result.get_unitary())
     self.assertAlmostEqual(decomp_unitary, unitary)
Ejemplo n.º 2
0
def random_unitary(dim, seed=None):
    """
    Return a random dim x dim Unitary from the Haar measure.

    Args:
        dim (int): the dim of the state space.
        seed (int): Optional. To set a random seed.

    Returns:
        Unitary: (dim, dim) unitary operator.

    Raises:
        QiskitError: if dim is not a positive power of 2.
    """
    if dim == 0 or not math.log2(dim).is_integer():
        raise QiskitError(
            "Desired statevector length not a positive power of 2.")
    matrix = np.zeros([dim, dim], dtype=complex)
    for j in range(dim):
        if j == 0:
            a = random_state(dim, seed)
        else:
            a = random_state(dim)
        matrix[:, j] = np.copy(a)
        # Grahm-Schmidt Orthogonalize
        i = j - 1
        while i >= 0:
            dc = np.vdot(matrix[:, i], a)
            matrix[:, j] = matrix[:, j] - dc * matrix[:, i]
            i = i - 1
        # normalize
        matrix[:, j] = matrix[:, j] * (
            1.0 / np.sqrt(np.vdot(matrix[:, j], matrix[:, j])))
    return Unitary(matrix)
Ejemplo n.º 3
0
 def test_two_qubit_kak(self):
     """Verify KAK decomposition for random Haar 4x4 unitaries.
     """
     for _ in range(100):
         unitary = random_unitary(4)
         with self.subTest(unitary=unitary):
             decomp_circuit = two_qubit_kak(unitary)
             result = execute(decomp_circuit, UnitarySimulatorPy()).result()
             decomp_unitary = Unitary(result.get_unitary())
             self.assertAlmostEqual(process_fidelity(
                 unitary.representation, decomp_unitary.representation),
                                    1.0,
                                    places=7)
Ejemplo n.º 4
0
    def test_consolidate_small_block(self):
        """test a small block of gates can be turned into a unitary on same wires"""
        qr = QuantumRegister(2, "qr")
        qc = QuantumCircuit(qr)
        qc.u1(0.5, qr[0])
        qc.u2(0.2, 0.6, qr[1])
        qc.cx(qr[0], qr[1])
        dag = circuit_to_dag(qc)

        pass_ = ConsolidateBlocks()
        pass_.property_set['block_list'] = [list(dag.topological_op_nodes())]
        new_dag = pass_.run(dag)

        sim = UnitarySimulatorPy()
        result = execute(qc, sim).result()
        unitary = Unitary(result.get_unitary())
        self.assertEqual(len(new_dag.op_nodes()), 1)
        fidelity = process_fidelity(new_dag.op_nodes()[0].op.representation,
                                    unitary.representation)
        self.assertAlmostEqual(fidelity, 1.0, places=7)
Ejemplo n.º 5
0
    def test_block_spanning_two_regs(self):
        """blocks spanning wires on different quantum registers work."""
        qr0 = QuantumRegister(1, "qr0")
        qr1 = QuantumRegister(1, "qr1")
        qc = QuantumCircuit(qr0, qr1)
        qc.u1(0.5, qr0[0])
        qc.u2(0.2, 0.6, qr1[0])
        qc.cx(qr0[0], qr1[0])
        dag = circuit_to_dag(qc)

        pass_ = ConsolidateBlocks()
        pass_.property_set['block_list'] = [list(dag.topological_op_nodes())]
        new_dag = pass_.run(dag)

        sim = UnitarySimulatorPy()
        result = execute(qc, sim).result()
        unitary = Unitary(result.get_unitary())
        self.assertEqual(len(new_dag.op_nodes()), 1)
        fidelity = process_fidelity(new_dag.op_nodes()[0].op.representation,
                                    unitary.representation)
        self.assertAlmostEqual(fidelity, 1.0, places=7)
Ejemplo n.º 6
0
    def test_3q_blocks(self):
        """blocks of more than 2 qubits work."""
        qr = QuantumRegister(3, "qr")
        qc = QuantumCircuit(qr)
        qc.u1(0.5, qr[0])
        qc.u2(0.2, 0.6, qr[1])
        qc.cx(qr[2], qr[1])
        qc.cx(qr[0], qr[1])
        dag = circuit_to_dag(qc)

        pass_ = ConsolidateBlocks()
        pass_.property_set['block_list'] = [list(dag.topological_op_nodes())]
        new_dag = pass_.run(dag)

        sim = UnitarySimulatorPy()
        result = execute(qc, sim).result()
        unitary = Unitary(result.get_unitary())
        self.assertEqual(len(new_dag.op_nodes()), 1)
        fidelity = process_fidelity(new_dag.op_nodes()[0].op.representation,
                                    unitary.representation)
        self.assertAlmostEqual(fidelity, 1.0, places=7)
Ejemplo n.º 7
0
def quantum_volume_circuit(num_qubits, depth, measure=True, seed=None):
    """Create a quantum volume circuit without measurement.

    The model circuits consist of layers of Haar random
    elements of SU(4) applied between corresponding pairs
    of qubits in a random bipartition.

    Args:
        num_qubits (int): number of qubits
        depth (int): ideal depth of each model circuit (over SU(4))
        measure (bool): include measurement in circuit.
        seed (int): the seed for the random number generator

    Returns:
        QuantumCircuit: A quantum volume circuit.
    """
    # Create random number generator with possibly fixed seed
    rng = random.RandomState(seed)
    # Create quantum/classical registers of size n
    qr = QuantumRegister(num_qubits)
    circuit = QuantumCircuit(qr)
    # For each layer
    for _ in repeat(None, depth):
        # Generate uniformly random permutation Pj of [0...n-1]
        perm = rng.permutation(num_qubits)
        # For each consecutive pair in Pj, generate Haar random SU(4)
        # Decompose each SU(4) into CNOT + SU(2) and add to Ci
        for k in range(math.floor(num_qubits / 2)):
            # Generate random SU(4) matrix
            X = (rng.randn(4, 4) + 1j * rng.randn(4, 4))
            SU4, _ = linalg.qr(X)  # Q is a unitary matrix
            SU4 /= pow(linalg.det(SU4), 1 / 4)  # make Q a special unitary
            qubits = [qr[int(perm[2 * k])], qr[int(perm[2 * k + 1])]]
            circuit.append(Unitary(SU4), qubits)
    if measure is True:
        circuit = _add_measurements(circuit, qr)
    return circuit
Ejemplo n.º 8
0
    def run(self, dag):
        """iterate over each block and replace it with an equivalent Unitary
        on the same wires.
        """
        new_dag = DAGCircuit()
        for qreg in dag.qregs.values():
            new_dag.add_qreg(qreg)
        for creg in dag.cregs.values():
            new_dag.add_creg(creg)

        sim = UnitarySimulatorPy()

        # compute ordered indices for the global circuit wires
        global_index_map = {}
        for wire in dag.wires:
            if not isinstance(wire[0], QuantumRegister):
                continue
            global_qregs = list(dag.qregs.values())
            global_index_map[wire] = global_qregs.index(wire[0]) + wire[1]

        blocks = self.property_set['block_list']
        nodes_seen = set()

        for node in dag.topological_op_nodes():
            # skip already-visited nodes or input/output nodes
            if node in nodes_seen or node.type == 'in' or node.type == 'out':
                continue
            # check if the node belongs to the next block
            if blocks and node in blocks[0]:
                block = blocks[0]
                # find the qubits involved in this block
                block_qargs = set()
                for nd in block:
                    block_qargs |= set(nd.qargs)
                # convert block to a sub-circuit, then simulate unitary and add
                block_width = len(block_qargs)
                q = QuantumRegister(block_width)
                subcirc = QuantumCircuit(q)
                block_index_map = self._block_qargs_to_indices(
                    block_qargs, global_index_map)
                for nd in block:
                    nodes_seen.add(nd)
                    subcirc.append(nd.op,
                                   [q[block_index_map[i]] for i in nd.qargs])
                qobj = assemble_circuits(subcirc)
                unitary_matrix = sim.run(qobj).result().get_unitary()
                unitary = Unitary(unitary_matrix)
                new_dag.apply_operation_back(
                    unitary,
                    sorted(block_qargs, key=lambda x: block_index_map[x]))
                del blocks[0]
            else:
                # the node could belong to some future block, but in that case
                # we simply skip it. It is guaranteed that we will revisit that
                # future block, via its other nodes
                for block in blocks[1:]:
                    if node in block:
                        break
                # freestanding nodes can just be added
                else:
                    nodes_seen.add(node)
                    new_dag.apply_operation_back(node.op, node.qargs,
                                                 node.cargs)

        return new_dag