def _circuit_zsx(theta, phi, lam, phase, simplify=True, atol=DEFAULT_ATOL):
     # Shift theta and phi so decomposition is
     # RZ(phi+pi).SX.RZ(theta+pi).SX.RZ(lam)
     theta = _mod2pi(theta + np.pi)
     phi = _mod2pi(phi + np.pi)
     circuit = QuantumCircuit(1, global_phase=phase - np.pi / 2)
     # Check for decomposition into minimimal number required SX gates
     if simplify and np.isclose(abs(theta), np.pi, atol=atol):
         if not np.isclose(_mod2pi(abs(lam + phi + theta)), [0., 2 * np.pi],
                           atol=atol).any():
             circuit.append(RZGate(_mod2pi(lam + phi + theta)), [0])
             circuit.global_phase += 0.5 * _mod2pi(lam + phi + theta)
         circuit.global_phase += np.pi / 2
     elif simplify and np.isclose(abs(theta), [np.pi / 2, 3 * np.pi / 2],
                                  atol=atol).any():
         if not np.isclose(_mod2pi(abs(lam + theta)), [0., 2 * np.pi],
                           atol=atol).any():
             circuit.append(RZGate(_mod2pi(lam + theta)), [0])
             circuit.global_phase += 0.5 * _mod2pi(lam + theta)
         circuit.append(SXGate(), [0])
         if not np.isclose(_mod2pi(abs(phi + theta)), [0., 2 * np.pi],
                           atol=atol).any():
             circuit.append(RZGate(_mod2pi(phi + theta)), [0])
             circuit.global_phase += 0.5 * _mod2pi(phi + theta)
         if np.isclose(theta, [-np.pi / 2, 3 * np.pi / 2], atol=atol).any():
             circuit.global_phase += np.pi / 2
     else:
         if not np.isclose(abs(lam), [0., 2 * np.pi], atol=atol).any():
             circuit.append(RZGate(lam), [0])
             circuit.global_phase += 0.5 * lam
         circuit.append(SXGate(), [0])
         if not np.isclose(abs(theta), [0., 2 * np.pi], atol=atol).any():
             circuit.append(RZGate(theta), [0])
             circuit.global_phase += 0.5 * theta
         circuit.append(SXGate(), [0])
         if not np.isclose(abs(phi), [0., 2 * np.pi], atol=atol).any():
             circuit.append(RZGate(phi), [0])
             circuit.global_phase += 0.5 * phi
     return circuit
def template_nct_6a_4():
    """
    Returns:
        QuantumCircuit: template as a quantum circuit.
    """
    qc = QuantumCircuit(3)
    qc.cx(1, 2)
    qc.ccx(0, 2, 1)
    qc.cx(1, 2)
    qc.cx(2, 1)
    qc.ccx(0, 1, 2)
    qc.cx(2, 1)
    return qc
    def _define(self):
        """Define the MCX gate using a V-chain of CX gates."""
        # pylint: disable=cyclic-import
        from qiskit.circuit.quantumcircuit import QuantumCircuit
        q = QuantumRegister(self.num_qubits, name='q')
        qc = QuantumCircuit(q, name=self.name)
        q_controls = q[:self.num_ctrl_qubits]
        q_target = q[self.num_ctrl_qubits]
        q_ancillas = q[self.num_ctrl_qubits + 1:]

        definition = []

        if self._dirty_ancillas:
            i = self.num_ctrl_qubits - 3
            ancilla_pre_rule = [
                (U2Gate(0, numpy.pi), [q_target], []),
                (CXGate(), [q_target, q_ancillas[i]], []),
                (U1Gate(-numpy.pi / 4), [q_ancillas[i]], []),
                (CXGate(), [q_controls[-1], q_ancillas[i]], []),
                (U1Gate(numpy.pi / 4), [q_ancillas[i]], []),
                (CXGate(), [q_target, q_ancillas[i]], []),
                (U1Gate(-numpy.pi / 4), [q_ancillas[i]], []),
                (CXGate(), [q_controls[-1], q_ancillas[i]], []),
                (U1Gate(numpy.pi / 4), [q_ancillas[i]], []),
            ]
            for inst in ancilla_pre_rule:
                definition.append(inst)

            for j in reversed(range(2, self.num_ctrl_qubits - 1)):
                definition.append(
                    (RCCXGate(),
                     [q_controls[j], q_ancillas[i - 1], q_ancillas[i]], []))
                i -= 1

        definition.append(
            (RCCXGate(), [q_controls[0], q_controls[1], q_ancillas[0]], []))
        i = 0
        for j in range(2, self.num_ctrl_qubits - 1):
            definition.append(
                (RCCXGate(), [q_controls[j], q_ancillas[i],
                              q_ancillas[i + 1]], []))
            i += 1

        if self._dirty_ancillas:
            ancilla_post_rule = [
                (U1Gate(-numpy.pi / 4), [q_ancillas[i]], []),
                (CXGate(), [q_controls[-1], q_ancillas[i]], []),
                (U1Gate(numpy.pi / 4), [q_ancillas[i]], []),
                (CXGate(), [q_target, q_ancillas[i]], []),
                (U1Gate(-numpy.pi / 4), [q_ancillas[i]], []),
                (CXGate(), [q_controls[-1], q_ancillas[i]], []),
                (U1Gate(numpy.pi / 4), [q_ancillas[i]], []),
                (CXGate(), [q_target, q_ancillas[i]], []),
                (U2Gate(0, numpy.pi), [q_target], []),
            ]
            for inst in ancilla_post_rule:
                definition.append(inst)
        else:
            definition.append(
                (CCXGate(), [q_controls[-1], q_ancillas[i], q_target], []))

        for j in reversed(range(2, self.num_ctrl_qubits - 1)):
            definition.append(
                (RCCXGate(), [q_controls[j], q_ancillas[i - 1],
                              q_ancillas[i]], []))
            i -= 1
        definition.append(
            (RCCXGate(), [q_controls[0], q_controls[1], q_ancillas[i]], []))

        if self._dirty_ancillas:
            for i, j in enumerate(list(range(2, self.num_ctrl_qubits - 1))):
                definition.append(
                    (RCCXGate(),
                     [q_controls[j], q_ancillas[i], q_ancillas[i + 1]], []))

        for instr, qargs, cargs in definition:
            qc._append(instr, qargs, cargs)
        self.definition = qc
Beispiel #4
0
def template_9d_1():
    """
    Returns:
        QuantumCircuit: template as a quantum circuit.
    """
    qc = QuantumCircuit(2)
    qc.cx(0, 1)
    qc.x(1)
    qc.cx(1, 0)
    qc.x(1)
    qc.cx(0, 1)
    qc.cx(1, 0)
    qc.x(1)
    qc.cx(0, 1)
    qc.cx(1, 0)
    return qc
