Exemplo n.º 1
0
def test_circ2graph(filename='inst_2x2_7_0.txt'):
    """
    This function tests direct reading of circuits to graphs.
    It should be noted that graphs can not to be used in place
    of buckets yet, since the information about transpositions
    of tensors (denoted by edges) is not kept during node
    relabelling
    """
    import networkx as nx

    nq, circuit = ops.read_circuit_file(filename)
    graph = gm.circ2graph(nq, circuit)

    n_qubits, circuit = ops.read_circuit_file(filename)
    buckets_original, _, bra_vars, ket_vars = opt.circ2buckets(
        n_qubits, circuit)
    graph_original = gm.buckets2graph(
        buckets_original, ignore_variables=bra_vars+ket_vars)

    from networkx.algorithms import isomorphism
    GM = isomorphism.GraphMatcher(graph, graph_original)

    print('Isomorphic? : {}'.format(GM.is_isomorphic()))
    graph = nx.relabel_nodes(graph, GM.mapping, copy=True)

    if not GM.is_isomorphic():
        gm.draw_graph(graph, 'new_graph.png')
        gm.draw_graph(graph_original, 'orig_graph.png')

    return GM.is_isomorphic()
Exemplo n.º 2
0
def test_maximum_cardinality_search():
    """Test maximum cardinality search algorithm"""

    # Read graph
    import qtree.operators as ops
    import os
    this_dir = os.path.dirname((os.path.abspath(__file__)))
    nq, c = ops.read_circuit_file(this_dir + '/../../inst_2x2_7_0.txt')
    old_g, *_ = circ2graph(nq, c)

    # Make random clique
    vertices = list(np.random.choice(old_g.nodes, 4, replace=False))
    while is_clique(old_g, vertices):
        vertices = list(np.random.choice(old_g.nodes, 4, replace=False))

    g = make_clique_on(old_g, vertices)

    # Make graph completion
    peo, tw = get_peo(g)
    g_chordal = get_fillin_graph2(g, peo)

    # MCS will produce alternative PEO with this clique at the end
    new_peo = maximum_cardinality_search(g_chordal, list(vertices))

    # Test if new peo is correct
    assert is_peo_zero_fillin(g_chordal, peo)
    assert is_peo_zero_fillin(g_chordal, new_peo)
    new_tw = get_treewidth_from_peo(g, new_peo)
    assert tw == new_tw

    print('peo:', peo)
    print('new_peo:', new_peo)
Exemplo n.º 3
0
def test_tree_from_peo(filename='inst_2x2_7_0.txt'):
    import qtree.operators as ops
    nq, c = ops.read_circuit_file(filename)
    graph, *_ = circ2graph(nq, c, omit_terminals=False)

    peo, _ = get_peo(graph)
    tree = get_tree_from_peo(get_simple_graph(graph), peo)
    elements = list(range(1, graph.number_of_nodes() + 1))

    for element in elements:
        nodes_containing_element = []
        for node in tree.nodes():
            if element in node:
                nodes_containing_element.append(node)

        subtree = nx.subgraph(tree, nodes_containing_element)
        if subtree.number_of_nodes() > 0:
            connected = nx.connected.is_connected(subtree)
        else:
            connected = True  # Take empty graph as connected
        if not connected:
            # draw_graph(subtree, f"st_{element}")
            pass

    draw_graph(tree, f"tree")
Exemplo n.º 4
0
def test_bucket_graph_conversion(filename):
    """
    Test the conversion between Buckets and the contraction multigraph
    """
    import qtree.graph_model as gm

    # load circuit
    n_qubits, circuit = ops.read_circuit_file(filename)
    buckets, data_dict, bra_vars, ket_vars = circ2buckets(n_qubits, circuit)
    graph, *_ = gm.importers.circ2graph(n_qubits,
                                        circuit,
                                        omit_terminals=False)

    graph_from_buckets = gm.importers.buckets2graph(buckets)
    buckets_from_graph = graph2buckets(graph)

    buckets_equal = True
    for b1, b2 in zip(buckets, buckets_from_graph):
        if sorted(b1) != sorted(b2):
            buckets_equal = False
            break

    print('C->B, C->G->B: Buckets equal? : {}'.format(buckets_equal))
    print('C->G, C->B->G: Graphs equal? : {}'.format(
        nx.is_isomorphic(graph, graph_from_buckets)))
