def get_success_probabilities_from_results(results: Sequence[Sequence[Sequence[int]]]) \ -> Sequence[float]: """ Get the probability of a successful addition for each possible pair of two n_bit summands from the results output by get_n_bit_adder_results :param results: a list of results output from a call to get_n_bit_adder_results :return: the success probability for the summation of each possible pair of n_bit summands """ num_shots = len(results[0]) n_bits = len(results[0][0]) - 1 probabilities = [] # loop over all binary strings of length n_bits for result, bits in zip(results, all_bitstrings(2 * n_bits)): # Input nums are written from (MSB .... LSB) = (a_n, ..., a_1, a_0) num_a = bit_array_to_int(bits[:n_bits]) num_b = bit_array_to_int(bits[n_bits:]) # add the numbers ans = num_a + num_b ans_bits = int_to_bit_array(ans, n_bits + 1) # a success occurs if a shot matches the expected ans bit for bit probability = 0 for shot in result: if np.array_equal(ans_bits, shot): probability += 1. / num_shots probabilities.append(probability) return probabilities
def get_error_hamming_distributions_from_results(results: Sequence[Sequence[Sequence[int]]]) \ -> Sequence[Sequence[float]]: """ Get the distribution of the hamming weight of the error vector (number of bits flipped between output and expected answer) for each possible pair of two n_bit summands using results output by get_n_bit_adder_results :param results: a list of results output from a call to get_n_bit_adder_results :return: the relative frequency of observing each hamming weight, 0 to n_bits+1, for the error that occurred when adding each pair of two n_bit summands """ num_shots = len(results[0]) n_bits = len(results[0][0]) - 1 hamming_wt_distrs = [] # loop over all binary strings of length n_bits for result, bits in zip(results, all_bitstrings(2 * n_bits)): # Input nums are written from (MSB .... LSB) = (a_n, ..., a_1, a_0) num_a = bit_array_to_int(bits[:n_bits]) num_b = bit_array_to_int(bits[n_bits:]) # add the numbers ans = num_a + num_b ans_bits = int_to_bit_array(ans, n_bits + 1) # record the fraction of shots that resulted in an error of the given weight hamming_wt_distr = [0. for _ in range(len(ans_bits) + 1)] for shot in result: # multiply relative hamming distance by the length of the output for the weight wt = len(ans_bits) * hamming(ans_bits, shot) hamming_wt_distr[int(wt)] += 1. / num_shots hamming_wt_distrs.append(hamming_wt_distr) return hamming_wt_distrs
def sample_rand_circuits_for_heavy_out( qc: QuantumComputer, qubits: Sequence[int], depth: int, program_generator: Callable[ [QuantumComputer, Sequence[int], Sequence[np.ndarray], np.ndarray], Program], num_circuits: int = 100, num_shots: int = 1000, show_progress_bar: bool = False) -> int: """ This method performs the bulk of the work in the quantum volume measurement. For the given depth, num_circuits many random model circuits are generated, the heavy outputs are determined from the ideal output distribution of each circuit, and a native quil implementation of the model circuit output by the program generator is run on the qc. The total number of sampled heavy outputs is returned. :param qc: the quantum resource that will implement the PyQuil program for each model circuit :param qubits: the qubits available in the qc for the program_generator to use. :param depth: the depth (and width in num of qubits) of the model circuits :param program_generator: a method which takes an abstract description of a model circuit and returns a native quil program that implements that circuit. See measure_quantum_volume docstring for specifics. :param num_circuits: the number of random model circuits to sample at this depth; should be >100 :param num_shots: the number of shots to sample from each model circuit :param show_progress_bar: displays a progress bar via tqdm if true. :return: the number of heavy outputs sampled among all circuits generated for this depth """ wfn_sim = NumpyWavefunctionSimulator(depth) num_heavy = 0 # display progress bar using tqdm for _ in tqdm(range(num_circuits), disable=not show_progress_bar): permutations, gates = generate_abstract_qv_circuit(depth) # generate a PyQuil program in native quil that implements the model circuit # The program should measure the output qubits in the order that is consistent with the # comparison of the bitstring results to the heavy outputs given by collect_heavy_outputs program = program_generator(qc, qubits, permutations, gates) # run the program num_shots many times program.wrap_in_numshots_loop(num_shots) executable = qc.compiler.native_quil_to_executable(program) results = qc.run(executable) # classically simulate model circuit represented by the perms and gates for heavy outputs heavy_outputs = collect_heavy_outputs(wfn_sim, permutations, gates) # determine if each result bitstring is a heavy output, as determined from simulation for result in results: # convert result to int for comparison with heavy outputs. output = bit_array_to_int(result) if output in heavy_outputs: num_heavy += 1 return num_heavy
def count(hh, res): num_heavy = 0 # determine if each result bitstring is a heavy output, as determined from simulation for result in res: # convert result to int for comparison with heavy outputs. output = bit_array_to_int(result) if output in hh: num_heavy += 1 return num_heavy
def count_heavy_hitters_sampled( qc_results: Iterator[np.ndarray], heavy_hitters: Iterator[List[int]]) -> Iterator[int]: """ Simple helper to count the number of heavy hitters sampled given the sampled results for a number of circuits along with the the actual heavy hitters for each circuit. :param qc_results: results from running each circuit on a quantum computer. :param heavy_hitters: the heavy hitters for each circuit (presumably calculated through simulating the circuit classically) :return: the number of samples which were heavy for each circuit. """ for results, hh_list in zip(qc_results, heavy_hitters): num_heavy = 0 # determine if each result bitstring is a heavy output, as determined from simulation for result in results: # convert result to int for comparison with heavy outputs. output = bit_array_to_int(result) if output in hh_list: num_heavy += 1 yield num_heavy