示例#1
0
def get_Zf(f, n):
    """
    This function generates the Zf gate satisfying the condition for x in {0,1}^n where Zf|x> -> (-1)^f(X)|x>
    This function requires that f(x) be calculated for all x, so f is passed as an anonymous function, the other
        parameter is n.
    The function has one dependency, the DefGate function defined in pyquil.quil
    This function finds all permutations of bitstrings of length n, then initializes a 2^n x 2^n matrix of all 0's,
        and sets all elements along the diagonal to either 1 or -1 depending on f(x)
    Finally a gate representation of this matrix is returned.
    """
    # generate bitstring permutations
    bitstrings = list()
    get_bitstring_permutations(0, bitstrings, n, [0] * n)
    # initialize a 2^n x 2^n matrix of all 0's
    gate = np.zeros((2 ** n, 2 ** n), dtype=int)
    # set diagonals of matrix based on f(x)
    for i in range(2 ** n):
        gate[i][i] = -1 if f(bitstrings[i]) == 1 else 1
    # create and return gate
    return Operator(gate)
    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(force_consolidate=True)
        pass_.property_set['block_list'] = [list(dag.topological_op_nodes())]
        new_dag = pass_.run(dag)

        sim = UnitarySimulatorPy()
        result = execute(qc, sim).result()
        unitary = UnitaryGate(result.get_unitary())
        self.assertEqual(len(new_dag.op_nodes()), 1)
        fidelity = process_fidelity(Operator(new_dag.op_nodes()[0].op), unitary.to_matrix())
        self.assertAlmostEqual(fidelity, 1.0, places=7)
    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(force_consolidate=True)
        pass_.property_set['block_list'] = [list(dag.topological_op_nodes())]
        new_dag = pass_.run(dag)

        sim = UnitarySimulatorPy()
        result = execute(qc, sim).result()
        unitary = UnitaryGate(result.get_unitary())
        self.assertEqual(len(new_dag.op_nodes()), 1)
        fidelity = process_fidelity(Operator(new_dag.op_nodes()[0].op), unitary.to_matrix())
        self.assertAlmostEqual(fidelity, 1.0, places=7)
示例#4
0
def random_unitary(dim, seed=None):
    """
    Return a random dim x dim unitary Operator from the Haar measure.

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

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

    Raises:
        QiskitError: if dim is not a positive power of 2.
    """
    if seed is not None:
        np.random.seed(seed)
    if dim == 0 or not math.log2(dim).is_integer():
        raise QiskitError(
            "Desired unitary dimension not a positive power of 2.")
    return Operator(unitary_group.rvs(dim))
示例#5
0
 def check_two_qubit_weyl_decomposition(self,
                                        target_unitary,
                                        tolerance=1.e-7):
     """Check TwoQubitWeylDecomposition() works for a given operator"""
     # pylint: disable=invalid-name
     decomp = TwoQubitWeylDecomposition(target_unitary)
     op = np.exp(1j * decomp.global_phase) * Operator(np.eye(4))
     for u, qs in (
         (decomp.K2r, [0]),
         (decomp.K2l, [1]),
         (Ud(decomp.a, decomp.b, decomp.c), [0, 1]),
         (decomp.K1r, [0]),
         (decomp.K1l, [1]),
     ):
         op = op.compose(u, qs)
     decomp_unitary = op.data
     maxdist = np.max(np.abs(target_unitary - decomp_unitary))
     self.assertTrue(
         np.abs(maxdist) < tolerance,
         "Unitary {}: Worst distance {}".format(target_unitary, maxdist))