Exemplo n.º 5
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))))
Exemplo n.º 6
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)
Exemplo n.º 7
0
def eval_contraction_cost(filename):
    """
    Loads circuit from file, evaluates contraction cost
    with and without optimization
    """
    # Prepare graphical model
    n_qubits, circuit = ops.read_circuit_file(filename)
    buckets, data_dict, bra_vars, ket_vars = opt.circ2buckets(
        n_qubits, circuit)

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

    # estimate cost
    mem_raw, flop_raw = gm.get_contraction_costs(graph_raw)
    mem_raw_tot = sum(mem_raw)

    # optimize node order
    peo, treewidth = gm.get_peo(graph_raw)

    # get cost for reordered graph
    graph, label_dict = gm.relabel_graph_nodes(
        graph_raw, dict(zip(peo, sorted(graph_raw.nodes(), key=int)))
    )
    mem_opt, flop_opt = gm.get_contraction_costs(graph)
    mem_opt_tot = sum(mem_opt)

    # split graph and relabel in optimized way
    n_var_parallel = 3
    _, reduced_graph = gm.split_graph_by_metric(
        graph_raw, n_var_parallel)
    # peo, treewidth = gm.get_peo(reduced_graph)
    peo, treewidth = gm.get_peo(reduced_graph)

    graph_parallel, label_dict = gm.relabel_graph_nodes(
        reduced_graph, dict(zip(
            peo, sorted(reduced_graph.nodes(), key=int)))
    )

    mem_par, flop_par = gm.get_contraction_costs(graph_parallel)
    mem_par_tot = sum(mem_par)

    print('Memory (in doubles):\n raw: {} optimized: {}'.format(
        mem_raw_tot, mem_opt_tot))
    print(' parallel:\n  node: {} total: {} n_tasks: {}'.format(
        mem_par_tot, mem_par_tot*2**(n_var_parallel),
        2**(n_var_parallel)
    ))
Exemplo n.º 8
0
def get_optimal_graphical_model(
        filename):
    """
    Builds a graphical model to contract a circuit in ``filename``
    and finds its tree decomposition
    """
    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)
    peo, tw = gm.get_peo(graph)
    graph_optimal, label_dict = gm.relabel_graph_nodes(
        graph, dict(zip(peo, range(1, len(peo) + 1)))
    )
    return graph_optimal
Exemplo n.º 9
0
def test_is_clique():
    """Test is_clique"""
    import qtree.operators as ops
    import os
    this_dir = os.path.dirname((os.path.abspath(__file__)))
    nq, c = ops.read_circuit_file(this_dir + '/../../inst_2x2_7_0.txt')
    g, *_ = circ2graph(nq, c)

    # select some random vertices
    vertices = list(np.random.choice(g.nodes, 4, replace=False))
    while is_clique(g, vertices):
        vertices = list(np.random.choice(g.nodes, 4, replace=False))

    g_new = make_clique_on(g, vertices)

    assert is_clique(g_new, vertices)
Exemplo n.º 10
0
def prepare_parallel_evaluation_np(filename, n_var_parallel):
    """
    Prepares for parallel evaluation of the quantum circuit.
    Some of the variables in the circuit are parallelized over.
    Unsliced Numpy buckets in the optimal order of elimination
    are returned
    """
    # import pdb
    # pdb.set_trace()
    # 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)

    # find a reduced graph
    vars_parallel, graph_reduced = gm.split_graph_by_metric_greedy(
        graph, n_var_parallel,
        metric_fn=gm.splitters.get_node_by_mem_reduction)

    # run quickbb once again to get peo and treewidth
    peo, treewidth = gm.get_peo(graph_reduced)

    # place bra and ket variables to beginning, so these variables
    # will be contracted first
    peo = ket_vars + bra_vars + vars_parallel + 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)
    vars_parallel = sorted([perm_dict[idx] for idx in vars_parallel],
                           key=str)

    environment = dict(
        bra_vars=bra_vars,
        ket_vars=ket_vars,
        vars_parallel=vars_parallel,
        buckets=perm_buckets,
        data_dict=data_dict,
    )

    return environment
