Source code for mqt.ionshuttler.multi_shuttler.inside.partition
# Copyright (c) 2023 - 2026 Chair for Design Automation, TUM
# All rights reserved.
#
# SPDX-License-Identifier: MIT
#
# Licensed under the MIT License
from __future__ import annotations
from pathlib import Path
import networkx as nx
from networkx.algorithms.community import kernighan_lin_bisection
from qiskit import QuantumCircuit
from qiskit.transpiler.passes import RemoveBarriers, RemoveFinalMeasurements
[docs]
def read_qasm_file(file_path: Path) -> QuantumCircuit:
circuit = QuantumCircuit.from_qasm_file(file_path)
# Remove barriers
circuit = RemoveBarriers()(circuit)
# Remove measurement operations
return RemoveFinalMeasurements()(circuit)
[docs]
def construct_interaction_graph(circuit: QuantumCircuit) -> nx.Graph:
graph: nx.Graph = nx.Graph()
qubits = circuit.qubits
for qubit in qubits:
graph.add_node(qubit._index)
for gate in circuit.data:
if len(gate.qubits) == 2: # Check if it is a 2-qubit gate
q0 = gate[1][0]._index
q1 = gate[1][1]._index
if graph.has_edge(q0, q1):
graph[q0][q1]["weight"] += 1
else:
graph.add_edge(q0, q1, weight=1)
elif len(gate.qubits) > 2:
msg = "Circuit contains gates with more than 2 qubits"
raise ValueError(msg)
# # plot graph
# nx.draw(graph, with_labels=True)
# nx.draw_networkx_edge_labels(
# graph, pos=nx.circular_layout(graph),
# edge_labels={(u, v): d['weight'] for u, v, d in graph.edges(data=True)}
# )
# plt.show()
return graph
# def partition_graph(graph, n):
# #partitions = []
# subgraphs = [graph]
# assert n > 1, "Number of partitions must be greater than 1"
# assert n <= len(graph.nodes), "Number of partitions
# must be less than or equal to the number of nodes in the graph"
# #assert n != len(graph.nodes), "Number of partitions must
# be less than the number of nodes in the graph TODO: handle this case?"
# while len(subgraphs) < n:
# print('new iteration')
# new_subgraphs = []
# for subgraph in subgraphs:
# #print(f"Start subgraph nodes: {list(subgraph.nodes)}",
# len(subgraph)+len(new_subgraphs),
# [list(new_subg.nodes) for new_subg in new_subgraphs])
# print('len(subgraph):', len(subgraph))
# print('len(new_subgraphs):', len(new_subgraphs),'\n')
# if len(subgraphs) + len(new_subgraphs) - 1 < n:
# # handle cases where the subgraph has less
# than 2 nodes (happens if n = # of nodes)
# if len(subgraph.nodes()) < 2:
# # #print(f"Subgraph nodes: {list(subgraph.nodes)}")
# # #print(f"Subgraph edges: {list(subgraph.edges)}")
# new_subgraphs.append(subgraph)
# continue
# part1, part2 = kernighan_lin_bisection(subgraph)
# #print(f"Part1: {part1}, Part2: {part2}")
# #print(f"Subgraph nodes: {list(subgraph.nodes)}")
# #print(f"Subgraph edges: {list(subgraph.edges)}")
# new_subgraphs.append(graph.subgraph(part1).copy())
# new_subgraphs.append(graph.subgraph(part2).copy())
# else:
# new_subgraphs.append(subgraph)
# subgraphs = new_subgraphs
# #partitions = subgraphs
# return subgraphs#partitions
[docs]
def partition_graph(graph: nx.Graph, n: int) -> list[nx.Graph]:
if n == 1:
return [graph]
assert n <= len(graph.nodes), (
f"Number of partitions must be less or equal to the number of nodes {len(graph.nodes), graph.nodes, n}"
)
partitions = [graph.copy()]
new_partitions: list[nx.Graph] = []
while len(partitions) < n:
len_partitions = len(partitions)
for _, partition in enumerate(partitions):
if len_partitions + len(new_partitions) < n:
if len(partition) < 2:
new_partitions.append(partition)
len_partitions -= 1
continue
part1, part2 = kernighan_lin_bisection(partition)
new_partitions.append(graph.subgraph(part1).copy())
new_partitions.append(graph.subgraph(part2).copy())
else:
new_partitions.append(partition)
partitions = new_partitions
new_partitions = []
return partitions
[docs]
def get_partition(qasm_file_path: Path, n: int) -> list[list[int]]:
circuit = read_qasm_file(qasm_file_path)
interaction_graph = construct_interaction_graph(circuit)
partition_graphs = partition_graph(interaction_graph, n)
partition = []
for graph in partition_graphs:
partition.append(list(graph.nodes))
return partition
if __name__ == "__main__":
# Example usage
qasm_file_path = Path(__file__).absolute().parent.parent.parent.parent.parent.parent / (
"inputs/qasm_files/full_register_access/full_register_access_6.qasm"
)
n = 5
print(get_partition(qasm_file_path, n))