示例#6
0
 def _compose_instr(instr0, instr1, num_qubits):
     """Helper function for compose a kraus with another instruction."""
     # If one of the instructions is an identity we only need
     # to return the other instruction
     if instr0['name'] == 'id':
         return instr1
     if instr1['name'] == 'id':
         return instr0
     # Convert to ops
     op0 = QuantumError._instr2op(instr0)
     op1 = QuantumError._instr2op(instr1)
     # Check if at least one of the instructions is a channel
     # and if so convert both to SuperOp representation
     if isinstance(op0,
                   (SuperOp, Kraus)) or isinstance(op1, (SuperOp, Kraus)):
         name = 'kraus'
         op0 = SuperOp(op0)
         op1 = SuperOp(op1)
     else:
         name = 'unitary'
     # Check qubits for compositions
     qubits0 = instr0['qubits']
     qubits1 = instr1['qubits']
     if qubits0 == qubits1:
         composed = op0.compose(op1)
         qubits = qubits0
     else:
         # If qubits don't match we compose with total number of qubits
         # for the error
         if name == 'kraus':
             composed = SuperOp(np.eye(4 ** num_qubits))
         else:
             composed = Operator(np.eye(2 ** num_qubits))
         composed.compose(op0, qargs=qubits0).compose(op1, qargs=qubits1)
         qubits = list(range(num_qubits))
     # Get instruction params
     if name == 'kraus':
         params = Kraus(composed).data
     else:
         params = [composed.data]
     return {'name': name, 'qubits': qubits, 'params': params}
示例#7
0
def bv_program(U_f, n, draw_circuit=False):
    circuit = QuantumCircuit(n + 1, n)

    # invert the helper qubit to make it 1
    circuit.x(n)

    # apply Hadamard to all input qubits and helper qubit
    for i in range(n + 1):
        circuit.h(i)

    # define the U_f gate based on the unitary matrix returned by get_U_f
    U_f_gate = Operator(U_f)
    circuit.unitary(U_f_gate, range(n, -1, -1), label='U_f')

    # apply Hadamard to all input qubits
    for i in range(n):
        circuit.h(i)

    if draw_circuit:
        print(circuit_drawer(circuit, output='text'))
    return circuit