Exemplo n.º 11
0
def get_amplitudes_from_cirq(filename, initial_state=0):
    """
    Calculates amplitudes for a circuit in file filename using Cirq
    """
    n_qubits, circuit = ops.read_circuit_file(filename)

    cirq_circuit = cirq.Circuit()

    for layer in circuit:
        cirq_circuit.append(op.to_cirq_1d_circ_op() for op in layer)

    print("Circuit:")
    print(cirq_circuit)
    simulator = cirq.Simulator()

    result = simulator.simulate(cirq_circuit, initial_state=initial_state)
    print("Simulation completed\n")

    # Cirq for some reason computes all amplitudes with phase -1j
    return result.final_state
Exemplo n.º 12
0
def test_is_zero_fillin():
    """
    Test graph filling using the elimination order
    """
    import time
    import qtree.operators as ops
    import os
    this_dir = os.path.dirname((os.path.abspath(__file__)))
    nq, c = ops.read_circuit_file(
        this_dir + '/../../test_circuits/inst/cz_v2/10x10/inst_10x10_60_1.txt')
    g, *_ = circ2graph(nq, c, omit_terminals=False)

    g1 = get_fillin_graph(g, list(range(g.number_of_nodes())))

    tim1 = time.time()
    print(is_peo_zero_fillin(g1, list(range(g.number_of_nodes()))))
    tim2 = time.time()
    print(is_peo_zero_fillin2(g1, list(range(g.number_of_nodes()))))
    tim3 = time.time()

    print(tim2 - tim1, tim3 - tim2)
Exemplo n.º 13
0
def test_get_fillin_graph():
    """
    Test graph filling using the elimination order
    """
    import time
    import qtree.operators as ops
    import os
    this_dir = os.path.dirname((os.path.abspath(__file__)))
    nq, c = ops.read_circuit_file(
        this_dir + '/../../test_circuits/inst/cz_v2/10x10/inst_10x10_60_1.txt'
        # 'inst_2x2_7_1.txt'
    )
    g, *_ = circ2graph(nq, c, omit_terminals=False)

    peo = np.random.permutation(g.nodes)

    tim1 = time.time()
    g1 = get_fillin_graph(g, list(peo))
    tim2 = time.time()
    g2 = get_fillin_graph2(g, list(peo))
    tim3 = time.time()

    assert nx.is_isomorphic(g1, g2)
    print(tim2 - tim1, tim3 - tim2)
Exemplo n.º 14
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)))
Exemplo n.º 15
0
def prepare_parallel_evaluation_tf(filename, n_var_parallel):
    """
    Prepares for parallel evaluation of the quantum circuit.
    Some of the variables in the circuit are parallelized over.
    Symbolic bucket elimination is performed with tensorflow and
    the resulting computation graph (as GraphDef) and other
    supporting information is returned
    """
    # 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)

    # find a reduced graph
    vars_parallel, graph_reduced = gm.split_graph_by_metric(
        graph, n_var_parallel,
        metric_fn=gm.splitters.get_node_by_mem_reduction)

    # run quickbb once again to get peo and treewidth
    peo, treewidth = gm.get_peo(graph_reduced)

    # place bra and ket variables to beginning, so these variables
    # will be contracted first
    peo = ket_vars + bra_vars + vars_parallel + 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)
    vars_parallel = sorted([perm_dict[idx] for idx in vars_parallel],
                           key=str)

    # Populate slice dict. Only shapes of slices are needed at this stage
    slice_dict = utils.slice_from_bits(
        0, bra_vars + ket_vars + vars_parallel)

    # create placeholders with proper shapes
    tf.reset_default_graph()
    tf_buckets, placeholders_dict = tffr.get_sliced_tf_buckets(
        perm_buckets, slice_dict)
    # save only placeholder's names as they are not picklable
    picklable_placeholders = {key.name: val for key, val in
                              placeholders_dict.items()}

    # Do symbolic computation of the result
    result = opt.bucket_elimination(
        tf_buckets, tffr.process_bucket_tf)
    comput_graph = tf.identity(result.data, name='result')

    environment = dict(
        bra_vars=bra_vars,
        ket_vars=ket_vars,
        vars_parallel=vars_parallel,
        tf_graph_def=tf.get_default_graph().as_graph_def(),
        data_dict=data_dict,
        picklable_placeholders=picklable_placeholders
    )

    return environment
