Exemple #1
0
 def test_density_matrix_snapshot_ideal(self):
     seed = 500
     op = qi.random_unitary(8, seed=seed)
     circ = QuantumCircuit(3)
     circ.append(op, [0, 1, 2])
     method = self.BACKEND_OPTS.get('method', 'automatic')
     label = 'density_matrix'
     snap_qargs = [[0, 1, 2], [0, 2, 1], [1, 0, 2], [1, 2, 0], [2, 0, 1],
                   [2, 1, 0], [0, 1], [1, 0], [0, 2], [2, 0], [1, 2],
                   [2, 1], [0], [1], [2]]
     evolve_qargs = [[0, 1, 2], [0, 2, 1], [1, 0, 2], [2, 0, 1], [1, 2, 0],
                     [2, 1, 0], [0, 1, 2], [1, 0, 2], [0, 2, 1], [1, 2, 0],
                     [2, 0, 1], [2, 1, 0], [0, 1, 2], [1, 0, 2], [2, 1, 0]]
     for squbits, equbits in zip(snap_qargs, evolve_qargs):
         with self.subTest(msg='qubits={}'.format(squbits)):
             num_qubits = len(squbits)
             tmp = circ.copy()
             tmp.append(Snapshot(label, 'density_matrix', num_qubits),
                        squbits)
             result = execute(tmp,
                              self.SIMULATOR,
                              backend_options=self.BACKEND_OPTS).result()
             if method not in QasmSnapshotDensityMatrixTests.SUPPORTED_QASM_METHODS:
                 self.assertFalse(result.success)
             else:
                 self.assertSuccess(result)
                 snapshots = result.data(0)['snapshots']['density_matrix']
                 value = qi.DensityMatrix(snapshots[label][0]['value'])
                 target = qi.DensityMatrix.from_label(3 * '0').evolve(
                     circ, equbits)
                 if num_qubits == 2:
                     target = qi.partial_trace(target, [2])
                 elif num_qubits == 1:
                     target = qi.partial_trace(target, [1, 2])
                 self.assertEqual(value, target)
Exemple #2
0
    def _target_quantum_state(self) -> Union[Statevector, DensityMatrix]:
        """Return the state tomography target"""
        # Check if circuit contains measure instructions
        # If so we cannot return target state
        circuit_ops = self._circuit.count_ops()
        if "measure" in circuit_ops:
            return None

        perm_circ = self._permute_circuit()
        try:
            if "reset" in circuit_ops or "kraus" in circuit_ops or "superop" in circuit_ops:
                state = DensityMatrix(perm_circ)
            else:
                state = Statevector(perm_circ)
        except QiskitError:
            # Circuit couldn't be simulated
            return None

        total_qubits = self._circuit.num_qubits
        if self._meas_qubits:
            num_meas = len(self._meas_qubits)
        else:
            num_meas = total_qubits
        if num_meas == total_qubits:
            return state

        # Trace out non-measurement qubits
        tr_qargs = range(num_meas, total_qubits)
        return partial_trace(state, tr_qargs)
Exemple #3
0
        def evolve_theoretical_rho(
            rho, U, traced_out_qubit
        ):  # evolution function of state after every collision
            evolving_rho = np.kron(np.array([[1, 0], [0, 0]]), rho)
            evolved_rho = np.matmul(np.matmul(U, evolving_rho), U.conj().T)

            return partial_trace(evolved_rho, [traced_out_qubit]).data
Exemple #4
0
    def _target_quantum_state(self) -> Union[Statevector, DensityMatrix]:
        """Return the state tomography target"""
        # Check if circuit contains measure instructions
        # If so we cannot return target state
        circuit_ops = self._circuit.count_ops()
        if "measure" in circuit_ops:
            return None

        try:
            circuit = self._permute_circuit()
            if "reset" in circuit_ops or "kraus" in circuit_ops or "superop" in circuit_ops:
                state = DensityMatrix(circuit)
            else:
                state = Statevector(circuit)
        except QiskitError:
            # Circuit couldn't be simulated
            return None

        if self._meas_qubits is None:
            return state

        non_meas_qargs = list(range(len(self._meas_qubits), self._circuit.num_qubits))
        if non_meas_qargs:
            # Trace over non-measured qubits
            state = partial_trace(state, non_meas_qargs)

        return state