def circuit_to_gate(circuit,
                    parameter_map=None,
                    equivalence_library=None,
                    label=None):
    """Build a ``Gate`` object from a ``QuantumCircuit``.

    The gate is anonymous (not tied to a named quantum register),
    and so can be inserted into another circuit. The gate will
    have the same string name as the circuit.

    Args:
        circuit (QuantumCircuit): the input circuit.
        parameter_map (dict): For parameterized circuits, a mapping from
           parameters in the circuit to parameters to be used in the gate.
           If None, existing circuit parameters will also parameterize the
           Gate.
        equivalence_library (EquivalenceLibrary): Optional equivalence library
           where the converted gate will be registered.
        label (str): Optional gate label.

    Raises:
        QiskitError: if circuit is non-unitary or if
            parameter_map is not compatible with circuit

    Return:
        Gate: a Gate equivalent to the action of the
        input circuit. Upon decomposition, this gate will
        yield the components comprising the original circuit.
    """
    # pylint: disable=cyclic-import
    from qiskit.circuit.quantumcircuit import QuantumCircuit

    if circuit.clbits:
        raise QiskitError("Circuit with classical bits cannot be converted "
                          "to gate.")

    for inst, _, _ in circuit.data:
        if not isinstance(inst, Gate):
            raise QiskitError(
                ("One or more instructions cannot be converted to"
                 ' a gate. "{}" is not a gate instruction').format(inst.name))

    if parameter_map is None:
        parameter_dict = {p: p for p in circuit.parameters}
    else:
        parameter_dict = circuit._unroll_param_dict(parameter_map)

    if parameter_dict.keys() != circuit.parameters:
        raise QiskitError(("parameter_map should map all circuit parameters. "
                           "Circuit parameters: {}, parameter_map: {}").format(
                               circuit.parameters, parameter_dict))

    gate = Gate(
        name=circuit.name,
        num_qubits=sum(qreg.size for qreg in circuit.qregs),
        params=[*parameter_dict.values()],
        label=label,
    )
    gate.condition = None

    target = circuit.assign_parameters(parameter_dict, inplace=False)

    if equivalence_library is not None:
        equivalence_library.add_equivalence(gate, target)

    rules = target.data

    if gate.num_qubits > 0:
        q = QuantumRegister(gate.num_qubits, "q")

    qubit_map = {bit: q[idx] for idx, bit in enumerate(circuit.qubits)}

    # The 3rd parameter in the output tuple) is hard coded to [] because
    # Gate objects do not have cregs set and we've verified that all
    # instructions are gates
    rules = [(inst, [qubit_map[y] for y in qargs], [])
             for inst, qargs, _ in rules]
    qc = QuantumCircuit(q, name=gate.name, global_phase=target.global_phase)
    for instr, qargs, cargs in rules:
        qc._append(instr, qargs, cargs)
    gate.definition = qc
    return gate
 def _circuit_u1x(theta,
                  phi,
                  lam,
                  simplify=True,
                  atol=DEFAULT_ATOL):
     # Shift theta and phi so decomposition is
     # U1(phi).X90.U1(theta).X90.U1(lam)
     theta += np.pi
     phi += np.pi
     # Check for decomposition into minimimal number required X90 pulses
     if simplify and np.isclose(abs(theta), np.pi, atol=atol):
         # Zero X90 gate decomposition
         circuit = QuantumCircuit(1)
         circuit.append(U1Gate(lam + phi + theta), [0])
         return circuit
     if simplify and np.isclose(abs(theta), np.pi/2, atol=atol):
         # Single X90 gate decomposition
         circuit = QuantumCircuit(1)
         circuit.append(U1Gate(lam + theta), [0])
         circuit.append(RXGate(np.pi / 2), [0])
         circuit.append(U1Gate(phi + theta), [0])
         return circuit
     # General two-X90 gate decomposition
     circuit = QuantumCircuit(1)
     circuit.append(U1Gate(lam), [0])
     circuit.append(RXGate(np.pi / 2), [0])
     circuit.append(U1Gate(theta), [0])
     circuit.append(RXGate(np.pi / 2), [0])
     circuit.append(U1Gate(phi), [0])
     return circuit
Beispiel #7
0
def xx_circuit_step(source, strength, target, embodiment):
    """
    Builds a single step in an XX-based circuit.

    `source` and `target` are positive canonical coordinates; `strength` is the interaction strength
    at this step in the circuit as a canonical coordinate (so that CX = RZX(pi/2) corresponds to
    pi/4); and `embodiment` is a Qiskit circuit which enacts the canonical gate of the prescribed
    interaction `strength`.
    """

    permute_source_for_overlap, permute_target_for_overlap = None, None

    # apply all possible reflections, shifts to the source
    for source_reflection_name in reflection_options:
        reflected_source_coord, source_reflection, reflection_phase_shift = apply_reflection(
            source_reflection_name, source
        )
        for source_shift_name in shift_options:
            shifted_source_coord, source_shift, shift_phase_shift = apply_shift(
                source_shift_name, reflected_source_coord
            )

            # check for overlap, back out permutation
            source_shared, target_shared = None, None
            for i, j in [(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2), (2, 0), (2, 1), (2, 2)]:

                if (
                    abs(np.mod(abs(shifted_source_coord[i] - target[j]), np.pi)) < EPSILON
                    or abs(np.mod(abs(shifted_source_coord[i] - target[j]), np.pi) - np.pi)
                    < EPSILON
                ):
                    source_shared, target_shared = i, j
                    break
            if source_shared is None:
                continue

            # pick out the other coordinates
            source_first, source_second = (x for x in [0, 1, 2] if x != source_shared)
            target_first, target_second = (x for x in [0, 1, 2] if x != target_shared)

            # check for arccos validity
            r, s, u, v, x, y = decompose_xxyy_into_xxyy_xx(
                float(target[target_first]),
                float(target[target_second]),
                float(shifted_source_coord[source_first]),
                float(shifted_source_coord[source_second]),
                float(strength),
            )
            if any(math.isnan(val) for val in (r, s, u, v, x, y)):
                continue

            # OK: this combination of things works.
            # save the permutation which rotates the shared coordinate into ZZ.
            permute_source_for_overlap = canonical_rotation_circuit(source_first, source_second)
            permute_target_for_overlap = canonical_rotation_circuit(target_first, target_second)
            break

        if permute_source_for_overlap is not None:
            break

    if permute_source_for_overlap is None:
        raise QiskitError(
            "Error during RZX decomposition: Could not find a suitable Weyl "
            f"reflection to match {source} to {target} along {strength}."
        )

    prefix_circuit, affix_circuit = QuantumCircuit(2), QuantumCircuit(2)

    # the basic formula we're trying to work with is:
    # target^p_t_f_o =
    #     rs * (source^s_reflection * s_shift)^p_s_f_o * uv * operation * xy
    # but we're rearranging it into the form
    #   target = affix source prefix
    # and computing just the prefix / affix circuits.

    # the outermost prefix layer comes from the (inverse) target permutation.
    prefix_circuit.compose(permute_target_for_overlap.inverse(), inplace=True)
    # the middle prefix layer comes from the local Z rolls.
    prefix_circuit.rz(2 * x, [0])
    prefix_circuit.rz(2 * y, [1])
    prefix_circuit.compose(embodiment, inplace=True)
    prefix_circuit.rz(2 * u, [0])
    prefix_circuit.rz(2 * v, [1])
    # the innermost prefix layer is source_reflection, shifted by source_shift,
    # finally conjugated by p_s_f_o.
    prefix_circuit.compose(permute_source_for_overlap, inplace=True)
    prefix_circuit.compose(source_reflection, inplace=True)
    prefix_circuit.global_phase += -np.log(reflection_phase_shift).imag
    prefix_circuit.global_phase += -np.log(shift_phase_shift).imag

    # the affix circuit is constructed in reverse.
    # first (i.e., innermost), we install the other half of the source transformations and p_s_f_o.
    affix_circuit.compose(source_reflection.inverse(), inplace=True)
    affix_circuit.compose(source_shift, inplace=True)
    affix_circuit.compose(permute_source_for_overlap.inverse(), inplace=True)
    # then, the other local rolls in the middle.
    affix_circuit.rz(2 * r, [0])
    affix_circuit.rz(2 * s, [1])
    # finally, the other half of the p_t_f_o conjugation.
    affix_circuit.compose(permute_target_for_overlap, inplace=True)

    return {"prefix_circuit": prefix_circuit, "affix_circuit": affix_circuit}
    def _circuit_kak(
        theta,
        phi,
        lam,
        phase,
        simplify=True,
        atol=DEFAULT_ATOL,
        allow_non_canonical=True,
        k_gate=RZGate,
        a_gate=RYGate,
    ):
        """
        Installs the angles phi, theta, and lam into a KAK-type decomposition of the form
        K(phi) . A(theta) . K(lam) , where K and A are an orthogonal pair drawn from RZGate, RYGate,
        and RXGate.

        Args:
            theta (float): The middle KAK parameter.  Expected to lie in [0, pi).
            phi (float): The first KAK parameter.
            lam (float): The final KAK parameter.
            phase (float): The input global phase.
            k_gate (Callable): The constructor for the K gate Instruction.
            a_gate (Callable): The constructor for the A gate Instruction.
            simplify (bool): Indicates whether gates should be elided / coalesced where possible.
            allow_non_canonical (bool): Indicates whether we are permitted to reverse the sign of
                the middle parameter, theta, in the output.  When this and `simplify` are both
                enabled, we take the opportunity to commute half-rotations in the outer gates past
                the middle gate, which permits us to coalesce them at the cost of reversing the sign
                of theta.

        Returns:
            QuantumCircuit: The assembled circuit.
        """
        gphase = phase - (phi + lam) / 2
        qr = QuantumRegister(1, "qr")
        circuit = QuantumCircuit(qr)
        if not simplify:
            atol = -1.0
        # Early return for the middle-gate-free case
        if abs(theta) < atol:
            lam, phi = lam + phi, 0
            # NOTE: The following normalization is safe, because the gphase correction below
            #       fixes a particular diagonal entry to 1, which prevents any potential phase
            #       slippage coming from _mod_2pi injecting multiples of 2pi.
            lam = _mod_2pi(lam, atol)
            if abs(lam) > atol:

                circuit._append(k_gate(lam), [qr[0]], [])
                gphase += lam / 2
            circuit.global_phase = gphase
            return circuit
        if abs(theta - np.pi) < atol:
            gphase += phi
            lam, phi = lam - phi, 0
        if allow_non_canonical and (abs(_mod_2pi(lam + np.pi)) < atol
                                    or abs(_mod_2pi(phi + np.pi)) < atol):
            lam, theta, phi = lam + np.pi, -theta, phi + np.pi
        lam = _mod_2pi(lam, atol)
        if abs(lam) > atol:
            gphase += lam / 2
            circuit._append(k_gate(lam), [qr[0]], [])
        circuit._append(a_gate(theta), [qr[0]], [])
        phi = _mod_2pi(phi, atol)
        if abs(phi) > atol:
            gphase += phi / 2
            circuit._append(k_gate(phi), [qr[0]], [])
        circuit.global_phase = gphase
        return circuit
