コード例 #1
0
def metadata_save(qc: QuantumComputer,
                  repo_path: str = None,
                  filename: str = None) -> pd.DataFrame:
    '''
    This helper function saves metadata related to your run on a Quantum computer.

    Basic data saved includes the date and time. Additionally information related to the quantum
    computer is saved: device name, topology, qubit labels, edges that have two qubit gates,
    device specs

    If a path is passed to this function information related to the Git Repository is saved,
    specifically the repository: name, branch and commit.

    :param qc: The QuantumComputer to run the experiment on.
    :param repo_path: path to repository e.g. '../'
    :param filename: The name of the file to write JSON-serialized results to.
    :return: pandas DataFrame
    '''

    # Git related things
    if repo_path is not None:
        repo = Repo(repo_path)
        branch = repo.active_branch
        sha = repo.head.object.hexsha
        short_sha = repo.git.rev_parse(sha, short=7)
        the_repo = repo.git_dir
        the_branch = branch.name
        the_commit = short_sha
    else:
        the_repo = None
        the_branch = None
        the_commit = None

    metadata = {
        # Time and date
        'Date': str(date.today()),
        'Time': str(datetime.now().time()),
        # Git stuff
        'Repository': the_repo,
        'Branch': the_branch,
        'Git_commit': the_commit,
        # QPU data
        'Device_name': qc.name,
        'Topology': qc.qubit_topology(),
        'Qubits': list(qc.qubit_topology().nodes),
        'Two_Qubit_Gates': list(qc.qubit_topology().edges),
        'Device_Specs': qc.device.get_specs(),
    }
    if filename:
        pd.DataFrame(metadata).to_json(filename)
    return pd.DataFrame(metadata)
コード例 #2
0
def get_qubit_registers_for_adder(qc: QuantumComputer, num_length: int,
                                  qubits: Optional[Sequence[int]] = None)\
        -> Tuple[Sequence[int], Sequence[int], int, int]:
    """
    Searches for a layout among the given qubits for the two n-bit registers and two additional
    ancilla that matches the simple layout given in figure 4 of [CDKM96]_.

    This method ignores any considerations of physical characteristics of the qc aside from the
    qubit layout. An error is thrown if the appropriate layout is not found.

    :param qc: the quantum resource on which an adder program will be executed.
    :param num_length: the length of the bitstring representation of one summand
    :param qubits: the available qubits on which to run the adder program.
    :return: the necessary registers and ancilla labels for implementing an adder
        program to add the numbers a and b. The output can be passed directly to :func:`adder`
    """
    if qubits is None:
        unavailable = []  # assume this means all qubits in qc are available
    else:
        unavailable = [qubit for qubit in qc.qubits() if qubit not in qubits]

    graph = qc.qubit_topology().copy()
    for qubit in unavailable:
        graph.remove_node(qubit)

    # network x only provides subgraph isomorphism, but we want a subgraph monomorphism, i.e. we
    # specifically want to match the edges desired_layout with some subgraph of graph. To
    # accomplish this, we swap the nodes and edges of graph by making a line graph.
    line_graph = nx.line_graph(graph)

    # We want a path of n nodes, which has n-1 edges. Since we are matching edges of graph with
    # nodes of layout we make a layout of n-1 nodes.
    num_desired_nodes = 2 * num_length + 2
    desired_layout = nx.path_graph(num_desired_nodes - 1)

    g_matcher = nx.algorithms.isomorphism.GraphMatcher(line_graph,
                                                       desired_layout)

    try:
        # pick out a subgraph isomorphic to the desired_layout if one exists
        # this is an isomorphic mapping from edges in graph (equivalently nodes of line_graph) to
        # nodes in desired_layout (equivalently edges of a path graph with one more node)
        edge_iso = next(g_matcher.subgraph_isomorphisms_iter())
    except IndexError:
        raise Exception(
            "An appropriate layout for the qubits could not be found among the "
            "provided qubits.")

    # pick out the edges of the isomorphism from the original graph
    subgraph = nx.Graph(graph.edge_subgraph(edge_iso.keys()))

    # pick out an endpoint of our path to start the assignment
    start_node = -1
    for node in subgraph.nodes:
        if subgraph.degree(node) == 1:  # found an endpoint
            start_node = node
            break

    return assign_registers_to_line_or_cycle(start_node, subgraph, num_length)