def quantum_conditional_entropy(rho, theta, phi, qubit=0):
    """
    The quantum conditional entropy for a two-qubit state,
    with a projective measurement in the specified direction

    Evaluates the formula

    .. math::

        \\sum_k p_k S(\\rho_k^B)

    where p_k is the probability of outcome k in the measurement, `\\rho_k^B` is the
    reduced state of the non-measured qubit after the measurement, and S(\\rho) is the
    von-Neumann entropy (log in base 2).

    Args:
        rho (Array): a two-qubit density operator
        theta (float): "latitude" angle for the direction of the measurement
        phi (float): "longitude" angle for the direction of the measurement
        qubit (int): 0 or 1, the qubit on which the measurement is done (default 0)

    Returns:
        float: the quantum conditional entropy
    """
    measurement = projective_measurement(theta, phi, qubit=qubit)
    prob = np.array([np.real(np.trace(p @ rho)) for p in measurement])
    rho_cond = [partial_trace(p @ rho @ p, [qubit]).data for p in measurement]
    rho_cond = [rho_cond[i] / prob[i] for i in range(len(prob))]
    s_ent = np.array(list(map(entropy, rho_cond)))
    return np.sum(prob * s_ent)
    def _target_quantum_state(
            cls,
            circuit: QuantumCircuit,
            measurement_qubits: Optional[Sequence[int]] = None):
        """Return the state tomography target"""
        # Check if circuit contains measure instructions
        # If so we cannot return target state
        circuit_ops = circuit.count_ops()
        if "measure" in circuit_ops:
            return None

        perm_circ = cls._permute_circuit(circuit,
                                         measurement_qubits=measurement_qubits)

        try:
            if "reset" in circuit_ops or "kraus" in circuit_ops or "superop" in circuit_ops:
                state = qi.DensityMatrix(perm_circ)
            else:
                state = qi.Statevector(perm_circ)
        except QiskitError:
            # Circuit couldn't be simulated
            return None

        total_qubits = circuit.num_qubits
        if measurement_qubits:
            num_meas = len(measurement_qubits)
        else:
            num_meas = total_qubits
        if num_meas == total_qubits:
            return state

        # Trace out non-measurement qubits
        tr_qargs = range(num_meas, total_qubits)
        return qi.partial_trace(state, tr_qargs)
 def get_result(item):
     if isinstance(item, (DictStateFn, SparseVectorStateFn)):
         item = item.primitive
     if isinstance(item, VectorStateFn):
         item = item.primitive.data
     if isinstance(item, dict):
         prob_dict = {}
         for key, val in item.items():
             prob_counts = val * np.conj(val)
             if int(key[0]) == 1:
                 prob_counts *= -1
             suffix = key[1:]
             prob_dict[suffix] = prob_dict.get(suffix, 0) + prob_counts
         for key in prob_dict:
             prob_dict[key] *= 2
         return prob_dict
     elif isinstance(item, scipy.sparse.spmatrix):
         # Generate the operator which computes the linear combination
         trace = _z_exp(item)
         return trace
     elif isinstance(item, Iterable):
         # Generate the operator which computes the linear combination
         lin_comb_op = 2 * Z ^ (I ^ state_op.num_qubits)
         lin_comb_op = lin_comb_op.to_matrix()
         outer = np.outer(item, item.conj())
         return list(
             np.diag(
                 partial_trace(lin_comb_op.dot(outer),
                               [state_op.num_qubits]).data))
     else:
         raise TypeError(
             "The state result should be either a DictStateFn or a VectorStateFn."
         )
    def _run_experiment(self, power):
        """Run a grover experiment for a given power of the Grover operator."""
        if self._quantum_instance.is_statevector:
            qc = self.construct_circuit(power, measurement=False)
            result = self._quantum_instance.execute(qc)
            statevector = result.get_statevector(qc)
            num_bits = len(self._grover_operator.reflection_qubits)
            # trace out work qubits
            if qc.width() != num_bits:
                rho = partial_trace(statevector, range(num_bits, qc.width()))
                statevector = np.diag(rho.data)
            max_amplitude = max(statevector.max(), statevector.min(), key=abs)
            max_amplitude_idx = np.where(statevector == max_amplitude)[0][0]
            top_measurement = np.binary_repr(max_amplitude_idx, num_bits)

        else:
            qc = self.construct_circuit(power, measurement=True)
            measurement = self._quantum_instance.execute(qc).get_counts(qc)
            self._ret['measurement'] = measurement
            top_measurement = max(measurement.items(), key=operator.itemgetter(1))[0]

        self._ret['top_measurement'] = top_measurement

        # as_list = [int(bit) for bit in top_measurement]
        # return self.post_processing(as_list), self.is_good_state(top_measurement)
        return self.post_processing(top_measurement), self.is_good_state(top_measurement)
Exemple #9
0
 def get_result(item):
     if isinstance(item, DictStateFn):
         item = item.primitive
     if isinstance(item, VectorStateFn):
         item = item.primitive.data
     if isinstance(item, Iterable):
         # Generate the operator which computes the linear combination
         lin_comb_op = 4 * (I ^ (state_op.num_qubits + 1)) ^ Z
         lin_comb_op = lin_comb_op.to_matrix()
         return list(
             np.diag(
                 partial_trace(
                     lin_comb_op.dot(np.outer(item, np.conj(item))),
                     [0, 1]).data))
     elif isinstance(item, dict):
         prob_dict = {}
         for key, val in item.values():
             prob_counts = val * np.conj(val)
             if int(key[-1]) == 1:
                 prob_counts *= -1
             prefix = key[:-2]
             prob_dict[prefix] = prob_dict.get(prefix, 0) + prob_counts
         for key in prob_dict:
             prob_dict[key] *= 4
         return prob_dict
     else:
         raise TypeError('The state result should be either a '
                         'DictStateFn or a VectorStateFn.')