Beispiel #9
0
def two_qubit_kak(unitary):
    """Decompose a two-qubit gate over SU(2)+CNOT using the KAK decomposition.

    Args:
        unitary (Operator): a 4x4 unitary operator to decompose.

    Returns:
        QuantumCircuit: a circuit implementing the unitary over SU(2)+CNOT

    Raises:
        QiskitError: input not a unitary, or error in KAK decomposition.
    """
    if hasattr(unitary, 'to_operator'):
        # If input is a BaseOperator subclass this attempts to convert
        # the object to an Operator so that we can extract the underlying
        # numpy matrix from `Operator.data`.
        unitary = unitary.to_operator().data
    if hasattr(unitary, 'to_matrix'):
        # If input is Gate subclass or some other class object that has
        # a to_matrix method this will call that method.
        unitary = unitary.to_matrix()
    # Convert to numpy array incase not already an array
    unitary_matrix = np.array(unitary, dtype=complex)
    # Check input is a 2-qubit unitary
    if unitary_matrix.shape != (4, 4):
        raise QiskitError("two_qubit_kak: Expected 4x4 matrix")
    if not is_unitary_matrix(unitary_matrix):
        raise QiskitError("Input matrix is not unitary.")
    phase = la.det(unitary_matrix)**(-1.0 / 4.0)
    # Make it in SU(4), correct phase at the end
    U = phase * unitary_matrix
    # B changes to the Bell basis
    B = (1.0 / math.sqrt(2)) * np.array(
        [[1, 1j, 0, 0], [0, 0, 1j, 1], [0, 0, 1j, -1], [1, -1j, 0, 0]],
        dtype=complex)

    # We also need B.conj().T below
    Bdag = B.conj().T
    # U' = Bdag . U . B
    Uprime = Bdag.dot(U.dot(B))
    # M^2 = trans(U') . U'
    M2 = Uprime.T.dot(Uprime)

    # Diagonalize M2
    # Must use diagonalization routine which finds a real orthogonal matrix P
    # when M2 is real.
    D, P = la.eig(M2)
    D = np.diag(D)
    # If det(P) == -1 then in O(4), apply a swap to make P in SO(4)
    if abs(la.det(P) + 1) < 1e-5:
        swap = np.array(
            [[1, 0, 0, 0], [0, 0, 1, 0], [0, 1, 0, 0], [0, 0, 0, 1]],
            dtype=complex)
        P = P.dot(swap)
        D = swap.dot(D.dot(swap))

    Q = np.sqrt(D)  # array from elementwise sqrt
    # Want to take square root so that Q has determinant 1
    if abs(la.det(Q) + 1) < 1e-5:
        Q[0, 0] = -Q[0, 0]

    # Q^-1*P.T = P' -> QP' = P.T (solve for P' using Ax=b)
    Pprime = la.solve(Q, P.T)
    # K' now just U' * P * P'
    Kprime = Uprime.dot(P.dot(Pprime))

    K1 = B.dot(Kprime.dot(P.dot(Bdag)))
    A = B.dot(Q.dot(Bdag))
    K2 = B.dot(P.T.dot(Bdag))
    # KAK = K1 * A * K2
    KAK = K1.dot(A.dot(K2))

    # Verify decomp matches input unitary.
    if la.norm(KAK - U) > 1e-6:
        raise QiskitError("two_qubit_kak: KAK decomposition " +
                          "does not return input unitary.")

    # Compute parameters alpha, beta, gamma so that
    # A = exp(i * (alpha * XX + beta * YY + gamma * ZZ))
    xx = np.array([[0, 0, 0, 1], [0, 0, 1, 0], [0, 1, 0, 0], [1, 0, 0, 0]],
                  dtype=complex)

    yy = np.array([[0, 0, 0, -1], [0, 0, 1, 0], [0, 1, 0, 0], [-1, 0, 0, 0]],
                  dtype=complex)

    zz = np.array([[1, 0, 0, 0], [0, -1, 0, 0], [0, 0, -1, 0], [0, 0, 0, 1]],
                  dtype=complex)

    A_real_tr = A.real.trace()
    alpha = math.atan2(A.dot(xx).imag.trace(), A_real_tr)
    beta = math.atan2(A.dot(yy).imag.trace(), A_real_tr)
    gamma = math.atan2(A.dot(zz).imag.trace(), A_real_tr)

    # K1 = kron(U1, U2) and K2 = kron(V1, V2)
    # Find the matrices U1, U2, V1, V2

    # Find a block in K1 where U1_ij * [U2] is not zero
    L = K1[0:2, 0:2]
    if la.norm(L) < 1e-9:
        L = K1[0:2, 2:4]
        if la.norm(L) < 1e-9:
            L = K1[2:4, 2:4]
    # Remove the U1_ij prefactor
    Q = L.dot(L.conj().T)
    U2 = L / math.sqrt(Q[0, 0].real)

    # Now grab U1 given we know U2
    R = K1.dot(np.kron(np.identity(2), U2.conj().T))
    U1 = np.zeros((2, 2), dtype=complex)
    U1[0, 0] = R[0, 0]
    U1[0, 1] = R[0, 2]
    U1[1, 0] = R[2, 0]
    U1[1, 1] = R[2, 2]

    # Repeat K1 routine for K2
    L = K2[0:2, 0:2]
    if la.norm(L) < 1e-9:
        L = K2[0:2, 2:4]
        if la.norm(L) < 1e-9:
            L = K2[2:4, 2:4]
    Q = np.dot(L, np.transpose(L.conjugate()))
    V2 = L / np.sqrt(Q[0, 0])
    R = np.dot(K2, np.kron(np.identity(2), np.transpose(V2.conjugate())))

    V1 = np.zeros_like(U1)
    V1[0, 0] = R[0, 0]
    V1[0, 1] = R[0, 2]
    V1[1, 0] = R[2, 0]
    V1[1, 1] = R[2, 2]

    if la.norm(np.kron(U1, U2) - K1) > 1e-4:
        raise QiskitError("two_qubit_kak: K1 != U1 x U2")
    if la.norm(np.kron(V1, V2) - K2) > 1e-4:
        raise QiskitError("two_qubit_kak: K2 != V1 x V2")

    test = la.expm(1j * (alpha * xx + beta * yy + gamma * zz))
    if la.norm(A - test) > 1e-4:
        raise QiskitError("two_qubit_kak: " +
                          "Matrix A does not match xx,yy,zz decomposition.")

    # Circuit that implements K1 * A * K2 (up to phase), using
    # Vatan and Williams Fig. 6 of quant-ph/0308006v3
    # Include prefix and suffix single-qubit gates into U2, V1 respectively.

    V2 = np.array([[np.exp(1j * np.pi / 4), 0], [0, np.exp(-1j * np.pi / 4)]],
                  dtype=complex).dot(V2)
    U1 = U1.dot(
        np.array([[np.exp(-1j * np.pi / 4), 0], [0, np.exp(1j * np.pi / 4)]],
                 dtype=complex))

    # Corrects global phase: exp(ipi/4)*phase'
    U1 = U1.dot(
        np.array([[np.exp(1j * np.pi / 4), 0], [0, np.exp(1j * np.pi / 4)]],
                 dtype=complex))
    U1 = phase.conjugate() * U1

    # Test
    g1 = np.kron(V1, V2)
    g2 = np.array([[1, 0, 0, 0], [0, 0, 0, 1], [0, 0, 1, 0], [0, 1, 0, 0]],
                  dtype=complex)

    theta = 2 * gamma - np.pi / 2

    Ztheta = np.array(
        [[np.exp(1j * theta / 2), 0], [0, np.exp(-1j * theta / 2)]],
        dtype=complex)

    kappa = np.pi / 2 - 2 * alpha
    Ykappa = np.array(
        [[math.cos(kappa / 2), math.sin(kappa / 2)],
         [-math.sin(kappa / 2), math.cos(kappa / 2)]],
        dtype=complex)
    g3 = np.kron(Ztheta, Ykappa)
    g4 = np.array([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 0, 1], [0, 0, 1, 0]],
                  dtype=complex)

    zeta = 2 * beta - np.pi / 2
    Yzeta = np.array(
        [[math.cos(zeta / 2), math.sin(zeta / 2)],
         [-math.sin(zeta / 2), math.cos(zeta / 2)]],
        dtype=complex)
    g5 = np.kron(np.identity(2), Yzeta)
    g6 = g2
    g7 = np.kron(U1, U2)

    V = g2.dot(g1)
    V = g3.dot(V)
    V = g4.dot(V)
    V = g5.dot(V)
    V = g6.dot(V)
    V = g7.dot(V)

    if la.norm(V - U * phase.conjugate()) > 1e-6:
        raise QiskitError("two_qubit_kak: " +
                          "sequence incorrect, unknown error")

    v1_param = euler_angles_1q(V1)
    v2_param = euler_angles_1q(V2)
    u1_param = euler_angles_1q(U1)
    u2_param = euler_angles_1q(U2)

    v1_gate = U3Gate(v1_param[0], v1_param[1], v1_param[2])
    v2_gate = U3Gate(v2_param[0], v2_param[1], v2_param[2])
    u1_gate = U3Gate(u1_param[0], u1_param[1], u1_param[2])
    u2_gate = U3Gate(u2_param[0], u2_param[1], u2_param[2])

    q = QuantumRegister(2)
    return_circuit = QuantumCircuit(q)

    return_circuit.append(v1_gate, [q[1]])

    return_circuit.append(v2_gate, [q[0]])

    return_circuit.append(CnotGate(), [q[0], q[1]])

    gate = U3Gate(0.0, 0.0, -2.0 * gamma + np.pi / 2.0)
    return_circuit.append(gate, [q[1]])

    gate = U3Gate(-np.pi / 2.0 + 2.0 * alpha, 0.0, 0.0)
    return_circuit.append(gate, [q[0]])

    return_circuit.append(CnotGate(), [q[1], q[0]])

    gate = U3Gate(-2.0 * beta + np.pi / 2.0, 0.0, 0.0)
    return_circuit.append(gate, [q[0]])

    return_circuit.append(CnotGate(), [q[0], q[1]])

    return_circuit.append(u1_gate, [q[1]])

    return_circuit.append(u2_gate, [q[0]])

    return return_circuit
