Пример #1
0
def simulate_buckets(tensor_expr, data_dict, slice_dict):
    numpy_buckets = npfr.get_sliced_np_buckets(tensor_expr, data_dict,
                                               slice_dict)
    print(numpy_buckets)
    print("Output tensor:", numpy_buckets[0][0].data)
    print("Input tensor:", numpy_buckets[-2][0].data)
    result = optimizer.bucket_elimination(numpy_buckets,
                                          npfr.process_bucket_np)
    return result.data
Пример #2
0
def eval_with_np(filename, initial_state=0):
    """
    Loads circuit from file and evaluates all amplitudes
    using the bucket elimination algorithm (with Numpy tensors).
    Same amplitudes are evaluated with Cirq for comparison.
    """
    # Prepare graphical model
    n_qubits, circuit = ops.read_circuit_file(filename)
    buckets, data_dict, bra_vars, ket_vars = opt.circ2buckets(
        n_qubits, circuit)

    graph = gm.buckets2graph(
        buckets,
        ignore_variables=bra_vars+ket_vars)

    # Run quickbb
    peo, treewidth = gm.get_peo(graph)
    # place bra and ket variables to beginning, so these variables
    # will be contracted first
    peo = ket_vars + bra_vars + peo
    perm_buckets, perm_dict = opt.reorder_buckets(buckets, peo)

    # extract bra and ket variables from variable list and sort according
    # to qubit order
    ket_vars = sorted([perm_dict[idx] for idx in ket_vars], key=str)
    bra_vars = sorted([perm_dict[idx] for idx in bra_vars], key=str)

    # Take the subtensor corresponding to the initial state
    slice_dict = utils.slice_from_bits(initial_state, ket_vars)

    amplitudes = []
    for target_state in range(2**n_qubits):
        # Take appropriate subtensors for different target bitstrings
        slice_dict.update(
            utils.slice_from_bits(target_state, bra_vars)
        )
        sliced_buckets = npfr.get_sliced_np_buckets(
            perm_buckets, data_dict, slice_dict)
        result = opt.bucket_elimination(
            sliced_buckets, npfr.process_bucket_np)
        amplitudes.append(result.data)

    # Cirq returns the amplitudes in big endian (largest bit first)

    amplitudes_reference = get_amplitudes_from_cirq(
        filename, initial_state)
    print('Result:')
    print(np.round(np.array(amplitudes), 3))
    print('Reference:')
    print(np.round(np.array(amplitudes_reference), 3))
    print('Max difference:')
    print(np.max(np.abs(
        np.array(amplitudes) - np.array(amplitudes_reference))))
Пример #3
0
def test_bucket_operation_speed():
    """
    This tests the speed of forming, permuting and transforming
    buckets.
    """
    import time
    tim1 = time.time()

    filename = 'test_circuits/inst/cz_v2/10x10/inst_10x10_60_1.txt'

    # Prepare graphical model
    n_qubits, circuit = ops.read_circuit_file(filename)
    buckets, data_dict, bra_vars, ket_vars = opt.circ2buckets(
        n_qubits, circuit)

    graph = gm.buckets2graph(
        buckets,
        ignore_variables=bra_vars+ket_vars)

    # Get peo
    peo = [opt.Var(node, name=data['name'], size=data['size']) for
           node, data in graph.nodes(data=True)]
    peo = list(np.random.permutation(peo))

    # place bra and ket variables to beginning, so these variables
    # will be contracted first
    peo = ket_vars + bra_vars + peo
    perm_buckets, perm_dict = opt.reorder_buckets(buckets, peo)

    # extract bra and ket variables from variable list and sort according
    # to qubit order
    ket_vars = sorted([perm_dict[idx] for idx in ket_vars], key=str)
    bra_vars = sorted([perm_dict[idx] for idx in bra_vars], key=str)

    # Take the subtensor corresponding to the initial state
    initial_state = 0
    slice_dict = utils.slice_from_bits(initial_state, ket_vars)

    # Take appropriate subtensors for target bitstring
    target_state = 0
    slice_dict.update(
        utils.slice_from_bits(target_state, bra_vars)
    )
    # Form final buckets
    sliced_buckets = npfr.get_sliced_np_buckets(
        perm_buckets, data_dict, slice_dict)

    tim2 = time.time()
    print(tim2 - tim1)