Exemple #10
0
    def _single_experiment(self, problem, power):
        """Run a grover experiment for a given power of the Grover operator."""
        if self._quantum_instance.is_statevector:
            qc = self.construct_circuit(problem, power, measurement=False)
            result = self._quantum_instance.execute(qc)
            statevector = result.get_statevector(qc)
            num_bits = len(problem.objective_qubits)

            # trace out work qubits
            if qc.width() != num_bits:
                indices = [
                    i for i in range(qc.num_qubits)
                    if i not in problem.objective_qubits
                ]
                rho = partial_trace(statevector, indices)
                statevector = np.diag(rho.data)

            max_amplitude = max(statevector.max(), statevector.min(), key=abs)
            max_amplitude_idx = np.where(statevector == max_amplitude)[0][0]
            top_measurement = np.binary_repr(max_amplitude_idx, num_bits)

        else:
            qc = self.construct_circuit(problem, power, measurement=True)
            measurement = self._quantum_instance.execute(qc).get_counts(qc)
            top_measurement = max(measurement.items(),
                                  key=operator.itemgetter(1))[0]

        return top_measurement, problem.is_good_state(top_measurement)
Exemple #11
0
def test_qsphere_bad_dm_input():
    """Tests the qsphere raises when passed impure dm"""

    qc = QuantumCircuit(3)
    qc.h(0)
    qc.cx(0, 1)
    qc.cx(1, 2)
    dm = DensityMatrix.from_instruction(qc)
    pdm = partial_trace(dm, [0, 1])
    with pytest.raises(KaleidoscopeError):
        assert qsphere(pdm)
 def trace_to_density_op(state: qk.DictStateFn,
                         trace_over: List[int]) -> qkinfo.DensityMatrix:
     """
     Take a state comprised on n qubits and get the trace of the system over the subsystems
     specified by a list of indices.
     
     Makes no assumption about the separability of the traced subsystems and gives a density
     matrix as a result.
     """
     input_statevector = qkinfo.Statevector(state.to_matrix())
     return qkinfo.partial_trace(input_statevector, trace_over)
 def trace_dict_state(state: qk.DictStateFn,
                      trace_over: List[int]) -> qk.DictStateFn:
     """
     Take a state comprised on n qubits and get the trace of the system over the subsystems
     specified by a list of indices.
     
     Assumes state is separable as a DictStateFn can only represent pure states.
     """
     input_statevector = qkinfo.Statevector(state.to_matrix())
     traced_statevector = qkinfo.partial_trace(input_statevector,
                                               trace_over).to_statevector()
     return qk.DictStateFn(traced_statevector.to_dict())
    def _target_quantum_channel(
        cls,
        circuit: QuantumCircuit,
        measurement_qubits: Optional[Sequence[int]] = None,
        preparation_qubits: Optional[Sequence[int]] = None,
    ):
        """Return the process tomography target"""
        # Check if circuit contains measure instructions
        # If so we cannot return target state
        circuit_ops = circuit.count_ops()
        if "measure" in circuit_ops:
            return None

        perm_circ = cls._permute_circuit(circuit,
                                         measurement_qubits=measurement_qubits,
                                         preparation_qubits=preparation_qubits)
        try:
            if "reset" in circuit_ops or "kraus" in circuit_ops or "superop" in circuit_ops:
                channel = qi.Choi(perm_circ)
            else:
                channel = qi.Operator(perm_circ)
        except QiskitError:
            # Circuit couldn't be simulated
            return None

        total_qubits = circuit.num_qubits
        if measurement_qubits:
            num_meas = len(measurement_qubits)
        else:
            num_meas = total_qubits
        if preparation_qubits:
            num_prep = len(preparation_qubits)
        else:
            num_prep = total_qubits

        if num_prep == total_qubits and num_meas == total_qubits:
            return channel

        # Trace out non-measurement subsystems
        tr_qargs = []
        if preparation_qubits:
            tr_qargs += list(range(num_prep, total_qubits))
        if measurement_qubits:
            tr_qargs += list(range(total_qubits + num_meas, 2 * total_qubits))

        chan_state = qi.Statevector(np.ravel(channel, order="F"))
        chan_state = qi.partial_trace(chan_state,
                                      tr_qargs) / 2**(total_qubits - num_meas)
        channel = qi.Choi(chan_state.data,
                          input_dims=[2] * num_prep,
                          output_dims=[2] * num_meas)
        return channel
    def test_different_qubit_sets(self):
        circuit = QuantumCircuit(5)
        circuit.h(0)
        circuit.cx(0, 1)
        circuit.x(2)
        circuit.s(3)
        circuit.z(4)
        circuit.cx(1, 3)

        for qubit_pair in [(0, 1), (2, 3), (1, 4), (0, 3)]:
            rho, psi = run_circuit_and_tomography(circuit, qubit_pair, self.method)
            psi = partial_trace(psi, [x for x in range(5) if x not in qubit_pair])
            F = state_fidelity(psi, rho, validate=False)
            self.assertAlmostEqual(F, 1, places=1)
    def _target_quantum_channel(self) -> Union[Choi, Operator]:
        """Return the process tomography target"""
        # Check if circuit contains measure instructions
        # If so we cannot return target state
        circuit_ops = self._circuit.count_ops()
        if "measure" in circuit_ops:
            return None

        try:
            circuit = self._permute_circuit()
            if "reset" in circuit_ops or "kraus" in circuit_ops or "superop" in circuit_ops:
                channel = Choi(circuit)
            else:
                channel = Operator(circuit)
        except QiskitError:
            # Circuit couldn't be simulated
            return None

        total_qubits = self._circuit.num_qubits
        num_meas = total_qubits if self._meas_qubits is None else len(self._meas_qubits)
        num_prep = total_qubits if self._prep_qubits is None else len(self._prep_qubits)

        # If all qubits are prepared or measurement we are done
        if num_meas == total_qubits and num_prep == total_qubits:
            return channel

        # Convert channel to a state to project and trace out non-tomography
        # input and output qubits
        if isinstance(channel, Operator):
            chan_state = Statevector(np.ravel(channel, order="F"))
        else:
            chan_state = DensityMatrix(channel.data)

        # Get qargs for non measured and prepared subsystems
        non_meas_qargs = list(range(num_meas, total_qubits))
        non_prep_qargs = list(range(total_qubits + num_prep, 2 * total_qubits))

        # Project non-prepared subsystems on to the zero state
        if non_prep_qargs:
            proj0 = Operator([[1, 0], [0, 0]])
            for qarg in non_prep_qargs:
                chan_state = chan_state.evolve(proj0, [qarg])

        # Trace out indices to remove
        tr_qargs = non_meas_qargs + non_prep_qargs
        chan_state = partial_trace(chan_state, tr_qargs)
        channel = Choi(chan_state.data, input_dims=[2] * num_prep, output_dims=[2] * num_meas)
        return channel