Beispiel #10
0
    def _build(self) -> None:
        """Build the circuit."""
        if self._data:
            return

        _ = self._check_configuration()

        self._data = []

        if self.num_qubits == 0:
            return

        circuit = QuantumCircuit(*self.qregs, name=self.name)

        # use the initial state as starting circuit, if it is set
        if self.initial_state:
            if isinstance(self.initial_state, QuantumCircuit):
                initial = self.initial_state.copy()
            else:
                initial = self.initial_state.construct_circuit(
                    "circuit", register=self.qregs[0])
            circuit.compose(initial, inplace=True)

        param_iter = iter(self.ordered_parameters)

        # build the prepended layers
        self._build_additional_layers(circuit, "prepended")

        # main loop to build the entanglement and rotation layers
        for i in range(self.reps):
            # insert barrier if specified and there is a preceding layer
            if self._insert_barriers and (i > 0
                                          or len(self._prepended_blocks) > 0):
                circuit.barrier()

            # build the rotation layer
            self._build_rotation_layer(circuit, param_iter, i)

            # barrier in between rotation and entanglement layer
            if self._insert_barriers and len(self._rotation_blocks) > 0:
                circuit.barrier()

            # build the entanglement layer
            self._build_entanglement_layer(circuit, param_iter, i)

        # add the final rotation layer
        if not self._skip_final_rotation_layer:
            if self.insert_barriers and self.reps > 0:
                circuit.barrier()
            self._build_rotation_layer(circuit, param_iter, self.reps)

        # add the appended layers
        self._build_additional_layers(circuit, "appended")

        # cast global phase to float if it has no free parameters
        if isinstance(circuit.global_phase, ParameterExpression):
            try:
                circuit.global_phase = float(circuit.global_phase._symbol_expr)
            # RuntimeError is raised if symengine is used, for SymPy it is a TypeError
            except (RuntimeError, TypeError):
                # expression contains free parameters
                pass

        try:
            block = circuit.to_gate()
        except QiskitError:
            block = circuit.to_instruction()

        self.append(block, self.qubits)
 def _circuit_psx(theta,
                  phi,
                  lam,
                  simplify=True,
                  atol=DEFAULT_ATOL):
     # Shift theta and phi so decomposition is
     # Phase(phi+pi).SX.Phase(theta+pi).SX.Phase(lam)
     theta = _mod2pi(theta + np.pi)
     phi = _mod2pi(phi + np.pi)
     circuit = QuantumCircuit(1)
     # Check for decomposition into minimimal number required SX gates
     if simplify and np.isclose(abs(theta), np.pi, atol=atol):
         if not np.isclose(_mod2pi(abs(lam + phi + theta)),
                           [0., 2*np.pi], atol=atol).any():
             circuit.append(PhaseGate(_mod2pi(lam + phi + theta)), [0])
     elif simplify and np.isclose(abs(theta),
                                  [np.pi/2, 3*np.pi/2], atol=atol).any():
         if not np.isclose(_mod2pi(abs(lam + theta)),
                           [0., 2*np.pi], atol=atol).any():
             circuit.append(PhaseGate(_mod2pi(lam + theta)), [0])
         circuit.append(SXGate(), [0])
         if not np.isclose(_mod2pi(abs(phi + theta)),
                           [0., 2*np.pi], atol=atol).any():
             circuit.append(PhaseGate(_mod2pi(phi + theta)), [0])
     else:
         if not np.isclose(abs(lam), [0., 2*np.pi], atol=atol).any():
             circuit.append(PhaseGate(lam), [0])
         circuit.append(SXGate(), [0])
         if not np.isclose(abs(theta), [0., 2*np.pi], atol=atol).any():
             circuit.append(PhaseGate(theta), [0])
         circuit.append(SXGate(), [0])
         if not np.isclose(abs(phi), [0., 2*np.pi], atol=atol).any():
             circuit.append(PhaseGate(phi), [0])
     return circuit
