hdh 0.0.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- hdh-0.0.1/LICENSE +21 -0
- hdh-0.0.1/PKG-INFO +37 -0
- hdh-0.0.1/README.md +14 -0
- hdh-0.0.1/hdh/__init__.py +0 -0
- hdh-0.0.1/hdh/converters/__init__.py +0 -0
- hdh-0.0.1/hdh/converters/convert_from_qasm.py +12 -0
- hdh-0.0.1/hdh/converters/convert_from_qiskit.py +39 -0
- hdh-0.0.1/hdh/graph.py +33 -0
- hdh-0.0.1/hdh/hdh.py +59 -0
- hdh-0.0.1/hdh/passes/__init__.py +0 -0
- hdh-0.0.1/hdh/passes/cut.py +39 -0
- hdh-0.0.1/hdh/visualize.py +175 -0
- hdh-0.0.1/pyproject.toml +24 -0
hdh-0.0.1/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Maria Gragera Garces
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
hdh-0.0.1/PKG-INFO
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
Metadata-Version: 2.3
|
|
2
|
+
Name: hdh
|
|
3
|
+
Version: 0.0.1
|
|
4
|
+
Summary: Hybrid Dependency Hypergraphs for quantum computation: translation, visualization, and partitioning.
|
|
5
|
+
License: MIT
|
|
6
|
+
Keywords: quantum,compiler,partitioning,hdh,hypergraph
|
|
7
|
+
Author: Maria Gragera Garces
|
|
8
|
+
Author-email: m.gragera.gaces@gmail.com
|
|
9
|
+
Requires-Python: >=3.10,<4.0
|
|
10
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
16
|
+
Requires-Dist: matplotlib (>=3.0,<4.0)
|
|
17
|
+
Requires-Dist: networkx (>=3.0,<4.0)
|
|
18
|
+
Requires-Dist: qiskit (>=1.0,<2.0)
|
|
19
|
+
Project-URL: Homepage, https://pypi.org/project/hdh/
|
|
20
|
+
Project-URL: Repository, https://github.com/grageragarces/hdh
|
|
21
|
+
Description-Content-Type: text/markdown
|
|
22
|
+
|
|
23
|
+
# hdh
|
|
24
|
+
|
|
25
|
+
**Hybrid Dependency Hypergraphs for Quantum Computation**
|
|
26
|
+
|
|
27
|
+
🚧 **Work in Progress**
|
|
28
|
+
This library translates quantum computations into Hybrid Dependency Hypergraph (HDH) representations for analysis, visualization, and partitioning.
|
|
29
|
+
|
|
30
|
+
## Project Goals
|
|
31
|
+
|
|
32
|
+
- Convert quantum circuits into HDH format
|
|
33
|
+
- Support for popular SDKs (e.g., Qiskit)
|
|
34
|
+
- Direct encoding from algorithmic structures
|
|
35
|
+
- Print HDHs in a readable, canonical format
|
|
36
|
+
- Apply graph partitioning (e.g., METIS, KaHyPar) for distribution-aware analysis
|
|
37
|
+
|
hdh-0.0.1/README.md
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# hdh
|
|
2
|
+
|
|
3
|
+
**Hybrid Dependency Hypergraphs for Quantum Computation**
|
|
4
|
+
|
|
5
|
+
🚧 **Work in Progress**
|
|
6
|
+
This library translates quantum computations into Hybrid Dependency Hypergraph (HDH) representations for analysis, visualization, and partitioning.
|
|
7
|
+
|
|
8
|
+
## Project Goals
|
|
9
|
+
|
|
10
|
+
- Convert quantum circuits into HDH format
|
|
11
|
+
- Support for popular SDKs (e.g., Qiskit)
|
|
12
|
+
- Direct encoding from algorithmic structures
|
|
13
|
+
- Print HDHs in a readable, canonical format
|
|
14
|
+
- Apply graph partitioning (e.g., METIS, KaHyPar) for distribution-aware analysis
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
from qiskit import QuantumCircuit
|
|
2
|
+
from hdh.converters.convert_from_qiskit import from_qiskit # your existing converter
|
|
3
|
+
|
|
4
|
+
def from_qasm(input_type: str, qasm: str):
|
|
5
|
+
if input_type == 'file':
|
|
6
|
+
circuit = QuantumCircuit.from_qasm_file(qasm)
|
|
7
|
+
elif input_type == 'string':
|
|
8
|
+
circuit = QuantumCircuit.from_qasm_str(qasm)
|
|
9
|
+
else:
|
|
10
|
+
raise ValueError("Unsupported type. Use 'file' or 'string'.")
|
|
11
|
+
|
|
12
|
+
return from_qiskit(circuit)
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
from qiskit import QuantumCircuit
|
|
2
|
+
from typing import Set
|
|
3
|
+
import sys
|
|
4
|
+
import os
|
|
5
|
+
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
|
|
6
|
+
from hdh.hdh import HDH
|
|
7
|
+
from models.circuit import Circuit
|
|
8
|
+
|
|
9
|
+
def from_qiskit(circuit: QuantumCircuit) -> HDH:
|
|
10
|
+
CONTROL_GATES = {
|
|
11
|
+
"cx": [0],
|
|
12
|
+
"ccx": [0, 1],
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
qc_adapter = Circuit()
|
|
16
|
+
|
|
17
|
+
for instruction in circuit.data:
|
|
18
|
+
gate = instruction.operation
|
|
19
|
+
qargs = instruction.qubits
|
|
20
|
+
cargs = instruction.clbits
|
|
21
|
+
name = gate.name.lower()
|
|
22
|
+
|
|
23
|
+
if name in {"barrier", "snapshot", "delay", "label"}:
|
|
24
|
+
continue
|
|
25
|
+
|
|
26
|
+
q_indices = [circuit.find_bit(q).index for q in qargs]
|
|
27
|
+
c_indices = [circuit.find_bit(c).index for c in cargs]
|
|
28
|
+
|
|
29
|
+
if name == "measure":
|
|
30
|
+
modifies_flags = [False] * len(q_indices)
|
|
31
|
+
elif name == "reset":
|
|
32
|
+
modifies_flags = [True] * len(q_indices)
|
|
33
|
+
else:
|
|
34
|
+
ctrl = CONTROL_GATES.get(name, list(range(len(q_indices) - 1)))
|
|
35
|
+
modifies_flags = [i not in ctrl for i in range(len(q_indices))]
|
|
36
|
+
|
|
37
|
+
qc_adapter.add_instruction(name, q_indices, c_indices, modifies_flags)
|
|
38
|
+
|
|
39
|
+
return qc_adapter.build_hdh()
|
hdh-0.0.1/hdh/graph.py
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
|
|
2
|
+
class HDHNode:
|
|
3
|
+
def __init__(self, id, type, time):
|
|
4
|
+
self.id = id
|
|
5
|
+
self.type = type # e.g., 'qubit', 'classical', 'measurement'
|
|
6
|
+
self.time = time
|
|
7
|
+
|
|
8
|
+
def __repr__(self):
|
|
9
|
+
return f"HDHNode(id={self.id}, type={self.type}, time={self.time})"
|
|
10
|
+
|
|
11
|
+
class HDHEdge:
|
|
12
|
+
def __init__(self, id, operation, inputs, outputs):
|
|
13
|
+
self.id = id
|
|
14
|
+
self.operation = operation # e.g., 'H', 'CX', 'M', etc.
|
|
15
|
+
self.inputs = inputs
|
|
16
|
+
self.outputs = outputs
|
|
17
|
+
|
|
18
|
+
def __repr__(self):
|
|
19
|
+
return f"HDHEdge(id={self.id}, op={self.operation}, in={self.inputs}, out={self.outputs})"
|
|
20
|
+
|
|
21
|
+
class HDHGraph:
|
|
22
|
+
def __init__(self):
|
|
23
|
+
self.nodes = {}
|
|
24
|
+
self.edges = []
|
|
25
|
+
|
|
26
|
+
def add_node(self, node):
|
|
27
|
+
self.nodes[node.id] = node
|
|
28
|
+
|
|
29
|
+
def add_edge(self, edge):
|
|
30
|
+
self.edges.append(edge)
|
|
31
|
+
|
|
32
|
+
def __repr__(self):
|
|
33
|
+
return f"HDHGraph(nodes={len(self.nodes)}, edges={len(self.edges)})"
|
hdh-0.0.1/hdh/hdh.py
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
from collections import defaultdict
|
|
2
|
+
from typing import Dict, Set, Tuple, List, Literal, Union
|
|
3
|
+
|
|
4
|
+
NodeType = Literal["q", "c"] # quantum or classical
|
|
5
|
+
EdgeType = Literal["q", "c"]
|
|
6
|
+
NodeID = str
|
|
7
|
+
TimeStep = int
|
|
8
|
+
|
|
9
|
+
class HDH:
|
|
10
|
+
def __init__(self):
|
|
11
|
+
self.S: Set[NodeID] = set()
|
|
12
|
+
self.C: Set[frozenset] = set()
|
|
13
|
+
self.T: Set[TimeStep] = set()
|
|
14
|
+
self.sigma: Dict[NodeID, NodeType] = {} # node types
|
|
15
|
+
self.tau: Dict[frozenset, EdgeType] = {} # hyperedge types
|
|
16
|
+
self.time_map: Dict[NodeID, TimeStep] = {} # f: S -> T
|
|
17
|
+
|
|
18
|
+
def add_node(self, node_id: NodeID, node_type: NodeType, time: TimeStep):
|
|
19
|
+
self.S.add(node_id)
|
|
20
|
+
self.sigma[node_id] = node_type
|
|
21
|
+
self.time_map[node_id] = time
|
|
22
|
+
self.T.add(time)
|
|
23
|
+
|
|
24
|
+
def add_hyperedge(self, node_ids: Set[NodeID], edge_type: EdgeType):
|
|
25
|
+
edge = frozenset(node_ids)
|
|
26
|
+
self.C.add(edge)
|
|
27
|
+
self.tau[edge] = edge_type
|
|
28
|
+
|
|
29
|
+
def get_ancestry(self, node: NodeID) -> Set[NodeID]:
|
|
30
|
+
"""Return nodes with paths ending at `node` and earlier time steps."""
|
|
31
|
+
return {
|
|
32
|
+
s for s in self.S
|
|
33
|
+
if self.time_map[s] <= self.time_map[node] and self._path_exists(s, node)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
def get_lineage(self, node: NodeID) -> Set[NodeID]:
|
|
37
|
+
"""Return nodes reachable from `node` with later time steps."""
|
|
38
|
+
return {
|
|
39
|
+
s for s in self.S
|
|
40
|
+
if self.time_map[s] >= self.time_map[node] and self._path_exists(node, s)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
def _path_exists(self, start: NodeID, end: NodeID) -> bool:
|
|
44
|
+
"""DFS to find a time-respecting path from `start` to `end`."""
|
|
45
|
+
visited = set()
|
|
46
|
+
stack = [start]
|
|
47
|
+
while stack:
|
|
48
|
+
current = stack.pop()
|
|
49
|
+
if current == end:
|
|
50
|
+
return True
|
|
51
|
+
visited.add(current)
|
|
52
|
+
neighbors = {
|
|
53
|
+
neighbor
|
|
54
|
+
for edge in self.C if current in edge
|
|
55
|
+
for neighbor in edge
|
|
56
|
+
if neighbor != current and self.time_map[neighbor] > self.time_map[current]
|
|
57
|
+
}
|
|
58
|
+
stack.extend(neighbors - visited)
|
|
59
|
+
return False
|
|
File without changes
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import networkx as nx
|
|
2
|
+
import networkx.algorithms.community as nx_comm
|
|
3
|
+
import metis
|
|
4
|
+
from typing import List, Set
|
|
5
|
+
from hdh.hdh import HDH
|
|
6
|
+
|
|
7
|
+
def compute_cut(hdh: HDH, num_parts: int) -> List[Set[str]]:
|
|
8
|
+
"""
|
|
9
|
+
Use METIS to partition HDH nodes into disjoint blocks.
|
|
10
|
+
|
|
11
|
+
Returns a list of disjoint sets of node IDs.
|
|
12
|
+
"""
|
|
13
|
+
# 1. Build undirected graph from HDH
|
|
14
|
+
G = nx.Graph()
|
|
15
|
+
G.add_nodes_from(hdh.S)
|
|
16
|
+
|
|
17
|
+
for edge in hdh.C:
|
|
18
|
+
edge_nodes = list(edge)
|
|
19
|
+
for i in range(len(edge_nodes)):
|
|
20
|
+
for j in range(i + 1, len(edge_nodes)):
|
|
21
|
+
G.add_edge(edge_nodes[i], edge_nodes[j])
|
|
22
|
+
|
|
23
|
+
# 2. Convert to METIS-compatible graph (requires contiguous integer node IDs)
|
|
24
|
+
node_list = list(G.nodes)
|
|
25
|
+
node_idx_map = {node: idx for idx, node in enumerate(node_list)}
|
|
26
|
+
idx_node_map = {idx: node for node, idx in node_idx_map.items()}
|
|
27
|
+
|
|
28
|
+
metis_graph = nx.relabel_nodes(G, node_idx_map, copy=True)
|
|
29
|
+
|
|
30
|
+
# 3. Call METIS
|
|
31
|
+
_, parts = metis.part_graph(metis_graph, nparts=num_parts)
|
|
32
|
+
|
|
33
|
+
# 4. Build partition sets
|
|
34
|
+
partition = [set() for _ in range(num_parts)]
|
|
35
|
+
for idx, part in enumerate(parts):
|
|
36
|
+
node_id = idx_node_map[idx]
|
|
37
|
+
partition[part].add(node_id)
|
|
38
|
+
|
|
39
|
+
return partition
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import matplotlib.pyplot as plt
|
|
2
|
+
import networkx as nx
|
|
3
|
+
import numpy as np
|
|
4
|
+
import re
|
|
5
|
+
import sys
|
|
6
|
+
import os
|
|
7
|
+
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
|
|
8
|
+
from hdh.hdh import HDH
|
|
9
|
+
|
|
10
|
+
def plot_hdh(hdh, save_path=None):
|
|
11
|
+
nodes = list(hdh.S)
|
|
12
|
+
edges = [tuple(e) for e in hdh.C]
|
|
13
|
+
|
|
14
|
+
node_positions = {}
|
|
15
|
+
node_timesteps = {}
|
|
16
|
+
node_qubits = {}
|
|
17
|
+
qubit_labels = set()
|
|
18
|
+
timesteps = set()
|
|
19
|
+
|
|
20
|
+
for node in nodes:
|
|
21
|
+
if node.startswith("q") or node.startswith("c"):
|
|
22
|
+
match = re.match(r"[qc](\d+)_t(\d+)", node)
|
|
23
|
+
if match:
|
|
24
|
+
index, timestep = map(int, match.groups())
|
|
25
|
+
node_timesteps[node] = timestep
|
|
26
|
+
node_qubits[node] = index
|
|
27
|
+
qubit_labels.add(index)
|
|
28
|
+
timesteps.add(timestep)
|
|
29
|
+
else:
|
|
30
|
+
print(f"Skipping node due to unrecognized format: {node}")
|
|
31
|
+
|
|
32
|
+
if not qubit_labels:
|
|
33
|
+
print("No valid nodes found with q{{index}}_t{{step}} or c{{index}}_t{{step}} format.")
|
|
34
|
+
return
|
|
35
|
+
|
|
36
|
+
max_index = max(qubit_labels)
|
|
37
|
+
|
|
38
|
+
for node in nodes:
|
|
39
|
+
if node in node_timesteps and node in node_qubits:
|
|
40
|
+
timestep = node_timesteps[node]
|
|
41
|
+
flipped_index = max_index - node_qubits[node]
|
|
42
|
+
node_positions[node] = (timestep, flipped_index)
|
|
43
|
+
|
|
44
|
+
qubit_ticks = sorted(qubit_labels)
|
|
45
|
+
flipped_ticks = [max_index - i for i in qubit_ticks]
|
|
46
|
+
timestep_ticks = sorted(timesteps)
|
|
47
|
+
|
|
48
|
+
fig, ax = plt.subplots(figsize=(10, 4))
|
|
49
|
+
ax.set_xlabel("Timestep")
|
|
50
|
+
ax.set_ylabel("Qubit/Clbit Index")
|
|
51
|
+
ax.set_xticks(timestep_ticks)
|
|
52
|
+
ax.set_yticks(flipped_ticks)
|
|
53
|
+
ax.set_yticklabels(qubit_ticks)
|
|
54
|
+
ax.set_ylim(min(flipped_ticks) - 1, max(flipped_ticks) + 1)
|
|
55
|
+
|
|
56
|
+
involved_nodes = set()
|
|
57
|
+
for edge in edges:
|
|
58
|
+
involved_nodes.update(edge)
|
|
59
|
+
|
|
60
|
+
for node in involved_nodes:
|
|
61
|
+
if node in node_positions:
|
|
62
|
+
x, y = node_positions[node]
|
|
63
|
+
node_type = hdh.sigma.get(node, "q")
|
|
64
|
+
color = {
|
|
65
|
+
"q": "black",
|
|
66
|
+
"ctrl": "black",
|
|
67
|
+
"c": "orange"
|
|
68
|
+
}.get(node_type, "black")
|
|
69
|
+
ax.plot(x, y, 'o', markersize=10, color=color)
|
|
70
|
+
ax.text(x, y + 0.15, node, ha='center')
|
|
71
|
+
|
|
72
|
+
seen_pairs = set()
|
|
73
|
+
for edge in edges:
|
|
74
|
+
edge_nodes = [n for n in edge if n in node_positions]
|
|
75
|
+
|
|
76
|
+
edge_type = hdh.tau.get(frozenset(edge))
|
|
77
|
+
if edge_type is None:
|
|
78
|
+
node_types = [hdh.sigma.get(n, "q") for n in edge]
|
|
79
|
+
edge_type = "c" if all(t == "c" for t in node_types) else "q"
|
|
80
|
+
|
|
81
|
+
color = "orange" if edge_type == "c" else "black"
|
|
82
|
+
|
|
83
|
+
for i in range(len(edge_nodes)):
|
|
84
|
+
for j in range(i + 1, len(edge_nodes)):
|
|
85
|
+
n1, n2 = edge_nodes[i], edge_nodes[j]
|
|
86
|
+
t1, t2 = node_timesteps[n1], node_timesteps[n2]
|
|
87
|
+
|
|
88
|
+
if t1 == t2:
|
|
89
|
+
continue
|
|
90
|
+
|
|
91
|
+
type1 = hdh.sigma.get(n1, "q")
|
|
92
|
+
type2 = hdh.sigma.get(n2, "q")
|
|
93
|
+
if type1 == "ctrl" and type2 == "ctrl":
|
|
94
|
+
continue
|
|
95
|
+
|
|
96
|
+
if t1 > t2:
|
|
97
|
+
n1, n2 = n2, n1
|
|
98
|
+
t1, t2 = t2, t1
|
|
99
|
+
|
|
100
|
+
pair = (n1, n2)
|
|
101
|
+
if pair in seen_pairs:
|
|
102
|
+
continue
|
|
103
|
+
seen_pairs.add(pair)
|
|
104
|
+
|
|
105
|
+
x0, y0 = node_positions[n1]
|
|
106
|
+
x1, y1 = node_positions[n2]
|
|
107
|
+
|
|
108
|
+
print(f"Edge {edge} has type {edge_type}")
|
|
109
|
+
|
|
110
|
+
if edge_type == "c":
|
|
111
|
+
dx = x1 - x0
|
|
112
|
+
dy = y1 - y0
|
|
113
|
+
dist = np.hypot(dx, dy)
|
|
114
|
+
if dist == 0:
|
|
115
|
+
continue
|
|
116
|
+
t = np.linspace(0, 1, 200)
|
|
117
|
+
x_line = x0 + dx * t
|
|
118
|
+
y_line = y0 + dy * t
|
|
119
|
+
nx_vec = -dy / dist
|
|
120
|
+
ny_vec = dx / dist
|
|
121
|
+
displacement = 0.08 * np.sin(6 * 2 * np.pi * t)
|
|
122
|
+
x_vals = x_line + displacement * nx_vec
|
|
123
|
+
y_vals = y_line + displacement * ny_vec
|
|
124
|
+
ax.plot(x_vals, y_vals, color=color, linewidth=2)
|
|
125
|
+
else:
|
|
126
|
+
ax.plot([x0, x1], [y0, y1], color=color, linewidth=1.5)
|
|
127
|
+
|
|
128
|
+
if save_path:
|
|
129
|
+
plt.savefig(save_path)
|
|
130
|
+
else:
|
|
131
|
+
plt.show()
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
def plot_hdh_networkx(hdh: HDH):
|
|
135
|
+
G = nx.DiGraph()
|
|
136
|
+
|
|
137
|
+
for node in hdh.S:
|
|
138
|
+
node_type = hdh.sigma[node]
|
|
139
|
+
color = {
|
|
140
|
+
"q": "skyblue",
|
|
141
|
+
"ctrl": "orange",
|
|
142
|
+
"c": "lightgreen"
|
|
143
|
+
}.get(node_type, "orange")
|
|
144
|
+
G.add_node(node, color=color)
|
|
145
|
+
|
|
146
|
+
for edge in hdh.C:
|
|
147
|
+
edge_type = hdh.tau.get(edge)
|
|
148
|
+
if edge_type is None:
|
|
149
|
+
node_types = [hdh.sigma.get(n, "q") for n in edge]
|
|
150
|
+
edge_type = "c" if all(t == "c" for t in node_types) else "q"
|
|
151
|
+
edge_nodes = list(edge)
|
|
152
|
+
for i in range(len(edge_nodes)):
|
|
153
|
+
for j in range(i + 1, len(edge_nodes)):
|
|
154
|
+
G.add_edge(edge_nodes[i], edge_nodes[j], type=edge_type)
|
|
155
|
+
|
|
156
|
+
pos = nx.spring_layout(G, seed=42)
|
|
157
|
+
node_colors = [G.nodes[n]["color"] for n in G.nodes()]
|
|
158
|
+
|
|
159
|
+
edge_colors = []
|
|
160
|
+
edge_styles = []
|
|
161
|
+
|
|
162
|
+
for u, v, d in G.edges(data=True):
|
|
163
|
+
if d.get("type") == "c":
|
|
164
|
+
edge_colors.append("orange")
|
|
165
|
+
edge_styles.append("dashed")
|
|
166
|
+
else:
|
|
167
|
+
edge_colors.append("orange")
|
|
168
|
+
edge_styles.append("solid")
|
|
169
|
+
|
|
170
|
+
for (u, v), color, style in zip(G.edges(), edge_colors, edge_styles):
|
|
171
|
+
nx.draw_networkx_edges(G, pos, edgelist=[(u, v)], edge_color=color, style=style)
|
|
172
|
+
|
|
173
|
+
nx.draw_networkx_nodes(G, pos, node_color=node_colors)
|
|
174
|
+
nx.draw_networkx_labels(G, pos)
|
|
175
|
+
plt.show()
|
hdh-0.0.1/pyproject.toml
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
[tool.poetry]
|
|
2
|
+
name = "hdh"
|
|
3
|
+
version = "0.0.1"
|
|
4
|
+
description = "Hybrid Dependency Hypergraphs for quantum computation: translation, visualization, and partitioning."
|
|
5
|
+
authors = ["Maria Gragera Garces <m.gragera.gaces@gmail.com>"]
|
|
6
|
+
license = "MIT"
|
|
7
|
+
readme = "README.md"
|
|
8
|
+
packages = [{ include = "hdh" }]
|
|
9
|
+
homepage = "https://pypi.org/project/hdh/"
|
|
10
|
+
repository = "https://github.com/grageragarces/hdh"
|
|
11
|
+
keywords = ["quantum", "compiler", "partitioning", "hdh", "hypergraph"]
|
|
12
|
+
|
|
13
|
+
[tool.poetry.dependencies]
|
|
14
|
+
python = "^3.10"
|
|
15
|
+
qiskit = "^1.0"
|
|
16
|
+
networkx = "^3.0"
|
|
17
|
+
matplotlib = "^3.0"
|
|
18
|
+
|
|
19
|
+
[tool.poetry.dev-dependencies]
|
|
20
|
+
pytest = "^8.0"
|
|
21
|
+
|
|
22
|
+
[build-system]
|
|
23
|
+
requires = ["poetry-core>=1.0.0"]
|
|
24
|
+
build-backend = "poetry.core.masonry.api"
|