示例#8
0
def C4HGate(numerator = 1, divisor = 1):
    h1 = compute_first_operand(numerator, divisor)
    h2 = compute_second_operand(numerator, divisor)
    return Operator([
        [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
        [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
        [0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
        [0, 0, 0, h1, 0, 0, 0, 0, 0, 0, 0, h2, 0, 0, 0, 0],
        [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0],
        [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0],
        [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0],
        [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
        [0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0],
        [0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0],
        [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0],
        [0, 0, 0, h2, 0, 0, 0, 0, 0, 0, 0, -h1, 0, 0, 0, 0],
        [0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
        [0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
        [0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0],
        [0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0],
    ])
示例#9
0
 def check_exact_decomposition(self,
                               target_unitary,
                               decomposer,
                               tolerance=1.e-7):
     """Check exact decomposition for a particular target"""
     with self.subTest(unitary=target_unitary, decomposer=decomposer):
         decomp_circuit = decomposer(target_unitary)
         result = execute(decomp_circuit, UnitarySimulatorPy()).result()
         decomp_unitary = Operator(result.get_unitary())
         result = execute(decomp_circuit, UnitarySimulatorPy()).result()
         decomp_unitary = result.get_unitary()
         target_unitary *= la.det(target_unitary)**(-0.25)
         decomp_unitary *= la.det(decomp_unitary)**(-0.25)
         maxdists = [
             np.max(np.abs(target_unitary + phase * decomp_unitary))
             for phase in [1, 1j, -1, -1j]
         ]
         maxdist = np.min(maxdists)
         self.assertTrue(
             np.abs(maxdist) < tolerance,
             "Worst distance {}".format(maxdist))
示例#10
0
    def test_cx_equivalence_1cx(self, seed=1):
        """Check circuits with  1 cx gates locally equivalent to a cx
        """
        state = np.random.default_rng(seed)
        rnd = 2 * np.pi * state.random(size=12)

        qr = QuantumRegister(2, name='q')
        qc = QuantumCircuit(qr)

        qc.u(rnd[0], rnd[1], rnd[2], qr[0])
        qc.u(rnd[3], rnd[4], rnd[5], qr[1])

        qc.cx(qr[1], qr[0])

        qc.u(rnd[6], rnd[7], rnd[8], qr[0])
        qc.u(rnd[9], rnd[10], rnd[11], qr[1])

        sim = UnitarySimulatorPy()
        unitary = execute(qc, sim).result().get_unitary()
        self.assertEqual(two_qubit_cnot_decompose.num_basis_gates(unitary), 1)
        self.assertTrue(Operator(two_qubit_cnot_decompose(unitary)).equiv(unitary))
示例#11
0
def represent_full_cost_function(params, U, gate):
    '''
    Cost function for variationally finding the environment of an iMPS with a quantum circuit. Requires full tomography of the reduced density matrices that are being evaluated.
    '''
    simulator = Aer.get_backend('statevector_simulator')
    target_environment = Operator(gate(params))

    circ_ρσ = QuantumCircuit(5)

    circ_ρσ.append(target_environment, [2, 1])
    circ_ρσ.append(U, [1, 0])
    circ_ρσ.append(target_environment, [4, 3])

    result = execute(circ_ρσ, simulator).result()
    statevector = result.get_statevector(circ_ρσ)
    ρ = np.outer(statevector, statevector.conj())

    ρ_1 = partial_trace(ρ, 5, [0])
    ρ_2 = partial_trace(ρ, 5, [3])

    return np.linalg.norm(ρ_1 - ρ_2)
示例#12
0
def qc_program(n, t, reload, verbose):
    trials = (n - 1) * (4 * t)

    u_f, s = getUf(n, reload)

    U_f = Operator(u_f)
    simulator = Aer.get_backend('qasm_simulator')
    circuit = QuantumCircuit(2 * n, n)

    circuit.h(range(n))
    circuit.append(U_f, range(2 * n)[::-1])
    circuit.h(range(n))

    circuit.measure(range(n), range(n))

    print(circuit)

    for i in range(4 * t):
        job = execute(circuit, simulator, shots=(n - 1))
        results = job.result().get_counts(circuit)
        if len(results.keys()) != n - 1:
            continue
        if verbose:
            print(f'    Trial {i+1}:')

        potential_ys = []
        for index, y in enumerate(results.keys()):
            potential_ys.append(y)
            if verbose:
                print(f'        y_{index} = {y}')
        if is_lin_indep(potential_ys):
            if verbose:
                print(
                    f'Found linearly independent ys!\nChecking if they solve to s correctly...'
                )
                print('====================================\n')
            return check_validity(potential_ys, s)
    if verbose:
        print('====================================\n')
    return None
示例#13
0
def get_Sx(ang=None, x=None, pad=True, circuit=False):
    backend = Aer.get_backend('unitary_simulator')

    if pad==True:
        q = QuantumRegister(2)
        qc = QuantumCircuit(q)
        qc = state_preparation(ang, qc, [0, 1])
    elif pad==False:
        x = x.astype(complex)
        q = QuantumRegister(1)
        qc = QuantumCircuit(q)
        qc.initialize(x, [0])

    job = execute(qc, backend)
    result = job.result()
    U = result.get_unitary(qc)
    S = Operator(U)
    
    if circuit==True:
        return qc
    else: 
        return S
示例#14
0
def distance(circuit, c_bit, a, b):
    """
    Calculate distances between 2 data points denoted as quantum states.

    Based on DistCalc from  Quantum Machine Learning for data scientists.

    !!! Not possible to run with current version of IBM Q API.
    :param circuit: IBM Q circuit object
    """
    # controlled swap operator 6x6
    cswap = Operator([[1, 0, 0, 0, 0, 0], [0, 1, 0, 0, 0,
                                           0], [0, 0, 0, 0, 1, 0],
                      [0, 0, 0, 0, 0, 1], [0, 0, 1, 0, 0, 0],
                      [0, 0, 0, 1, 0, 0]])

    # |s0> = |0, a, b>
    # 0 - control bit
    # a, b - to find dist between

    circuit.h(c_bit)
    circuit.append(cswap, [c_bit, a, b])
    circuit.h(c_bit)
示例#15
0
    def __call__(self, unitary_mat, simplify=True, atol=DEFAULT_ATOL):
        """Decompose single qubit gate into a circuit.

        Args:
            unitary_mat (array_like): 1-qubit unitary matrix
            simplify (bool): remove zero-angle rotations [Default: True]
            atol (float): absolute tolerance for checking angles zero.

        Returns:
            QuantumCircuit: the decomposed single-qubit gate circuit

        Raises:
            QiskitError: if input is invalid or synthesis fails.
        """
        if hasattr(unitary_mat, '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_mat = unitary_mat.to_operator().data
        if hasattr(unitary_mat, 'to_matrix'):
            # If input is Gate subclass or some other class object that has
            # a to_matrix method this will call that method.
            unitary_mat = unitary_mat.to_matrix()
        # Convert to numpy array incase not already an array
        unitary_mat = np.asarray(unitary_mat, dtype=complex)

        # Check input is a 2-qubit unitary
        if unitary_mat.shape != (2, 2):
            raise QiskitError("OneQubitEulerDecomposer: "
                              "expected 2x2 input matrix")
        if not is_unitary_matrix(unitary_mat):
            raise QiskitError("OneQubitEulerDecomposer: "
                              "input matrix is not unitary.")
        circuit = self._circuit(unitary_mat, simplify=simplify, atol=atol)
        # Check circuit is correct
        if not Operator(circuit).equiv(unitary_mat):
            raise QiskitError("OneQubitEulerDecomposer: "
                              "synthesis failed within required accuracy.")
        return circuit
示例#16
0
 def check_one_qubit_euler_angles(self,
                                  operator,
                                  basis='U3',
                                  tolerance=1e-12,
                                  phase_equal=False):
     """Check OneQubitEulerDecomposer works for the given unitary"""
     target_unitary = operator.data
     if basis is None:
         angles = OneQubitEulerDecomposer().angles(target_unitary)
         decomp_unitary = U3Gate(*angles).to_matrix()
     else:
         decomposer = OneQubitEulerDecomposer(basis)
         decomp_unitary = Operator(decomposer(target_unitary)).data
     # Add global phase to make special unitary
     target_unitary *= la.det(target_unitary)**(-0.5)
     decomp_unitary *= la.det(decomp_unitary)**(-0.5)
     maxdist = np.max(np.abs(target_unitary - decomp_unitary))
     if not phase_equal and maxdist > 0.1:
         maxdist = np.max(np.abs(target_unitary + decomp_unitary))
     self.assertTrue(
         np.abs(maxdist) < tolerance,
         "Operator {}: Worst distance {}".format(operator, maxdist))
示例#17
0
    def test_two_qubit_operations_supported_by_pennylane(self, recorder):
        """Tests loading a circuit with the two-qubit operations supported by PennyLane."""

        two_wires = [0, 1]

        qc = QuantumCircuit(2, 1)

        unitary_op = [[1, 0, 0, 0], [0, 0, 1j, 0], [0, 1j, 0, 0], [0, 0, 0, 1]]
        iswap_op = Operator(unitary_op)

        qc.cx(*two_wires)
        qc.cz(*two_wires)
        qc.swap(*two_wires)
        qc.unitary(iswap_op, [0, 1], label='iswap')

        quantum_circuit = load(qc)
        with recorder:
            quantum_circuit()

        assert len(recorder.queue) == 4

        assert recorder.queue[0].name == 'CNOT'
        assert recorder.queue[0].params == []
        assert recorder.queue[0].wires == two_wires

        assert recorder.queue[1].name == 'CZ'
        assert recorder.queue[1].params == []
        assert recorder.queue[1].wires == two_wires

        assert recorder.queue[2].name == 'SWAP'
        assert recorder.queue[2].params == []
        assert recorder.queue[2].wires == two_wires

        assert recorder.queue[3].name == 'QubitUnitary'
        assert len(recorder.queue[3].params) == 1
        assert np.array_equal(recorder.queue[3].params[0],
                              np.array(unitary_op))
        assert recorder.queue[3].wires == two_wires
示例#18
0
def linear_operator(param, pad=True, circuit = False):
    backend = Aer.get_backend('unitary_simulator')
    '''pad variable influences the size of params vector'''
    if pad==True:
        data = QuantumRegister(2)
        qc = QuantumCircuit(data)
        qc.u3(param[0], param[1], param[2], data[0])
        qc.u3(param[3], param[4], param[5], data[1])
        qc.cx(data[0], data[1])
    elif pad==False:
        data = QuantumRegister(1)
        qc = QuantumCircuit(data)
        qc.u3(param[0], param[1], param[2], data)
    
    job = execute(qc, backend)
    result = job.result()
    
    if circuit==True:
        return qc
    else: 
        U = result.get_unitary(qc)
        G = Operator(U)
        return G
示例#19
0
def random_unitary(dims, seed=None):
    """Return a random unitary Operator.

    The operator is sampled from the unitary Haar measure.

    Args:
        dims (int or tuple): the input dimensions of the Operator.
        seed (int or np.random.Generator): Optional. Set a fixed seed or
                                           generator for RNG.

    Returns:
        Operator: a unitary operator.
    """
    if seed is None:
        random_state = np.random.default_rng()
    elif isinstance(seed, np.random.Generator):
        random_state = seed
    else:
        random_state = default_rng(seed)

    dim = np.product(dims)
    mat = stats.unitary_group.rvs(dim, random_state=random_state)
    return Operator(mat, input_dims=dims, output_dims=dims)
示例#20
0
def sigma(pad=True, circuit = False):
    
    backend = Aer.get_backend('unitary_simulator')
    
    if pad==True:
        data = QuantumRegister(2)
        qc = QuantumCircuit(data)
        qc.id(data)
    if pad==False:
        data = QuantumRegister(1)
        qc = QuantumCircuit(data)
        qc.id(data)

    job = execute(qc, backend)
    result = job.result()
    
    U = result.get_unitary(qc)
    I = Operator(U)

    if circuit==True:
        return qc
    else: 
        return I
示例#21
0
    def test_overlapping_block_and_run(self):
        """Test that an overlapping block and run only consolidate once"""
        qc = QuantumCircuit(2)
        qc.h(0)
        qc.t(0)
        qc.sdg(0)
        qc.cx(0, 1)
        qc.t(1)
        qc.sdg(1)
        qc.z(1)
        qc.i(1)

        pass_manager = PassManager()
        pass_manager.append(Collect2qBlocks())
        pass_manager.append(Collect1qRuns())
        pass_manager.append(ConsolidateBlocks(force_consolidate=True))
        result = pass_manager.run(qc)
        expected = Operator(qc)
        # Assert output circuit is a single unitary gate equivalent to
        # unitary of original circuit
        self.assertEqual(len(result), 1)
        self.assertIsInstance(result.data[0][0], UnitaryGate)
        self.assertTrue(np.allclose(result.data[0][0].to_matrix(), expected))
示例#22
0
def generate_circuit(n, t, reload, verbose):
    SAVEDIR = 'plots/'
    CIRCUIT_FILENAME = f'simon_{n}.pdf'
    trials = (n - 1) * (4 * t)

    u_f, s = getUf(n, reload)
    U_f = Operator(u_f)

    circuit = QuantumCircuit(2 * n, n)

    circuit.h(range(n))
    # circuit.append(U_f, range(2*n)[::-1])
    circuit.barrier()
    # for i in range(n):
    #     for j in range(n):
    #         circuit.cx(i, n+j)
    for i in range(n):
        if s[i] == '1':
            for j in range(n):
                circuit.cx(n - 1 - i, n + j)
    circuit.barrier()
    circuit.h(range(n))
    circuit.barrier()

    circuit.measure(range(0, n), range(n))
    #circuit.measure(range(n, 2*n), range(n))

    if v:
        circuit.draw('mpl')
        print(f'Saving circuit to {CIRCUIT_FILENAME} .. ', end='', flush=True)
        if not os.path.exists(SAVEDIR):
            os.mkdir(SAVEDIR)

        matplotlib.pyplot.savefig(f'{SAVEDIR}{CIRCUIT_FILENAME}')
        print('done\n', flush=True)

    return circuit, s
    def _logarithmic_encoding(
        self, spin: Union[Fraction, int]
    ) -> Tuple[PauliSumOp, PauliSumOp, PauliSumOp, PauliSumOp]:
        """The logarithmic encoding.

        Args:
            spin: Positive half-integer (integer or half-odd-integer) that represents spin.

        Returns:
            A tuple containing four PauliSumOp.
        """
        spin_op_encoding: List[PauliSumOp] = []
        dspin = int(2 * spin + 1)
        num_qubits = int(np.ceil(np.log2(dspin)))

        # Get the spin matrices
        spin_matrices = [
            SpinOp(symbol, spin=spin).to_matrix() for symbol in "XYZ"
        ]
        # Append the identity
        spin_matrices.append(np.eye(dspin))

        # Embed the spin matrices in a larger matrix of size 2**num_qubits x 2**num_qubits
        embedded_spin_matrices = [
            self._embed_matrix(matrix, num_qubits) for matrix in spin_matrices
        ]

        # Generate operators from these embedded spin matrices
        embedded_operators = [
            Operator(matrix) for matrix in embedded_spin_matrices
        ]
        for op in embedded_operators:
            op = SparsePauliOp.from_operator(op)
            op.chop()
            spin_op_encoding.append(PauliSumOp(1.0 * op))

        return tuple(spin_op_encoding)  # type: ignore
示例#24
0
    def __build_circuit(self):
        self.__produce_u_f_gate()

        circuit = QuantumCircuit(self.n + 1, self.n)

        circuit.x(0)

        for i in range(self.n + 1):
            circuit.h(i)

        if self.__check_identity() == False:
            circuit.unitary(Operator(self.__Uf),
                            [i for i in range(self.n + 1)],
                            label='Uf')

        for i in range(1, self.n + 1):
            circuit.h(i)

        circuit.measure([i for i in range(self.n, 0, -1)],
                        [i for i in range(self.n)])

        #print(circuit.draw())

        self.__circuit = circuit
示例#25
0
def parityCircuit(theta1=0, theta2=0):

    # Noise rotation matrix.
    n1 = rotationMatrix(theta1)
    n2 = rotationMatrix(theta2)
    n = np.kron(n1, n2)



    # Noise operator
    id_op = Operator(n)

    truthtable = "10011001"
    oracle = TruthTableOracle(truthtable)
    or_cx = oracle.construct_circuit()
    # print(oracle.output_register)
    v = oracle.variable_register
    o = oracle.output_register

    cr1 = ClassicalRegister(3)
    cr2 = ClassicalRegister(1)

    cx_circ = QuantumCircuit(v, cr2)

    or_cx.add_register(cr1)
    cx_circ.h(v[1])
    cx_circ.cx(v[1], v[0])

    cx_circ.unitary(id_op, v[1:3], label='idop')


    total_cx = cx_circ + or_cx
    total_cx.measure(v, cr1)
    total_cx.measure(o, cr2)

    return total_cx
示例#26
0
    def __init__(self, gate, basis_fidelity=1.0, euler_basis=None):
        self.gate = gate
        self.basis_fidelity = basis_fidelity

        basis = self.basis = TwoQubitWeylDecomposition(Operator(gate).data)
        if euler_basis is not None:
            self._decomposer1q = OneQubitEulerDecomposer(euler_basis)
        else:
            self._decomposer1q = OneQubitEulerDecomposer("U3")

        # FIXME: find good tolerances
        self.is_supercontrolled = math.isclose(basis.a, np.pi / 4) and math.isclose(basis.c, 0.0)

        # Create some useful matrices U1, U2, U3 are equivalent to the basis,
        # expand as Ui = Ki1.Ubasis.Ki2
        b = basis.b
        K11l = (
            1
            / (1 + 1j)
            * np.array(
                [
                    [-1j * cmath.exp(-1j * b), cmath.exp(-1j * b)],
                    [-1j * cmath.exp(1j * b), -cmath.exp(1j * b)],
                ],
                dtype=complex,
            )
        )
        K11r = (
            1
            / math.sqrt(2)
            * np.array(
                [
                    [1j * cmath.exp(-1j * b), -cmath.exp(-1j * b)],
                    [cmath.exp(1j * b), -1j * cmath.exp(1j * b)],
                ],
                dtype=complex,
            )
        )
        K12l = 1 / (1 + 1j) * np.array([[1j, 1j], [-1, 1]], dtype=complex)
        K12r = 1 / math.sqrt(2) * np.array([[1j, 1], [-1, -1j]], dtype=complex)
        K32lK21l = (
            1
            / math.sqrt(2)
            * np.array(
                [
                    [1 + 1j * np.cos(2 * b), 1j * np.sin(2 * b)],
                    [1j * np.sin(2 * b), 1 - 1j * np.cos(2 * b)],
                ],
                dtype=complex,
            )
        )
        K21r = (
            1
            / (1 - 1j)
            * np.array(
                [
                    [-1j * cmath.exp(-2j * b), cmath.exp(-2j * b)],
                    [1j * cmath.exp(2j * b), cmath.exp(2j * b)],
                ],
                dtype=complex,
            )
        )
        K22l = 1 / math.sqrt(2) * np.array([[1, -1], [1, 1]], dtype=complex)
        K22r = np.array([[0, 1], [-1, 0]], dtype=complex)
        K31l = (
            1
            / math.sqrt(2)
            * np.array(
                [[cmath.exp(-1j * b), cmath.exp(-1j * b)], [-cmath.exp(1j * b), cmath.exp(1j * b)]],
                dtype=complex,
            )
        )
        K31r = 1j * np.array([[cmath.exp(1j * b), 0], [0, -cmath.exp(-1j * b)]], dtype=complex)
        K32r = (
            1
            / (1 - 1j)
            * np.array(
                [
                    [cmath.exp(1j * b), -cmath.exp(-1j * b)],
                    [-1j * cmath.exp(1j * b), -1j * cmath.exp(-1j * b)],
                ],
                dtype=complex,
            )
        )
        k1ld = basis.K1l.T.conj()
        k1rd = basis.K1r.T.conj()
        k2ld = basis.K2l.T.conj()
        k2rd = basis.K2r.T.conj()

        # Pre-build the fixed parts of the matrices used in 3-part decomposition
        self.u0l = K31l.dot(k1ld)
        self.u0r = K31r.dot(k1rd)
        self.u1l = k2ld.dot(K32lK21l).dot(k1ld)
        self.u1ra = k2rd.dot(K32r)
        self.u1rb = K21r.dot(k1rd)
        self.u2la = k2ld.dot(K22l)
        self.u2lb = K11l.dot(k1ld)
        self.u2ra = k2rd.dot(K22r)
        self.u2rb = K11r.dot(k1rd)
        self.u3l = k2ld.dot(K12l)
        self.u3r = k2rd.dot(K12r)

        # Pre-build the fixed parts of the matrices used in the 2-part decomposition
        self.q0l = K12l.T.conj().dot(k1ld)
        self.q0r = K12r.T.conj().dot(_ipz).dot(k1rd)
        self.q1la = k2ld.dot(K11l.T.conj())
        self.q1lb = K11l.dot(k1ld)
        self.q1ra = k2rd.dot(_ipz).dot(K11r.T.conj())
        self.q1rb = K11r.dot(k1rd)
        self.q2l = k2ld.dot(K12l)
        self.q2r = k2rd.dot(K12r)

        # Decomposition into different number of gates
        # In the future could use different decomposition functions for different basis classes, etc
        if not self.is_supercontrolled:
            warnings.warn(
                "Only know how to decompose properly for supercontrolled basis gate. "
                "This gate is ~Ud({}, {}, {})".format(basis.a, basis.b, basis.c),
                stacklevel=2,
            )
        self.decomposition_fns = [
            self.decomp0,
            self.decomp1,
            self.decomp2_supercontrolled,
            self.decomp3_supercontrolled,
        ]
示例#27
0
 def actual_fidelity(self, **kwargs) -> float:
     """Calculates the actual fidelity of the decomposed circuit to the input unitary"""
     circ = self.circuit(**kwargs)
     trace = np.trace(Operator(circ).data.T.conj() @ self.unitary_matrix)
     return trace_to_fid(trace)
示例#28
0
import numpy as np
from qiskit.quantum_info.operators import Operator
import qiskit

################################## 1. P_op ##################################
#
################################## QSL 5.17 #################################

# The unitary U∗P is a permutation of the unitary U∗ that permutes the first and third input,
# such that U∗P = P U∗P

# This can also be modeled by simply swapping the inputs of qubits 4 and 6 into the unitary U∗,
# and swapping them back afterwards.

P_op = Operator([[1, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 1, 0, 0, 0],
                 [0, 0, 1, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 1, 0],
                 [0, 1, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 1, 0, 0],
                 [0, 0, 0, 1, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 1]])

################################## 2. G_op ##################################
#
################################## QSL 5.18 ################################

# Deterministic Teleportation Protocol

G_op = Operator([[0, 0, 0, -1], [0, 1, 0, 0], [0, 0, 1, 0], [-1, 0, 0, 0]])

################################### 3. Us_op ##################################
#
################################## QSL 5.25 ###################################

# The scrambling unitary Us
示例#29
0
def _commute(node1, node2):
    """Function to verify commutation relation between two nodes in the DAG

    Args:
        node1 (DAGnode): first node operation (attribute ['operation'] in the DAG)
        node2 (DAGnode): second node operation

    Return:
        bool: True if the gates commute and false if it is not the case.
    """

    # Create set of qubits on which the operation acts
    qarg1 = [node1.qargs[i].index for i in range(0, len(node1.qargs))]
    qarg2 = [node2.qargs[i].index for i in range(0, len(node2.qargs))]

    # Create set of cbits on which the operation acts
    carg1 = [node1.qargs[i].index for i in range(0, len(node1.cargs))]
    carg2 = [node2.qargs[i].index for i in range(0, len(node2.cargs))]

    # Commutation for classical conditional gates
    if node1.condition or node2.condition:
        intersection = set(qarg1).intersection(set(qarg2))
        if intersection or carg1 or carg2:
            commute_condition = False
        else:
            commute_condition = True
        return commute_condition

    # Commutation for measurement
    if node1.name == 'measure' or node2.name == 'measure':
        intersection_q = set(qarg1).intersection(set(qarg2))
        intersection_c = set(carg1).intersection(set(carg2))
        if intersection_q or intersection_c:
            commute_measurement = False
        else:
            commute_measurement = True
        return commute_measurement

    # Commutation for barrier-like directives
    directives = ['barrier', 'snapshot']
    if node1.name in directives or node2.name in directives:
        intersection = set(qarg1).intersection(set(qarg2))
        if intersection:
            commute_directive = False
        else:
            commute_directive = True
        return commute_directive

    # List of non commuting gates (TO DO: add more elements)
    non_commute_list = [set(['x', 'y']), set(['x', 'z'])]

    if qarg1 == qarg2 and (set([node1.name, node2.name]) in non_commute_list):
        return False

    # Create matrices to check commutation relation if no other criteria are matched
    qarg = list(set(node1.qargs + node2.qargs))
    qbit_num = len(qarg)

    qarg1 = [qarg.index(q) for q in node1.qargs]
    qarg2 = [qarg.index(q) for q in node2.qargs]

    id_op = Operator(np.eye(2**qbit_num))

    op12 = id_op.compose(node1.op, qargs=qarg1).compose(node2.op, qargs=qarg2)
    op21 = id_op.compose(node2.op, qargs=qarg2).compose(node1.op, qargs=qarg1)

    if_commute = (op12 == op21)

    return if_commute
示例#30
0
 def test_unitary_decomposition_via_definition(self):
     """Test decomposition for 1Q unitary via definition."""
     mat = numpy.array([[0, 1], [1, 0]])
     numpy.allclose(Operator(UnitaryGate(mat).definition).data, mat)