Exemple #17
0
def get_statevectors(QAE, noisy_states):
    # QAE : QAE to use
    # noisy_states : list of noisy states
    
    backend = Aer.get_backend('statevector_simulator')
    QAE_circ, out_qubits = QAE.subroutine_2()
    
    state_0 = np.zeros((2**QAE.M[0],2**QAE.M[0]), dtype = 'complex128')
    state_1 = np.zeros(2**QAE.M[0], dtype = 'complex128')
    for state in noisy_states:
        circ_0 = QuantumCircuit(QAE.W)
        circ_0.append(state, range(QAE.M[0]))
        circ_0.append(QAE_circ, range(QAE.W))
        
        state_0 += partial_trace(execute(circ_0, backend).result().get_statevector(), list(set(range(QAE.W)) - set(out_qubits))).data
        state_1 += execute(state, backend).result().get_statevector()
    return (state_0/len(noisy_states), state_1/len(noisy_states))
Exemple #18
0
 def separatedBlochSpheres(self):
     """
     returns list of response object for the bloch sphere of every wire
     """
     pos=list(range(self.num_qubits))
     res={}
     for i in range(self.num_qubits):
         #density matrix of the wire
         [[a, b], [c, d]] = partial_trace(self.statevector, pos[:i]+pos[i+1:]).data 
         #polar coordinate
         x = 2*b.real
         y = 2*c.imag
         z = a.real-d.real
         #blochSphere figure
         fig=plot_bloch_vector([x,y,z])#,title="qubit "+str(i)
         #appending response object of the figure
         res[i]=self.figToResponse(fig)
     return res
def classical_correlation(rho, qubit=0):
    """
    Calculate the truly classical correlations between two qubits.

    The classical correlations are defined e.g. in Eq. (8)
    of Phys. Rev. A 83, 052108 (2011). We use base 2 for log.

    Args:
        rho (Array): a two-qubit density operator
        qubit (int): 0 or 1, the qubit on which the measurement is done (default 0)

    Returns:
        float: classical correlations
    """
    assert rho.shape == (4, 4), "Not a two-qubit density matrix"
    cc = lambda x: quantum_conditional_entropy(rho, x[0], x[1], qubit=qubit)
    f = minimize(cc, [np.pi / 2, np.pi])
    return (entropy(partial_trace(rho, [qubit])) - f.fun) / np.log(2)
    def test_matrices(self, matrix, time=1.0, power=1):
        """Test the different matrix classes."""
        matrix.evolution_time = time

        num_qubits = matrix.num_state_qubits
        pow_circ = matrix.power(power).control()
        circ_qubits = pow_circ.num_qubits
        qc = QuantumCircuit(circ_qubits)
        qc.append(matrix.power(power).control(), list(range(circ_qubits)))
        # extract the parts of the circuit matrix corresponding to TridiagonalToeplitz
        zero_op = (I + Z) / 2
        one_op = (I - Z) / 2
        proj = Operator((zero_op ^ pow_circ.num_ancillas) ^ (I ^ num_qubits) ^ one_op).data
        circ_matrix = Operator(qc).data
        approx_exp = partial_trace(
            np.dot(proj, circ_matrix), [0] + list(range(num_qubits + 1, circ_qubits))
        ).data

        exact_exp = expm(1j * matrix.evolution_time * power * matrix.matrix)
        np.testing.assert_array_almost_equal(approx_exp, exact_exp, decimal=2)