Beispiel #12
0
    def add_layer(
        self,
        other: Union["NLocal", Instruction, QuantumCircuit],
        entanglement: Optional[Union[List[int], str, List[List[int]]]] = None,
        front: bool = False,
    ) -> "NLocal":
        """Append another layer to the NLocal.

        Args:
            other: The layer to compose, can be another NLocal, an Instruction or Gate,
                or a QuantumCircuit.
            entanglement: The entanglement or qubit indices.
            front: If True, ``other`` is appended to the front, else to the back.

        Returns:
            self, such that chained composes are possible.

        Raises:
            TypeError: If `other` is not compatible, i.e. is no Instruction and does not have a
                `to_instruction` method.
        """
        block = self._convert_to_block(other)

        if entanglement is None:
            entanglement = [list(range(block.num_qubits))]
        elif isinstance(entanglement,
                        list) and not isinstance(entanglement[0], list):
            entanglement = [entanglement]

        if front:
            self._prepended_blocks += [block]
            self._prepended_entanglement += [entanglement]
        else:
            self._appended_blocks += [block]
            self._appended_entanglement += [entanglement]

        if isinstance(entanglement, list):
            num_qubits = 1 + max(max(indices) for indices in entanglement)
            if num_qubits > self.num_qubits:
                self._invalidate()  # rebuild circuit
                self.num_qubits = num_qubits

        # modify the circuit accordingly
        if self._data and front is False:
            if self._insert_barriers and len(self._data) > 0:
                self.barrier()

            if isinstance(entanglement, str):
                entangler_map = get_entangler_map(block.num_qubits,
                                                  self.num_qubits,
                                                  entanglement)
            else:
                entangler_map = entanglement

            layer = QuantumCircuit(self.num_qubits)
            for i in entangler_map:
                params = self.ordered_parameters[-len(get_parameters(block)):]
                parameterized_block = self._parameterize_block(block,
                                                               params=params)
                layer.compose(parameterized_block, i, inplace=True)

            self.compose(layer, inplace=True)
        else:
            # cannot prepend a block currently, just rebuild
            self._invalidate()

        return self
Beispiel #13
0
def template_7b_1():
    """
    Returns:
        QuantumCircuit: template as a quantum circuit.
    """
    qc = QuantumCircuit(3)
    qc.x(0)
    qc.cx(0, 1)
    qc.cx(1, 2)
    qc.ccx(0, 1, 2)
    qc.cx(0, 1)
    qc.x(0)
    qc.ccx(0, 1, 2)
    return qc
Beispiel #14
0
 def _define(self):
     """
     gate cphase(lambda) a,b
     { phase(lambda/2) a; cx a,b;
       phase(-lambda/2) b; cx a,b;
       phase(lambda/2) b;
     }
     """
     # pylint: disable=cyclic-import
     from qiskit.circuit.quantumcircuit import QuantumCircuit
     q = QuantumRegister(2, 'q')
     qc = QuantumCircuit(q, name=self.name)
     qc.p(self.params[0] / 2, 0)
     qc.cx(0, 1)
     qc.p(-self.params[0] / 2, 1)
     qc.cx(0, 1)
     qc.p(self.params[0] / 2, 1)
     self.definition = qc
 def _circuit_rr(theta, phi, lam, simplify=True, atol=DEFAULT_ATOL):
     circuit = QuantumCircuit(1)
     if not simplify or not np.isclose(theta, -np.pi, atol=atol):
         circuit.append(RGate(theta + np.pi, np.pi / 2 - lam), [0])
     circuit.append(RGate(-np.pi, 0.5 * (phi - lam + np.pi)), [0])
     return circuit
Beispiel #16
0
def clifford_6_5():
    """
    Returns:
        QuantumCircuit: template as a quantum circuit.
    """
    qc = QuantumCircuit(2)
    qc.cz(0, 1)
    qc.cx(0, 1)
    qc.s(0)
    qc.sdg(1)
    qc.cx(0, 1)
    qc.s(1)
    return qc
 def _circuit_zxz(theta,
                  phi,
                  lam,
                  simplify=False,
                  atol=DEFAULT_ATOL):
     if simplify and np.isclose(theta, 0.0, atol=atol):
         circuit = QuantumCircuit(1)
         circuit.append(RZGate(phi + lam), [0])
         return circuit
     circuit = QuantumCircuit(1)
     if not simplify or not np.isclose(lam, 0.0, atol=atol):
         circuit.append(RZGate(lam), [0])
     if not simplify or not np.isclose(theta, 0.0, atol=atol):
         circuit.append(RXGate(theta), [0])
     if not simplify or not np.isclose(phi, 0.0, atol=atol):
         circuit.append(RZGate(phi), [0])
     return circuit
def circuit_to_instruction(circuit,
                           parameter_map=None,
                           equivalence_library=None):
    """Build an ``Instruction`` object from a ``QuantumCircuit``.

    The instruction is anonymous (not tied to a named quantum register),
    and so can be inserted into another circuit. The instruction will
    have the same string name as the circuit.

    Args:
        circuit (QuantumCircuit): the input circuit.
        parameter_map (dict): For parameterized circuits, a mapping from
           parameters in the circuit to parameters to be used in the instruction.
           If None, existing circuit parameters will also parameterize the
           instruction.
        equivalence_library (EquivalenceLibrary): Optional equivalence library
           where the converted instruction will be registered.

    Raises:
        QiskitError: if parameter_map is not compatible with circuit

    Return:
        qiskit.circuit.Instruction: an instruction equivalent to the action of the
        input circuit. Upon decomposition, this instruction will
        yield the components comprising the original circuit.

    Example:
        .. jupyter-execute::

            from qiskit import QuantumRegister, ClassicalRegister, QuantumCircuit
            from qiskit.converters import circuit_to_instruction
            %matplotlib inline

            q = QuantumRegister(3, 'q')
            c = ClassicalRegister(3, 'c')
            circ = QuantumCircuit(q, c)
            circ.h(q[0])
            circ.cx(q[0], q[1])
            circ.measure(q[0], c[0])
            circ.rz(0.5, q[1]).c_if(c, 2)
            circuit_to_instruction(circ)
    """
    # pylint: disable=cyclic-import
    from qiskit.circuit.quantumcircuit import QuantumCircuit

    if parameter_map is None:
        parameter_dict = {p: p for p in circuit.parameters}
    else:
        parameter_dict = circuit._unroll_param_dict(parameter_map)

    if parameter_dict.keys() != circuit.parameters:
        raise QiskitError(('parameter_map should map all circuit parameters. '
                           'Circuit parameters: {}, parameter_map: {}').format(
                               circuit.parameters, parameter_dict))

    instruction = Instruction(
        name=circuit.name,
        num_qubits=sum([qreg.size for qreg in circuit.qregs]),
        num_clbits=sum([creg.size for creg in circuit.cregs]),
        params=sorted(parameter_dict.values(), key=lambda p: p.name))
    instruction.condition = None

    def find_bit_position(bit):
        """find the index of a given bit (Register, int) within
        a flat ordered list of bits of the circuit
        """
        if isinstance(bit, Qubit):
            ordered_regs = circuit.qregs
        else:
            ordered_regs = circuit.cregs
        reg_index = ordered_regs.index(bit.register)
        return sum([reg.size for reg in ordered_regs[:reg_index]]) + bit.index

    target = circuit.assign_parameters(parameter_dict, inplace=False)

    if equivalence_library is not None:
        equivalence_library.add_equivalence(instruction, target)

    definition = target.data

    regs = []
    if instruction.num_qubits > 0:
        q = QuantumRegister(instruction.num_qubits, 'q')
        regs.append(q)

    if instruction.num_clbits > 0:
        c = ClassicalRegister(instruction.num_clbits, 'c')
        regs.append(c)

    definition = list(
        map(
            lambda x:
            (x[0], list(map(lambda y: q[find_bit_position(y)], x[1])),
             list(map(lambda y: c[find_bit_position(y)], x[2]))), definition))

    # fix condition
    for rule in definition:
        condition = rule[0].condition
        if condition:
            reg, val = condition
            if reg.size == c.size:
                rule[0].condition = (c, val)
            else:
                raise QiskitError(
                    'Cannot convert condition in circuit with '
                    'multiple classical registers to instruction')

    qc = QuantumCircuit(*regs, name=instruction.name)
    qc._data = definition
    if circuit.global_phase:
        qc.global_phase = circuit.global_phase

    instruction.definition = qc

    return instruction
