Exemple #1
0
def quantum_volume_circuit(n, 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:
        n (int): number of qubits
        depth (int): ideal depth of each model circuit (over SU(4))
        measure (bool): include measurement in circuit.

    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(n)
    circuit = QuantumCircuit(qr)
    # For each layer
    for _ in repeat(None, depth):
        # Generate uniformly random permutation Pj of [0...n-1]
        perm = rng.permutation(n)
        # 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(n / 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
            decomposed_SU4 = two_qubit_kak(
                SU4)  # Decompose into CX and U gates
            qubits = [int(perm[2 * k]), int(perm[2 * k + 1])]
            for gate in decomposed_SU4:
                i0 = qubits[gate["args"][0]]
                if gate["name"] == "cx":
                    i1 = qubits[gate["args"][1]]
                    circuit.cx(qr[i0], qr[i1])
                elif gate["name"] == "u1":
                    circuit.u1(gate["params"][2], qr[i0])
                elif gate["name"] == "u2":
                    circuit.u2(gate["params"][1], gate["params"][2], qr[i0])
                elif gate["name"] == "u3":
                    circuit.u3(gate["params"][0], gate["params"][1],
                               gate["params"][2], qr[i0])
                elif gate["name"] == "id":
                    pass
    if measure is True:
        cr = ClassicalRegister(n)
        meas = QuantumCircuit(qr, cr)
        meas.barrier(qr)
        meas.measure(qr, cr)
        circuit = circuit + meas
    return circuit
Exemple #2
0
def build_model_circuits(n, depth, num_circ=1):
    """Create a quantum program containing model circuits.
    The model circuits consist of layers of Haar random
    elements of SU(4) applied between corresponding pairs
    of qubits in a random bipartition.

    Args:
        n (int): number of qubits
        depth (int): ideal depth of each model circuit (over SU(4))
        num_circ (int): number of model circuits to construct

    Returns:
        list(QuantumCircuit): list of quantum volume circuits
    """
    # Create quantum/classical registers of size n
    q = QuantumRegister(n)
    c = ClassicalRegister(n)
    # For each sample number, build the model circuits
    circuits = []
    for i in range(num_circ):
        # Initialize empty circuit
        circuit = QuantumCircuit(q, c)
        # For each layer
        for j in range(depth):
            # Generate uniformly random permutation Pj of [0...n-1]
            perm = random.permutation(n)
            # 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(n / 2)):
                qubits = [int(perm[2 * k]), int(perm[2 * k + 1])]
                SU = random_SU(4)
                decomposed_SU = two_qubit_kak(SU)
                for gate in decomposed_SU:
                    i0 = qubits[gate["args"][0]]
                    if gate["name"] == "cx":
                        i1 = qubits[gate["args"][1]]
                        circuit.cx(q[i0], q[i1])
                    elif gate["name"] == "u1":
                        circuit.u1(gate["params"][2], q[i0])
                    elif gate["name"] == "u2":
                        circuit.u2(gate["params"][1], gate["params"][2], q[i0])
                    elif gate["name"] == "u3":
                        circuit.u3(gate["params"][0], gate["params"][1],
                                   gate["params"][2], q[i0])
                    elif gate["name"] == "id":
                        pass
        # Barrier before measurement to prevent reordering, then measure
        circuit.barrier(q)
        circuit.measure(q, c)
        # Save sample circuit
        circuits.append(circuit)
    return circuits
Exemple #3
0
def build_model_circuits(name, n, depth, num_circ=1):
    """Create a quantum program containing model circuits.
    The model circuits consist of layers of Haar random
    elements of SU(4) applied between corresponding pairs
    of qubits in a random bipartition.
    name = leading name of circuits
    n = number of qubits
    depth = ideal depth of each model circuit (over SU(4))
    num_circ = number of model circuits to construct
    Return a quantum program.
    """
    qp = QuantumProgram()
    q = qp.create_quantum_register("q", n)
    c = qp.create_classical_register("c", n)
    # Create measurement subcircuit
    meas = qp.create_circuit("meas", [q], [c])
    for j in range(n):
        meas.measure(q[j], c[j])
    # For each sample number, build the model circuits
    for i in range(num_circ):
        # Initialize empty circuit Ci without measurement
        circuit_i = qp.create_circuit("%s_%d" % (name, i), [q], [c])
        # For each layer
        for j in range(depth):
            # Generate uniformly random permutation Pj of [0...n-1]
            perm = np.random.permutation(n)
            # For each pair p 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(n / 2)):
                qubits = [int(perm[2 * k]), int(perm[2 * k + 1])]
                SU = random_SU(4)
                for gate in two_qubit_kak(SU):
                    i0 = qubits[gate["args"][0]]
                    if gate["name"] == "cx":
                        i1 = qubits[gate["args"][1]]
                        circuit_i.cx(q[i0], q[i1])
                    elif gate["name"] == "u1":
                        circuit_i.u1(gate["params"][2], q[i0])
                    elif gate["name"] == "u2":
                        circuit_i.u2(gate["params"][1], gate["params"][2],
                                     q[i0])
                    elif gate["name"] == "u3":
                        circuit_i.u3(gate["params"][0], gate["params"][1],
                                     gate["params"][2], q[i0])
                    elif gate["name"] == "id":
                        pass  # do nothing
            # circuit_i.barrier(q)  # barriers between layers
        circuit_i.barrier(q)  # barrier before measurement
        # Create circuit with final measurement
        qp.add_circuit("%s_%d_meas" % (name, i), circuit_i + meas)
    return qp
Exemple #4
0
def makeGatesFrom4DMatrix(qc, qubits, mat):
    """makeGatesFrom4DMatrix

    :param qc: QuantumCircuit to apply the gate to
    :param qubits: qubits this gate acts on (2 qubits in an array)
    :param mat: unitary matrix (4D)
    """
    q1 = qubits[0]
    q2 = qubits[1]
    mat = filterNpdArray(mat)
    print('mat: ')
    test = filterNpdArray(dot(mat, mat.conj().T))
    matprint(test)
    MS_gate = two_qubit_kak(mat)
    mp = createMapping(qc)
    n = len(MS_gate)
    for i in range(n):
        gate = MS_gate[i]['name']
        qubits_direction = MS_gate[i]['args']
        params = MS_gate[i]['params']

        # grabs the gate (function) from mapping
        qiskit_gate = mp[gate]['gate']
        num_args = mp[gate]['args']
        argpos = mp[gate]['argpos']
        # num_ctl = mp[gate]['ctl']

        paramsf = []
        # print(params)
        if num_args != 0:
            for index in argpos:
                print(index)
                paramsf.append(params[index])

        qubits_inorder = []
        print(gate)
        for j in range(len(qubits_direction)):
            if qubits_direction[j] == 1:
                qubits_inorder.append(q2)
            else:
                qubits_inorder.append(q1)
        # implements the gate
        qiskit_gate(*paramsf, *qubits_inorder)
Exemple #5
0
def quantum_volume(qubit, final_measure=True, depth=10, seed=0):
    qreg = QuantumRegister(qubit)
    width = qubit

    np.random.seed(seed)
    circuit = QuantumCircuit(qreg,
                             name=f"Qvolume: {width} by {depth}, seed: {seed}")

    for _ in range(depth):
        # Generate uniformly random permutation Pj of [0...n-1]
        perm = np.random.permutation(width)

        # For each pair p in Pj, generate Haar random U(4)
        # Decompose each U(4) into CNOT + SU(2)
        for k in range(width // 2):
            U = random_unitary_matrix(4)
            for gate in two_qubit_kak(U):
                qs = [qreg[int(perm[2 * k + i])] for i in gate["args"]]
                pars = gate["params"]
                name = gate["name"]
                if name == "cx":
                    circuit.cx(qs[0], qs[1])
                elif name == "u1":
                    circuit.u1(pars[0], qs[0])
                elif name == "u2":
                    circuit.u2(*pars[:2], qs[0])
                elif name == "u3":
                    circuit.u3(*pars[:3], qs[0])
                elif name == "id":
                    pass  # do nothing
                else:
                    raise Exception(f"Unexpected gate name: {name}")

    circuit.barrier(qreg)

    if final_measure:
        creg = ClassicalRegister(qubit)
        circuit.add_register(creg)
        circuit.measure(qreg, creg)

    return circuit
Exemple #6
0
def build_model_circuit_kak(width, depth, seed=None):
    """Create quantum volume model circuit on quantum register qreg of given
    depth (default depth is equal to width) and random seed.
    The model circuits consist of layers of Haar random
    elements of U(4) applied between corresponding pairs
    of qubits in a random bipartition.
    """
    qreg = QuantumRegister(width)
    depth = depth or width

    np.random.seed(seed)
    circuit = QuantumCircuit(qreg,
                             name="Qvolume: %s by %s, seed: %s" %
                             (width, depth, seed))

    for _ in range(depth):
        # Generate uniformly random permutation Pj of [0...n-1]
        perm = np.random.permutation(width)

        # For each pair p in Pj, generate Haar random U(4)
        # Decompose each U(4) into CNOT + SU(2)
        for k in range(width // 2):
            U = random_unitary_matrix(4)
            for gate in two_qubit_kak(U):
                qs = [qreg[int(perm[2 * k + i])] for i in gate["args"]]
                pars = gate["params"]
                name = gate["name"]
                if name == "cx":
                    circuit.cx(qs[0], qs[1])
                elif name == "u1":
                    circuit.u1(pars[0], qs[0])
                elif name == "u2":
                    circuit.u2(*pars[:2], qs[0])
                elif name == "u3":
                    circuit.u3(*pars[:3], qs[0])
                elif name == "id":
                    pass  # do nothing
                else:
                    raise Exception("Unexpected gate name: %s" % name)
    return circuit
def random_circuit(n: int,
                   depth: int = 20,
                   seed: int = None) -> QuantumCircuit:
    """Create a quantum program containing model circuits.
    The model circuits consist of layers of Haar random
    elements of SU(4) applied between corresponding pairs
    of qubits in a random bipartition.
    name = leading name of circuits
    n = number of qubits
    depth = ideal depth of each model circuit (over SU(4))
    Return a quantum circuit.
    """
    np_random = np.random.RandomState(seed)
    q = QuantumRegister(n)
    qc = QuantumCircuit(q)
    # For each layer
    for j in range(depth):
        # Generate uniformly random permutation Pj of [0...n-1]
        perm = np_random.permutation(n)
        # For each pair p in Pj, generate Haar random SU(4)
        for k in range(math.floor(n / 2)):
            qubits = [int(perm[2 * k]), int(perm[2 * k + 1])]
            U = random_unitary(4, np_random)
            # TODO: Replace this with a general "two-qubit" gate instead of decomposing it.
            for gate in two_qubit_kak(U):
                i0 = qubits[gate["args"][0]]
                if gate["name"] == "cx":
                    i1 = qubits[gate["args"][1]]
                    qc.cx(q[i0], q[i1])
                elif gate["name"] == "u1":
                    qc.u1(gate["params"][2], q[i0])
                elif gate["name"] == "u2":
                    qc.u2(gate["params"][1], gate["params"][2], q[i0])
                elif gate["name"] == "u3":
                    qc.u3(gate["params"][0], gate["params"][1],
                          gate["params"][2], q[i0])
                elif gate["name"] == "id":
                    pass  # do nothing
    return qc
from math import log, floor

###############################################################################
# Testing values
sqrtX = array(
    [[0.5 * (1 + 1j), 0.5 * (1 - 1j)], [0.5 * (1 - 1j), 0.5 * (1 + 1j)]],
    dtype=complex)
sqrtX2, sqrtX2_I = sqrtGate()
MS = array(
    [[1, 0, 0, 0 - 1j], [0, 1, 0 - 1j, 0], [0, 0 - 1j, 1, 0],
     [0 - 1j, 0, 0, 1]],
    dtype=complex)

theta, phi, lmbda, s = euler_angles_1q(sqrtX)
theta2, phi2, lmbda2, s2 = euler_angles_1q(sqrtX2)
MS_gate = two_qubit_kak(MS)
print(theta, phi, lmbda, s)
print(theta2, phi2, lmbda2, s2)
for gate in MS_gate:
    print(gate)
###############################################################################

# still have to construct the controlled versions of the sqrt gates!


def change_basis(qc, q, theta, phi):
    qc.u3(theta, phi, phi, q)


def R(qc, q, theta, phi):
    """R