Exemple #21
0
    def _run(self) -> AlgorithmResult:
        if not self._ret['factors']:
            logger.debug('Running with N=%s and a=%s.', self._N, self._a)

            if self._quantum_instance.is_statevector:
                circuit = self.construct_circuit(measurement=False)
                logger.warning('The statevector_simulator might lead to '
                               'subsequent computation using too much memory.')
                result = self._quantum_instance.execute(circuit)
                complete_state_vec = result.get_statevector(circuit)
                # TODO: this uses too much memory
                up_qreg_density_mat = partial_trace(
                    complete_state_vec, range(2 * self._n, 4 * self._n + 2))
                up_qreg_density_mat_diag = np.diag(up_qreg_density_mat)

                counts = dict()
                for i, v in enumerate(up_qreg_density_mat_diag):
                    if not v == 0:
                        counts[bin(int(i))[2:].zfill(2 * self._n)] = v**2
            else:
                circuit = self.construct_circuit(measurement=True)
                counts = self._quantum_instance.execute(circuit).get_counts(
                    circuit)

            self._ret.data["total_counts"] = len(counts)

            # For each simulation result, print proper info to user
            # and try to calculate the factors of N
            for measurement in list(counts.keys()):
                # Get the x_final value from the final state qubits
                logger.info("------> Analyzing result %s.", measurement)
                factors = self._get_factors(measurement)

                if factors:
                    logger.info('Found factors %s from measurement %s.',
                                factors, measurement)
                    self._ret.data["successful_counts"] += 1
                    if factors not in self._ret['factors']:
                        self._ret['factors'].append(factors)

        return self._ret