Beispiel #19
0
def _two_qubit_evolution(pauli, time, cx_structure):
    # Get the Paulis and the qubits they act on.
    # Note that all phases are removed from the pauli label and are only in the coefficients.
    # That's because the operators we evolved have all been translated to a SparsePauliOp.
    labels_as_array = np.array(list(reversed(pauli.to_label())))
    qubits = np.where(labels_as_array != "I")[0]
    labels = np.array([labels_as_array[idx] for idx in qubits])

    definition = QuantumCircuit(pauli.num_qubits)

    # go through all cases we have implemented in Qiskit
    if all(labels == "X"):  # RXX
        definition.rxx(2 * time, qubits[0], qubits[1])
    elif all(labels == "Y"):  # RYY
        definition.ryy(2 * time, qubits[0], qubits[1])
    elif all(labels == "Z"):  # RZZ
        definition.rzz(2 * time, qubits[0], qubits[1])
    elif labels[0] == "Z" and labels[1] == "X":  # RZX
        definition.rzx(2 * time, qubits[0], qubits[1])
    elif labels[0] == "X" and labels[1] == "Z":  # RXZ
        definition.rzx(2 * time, qubits[1], qubits[0])
    else:  # all the others are not native in Qiskit, so use default the decomposition
        definition = _multi_qubit_evolution(pauli, time, cx_structure)

    return definition
Beispiel #20
0
def _experiments_to_circuits(qobj):
    """Return a list of QuantumCircuit object(s) from a qobj.

    Args:
        qobj (Qobj): The Qobj object to convert to QuantumCircuits

    Returns:
        list: A list of QuantumCircuit objects from the qobj
    """
    if not qobj.experiments:
        return None

    circuits = []
    for exp in qobj.experiments:
        quantum_registers = [
            QuantumRegister(i[1], name=i[0]) for i in exp.header.qreg_sizes
        ]
        classical_registers = [
            ClassicalRegister(i[1], name=i[0]) for i in exp.header.creg_sizes
        ]
        circuit = QuantumCircuit(*quantum_registers,
                                 *classical_registers,
                                 name=exp.header.name)
        qreg_dict = collections.OrderedDict()
        creg_dict = collections.OrderedDict()
        for reg in quantum_registers:
            qreg_dict[reg.name] = reg
        for reg in classical_registers:
            creg_dict[reg.name] = reg
        conditional = {}
        for i in exp.instructions:
            name = i.name
            qubits = []
            params = getattr(i, "params", [])
            try:
                for qubit in i.qubits:
                    qubit_label = exp.header.qubit_labels[qubit]
                    qubits.append(qreg_dict[qubit_label[0]][qubit_label[1]])
            except Exception:  # pylint: disable=broad-except
                pass
            clbits = []
            try:
                for clbit in i.memory:
                    clbit_label = exp.header.clbit_labels[clbit]
                    clbits.append(creg_dict[clbit_label[0]][clbit_label[1]])
            except Exception:  # pylint: disable=broad-except
                pass
            if hasattr(circuit, name):
                instr_method = getattr(circuit, name)
                if i.name in ["snapshot"]:
                    _inst = instr_method(i.label,
                                         snapshot_type=i.snapshot_type,
                                         qubits=qubits,
                                         params=params)
                elif i.name == "initialize":
                    _inst = instr_method(params, qubits)
                elif i.name == "isometry":
                    _inst = instr_method(*params, qubits, clbits)
                elif i.name in ["mcx", "mcu1", "mcp"]:
                    _inst = instr_method(*params, qubits[:-1], qubits[-1],
                                         *clbits)
                else:
                    _inst = instr_method(*params, *qubits, *clbits)
            elif name == "bfunc":
                conditional["value"] = int(i.val, 16)
                full_bit_size = sum(creg_dict[x].size for x in creg_dict)
                mask_map = {}
                raw_map = {}
                raw = []

                for creg in creg_dict:
                    size = creg_dict[creg].size
                    reg_raw = [1] * size
                    if not raw:
                        raw = reg_raw
                    else:
                        for pos, val in enumerate(raw):
                            if val == 1:
                                raw[pos] = 0
                        raw = reg_raw + raw
                    mask = [0] * (full_bit_size - len(raw)) + raw
                    raw_map[creg] = mask
                    mask_map[int("".join(str(x) for x in mask), 2)] = creg
                if bin(int(i.mask, 16)).count("1") == 1:
                    cbit = int(math.log2(int(i.mask, 16)))
                    for reg in creg_dict:
                        size = creg_dict[reg].size
                        if cbit >= size:
                            cbit -= size
                        else:
                            conditional["register"] = creg_dict[reg][cbit]
                            break
                    mask_str = bin(int(i.mask, 16))[2:].zfill(full_bit_size)
                    mask = [int(item) for item in list(mask_str)]
                else:
                    creg = mask_map[int(i.mask, 16)]
                    conditional["register"] = creg_dict[creg]
                    mask = raw_map[creg]
                val = int(i.val, 16)
                for j in reversed(mask):
                    if j == 0:
                        val = val >> 1
                    else:
                        conditional["value"] = val
                        break
            else:
                _inst = temp_opaque_instruction = Instruction(
                    name=name,
                    num_qubits=len(qubits),
                    num_clbits=len(clbits),
                    params=params)
                circuit.append(temp_opaque_instruction, qubits, clbits)
            if conditional and name != "bfunc":
                _inst.c_if(conditional["register"], conditional["value"])
                conditional = {}
        pulse_lib = qobj.config.pulse_library if hasattr(
            qobj.config, "pulse_library") else []
        parametric_pulses = (qobj.config.parametric_pulses if hasattr(
            qobj.config, "parametric_pulses") else [])
        # The dict update method did not work here; could investigate in the future
        if hasattr(qobj.config, "calibrations"):
            circuit.calibrations = dict(
                **circuit.calibrations,
                **_qobj_to_circuit_cals(qobj, pulse_lib, parametric_pulses))
        if hasattr(exp.config, "calibrations"):
            circuit.calibrations = dict(
                **circuit.calibrations,
                **_qobj_to_circuit_cals(exp, pulse_lib, parametric_pulses))
        circuits.append(circuit)
    return circuits
Beispiel #21
0
def circuit_to_gate(circuit,
                    parameter_map=None,
                    equivalence_library=None,
                    label=None):
    """Build a ``Gate`` object from a ``QuantumCircuit``.

    The gate is anonymous (not tied to a named quantum register),
    and so can be inserted into another circuit. The gate will
    have the same string name as the circuit.

    Args:
        circuit (QuantumCircuit): the input circuit.
        parameter_map (dict): For parameterized circuits, a mapping from
           parameters in the circuit to parameters to be used in the gate.
           If None, existing circuit parameters will also parameterize the
           Gate.
        equivalence_library (EquivalenceLibrary): Optional equivalence library
           where the converted gate will be registered.
        label (str): Optional gate label.

    Raises:
        QiskitError: if circuit is non-unitary or if
            parameter_map is not compatible with circuit

    Return:
        Gate: a Gate equivalent to the action of the
        input circuit. Upon decomposition, this gate will
        yield the components comprising the original circuit.
    """
    # pylint: disable=cyclic-import
    from qiskit.circuit.quantumcircuit import QuantumCircuit
    if circuit.clbits:
        raise QiskitError('Circuit with classical bits cannot be converted '
                          'to gate.')

    for inst, _, _ in circuit.data:
        if not isinstance(inst, Gate):
            raise QiskitError(
                ('One or more instructions cannot be converted to'
                 ' a gate. "{}" is not a gate instruction').format(inst.name))

    if parameter_map is None:
        parameter_dict = {p: p for p in circuit.parameters}
    else:
        parameter_dict = circuit._unroll_param_dict(parameter_map)

    if parameter_dict.keys() != circuit.parameters:
        raise QiskitError(('parameter_map should map all circuit parameters. '
                           'Circuit parameters: {}, parameter_map: {}').format(
                               circuit.parameters, parameter_dict))

    gate = Gate(name=circuit.name,
                num_qubits=sum([qreg.size for qreg in circuit.qregs]),
                params=sorted(parameter_dict.values(), key=lambda p: p.name),
                label=label)
    gate.condition = None

    def find_bit_position(bit):
        """find the index of a given bit (Register, int) within
        a flat ordered list of bits of the circuit
        """
        if isinstance(bit, Qubit):
            ordered_regs = circuit.qregs
        else:
            ordered_regs = circuit.cregs
        reg_index = ordered_regs.index(bit.register)
        return sum([reg.size for reg in ordered_regs[:reg_index]]) + bit.index

    target = circuit.assign_parameters(parameter_dict, inplace=False)

    if equivalence_library is not None:
        equivalence_library.add_equivalence(gate, target)

    rules = target.data

    if gate.num_qubits > 0:
        q = QuantumRegister(gate.num_qubits, 'q')

    # The 3rd parameter in the output tuple) is hard coded to [] because
    # Gate objects do not have cregs set and we've verified that all
    # instructions are gates
    rules = list(
        map(
            lambda x:
            (x[0], list(map(lambda y: q[find_bit_position(y)], x[1])), []),
            rules))
    qc = QuantumCircuit(q, name=gate.name)
    qc.data = rules
    gate.definition = qc
    return gate
