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)
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)
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
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)
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.')
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)
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
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))
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)
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
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)
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)
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
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
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
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, ), )