Exemple #22
0
    def test_sparse_entropy_equal_qiskit(self):
        N = 33
        Y = aux.coprime(N)
        L = aux.lfy(N)
        k = 2 * L
        number_of_qubits = k + L
        nonzeros_decimal = aux.nonzeros_decimal(k, N, Y)
        state = construct_modular_state(k, L, nonzeros_decimal)
        tries = 200
        for i in range(tries):
            chosen = random_bipartition(range(number_of_qubits),
                                        number_of_qubits // 2)
            notchosen = bip.notchosen(chosen, number_of_qubits)
            state_entropy = entanglement_entropy_from_state(state,
                                                            chosen,
                                                            sparse=True)
            qentropy = entropy(
                partial_trace(Statevector(state.toarray().flatten()),
                              [k + L - 1 - i for i in notchosen]))

            self.assertTrue(np.abs(qentropy - state_entropy) < 1e-12)
Exemple #23
0
    def test_IQFT_entropy_equals_qiskit(self):
        Y = 13
        N = 28
        L = aux.lfy(N)
        k = 2 * L
        number_of_qubits = k + L

        state = construct_modular_state(k, L, aux.nonzeros_decimal(k, Y, N))
        state = apply_IQFT(L, state.toarray())

        tries = 30
        for i in range(tries):
            chosen_qubits = random_bipartition(range(number_of_qubits),
                                               number_of_qubits // 2)
            notchosen_qubits = notchosen(chosen_qubits, number_of_qubits)
            myentropy = entanglement_entropy_from_state(state,
                                                        chosen_qubits,
                                                        sparse=False,
                                                        gpu=False)
            qentropy = entropy(
                partial_trace(Statevector(state), notchosen_qubits))
            self.assertTrue(np.abs(myentropy - qentropy) < 1e-5)
Exemple #24
0
def stacked_QAE_fidelity(QAE, L, k):
    # QAE : QAE to use
    # L : list of test states
    # k : stacking maximum
    
    backend = Aer.get_backend('statevector_simulator')
    
    QAE_circ, out_qubits = QAE.subroutine_2()
    circ_0 = QuantumCircuit(QAE.W)
    circ_0.append(L[0][0], range(QAE.M[0])) 
    
    for i in range(k):
        circ_0.append(QAE_circ, range(QAE.W))
        circ_0.reset(list(set(range(QAE.W)) - set(out_qubits)))
    
    fid = []
    for pair in L:
        circ_0.data[0] = (pair[0], circ_0.data[0][1], circ_0.data[0][2])
        state_0 = partial_trace(execute(circ_0, backend).result().get_statevector(), list(set(range(QAE.W)) - set(out_qubits)))
        state_1 = execute(pair[1], backend).result().get_statevector()
        fid.append(state_fidelity(state_0, state_1))
        
    return fid
Exemple #25
0
def stacked_QAE_fidelity_range(QAE, L, k, filename = None):
    # QAE : QAE to use
    # L : list of test states
    # k : stacking maximum
    # filename : whether to save figure and figure name
    
    backend = Aer.get_backend('statevector_simulator')
    
    QAE_circ, out_qubits = QAE.subroutine_2()
    circ_0 = QuantumCircuit(QAE.W)
    circ_0.append(L[0][0], range(QAE.M[0]))    
    
    all_fid_mean = []
    all_fid_std = []
    for i in range(k):
        circ_0.append(QAE_circ, range(QAE.W))
        circ_0.reset(list(set(range(QAE.W)) - set(out_qubits)))
        
        fid = []
        for pair in L:
            circ_0.data[0] = (pair[0], circ_0.data[0][1], circ_0.data[0][2])
            state_0 = partial_trace(execute(circ_0, backend).result().get_statevector(), list(set(range(QAE.W)) - set(out_qubits)))
            state_1 = execute(pair[1], backend).result().get_statevector()
            fid.append(state_fidelity(state_0, state_1))
            
        all_fid_mean.append(np.mean(fid))
        all_fid_std.append(np.std(fid))
    
    # Plot
    plt.errorbar(range(1,k+1), all_fid_mean, all_fid_std, marker = 'D', ms = 4, color = '#0000CC', capsize = 5)
    plt.grid(lw = 0.5, ls = 'dotted')
    plt.xlabel('Number of QAEs stacked')
    plt.ylabel('Fidelity with GHZ')
    
    if filename != None:
        plt.savefig(filename + '.pdf', bbox_inches = 'tight')
    def amplify(self, amplification_problem: AmplificationProblem) -> 'GroverResult':
        """Run the Grover algorithm.

        Args:
            amplification_problem: The amplification problem.

        Returns:
            The result as a ``GroverResult``, where e.g. the most likely state can be queried
            as ``result.top_measurement``.
        """
        if isinstance(self._iterations, list):
            max_iterations = len(self._iterations)
            max_power = np.inf  # no cap on the power
            iterator = iter(self._iterations)
        else:
            max_iterations = max(10, 2 ** amplification_problem.oracle.num_qubits)
            max_power = np.ceil(
                2 ** (len(amplification_problem.grover_operator.reflection_qubits) / 2))
            iterator = self._iterations

        result = GroverResult()

        iterations = []
        top_measurement = '0' * len(amplification_problem.objective_qubits)
        oracle_evaluation = False
        all_circuit_results = []
        max_probability = 0
        shots = 0

        for _ in range(max_iterations):  # iterate at most to the max number of iterations
            # get next power and check if allowed
            power = next(iterator)

            if power > max_power:
                break

            iterations.append(power)  # store power

            # sample from [0, power) if specified
            if self._sample_from_iterations:
                power = np.random.randint(power)
            # Run a grover experiment for a given power of the Grover operator.
            if self._quantum_instance.is_statevector:
                qc = self.construct_circuit(amplification_problem, power, measurement=False)
                circuit_results = self._quantum_instance.execute(qc).get_statevector()
                num_bits = len(amplification_problem.objective_qubits)

                # trace out work qubits
                if qc.width() != num_bits:
                    indices = [i for i in range(qc.num_qubits)
                               if i not in amplification_problem.objective_qubits]
                    rho = partial_trace(circuit_results, indices)
                    circuit_results = np.diag(rho.data)

                max_amplitude = max(circuit_results.max(), circuit_results.min(), key=abs)
                max_amplitude_idx = np.where(circuit_results == max_amplitude)[0][0]
                top_measurement = np.binary_repr(max_amplitude_idx, num_bits)
                max_probability = np.abs(max_amplitude)**2
                shots = 1
            else:
                qc = self.construct_circuit(amplification_problem, power, measurement=True)
                circuit_results = self._quantum_instance.execute(qc).get_counts(qc)
                top_measurement = max(circuit_results.items(), key=operator.itemgetter(1))[0]
                shots = sum(circuit_results.values())
                max_probability = max(circuit_results.items(), key=operator.itemgetter(1))[1] \
                    / shots

            all_circuit_results.append(circuit_results)
            oracle_evaluation = amplification_problem.is_good_state(top_measurement)
            if oracle_evaluation is True:
                break  # we found a solution

        result.iterations = iterations
        result.top_measurement = top_measurement
        result.assignment = amplification_problem.post_processing(top_measurement)
        result.oracle_evaluation = oracle_evaluation
        result.circuit_results = all_circuit_results
        result.max_probability = max_probability

        return result
Exemple #27
0
    def factor(
        self,
        N: int,
        a: int = 2,
    ) -> 'ShorResult':
        """Execute the algorithm.

        The input integer :math:`N` to be factored is expected to be odd and greater than 2.
        Even though this implementation is general, its capability will be limited by the
        capacity of the simulator/hardware. Another input integer :math:`a`  can also be supplied,
        which needs to be a co-prime smaller than :math:`N` .

        Args:
            N: The integer to be factored, has a min. value of 3.
            a: Any integer that satisfies 1 < a < N and gcd(a, N) = 1.

        Returns:
            ShorResult: results of the algorithm.

        Raises:
            ValueError: Invalid input
            AlgorithmError: If a quantum instance or backend has not been provided

        """
        validate_min('N', N, 3)
        validate_min('a', a, 2)

        # check the input integer
        if N < 1 or N % 2 == 0:
            raise ValueError(
                'The input needs to be an odd integer greater than 1.')

        if a >= N or math.gcd(a, N) != 1:
            raise ValueError(
                'The integer a needs to satisfy a < N and gcd(a, N) = 1.')

        if self.quantum_instance is None:
            raise AlgorithmError(
                "A QuantumInstance or Backend "
                "must be supplied to run the quantum algorithm.")

        result = ShorResult()

        # check if the input integer is a power
        tf, b, p = is_power(N, return_decomposition=True)
        if tf:
            logger.info('The input integer is a power: %s=%s^%s.', N, b, p)
            result.factors.append(b)

        if not result.factors:
            logger.debug('Running with N=%s and a=%s.', N, a)

            if self._quantum_instance.is_statevector:
                circuit = self.construct_circuit(N=N, a=a, measurement=False)
                logger.warning('The statevector_simulator might lead to '
                               'subsequent computation using too much memory.')
                result = self._quantum_instance.execute(circuit)
                complete_state_vec = result.get_statevector(circuit)
                # TODO: this uses too much memory
                up_qreg_density_mat = partial_trace(
                    complete_state_vec, range(2 * self._n, 4 * self._n + 2))
                up_qreg_density_mat_diag = np.diag(up_qreg_density_mat)

                counts = dict()
                for i, v in enumerate(up_qreg_density_mat_diag):
                    if not v == 0:
                        counts[bin(int(i))[2:].zfill(2 * self._n)] = v**2
            else:
                circuit = self.construct_circuit(N=N, a=a, measurement=True)
                counts = self._quantum_instance.execute(circuit).get_counts(
                    circuit)

            result.total_counts = len(counts)

            # For each simulation result, print proper info to user
            # and try to calculate the factors of N
            for measurement in list(counts.keys()):
                # Get the x_final value from the final state qubits
                logger.info("------> Analyzing result %s.", measurement)
                factors = self._get_factors(N, a, measurement)

                if factors:
                    logger.info('Found factors %s from measurement %s.',
                                factors, measurement)
                    result.successful_counts = result.successful_counts + 1
                    if factors not in result.factors:
                        result.factors.append(factors)

        return result
Exemple #28
0
def theoretical_tangle(phi):  # Theoretical Three-tangle function
    d1 = phi[0] ** 2 * phi[7] ** 2 + phi[1] ** 2 * phi[6] ** 2 + \
         phi[2] ** 2 * phi[5] ** 2 + phi[4] ** 2 * phi[3] ** 2
    d2 = phi[0] * phi[7] * phi[3] * phi[4] + phi[0] * phi[7] * phi[5] * phi[2] + \
         phi[0] * phi[7] * phi[6] * phi[1] + phi[3] * phi[4] * phi[5] * phi[2] + \
         phi[3] * phi[4] * phi[6] * phi[1] + phi[5] * phi[2] * phi[6] * phi[1]
    d3 = phi[0] * phi[6] * phi[5] * phi[3] + phi[7] * phi[1] * phi[2] * phi[4]
    tau = 4 * np.abs(d1 - 2 * d2 + 4 * d3)

    return tau


def concurrence(rho):  # Concurrence Function
    Y = np.array([[0, -1j], [1j, 0]])
    spin_flip = np.kron(Y, Y)
    rho_tilde = np.matmul(np.matmul(spin_flip, np.matrix.conjugate(rho)),
                          spin_flip)
    l = np.sort(
        np.nan_to_num(
            np.sqrt(np.real(np.linalg.eigvals(np.matmul(rho,
                                                        rho_tilde))))))[::-1]

    return np.max([0, l[0] - l[1] - l[2] - l[3]])


psi = [0, 1, 1, 0, 1, 0, 0, 2]
psi /= np.linalg.norm(psi)
rho = np.outer(psi, psi)
rho = partial_trace(rho, [2]).data
print(concurrence(rho)**2)
print(theoretical_tangle(psi))
    # Build noise channel
    bit_flip_channel = Kraus([[[0, np.sqrt(p)], [np.sqrt(p), 0]],
                              [[np.sqrt(1 - p), 0], [0, np.sqrt(1 - p)]]])
    bit_flip_channel = bit_flip_channel.tensor(bit_flip_channel).tensor(
        bit_flip_channel)
    bit_flip_channel = bit_flip_channel.expand(Kraus(np.eye(2))).expand(
        Kraus(np.eye(2)))

    # Apply channels
    corrupted_state = DensityMatrix(init_state.evolve(bit_flip_channel))
    corrected_state = DensityMatrix(corrupted_state.evolve(syndrome_op))
    corrected_state = DensityMatrix(corrected_state.evolve(
        qecc.correction_ckt))

    # Trace out syndrome
    ini = DensityMatrix(partial_trace(init_state, [3, 4]))
    corrupted_state = DensityMatrix(partial_trace(corrupted_state, [3, 4]))
    corrected_state = DensityMatrix(partial_trace(corrected_state, [3, 4]))

    # Record results
    f1.append(state_fidelity(ini, corrupted_state))
    f2.append(state_fidelity(ini, corrected_state))

# Plot fidelity
fig = plt.figure(figsize=(8, 6))
ax = fig.add_subplot(111)
ax.plot(p_error, f1, label='w/o code')
ax.plot(p_error, f2, label='with code')
ax.set_title("$Fidelity$ vs $P_{error}$")
ax.set_xlabel('$P_{error}$')
ax.set_ylabel('$Fidelity$')
    def solve(self, problem: QuadraticProgram) -> OptimizationResult:
        """Tries to solves the given problem using the grover optimizer.

        Runs the optimizer to try to solve the optimization problem. If the problem cannot be,
        converted to a QUBO, this optimizer raises an exception due to incompatibility.

        Args:
            problem: The problem to be solved.

        Returns:
            The result of the optimizer applied to the problem.

        Raises:
            AttributeError: If the quantum instance has not been set.
            QiskitOptimizationError: If the problem is incompatible with the optimizer.
        """
        if self.quantum_instance is None:
            raise AttributeError(
                "The quantum instance or backend has not been set.")

        self._verify_compatibility(problem)

        # convert problem to QUBO
        problem_ = self._convert(problem, self._converters)
        problem_init = deepcopy(problem_)

        # convert to minimization problem
        if problem_.objective.sense == problem_.objective.Sense.MAXIMIZE:
            problem_.objective.sense = problem_.objective.Sense.MINIMIZE
            problem_.objective.constant = -problem_.objective.constant
            for i, val in problem_.objective.linear.to_dict().items():
                problem_.objective.linear[i] = -val
            for (i, j), val in problem_.objective.quadratic.to_dict().items():
                problem_.objective.quadratic[i, j] = -val
        self._num_key_qubits = len(problem_.objective.linear.to_array())

        # Variables for tracking the optimum.
        optimum_found = False
        optimum_key = math.inf
        optimum_value = math.inf
        threshold = 0
        n_key = self._num_key_qubits
        n_value = self._num_value_qubits

        # Variables for tracking the solutions encountered.
        num_solutions = 2**n_key
        keys_measured = []

        # Variables for result object.
        operation_count = {}
        iteration = 0

        # Variables for stopping if we've hit the rotation max.
        rotations = 0
        max_rotations = int(np.ceil(100 * np.pi / 4))

        # Initialize oracle helper object.
        qr_key_value = QuantumRegister(self._num_key_qubits +
                                       self._num_value_qubits)
        orig_constant = problem_.objective.constant
        measurement = not self.quantum_instance.is_statevector
        oracle, is_good_state = self._get_oracle(qr_key_value)

        while not optimum_found:
            m = 1
            improvement_found = False

            # Get oracle O and the state preparation operator A for the current threshold.
            problem_.objective.constant = orig_constant - threshold
            a_operator = self._get_a_operator(qr_key_value, problem_)

            # Iterate until we measure a negative.
            loops_with_no_improvement = 0
            while not improvement_found:
                # Determine the number of rotations.
                loops_with_no_improvement += 1
                rotation_count = int(
                    np.ceil(algorithm_globals.random.uniform(0, m - 1)))
                rotations += rotation_count
                # Apply Grover's Algorithm to find values below the threshold.
                # TODO: Utilize Grover's incremental feature - requires changes to Grover.
                amp_problem = AmplificationProblem(
                    oracle=oracle,
                    state_preparation=a_operator,
                    is_good_state=is_good_state,
                )
                grover = Grover()
                circuit = grover.construct_circuit(problem=amp_problem,
                                                   power=rotation_count,
                                                   measurement=measurement)

                # Get the next outcome.
                outcome = self._measure(circuit)
                k = int(outcome[0:n_key], 2)
                v = outcome[n_key:n_key + n_value]
                int_v = self._bin_to_int(v, n_value) + threshold
                logger.info("Outcome: %s", outcome)
                logger.info("Value Q(x): %s", int_v)
                # If the value is an improvement, we update the iteration parameters (e.g. oracle).
                if int_v < optimum_value:
                    optimum_key = k
                    optimum_value = int_v
                    logger.info("Current Optimum Key: %s", optimum_key)
                    logger.info("Current Optimum Value: %s", optimum_value)
                    improvement_found = True
                    threshold = optimum_value

                    # trace out work qubits and store samples
                    if self._quantum_instance.is_statevector:
                        indices = list(range(n_key, len(outcome)))
                        rho = partial_trace(self._circuit_results, indices)
                        self._circuit_results = np.diag(rho.data)**0.5
                    else:
                        self._circuit_results = {
                            i[-1 * n_key:]: v
                            for i, v in self._circuit_results.items()
                        }

                    raw_samples = self._eigenvector_to_solutions(
                        self._circuit_results, problem_init)
                    raw_samples.sort(
                        key=lambda x: problem_.objective.sense.value * x.fval)
                    samples = self._interpret_samples(problem, raw_samples,
                                                      self._converters)
                else:
                    # Using Durr and Hoyer method, increase m.
                    m = int(np.ceil(min(m * 8 / 7, 2**(n_key / 2))))
                    logger.info("No Improvement. M: %s", m)

                    # Check if we've already seen this value.
                    if k not in keys_measured:
                        keys_measured.append(k)

                    # Assume the optimal if any of the stop parameters are true.
                    if (loops_with_no_improvement >= self._n_iterations
                            or len(keys_measured) == num_solutions
                            or rotations >= max_rotations):
                        improvement_found = True
                        optimum_found = True

                # Track the operation count.
                operations = circuit.count_ops()
                operation_count[iteration] = operations
                iteration += 1
                logger.info("Operation Count: %s\n", operations)

        # If the constant is 0 and we didn't find a negative, the answer is likely 0.
        if optimum_value >= 0 and orig_constant == 0:
            optimum_key = 0

        opt_x = np.array([
            1 if s == "1" else 0
            for s in ("{0:%sb}" % n_key).format(optimum_key)
        ])
        # Compute function value
        fval = problem_init.objective.evaluate(opt_x)

        # cast binaries back to integers
        return cast(
            GroverOptimizationResult,
            self._interpret(
                x=opt_x,
                converters=self._converters,
                problem=problem,
                result_class=GroverOptimizationResult,
                samples=samples,
                raw_samples=raw_samples,
                operation_counts=operation_count,
                n_input_qubits=n_key,
                n_output_qubits=n_value,
                intermediate_fval=fval,
                threshold=threshold,
            ),
        )