Beispiel #22
0
    def _convert_to_block(self, layer: Union[str, type, Gate, QuantumCircuit]) -> QuantumCircuit:
        """For a layer provided as str (e.g. 'ry') or type (e.g. RYGate) this function returns the
        according layer type along with the number of parameters (e.g. (RYGate, 1)).

        Args:
            layer: The qubit layer.

        Returns:
            The specified layer with the required number of parameters.

        Raises:
            TypeError: The type of `layer` is invalid.
            ValueError: The type of `layer` is str but the name is unknown.
            ValueError: The type of `layer` is type but the layer type is unknown.

        Note:
            Outlook: If layers knew their number of parameters as static property, we could also
            allow custom layer types.
        """
        if isinstance(layer, QuantumCircuit):
            return layer

        # check the list of valid layers
        # this could be a lot easier if the standard layers would have `name` and `num_params`
        # as static types, which might be something they should have anyways
        theta = Parameter("θ")
        valid_layers = {
            "ch": CHGate(),
            "cx": CXGate(),
            "cy": CYGate(),
            "cz": CZGate(),
            "crx": CRXGate(theta),
            "cry": CRYGate(theta),
            "crz": CRZGate(theta),
            "h": HGate(),
            "i": IGate(),
            "id": IGate(),
            "iden": IGate(),
            "rx": RXGate(theta),
            "rxx": RXXGate(theta),
            "ry": RYGate(theta),
            "ryy": RYYGate(theta),
            "rz": RZGate(theta),
            "rzx": RZXGate(theta),
            "rzz": RZZGate(theta),
            "s": SGate(),
            "sdg": SdgGate(),
            "swap": SwapGate(),
            "x": XGate(),
            "y": YGate(),
            "z": ZGate(),
            "t": TGate(),
            "tdg": TdgGate(),
        }

        # try to exchange `layer` from a string to a gate instance
        if isinstance(layer, str):
            try:
                layer = valid_layers[layer]
            except KeyError as ex:
                raise ValueError(f"Unknown layer name `{layer}`.") from ex

        # try to exchange `layer` from a type to a gate instance
        if isinstance(layer, type):
            # iterate over the layer types and look for the specified layer
            instance = None
            for gate in valid_layers.values():
                if isinstance(gate, layer):
                    instance = gate
            if instance is None:
                raise ValueError(f"Unknown layer type`{layer}`.")
            layer = instance

        if isinstance(layer, Instruction):
            circuit = QuantumCircuit(layer.num_qubits)
            circuit.append(layer, list(range(layer.num_qubits)))
            return circuit

        raise TypeError(
            f"Invalid input type {type(layer)}. " + "`layer` must be a type, str or QuantumCircuit."
        )
Beispiel #23
0
    def __call__(self, target, basis_fidelity=None):
        """Decompose a two-qubit unitary over fixed basis + SU(2) using the best approximation given
        that each basis application has a finite fidelity.
        """
        basis_fidelity = basis_fidelity or self.basis_fidelity
        if hasattr(target, 'to_operator'):
            # If input is a BaseOperator subclass this attempts to convert
            # the object to an Operator so that we can extract the underlying
            # numpy matrix from `Operator.data`.
            target = target.to_operator().data
        if hasattr(target, 'to_matrix'):
            # If input is Gate subclass or some other class object that has
            # a to_matrix method this will call that method.
            target = target.to_matrix()
        # Convert to numpy array incase not already an array
        target = np.asarray(target, dtype=complex)
        # Check input is a 2-qubit unitary
        if target.shape != (4, 4):
            raise QiskitError("TwoQubitBasisDecomposer: expected 4x4 matrix for target")
        if not is_unitary_matrix(target):
            raise QiskitError("TwoQubitBasisDecomposer: target matrix is not unitary.")

        target_decomposed = TwoQubitWeylDecomposition(target)
        traces = self.traces(target_decomposed)
        expected_fidelities = [trace_to_fid(traces[i]) * basis_fidelity**i for i in range(4)]

        best_nbasis = np.argmax(expected_fidelities)
        decomposition = self.decomposition_fns[best_nbasis](target_decomposed)
        decomposition_euler = [self._decomposer1q(x) for x in decomposition]

        q = QuantumRegister(2)
        return_circuit = QuantumCircuit(q)
        for i in range(best_nbasis):
            return_circuit.compose(decomposition_euler[2*i], [q[0]], inplace=True)
            return_circuit.compose(decomposition_euler[2*i+1], [q[1]], inplace=True)
            return_circuit.append(self.gate, [q[0], q[1]])
        return_circuit.compose(decomposition_euler[2*best_nbasis], [q[0]], inplace=True)
        return_circuit.compose(decomposition_euler[2*best_nbasis+1], [q[1]], inplace=True)

        return return_circuit
    def run(self, dag):
        """Run the ConsolidateBlocks pass on `dag`.

        Iterate over each block and replace it with an equivalent Unitary
        on the same wires.
        """
        if self.decomposer is None:
            return dag

        # compute ordered indices for the global circuit wires
        global_index_map = {wire: idx for idx, wire in enumerate(dag.qubits)}
        blocks = self.property_set["block_list"]
        basis_gate_name = self.decomposer.gate.name
        all_block_gates = set()
        for block in blocks:
            if len(block) == 1 and (self.basis_gates and block[0].name not in self.basis_gates):
                all_block_gates.add(block[0])
                dag.substitute_node(block[0], UnitaryGate(block[0].op.to_matrix()))
            else:
                basis_count = 0
                outside_basis = False
                block_qargs = set()
                block_cargs = set()
                for nd in block:
                    block_qargs |= set(nd.qargs)
                    if isinstance(nd, DAGOpNode) and nd.op.condition:
                        block_cargs |= set(nd.op.condition[0])
                    all_block_gates.add(nd)
                q = QuantumRegister(len(block_qargs))
                qc = QuantumCircuit(q)
                if block_cargs:
                    c = ClassicalRegister(len(block_cargs))
                    qc.add_register(c)
                block_index_map = self._block_qargs_to_indices(block_qargs, global_index_map)
                for nd in block:
                    if nd.op.name == basis_gate_name:
                        basis_count += 1
                    if self.basis_gates and nd.op.name not in self.basis_gates:
                        outside_basis = True
                    qc.append(nd.op, [q[block_index_map[i]] for i in nd.qargs])
                unitary = UnitaryGate(Operator(qc))

                max_2q_depth = 20  # If depth > 20, there will be 1q gates to consolidate.
                if (  # pylint: disable=too-many-boolean-expressions
                    self.force_consolidate
                    or unitary.num_qubits > 2
                    or self.decomposer.num_basis_gates(unitary) < basis_count
                    or len(block) > max_2q_depth
                    or (self.basis_gates is not None and outside_basis)
                ):
                    dag.replace_block_with_op(block, unitary, block_index_map, cycle_check=False)
        # If 1q runs are collected before consolidate those too
        runs = self.property_set["run_list"] or []
        for run in runs:
            if run[0] in all_block_gates:
                continue
            if len(run) == 1 and self.basis_gates and run[0].name not in self.basis_gates:
                dag.substitute_node(run[0], UnitaryGate(run[0].op.to_matrix()))
            else:
                qubit = run[0].qargs[0]
                operator = run[0].op.to_matrix()
                already_in_block = False
                for gate in run[1:]:
                    if gate in all_block_gates:
                        already_in_block = True
                    operator = gate.op.to_matrix().dot(operator)
                if already_in_block:
                    continue
                unitary = UnitaryGate(operator)
                dag.replace_block_with_op(run, unitary, {qubit: 0}, cycle_check=False)
        return dag