Exemplo n.º 16
0
def eval_with_tf(filename, initial_state=0):
    """
    Loads circuit from file and evaluates all amplitudes
    using the bucket elimination algorithm (with tensorflow 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)

    # Populate slice dict. Only shapes of slices are needed at this stage
    slice_dict = utils.slice_from_bits(initial_state, ket_vars)
    slice_dict.update(utils.slice_from_bits(
        initial_state, bra_vars))

    # create placeholders with proper shapes
    tf_buckets, placeholders_dict = tffr.get_sliced_tf_buckets(
        perm_buckets, slice_dict)

    # build the Tensorflow operation graph
    result = opt.bucket_elimination(
        tf_buckets, tffr.process_bucket_tf)
    comput_graph = result.data

    # prepare static part of the feed_dict
    feed_dict = tffr.assign_tensor_placeholders(
        placeholders_dict, data_dict)

    amplitudes = []
    for target_state in range(2**n_qubits):
        # Now the bounds of slices are needed
        slice_dict.update(
            utils.slice_from_bits(target_state, bra_vars))
        # populate feed dict with slice variables
        feed_dict.update(tffr.assign_variable_placeholders(
            placeholders_dict, slice_dict))

        amplitude = tffr.run_tf_session(comput_graph, feed_dict)
        amplitudes.append(amplitude)

    amplitudes_reference = get_amplitudes_from_cirq(filename,
                                                    initial_state)
    print('Result:')
    print(np.round(np.array(amplitudes), 3))
    print('Reference:')
    print(np.round(amplitudes_reference, 3))
    print('Max difference:')
    print(np.max(np.abs(amplitudes - np.array(amplitudes_reference))))
Exemplo n.º 17
0
def test_eval_circuit(filename='inst_2x2_7_0.txt'):
    import numpy as np

    initial_state = 0
    final_state = 0
    measured_initial = [1, 2, 3]
    measured_final = [0, 1, 2, 3]

    # prepare reference
    # calculate proper slices
    n_qubits, circuit = ops.read_circuit_file(filename)
    buckets, data_dict, bra_vars, ket_vars = opt.circ2buckets(
        n_qubits, circuit)

    free_bra_vars = [bra_vars[idx] for idx in range(n_qubits)
                     if idx not in measured_final]
    fixed_bra_vars = [bra_vars[idx] for idx in range(n_qubits)
                      if idx in measured_final]
    free_ket_vars = [ket_vars[idx] for idx in range(n_qubits)
                     if idx not in measured_initial]
    fixed_ket_vars = [ket_vars[idx] for idx in range(n_qubits)
                      if idx in measured_initial]

    slice_dict = utils.slice_from_bits(final_state, fixed_bra_vars)
    slice_dict.update({var: slice(None) for var in free_bra_vars})
    slice_dict.update(
        utils.slice_from_bits(initial_state, fixed_ket_vars))
    slice_dict.update({var: slice(None) for var in free_ket_vars})

    # sort slice in the big endian order for Cirq
    bra_subtensor = tuple([slice_dict[var] for var in bra_vars])
    ket_subtensor = tuple([slice_dict[var] for var in ket_vars])

    reference = np.empty([2]*n_qubits+[2]*n_qubits, dtype=np.complex64)[
        bra_subtensor + ket_subtensor]

    temp_slice_dict = utils.slice_from_bits(initial_state, fixed_ket_vars)
    for ket_state in range(2**len(free_ket_vars)):
        amplitudes = get_amplitudes_from_cirq(filename, ket_state)
        slice_of_amplitudes = amplitudes.reshape(
            [2]*n_qubits)[bra_subtensor]
        temp_slice_dict.update(
            utils.slice_from_bits(ket_state, free_ket_vars))
        partial_ket_subtensor = tuple(
            [temp_slice_dict[var] for var in ket_vars])

        final_shape = slice_of_amplitudes.shape + (1,) * n_qubits
        reference[
            bra_subtensor+partial_ket_subtensor
        ] = slice_of_amplitudes.reshape(final_shape)

    # get the result
    result = eval_circuit(n_qubits, circuit, final_state=final_state,
                          initial_state=initial_state,
                          measured_final=measured_final,
                          measured_initial=measured_initial)
    reference = reference.flatten()
    result = result.flatten()

    # difference
    print('Result:')
    print(np.round(result, 3))
    print('Reference:')
    print(np.round(reference, 3))
    print('Max difference:')
    print(np.max(np.abs(result - reference)))