コード例 #3
0
def test_device_stuff():
    topo = nx.from_edgelist([(0, 4), (0, 99)])
    qc = QuantumComputer(
        name='testy!',
        qam=None,  # not necessary for this test
        device=NxDevice(topo),
        compiler=DummyCompiler())
    assert nx.is_isomorphic(qc.qubit_topology(), topo)

    isa = qc.get_isa(twoq_type='CPHASE')
    assert sorted(isa.edges)[0].type == 'CPHASE'
    assert sorted(isa.edges)[0].targets == [0, 4]
コード例 #4
0
def process_characterisation(qc: QuantumComputer) -> dict:
    """Convert a :py:class:`pyquil.api.QuantumComputer` to a dictionary containing
    Rigetti device Characteristics

    :param qc: A quantum computer to be converted
    :type qc: QuantumComputer
    :return: A dictionary containing Rigetti device characteristics
    """
    specs = qc.device.get_specs()

    coupling_map = [[n, ni]
                    for n, neigh_dict in qc.qubit_topology().adjacency()
                    for ni, _ in neigh_dict.items()]

    node_ers_dict = {}
    link_ers_dict = {}
    t1_times_dict = {}
    t2_times_dict = {}

    device_node_fidelities = specs.f1QRBs()  # type: ignore
    device_link_fidelities = specs.fCZs()  # type: ignore
    device_fROs = specs.fROs()  # type: ignore
    device_t1s = specs.T1s()  # type: ignore
    device_t2s = specs.T2s()  # type: ignore

    for index in qc.qubits():
        error_cont = QubitErrorContainer({OpType.Rx, OpType.Rz})
        error_cont.add_readout(1 - device_fROs[index])  # type: ignore
        t1_times_dict[index] = device_t1s[index]
        t2_times_dict[index] = device_t2s[index]
        error_cont.add_error(
            (OpType.Rx, 1 - device_node_fidelities[index]))  # type: ignore
        # Rigetti use frame changes for Rz, so they effectively have no error.
        node_ers_dict[Node(index)] = error_cont

    for (a, b), fid in device_link_fidelities.items():
        error_cont = QubitErrorContainer({OpType.CZ})
        error_cont.add_error((OpType.CZ, 1 - fid))  # type: ignore
        link_ers_dict[(Node(a), Node(b))] = error_cont
        link_ers_dict[(Node(b), Node(a))] = error_cont

    arc = Architecture(coupling_map)

    characterisation = dict()
    characterisation["NodeErrors"] = node_ers_dict
    characterisation["EdgeErrors"] = link_ers_dict
    characterisation["Architecture"] = arc
    characterisation["t1times"] = t1_times_dict
    characterisation["t2times"] = t2_times_dict

    return characterisation
コード例 #5
0
topology = nx.from_edgelist([
    (10, 2),
    (10, 4),
    (10, 6),
    (10, 8),
])

device = NxDevice(topology)


class MyLazyCompiler(AbstractCompiler):
    def quil_to_native_quil(self, program, *, protoquil=None):
        return program

    def native_quil_to_executable(self, nq_program):
        return nq_program


my_qc = QuantumComputer(
    name='my-qvm',
    qam=QVM(connection=ForestConnection()),
    device=device,
    compiler=MyLazyCompiler(),
)

nx.draw(my_qc.qubit_topology())
plt.title('5qcm', fontsize=18)
plt.show()

my_qc.run_and_measure(Program(X(10)), trials=5)