Beispiel #25
0
def _experiments_to_circuits(qobj):
    """Return a list of QuantumCircuit object(s) from a qobj.

    Args:
        qobj (Qobj): The Qobj object to convert to QuantumCircuits

    Returns:
        list: A list of QuantumCircuit objects from the qobj
    """
    if not qobj.experiments:
        return None

    circuits = []
    for exp in qobj.experiments:
        quantum_registers = [
            QuantumRegister(i[1], name=i[0]) for i in exp.header.qreg_sizes
        ]
        classical_registers = [
            ClassicalRegister(i[1], name=i[0]) for i in exp.header.creg_sizes
        ]
        circuit = QuantumCircuit(*quantum_registers,
                                 *classical_registers,
                                 name=exp.header.name)
        qreg_dict = collections.OrderedDict()
        creg_dict = collections.OrderedDict()
        for reg in quantum_registers:
            qreg_dict[reg.name] = reg
        for reg in classical_registers:
            creg_dict[reg.name] = reg
        conditional = {}
        for i in exp.instructions:
            name = i.name
            qubits = []
            params = getattr(i, "params", [])
            try:
                for qubit in i.qubits:
                    qubit_label = exp.header.qubit_labels[qubit]
                    qubits.append(qreg_dict[qubit_label[0]][qubit_label[1]])
            except Exception:  # pylint: disable=broad-except
                pass
            clbits = []
            try:
                for clbit in i.memory:
                    clbit_label = exp.header.clbit_labels[clbit]
                    clbits.append(creg_dict[clbit_label[0]][clbit_label[1]])
            except Exception:  # pylint: disable=broad-except
                pass
            if hasattr(circuit, name):
                instr_method = getattr(circuit, name)
                if i.name in ["snapshot"]:
                    _inst = instr_method(i.label,
                                         snapshot_type=i.snapshot_type,
                                         qubits=qubits,
                                         params=params)
                elif i.name == "initialize":
                    _inst = instr_method(params, qubits)
                elif i.name == "isometry":
                    _inst = instr_method(*params, qubits, clbits)
                elif i.name in ["mcx", "mcu1", "mcp"]:
                    _inst = instr_method(*params, qubits[:-1], qubits[-1],
                                         *clbits)
                else:
                    _inst = instr_method(*params, *qubits, *clbits)
            elif name == "bfunc":
                conditional["value"] = int(i.val, 16)
                full_bit_size = sum([creg_dict[x].size for x in creg_dict])
                mask_map = {}
                raw_map = {}
                raw = []

                for creg in creg_dict:
                    size = creg_dict[creg].size
                    reg_raw = [1] * size
                    if not raw:
                        raw = reg_raw
                    else:
                        for pos, val in enumerate(raw):
                            if val == 1:
                                raw[pos] = 0
                        raw = reg_raw + raw
                    mask = [0] * (full_bit_size - len(raw)) + raw
                    raw_map[creg] = mask
                    mask_map[int("".join(str(x) for x in mask), 2)] = creg
                creg = mask_map[int(i.mask, 16)]
                conditional["register"] = creg_dict[creg]
                val = int(i.val, 16)
                mask = raw_map[creg]
                for j in reversed(mask):
                    if j == 0:
                        val = val >> 1
                    else:
                        conditional["value"] = val
                        break
            else:
                _inst = temp_opaque_instruction = Instruction(
                    name=name,
                    num_qubits=len(qubits),
                    num_clbits=len(clbits),
                    params=params)
                circuit.append(temp_opaque_instruction, qubits, clbits)
            if conditional and name != "bfunc":
                _inst.c_if(conditional["register"], conditional["value"])
                conditional = {}
        circuits.append(circuit)
    return circuits
    def __init__(self, adjacency_matrix: Union[List[List[int]], np.ndarray]) -> None:
        """Create new HLF circuit.

        Args:
            adjacency_matrix: a symmetric n-by-n list of 0-1 lists.
                n will be the number of qubits.

        Raises:
            CircuitError: If A is not symmetric.
        """
        adjacency_matrix = np.asarray(adjacency_matrix)
        if not np.allclose(adjacency_matrix, adjacency_matrix.transpose()):
            raise CircuitError("The adjacency matrix must be symmetric.")

        num_qubits = len(adjacency_matrix)
        circuit = QuantumCircuit(num_qubits, name="hlf: %s" % adjacency_matrix)

        circuit.h(range(num_qubits))
        for i in range(num_qubits):
            for j in range(i + 1, num_qubits):
                if adjacency_matrix[i][j]:
                    circuit.cz(i, j)
        for i in range(num_qubits):
            if adjacency_matrix[i][i]:
                circuit.s(i)
        circuit.h(range(num_qubits))

        super().__init__(*circuit.qregs, name=circuit.name)
        self.compose(circuit.to_gate(), qubits=self.qubits, inplace=True)
Beispiel #27
0
 def _define(self):
     from qiskit.circuit.quantumcircuit import QuantumCircuit
     q = QuantumRegister(1, 'q')
     qc = QuantumCircuit(q, name=self.name)
     qc.u(self.params[0], self.params[1], self.params[2], 0)
     self.definition = qc
 def _circuit_u3(theta, phi, lam, simplify=True, atol=DEFAULT_ATOL):
     # pylint: disable=unused-argument
     circuit = QuantumCircuit(1)
     circuit.append(U3Gate(theta, phi, lam), [0])
     return circuit
    def _define(self):
        """
        gate c3x a,b,c,d
        {
            h d;
            p(pi/8) a;
            p(pi/8) b;
            p(pi/8) c;
            p(pi/8) d;
            cx a, b;
            p(-pi/8) b;
            cx a, b;
            cx b, c;
            p(-pi/8) c;
            cx a, c;
            p(pi/8) c;
            cx b, c;
            p(-pi/8) c;
            cx a, c;
            cx c, d;
            p(-pi/8) d;
            cx b, d;
            p(pi/8) d;
            cx c, d;
            p(-pi/8) d;
            cx a, d;
            p(pi/8) d;
            cx c, d;
            p(-pi/8) d;
            cx b, d;
            p(pi/8) d;
            cx c, d;
            p(-pi/8) d;
            cx a, d;
            h d;
        }
        """
        from qiskit.circuit.quantumcircuit import QuantumCircuit
        q = QuantumRegister(4, name='q')
        qc = QuantumCircuit(q, name=self.name)
        qc.h(3)
        qc.p(pi / 8, [0, 1, 2, 3])
        qc.cx(0, 1)
        qc.p(-pi / 8, 1)
        qc.cx(0, 1)
        qc.cx(1, 2)
        qc.p(-pi / 8, 2)
        qc.cx(0, 2)
        qc.p(pi / 8, 2)
        qc.cx(1, 2)
        qc.p(-pi / 8, 2)
        qc.cx(0, 2)
        qc.cx(2, 3)
        qc.p(-pi / 8, 3)
        qc.cx(1, 3)
        qc.p(pi / 8, 3)
        qc.cx(2, 3)
        qc.p(-pi / 8, 3)
        qc.cx(0, 3)
        qc.p(pi / 8, 3)
        qc.cx(2, 3)
        qc.p(-pi / 8, 3)
        qc.cx(1, 3)
        qc.p(pi / 8, 3)
        qc.cx(2, 3)
        qc.p(-pi / 8, 3)
        qc.cx(0, 3)
        qc.h(3)

        self.definition = qc
 def _circuit_u(theta, phi, lam, phase, simplify=True, atol=DEFAULT_ATOL):
     # pylint: disable=unused-argument
     circuit = QuantumCircuit(1, global_phase=phase)
     circuit.u(theta, phi, lam, 0)
     return circuit