Demo 3:矩阵秩¶
可视化:3 子图 —— 4×4 高斯消元 + 量子查询复杂度
对应教程:第 11 章 查询复杂度 中相关小节 · 依赖安装:pip install "unified-quantum[visualization,simulation]"
实现要点¶
核心:构造 4x4 二值矩阵 A (rank=3), 演示 (左上) 矩阵 A 热图 + rank + 奇异值 (右上) 高斯消元 4 步 row-echelon 形式 (经典 nm = 16 次 oracle 查询基线) (左下) 经典 O(nm) vs 量子 O(sqrt(r(n-r+1)) L T) 查询数对比 (右下) uniqc 验证 16 个 entry oracle: A[i,j]=0 -> P(0)~1; A[i,j]=1 -> P(0)~0
完整源码¶
demos/ch11-query-complexity/03_matrix_rank.py¶
1"""
2ch11 演示 3:矩阵秩判定查询复杂度对比 + Gaussian 消元步骤可视化
3
4对应教程:chenzhaoyun.com/quantum-tutorial/ch11-query-complexity/matrix-rank.html
5核心:构造 4x4 二值矩阵 A (rank=3), 演示
6 (左上) 矩阵 A 热图 + rank + 奇异值
7 (右上) 高斯消元 4 步 row-echelon 形式 (经典 nm = 16 次 oracle 查询基线)
8 (左下) 经典 O(nm) vs 量子 O(sqrt(r(n-r+1)) L T) 查询数对比
9 (右下) uniqc 验证 16 个 entry oracle: A[i,j]=0 -> P(0)~1; A[i,j]=1 -> P(0)~0
10
11依赖:pip install unified-quantum[visualization]
12运行:python demos/ch11-query-complexity/03_matrix_rank.py
13"""
14from pathlib import Path
15
16import matplotlib
17matplotlib.use("Agg")
18import matplotlib.pyplot as plt
19import numpy as np
20
21from uniqc import Circuit, submit_task, wait_for_result
22
23OUT = Path(__file__).parent
24SHOTS = 150 # 16 entry probes * 150 = 2400 total, < 3000 budget
25
26# === 4x4 binary matrix A (rank = 3) ===
27A = np.array([[1, 1, 0, 1], [0, 1, 1, 1], [1, 0, 1, 0], [1, 1, 0, 1]], dtype=int)
28
29
30def gaussian_steps(M: np.ndarray) -> list[np.ndarray]:
31 A = M.astype(float).copy()
32 n, m = A.shape
33 steps = [A.copy()]
34 for k in range(min(n, m)):
35 pivot = next((i for i in range(k, n) if abs(A[i, k]) > 1e-9), None)
36 if pivot is None:
37 continue
38 if pivot != k:
39 A[[k, pivot]] = A[[pivot, k]]
40 for i in range(n):
41 if i != k and abs(A[i, k]) > 1e-9:
42 A[i] -= (A[i, k] / A[k, k]) * A[k]
43 steps.append(A.copy())
44 return steps
45
46
47def entry_oracle_p(row: int, col: int) -> float:
48 """1-qubit RX(theta) oracle: P(0) = cos^2(pi*A[i,j]/2)."""
49 c = Circuit()
50 c.rx(0, float(np.pi * A[row, col]))
51 c.measure(0)
52 r = wait_for_result(submit_task(circuit=c, backend="dummy:local:simulator", shots=SHOTS))
53 return float(r.probabilities.get("0", 0.0))
54
55
56def belovs_Q(n: int, r: int, gap: float = 0.3) -> float:
57 """Q = sqrt(r(n-r+1)) L T (dense oracle, T=1, L = sqrt(r)/gap)."""
58 return np.sqrt(r * (n - r + 1)) * np.sqrt(r) / gap
59
60
61# === 矩阵性质 ===
62print("ch11-query-complexity demo 3: matrix rank via Gaussian elim + span program")
63print(f" matrix A shape = {A.shape}")
64print(f" A =\n{A}")
65_, s, _ = np.linalg.svd(A.astype(float))
66rank = int(np.sum(s > 1e-9))
67print(f" rank(A) = {rank}, sigma = {np.round(s, 4).tolist()}")
68
69# === Gaussian 消元 ===
70gauss_steps = gaussian_steps(A)
71
72# === Oracle 验证 (16 个 entry) ===
73n, m = A.shape
74oracle_p0 = np.array([[entry_oracle_p(i, j) for j in range(m)] for i in range(n)])
75print(f" matrix entry oracle probes (16 entries, all P(0) in {{0, 1}}):")
76for i in range(n):
77 for j in range(m):
78 print(f" P(0|A[{i},{j}]={A[i,j]}) = {oracle_p0[i,j]:.3f}", end=" ")
79 print()
80
81# === 复杂度曲线 ===
82N_DIM_LIST = [4, 8, 16, 32, 64, 128, 256]
83classical_curve = np.array([float(d * d) for d in N_DIM_LIST])
84quantum_dense = np.array([belovs_Q(d, d // 2) for d in N_DIM_LIST])
85quantum_midrank = np.array([belovs_Q(d, d // 4) for d in N_DIM_LIST])
86quantum_sparse = np.array([belovs_Q(d, 1) for d in N_DIM_LIST])
87
88# === 画图 ===
89fig, axes = plt.subplots(2, 2, figsize=(14.5, 9.5))
90
91# (左上) A 热图
92ax = axes[0, 0]
93im = ax.imshow(A, cmap="Blues", vmin=0, vmax=1)
94for i in range(n):
95 for j in range(m):
96 ax.text(j, i, str(A[i, j]), ha="center", va="center", fontsize=14, fontweight="bold",
97 color="white" if A[i, j] > 0.5 else "black")
98ax.set_xticks(np.arange(m))
99ax.set_yticks(np.arange(n))
100ax.set_xticklabels([f"col {j}" for j in range(m)])
101ax.set_yticklabels([f"row {i}" for i in range(n)])
102ax.set_title(f"binary matrix A (n x m = {n} x {m})\n"
103 f"rank = {rank}, sigma = {np.round(s, 3).tolist()}")
104plt.colorbar(im, ax=ax, fraction=0.046, pad=0.04)
105
106# (右上) Gaussian 4 步
107ax = axes[0, 1]
108ax.axis("off")
109inner = ax.get_subplotspec().subgridspec(2, 2, hspace=0.35, wspace=0.2)
110for k, step in enumerate(gauss_steps[:4]):
111 rk, ck = divmod(k, 2)
112 sax = fig.add_subplot(inner[rk, ck])
113 sax.imshow(np.abs(step), cmap="Oranges", vmin=0, vmax=2)
114 sax.set_xticks(np.arange(m))
115 sax.set_yticks(np.arange(n))
116 sax.set_xticklabels([str(j) for j in range(m)], fontsize=7)
117 sax.set_yticklabels([str(i) for i in range(n)], fontsize=7)
118 sax.set_title(f"step {k}" + (" (start)" if k == 0 else f" after pivot {k}"), fontsize=9)
119 for i in range(n):
120 for j in range(m):
121 sax.text(j, i, f"{step[i, j]:.1f}", ha="center", va="center", fontsize=7)
122ax.set_title(f"Gaussian elimination: {len(gauss_steps)-1} pivot steps\n"
123 f"classical baseline = n*m = {n*m} oracle queries", fontsize=10)
124
125# (左下) 复杂度对比
126ax = axes[1, 0]
127ax.loglog(N_DIM_LIST, classical_curve, "o-", color="#d62728", lw=2, ms=8, label=r"classical $Q = nm$")
128ax.loglog(N_DIM_LIST, quantum_dense, "s-", color="#1f77b4", lw=2, ms=8, label=r"quantum $r = n/2$ (dense)")
129ax.loglog(N_DIM_LIST, quantum_midrank, "^-", color="#2ca02c", lw=2, ms=7, label=r"quantum $r = n/4$")
130ax.loglog(N_DIM_LIST, quantum_sparse, "v-", color="#9467bd", lw=2, ms=7, label=r"quantum $r = 1$ (OR)")
131for x, yc, yd in zip(N_DIM_LIST, classical_curve, quantum_dense):
132 ax.annotate(f"{int(yc)}", (x, yc), textcoords="offset points", xytext=(4, 4),
133 fontsize=7, color="#d62728")
134 ax.annotate(f"{yd:.0f}", (x, yd), textcoords="offset points", xytext=(4, -12),
135 fontsize=7, color="#1f77b4")
136ref_x = np.array([N_DIM_LIST[0], N_DIM_LIST[-1]], dtype=float)
137ax.loglog(ref_x, ref_x ** 2, ":", color="#d62728", alpha=0.4)
138ax.loglog(ref_x, ref_x ** 1.5 * 0.5, ":", color="#1f77b4", alpha=0.4)
139ax.set_xlabel(r"matrix dim $n$ ($m = n$)")
140ax.set_ylabel(r"# oracle queries")
141ax.set_title(r"matrix rank decision: classical $nm$ vs quantum $O(\sqrt{r(n-r+1)} L T)$")
142ax.legend(loc="upper left", fontsize=8)
143ax.grid(alpha=0.3, which="both")
144
145# (右下) oracle 实测 P(0) 热图
146ax = axes[1, 1]
147im = ax.imshow(oracle_p0, cmap="viridis_r", vmin=0, vmax=1)
148for i in range(n):
149 for j in range(m):
150 ax.text(j, i, f"{oracle_p0[i, j]:.2f}", ha="center", va="center", fontsize=10,
151 color="white" if oracle_p0[i, j] > 0.5 else "black")
152ax.set_xticks(np.arange(m))
153ax.set_yticks(np.arange(n))
154ax.set_xticklabels([f"j={j}" for j in range(m)])
155ax.set_yticklabels([f"i={i}" for i in range(n)])
156ax.set_title("measured P(0) on matrix entry oracle\n"
157 "A_ij=0 -> P(0)~1 ; A_ij=1 -> P(0)~0")
158plt.colorbar(im, ax=ax, fraction=0.046, pad=0.04)
159
160fig.suptitle("ch11 demo 3: matrix rank — Gaussian elimination vs Belovs span program",
161 y=1.01, fontsize=13)
162plt.tight_layout()
163out_path = OUT / "03_matrix_rank.png"
164plt.savefig(out_path, dpi=120, bbox_inches="tight")
165plt.close()
166
167print(f" Gaussian elim: {len(gauss_steps)-1} pivots, classical baseline {n*m} queries")
168print(f" Belovs span upper bound for n={n}, r={rank}: "
169 f"Q = sqrt({rank} * {n - rank + 1}) * L * T = {belovs_Q(n, rank):.1f} queries")
170print(f" complexity scaling (n=m, dense oracle, gap=0.3):")
171for d, qc, qd, qs in zip(N_DIM_LIST, classical_curve, quantum_dense, quantum_sparse):
172 print(f" n = {d:>4d} classical = {int(qc):>6d} "
173 f"quantum r=n/2 = {qd:>7.1f} quantum r=1 = {qs:>6.1f}")
174print(f" saved: {out_path}")
运行结果¶

运行方式¶
# 仓库根目录执行;输出 PNG 到 demos/ch11-query-complexity/03_matrix_rank.png,关键统计到 stdout
.venv/bin/python3 demos/ch11-query-complexity/03_matrix_rank.py