Пример #4
0
def eval_circuit(n_qubits, circuit, final_state,
                 initial_state=0, measured_final=None,
                 measured_initial=None, pdict={}):
    """
    Evaluate a circuit with specified initial and final states.

    Parameters
    ----------
    n_qubits: int
              Number of qubits in the circuit
    circuit: list of lists
             List of lists of gates
    final_state: int
             Values of measured qubits at the end of the circuit (bra).
             Bitwise coded with the length of
             min(n_qubits, len(measured_final)
    initial_state: int
             Values of the measured qubits at the beginning of the
             circuit (ket). Bitwise coded with the length of
             min(n_qubits, len(measured_initial)
    measured_final: list, default None
             Iterable with the positions of qubits which are measured. If
             not all qubits are measured, then a subset of amplitudes will
             be evaluated
    measured_initial: list, default None
             Iterable with the positions of qubits which are measured
             initially. If not all are measured, then the resulting
             amplitudes will be evaluated for a subset of initial states.
    pdict: dict, default {}
    Returns
    -------
    amplitudes: numpy.array
    """
    # Check which qubits are measured
    all_qubits = set(range(n_qubits))
    if measured_final is None:
        measured_final = tuple(range(n_qubits))
    else:
        if not set(measured_final).issubset(all_qubits):
            raise ValueError(f'measured_final qubits outside allowed'
                             f' range: {measured_final}')

    if measured_initial is None:
        measured_initial = tuple(range(n_qubits))
    else:
        if not set(measured_initial).issubset(all_qubits):
            raise ValueError(f'measured_initial qubits outside allowed'
                             f' range: {measured_initial}')

    # Prepare graphical model
    buckets, data_dict, bra_vars, ket_vars = opt.circ2buckets(
        n_qubits, circuit, pdict=pdict)

    # Collect free qubit variables
    free_final = sorted(all_qubits - set(measured_final))
    free_bra_vars = [bra_vars[idx] for idx in free_final]
    bra_vars = [bra_vars[idx] for idx in measured_final]

    free_initial = sorted(all_qubits - set(measured_initial))
    free_ket_vars = [ket_vars[idx] for idx in free_initial]
    ket_vars = [ket_vars[idx] for idx in measured_initial]

    if len(free_bra_vars) > 0:
        log.info('Evaluate amplitudes over all final states of qubits:')
        log.info(f'{free_final}')

    if len(free_ket_vars) > 0:
        log.info('Evaluate amplitudes over all initial states of qubits:')
        log.info(f'{free_initial}')

    graph_initial = gm.buckets2graph(
        buckets,
        ignore_variables=bra_vars+ket_vars)

    graph = gm.make_clique_on(graph_initial, free_bra_vars+free_ket_vars)

    # Get PEO
    peo_initial, treewidth = gm.get_peo(graph)

    # transform peo so free_bra_vars and free_ket_vars are at the end
    # this fixes the layout of the tensor
    peo = gm.get_equivalent_peo(graph, peo_initial,
                                free_bra_vars+free_ket_vars)

    # place bra and ket variables to beginning, so these variables
    # will be contracted first
    perm_buckets, perm_dict = opt.reorder_buckets(
        buckets, bra_vars + ket_vars + peo)
    perm_graph, _ = gm.relabel_graph_nodes(
        graph, perm_dict)

    # extract bra and ket variables from variable list and sort according
    # to qubit order
    ket_vars = sorted([perm_dict[idx] for idx in ket_vars], key=str)
    bra_vars = sorted([perm_dict[idx] for idx in bra_vars], key=str)

    # make proper slice dictionaries. We choose ket = |0>,
    # bra = |0> on fixed entries
    slice_dict = utils.slice_from_bits(initial_state, ket_vars)
    slice_dict.update(utils.slice_from_bits(final_state, bra_vars))
    slice_dict.update({var: slice(None) for var in free_bra_vars})
    slice_dict.update({var: slice(None) for var in free_ket_vars})

    # Finally make numpy buckets and calculate
    sliced_buckets = npfr.get_sliced_np_buckets(
        perm_buckets, data_dict, slice_dict)
    result = opt.bucket_elimination(
        sliced_buckets, npfr.process_bucket_np,
        n_var_nosum=len(free_bra_vars+free_ket_vars))

    return result.data
Пример #5
0
 def get_sliced_buckets(self, buckets, data_dict, slice_dict):
     return np_framework.get_sliced_np_buckets(buckets, data_dict,
                                               slice_dict)
Пример #6
0
from qtree import optimizer

tensor_expr, data_dict, bra, ket = optimizer.circ2buckets(1, [[myGate]])
print(tensor_expr)
print(data_dict)
print(bra)
print(ket)
# -

from qtree import np_framework as npfr

# ## Sum of all amplitudes for all inputs
#
# This is just a full contraction of the tensor network

numpy_buckets = npfr.get_sliced_np_buckets(tensor_expr, data_dict, {})
numpy_buckets

result = optimizer.bucket_elimination(numpy_buckets, npfr.process_bucket_np)
result

result.data

# ## Sum of amplitudes for single input
#
# This is a contraction of a network that was sliced over input indices

