Ejemplo n.º 1
0
def fixed_probability_circuit(p, threads, print_round_by_round):
    #here we make a circuit of the form U U^dagger V(p) as described in equation (22) of https://arxiv.org/abs/2101.12223
    qubits = 40
    t_U = 16  # the U portion of the circuit has 16 T(theta) gates

    depth = 1000  # the U portion of the circuit has 1000 total gates
    count = 10000  # we search over 10000 randomly generated circuits

    rng = random.Random(1000)  # initialize pseudo-random number generator

    measured_qubits = 8  # we are going to measure qubits 0-7 (inclusive)
    aArray = np.zeros(
        measured_qubits, dtype=np.uint8
    )  # we are computing the probability for the outcome 00000000

    effectiveT = 32
    beta = np.log2(4. - 2. * np.sqrt(2.))
    total_extent = np.power(
        2, beta * effectiveT
    )  # phase gates have extent that varies with the phase so we can tune the T(theta) gates such that we get an extent that doesn't vary with p
    m = np.sqrt(total_extent)

    #params for Estimate
    epsTot = 0.1
    deltaTot = 0.001

    max_r = 8  # the maximum r we will allow we will search random circuits until we find one with r=8, we search for relatively small r as large ones can be efficiently computed by the Compute algorithm

    for i, U in enumerate(
            util.random_clifford_circuits_with_bounded_T(
                qubits, depth, count, t_U,
                rng)):  # generate our random U circuits
        # our circuit is U U^dagger V(p)
        uDagger = U.inverse()
        circ = CompositeCliffordGate()
        circ.gates = U.gates + uDagger.gates

        for j in range(measured_qubits):
            circ.gates.append(HGate(j))
            circ.gates.append(TGate(j))
            circ.gates.append(HGate(j))

        gates, controls, targets = util.convert_circuit_to_numpy_arrays(circ)

        #here we are interested in the performance without imposing the region c constraints detailed in appendix G of the manuscript
        #since we make no guarantees that the arrrays will not be changed by the code it is a good idea to copy them
        #particuarly since we want to pass the same ones to the estimate algorithm later
        d, r, t, delta_d, delta_t, delta_t_prime, final_d, final_t, v, CH, AG = clifford_t_estim.compress_algorithm_no_region_c_constraints(
            qubits, measured_qubits, np.copy(gates), np.copy(controls),
            np.copy(targets), np.copy(aArray))

        if r <= max_r:  # we have searched a bunch of circuits and found one with a low enough r that we're interested in it
            #now we compute the phases we need for our T(phi) and T(theta) gates

            phases = np.zeros(
                40, dtype=np.float64)  # 40 = 16 + 16 + 8 for U, U^dagger and V

            phi = np.arccos(
                np.power(p, 1. / 16)
            ) * 2  # it is easy to compute what phi you need for a given p

            #it is more complicated to compute what theta you need but the function is monotone so we can do interval bisection
            sqrt_remaining_extent_per_t = np.sqrt(
                4 - 2 * np.sqrt(2)) / np.power(
                    np.sqrt(1 - np.sin(phi)) + np.sqrt(1 - np.cos(phi)),
                    1 / 4.)
            precision = 1e-15
            lower_bound = 0
            upper_bound = np.pi / 4

            width = upper_bound - lower_bound
            midpoint = lower_bound + width / 2.
            while width > precision:
                midpoint = lower_bound + width / 2.
                if np.sqrt(1 - np.sin(midpoint)) + np.sqrt(
                        1 - np.cos(midpoint)) > sqrt_remaining_extent_per_t:
                    upper_bound = midpoint
                else:
                    lower_bound = midpoint
                width = upper_bound - lower_bound
            theta = midpoint

            for k in range(32):
                phases[k] = theta
            for k in range(32, 40):
                phases[k] = phi
            return estimate.estimate_with_phases(
                epsTot,
                deltaTot,
                t,
                measured_qubits,
                r,
                v,
                m,
                CH,
                AG,
                phases,
                seed=None,
                threads=threads,
                print_round_by_round=print_round_by_round)
Ejemplo n.º 2
0
from gates import SGate, CXGate, CZGate, HGate
from gates import TGate

import util

import clifford_t_estim  # this is the module containing out C code

import estimate  # the python estimate code wraps the C implementation of RawEstim

if __name__ == "__main__":

    #first setup a simple quantum circuit
    #note our initial state is always |0>^n = [1,0,0....0]
    qubits = 2
    circ = HGate(0) | TGate(0) | HGate(0)

    #we have two qubits labelled 0 and 1, we don't do anything to one of them and the other gets H T H applied
    # H T H corresponds to a rotation about the X axis of the Bloch sphere by pi/4
    #following this rotation the probability of obtaining the outcome 0 in a computational-basis measurement of the first qubit is (1 + 1/sqrt(2))/2, roughly 0.854

    # the c code is given the circuit in the form of 3 numpy arrays, for convenience this function does the transformation
    gates, controls, targets = util.convert_circuit_to_numpy_arrays(circ)

    measured_qubits = 1  #we measure only the first qubit

    measurement_outcome = numpy.array(
        [0],
        dtype=numpy.uint8)  # we seek the probability for measurement outcome 0

    d, r, t, delta_d, delta_t, delta_t_prime, final_d, final_t, v, pyChState, pyAGState, magic_arr = clifford_t_estim.compress_algorithm(