Skip to content

Commit 2fc02b1

Browse files
msoekenbrad-lackeyCopilotbilltiCopilot
authored
QRE Update (#3090)
Co-authored-by: Brad Lackey <[email protected]> Co-authored-by: Brad Lackey <[email protected]> Co-authored-by: Copilot <[email protected]> Co-authored-by: Bill Ticehurst <[email protected]> Co-authored-by: Bill Ticehurst <[email protected]> Co-authored-by: Copilot <[email protected]>
1 parent e0752aa commit 2fc02b1

108 files changed

Lines changed: 20776 additions & 6 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/CODEOWNERS

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
/source/compiler/qsc_partial_eval @idavis @swernli
1111
/source/compiler/qsc_rca @idavis @swernli
1212
/source/compiler/qsc_rir @idavis @swernli
13-
/source/fuzz @billti @idavis @swernli
13+
/source/fuzz @billti @idavis @swernli
1414
/katas @billti @swernli
1515
/source/jupyterlab @billti @idavis @minestarks
1616
/source/language_service @billti @idavis @minestarks @ScottCarda-MS
@@ -19,7 +19,9 @@
1919
/library @swernli @orpuente-MS
2020
/source/npm @billti @minestarks @ScottCarda-MS
2121
/source/pip @billti @idavis @minestarks
22+
/source/pip/qsharp/qre @msoeken @brad-lackey @jwhogabo
2223
/source/playground @billti @minestarks
24+
/source/qre @msoeken @brad-lackey @jwhogabo
2325
/source/resource_estimator @billti @swernli
2426
/samples @minestarks @swernli
2527
/source/vscode @billti @idavis @minestarks

Cargo.lock

Lines changed: 13 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ members = [
2828
"source/language_service",
2929
"source/simulators",
3030
"source/pip",
31+
"source/qre",
3132
"source/resource_estimator",
3233
"source/samples_test",
3334
"source/wasm",

source/pip/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ num-traits = { workspace = true }
1818
qsc = { path = "../compiler/qsc" }
1919
qdk_simulators = { path = "../simulators" }
2020
resource_estimator = { path = "../resource_estimator" }
21+
qre = { path = "../qre" }
2122
miette = { workspace = true, features = ["fancy"] }
2223
rustc-hash = { workspace = true }
2324
serde = { workspace = true, features = ["derive"] }

source/pip/benchmarks/bench_qre.py

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
# Copyright (c) Microsoft Corporation.
2+
# Licensed under the MIT License.
3+
4+
import timeit
5+
from dataclasses import dataclass, KW_ONLY, field
6+
from qsharp.qre import linear_function, generic_function
7+
from qsharp.qre._architecture import _make_instruction
8+
from qsharp.qre.models import (
9+
GateBased,
10+
SurfaceCode,
11+
TwoDimensionalYokedSurfaceCode,
12+
Litinski19Factory,
13+
)
14+
from qsharp.qre._enumeration import _enumerate_instances
15+
16+
17+
def bench_enumerate_instances():
18+
# Measure performance of enumerating instances with a large domain
19+
@dataclass
20+
class LargeDomain:
21+
_: KW_ONLY
22+
param1: int = field(default=0, metadata={"domain": range(1000)})
23+
param2: bool
24+
25+
number = 100
26+
27+
duration = timeit.timeit(
28+
"list(_enumerate_instances(LargeDomain))",
29+
globals={
30+
"_enumerate_instances": _enumerate_instances,
31+
"LargeDomain": LargeDomain,
32+
},
33+
number=number,
34+
)
35+
36+
print(f"Enumerating instances took {duration / number:.6f} seconds on average.")
37+
38+
39+
def bench_enumerate_isas():
40+
ctx = GateBased(gate_time=50, measurement_time=100).context()
41+
42+
# Hierarchical factory using from_components
43+
query = (
44+
SurfaceCode.q()
45+
* TwoDimensionalYokedSurfaceCode.q(source=SurfaceCode.q())
46+
* Litinski19Factory.q()
47+
)
48+
49+
number = 100
50+
duration = timeit.timeit(
51+
"list(query.enumerate(ctx))",
52+
globals={
53+
"query": query,
54+
"ctx": ctx,
55+
},
56+
number=number,
57+
)
58+
59+
print(f"Enumerating ISAs took {duration / number:.6f} seconds on average.")
60+
61+
62+
def bench_function_evaluation_linear():
63+
fl = linear_function(12)
64+
65+
inst = _make_instruction(42, 0, None, 1, fl, None, 1.0, {})
66+
number = 1000
67+
duration = timeit.timeit(
68+
"inst.space(5)",
69+
globals={
70+
"inst": inst,
71+
},
72+
number=number,
73+
)
74+
75+
print(
76+
f"Evaluating linear function took {duration / number:.6f} seconds on average."
77+
)
78+
79+
80+
def bench_function_evaluation_generic():
81+
def func(arity: int) -> int:
82+
return 12 * arity
83+
84+
fg = generic_function(func)
85+
86+
inst = _make_instruction(42, 0, None, 1, fg, None, 1.0, {})
87+
number = 1000
88+
duration = timeit.timeit(
89+
"inst.space(5)",
90+
globals={
91+
"inst": inst,
92+
},
93+
number=number,
94+
)
95+
96+
print(
97+
f"Evaluating linear function took {duration / number:.6f} seconds on average."
98+
)
99+
100+
101+
if __name__ == "__main__":
102+
bench_enumerate_instances()
103+
bench_enumerate_isas()
104+
bench_function_evaluation_linear()
105+
bench_function_evaluation_generic()

source/pip/pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ jupyterlab = ["qsharp-jupyterlab"]
2424
widgets = ["qsharp-widgets"]
2525
qiskit = ["qiskit>=1.2.2,<3.0.0"]
2626
cirq = ["cirq-core>=1.6.1,<1.7"]
27+
qre = ["cirq-core==1.6.1,<1.7", "pandas>=2.1", "ply>=3.11", "pyqir>=0.12.3,<0.13"]
2728

2829
[build-system]
2930
requires = ["maturin ~= 1.10.2"]
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# Copyright (c) Microsoft Corporation.
2+
# Licensed under the MIT License.
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# Copyright (c) Microsoft Corporation.
2+
# Licensed under the MIT License.
3+
4+
# flake8: noqa F403
5+
# pyright: ignore[reportWildcardImportFromLibrary]
6+
7+
"""Magnets application module.
8+
9+
Re-exports from the submodules."""
10+
11+
from .geometry import *
12+
from .models import *
13+
from .trotter import *
14+
from .utilities import *
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# Copyright (c) Microsoft Corporation.
2+
# Licensed under the MIT License.
3+
4+
"""Geometry module for representing quantum system topologies.
5+
6+
This module provides hypergraph data structures for representing the
7+
geometric structure of quantum systems, including lattice topologies
8+
and interaction graphs.
9+
"""
10+
11+
from .complete import CompleteBipartiteGraph, CompleteGraph
12+
from .lattice1d import Chain1D, Ring1D
13+
from .lattice2d import Patch2D, Torus2D
14+
15+
__all__ = [
16+
"CompleteBipartiteGraph",
17+
"CompleteGraph",
18+
"Chain1D",
19+
"Ring1D",
20+
"Patch2D",
21+
"Torus2D",
22+
]
Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
# Copyright (c) Microsoft Corporation.
2+
# Licensed under the MIT License.
3+
4+
"""Complete graph geometries for quantum simulations.
5+
6+
This module provides classes for representing complete graphs and complete
7+
bipartite graphs as hypergraphs. These structures are useful for quantum
8+
systems with all-to-all or bipartite all-to-all interactions.
9+
"""
10+
11+
from ..utilities import (
12+
Hyperedge,
13+
Hypergraph,
14+
HypergraphEdgeColoring,
15+
)
16+
17+
18+
class CompleteGraph(Hypergraph):
19+
"""A complete graph where every vertex is connected to every other vertex.
20+
21+
In a complete graph K_n, there are n vertices and n(n-1)/2 edges,
22+
with each pair of distinct vertices connected by exactly one edge.
23+
24+
Attributes:
25+
n: Number of vertices in the graph.
26+
27+
Example:
28+
29+
.. code-block:: python
30+
>>> graph = CompleteGraph(4)
31+
>>> graph.nvertices
32+
4
33+
>>> graph.nedges
34+
6
35+
"""
36+
37+
def __init__(self, n: int, self_loops: bool = False) -> None:
38+
"""Initialize a complete graph.
39+
40+
Args:
41+
n: Number of vertices in the graph.
42+
self_loops: If True, include self-loop edges on each vertex
43+
for single-site terms.
44+
"""
45+
if self_loops:
46+
_edges = [Hyperedge([i]) for i in range(n)]
47+
else:
48+
_edges = []
49+
50+
# Add all pairs of vertices
51+
for i in range(n):
52+
for j in range(i + 1, n):
53+
_edges.append(Hyperedge([i, j]))
54+
super().__init__(_edges)
55+
56+
self.n = n
57+
58+
def edge_coloring(self) -> HypergraphEdgeColoring:
59+
"""Compute edge coloring for this complete graph."""
60+
coloring = HypergraphEdgeColoring(self)
61+
for edge in self.edges():
62+
if len(edge.vertices) == 1:
63+
coloring.add_edge(edge, -1)
64+
else:
65+
if self.n % 2 == 0:
66+
i, j = edge.vertices
67+
m = self.n - 1
68+
if j == m:
69+
coloring.add_edge(edge, i)
70+
elif (j - i) % 2 == 0:
71+
coloring.add_edge(edge, (j - i) // 2)
72+
else:
73+
coloring.add_edge(edge, (j - i + m) // 2)
74+
else:
75+
m = self.n
76+
i, j = edge.vertices
77+
if (j - i) % 2 == 0:
78+
coloring.add_edge(edge, (j - i) // 2)
79+
else:
80+
coloring.add_edge(edge, (j - i + m) // 2)
81+
return coloring
82+
83+
84+
class CompleteBipartiteGraph(Hypergraph):
85+
"""A complete bipartite graph with two vertex sets.
86+
87+
In a complete bipartite graph K_{m,n} (m <= n), there are m + n
88+
vertices partitioned into two sets of sizes m and n. Every vertex
89+
in the first set is connected to every vertex in the second set,
90+
giving m * n edges total.
91+
92+
Vertices 0 to m-1 form the first set, and vertices m to m+n-1
93+
form the second set.
94+
95+
Attributes:
96+
m: Number of vertices in the first set.
97+
n: Number of vertices in the second set.
98+
99+
Requires:
100+
m <= n
101+
102+
Example:
103+
104+
.. code-block:: python
105+
>>> graph = CompleteBipartiteGraph(2, 3)
106+
>>> graph.nvertices
107+
5
108+
>>> graph.nedges
109+
6
110+
"""
111+
112+
def __init__(self, m: int, n: int, self_loops: bool = False) -> None:
113+
"""Initialize a complete bipartite graph.
114+
115+
Args:
116+
m: Number of vertices in the first set (vertices 0 to m-1).
117+
n: Number of vertices in the second set (vertices m to m+n-1).
118+
self_loops: If True, include self-loop edges on each vertex
119+
for single-site terms.
120+
"""
121+
assert m <= n, "Require m <= n for CompleteBipartiteGraph."
122+
total_vertices = m + n
123+
124+
if self_loops:
125+
_edges = [Hyperedge([i]) for i in range(total_vertices)]
126+
127+
else:
128+
_edges = []
129+
130+
# Connect every vertex in first set to every vertex in second set
131+
for i in range(m):
132+
for j in range(m, m + n):
133+
_edges.append(Hyperedge([i, j]))
134+
super().__init__(_edges)
135+
136+
self.m = m
137+
self.n = n
138+
139+
def edge_coloring(self) -> HypergraphEdgeColoring:
140+
"""Compute edge coloring for this complete bipartite graph."""
141+
coloring = HypergraphEdgeColoring(self)
142+
m = self.m
143+
n = self.n
144+
for edge in self.edges():
145+
if len(edge.vertices) == 1:
146+
coloring.add_edge(edge, -1)
147+
else:
148+
i, j = edge.vertices
149+
coloring.add_edge(edge, (i + j - m) % n)
150+
return coloring

0 commit comments

Comments
 (0)