initial_state = 0
slice_dict = qtree.utils.slice_from_bits(initial_state, ket)
slice_dict
Пример #7
0
def eval_with_multiamp_np(filename, initial_state=0):
    """
    Loads circuit from file and evaluates
    multiple amplitudes at once using np framework
    """
    # Values of the fixed bra qubits.
    # this can be changed to your taste
    target_state = 0

    # Prepare graphical model
    n_qubits, circuit = ops.read_circuit_file(filename)
    buckets, data_dict, bra_vars, ket_vars = opt.circ2buckets(
        n_qubits, circuit)

    # Collect free qubit variables
    free_final_qubits = [1, 3]
    free_bra_vars = []
    for ii in free_final_qubits:
        try:
            free_bra_vars.append(bra_vars[ii])
        except IndexError:
            pass
    bra_vars = [var for var in bra_vars if var not in free_bra_vars]

    if len(free_bra_vars) > 0:
        print('Evaluate all amplitudes over final qubits:')
        print(free_final_qubits)
        print('Free variables in the resulting expression:')
        print(free_bra_vars)

    graph_initial = gm.buckets2graph(
        buckets,
        ignore_variables=bra_vars+ket_vars)

    graph = gm.make_clique_on(graph_initial, free_bra_vars)

    # Run quickbb
    peo_initial, treewidth = gm.get_peo(graph)

    # transform peo so free_bra_vars are at the end
    peo = gm.get_equivalent_peo(graph, peo_initial, free_bra_vars)

    # place bra and ket variables to beginning, so these variables
    # will be contracted first
    perm_buckets, perm_dict = opt.reorder_buckets(
        buckets, bra_vars + ket_vars + peo)
    perm_graph, _ = gm.relabel_graph_nodes(
        graph, perm_dict)

    # extract bra and ket variables from variable list and sort according
    # to qubit order
    ket_vars = sorted([perm_dict[idx] for idx in ket_vars], key=str)
    bra_vars = sorted([perm_dict[idx] for idx in bra_vars], key=str)

    # make proper slice dictionaries. We choose ket = |0>,
    # bra = |0> on fixed entries
    slice_dict = utils.slice_from_bits(initial_state, ket_vars)
    slice_dict.update(utils.slice_from_bits(target_state, bra_vars))
    slice_dict.update({var: slice(None) for var in free_bra_vars})

    # Finally make numpy buckets and calculate
    sliced_buckets = npfr.get_sliced_np_buckets(
        perm_buckets, data_dict, slice_dict)
    result = opt.bucket_elimination(
        sliced_buckets, npfr.process_bucket_np,
        n_var_nosum=len(free_bra_vars))
    amplitudes = result.data.flatten()

    # Now calculate the reference
    amplitudes_reference = get_amplitudes_from_cirq(filename)

    # Get a slice as we do not need full amplitude
    bra_slices = {var: slice_dict[var] for var in slice_dict
                  if var.name.startswith('o')}

    # sort slice in the big endian order for Cirq
    computed_subtensor = [slice_dict[var]
                          for var in sorted(bra_slices, key=str)]

    slice_of_amplitudes = amplitudes_reference.reshape(
        [2]*n_qubits)[tuple(computed_subtensor)]
    slice_of_amplitudes = slice_of_amplitudes.flatten()

    print('Result:')
    print(np.round(amplitudes, 3))
    print('Reference:')
    print(np.round(slice_of_amplitudes, 3))
    print('Max difference:')
    print(np.max(np.abs(amplitudes - slice_of_amplitudes)))
Пример #8
0
def eval_with_np_parallel_mpi(filename, initial_state=0):
    """
    Evaluate quantum circuit using MPI to parallelize
    over some of the variables.
    """
    comm = MPI.COMM_WORLD
    comm_size = comm.size
    rank = comm.rank

    # number of variables to split by parallelization
    # this should be adjusted by the algorithm from memory/cpu
    # requirements
    n_var_parallel = 2
    if rank == 0:
        env = prepare_parallel_evaluation_np(filename, n_var_parallel)
    else:
        env = None

    env = comm.bcast(env, root=0)

    # restore buckets
    buckets = env['buckets']

    # restore other parts of the environment
    bra_vars = env['bra_vars']
    ket_vars = env['ket_vars']
    vars_parallel = env['vars_parallel']

    # restore data dictionary
    data_dict = env['data_dict']

    # Construct slice dictionary for initial state
    slice_dict = utils.slice_from_bits(initial_state, ket_vars)

    # Loop over all amplitudes
    amplitudes = []
    for target_state in range(2**len(bra_vars)):
        # Construct slice dictionary for the target state
        slice_dict.update(
            utils.slice_from_bits(target_state, bra_vars))

        # main computation loop. Populate respective slices
        # and do contraction

        amplitude = 0
        for parallel_slice_dict in utils.slice_values_generator(
                vars_parallel, rank, comm_size):
            slice_dict.update(parallel_slice_dict)
            sliced_buckets = npfr.get_sliced_np_buckets(
                buckets, data_dict, slice_dict)
            result = opt.bucket_elimination(
                sliced_buckets, npfr.process_bucket_np)

            amplitude += result.data

        amplitude = comm.reduce(amplitude, op=MPI.SUM, root=0)
        amplitudes.append(amplitude)

    if rank == 0:
        amplitudes_reference = get_amplitudes_from_cirq(filename)
        print('Result:')
        print(np.round(np.array(amplitudes), 3))
        print('Reference:')
        print(np.round(amplitudes_reference, 3))
        print('Max difference:')
        print(np.max(np.array(amplitudes)
                     - np.array(amplitudes_reference)))