updates?
0
latex/.gitignore → .gitignore
vendored
@@ -1,8 +1,8 @@
|
|||||||
# Simulation
|
# Simulation
|
||||||
|
|
||||||
## Define random sampling using standard uniform measure on the unit sphere
|
## Define random sampling using standard uniform measure on the unit sphere
|
||||||
|
|
||||||
## Define and visualized the concentration of measure phenomenon on complex projective space
|
## Define and visualized the concentration of measure phenomenon on complex projective space
|
||||||
|
|
||||||
## Define random sampling using Majorana Stellar representation
|
## Define random sampling using Majorana Stellar representation
|
||||||
|
|
||||||
|
|||||||
@@ -1,24 +1,27 @@
|
|||||||
"""Edit globals here; no CLI parser is used."""
|
"""Edit globals here; no CLI parser is used."""
|
||||||
from datetime import datetime
|
|
||||||
from pathlib import Path
|
from datetime import datetime
|
||||||
|
from pathlib import Path
|
||||||
SEED = 7
|
|
||||||
KAPPA = 1e-3
|
SEED = 114514
|
||||||
NUM_SAMPLES = 10**4 # requested default
|
KAPPA = 1e-3
|
||||||
LIPSCHITZ_PAIRS = 12_000
|
NUM_SAMPLES = 10**6 # requested default
|
||||||
LIPSCHITZ_RESERVOIR = 4_096
|
LIPSCHITZ_PAIRS = 12_000
|
||||||
MAJORANA_STAR_STATES = 16 # only for visualization
|
LIPSCHITZ_RESERVOIR = 4_096
|
||||||
MAX_STAR_DEGREE = 63 # avoid unstable huge root-finding plots
|
MAJORANA_STAR_STATES = 16 # only for visualization
|
||||||
|
MAX_STAR_DEGREE = 63 # avoid unstable huge root-finding plots
|
||||||
BACKEND = "auto" # auto | jax | numpy
|
|
||||||
JAX_PLATFORM = "" # "", "cpu", "gpu"; set before importing JAX
|
BACKEND = "auto" # auto | jax | numpy
|
||||||
RESULTS_DIR = Path("./results") / f"exp-{datetime.now():%Y%m%d-%H%M%S}"
|
JAX_PLATFORM = "gpu" # "", "cpu", "gpu"; set before importing JAX
|
||||||
|
RESULTS_DIR = (
|
||||||
# Chosen so the three families have comparable intrinsic dimensions:
|
Path.joinpath(Path.cwd(), Path("./results")) / f"exp-{datetime.now():%Y%m%d-%H%M%S}"
|
||||||
# sphere S^(m-1), CP^(d_A d_B - 1), and Sym^N(C^2) ~ CP^N.
|
)
|
||||||
SPHERE_DIMS = [16, 64, 256, 1024]
|
|
||||||
CP_DIMS = [(4, 4), (8, 8), (16, 16), (32, 32)]
|
# Chosen so the three families have comparable intrinsic dimensions:
|
||||||
MAJORANA_N = [15, 63, 255, 1023]
|
# sphere S^(m-1), CP^(d_A d_B - 1), and Sym^N(C^2) ~ CP^N.
|
||||||
|
SPHERE_DIMS = [1<<i for i in range(4, 12)]
|
||||||
# Batch sizes are the main speed knob; reduce CP batches first if memory is tight.
|
CP_DIMS = [(1<<i, 1<<i) for i in range(4, 12)]
|
||||||
BATCH = {"sphere": 32_768, "cp": 256, "majorana": 65_536}
|
MAJORANA_N = [(1<<i)-1 for i in range(4, 12)]
|
||||||
|
|
||||||
|
# Batch sizes are the main speed knob; reduce CP batches first if memory is tight.
|
||||||
|
BATCH = {"sphere": 32_768, "cp": 256, "majorana": 65_536}
|
||||||
|
|||||||
@@ -1,85 +1,112 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
"""Unified Monte Carlo for S^(m-1), CP^n, and symmetric-state CP^N via Majorana stars."""
|
"""Unified Monte Carlo for S^(m-1), CP^n, and symmetric-state CP^N via Majorana stars."""
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import os
|
import os
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
|
||||||
import config
|
import sys
|
||||||
|
|
||||||
if config.JAX_PLATFORM:
|
# Add the parent directory to sys.path
|
||||||
os.environ["JAX_PLATFORM_NAME"] = config.JAX_PLATFORM
|
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||||
|
|
||||||
from sampling_pipeline import ( # noqa: E402
|
import config
|
||||||
plot_cross_space_comparison,
|
|
||||||
plot_family_summary,
|
if config.JAX_PLATFORM:
|
||||||
plot_histogram,
|
os.environ["JAX_PLATFORM_NAME"] = config.JAX_PLATFORM
|
||||||
plot_majorana_stars,
|
|
||||||
plot_tail,
|
from sampling_pipeline import (
|
||||||
simulate_space,
|
plot_cross_space_comparison,
|
||||||
write_summary_csv,
|
plot_family_summary,
|
||||||
)
|
plot_histogram,
|
||||||
from spaces import ComplexProjectiveSpace, MajoranaSymmetricSpace, UnitSphereSpace # noqa: E402
|
plot_majorana_stars,
|
||||||
|
plot_tail,
|
||||||
|
simulate_space,
|
||||||
def main() -> None:
|
write_summary_csv,
|
||||||
outdir = Path(config.RESULTS_DIR)
|
)
|
||||||
outdir.mkdir(parents=True, exist_ok=True)
|
from spaces import (
|
||||||
|
ComplexProjectiveSpace,
|
||||||
spaces = (
|
MajoranaSymmetricSpace,
|
||||||
[UnitSphereSpace(m) for m in config.SPHERE_DIMS]
|
UnitSphereSpace,
|
||||||
+ [ComplexProjectiveSpace(a, b) for a, b in config.CP_DIMS]
|
)
|
||||||
+ [MajoranaSymmetricSpace(n) for n in config.MAJORANA_N]
|
|
||||||
)
|
|
||||||
|
def main() -> None:
|
||||||
seeds = np.random.SeedSequence(config.SEED).spawn(len(spaces) + 16)
|
outdir = Path(config.RESULTS_DIR)
|
||||||
results = []
|
outdir.mkdir(parents=True, exist_ok=True)
|
||||||
|
|
||||||
for i, space in enumerate(spaces):
|
spaces = (
|
||||||
result = simulate_space(
|
[UnitSphereSpace(m) for m in config.SPHERE_DIMS]
|
||||||
space,
|
+ [ComplexProjectiveSpace(a, b) for a, b in config.CP_DIMS]
|
||||||
num_samples=config.NUM_SAMPLES,
|
+ [MajoranaSymmetricSpace(n) for n in config.MAJORANA_N]
|
||||||
batch=config.BATCH[space.family],
|
)
|
||||||
kappa=config.KAPPA,
|
|
||||||
seed=int(seeds[i].generate_state(1, dtype=np.uint32)[0]),
|
seeds = np.random.SeedSequence(config.SEED).spawn(len(spaces) + 16)
|
||||||
backend=config.BACKEND,
|
results = []
|
||||||
lipschitz_pairs=config.LIPSCHITZ_PAIRS,
|
|
||||||
lipschitz_reservoir=config.LIPSCHITZ_RESERVOIR,
|
for i, space in enumerate(spaces):
|
||||||
)
|
result = simulate_space(
|
||||||
results.append(result)
|
space,
|
||||||
plot_histogram(result, outdir)
|
num_samples=config.NUM_SAMPLES,
|
||||||
plot_tail(result, space, outdir)
|
batch=config.BATCH[space.family],
|
||||||
|
kappa=config.KAPPA,
|
||||||
if space.family == "majorana" and space.N <= config.MAX_STAR_DEGREE:
|
seed=int(seeds[i].generate_state(1, dtype=np.uint32)[0]),
|
||||||
star_seed = int(seeds[len(spaces) + i].generate_state(1, dtype=np.uint32)[0])
|
backend=config.BACKEND,
|
||||||
from pipeline import _sample_stream # local import to avoid exporting internals
|
lipschitz_pairs=config.LIPSCHITZ_PAIRS,
|
||||||
states, _ = _sample_stream(space, config.MAJORANA_STAR_STATES, min(config.MAJORANA_STAR_STATES, config.BATCH["majorana"]), star_seed, config.BACKEND, keep_states=True)
|
lipschitz_reservoir=config.LIPSCHITZ_RESERVOIR,
|
||||||
plot_majorana_stars(space, states, outdir)
|
)
|
||||||
|
results.append(result)
|
||||||
results.sort(key=lambda r: (r.family, r.intrinsic_dim))
|
plot_histogram(result, outdir)
|
||||||
write_summary_csv(results, outdir / "observable_diameter_summary.csv")
|
plot_tail(result, space, outdir)
|
||||||
for fam in ("sphere", "cp", "majorana"):
|
|
||||||
plot_family_summary(results, fam, outdir)
|
if space.family == "majorana" and space.N <= config.MAX_STAR_DEGREE:
|
||||||
plot_cross_space_comparison(results, outdir)
|
star_seed = int(
|
||||||
|
seeds[len(spaces) + i].generate_state(1, dtype=np.uint32)[0]
|
||||||
with (outdir / "run_config.txt").open("w") as fh:
|
)
|
||||||
fh.write(
|
from sampling_pipeline import (
|
||||||
f"SEED={config.SEED}\nKAPPA={config.KAPPA}\nNUM_SAMPLES={config.NUM_SAMPLES}\n"
|
_sample_stream,
|
||||||
f"LIPSCHITZ_PAIRS={config.LIPSCHITZ_PAIRS}\nLIPSCHITZ_RESERVOIR={config.LIPSCHITZ_RESERVOIR}\n"
|
) # local import to avoid exporting internals
|
||||||
f"BACKEND={config.BACKEND}\nJAX_PLATFORM={config.JAX_PLATFORM}\n"
|
|
||||||
f"SPHERE_DIMS={config.SPHERE_DIMS}\nCP_DIMS={config.CP_DIMS}\nMAJORANA_N={config.MAJORANA_N}\n"
|
states, _ = _sample_stream(
|
||||||
f"BATCH={config.BATCH}\n"
|
space,
|
||||||
)
|
config.MAJORANA_STAR_STATES,
|
||||||
|
min(config.MAJORANA_STAR_STATES, config.BATCH["majorana"]),
|
||||||
print("family dim mean(bits) part_diam(bits) norm_proxy_q99")
|
star_seed,
|
||||||
for r in results:
|
config.BACKEND,
|
||||||
q = f"{r.normalized_proxy_q99:.6g}" if r.normalized_proxy_q99 == r.normalized_proxy_q99 else "nan"
|
keep_states=True,
|
||||||
print(f"{r.family:8s} {r.intrinsic_dim:5d} {r.mean:11.6f} {r.partial_diameter:16.6f} {q:>14s}")
|
)
|
||||||
print(f"\nWrote results to: {outdir.resolve()}")
|
plot_majorana_stars(space, states, outdir)
|
||||||
|
|
||||||
|
results.sort(key=lambda r: (r.family, r.intrinsic_dim))
|
||||||
if __name__ == "__main__":
|
write_summary_csv(results, outdir / "observable_diameter_summary.csv")
|
||||||
main()
|
for fam in ("sphere", "cp", "majorana"):
|
||||||
|
plot_family_summary(results, fam, outdir)
|
||||||
|
plot_cross_space_comparison(results, outdir)
|
||||||
|
|
||||||
|
with (outdir / "run_config.txt").open("w") as fh:
|
||||||
|
fh.write(
|
||||||
|
f"SEED={config.SEED}\nKAPPA={config.KAPPA}\nNUM_SAMPLES={config.NUM_SAMPLES}\n"
|
||||||
|
f"LIPSCHITZ_PAIRS={config.LIPSCHITZ_PAIRS}\nLIPSCHITZ_RESERVOIR={config.LIPSCHITZ_RESERVOIR}\n"
|
||||||
|
f"BACKEND={config.BACKEND}\nJAX_PLATFORM={config.JAX_PLATFORM}\n"
|
||||||
|
f"SPHERE_DIMS={config.SPHERE_DIMS}\nCP_DIMS={config.CP_DIMS}\nMAJORANA_N={config.MAJORANA_N}\n"
|
||||||
|
f"BATCH={config.BATCH}\n"
|
||||||
|
)
|
||||||
|
|
||||||
|
print("family dim mean(bits) part_diam(bits) norm_proxy_q99")
|
||||||
|
for r in results:
|
||||||
|
q = (
|
||||||
|
f"{r.normalized_proxy_q99:.6g}"
|
||||||
|
if r.normalized_proxy_q99 == r.normalized_proxy_q99
|
||||||
|
else "nan"
|
||||||
|
)
|
||||||
|
print(
|
||||||
|
f"{r.family:8s} {r.intrinsic_dim:5d} {r.mean:11.6f} {r.partial_diameter:16.6f} {q:>14s}"
|
||||||
|
)
|
||||||
|
print(f"\nWrote results to: {outdir.resolve()}")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
numpy>=1.26
|
numpy>=1.26
|
||||||
matplotlib>=3.8
|
matplotlib>=3.8
|
||||||
tqdm>=4.66
|
tqdm>=4.66
|
||||||
# CPU-only JAX
|
# CPU-only JAX
|
||||||
# jax
|
# jax
|
||||||
# Apple Metal JAX (experimental; complex64/complex128 currently unsupported)
|
# Apple Metal JAX (experimental; complex64/complex128 currently unsupported)
|
||||||
# jax-metal
|
# jax-metal
|
||||||
# NVIDIA Linux JAX
|
# NVIDIA Linux JAX
|
||||||
jax[cuda13]
|
jax[cuda13]
|
||||||
# or, if needed:
|
# or, if needed:
|
||||||
# jax[cuda12]
|
# jax[cuda12]
|
||||||
@@ -1,324 +0,0 @@
|
|||||||
from __future__ import annotations
|
|
||||||
|
|
||||||
import csv
|
|
||||||
import math
|
|
||||||
from dataclasses import dataclass, field
|
|
||||||
from pathlib import Path
|
|
||||||
from typing import Sequence
|
|
||||||
|
|
||||||
import matplotlib.pyplot as plt
|
|
||||||
import numpy as np
|
|
||||||
from tqdm.auto import tqdm
|
|
||||||
|
|
||||||
from spaces import HAS_JAX, MetricMeasureSpace, jax, random
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
|
||||||
class SystemResult:
|
|
||||||
"""Compact record of one simulated metric-measure system."""
|
|
||||||
family: str
|
|
||||||
label: str
|
|
||||||
slug: str
|
|
||||||
intrinsic_dim: int
|
|
||||||
num_samples: int
|
|
||||||
kappa: float
|
|
||||||
mass: float
|
|
||||||
observable_max: float
|
|
||||||
values: np.ndarray
|
|
||||||
partial_diameter: float
|
|
||||||
interval_left: float
|
|
||||||
interval_right: float
|
|
||||||
mean: float
|
|
||||||
median: float
|
|
||||||
std: float
|
|
||||||
empirical_lipschitz_max: float
|
|
||||||
empirical_lipschitz_q99: float
|
|
||||||
normalized_proxy_max: float
|
|
||||||
normalized_proxy_q99: float
|
|
||||||
theory: dict[str, float] = field(default_factory=dict)
|
|
||||||
|
|
||||||
|
|
||||||
def partial_diameter(samples: np.ndarray, mass: float) -> tuple[float, float, float]:
|
|
||||||
"""Shortest interval carrying the requested empirical mass."""
|
|
||||||
x = np.sort(np.asarray(samples, float))
|
|
||||||
n = len(x)
|
|
||||||
if n == 0 or not (0.0 < mass <= 1.0):
|
|
||||||
raise ValueError("Need nonempty samples and mass in (0,1].")
|
|
||||||
if n == 1:
|
|
||||||
return 0.0, float(x[0]), float(x[0])
|
|
||||||
m = max(1, int(math.ceil(mass * n)))
|
|
||||||
if m <= 1:
|
|
||||||
return 0.0, float(x[0]), float(x[0])
|
|
||||||
w = x[m - 1 :] - x[: n - m + 1]
|
|
||||||
i = int(np.argmin(w))
|
|
||||||
return float(w[i]), float(x[i]), float(x[i + m - 1])
|
|
||||||
|
|
||||||
|
|
||||||
def empirical_lipschitz(
|
|
||||||
space: MetricMeasureSpace,
|
|
||||||
states: np.ndarray,
|
|
||||||
values: np.ndarray,
|
|
||||||
rng: np.random.Generator,
|
|
||||||
num_pairs: int,
|
|
||||||
) -> tuple[float, float]:
|
|
||||||
"""Estimate max and q99 slope over random state pairs."""
|
|
||||||
n = len(states)
|
|
||||||
if n < 2 or num_pairs <= 0:
|
|
||||||
return float("nan"), float("nan")
|
|
||||||
i = rng.integers(0, n, size=num_pairs)
|
|
||||||
j = rng.integers(0, n - 1, size=num_pairs)
|
|
||||||
j += (j >= i)
|
|
||||||
d = space.metric_pairs(states[i], states[j])
|
|
||||||
good = d > 1e-12
|
|
||||||
if not np.any(good):
|
|
||||||
return float("nan"), float("nan")
|
|
||||||
r = np.abs(values[i] - values[j])[good] / d[good]
|
|
||||||
return float(np.max(r)), float(np.quantile(r, 0.99))
|
|
||||||
|
|
||||||
|
|
||||||
def _sample_stream(
|
|
||||||
space: MetricMeasureSpace,
|
|
||||||
n: int,
|
|
||||||
batch: int,
|
|
||||||
seed: int,
|
|
||||||
backend: str,
|
|
||||||
keep_states: bool,
|
|
||||||
) -> tuple[np.ndarray | None, np.ndarray]:
|
|
||||||
"""Sample values, optionally keeping state vectors for Lipschitz estimation."""
|
|
||||||
vals = np.empty(n, dtype=np.float32)
|
|
||||||
states = np.empty((n, space.state_dim), dtype=np.float32 if space.family == "sphere" else np.complex64) if keep_states else None
|
|
||||||
use_jax = backend != "numpy" and HAS_JAX
|
|
||||||
desc = f"{space.slug}: {n:,} samples"
|
|
||||||
if use_jax:
|
|
||||||
key = random.PRNGKey(seed)
|
|
||||||
for s in tqdm(range(0, n, batch), desc=desc, unit="batch"):
|
|
||||||
b = min(batch, n - s)
|
|
||||||
key, sub = random.split(key)
|
|
||||||
x, y = space.sample_jax(sub, b)
|
|
||||||
vals[s : s + b] = np.asarray(jax.device_get(y), dtype=np.float32)
|
|
||||||
if keep_states:
|
|
||||||
states[s : s + b] = np.asarray(jax.device_get(x), dtype=states.dtype)
|
|
||||||
else:
|
|
||||||
rng = np.random.default_rng(seed)
|
|
||||||
for s in tqdm(range(0, n, batch), desc=desc, unit="batch"):
|
|
||||||
b = min(batch, n - s)
|
|
||||||
x, y = space.sample_np(rng, b)
|
|
||||||
vals[s : s + b] = y
|
|
||||||
if keep_states:
|
|
||||||
states[s : s + b] = x.astype(states.dtype)
|
|
||||||
return states, vals
|
|
||||||
|
|
||||||
|
|
||||||
def simulate_space(
|
|
||||||
space: MetricMeasureSpace,
|
|
||||||
*,
|
|
||||||
num_samples: int,
|
|
||||||
batch: int,
|
|
||||||
kappa: float,
|
|
||||||
seed: int,
|
|
||||||
backend: str,
|
|
||||||
lipschitz_pairs: int,
|
|
||||||
lipschitz_reservoir: int,
|
|
||||||
) -> SystemResult:
|
|
||||||
"""Main Monte Carlo pass plus a smaller Lipschitz pass."""
|
|
||||||
vals = _sample_stream(space, num_samples, batch, seed, backend, keep_states=False)[1]
|
|
||||||
mass = 1.0 - kappa
|
|
||||||
width, left, right = partial_diameter(vals, mass)
|
|
||||||
|
|
||||||
r_states, r_vals = _sample_stream(space, min(lipschitz_reservoir, num_samples), min(batch, lipschitz_reservoir), seed + 1, backend, keep_states=True)
|
|
||||||
lip_rng = np.random.default_rng(seed + 2)
|
|
||||||
lip_max, lip_q99 = empirical_lipschitz(space, r_states, r_vals, lip_rng, lipschitz_pairs)
|
|
||||||
nmax = width / lip_max if lip_max == lip_max and lip_max > 0 else float("nan")
|
|
||||||
nq99 = width / lip_q99 if lip_q99 == lip_q99 and lip_q99 > 0 else float("nan")
|
|
||||||
|
|
||||||
return SystemResult(
|
|
||||||
family=space.family,
|
|
||||||
label=space.label,
|
|
||||||
slug=space.slug,
|
|
||||||
intrinsic_dim=space.intrinsic_dim,
|
|
||||||
num_samples=num_samples,
|
|
||||||
kappa=kappa,
|
|
||||||
mass=mass,
|
|
||||||
observable_max=space.observable_max,
|
|
||||||
values=vals,
|
|
||||||
partial_diameter=width,
|
|
||||||
interval_left=left,
|
|
||||||
interval_right=right,
|
|
||||||
mean=float(np.mean(vals)),
|
|
||||||
median=float(np.median(vals)),
|
|
||||||
std=float(np.std(vals, ddof=1)) if len(vals) > 1 else 0.0,
|
|
||||||
empirical_lipschitz_max=lip_max,
|
|
||||||
empirical_lipschitz_q99=lip_q99,
|
|
||||||
normalized_proxy_max=nmax,
|
|
||||||
normalized_proxy_q99=nq99,
|
|
||||||
theory=space.theory(kappa),
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def write_summary_csv(results: Sequence[SystemResult], out_path: Path) -> None:
|
|
||||||
"""Write one flat CSV with optional theory fields."""
|
|
||||||
extras = sorted({k for r in results for k in r.theory})
|
|
||||||
fields = [
|
|
||||||
"family", "label", "intrinsic_dim", "num_samples", "kappa", "mass",
|
|
||||||
"observable_max_bits", "partial_diameter_bits", "interval_left_bits", "interval_right_bits",
|
|
||||||
"mean_bits", "median_bits", "std_bits", "empirical_lipschitz_max", "empirical_lipschitz_q99",
|
|
||||||
"normalized_proxy_max", "normalized_proxy_q99",
|
|
||||||
] + extras
|
|
||||||
with out_path.open("w", newline="") as fh:
|
|
||||||
w = csv.DictWriter(fh, fieldnames=fields)
|
|
||||||
w.writeheader()
|
|
||||||
for r in results:
|
|
||||||
row = {
|
|
||||||
"family": r.family,
|
|
||||||
"label": r.label,
|
|
||||||
"intrinsic_dim": r.intrinsic_dim,
|
|
||||||
"num_samples": r.num_samples,
|
|
||||||
"kappa": r.kappa,
|
|
||||||
"mass": r.mass,
|
|
||||||
"observable_max_bits": r.observable_max,
|
|
||||||
"partial_diameter_bits": r.partial_diameter,
|
|
||||||
"interval_left_bits": r.interval_left,
|
|
||||||
"interval_right_bits": r.interval_right,
|
|
||||||
"mean_bits": r.mean,
|
|
||||||
"median_bits": r.median,
|
|
||||||
"std_bits": r.std,
|
|
||||||
"empirical_lipschitz_max": r.empirical_lipschitz_max,
|
|
||||||
"empirical_lipschitz_q99": r.empirical_lipschitz_q99,
|
|
||||||
"normalized_proxy_max": r.normalized_proxy_max,
|
|
||||||
"normalized_proxy_q99": r.normalized_proxy_q99,
|
|
||||||
}
|
|
||||||
row.update(r.theory)
|
|
||||||
w.writerow(row)
|
|
||||||
|
|
||||||
|
|
||||||
def plot_histogram(r: SystemResult, outdir: Path) -> None:
|
|
||||||
"""Per-system histogram with interval and theory overlays when available."""
|
|
||||||
v = r.values
|
|
||||||
vmin, vmax = float(np.min(v)), float(np.max(v))
|
|
||||||
vr = max(vmax - vmin, 1e-9)
|
|
||||||
plt.figure(figsize=(8.5, 5.5))
|
|
||||||
plt.hist(v, bins=48, density=True, alpha=0.75)
|
|
||||||
plt.axvspan(r.interval_left, r.interval_right, alpha=0.18, label=f"shortest {(r.mass):.0%} interval")
|
|
||||||
plt.axvline(r.observable_max, linestyle="--", linewidth=2, label="observable upper bound")
|
|
||||||
plt.axvline(r.mean, linestyle="-.", linewidth=2, label="empirical mean")
|
|
||||||
if "page_average_bits" in r.theory:
|
|
||||||
plt.axvline(r.theory["page_average_bits"], linestyle=":", linewidth=2, label="Page average")
|
|
||||||
if "hayden_cutoff_bits" in r.theory:
|
|
||||||
plt.axvline(r.theory["hayden_cutoff_bits"], linewidth=2, label="Hayden cutoff")
|
|
||||||
plt.xlim(vmin - 0.1 * vr, vmax + 0.25 * vr)
|
|
||||||
plt.xlabel("Entropy observable (bits)")
|
|
||||||
plt.ylabel("Empirical density")
|
|
||||||
plt.title(r.label)
|
|
||||||
plt.legend(frameon=False)
|
|
||||||
plt.tight_layout()
|
|
||||||
plt.savefig(outdir / f"hist_{r.slug}.png", dpi=180)
|
|
||||||
plt.close()
|
|
||||||
|
|
||||||
|
|
||||||
def plot_tail(r: SystemResult, space: MetricMeasureSpace, outdir: Path) -> None:
|
|
||||||
"""Upper-tail plot for the entropy deficit from its natural ceiling."""
|
|
||||||
deficits = r.observable_max - np.sort(r.values)
|
|
||||||
n = len(deficits)
|
|
||||||
ccdf = np.maximum(1.0 - (np.arange(1, n + 1) / n), 1.0 / n)
|
|
||||||
x = np.linspace(0.0, max(float(np.max(deficits)), 1e-6), 256)
|
|
||||||
plt.figure(figsize=(8.5, 5.5))
|
|
||||||
plt.semilogy(deficits, ccdf, marker="o", linestyle="none", markersize=3, alpha=0.45, label="empirical tail")
|
|
||||||
bound = space.tail_bound(x)
|
|
||||||
if bound is not None:
|
|
||||||
plt.semilogy(x, bound, linewidth=2, label="theory bound")
|
|
||||||
plt.xlabel("Entropy deficit (bits)")
|
|
||||||
plt.ylabel("Tail probability")
|
|
||||||
plt.title(f"Tail plot: {r.label}")
|
|
||||||
plt.legend(frameon=False)
|
|
||||||
plt.tight_layout()
|
|
||||||
plt.savefig(outdir / f"tail_{r.slug}.png", dpi=180)
|
|
||||||
plt.close()
|
|
||||||
|
|
||||||
|
|
||||||
def plot_family_summary(results: Sequence[SystemResult], family: str, outdir: Path) -> None:
|
|
||||||
"""Original-style summary plots, one family at a time."""
|
|
||||||
rs = sorted([r for r in results if r.family == family], key=lambda z: z.intrinsic_dim)
|
|
||||||
if not rs:
|
|
||||||
return
|
|
||||||
x = np.array([r.intrinsic_dim for r in rs], float)
|
|
||||||
pd = np.array([r.partial_diameter for r in rs], float)
|
|
||||||
sd = np.array([r.std for r in rs], float)
|
|
||||||
md = np.array([r.observable_max - r.mean for r in rs], float)
|
|
||||||
|
|
||||||
plt.figure(figsize=(8.5, 5.5))
|
|
||||||
plt.plot(x, pd, marker="o", linewidth=2, label=r"shortest $(1-\kappa)$ interval")
|
|
||||||
plt.plot(x, sd, marker="s", linewidth=2, label="empirical std")
|
|
||||||
plt.plot(x, md, marker="^", linewidth=2, label="mean deficit")
|
|
||||||
plt.xlabel("Intrinsic dimension")
|
|
||||||
plt.ylabel("Bits")
|
|
||||||
plt.title(f"Concentration summary: {family}")
|
|
||||||
plt.legend(frameon=False)
|
|
||||||
plt.tight_layout()
|
|
||||||
plt.savefig(outdir / f"summary_{family}.png", dpi=180)
|
|
||||||
plt.close()
|
|
||||||
|
|
||||||
good = [r for r in rs if r.normalized_proxy_q99 == r.normalized_proxy_q99]
|
|
||||||
if good:
|
|
||||||
x = np.array([r.intrinsic_dim for r in good], float)
|
|
||||||
y1 = np.array([r.normalized_proxy_max for r in good], float)
|
|
||||||
y2 = np.array([r.normalized_proxy_q99 for r in good], float)
|
|
||||||
plt.figure(figsize=(8.5, 5.5))
|
|
||||||
plt.plot(x, y1, marker="o", linewidth=2, label="width / Lipschitz max")
|
|
||||||
plt.plot(x, y2, marker="s", linewidth=2, label="width / Lipschitz q99")
|
|
||||||
plt.xlabel("Intrinsic dimension")
|
|
||||||
plt.ylabel("Normalized proxy")
|
|
||||||
plt.title(f"Lipschitz-normalized proxy: {family}")
|
|
||||||
plt.legend(frameon=False)
|
|
||||||
plt.tight_layout()
|
|
||||||
plt.savefig(outdir / f"normalized_{family}.png", dpi=180)
|
|
||||||
plt.close()
|
|
||||||
|
|
||||||
|
|
||||||
def plot_cross_space_comparison(results: Sequence[SystemResult], outdir: Path) -> None:
|
|
||||||
"""Direct comparison of the three spaces on one figure."""
|
|
||||||
marks = {"sphere": "o", "cp": "s", "majorana": "^"}
|
|
||||||
|
|
||||||
plt.figure(figsize=(8.8, 5.6))
|
|
||||||
for fam in ("sphere", "cp", "majorana"):
|
|
||||||
rs = sorted([r for r in results if r.family == fam], key=lambda z: z.intrinsic_dim)
|
|
||||||
if rs:
|
|
||||||
plt.plot([r.intrinsic_dim for r in rs], [r.partial_diameter for r in rs], marker=marks[fam], linewidth=2, label=fam)
|
|
||||||
plt.xlabel("Intrinsic dimension")
|
|
||||||
plt.ylabel("Partial diameter in bits")
|
|
||||||
plt.title("Entropy-based observable-diameter proxy: raw width comparison")
|
|
||||||
plt.legend(frameon=False)
|
|
||||||
plt.tight_layout()
|
|
||||||
plt.savefig(outdir / "compare_partial_diameter.png", dpi=180)
|
|
||||||
plt.close()
|
|
||||||
|
|
||||||
plt.figure(figsize=(8.8, 5.6))
|
|
||||||
for fam in ("sphere", "cp", "majorana"):
|
|
||||||
rs = sorted([r for r in results if r.family == fam and r.normalized_proxy_q99 == r.normalized_proxy_q99], key=lambda z: z.intrinsic_dim)
|
|
||||||
if rs:
|
|
||||||
plt.plot([r.intrinsic_dim for r in rs], [r.normalized_proxy_q99 for r in rs], marker=marks[fam], linewidth=2, label=fam)
|
|
||||||
plt.xlabel("Intrinsic dimension")
|
|
||||||
plt.ylabel("Normalized proxy")
|
|
||||||
plt.title("Entropy-based observable-diameter proxy: normalized comparison")
|
|
||||||
plt.legend(frameon=False)
|
|
||||||
plt.tight_layout()
|
|
||||||
plt.savefig(outdir / "compare_normalized_proxy.png", dpi=180)
|
|
||||||
plt.close()
|
|
||||||
|
|
||||||
|
|
||||||
def plot_majorana_stars(space: MetricMeasureSpace, states: np.ndarray, outdir: Path) -> None:
|
|
||||||
"""Scatter Majorana stars in longitude/latitude coordinates."""
|
|
||||||
if not hasattr(space, "majorana_stars") or len(states) == 0:
|
|
||||||
return
|
|
||||||
pts = np.vstack([space.majorana_stars(s) for s in states])
|
|
||||||
x, y, z = pts[:, 0], pts[:, 1], np.clip(pts[:, 2], -1.0, 1.0)
|
|
||||||
lon, lat = np.arctan2(y, x), np.arcsin(z)
|
|
||||||
plt.figure(figsize=(8.8, 4.6))
|
|
||||||
plt.scatter(lon, lat, s=10, alpha=0.35)
|
|
||||||
plt.xlim(-math.pi, math.pi)
|
|
||||||
plt.ylim(-math.pi / 2, math.pi / 2)
|
|
||||||
plt.xlabel("longitude")
|
|
||||||
plt.ylabel("latitude")
|
|
||||||
plt.title(f"Majorana stars: {space.label}")
|
|
||||||
plt.tight_layout()
|
|
||||||
plt.savefig(outdir / f"majorana_stars_{space.slug}.png", dpi=180)
|
|
||||||
plt.close()
|
|
||||||
@@ -1,284 +1,338 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import math
|
import math
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import jax
|
import jax
|
||||||
import jax.numpy as jnp
|
import jax.numpy as jnp
|
||||||
from jax import random
|
from jax import random
|
||||||
|
|
||||||
jax.config.update("jax_enable_x64", False)
|
jax.config.update("jax_enable_x64", False)
|
||||||
HAS_JAX = True
|
HAS_JAX = True
|
||||||
except Exception: # pragma: no cover
|
except Exception: # pragma: no cover
|
||||||
jax = jnp = random = None
|
jax = jnp = random = None
|
||||||
HAS_JAX = False
|
HAS_JAX = False
|
||||||
|
|
||||||
HAYDEN_C = 1.0 / (8.0 * math.pi**2)
|
HAYDEN_C = 1.0 / (8.0 * math.pi**2)
|
||||||
|
|
||||||
|
|
||||||
def entropy_bits_from_probs(p: Any, xp: Any) -> Any:
|
def entropy_bits_from_probs(p: Any, xp: Any) -> Any:
|
||||||
"""Return Shannon/von-Neumann entropy of probabilities/eigenvalues in bits."""
|
"""Return Shannon/von-Neumann entropy of probabilities/eigenvalues in bits."""
|
||||||
p = xp.clip(xp.real(p), 1e-30, 1.0)
|
p = xp.clip(xp.real(p), 1e-30, 1.0)
|
||||||
return -xp.sum(p * xp.log2(p), axis=-1)
|
return -xp.sum(p * xp.log2(p), axis=-1)
|
||||||
|
|
||||||
|
|
||||||
def fs_metric_np(x: np.ndarray, y: np.ndarray) -> np.ndarray:
|
def fs_metric_np(x: np.ndarray, y: np.ndarray) -> np.ndarray:
|
||||||
"""Fubini-Study distance for batches of normalized complex vectors."""
|
"""Fubini-Study distance for batches of normalized complex vectors."""
|
||||||
ov = np.abs(np.sum(np.conj(x) * y, axis=-1))
|
ov = np.abs(np.sum(np.conj(x) * y, axis=-1))
|
||||||
return np.arccos(np.clip(ov, 0.0, 1.0))
|
return np.arccos(np.clip(ov, 0.0, 1.0))
|
||||||
|
|
||||||
|
|
||||||
def sphere_metric_np(x: np.ndarray, y: np.ndarray) -> np.ndarray:
|
def sphere_metric_np(x: np.ndarray, y: np.ndarray) -> np.ndarray:
|
||||||
"""Geodesic distance on the real unit sphere."""
|
"""Geodesic distance on the real unit sphere."""
|
||||||
dot = np.sum(x * y, axis=-1)
|
dot = np.sum(x * y, axis=-1)
|
||||||
return np.arccos(np.clip(dot, -1.0, 1.0))
|
return np.arccos(np.clip(dot, -1.0, 1.0))
|
||||||
|
|
||||||
|
|
||||||
class MetricMeasureSpace:
|
class MetricMeasureSpace:
|
||||||
"""Minimal interface: direct sampler + metric + scalar observable ceiling."""
|
"""Minimal interface: direct sampler + metric + scalar observable ceiling."""
|
||||||
|
|
||||||
family: str = "base"
|
family: str = "base"
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def label(self) -> str:
|
def label(self) -> str:
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def slug(self) -> str:
|
def slug(self) -> str:
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def intrinsic_dim(self) -> int:
|
def intrinsic_dim(self) -> int:
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def state_dim(self) -> int:
|
def state_dim(self) -> int:
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def observable_max(self) -> float:
|
def observable_max(self) -> float:
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
def sample_np(self, rng: np.random.Generator, batch: int) -> tuple[np.ndarray, np.ndarray]:
|
def sample_np(
|
||||||
raise NotImplementedError
|
self, rng: np.random.Generator, batch: int
|
||||||
|
) -> tuple[np.ndarray, np.ndarray]:
|
||||||
def sample_jax(self, key: Any, batch: int) -> tuple[Any, Any]:
|
raise NotImplementedError
|
||||||
raise NotImplementedError
|
|
||||||
|
def sample_jax(self, key: Any, batch: int) -> tuple[Any, Any]:
|
||||||
def metric_pairs(self, x: np.ndarray, y: np.ndarray) -> np.ndarray:
|
raise NotImplementedError
|
||||||
raise NotImplementedError
|
|
||||||
|
def metric_pairs(self, x: np.ndarray, y: np.ndarray) -> np.ndarray:
|
||||||
def theory(self, kappa: float) -> dict[str, float]:
|
raise NotImplementedError
|
||||||
return {}
|
|
||||||
|
def theory(self, kappa: float) -> dict[str, float]:
|
||||||
def tail_bound(self, deficits: np.ndarray) -> np.ndarray | None:
|
return {}
|
||||||
return None
|
|
||||||
|
def tail_bound(self, deficits: np.ndarray) -> np.ndarray | None:
|
||||||
|
return None
|
||||||
@dataclass
|
|
||||||
class UnitSphereSpace(MetricMeasureSpace):
|
|
||||||
"""Uniform measure on the real unit sphere S^(m-1), observable H(x_i^2)."""
|
@dataclass
|
||||||
|
class UnitSphereSpace(MetricMeasureSpace):
|
||||||
dim: int
|
"""Uniform measure on the real unit sphere S^(m-1), observable H(x_i^2)."""
|
||||||
family: str = "sphere"
|
|
||||||
|
dim: int
|
||||||
@property
|
family: str = "sphere"
|
||||||
def label(self) -> str:
|
|
||||||
return f"S^{self.dim - 1}"
|
@property
|
||||||
|
def label(self) -> str:
|
||||||
@property
|
return f"S^{self.dim - 1}"
|
||||||
def slug(self) -> str:
|
|
||||||
return f"sphere_{self.dim}"
|
@property
|
||||||
|
def slug(self) -> str:
|
||||||
@property
|
return f"sphere_{self.dim}"
|
||||||
def intrinsic_dim(self) -> int:
|
|
||||||
return self.dim - 1
|
@property
|
||||||
|
def intrinsic_dim(self) -> int:
|
||||||
@property
|
return self.dim - 1
|
||||||
def state_dim(self) -> int:
|
|
||||||
return self.dim
|
@property
|
||||||
|
def state_dim(self) -> int:
|
||||||
@property
|
return self.dim
|
||||||
def observable_max(self) -> float:
|
|
||||||
return math.log2(self.dim)
|
@property
|
||||||
|
def observable_max(self) -> float:
|
||||||
def sample_np(self, rng: np.random.Generator, batch: int) -> tuple[np.ndarray, np.ndarray]:
|
return math.log2(self.dim)
|
||||||
x = rng.normal(size=(batch, self.dim)).astype(np.float32)
|
|
||||||
x /= np.linalg.norm(x, axis=1, keepdims=True)
|
def sample_np(
|
||||||
return x, entropy_bits_from_probs(x * x, np).astype(np.float32)
|
self, rng: np.random.Generator, batch: int
|
||||||
|
) -> tuple[np.ndarray, np.ndarray]:
|
||||||
def sample_jax(self, key: Any, batch: int) -> tuple[Any, Any]:
|
x = rng.normal(size=(batch, self.dim)).astype(np.float32)
|
||||||
x = random.normal(key, (batch, self.dim), dtype=jnp.float32)
|
x /= np.linalg.norm(x, axis=1, keepdims=True)
|
||||||
x /= jnp.linalg.norm(x, axis=1, keepdims=True)
|
return x, entropy_bits_from_probs(x * x, np).astype(np.float32)
|
||||||
return x, entropy_bits_from_probs(x * x, jnp)
|
|
||||||
|
def sample_jax(self, key: Any, batch: int) -> tuple[Any, Any]:
|
||||||
def metric_pairs(self, x: np.ndarray, y: np.ndarray) -> np.ndarray:
|
x = random.normal(key, (batch, self.dim), dtype=jnp.float32)
|
||||||
return sphere_metric_np(x, y)
|
x /= jnp.linalg.norm(x, axis=1, keepdims=True)
|
||||||
|
return x, entropy_bits_from_probs(x * x, jnp)
|
||||||
|
|
||||||
@dataclass
|
def metric_pairs(self, x: np.ndarray, y: np.ndarray) -> np.ndarray:
|
||||||
class ComplexProjectiveSpace(MetricMeasureSpace):
|
return sphere_metric_np(x, y)
|
||||||
"""Haar-random pure states on C^(d_A d_B), observable = entanglement entropy."""
|
|
||||||
|
|
||||||
d_a: int
|
@dataclass
|
||||||
d_b: int
|
class ComplexProjectiveSpace(MetricMeasureSpace):
|
||||||
family: str = "cp"
|
"""Haar-random pure states on C^(d_A d_B), observable = entanglement entropy."""
|
||||||
|
|
||||||
def __post_init__(self) -> None:
|
d_a: int
|
||||||
if self.d_a <= 1 or self.d_b <= 1:
|
d_b: int
|
||||||
raise ValueError("Need d_A,d_B >= 2.")
|
family: str = "cp"
|
||||||
if self.d_a > self.d_b:
|
|
||||||
self.d_a, self.d_b = self.d_b, self.d_a
|
def __post_init__(self) -> None:
|
||||||
|
if self.d_a <= 1 or self.d_b <= 1:
|
||||||
@property
|
raise ValueError("Need d_A,d_B >= 2.")
|
||||||
def label(self) -> str:
|
if self.d_a > self.d_b:
|
||||||
return f"CP^{self.d_a * self.d_b - 1} via C^{self.d_a}⊗C^{self.d_b}"
|
self.d_a, self.d_b = self.d_b, self.d_a
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def slug(self) -> str:
|
def label(self) -> str:
|
||||||
return f"cp_{self.d_a}x{self.d_b}"
|
return f"CP^{self.d_a * self.d_b - 1} via C^{self.d_a}⊗C^{self.d_b}"
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def intrinsic_dim(self) -> int:
|
def slug(self) -> str:
|
||||||
return self.d_a * self.d_b - 1
|
return f"cp_{self.d_a}x{self.d_b}"
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def state_dim(self) -> int:
|
def intrinsic_dim(self) -> int:
|
||||||
return self.d_a * self.d_b
|
return self.d_a * self.d_b - 1
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def observable_max(self) -> float:
|
def state_dim(self) -> int:
|
||||||
return math.log2(self.d_a)
|
return self.d_a * self.d_b
|
||||||
|
|
||||||
def sample_np(self, rng: np.random.Generator, batch: int) -> tuple[np.ndarray, np.ndarray]:
|
@property
|
||||||
g = (rng.normal(size=(batch, self.d_a, self.d_b)) + 1j * rng.normal(size=(batch, self.d_a, self.d_b)))
|
def observable_max(self) -> float:
|
||||||
g = (g / math.sqrt(2.0)).astype(np.complex64)
|
return math.log2(self.d_a)
|
||||||
g /= np.sqrt(np.sum(np.abs(g) ** 2, axis=(1, 2), keepdims=True))
|
|
||||||
rho = g @ np.swapaxes(np.conj(g), 1, 2)
|
def sample_np(
|
||||||
lam = np.clip(np.linalg.eigvalsh(rho).real, 1e-30, 1.0)
|
self, rng: np.random.Generator, batch: int
|
||||||
return g.reshape(batch, -1), entropy_bits_from_probs(lam, np).astype(np.float32)
|
) -> tuple[np.ndarray, np.ndarray]:
|
||||||
|
"""
|
||||||
def sample_jax(self, key: Any, batch: int) -> tuple[Any, Any]:
|
Sample haars-random pure states on C^(d_A d_B), observable = entanglement entropy.
|
||||||
k1, k2 = random.split(key)
|
|
||||||
g = (random.normal(k1, (batch, self.d_a, self.d_b), dtype=jnp.float32)
|
Parameters
|
||||||
+ 1j * random.normal(k2, (batch, self.d_a, self.d_b), dtype=jnp.float32)) / math.sqrt(2.0)
|
----------
|
||||||
g = g / jnp.sqrt(jnp.sum(jnp.abs(g) ** 2, axis=(1, 2), keepdims=True))
|
rng : np.random.Generator
|
||||||
rho = g @ jnp.swapaxes(jnp.conj(g), -1, -2)
|
Random number generator.
|
||||||
lam = jnp.clip(jnp.linalg.eigvalsh(rho).real, 1e-30, 1.0)
|
batch : int
|
||||||
return g.reshape(batch, -1), entropy_bits_from_probs(lam, jnp)
|
Number of samples to generate.
|
||||||
|
|
||||||
def metric_pairs(self, x: np.ndarray, y: np.ndarray) -> np.ndarray:
|
Returns
|
||||||
return fs_metric_np(x, y)
|
-------
|
||||||
|
x : np.ndarray
|
||||||
def theory(self, kappa: float) -> dict[str, float]:
|
Shape (batch, d_a * d_b), complex64.
|
||||||
d = self.d_a * self.d_b
|
y : np.ndarray
|
||||||
beta = self.d_a / (math.log(2.0) * self.d_b)
|
Shape (batch,), float32.
|
||||||
alpha = (math.log2(self.d_a) / math.sqrt(HAYDEN_C * (d - 1.0))) * math.sqrt(math.log(1.0 / kappa))
|
"""
|
||||||
tail = sum(1.0 / k for k in range(self.d_b + 1, d + 1))
|
g = rng.normal(size=(batch, self.d_a, self.d_b)) + 1j * rng.normal(
|
||||||
page = (tail - (self.d_a - 1.0) / (2.0 * self.d_b)) / math.log(2.0)
|
size=(batch, self.d_a, self.d_b)
|
||||||
return {
|
)
|
||||||
"page_average_bits": page,
|
g = (g / math.sqrt(2.0)).astype(np.complex64)
|
||||||
"hayden_mean_lower_bits": math.log2(self.d_a) - beta,
|
g /= np.sqrt(np.sum(np.abs(g) ** 2, axis=(1, 2), keepdims=True))
|
||||||
"hayden_cutoff_bits": math.log2(self.d_a) - (beta + alpha),
|
rho = g @ np.swapaxes(np.conj(g), 1, 2)
|
||||||
"hayden_one_sided_width_bits": beta + alpha,
|
lam = np.clip(np.linalg.eigvalsh(rho).real, 1e-30, 1.0)
|
||||||
"levy_scaling_width_bits": 2.0
|
return g.reshape(batch, -1), entropy_bits_from_probs(lam, np).astype(np.float32)
|
||||||
* (math.log2(self.d_a) / math.sqrt(HAYDEN_C * (d - 1.0)))
|
|
||||||
* math.sqrt(math.log(2.0 / kappa)),
|
def sample_jax(self, key: Any, batch: int) -> tuple[Any, Any]:
|
||||||
}
|
k1, k2 = random.split(key)
|
||||||
|
g = (
|
||||||
def tail_bound(self, deficits: np.ndarray) -> np.ndarray:
|
random.normal(k1, (batch, self.d_a, self.d_b), dtype=jnp.float32)
|
||||||
beta = self.d_a / (math.log(2.0) * self.d_b)
|
+ 1j * random.normal(k2, (batch, self.d_a, self.d_b), dtype=jnp.float32)
|
||||||
shifted = np.maximum(np.asarray(deficits, float) - beta, 0.0)
|
) / math.sqrt(2.0)
|
||||||
expo = -(self.d_a * self.d_b - 1.0) * HAYDEN_C * shifted**2 / (math.log2(self.d_a) ** 2)
|
g = g / jnp.sqrt(jnp.sum(jnp.abs(g) ** 2, axis=(1, 2), keepdims=True))
|
||||||
out = np.exp(expo)
|
rho = g @ jnp.swapaxes(jnp.conj(g), -1, -2)
|
||||||
out[deficits <= beta] = 1.0
|
lam = jnp.clip(jnp.linalg.eigvalsh(rho).real, 1e-30, 1.0)
|
||||||
return np.clip(out, 0.0, 1.0)
|
return g.reshape(batch, -1), entropy_bits_from_probs(lam, jnp)
|
||||||
|
|
||||||
|
def metric_pairs(self, x: np.ndarray, y: np.ndarray) -> np.ndarray:
|
||||||
@dataclass
|
return fs_metric_np(x, y)
|
||||||
class MajoranaSymmetricSpace(MetricMeasureSpace):
|
|
||||||
"""Haar-random symmetric N-qubit states; stars are for visualization only."""
|
def theory(self, kappa: float) -> dict[str, float]:
|
||||||
|
d = self.d_a * self.d_b
|
||||||
N: int
|
beta = self.d_a / (math.log(2.0) * self.d_b)
|
||||||
family: str = "majorana"
|
alpha = (math.log2(self.d_a) / math.sqrt(HAYDEN_C * (d - 1.0))) * math.sqrt(
|
||||||
|
math.log(1.0 / kappa)
|
||||||
@property
|
)
|
||||||
def label(self) -> str:
|
tail = sum(1.0 / k for k in range(self.d_b + 1, d + 1))
|
||||||
return f"Sym^{self.N}(C^2) ≅ CP^{self.N}"
|
page = (tail - (self.d_a - 1.0) / (2.0 * self.d_b)) / math.log(2.0)
|
||||||
|
return {
|
||||||
@property
|
"page_average_bits": page,
|
||||||
def slug(self) -> str:
|
"hayden_mean_lower_bits": math.log2(self.d_a) - beta,
|
||||||
return f"majorana_{self.N}"
|
"hayden_cutoff_bits": math.log2(self.d_a) - (beta + alpha),
|
||||||
|
"hayden_one_sided_width_bits": beta + alpha,
|
||||||
@property
|
"levy_scaling_width_bits": 2.0
|
||||||
def intrinsic_dim(self) -> int:
|
* (math.log2(self.d_a) / math.sqrt(HAYDEN_C * (d - 1.0)))
|
||||||
return self.N
|
* math.sqrt(math.log(2.0 / kappa)),
|
||||||
|
}
|
||||||
@property
|
|
||||||
def state_dim(self) -> int:
|
def tail_bound(self, deficits: np.ndarray) -> np.ndarray:
|
||||||
return self.N + 1
|
beta = self.d_a / (math.log(2.0) * self.d_b)
|
||||||
|
shifted = np.maximum(np.asarray(deficits, float) - beta, 0.0)
|
||||||
@property
|
expo = (
|
||||||
def observable_max(self) -> float:
|
-(self.d_a * self.d_b - 1.0)
|
||||||
return 1.0 # one-qubit entropy upper bound
|
* HAYDEN_C
|
||||||
|
* shifted**2
|
||||||
def _rho1_np(self, c: np.ndarray) -> np.ndarray:
|
/ (math.log2(self.d_a) ** 2)
|
||||||
k = np.arange(self.N + 1, dtype=np.float32)
|
)
|
||||||
p = np.abs(c) ** 2
|
out = np.exp(expo)
|
||||||
rho11 = (p * k).sum(axis=1) / self.N
|
out[deficits <= beta] = 1.0
|
||||||
coef = np.sqrt((np.arange(self.N, dtype=np.float32) + 1.0) * (self.N - np.arange(self.N, dtype=np.float32))) / self.N
|
return np.clip(out, 0.0, 1.0)
|
||||||
off = (np.conj(c[:, :-1]) * c[:, 1:] * coef).sum(axis=1)
|
|
||||||
rho = np.zeros((len(c), 2, 2), dtype=np.complex64)
|
|
||||||
rho[:, 0, 0] = 1.0 - rho11
|
@dataclass
|
||||||
rho[:, 1, 1] = rho11
|
class MajoranaSymmetricSpace(MetricMeasureSpace):
|
||||||
rho[:, 0, 1] = off
|
"""Haar-random symmetric N-qubit states; stars are for visualization only."""
|
||||||
rho[:, 1, 0] = np.conj(off)
|
|
||||||
return rho
|
N: int
|
||||||
|
family: str = "majorana"
|
||||||
def _rho1_jax(self, c: Any) -> Any:
|
|
||||||
k = jnp.arange(self.N + 1, dtype=jnp.float32)
|
@property
|
||||||
p = jnp.abs(c) ** 2
|
def label(self) -> str:
|
||||||
rho11 = jnp.sum(p * k, axis=1) / self.N
|
return f"Sym^{self.N}(C^2) ≅ CP^{self.N}"
|
||||||
kk = jnp.arange(self.N, dtype=jnp.float32)
|
|
||||||
coef = jnp.sqrt((kk + 1.0) * (self.N - kk)) / self.N
|
@property
|
||||||
off = jnp.sum(jnp.conj(c[:, :-1]) * c[:, 1:] * coef, axis=1)
|
def slug(self) -> str:
|
||||||
rho = jnp.zeros((c.shape[0], 2, 2), dtype=jnp.complex64)
|
return f"majorana_{self.N}"
|
||||||
rho = rho.at[:, 0, 0].set(1.0 - rho11)
|
|
||||||
rho = rho.at[:, 1, 1].set(rho11)
|
@property
|
||||||
rho = rho.at[:, 0, 1].set(off)
|
def intrinsic_dim(self) -> int:
|
||||||
rho = rho.at[:, 1, 0].set(jnp.conj(off))
|
return self.N
|
||||||
return rho
|
|
||||||
|
@property
|
||||||
def sample_np(self, rng: np.random.Generator, batch: int) -> tuple[np.ndarray, np.ndarray]:
|
def state_dim(self) -> int:
|
||||||
c = (rng.normal(size=(batch, self.N + 1)) + 1j * rng.normal(size=(batch, self.N + 1)))
|
return self.N + 1
|
||||||
c = (c / math.sqrt(2.0)).astype(np.complex64)
|
|
||||||
c /= np.linalg.norm(c, axis=1, keepdims=True)
|
@property
|
||||||
lam = np.clip(np.linalg.eigvalsh(self._rho1_np(c)).real, 1e-30, 1.0)
|
def observable_max(self) -> float:
|
||||||
return c, entropy_bits_from_probs(lam, np).astype(np.float32)
|
return 1.0 # one-qubit entropy upper bound
|
||||||
|
|
||||||
def sample_jax(self, key: Any, batch: int) -> tuple[Any, Any]:
|
def _rho1_np(self, c: np.ndarray) -> np.ndarray:
|
||||||
k1, k2 = random.split(key)
|
k = np.arange(self.N + 1, dtype=np.float32)
|
||||||
c = (random.normal(k1, (batch, self.N + 1), dtype=jnp.float32)
|
p = np.abs(c) ** 2
|
||||||
+ 1j * random.normal(k2, (batch, self.N + 1), dtype=jnp.float32)) / math.sqrt(2.0)
|
rho11 = (p * k).sum(axis=1) / self.N
|
||||||
c = c / jnp.linalg.norm(c, axis=1, keepdims=True)
|
coef = (
|
||||||
lam = jnp.clip(jnp.linalg.eigvalsh(self._rho1_jax(c)).real, 1e-30, 1.0)
|
np.sqrt(
|
||||||
return c, entropy_bits_from_probs(lam, jnp)
|
(np.arange(self.N, dtype=np.float32) + 1.0)
|
||||||
|
* (self.N - np.arange(self.N, dtype=np.float32))
|
||||||
def metric_pairs(self, x: np.ndarray, y: np.ndarray) -> np.ndarray:
|
)
|
||||||
return fs_metric_np(x, y)
|
/ self.N
|
||||||
|
)
|
||||||
def majorana_stars(self, coeffs: np.ndarray) -> np.ndarray:
|
off = (np.conj(c[:, :-1]) * c[:, 1:] * coef).sum(axis=1)
|
||||||
"""Map one symmetric state to its Majorana stars on S^2."""
|
rho = np.zeros((len(c), 2, 2), dtype=np.complex64)
|
||||||
a = np.array([((-1) ** k) * math.sqrt(math.comb(self.N, k)) * coeffs[k] for k in range(self.N + 1)], np.complex128)
|
rho[:, 0, 0] = 1.0 - rho11
|
||||||
poly = np.trim_zeros(a[::-1], trim="f")
|
rho[:, 1, 1] = rho11
|
||||||
roots = np.roots(poly) if len(poly) > 1 else np.empty(0, dtype=np.complex128)
|
rho[:, 0, 1] = off
|
||||||
r2 = np.abs(roots) ** 2
|
rho[:, 1, 0] = np.conj(off)
|
||||||
pts = np.c_[2 * roots.real / (1 + r2), 2 * roots.imag / (1 + r2), (r2 - 1) / (1 + r2)]
|
return rho
|
||||||
missing = self.N - len(pts)
|
|
||||||
if missing > 0:
|
def _rho1_jax(self, c: Any) -> Any:
|
||||||
pts = np.vstack([pts, np.tile(np.array([[0.0, 0.0, 1.0]]), (missing, 1))])
|
k = jnp.arange(self.N + 1, dtype=jnp.float32)
|
||||||
return pts.astype(np.float32)
|
p = jnp.abs(c) ** 2
|
||||||
|
rho11 = jnp.sum(p * k, axis=1) / self.N
|
||||||
|
kk = jnp.arange(self.N, dtype=jnp.float32)
|
||||||
|
coef = jnp.sqrt((kk + 1.0) * (self.N - kk)) / self.N
|
||||||
|
off = jnp.sum(jnp.conj(c[:, :-1]) * c[:, 1:] * coef, axis=1)
|
||||||
|
rho = jnp.zeros((c.shape[0], 2, 2), dtype=jnp.complex64)
|
||||||
|
rho = rho.at[:, 0, 0].set(1.0 - rho11)
|
||||||
|
rho = rho.at[:, 1, 1].set(rho11)
|
||||||
|
rho = rho.at[:, 0, 1].set(off)
|
||||||
|
rho = rho.at[:, 1, 0].set(jnp.conj(off))
|
||||||
|
return rho
|
||||||
|
|
||||||
|
def sample_np(
|
||||||
|
self, rng: np.random.Generator, batch: int
|
||||||
|
) -> tuple[np.ndarray, np.ndarray]:
|
||||||
|
c = rng.normal(size=(batch, self.N + 1)) + 1j * rng.normal(
|
||||||
|
size=(batch, self.N + 1)
|
||||||
|
)
|
||||||
|
c = (c / math.sqrt(2.0)).astype(np.complex64)
|
||||||
|
c /= np.linalg.norm(c, axis=1, keepdims=True)
|
||||||
|
lam = np.clip(np.linalg.eigvalsh(self._rho1_np(c)).real, 1e-30, 1.0)
|
||||||
|
return c, entropy_bits_from_probs(lam, np).astype(np.float32)
|
||||||
|
|
||||||
|
def sample_jax(self, key: Any, batch: int) -> tuple[Any, Any]:
|
||||||
|
k1, k2 = random.split(key)
|
||||||
|
c = (
|
||||||
|
random.normal(k1, (batch, self.N + 1), dtype=jnp.float32)
|
||||||
|
+ 1j * random.normal(k2, (batch, self.N + 1), dtype=jnp.float32)
|
||||||
|
) / math.sqrt(2.0)
|
||||||
|
c = c / jnp.linalg.norm(c, axis=1, keepdims=True)
|
||||||
|
lam = jnp.clip(jnp.linalg.eigvalsh(self._rho1_jax(c)).real, 1e-30, 1.0)
|
||||||
|
return c, entropy_bits_from_probs(lam, jnp)
|
||||||
|
|
||||||
|
def metric_pairs(self, x: np.ndarray, y: np.ndarray) -> np.ndarray:
|
||||||
|
return fs_metric_np(x, y)
|
||||||
|
|
||||||
|
def majorana_stars(self, coeffs: np.ndarray) -> np.ndarray:
|
||||||
|
"""Map one symmetric state to its Majorana stars on S^2."""
|
||||||
|
a = np.array(
|
||||||
|
[
|
||||||
|
((-1) ** k) * math.sqrt(math.comb(self.N, k)) * coeffs[k]
|
||||||
|
for k in range(self.N + 1)
|
||||||
|
],
|
||||||
|
np.complex128,
|
||||||
|
)
|
||||||
|
poly = np.trim_zeros(a[::-1], trim="f")
|
||||||
|
roots = np.roots(poly) if len(poly) > 1 else np.empty(0, dtype=np.complex128)
|
||||||
|
r2 = np.abs(roots) ** 2
|
||||||
|
pts = np.c_[
|
||||||
|
2 * roots.real / (1 + r2), 2 * roots.imag / (1 + r2), (r2 - 1) / (1 + r2)
|
||||||
|
]
|
||||||
|
missing = self.N - len(pts)
|
||||||
|
if missing > 0:
|
||||||
|
pts = np.vstack([pts, np.tile(np.array([[0.0, 0.0, 1.0]]), (missing, 1))])
|
||||||
|
return pts.astype(np.float32)
|
||||||
|
|||||||
@@ -1,48 +1,48 @@
|
|||||||
"""
|
"""
|
||||||
plot the probability of the entropy of the reduced density matrix of the pure state being greater than log2(d_A) - alpha - beta
|
plot the probability of the entropy of the reduced density matrix of the pure state being greater than log2(d_A) - alpha - beta
|
||||||
for different alpha values
|
for different alpha values
|
||||||
|
|
||||||
IGNORE THE CONSTANT C
|
IGNORE THE CONSTANT C
|
||||||
|
|
||||||
NOTE there is bug in the program, You should fix it if you want to use the visualization, it relates to the alpha range and you should not plot the prob of 0
|
NOTE there is bug in the program, You should fix it if you want to use the visualization, it relates to the alpha range and you should not plot the prob of 0
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
import matplotlib.pyplot as plt
|
import matplotlib.pyplot as plt
|
||||||
from quantum_states import sample_and_calculate
|
from quantum_states import sample_and_calculate
|
||||||
from tqdm import tqdm
|
from tqdm import tqdm
|
||||||
|
|
||||||
# Set dimensions
|
# Set dimensions
|
||||||
db = 16
|
db = 16
|
||||||
da_values = [8, 16, 32]
|
da_values = [8, 16, 32]
|
||||||
alpha_range = np.linspace(0, 2, 100) # Range of alpha values to plot
|
alpha_range = np.linspace(0, 2, 100) # Range of alpha values to plot
|
||||||
n_samples = 100000
|
n_samples = 100000
|
||||||
|
|
||||||
plt.figure(figsize=(10, 6))
|
plt.figure(figsize=(10, 6))
|
||||||
|
|
||||||
for da in tqdm(da_values, desc="Processing d_A values"):
|
for da in tqdm(da_values, desc="Processing d_A values"):
|
||||||
# Calculate beta according to the formula
|
# Calculate beta according to the formula
|
||||||
beta = da / (np.log(2) * db)
|
beta = da / (np.log(2) * db)
|
||||||
|
|
||||||
# Calculate probability for each alpha
|
# Calculate probability for each alpha
|
||||||
predicted_probabilities = []
|
predicted_probabilities = []
|
||||||
actual_probabilities = []
|
actual_probabilities = []
|
||||||
for alpha in tqdm(alpha_range, desc=f"Calculating probabilities for d_A={da}", leave=False):
|
for alpha in tqdm(alpha_range, desc=f"Calculating probabilities for d_A={da}", leave=False):
|
||||||
# Calculate probability according to the formula
|
# Calculate probability according to the formula
|
||||||
# Ignoring constant C as requested
|
# Ignoring constant C as requested
|
||||||
prob = np.exp(-(da * db - 1) * alpha**2 / (np.log2(da))**2)
|
prob = np.exp(-(da * db - 1) * alpha**2 / (np.log2(da))**2)
|
||||||
predicted_probabilities.append(prob)
|
predicted_probabilities.append(prob)
|
||||||
# Calculate actual probability
|
# Calculate actual probability
|
||||||
entropies = sample_and_calculate(da, db, n_samples=n_samples)
|
entropies = sample_and_calculate(da, db, n_samples=n_samples)
|
||||||
actual_probabilities.append(np.sum(entropies > np.log2(da) - alpha - beta) / n_samples)
|
actual_probabilities.append(np.sum(entropies > np.log2(da) - alpha - beta) / n_samples)
|
||||||
|
|
||||||
# plt.plot(alpha_range, predicted_probabilities, label=f'$d_A={da}$', linestyle='--')
|
# plt.plot(alpha_range, predicted_probabilities, label=f'$d_A={da}$', linestyle='--')
|
||||||
plt.plot(alpha_range, actual_probabilities, label=f'$d_A={da}$', linestyle='-')
|
plt.plot(alpha_range, actual_probabilities, label=f'$d_A={da}$', linestyle='-')
|
||||||
|
|
||||||
plt.xlabel(r'$\alpha$')
|
plt.xlabel(r'$\alpha$')
|
||||||
plt.ylabel('Probability')
|
plt.ylabel('Probability')
|
||||||
plt.title(r'$\operatorname{Pr}[H(\psi_A) <\log_2(d_A)-\alpha-\beta]$ vs $\alpha$ for different $d_A$')
|
plt.title(r'$\operatorname{Pr}[H(\psi_A) <\log_2(d_A)-\alpha-\beta]$ vs $\alpha$ for different $d_A$')
|
||||||
plt.legend()
|
plt.legend()
|
||||||
plt.grid(True)
|
plt.grid(True)
|
||||||
plt.yscale('log') # Use log scale for better visualization
|
plt.yscale('log') # Use log scale for better visualization
|
||||||
plt.show()
|
plt.show()
|
||||||
|
|||||||
@@ -1,52 +1,52 @@
|
|||||||
"""
|
"""
|
||||||
plot the probability of the entropy of the reduced density matrix of the pure state being greater than log2(d_A) - alpha - beta
|
plot the probability of the entropy of the reduced density matrix of the pure state being greater than log2(d_A) - alpha - beta
|
||||||
|
|
||||||
for different d_A values, with fixed alpha and d_B Note, d_B>d_A
|
for different d_A values, with fixed alpha and d_B Note, d_B>d_A
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
import matplotlib.pyplot as plt
|
import matplotlib.pyplot as plt
|
||||||
from quantum_states import sample_and_calculate
|
from quantum_states import sample_and_calculate
|
||||||
from tqdm import tqdm
|
from tqdm import tqdm
|
||||||
|
|
||||||
# Set dimensions
|
# Set dimensions
|
||||||
db = 32
|
db = 32
|
||||||
alpha = 0
|
alpha = 0
|
||||||
da_range = np.arange(2, 10, 1) # Range of d_A values to plot
|
da_range = np.arange(2, 10, 1) # Range of d_A values to plot
|
||||||
n_samples = 1000000
|
n_samples = 1000000
|
||||||
|
|
||||||
plt.figure(figsize=(10, 6))
|
plt.figure(figsize=(10, 6))
|
||||||
|
|
||||||
predicted_probabilities = []
|
predicted_probabilities = []
|
||||||
actual_probabilities = []
|
actual_probabilities = []
|
||||||
|
|
||||||
for da in tqdm(da_range, desc="Processing d_A values"):
|
for da in tqdm(da_range, desc="Processing d_A values"):
|
||||||
# Calculate beta according to the formula
|
# Calculate beta according to the formula
|
||||||
beta = da / (np.log(2) * db)
|
beta = da / (np.log(2) * db)
|
||||||
|
|
||||||
# Calculate probability according to the formula
|
# Calculate probability according to the formula
|
||||||
# Ignoring constant C as requested
|
# Ignoring constant C as requested
|
||||||
prob = np.exp(-((da * db - 1) * alpha**2 / (np.log2(da)**2)))
|
prob = np.exp(-((da * db - 1) * alpha**2 / (np.log2(da)**2)))
|
||||||
predicted_probabilities.append(prob)
|
predicted_probabilities.append(prob)
|
||||||
# Calculate actual probability
|
# Calculate actual probability
|
||||||
entropies = sample_and_calculate(da, db, n_samples=n_samples)
|
entropies = sample_and_calculate(da, db, n_samples=n_samples)
|
||||||
count = np.sum(entropies < np.log2(da) - alpha - beta)
|
count = np.sum(entropies < np.log2(da) - alpha - beta)
|
||||||
# early stop if count is 0
|
# early stop if count is 0
|
||||||
if count != 0:
|
if count != 0:
|
||||||
actual_probabilities.append(count / n_samples)
|
actual_probabilities.append(count / n_samples)
|
||||||
else:
|
else:
|
||||||
actual_probabilities.extend([np.nan] * (len(da_range) - len(actual_probabilities)))
|
actual_probabilities.extend([np.nan] * (len(da_range) - len(actual_probabilities)))
|
||||||
break
|
break
|
||||||
# debug
|
# debug
|
||||||
print(f'da={da}, theoretical_prob={prob}, threshold={np.log2(da) - alpha - beta}, actual_prob={actual_probabilities[-1]}, entropy_heads={entropies[:10]}')
|
print(f'da={da}, theoretical_prob={prob}, threshold={np.log2(da) - alpha - beta}, actual_prob={actual_probabilities[-1]}, entropy_heads={entropies[:10]}')
|
||||||
|
|
||||||
# plt.plot(da_range, predicted_probabilities, label=f'$d_A={da}$', linestyle='--')
|
# plt.plot(da_range, predicted_probabilities, label=f'$d_A={da}$', linestyle='--')
|
||||||
plt.plot(da_range, actual_probabilities, label=f'$d_A={da}$', linestyle='-')
|
plt.plot(da_range, actual_probabilities, label=f'$d_A={da}$', linestyle='-')
|
||||||
|
|
||||||
plt.xlabel(r'$d_A$')
|
plt.xlabel(r'$d_A$')
|
||||||
plt.ylabel('Probability')
|
plt.ylabel('Probability')
|
||||||
plt.title(r'$\operatorname{Pr}[H(\psi_A) < \log_2(d_A)-\alpha-\beta]$ vs $d_A$ for fixed $\alpha=$'+str(alpha)+r' and $d_B=$' +str(db)+ r' with $n=$' +str(n_samples))
|
plt.title(r'$\operatorname{Pr}[H(\psi_A) < \log_2(d_A)-\alpha-\beta]$ vs $d_A$ for fixed $\alpha=$'+str(alpha)+r' and $d_B=$' +str(db)+ r' with $n=$' +str(n_samples))
|
||||||
# plt.legend()
|
# plt.legend()
|
||||||
plt.grid(True)
|
plt.grid(True)
|
||||||
plt.yscale('log') # Use log scale for better visualization
|
plt.yscale('log') # Use log scale for better visualization
|
||||||
plt.show()
|
plt.show()
|
||||||
|
|||||||
@@ -1,55 +1,55 @@
|
|||||||
import numpy as np
|
import numpy as np
|
||||||
import matplotlib.pyplot as plt
|
import matplotlib.pyplot as plt
|
||||||
from quantum_states import sample_and_calculate
|
from quantum_states import sample_and_calculate
|
||||||
from tqdm import tqdm
|
from tqdm import tqdm
|
||||||
|
|
||||||
# Set dimensions, keep db\geq da\geq 3
|
# Set dimensions, keep db\geq da\geq 3
|
||||||
db = 64
|
db = 64
|
||||||
da_values = [4, 8, 16, 32]
|
da_values = [4, 8, 16, 32]
|
||||||
da_colors = ['b', 'g', 'r', 'c']
|
da_colors = ['b', 'g', 'r', 'c']
|
||||||
n_samples = 100000
|
n_samples = 100000
|
||||||
|
|
||||||
plt.figure(figsize=(10, 6))
|
plt.figure(figsize=(10, 6))
|
||||||
|
|
||||||
# Define range of deviations to test (in bits)
|
# Define range of deviations to test (in bits)
|
||||||
deviations = np.linspace(0, 1, 50) # Test deviations from 0 to 1 bits
|
deviations = np.linspace(0, 1, 50) # Test deviations from 0 to 1 bits
|
||||||
|
|
||||||
for i, da in enumerate(tqdm(da_values, desc="Processing d_A values")):
|
for i, da in enumerate(tqdm(da_values, desc="Processing d_A values")):
|
||||||
# Calculate maximal entropy
|
# Calculate maximal entropy
|
||||||
max_entropy = np.log2(min(da, db))
|
max_entropy = np.log2(min(da, db))
|
||||||
|
|
||||||
# Sample random states and calculate their entropies
|
# Sample random states and calculate their entropies
|
||||||
entropies = sample_and_calculate(da, db, n_samples=n_samples)
|
entropies = sample_and_calculate(da, db, n_samples=n_samples)
|
||||||
|
|
||||||
# Calculate probabilities for each deviation
|
# Calculate probabilities for each deviation
|
||||||
probabilities = []
|
probabilities = []
|
||||||
theoretical_probs = []
|
theoretical_probs = []
|
||||||
for dev in deviations:
|
for dev in deviations:
|
||||||
# Count states that deviate by more than dev bits from max entropy
|
# Count states that deviate by more than dev bits from max entropy
|
||||||
count = np.sum(max_entropy - entropies > dev)
|
count = np.sum(max_entropy - entropies > dev)
|
||||||
# Omit the case where count is 0
|
# Omit the case where count is 0
|
||||||
if count != 0:
|
if count != 0:
|
||||||
prob = count / len(entropies)
|
prob = count / len(entropies)
|
||||||
probabilities.append(prob)
|
probabilities.append(prob)
|
||||||
else:
|
else:
|
||||||
probabilities.append(np.nan)
|
probabilities.append(np.nan)
|
||||||
|
|
||||||
# Calculate theoretical probability using concentration inequality
|
# Calculate theoretical probability using concentration inequality
|
||||||
# note max_entropy - dev = max_entropy - beta - alpha, so alpha = dev - beta
|
# note max_entropy - dev = max_entropy - beta - alpha, so alpha = dev - beta
|
||||||
beta = da / (np.log(2)*db)
|
beta = da / (np.log(2)*db)
|
||||||
alpha = dev - beta
|
alpha = dev - beta
|
||||||
theoretical_prob = np.exp(-(da * db - 1) * alpha**2 / (np.log2(da))**2)
|
theoretical_prob = np.exp(-(da * db - 1) * alpha**2 / (np.log2(da))**2)
|
||||||
# # debug
|
# # debug
|
||||||
# print(f"dev: {dev}, beta: {beta}, alpha: {alpha}, theoretical_prob: {theoretical_prob}")
|
# print(f"dev: {dev}, beta: {beta}, alpha: {alpha}, theoretical_prob: {theoretical_prob}")
|
||||||
theoretical_probs.append(theoretical_prob)
|
theoretical_probs.append(theoretical_prob)
|
||||||
|
|
||||||
plt.plot(deviations, probabilities, '-', label=f'$d_A={da}$ (simulated)', color=da_colors[i])
|
plt.plot(deviations, probabilities, '-', label=f'$d_A={da}$ (simulated)', color=da_colors[i])
|
||||||
plt.plot(deviations, theoretical_probs, '--', label=f'$d_A={da}$ (theoretical)', color=da_colors[i])
|
plt.plot(deviations, theoretical_probs, '--', label=f'$d_A={da}$ (theoretical)', color=da_colors[i])
|
||||||
|
|
||||||
plt.xlabel('Deviation from maximal entropy (bits)')
|
plt.xlabel('Deviation from maximal entropy (bits)')
|
||||||
plt.ylabel('Probability')
|
plt.ylabel('Probability')
|
||||||
plt.title(f'Probability of deviation from maximal entropy simulation with sample size {n_samples} for $d_B={db}$ ignoring the constant $C$')
|
plt.title(f'Probability of deviation from maximal entropy simulation with sample size {n_samples} for $d_B={db}$ ignoring the constant $C$')
|
||||||
plt.legend()
|
plt.legend()
|
||||||
plt.grid(True)
|
plt.grid(True)
|
||||||
plt.yscale('log') # Use log scale for better visualization
|
plt.yscale('log') # Use log scale for better visualization
|
||||||
plt.show()
|
plt.show()
|
||||||
|
|||||||
@@ -1,33 +1,33 @@
|
|||||||
import numpy as np
|
import numpy as np
|
||||||
import matplotlib.pyplot as plt
|
import matplotlib.pyplot as plt
|
||||||
from quantum_states import sample_and_calculate
|
from quantum_states import sample_and_calculate
|
||||||
from tqdm import tqdm
|
from tqdm import tqdm
|
||||||
|
|
||||||
# Define range of dimensions to test
|
# Define range of dimensions to test
|
||||||
fixed_dim = 64
|
fixed_dim = 64
|
||||||
dimensions = np.arange(2, 64, 2) # Test dimensions from 2 to 50 in steps of 2
|
dimensions = np.arange(2, 64, 2) # Test dimensions from 2 to 50 in steps of 2
|
||||||
expected_entropies = []
|
expected_entropies = []
|
||||||
theoretical_entropies = []
|
theoretical_entropies = []
|
||||||
predicted_entropies = []
|
predicted_entropies = []
|
||||||
|
|
||||||
# Calculate entropies for each dimension
|
# Calculate entropies for each dimension
|
||||||
for dim in tqdm(dimensions, desc="Calculating entropies"):
|
for dim in tqdm(dimensions, desc="Calculating entropies"):
|
||||||
# For each dimension, we'll keep one subsystem fixed at dim=2
|
# For each dimension, we'll keep one subsystem fixed at dim=2
|
||||||
# and vary the other dimension
|
# and vary the other dimension
|
||||||
entropies = sample_and_calculate(dim, fixed_dim, n_samples=1000)
|
entropies = sample_and_calculate(dim, fixed_dim, n_samples=1000)
|
||||||
expected_entropies.append(np.mean(entropies))
|
expected_entropies.append(np.mean(entropies))
|
||||||
theoretical_entropies.append(np.log2(min(dim, fixed_dim)))
|
theoretical_entropies.append(np.log2(min(dim, fixed_dim)))
|
||||||
beta = min(dim, fixed_dim)/(2*np.log(2)*max(dim, fixed_dim))
|
beta = min(dim, fixed_dim)/(2*np.log(2)*max(dim, fixed_dim))
|
||||||
predicted_entropies.append(np.log2(min(dim, fixed_dim)) - beta)
|
predicted_entropies.append(np.log2(min(dim, fixed_dim)) - beta)
|
||||||
|
|
||||||
# Create the plot
|
# Create the plot
|
||||||
plt.figure(figsize=(10, 6))
|
plt.figure(figsize=(10, 6))
|
||||||
plt.plot(dimensions, expected_entropies, 'b-', label='Expected Entropy')
|
plt.plot(dimensions, expected_entropies, 'b-', label='Expected Entropy')
|
||||||
plt.plot(dimensions, theoretical_entropies, 'r--', label='Theoretical Entropy')
|
plt.plot(dimensions, theoretical_entropies, 'r--', label='Theoretical Entropy')
|
||||||
plt.plot(dimensions, predicted_entropies, 'g--', label='Predicted Entropy')
|
plt.plot(dimensions, predicted_entropies, 'g--', label='Predicted Entropy')
|
||||||
plt.xlabel('Dimension of Subsystem B')
|
plt.xlabel('Dimension of Subsystem B')
|
||||||
plt.ylabel('von Neumann Entropy (bits)')
|
plt.ylabel('von Neumann Entropy (bits)')
|
||||||
plt.title(f'von Neumann Entropy vs. System Dimension, with Dimension of Subsystem A = {fixed_dim}')
|
plt.title(f'von Neumann Entropy vs. System Dimension, with Dimension of Subsystem A = {fixed_dim}')
|
||||||
plt.legend()
|
plt.legend()
|
||||||
plt.grid(True)
|
plt.grid(True)
|
||||||
plt.show()
|
plt.show()
|
||||||
|
|||||||
@@ -1,51 +1,51 @@
|
|||||||
import numpy as np
|
import numpy as np
|
||||||
import matplotlib.pyplot as plt
|
import matplotlib.pyplot as plt
|
||||||
from quantum_states import sample_and_calculate
|
from quantum_states import sample_and_calculate
|
||||||
from tqdm import tqdm
|
from tqdm import tqdm
|
||||||
from mpl_toolkits.mplot3d import Axes3D
|
from mpl_toolkits.mplot3d import Axes3D
|
||||||
|
|
||||||
# Define range of dimensions to test
|
# Define range of dimensions to test
|
||||||
dimensionsA = np.arange(2, 64, 2) # Test dimensions from 2 to 50 in steps of 2
|
dimensionsA = np.arange(2, 64, 2) # Test dimensions from 2 to 50 in steps of 2
|
||||||
dimensionsB = np.arange(2, 64, 2) # Test dimensions from 2 to 50 in steps of 2
|
dimensionsB = np.arange(2, 64, 2) # Test dimensions from 2 to 50 in steps of 2
|
||||||
|
|
||||||
# Create meshgrid for 3D plot
|
# Create meshgrid for 3D plot
|
||||||
X, Y = np.meshgrid(dimensionsA, dimensionsB)
|
X, Y = np.meshgrid(dimensionsA, dimensionsB)
|
||||||
Z = np.zeros_like(X, dtype=float)
|
Z = np.zeros_like(X, dtype=float)
|
||||||
|
|
||||||
# Calculate entropies for each dimension combination
|
# Calculate entropies for each dimension combination
|
||||||
total_iterations = len(dimensionsA) * len(dimensionsB)
|
total_iterations = len(dimensionsA) * len(dimensionsB)
|
||||||
pbar = tqdm(total=total_iterations, desc="Calculating entropies")
|
pbar = tqdm(total=total_iterations, desc="Calculating entropies")
|
||||||
|
|
||||||
for i, dim_a in enumerate(dimensionsA):
|
for i, dim_a in enumerate(dimensionsA):
|
||||||
for j, dim_b in enumerate(dimensionsB):
|
for j, dim_b in enumerate(dimensionsB):
|
||||||
entropies = sample_and_calculate(dim_a, dim_b, n_samples=100)
|
entropies = sample_and_calculate(dim_a, dim_b, n_samples=100)
|
||||||
Z[j,i] = np.mean(entropies)
|
Z[j,i] = np.mean(entropies)
|
||||||
pbar.update(1)
|
pbar.update(1)
|
||||||
pbar.close()
|
pbar.close()
|
||||||
|
|
||||||
# Create the 3D plot
|
# Create the 3D plot
|
||||||
fig = plt.figure(figsize=(12, 8))
|
fig = plt.figure(figsize=(12, 8))
|
||||||
ax = fig.add_subplot(111, projection='3d')
|
ax = fig.add_subplot(111, projection='3d')
|
||||||
|
|
||||||
# Plot the surface
|
# Plot the surface
|
||||||
surf = ax.plot_surface(X, Y, Z, cmap='viridis')
|
surf = ax.plot_surface(X, Y, Z, cmap='viridis')
|
||||||
|
|
||||||
# Add labels and title with larger font sizes
|
# Add labels and title with larger font sizes
|
||||||
ax.set_xlabel('Dimension of Subsystem A', fontsize=12, labelpad=10)
|
ax.set_xlabel('Dimension of Subsystem A', fontsize=12, labelpad=10)
|
||||||
ax.set_ylabel('Dimension of Subsystem B', fontsize=12, labelpad=10)
|
ax.set_ylabel('Dimension of Subsystem B', fontsize=12, labelpad=10)
|
||||||
ax.set_zlabel('von Neumann Entropy (bits)', fontsize=12, labelpad=10)
|
ax.set_zlabel('von Neumann Entropy (bits)', fontsize=12, labelpad=10)
|
||||||
ax.set_title('von Neumann Entropy vs. System Dimensions', fontsize=14, pad=20)
|
ax.set_title('von Neumann Entropy vs. System Dimensions', fontsize=14, pad=20)
|
||||||
|
|
||||||
# Add colorbar
|
# Add colorbar
|
||||||
cbar = fig.colorbar(surf, ax=ax, label='Entropy')
|
cbar = fig.colorbar(surf, ax=ax, label='Entropy')
|
||||||
cbar.ax.set_ylabel('Entropy', fontsize=12)
|
cbar.ax.set_ylabel('Entropy', fontsize=12)
|
||||||
|
|
||||||
# Add tick labels with larger font size
|
# Add tick labels with larger font size
|
||||||
ax.tick_params(axis='x', labelsize=10)
|
ax.tick_params(axis='x', labelsize=10)
|
||||||
ax.tick_params(axis='y', labelsize=10)
|
ax.tick_params(axis='y', labelsize=10)
|
||||||
ax.tick_params(axis='z', labelsize=10)
|
ax.tick_params(axis='z', labelsize=10)
|
||||||
|
|
||||||
# Rotate the plot for better visibility
|
# Rotate the plot for better visibility
|
||||||
ax.view_init(elev=30, azim=45)
|
ax.view_init(elev=30, azim=45)
|
||||||
|
|
||||||
plt.show()
|
plt.show()
|
||||||
@@ -1,96 +1,96 @@
|
|||||||
import numpy as np
|
import numpy as np
|
||||||
from scipy.linalg import sqrtm
|
from scipy.linalg import sqrtm
|
||||||
from scipy.stats import unitary_group
|
from scipy.stats import unitary_group
|
||||||
from tqdm import tqdm
|
from tqdm import tqdm
|
||||||
|
|
||||||
def random_pure_state(dim_a, dim_b):
|
def random_pure_state(dim_a, dim_b):
|
||||||
"""
|
"""
|
||||||
Generate a random pure state for a bipartite system.
|
Generate a random pure state for a bipartite system.
|
||||||
|
|
||||||
The random pure state is uniformly distributed by the Haar (Fubini-Study) measure on the unit sphere $S^{dim_a * dim_b - 1}$. (Invariant under the unitary group $U(dim_a) \times U(dim_b)$)
|
The random pure state is uniformly distributed by the Haar (Fubini-Study) measure on the unit sphere $S^{dim_a * dim_b - 1}$. (Invariant under the unitary group $U(dim_a) \times U(dim_b)$)
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
dim_a (int): Dimension of subsystem A
|
dim_a (int): Dimension of subsystem A
|
||||||
dim_b (int): Dimension of subsystem B
|
dim_b (int): Dimension of subsystem B
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
numpy.ndarray: Random pure state vector of shape (dim_a * dim_b,)
|
numpy.ndarray: Random pure state vector of shape (dim_a * dim_b,)
|
||||||
"""
|
"""
|
||||||
# Total dimension of the composite system
|
# Total dimension of the composite system
|
||||||
dim_total = dim_a * dim_b
|
dim_total = dim_a * dim_b
|
||||||
|
|
||||||
# Generate non-zero random complex vector
|
# Generate non-zero random complex vector
|
||||||
while True:
|
while True:
|
||||||
state = np.random.normal(size=(dim_total,)) + 1j * np.random.normal(size=(dim_total,))
|
state = np.random.normal(size=(dim_total,)) + 1j * np.random.normal(size=(dim_total,))
|
||||||
if np.linalg.norm(state) > 0:
|
if np.linalg.norm(state) > 0:
|
||||||
break
|
break
|
||||||
|
|
||||||
# Normalize the state
|
# Normalize the state
|
||||||
state = state / np.linalg.norm(state)
|
state = state / np.linalg.norm(state)
|
||||||
|
|
||||||
return state
|
return state
|
||||||
|
|
||||||
def von_neumann_entropy_bipartite_pure_state(state, dim_a, dim_b):
|
def von_neumann_entropy_bipartite_pure_state(state, dim_a, dim_b):
|
||||||
"""
|
"""
|
||||||
Calculate the von Neumann entropy of the reduced density matrix.
|
Calculate the von Neumann entropy of the reduced density matrix.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
state (numpy.ndarray): Pure state vector
|
state (numpy.ndarray): Pure state vector
|
||||||
dim_a (int): Dimension of subsystem A
|
dim_a (int): Dimension of subsystem A
|
||||||
dim_b (int): Dimension of subsystem B
|
dim_b (int): Dimension of subsystem B
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
float: Von Neumann entropy
|
float: Von Neumann entropy
|
||||||
"""
|
"""
|
||||||
# Reshape state vector to matrix form
|
# Reshape state vector to matrix form
|
||||||
state_matrix = state.reshape(dim_a, dim_b)
|
state_matrix = state.reshape(dim_a, dim_b)
|
||||||
|
|
||||||
# Calculate reduced density matrix of subsystem A
|
# Calculate reduced density matrix of subsystem A
|
||||||
rho_a = np.dot(state_matrix, state_matrix.conj().T)
|
rho_a = np.dot(state_matrix, state_matrix.conj().T)
|
||||||
|
|
||||||
# Calculate eigenvalues
|
# Calculate eigenvalues
|
||||||
eigenvals = np.linalg.eigvalsh(rho_a)
|
eigenvals = np.linalg.eigvalsh(rho_a)
|
||||||
|
|
||||||
# Remove very small eigenvalues (numerical errors)
|
# Remove very small eigenvalues (numerical errors)
|
||||||
eigenvals = eigenvals[eigenvals > 1e-15]
|
eigenvals = eigenvals[eigenvals > 1e-15]
|
||||||
|
|
||||||
# Calculate von Neumann entropy
|
# Calculate von Neumann entropy
|
||||||
entropy = -np.sum(eigenvals * np.log2(eigenvals))
|
entropy = -np.sum(eigenvals * np.log2(eigenvals))
|
||||||
|
|
||||||
return np.real(entropy)
|
return np.real(entropy)
|
||||||
|
|
||||||
def sample_and_calculate(dim_a, dim_b, n_samples=1000):
|
def sample_and_calculate(dim_a, dim_b, n_samples=1000):
|
||||||
"""
|
"""
|
||||||
Sample random pure states (generate random co) and calculate their von Neumann entropy.
|
Sample random pure states (generate random co) and calculate their von Neumann entropy.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
dim_a (int): Dimension of subsystem A
|
dim_a (int): Dimension of subsystem A
|
||||||
dim_b (int): Dimension of subsystem B
|
dim_b (int): Dimension of subsystem B
|
||||||
n_samples (int): Number of samples to generate
|
n_samples (int): Number of samples to generate
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
numpy.ndarray: Array of entropy values
|
numpy.ndarray: Array of entropy values
|
||||||
"""
|
"""
|
||||||
entropies = np.zeros(n_samples)
|
entropies = np.zeros(n_samples)
|
||||||
|
|
||||||
for i in tqdm(range(n_samples), desc=f"Sampling states (d_A={dim_a}, d_B={dim_b})", leave=False):
|
for i in tqdm(range(n_samples), desc=f"Sampling states (d_A={dim_a}, d_B={dim_b})", leave=False):
|
||||||
state = random_pure_state(dim_a, dim_b)
|
state = random_pure_state(dim_a, dim_b)
|
||||||
entropies[i] = von_neumann_entropy_bipartite_pure_state(state, dim_a, dim_b)
|
entropies[i] = von_neumann_entropy_bipartite_pure_state(state, dim_a, dim_b)
|
||||||
|
|
||||||
return entropies
|
return entropies
|
||||||
|
|
||||||
# Example usage:
|
# Example usage:
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
# Example: 2-qubit system
|
# Example: 2-qubit system
|
||||||
dim_a, dim_b = 50,100
|
dim_a, dim_b = 50,100
|
||||||
|
|
||||||
# Generate single random state and calculate entropy
|
# Generate single random state and calculate entropy
|
||||||
state = random_pure_state(dim_a, dim_b)
|
state = random_pure_state(dim_a, dim_b)
|
||||||
entropy = von_neumann_entropy_bipartite_pure_state(state, dim_a, dim_b)
|
entropy = von_neumann_entropy_bipartite_pure_state(state, dim_a, dim_b)
|
||||||
print(f"Single state entropy: {entropy}")
|
print(f"Single state entropy: {entropy}")
|
||||||
|
|
||||||
# Sample multiple states
|
# Sample multiple states
|
||||||
entropies = sample_and_calculate(dim_a, dim_b, n_samples=1000)
|
entropies = sample_and_calculate(dim_a, dim_b, n_samples=1000)
|
||||||
print(f"Expected entropy: {np.mean(entropies)}")
|
print(f"Expected entropy: {np.mean(entropies)}")
|
||||||
print(f"Theoretical entropy: {np.log2(max(dim_a, dim_b))}")
|
print(f"Theoretical entropy: {np.log2(max(dim_a, dim_b))}")
|
||||||
print(f"Standard deviation: {np.std(entropies)}")
|
print(f"Standard deviation: {np.std(entropies)}")
|
||||||
|
|||||||
@@ -1,32 +1,32 @@
|
|||||||
# unit test for the functions in quantum_states.py
|
# unit test for the functions in quantum_states.py
|
||||||
|
|
||||||
import unittest
|
import unittest
|
||||||
import numpy as np
|
import numpy as np
|
||||||
from quantum_states import random_pure_state, von_neumann_entropy_bipartite_pure_state
|
from quantum_states import random_pure_state, von_neumann_entropy_bipartite_pure_state
|
||||||
|
|
||||||
class LearningCase(unittest.TestCase):
|
class LearningCase(unittest.TestCase):
|
||||||
def test_random_pure_state_shape_and_norm(self):
|
def test_random_pure_state_shape_and_norm(self):
|
||||||
dim_a = 2
|
dim_a = 2
|
||||||
dim_b = 2
|
dim_b = 2
|
||||||
state = random_pure_state(dim_a, dim_b)
|
state = random_pure_state(dim_a, dim_b)
|
||||||
self.assertEqual(state.shape, (dim_a * dim_b,))
|
self.assertEqual(state.shape, (dim_a * dim_b,))
|
||||||
self.assertAlmostEqual(np.linalg.norm(state), 1)
|
self.assertAlmostEqual(np.linalg.norm(state), 1)
|
||||||
|
|
||||||
def test_partial_trace_entropy(self):
|
def test_partial_trace_entropy(self):
|
||||||
dim_a = 2
|
dim_a = 2
|
||||||
dim_b = 2
|
dim_b = 2
|
||||||
state = random_pure_state(dim_a, dim_b)
|
state = random_pure_state(dim_a, dim_b)
|
||||||
self.assertAlmostEqual(von_neumann_entropy_bipartite_pure_state(state, dim_a, dim_b), von_neumann_entropy_bipartite_pure_state(state, dim_b, dim_a))
|
self.assertAlmostEqual(von_neumann_entropy_bipartite_pure_state(state, dim_a, dim_b), von_neumann_entropy_bipartite_pure_state(state, dim_b, dim_a))
|
||||||
|
|
||||||
def test_sample_uniformly(self):
|
def test_sample_uniformly(self):
|
||||||
# calculate the distribution of the random pure state
|
# calculate the distribution of the random pure state
|
||||||
dim_a = 2
|
dim_a = 2
|
||||||
dim_b = 2
|
dim_b = 2
|
||||||
state = random_pure_state(dim_a, dim_b)
|
state = random_pure_state(dim_a, dim_b)
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
main()
|
main()
|
||||||
@@ -1,244 +1,435 @@
|
|||||||
% chapters/chap2.tex
|
% chapters/chap2.tex
|
||||||
\documentclass[../main.tex]{subfiles}
|
\documentclass[../main.tex]{subfiles}
|
||||||
|
|
||||||
\ifSubfilesClassLoaded{
|
\ifSubfilesClassLoaded{
|
||||||
\addbibresource{../main.bib}
|
\addbibresource{../main.bib}
|
||||||
}
|
}
|
||||||
|
|
||||||
\begin{document}
|
\begin{document}
|
||||||
|
|
||||||
\chapter{Levy's family and observable diameters}
|
\chapter{Levy's family and observable diameters}
|
||||||
|
|
||||||
In this section, we will explore how the results from Hayden's concentration of measure theorem can be understood in terms of observable diameters from Gromov's perspective and what properties it reveals for entropy functions.
|
In this section, we will explore how the results from Hayden's concentration of measure theorem can be understood in terms of observable diameters from Gromov's perspective and what properties it reveals for entropy functions.
|
||||||
|
|
||||||
We will try to use the results from previous sections to estimate the observable diameter for complex projective spaces.
|
We will try to use the results from previous sections to estimate the observable diameter for complex projective spaces.
|
||||||
|
|
||||||
\section{Observable diameters}
|
\section{Observable diameters}
|
||||||
|
|
||||||
Recall from previous sections, an arbitrary 1-Lipschitz function $f:S^n\to \mathbb{R}$ concentrates near a single value $a_0\in \mathbb{R}$ as strongly as the distance function does.
|
Recall from previous sections, an arbitrary 1-Lipschitz function $f:S^n\to \mathbb{R}$ concentrates near a single value $a_0\in \mathbb{R}$ as strongly as the distance function does.
|
||||||
|
|
||||||
\begin{defn}
|
\begin{defn}
|
||||||
\label{defn:mm-space}
|
\label{defn:mm-space}
|
||||||
|
|
||||||
Let $X$ be a topological space with the following:
|
Let $X$ be a topological space with the following:
|
||||||
|
|
||||||
\begin{enumerate}
|
\begin{enumerate}
|
||||||
\item $X$ is a complete (every Cauchy sequence converges)
|
\item $X$ is a complete (every Cauchy sequence converges)
|
||||||
\item $X$ is a metric space with metric $d_X$
|
\item $X$ is a metric space with metric $d_X$
|
||||||
\item $X$ has a Borel probability measure $\mu_X$
|
\item $X$ has a Borel probability measure $\mu_X$
|
||||||
\end{enumerate}
|
\end{enumerate}
|
||||||
|
|
||||||
Then $(X,d_X,\mu_X)$ is a \textbf{metric measure space}.
|
Then $(X,d_X,\mu_X)$ is a \textbf{metric measure space}.
|
||||||
\end{defn}
|
\end{defn}
|
||||||
|
|
||||||
\begin{defn}
|
\begin{defn}
|
||||||
\label{defn:diameter}
|
\label{defn:diameter}
|
||||||
|
|
||||||
Let $(X,d_X)$ be a metric space. The \textbf{diameter} of a set $A\subset X$ is defined as
|
Let $(X,d_X)$ be a metric space. The \textbf{diameter} of a set $A\subset X$ is defined as
|
||||||
$$
|
$$
|
||||||
\diam(A)=\sup_{x,y\in A}d_X(x,y).
|
\diam(A)=\sup_{x,y\in A}d_X(x,y).
|
||||||
$$
|
$$
|
||||||
\end{defn}
|
\end{defn}
|
||||||
|
|
||||||
\begin{defn}
|
\begin{defn}
|
||||||
\label{defn:partial-diameter}
|
\label{defn:partial-diameter}
|
||||||
|
|
||||||
Let $(X,d_X,\mu_X)$ be a metric measure space, For any real number $\alpha\leq 1$, the \textbf{partial diameter} of $X$ is defined as
|
Let $(X,d_X,\mu_X)$ be a metric measure space, For any real number $\alpha\leq 1$, the \textbf{partial diameter} of $X$ is defined as
|
||||||
$$
|
$$
|
||||||
\diam(A;\alpha)=\inf_{A\subseteq X|\mu_X(A)\geq \alpha}\diam(A).
|
\diam(A;\alpha)=\inf_{A\subseteq X|\mu_X(A)\geq \alpha}\diam(A).
|
||||||
$$
|
$$
|
||||||
\end{defn}
|
\end{defn}
|
||||||
|
|
||||||
This definition generalize the relation between the measure and metric in the metric-measure space. Intuitively, the space with smaller partial diameter can take more volume with the same diameter constrains.
|
This definition generalize the relation between the measure and metric in the metric-measure space. Intuitively, the space with smaller partial diameter can take more volume with the same diameter constrains.
|
||||||
|
|
||||||
However, in higher dimensions, the volume may tend to concentrates more around a small neighborhood of the set, as we see in previous chapters with high dimensional sphere as example. We can safely cut $\kappa>0$ volume to significantly reduce the diameter, this yields better measure for concentration for shapes in spaces with high dimension.
|
However, in higher dimensions, the volume may tend to concentrates more around a small neighborhood of the set, as we see in previous chapters with high dimensional sphere as example. We can safely cut $\kappa>0$ volume to significantly reduce the diameter, this yields better measure for concentration for shapes in spaces with high dimension.
|
||||||
|
|
||||||
|
|
||||||
\begin{defn}
|
\begin{defn}
|
||||||
\label{defn:observable-diameter}
|
\label{defn:observable-diameter}
|
||||||
Let $X$ be a metric-measure space, $Y$ be a metric space, and $f:X\to Y$ be a 1-Lipschitz function. Then $f_*\mu_X=\mu_Y$ is a push forward measure on $Y$.
|
Let $X$ be a metric-measure space, $Y$ be a metric space, and $f:X\to Y$ be a 1-Lipschitz function. Then $f_*\mu_X=\mu_Y$ is a push forward measure on $Y$.
|
||||||
|
|
||||||
For any real number $\kappa>0$, the \textbf{$\kappa$-observable diameter with screen $Y$} is defined as
|
For any real number $\kappa>0$, the \textbf{$\kappa$-observable diameter with screen $Y$} is defined as
|
||||||
|
|
||||||
$$
|
$$
|
||||||
\obdiam_Y(X;\kappa)=\sup\{\diam(f_*\mu_X;1-\kappa)\}
|
\obdiam_Y(X;\kappa)=\sup\{\diam(f_*\mu_X;1-\kappa)\}
|
||||||
$$
|
$$
|
||||||
|
|
||||||
And the \textbf{obbservable diameter with screen $Y$} is defined as
|
And the \textbf{obbservable diameter with screen $Y$} is defined as
|
||||||
|
|
||||||
$$
|
$$
|
||||||
\obdiam_Y(X)=\inf_{\kappa>0}\max\{\obdiam_Y(X;\kappa)\}
|
\obdiam_Y(X)=\inf_{\kappa>0}\max\{\obdiam_Y(X;\kappa)\}
|
||||||
$$
|
$$
|
||||||
|
|
||||||
If $Y=\R$, we call it the \textbf{observable diameter}.
|
If $Y=\R$, we call it the \textbf{observable diameter}.
|
||||||
|
|
||||||
\end{defn}
|
\end{defn}
|
||||||
|
|
||||||
If we collapse it naively via
|
If we collapse it naively via
|
||||||
$$
|
$$
|
||||||
\inf_{\kappa>0}\obdiam_Y(X;\kappa),
|
\inf_{\kappa>0}\obdiam_Y(X;\kappa),
|
||||||
$$
|
$$
|
||||||
we typically get something degenerate: as $\kappa\to 1$, the condition ``mass $\ge 1-\kappa$'' becomes almost empty space, so $\diam(\nu;1-\kappa)$ can be forced to be $0$ (take a tiny set of positive mass), and hence the infimum tends to $0$ for essentially any non-atomic space.
|
we typically get something degenerate: as $\kappa\to 1$, the condition ``mass $\ge 1-\kappa$'' becomes almost empty space, so $\diam(\nu;1-\kappa)$ can be forced to be $0$ (take a tiny set of positive mass), and hence the infimum tends to $0$ for essentially any non-atomic space.
|
||||||
|
|
||||||
This is why one either:
|
This is why one either:
|
||||||
\begin{enumerate}
|
\begin{enumerate}
|
||||||
\item keeps $\obdiam_Y(X;\kappa)$ as a \emph{function of $\kappa$} (picking $\kappa$ to be small but not $0$), or
|
\item keeps $\obdiam_Y(X;\kappa)$ as a \emph{function of $\kappa$} (picking $\kappa$ to be small but not $0$), or
|
||||||
\item if one insists on a single number, balances ``spread'' against ``exceptional mass'' by defining $\obdiam_Y(X)=\inf_{\kappa>0}\max\{\obdiam_Y(X;\kappa),\kappa\}$ as above.
|
\item if one insists on a single number, balances ``spread'' against ``exceptional mass'' by defining $\obdiam_Y(X)=\inf_{\kappa>0}\max\{\obdiam_Y(X;\kappa),\kappa\}$ as above.
|
||||||
\end{enumerate}
|
\end{enumerate}
|
||||||
The point of the $\max\{\cdot,\kappa\}$ is that it prevents cheating by taking $\kappa$ close to $1$: if $\kappa$ is large then the maximum is large regardless of how small $\obdiam_Y(X;\kappa)$ is, so the infimum is forced to occur where the exceptional mass and the observable spread are small.
|
The point of the $\max\{\cdot,\kappa\}$ is that it prevents cheating by taking $\kappa$ close to $1$: if $\kappa$ is large then the maximum is large regardless of how small $\obdiam_Y(X;\kappa)$ is, so the infimum is forced to occur where the exceptional mass and the observable spread are small.
|
||||||
|
|
||||||
Few additional proposition in \cite{shioya2014metricmeasuregeometry} will help us to estimate the observable diameter for complex projective spaces.
|
Few additional proposition in \cite{shioya2014metricmeasuregeometry} will help us to estimate the observable diameter for complex projective spaces.
|
||||||
|
|
||||||
\begin{prop}
|
\begin{prop}
|
||||||
\label{prop:observable-diameter-domination}
|
\label{prop:observable-diameter-domination}
|
||||||
Let $X$ and $Y$ be two metric-measure spaces and $\kappa>0$, and let $f:Y\to X$ be a 1-Lipschitz function ($Y$ dominates $X$, denoted as $X\prec Y$) then:
|
Let $X$ and $Y$ be two metric-measure spaces and $\kappa>0$, and let $f:Y\to X$ be a 1-Lipschitz function ($Y$ dominates $X$, denoted as $X\prec Y$) then:
|
||||||
|
|
||||||
\begin{enumerate}
|
\begin{enumerate}
|
||||||
\item
|
\item
|
||||||
$
|
$
|
||||||
\diam(X,1-\kappa)\leq \diam(Y,1-\kappa)
|
\diam(X,1-\kappa)\leq \diam(Y,1-\kappa)
|
||||||
$
|
$
|
||||||
\item $\obdiam(X;-\kappa)\leq \diam(X;1-\kappa)$, and $\obdiam(X)$ is finite.
|
\item $\obdiam(X;-\kappa)\leq \diam(X;1-\kappa)$, and $\obdiam(X)$ is finite.
|
||||||
\item
|
\item
|
||||||
$
|
$
|
||||||
\obdiam(X;-\kappa)\leq \obdiam(Y;-\kappa)
|
\obdiam(X;-\kappa)\leq \obdiam(Y;-\kappa)
|
||||||
$
|
$
|
||||||
\end{enumerate}
|
\end{enumerate}
|
||||||
\end{prop}
|
\end{prop}
|
||||||
|
|
||||||
\begin{proof}
|
\begin{proof}
|
||||||
Since $f$ is 1-Lipschitz, we have $f_*\mu Y=\mu_X$. Let $A$ be any Borel set of $Y$ with $\mu_Y(A)\geq 1-\kappa$ and $\overline{f(A)}$ be the closure of $f(A)$ in $X$. We have $\mu_X(\overline{f(A)})=\mu_Y(f^{-1}(\overline{f(A)}))\geq \mu_Y(A)\geq 1-\kappa$ and by the 1-lipschitz property, $\diam(\overline{f(A)})\leq \diam(A)$, so $\diam(X;1-\kappa)\leq \diam(A)\leq \diam(Y;1-\kappa)$.
|
Since $f$ is 1-Lipschitz, we have $f_*\mu Y=\mu_X$. Let $A$ be any Borel set of $Y$ with $\mu_Y(A)\geq 1-\kappa$ and $\overline{f(A)}$ be the closure of $f(A)$ in $X$. We have $\mu_X(\overline{f(A)})=\mu_Y(f^{-1}(\overline{f(A)}))\geq \mu_Y(A)\geq 1-\kappa$ and by the 1-lipschitz property, $\diam(\overline{f(A)})\leq \diam(A)$, so $\diam(X;1-\kappa)\leq \diam(A)\leq \diam(Y;1-\kappa)$.
|
||||||
|
|
||||||
Let $g:X\to \R$ be any 1-lipschitz function, since $(\R,|\cdot|,g_*\mu_X)$ is dominated by $X$, $\diam(\R;1-\kappa)\leq \diam(X;1-\kappa)$. Therefore, $\obdiam(X;-\kappa)\leq \diam(X;1-\kappa)$.
|
Let $g:X\to \R$ be any 1-lipschitz function, since $(\R,|\cdot|,g_*\mu_X)$ is dominated by $X$, $\diam(\R;1-\kappa)\leq \diam(X;1-\kappa)$. Therefore, $\obdiam(X;-\kappa)\leq \diam(X;1-\kappa)$.
|
||||||
|
|
||||||
and
|
and
|
||||||
$$
|
$$
|
||||||
\diam(g_*\mu_X;1-\kappa)\leq \diam((f\circ g)_*\mu_Y;1-\kappa)\leq \obdiam(Y;1-\kappa)
|
\diam(g_*\mu_X;1-\kappa)\leq \diam((f\circ g)_*\mu_Y;1-\kappa)\leq \obdiam(Y;1-\kappa)
|
||||||
$$
|
$$
|
||||||
\end{proof}
|
\end{proof}
|
||||||
|
|
||||||
\begin{prop}
|
\begin{prop}
|
||||||
\label{prop:observable-diameter-scale}
|
\label{prop:observable-diameter-scale}
|
||||||
Let $X$ be an metric-measure space. Then for any real number $t>0$, we have
|
Let $X$ be an metric-measure space. Then for any real number $t>0$, we have
|
||||||
|
|
||||||
$$
|
$$
|
||||||
\obdiam(tX;-\kappa)=t\obdiam(X;-\kappa)
|
\obdiam(tX;-\kappa)=t\obdiam(X;-\kappa)
|
||||||
$$
|
$$
|
||||||
|
|
||||||
Where $tX=(X,tdX,\mu X)$.
|
Where $tX=(X,tdX,\mu X)$.
|
||||||
\end{prop}
|
\end{prop}
|
||||||
|
|
||||||
\begin{proof}
|
\begin{proof}
|
||||||
$$
|
$$
|
||||||
\begin{aligned}
|
\begin{aligned}
|
||||||
\obdiam(tX;-\kappa)&=\sup\{\diam(f_*\mu_X;1-\kappa)|f:tX\to \R \text{ is 1-Lipschitz}\}\\
|
\obdiam(tX;-\kappa)&=\sup\{\diam(f_*\mu_X;1-\kappa)|f:tX\to \R \text{ is 1-Lipschitz}\}\\
|
||||||
&=\sup\{\diam(f_*\mu_X;1-\kappa)|t^{-1}f:X\to \R \text{ is 1-Lipschitz}\}\\
|
&=\sup\{\diam(f_*\mu_X;1-\kappa)|t^{-1}f:X\to \R \text{ is 1-Lipschitz}\}\\
|
||||||
&=\sup\{\diam((tg)_*\mu_X;1-\kappa)|g:X\to \R \text{ is 1-Lipschitz}\}\\
|
&=\sup\{\diam((tg)_*\mu_X;1-\kappa)|g:X\to \R \text{ is 1-Lipschitz}\}\\
|
||||||
&=t\sup\{\diam(g_*\mu_X;1-\kappa)|g:X\to \R \text{ is 1-Lipschitz}\}\\
|
&=t\sup\{\diam(g_*\mu_X;1-\kappa)|g:X\to \R \text{ is 1-Lipschitz}\}\\
|
||||||
&=t\obdiam(X;-\kappa)
|
&=t\obdiam(X;-\kappa)
|
||||||
\end{aligned}
|
\end{aligned}
|
||||||
$$
|
$$
|
||||||
\end{proof}
|
\end{proof}
|
||||||
|
|
||||||
\subsection{Observable diameter for class of spheres}
|
\subsection{Observable diameter for class of spheres}
|
||||||
|
|
||||||
In this section, we will try to use the results from previous sections to estimate the observable diameter for class of spheres.
|
In this section, we will try to use the results from previous sections to estimate the observable diameter for class of spheres.
|
||||||
|
|
||||||
\begin{theorem}
|
\begin{theorem}
|
||||||
\label{thm:observable-diameter-sphere}
|
\label{thm:observable-diameter-sphere}
|
||||||
For any real number $\kappa$ with $0<\kappa<1$, we have
|
For any real number $\kappa$ with $0<\kappa<1$, we have
|
||||||
$$
|
$$
|
||||||
\obdiam(S^n(1);-\kappa)=O(\sqrt{n})
|
\obdiam(S^n(1);-\kappa)=O(\sqrt{n})
|
||||||
$$
|
$$
|
||||||
\end{theorem}
|
\end{theorem}
|
||||||
|
|
||||||
\begin{proof}
|
\begin{proof}
|
||||||
First, recall that by maxwell boltzmann distribution, we have that for any $n>0$, let $I(r)$ denote the measure of standard gaussian measure on the interval $[0,r]$. Then we have
|
First, recall that by maxwell boltzmann distribution, we have that for any $n>0$, let $I(r)$ denote the measure of standard gaussian measure on the interval $[0,r]$. Then we have
|
||||||
|
|
||||||
$$
|
$$
|
||||||
\begin{aligned}
|
\begin{aligned}
|
||||||
\lim_{n\to \infty} \obdiam(S^n(\sqrt{n});-\kappa)&=\lim_{n\to \infty} \sup\{\diam((\pi_{n,k})_*\sigma^n;1-\kappa)|\pi_{n,k} \text{ is 1-Lipschitz}\}\\
|
\lim_{n\to \infty} \obdiam(S^n(\sqrt{n});-\kappa)&=\lim_{n\to \infty} \sup\{\diam((\pi_{n,k})_*\sigma^n;1-\kappa)|\pi_{n,k} \text{ is 1-Lipschitz}\}\\
|
||||||
&=\lim_{n\to \infty} \sup\{\diam(\gamma^1;1-\kappa)|\gamma^1 \text{ is the standard gaussian measure}\}\\
|
&=\lim_{n\to \infty} \sup\{\diam(\gamma^1;1-\kappa)|\gamma^1 \text{ is the standard gaussian measure}\}\\
|
||||||
&=\diam(\gamma^1;1-\kappa)\\
|
&=\diam(\gamma^1;1-\kappa)\\
|
||||||
&=2I^{-1}(\frac{1-\kappa}{2})\text { cutting the extremum for normal distribution}\\
|
&=2I^{-1}(\frac{1-\kappa}{2})\text { cutting the extremum for normal distribution}\\
|
||||||
\end{aligned}
|
\end{aligned}
|
||||||
$$
|
$$
|
||||||
|
|
||||||
By proposition \ref{prop:observable-diameter-scale}, we have
|
By proposition \ref{prop:observable-diameter-scale}, we have
|
||||||
|
|
||||||
$$
|
$$
|
||||||
\obdiam(S^n(\sqrt{n});-\kappa)=\sqrt{n}\obdiam(S^n(1);-\kappa)
|
\obdiam(S^n(\sqrt{n});-\kappa)=\sqrt{n}\obdiam(S^n(1);-\kappa)
|
||||||
$$
|
$$
|
||||||
|
|
||||||
So $\obdiam(S^n(1);-\kappa)=\sqrt{n}(2I^{-1}(\frac{1-\kappa}{2}))=O(\sqrt{n})$.
|
So $\obdiam(S^n(1);-\kappa)=\sqrt{n}(2I^{-1}(\frac{1-\kappa}{2}))=O(\sqrt{n})$.
|
||||||
\end{proof}
|
\end{proof}
|
||||||
|
|
||||||
From the previous discussion, we see that the only remaining for finding observable diameter of $\C P^n$ is to find the lipchitz function that is isometric with consistent push-forward measure.
|
From the previous discussion, we see that the only remaining for finding observable diameter of $\C P^n$ is to find the lipchitz function that is isometric with consistent push-forward measure.
|
||||||
|
|
||||||
To find such metric, we need some additional results from previous sections.
|
To find such metric, we need some additional results.
|
||||||
|
|
||||||
A natural measure for $\C P^n$ is the normalized volume measure on $\C P^n$ induced from the Fubini-Study metric. \cite{lee_introduction_2018} Example 2.30
|
\begin{defn}
|
||||||
|
\label{defn:riemannian-metric}
|
||||||
\begin{defn}
|
|
||||||
\label{defn:fubini-study-metric}
|
Let $M$ be a smooth manifold. A \textit{\textbf{Riemannian metric}} on $M$ is a smooth covariant tensor field $g\in \mathcal{T}^2(M)$ such that for each $p\in M$, $g_p$ is an inner product on $T_pM$.
|
||||||
|
|
||||||
Let $n$ be a positive integer, and consider the complex projective space $\C P^n$ defined as the quotient space of $\C^{n+1}$ by the equivalence relation $z\sim z'$ if there exists $\lambda \in \C$ such that $z=\lambda z'$. The map $\pi:\C^{n+1}\setminus\{0\}\to \C P^n$ sending each point in $\C^{n+1}\setminus\{0\}$ to its span is surjective smooth submersion.
|
$g_p(v,v)\geq 0$ for each $p\in M$ and each $v\in T_pM$. equality holds if and only if $v=0$.
|
||||||
|
|
||||||
Identifying $\C^{n+1}$ with $\R^{2n+2}$ with its Euclidean metric, we can view the unit sphere $S^{2n+1}$ with its roud metric $\mathring{g}$ as an embedded Riemannian submanifold of $\C^{n+1}\setminus\{0\}$. Let $p:S^{2n+1}\to \C P^n$ denote the restriction of the map $\pi$. Then $p$ is smooth, and its is surjective, because every 1-dimensional complex subspace contains elements of unit norm.
|
\end{defn}
|
||||||
|
|
||||||
\end{defn}
|
% TODO: There is a hidden chapter on group action on manifolds, can you find that?
|
||||||
|
|
||||||
There are many additional properties for such construction, we will check them just for curiosity.
|
\begin{theorem}
|
||||||
|
\label{theorem:riemannian-submersion}
|
||||||
We need to show that it is a submersion.
|
|
||||||
|
Let $(\tilde{M},\tilde{g})$ be a Riemannian manifold, let $\pi:\tilde{M}\to M$ be a surjective smooth submersion, and let $G$ be a group acting on $\tilde{M}$. If the \textbf{action} is
|
||||||
\begin{proof}
|
\begin{enumerate}
|
||||||
Let $z_0\in S^{2n+1}$ and set $\zeta_0=p(z_0)\in \C P^n$. Since $\pi$ is a smooth submersion, it has a smooth local section $\sigma: U\to \C^{n+1}$ defined on a neighborhood $U$ of $\zeta_0$ and satisfying $\sigma(\zeta_0)=z_0$ by the local section theorem (Theorem \ref{theorem:local_section_theorem}). Let $v:\C^{n+1}\setminus\{0\}\to S^{2n+1}$ be the radial projection on to the sphere:
|
\item isometric: the map $x\mapsto \varphi\cdot x$ is an isometry for each $\varphi\in G$.
|
||||||
|
\item vertical: every element $\varphi\in G$ takes each fiber to itself, that is $\pi(\varphi\cdot p)=\pi(p)$ for all $p\in \tilde{M}$.
|
||||||
$$
|
\item transitive on fibers: for each $p,q\in \tilde{M}$ such that $\pi(p)=\pi(q)$, there exists $\varphi\in G$ such that $\varphi\cdot p = q$.
|
||||||
v(z)=\frac{z}{|z|}
|
\end{enumerate}
|
||||||
$$
|
Then there is a unique Riemannian metric on $M$ such that $\pi$ is a Riemannian submersion.
|
||||||
|
|
||||||
Since dividing an element of $\C^{n+1}$ by a nonzero scalar does not change its span, it follows that $p\circ v=\pi$. Therefore, if we set $\tilde{\sigma}=v\circ \sigma$, then $\tilde{\sigma}$ is a smooth local section of $p$. Apply the local section theorem (Theorem \ref{theorem:local_section_theorem}) again, this shows that $p$ is a submersion.
|
\end{theorem}
|
||||||
|
|
||||||
Define an action of $S^1$ on $S^{2n+1}$ by complex multiplication:
|
A natural measure for $\C P^n$ is the normalized volume measure on $\C P^n$ induced from the Fubini-Study metric. \cite{lee_introduction_2018} Example 2.30
|
||||||
|
|
||||||
$$
|
\begin{defn}
|
||||||
\lambda (z^1,z^2,\ldots,z^{n+1})=(\lambda z^1,\lambda z^2,\ldots,\lambda z^{n+1})
|
\label{defn:fubini-study-metric}
|
||||||
$$
|
|
||||||
|
Let $n$ be a positive integer, and consider the complex projective space $\C P^n$ defined as the quotient space of $\C^{n+1}$ by the equivalence relation $z\sim z'$ if there exists $\lambda \in \C$ such that $z=\lambda z'$. The map $\pi:\C^{n+1}\setminus\{0\}\to \C P^n$ sending each point in $\C^{n+1}\setminus\{0\}$ to its span is surjective smooth submersion.
|
||||||
for $\lambda\in S^1$ (viewed as complex number of norm 1) and $z=(z^1,z^2,\ldots,z^{n+1})\in S^{2n+1}$. This is easily seen to be isometric, vertical, and transitive on fibers of $p$.
|
|
||||||
|
Identifying $\C^{n+1}$ with $\R^{2n+2}$ with its Euclidean metric, we can view the unit sphere $S^{2n+1}$ with its roud metric $\mathring{g}$ as an embedded Riemannian submanifold of $\C^{n+1}\setminus\{0\}$. Let $p:S^{2n+1}\to \C P^n$ denote the restriction of the map $\pi$. Then $p$ is smooth, and its is surjective, because every 1-dimensional complex subspace contains elements of unit norm.
|
||||||
By (Theorem \ref{theorem:riemannian-submersion}). Therefore, there is a unique metric on $\C P^n$ such that the map $p:S^{2n+1}\to \C P^n$ is a Riemannian submersion. This metric is called the Fubini-study metric.
|
|
||||||
\end{proof}
|
\end{defn}
|
||||||
|
|
||||||
\subsection{Observable diameter for complex projective spaces}
|
There are many additional properties for such construction, we will check them just for curiosity.
|
||||||
|
|
||||||
Using the projection map and Hopf's fibration, we can estimate the observable diameter for complex projective spaces from the observable diameter of spheres.
|
We need to show that it is a submersion.
|
||||||
|
|
||||||
\begin{theorem}
|
\begin{proof}
|
||||||
\label{thm:observable-diameter-complex-projective-space}
|
Let $z_0\in S^{2n+1}$ and set $\zeta_0=p(z_0)\in \C P^n$. Since $\pi$ is a smooth submersion, it has a smooth local section $\sigma: U\to \C^{n+1}$ defined on a neighborhood $U$ of $\zeta_0$ and satisfying $\sigma(\zeta_0)=z_0$ by the local section theorem (Theorem \ref{theorem:local_section_theorem}). Let $v:\C^{n+1}\setminus\{0\}\to S^{2n+1}$ be the radial projection on to the sphere:
|
||||||
For any real number $\kappa$ with $0<\kappa<1$, we have
|
|
||||||
$$
|
$$
|
||||||
\obdiam(\mathbb{C}P^n(1);-\kappa)\leq O(\sqrt{n})
|
v(z)=\frac{z}{|z|}
|
||||||
$$
|
$$
|
||||||
\end{theorem}
|
|
||||||
|
Since dividing an element of $\C^{n+1}$ by a nonzero scalar does not change its span, it follows that $p\circ v=\pi$. Therefore, if we set $\tilde{\sigma}=v\circ \sigma$, then $\tilde{\sigma}$ is a smooth local section of $p$. Apply the local section theorem (Theorem \ref{theorem:local_section_theorem}) again, this shows that $p$ is a submersion.
|
||||||
\begin{proof}
|
|
||||||
Recall from Example 2.30 in \cite{lee_introduction_2018}, the Hopf fibration $f_n:S^{2n+1}(1)\to \C P^n$ is 1-Lipschitz continuous with respect to the Fubini-Study metric on $\C P^n$. and the push-forward $(f_n)_*\sigma^{2n+1}$ coincides with the normalized volume measure on $\C P^n$ induced from the Fubini-Study metric.
|
Define an action of $S^1$ on $S^{2n+1}$ by complex multiplication:
|
||||||
|
|
||||||
By proposition \ref{prop:observable-diameter-domination}, we have $\obdiam(\mathbb{C}P^n(1);-\kappa)\leq \obdiam(S^{2n+1}(1);-\kappa)\leq O(\sqrt{n})$.
|
$$
|
||||||
|
\lambda (z^1,z^2,\ldots,z^{n+1})=(\lambda z^1,\lambda z^2,\ldots,\lambda z^{n+1})
|
||||||
\end{proof}
|
$$
|
||||||
|
|
||||||
\section{Use entropy function as estimator of observable diameter for complex projective spaces}
|
for $\lambda\in S^1$ (viewed as complex number of norm 1) and $z=(z^1,z^2,\ldots,z^{n+1})\in S^{2n+1}$. This is easily seen to be isometric, vertical, and transitive on fibers of $p$.
|
||||||
|
|
||||||
In this section, we wish to use observable diameter to estimate the statics of thermal dynamics of some classical systems.
|
By (Theorem \ref{theorem:riemannian-submersion}). Therefore, there is a unique metric on $\C P^n$ such that the map $p:S^{2n+1}\to \C P^n$ is a Riemannian submersion. This metric is called the Fubini-study metric.
|
||||||
|
\end{proof}
|
||||||
|
|
||||||
|
\subsection{Observable diameter for complex projective spaces}
|
||||||
\ifSubfilesClassLoaded{
|
|
||||||
\printbibliography[title={References}]
|
Using the projection map and Hopf's fibration, we can estimate the observable diameter for complex projective spaces from the observable diameter of spheres.
|
||||||
}
|
|
||||||
|
\begin{theorem}
|
||||||
\end{document}
|
\label{thm:observable-diameter-complex-projective-space}
|
||||||
|
For any real number $\kappa$ with $0<\kappa<1$, we have
|
||||||
|
$$
|
||||||
|
\obdiam(\mathbb{C}P^n(1);-\kappa)\leq O(\sqrt{n})
|
||||||
|
$$
|
||||||
|
\end{theorem}
|
||||||
|
|
||||||
|
\begin{proof}
|
||||||
|
Recall from Example 2.30 in \cite{lee_introduction_2018}, the Hopf fibration $f_n:S^{2n+1}(1)\to \C P^n$ is 1-Lipschitz continuous with respect to the Fubini-Study metric on $\C P^n$. and the push-forward $(f_n)_*\sigma^{2n+1}$ coincides with the normalized volume measure on $\C P^n$ induced from the Fubini-Study metric.
|
||||||
|
|
||||||
|
By proposition \ref{prop:observable-diameter-domination}, we have $\obdiam(\mathbb{C}P^n(1);-\kappa)\leq \obdiam(S^{2n+1}(1);-\kappa)\leq O(\sqrt{n})$.
|
||||||
|
|
||||||
|
\end{proof}
|
||||||
|
|
||||||
|
\section{Use entropy function as estimator of observable diameter for complex projective spaces}
|
||||||
|
|
||||||
|
In this section we describe a Monte Carlo pipeline for comparing concentration phenomena across three metric-measure spaces using real-valued entropy observables. The goal is not to compute the exact observable diameter
|
||||||
|
$$
|
||||||
|
\operatorname{ObsDiam}_{\mathbb{R}}(X;-\kappa)
|
||||||
|
=
|
||||||
|
\sup_{f \in \operatorname{Lip}_1(X,\mathbb{R})}
|
||||||
|
\operatorname{diam}(f_*\mu_X;1-\kappa),
|
||||||
|
$$
|
||||||
|
but to estimate it by choosing a specific observable $f:X\to \mathbb{R}$ and then measuring the partial diameter of its push-forward distribution. Thus all numerical quantities below should be interpreted as \emph{entropy-based observable-diameter proxies}, not exact observable diameters in Gromov's sense \cite{MGomolovs,shioya2014metricmeasuregeometry}.
|
||||||
|
|
||||||
|
The screen is $\mathbb{R}$ equipped with the Euclidean metric, and for a fixed $\kappa \in (0,1)$ we set
|
||||||
|
$$
|
||||||
|
\alpha = 1-\kappa.
|
||||||
|
$$
|
||||||
|
Given sampled values $y_1,\dots,y_N \in \mathbb{R}$ of the observable, the code sorts them and computes the shortest interval $[a,b]$ containing at least $\lceil \alpha N \rceil$ samples. Its width
|
||||||
|
$$
|
||||||
|
b-a
|
||||||
|
$$
|
||||||
|
is the empirical partial diameter of the push-forward measure on $\mathbb{R}$.
|
||||||
|
|
||||||
|
To compare this width with the true observable diameter, the code also estimates an empirical Lipschitz constant of the chosen observable. If $x_i,x_j \in X$ are sampled states and $f(x_i),f(x_j)$ are the corresponding observable values, then the sampled slopes are
|
||||||
|
$$
|
||||||
|
\frac{|f(x_i)-f(x_j)|}{d_X(x_i,x_j)},
|
||||||
|
$$
|
||||||
|
where $d_X$ is the metric of the ambient space. The code records both the maximum sampled slope and the $0.99$-quantile of these slopes. Dividing the empirical partial diameter by these sampled Lipschitz constants gives two normalized proxies:
|
||||||
|
$$
|
||||||
|
\frac{\operatorname{diam}(f_*\mu_X;1-\kappa)}{L_{\max}}
|
||||||
|
\qquad \text{and} \qquad
|
||||||
|
\frac{\operatorname{diam}(f_*\mu_X;1-\kappa)}{L_{0.99}}.
|
||||||
|
$$
|
||||||
|
If the chosen observable were exactly $1$-Lipschitz, these normalized quantities would coincide with the raw width. In practice they should be viewed only as heuristic lower-scale corrections.
|
||||||
|
|
||||||
|
\subsection{Random sampling using standard uniform measure on the unit sphere}
|
||||||
|
|
||||||
|
The first family of spaces is the real unit sphere
|
||||||
|
$$
|
||||||
|
S^{m-1}
|
||||||
|
=
|
||||||
|
\left\{
|
||||||
|
x=(x_1,\dots,x_m)\in \mathbb{R}^m : \|x\|_2=1
|
||||||
|
\right\},
|
||||||
|
$$
|
||||||
|
equipped with the geodesic distance
|
||||||
|
$$
|
||||||
|
d_{S}(x,y)=\arccos \langle x,y\rangle
|
||||||
|
$$
|
||||||
|
and the normalized Riemannian volume measure. This is the standard metric-measure structure used in concentration of measure on spheres \cite{lee_introduction_2018,romanvershyni,shioya2014metricmeasuregeometry}.
|
||||||
|
|
||||||
|
Sampling is performed by drawing a standard Gaussian vector $g\in \mathbb{R}^m$ and normalizing:
|
||||||
|
$$
|
||||||
|
x=\frac{g}{\|g\|_2}.
|
||||||
|
$$
|
||||||
|
This produces the uniform distribution on $S^{m-1}$.
|
||||||
|
|
||||||
|
The observable is a Shannon entropy built from the squared coordinates:
|
||||||
|
$$
|
||||||
|
f_{\mathrm{sphere}}(x)
|
||||||
|
=
|
||||||
|
-\sum_{i=1}^m x_i^2 \log_2(x_i^2).
|
||||||
|
$$
|
||||||
|
Since $(x_1^2,\dots,x_m^2)$ is a probability vector, $f_{\mathrm{sphere}}$ takes values in $[0,\log_2 m]$, and the code records $\log_2 m$ as the natural upper bound of the observable.
|
||||||
|
|
||||||
|
For each chosen dimension $m$, the experiment generates $N$ independent samples $x^{(1)},\dots,x^{(N)}$, computes the values
|
||||||
|
$$
|
||||||
|
f_{\mathrm{sphere}}(x^{(1)}),\dots,f_{\mathrm{sphere}}(x^{(N)}),
|
||||||
|
$$
|
||||||
|
and then evaluates the shortest interval containing mass at least $1-\kappa$. This gives an empirical observable-diameter proxy for the sphere family. The code also computes the empirical mean, median, standard deviation, and the normalized proxies obtained from sampled Lipschitz ratios.
|
||||||
|
|
||||||
|
\subsection{Visualized the concentration of measure phenomenon on complex projective space}
|
||||||
|
|
||||||
|
The second family is complex projective space
|
||||||
|
$$
|
||||||
|
\mathbb{C}P^{d_A d_B-1},
|
||||||
|
$$
|
||||||
|
viewed as the space of pure states in $\mathbb{C}^{d_A}\otimes \mathbb{C}^{d_B}$ modulo global phase. Geometrically, this space is equipped with the Fubini--Study metric and its associated normalized volume measure \cite{lee_introduction_2018,Bengtsson_Zyczkowski_2017}. Numerically, a projective point is represented by a unit vector
|
||||||
|
$$
|
||||||
|
\psi \in \mathbb{C}^{d_A d_B},
|
||||||
|
\qquad
|
||||||
|
\|\psi\|=1,
|
||||||
|
$$
|
||||||
|
and distances are computed by the Fubini--Study formula
|
||||||
|
$$
|
||||||
|
d_{FS}([\psi],[\phi])
|
||||||
|
=
|
||||||
|
\arccos |\langle \psi,\phi\rangle|.
|
||||||
|
$$
|
||||||
|
|
||||||
|
Sampling is implemented by drawing a complex Gaussian matrix
|
||||||
|
$$
|
||||||
|
G \in \mathbb{C}^{d_A \times d_B},
|
||||||
|
$$
|
||||||
|
with independent standard complex normal entries, and then normalizing it so that
|
||||||
|
$$
|
||||||
|
\psi = \frac{\operatorname{vec}(G)}{\|\operatorname{vec}(G)\|}.
|
||||||
|
$$
|
||||||
|
This is equivalent to Haar sampling on the unit sphere in $\mathbb{C}^{d_A d_B}$ and hence induces the standard unitarily invariant measure on $\mathbb{C}P^{d_A d_B-1}$ \cite{Bengtsson_Zyczkowski_2017,Nielsen_Chuang_2010}.
|
||||||
|
|
||||||
|
The real-valued observable is the bipartite entanglement entropy. Writing
|
||||||
|
$$
|
||||||
|
\rho_A = \operatorname{Tr}_B |\psi\rangle\langle \psi|,
|
||||||
|
$$
|
||||||
|
the code defines
|
||||||
|
$$
|
||||||
|
f_{\mathrm{CP}}([\psi])
|
||||||
|
=
|
||||||
|
S(\rho_A)
|
||||||
|
=
|
||||||
|
-\operatorname{Tr}(\rho_A \log_2 \rho_A).
|
||||||
|
$$
|
||||||
|
Equivalently, if $\lambda_1,\dots,\lambda_{d_A}$ are the eigenvalues of $\rho_A$, then
|
||||||
|
$$
|
||||||
|
f_{\mathrm{CP}}([\psi])
|
||||||
|
=
|
||||||
|
-\sum_{i=1}^{d_A}\lambda_i \log_2 \lambda_i.
|
||||||
|
$$
|
||||||
|
This observable takes values in $[0,\log_2 d_A]$.
|
||||||
|
|
||||||
|
For each dimension pair $(d_A,d_B)$, the experiment samples $N$ independent Haar-random pure states, computes the entropy values, and then forms the empirical push-forward distribution on $\mathbb{R}$. The shortest interval containing mass at least $1-\kappa$ is reported as the entropy-based observable-diameter proxy. In addition, the code plots histograms, upper-tail deficit plots for
|
||||||
|
$$
|
||||||
|
\log_2 d_A - S(\rho_A),
|
||||||
|
$$
|
||||||
|
and family-wise comparisons of partial diameter, standard deviation, and mean deficit. When available, these plots are overlaid with the Page average entropy and with Hayden-style concentration scales, which serve as theoretical guides rather than direct outputs of the simulation \cite{Hayden,Hayden_2006,Pages_conjecture_simple_proof}.
|
||||||
|
|
||||||
|
\subsection{Random sampling using Majorana Stellar representation}
|
||||||
|
|
||||||
|
The third family is the symmetric subspace
|
||||||
|
$$
|
||||||
|
\operatorname{Sym}^N(\mathbb{C}^2),
|
||||||
|
$$
|
||||||
|
which is naturally identified with $\mathbb{C}P^N$ after projectivization. In this model, a pure symmetric $N$-qubit state is written in the Dicke basis as
|
||||||
|
$$
|
||||||
|
|\psi\rangle
|
||||||
|
=
|
||||||
|
\sum_{k=0}^{N} c_k |D^N_k\rangle,
|
||||||
|
\qquad
|
||||||
|
\sum_{k=0}^{N}|c_k|^2 = 1.
|
||||||
|
$$
|
||||||
|
The projective metric is again the Fubini--Study metric
|
||||||
|
$$
|
||||||
|
d_{FS}([\psi],[\phi])=\arccos |\langle \psi,\phi\rangle|.
|
||||||
|
$$
|
||||||
|
|
||||||
|
Sampling is performed by drawing a standard complex Gaussian vector
|
||||||
|
$$
|
||||||
|
(c_0,\dots,c_N)\in \mathbb{C}^{N+1}
|
||||||
|
$$
|
||||||
|
and normalizing it. This gives the unitarily invariant measure on the projective symmetric state space.
|
||||||
|
|
||||||
|
The observable used by the code is the one-particle entropy of the symmetric state. From the coefficient vector $(c_0,\dots,c_N)$ one constructs the one-qubit reduced density matrix $\rho_1$, and then defines
|
||||||
|
$$
|
||||||
|
f_{\mathrm{Maj}}([\psi])
|
||||||
|
=
|
||||||
|
S(\rho_1)
|
||||||
|
=
|
||||||
|
-\operatorname{Tr}(\rho_1 \log_2 \rho_1).
|
||||||
|
$$
|
||||||
|
Since $\rho_1$ is a qubit state, this observable takes values in $[0,1]$.
|
||||||
|
|
||||||
|
To visualize the same states in Majorana form, the code also associates to a sampled symmetric state its Majorana polynomial and computes its roots. After stereographic projection, these roots define $N$ points on $S^2$, called the Majorana stars \cite{Bengtsson_Zyczkowski_2017}. The resulting star plots are included only as geometric visualizations; they are not used to define the metric or the observable. The metric-measure structure used in the actual simulation remains the Fubini--Study metric and the unitarily invariant measure on the projective symmetric state space.
|
||||||
|
|
||||||
|
Thus, for each $N$, the simulation produces:
|
||||||
|
\begin{enumerate}
|
||||||
|
\item a sample of symmetric states,
|
||||||
|
\item the corresponding one-body entropy values,
|
||||||
|
\item the shortest interval containing mass at least $1-\kappa$ in the push-forward distribution on $\mathbb{R}$,
|
||||||
|
\item empirical Lipschitz-normalized versions of this width,
|
||||||
|
\item and a separate Majorana-star visualization of representative samples.
|
||||||
|
\end{enumerate}
|
||||||
|
|
||||||
|
Taken together, these three families allow us to compare how entropy-based concentration behaves on a real sphere, on a general complex projective space carrying bipartite entanglement entropy, and on the symmetric subspace described by Majorana stellar data.
|
||||||
|
|
||||||
|
|
||||||
|
\ifSubfilesClassLoaded{
|
||||||
|
\printbibliography[title={References}]
|
||||||
|
}
|
||||||
|
|
||||||
|
\end{document}
|
||||||
|
|||||||
@@ -1,57 +1,57 @@
|
|||||||
% chapters/chap2.tex
|
% chapters/chap2.tex
|
||||||
\documentclass[../main.tex]{subfiles}
|
\documentclass[../main.tex]{subfiles}
|
||||||
|
|
||||||
\ifSubfilesClassLoaded{
|
\ifSubfilesClassLoaded{
|
||||||
\addbibresource{../main.bib}
|
\addbibresource{../main.bib}
|
||||||
}
|
}
|
||||||
|
|
||||||
\begin{document}
|
\begin{document}
|
||||||
|
|
||||||
\chapter{Seigel-Bargmann Space}
|
\chapter{Seigel-Bargmann Space}
|
||||||
|
|
||||||
In this chapter, we will collect ideas and other perspective we have understanding the concentration of measure phenomenon. Especially with symmetric product of $\C P^1$ and see how it relates to Riemman surfaces and Seigel-Bargmann spaces.
|
In this chapter, we will collect ideas and other perspective we have understanding the concentration of measure phenomenon. Especially with symmetric product of $\C P^1$ and see how it relates to Riemman surfaces and Seigel-Bargmann spaces.
|
||||||
|
|
||||||
\begin{figure}[h]
|
\begin{figure}[h]
|
||||||
\centering
|
\centering
|
||||||
\begin{tikzpicture}[node distance=40mm, thick,
|
\begin{tikzpicture}[node distance=40mm, thick,
|
||||||
main/.style={draw, draw=white},
|
main/.style={draw, draw=white},
|
||||||
towards/.style={->},
|
towards/.style={->},
|
||||||
towards_imp/.style={<->,red},
|
towards_imp/.style={<->,red},
|
||||||
mutual/.style={<->}
|
mutual/.style={<->}
|
||||||
]
|
]
|
||||||
\node[main] (cp) {$\mathbb{C}P^{n}$};
|
\node[main] (cp) {$\mathbb{C}P^{n}$};
|
||||||
\node[main] (c) [below of=cp] {$\mathbb{C}^{n+1}$};
|
\node[main] (c) [below of=cp] {$\mathbb{C}^{n+1}$};
|
||||||
\node[main] (p) [right of=cp] {$\mathbb{P}^n$};
|
\node[main] (p) [right of=cp] {$\mathbb{P}^n$};
|
||||||
\node[main] (sym) [below of=p] {$\operatorname{Sym}_n(\mathbb{C}P^1)$};
|
\node[main] (sym) [below of=p] {$\operatorname{Sym}_n(\mathbb{C}P^1)$};
|
||||||
% draw edges
|
% draw edges
|
||||||
\draw[towards] (c) -- (cp) node[midway, left] {$z\sim \lambda z$};
|
\draw[towards] (c) -- (cp) node[midway, left] {$z\sim \lambda z$};
|
||||||
\draw[towards] (c) -- (p) node[midway, fill=white] {$w(z)=\sum_{i=0}^n Z_i z^i$};
|
\draw[towards] (c) -- (p) node[midway, fill=white] {$w(z)=\sum_{i=0}^n Z_i z^i$};
|
||||||
\draw[towards_imp] (cp) -- (p) node[midway, above] {$w(z)\sim w(\lambda z)$};
|
\draw[towards_imp] (cp) -- (p) node[midway, above] {$w(z)\sim w(\lambda z)$};
|
||||||
\draw[mutual] (p) -- (sym) node[midway, right] {root of $w(z)$};
|
\draw[mutual] (p) -- (sym) node[midway, right] {root of $w(z)$};
|
||||||
\end{tikzpicture}
|
\end{tikzpicture}
|
||||||
\caption{Majorana stellar representation}
|
\caption{Majorana stellar representation}
|
||||||
\label{fig:majorana_stellar_representation}
|
\label{fig:majorana_stellar_representation}
|
||||||
\end{figure}
|
\end{figure}
|
||||||
|
|
||||||
Basically, there is a bijection between the complex projective space $\mathbb{C}P^n$ and the set of roots of a polynomial of degree $n$.
|
Basically, there is a bijection between the complex projective space $\mathbb{C}P^n$ and the set of roots of a polynomial of degree $n$.
|
||||||
|
|
||||||
We can use a symmetric group of permutations of $n$ complex numbers (or $S^2$) to represent the $\mathbb{C}P^n$, that is, $\mathbb{C}P^n=S^2\times S^2\times \cdots \times S^2/S_n$.
|
We can use a symmetric group of permutations of $n$ complex numbers (or $S^2$) to represent the $\mathbb{C}P^n$, that is, $\mathbb{C}P^n=S^2\times S^2\times \cdots \times S^2/S_n$.
|
||||||
|
|
||||||
One might be interested in the random sampling over the $\operatorname{Sym}_n(\mathbb{C}P^1)$ and the concentration of measure phenomenon on that.
|
One might be interested in the random sampling over the $\operatorname{Sym}_n(\mathbb{C}P^1)$ and the concentration of measure phenomenon on that.
|
||||||
|
|
||||||
\section{Majorana stellar representation of the quantum state}
|
\section{Majorana stellar representation of the quantum state}
|
||||||
|
|
||||||
\begin{defn}
|
\begin{defn}
|
||||||
Let $n$ be a positive integer. The Majorana stellar representation of the quantum state is the set of all roots of a polynomial of degree $n$ in $\mathbb{C}$.
|
Let $n$ be a positive integer. The Majorana stellar representation of the quantum state is the set of all roots of a polynomial of degree $n$ in $\mathbb{C}$.
|
||||||
|
|
||||||
|
|
||||||
\end{defn}
|
\end{defn}
|
||||||
\section{Space of complex valued functions and pure states}
|
\section{Space of complex valued functions and pure states}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
\ifSubfilesClassLoaded{
|
\ifSubfilesClassLoaded{
|
||||||
\printbibliography[title={References for Chapter 2}]
|
\printbibliography[title={References for Chapter 2}]
|
||||||
}
|
}
|
||||||
|
|
||||||
\end{document}
|
\end{document}
|
||||||
|
|||||||
224
latex/main.tex
@@ -1,112 +1,112 @@
|
|||||||
% main.tex
|
% main.tex
|
||||||
\documentclass[11pt]{book}
|
\documentclass[11pt]{book}
|
||||||
|
|
||||||
% --- Math + structure ---
|
% --- Math + structure ---
|
||||||
\usepackage{amsmath,amssymb,amsthm}
|
\usepackage{amsmath,amssymb,amsthm}
|
||||||
\usepackage{hyperref}
|
\usepackage{hyperref}
|
||||||
\usepackage{subfiles} % allows chapters to compile independently
|
\usepackage{subfiles} % allows chapters to compile independently
|
||||||
|
|
||||||
% --- Formatting ---
|
% --- Formatting ---
|
||||||
\usepackage{fancyhdr,parskip}
|
\usepackage{fancyhdr,parskip}
|
||||||
\usepackage{fullpage}
|
\usepackage{fullpage}
|
||||||
|
|
||||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
% add special notation supports
|
% add special notation supports
|
||||||
\usepackage[mathscr]{euscript}
|
\usepackage[mathscr]{euscript}
|
||||||
\usepackage{mathtools}
|
\usepackage{mathtools}
|
||||||
\usepackage{braket}
|
\usepackage{braket}
|
||||||
|
|
||||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
% add image package and directory
|
% add image package and directory
|
||||||
\usepackage{graphicx}
|
\usepackage{graphicx}
|
||||||
\usepackage{tikz}
|
\usepackage{tikz}
|
||||||
\graphicspath{{./images/}}
|
\graphicspath{{./images/}}
|
||||||
% dependency graph
|
% dependency graph
|
||||||
\usetikzlibrary{trees,positioning,arrows.meta,backgrounds}
|
\usetikzlibrary{trees,positioning,arrows.meta,backgrounds}
|
||||||
% floating graph
|
% floating graph
|
||||||
\usepackage{float}
|
\usepackage{float}
|
||||||
|
|
||||||
% --- Bibliography: biblatex + biber ---
|
% --- Bibliography: biblatex + biber ---
|
||||||
\usepackage[
|
\usepackage[
|
||||||
backend=biber,
|
backend=biber,
|
||||||
style=alphabetic,
|
style=alphabetic,
|
||||||
sorting=nyt,
|
sorting=nyt,
|
||||||
giveninits=true
|
giveninits=true
|
||||||
]{biblatex}
|
]{biblatex}
|
||||||
|
|
||||||
% --- Beamer-like blocks (printer-friendly) ---
|
% --- Beamer-like blocks (printer-friendly) ---
|
||||||
\usepackage[most]{tcolorbox}
|
\usepackage[most]{tcolorbox}
|
||||||
\usepackage{xcolor}
|
\usepackage{xcolor}
|
||||||
|
|
||||||
% A dedicated "Examples" block (optional convenience wrapper)
|
% A dedicated "Examples" block (optional convenience wrapper)
|
||||||
\newtcolorbox{examples}[1][Example]{%
|
\newtcolorbox{examples}[1][Example]{%
|
||||||
enhanced,
|
enhanced,
|
||||||
breakable,
|
breakable,
|
||||||
colback=white,
|
colback=white,
|
||||||
colframe=black!90,
|
colframe=black!90,
|
||||||
coltitle=white, % title text color
|
coltitle=white, % title text color
|
||||||
colbacktitle=black!90, % <<< grey 80 title bar
|
colbacktitle=black!90, % <<< grey 80 title bar
|
||||||
boxrule=0.6pt,
|
boxrule=0.6pt,
|
||||||
arc=1.5mm,
|
arc=1.5mm,
|
||||||
left=1.2mm,right=1.2mm,top=1.0mm,bottom=1.0mm,
|
left=1.2mm,right=1.2mm,top=1.0mm,bottom=1.0mm,
|
||||||
fonttitle=\bfseries,
|
fonttitle=\bfseries,
|
||||||
title=#1
|
title=#1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
% In the assembled book, we load *all* chapter bib files here,
|
% In the assembled book, we load *all* chapter bib files here,
|
||||||
% and print one combined bibliography at the end.
|
% and print one combined bibliography at the end.
|
||||||
|
|
||||||
\addbibresource{main.bib}
|
\addbibresource{main.bib}
|
||||||
|
|
||||||
%%
|
%%
|
||||||
% Some convenient commands if you need to use integrals
|
% Some convenient commands if you need to use integrals
|
||||||
\newcommand{\is}{\hspace{2pt}}
|
\newcommand{\is}{\hspace{2pt}}
|
||||||
\newcommand{\dx}{\is dx}
|
\newcommand{\dx}{\is dx}
|
||||||
|
|
||||||
|
|
||||||
%%%%%%%%%%%%%%%%%%%%%%
|
%%%%%%%%%%%%%%%%%%%%%%
|
||||||
% These are commands you can use that will generate nice things in TeX. Feel free to define your own, too.
|
% These are commands you can use that will generate nice things in TeX. Feel free to define your own, too.
|
||||||
\newcommand{\Z}{\mathbb{Z}} % integers
|
\newcommand{\Z}{\mathbb{Z}} % integers
|
||||||
\newcommand{\Q}{\mathbb{Q}} % rationals
|
\newcommand{\Q}{\mathbb{Q}} % rationals
|
||||||
\newcommand{\R}{\mathbb{R}} % reals
|
\newcommand{\R}{\mathbb{R}} % reals
|
||||||
\newcommand{\C}{\mathbb{C}} % complex numbers
|
\newcommand{\C}{\mathbb{C}} % complex numbers
|
||||||
\newcommand{\ds}{\displaystyle} % invoke "display style", which makes fractions come out big, etc.
|
\newcommand{\ds}{\displaystyle} % invoke "display style", which makes fractions come out big, etc.
|
||||||
\newcommand{\charac}{\operatorname{char}} % characteristic of a field
|
\newcommand{\charac}{\operatorname{char}} % characteristic of a field
|
||||||
\newcommand{\st}{\ensuremath{\,:\,}} % Makes the colon in set-builder notation space properly
|
\newcommand{\st}{\ensuremath{\,:\,}} % Makes the colon in set-builder notation space properly
|
||||||
|
|
||||||
%%%%%%%%%%%%%%%%%%%%%%
|
%%%%%%%%%%%%%%%%%%%%%%
|
||||||
% These commands are for convenient notation for the concentration of measure theorem
|
% These commands are for convenient notation for the concentration of measure theorem
|
||||||
\newcommand{\obdiam}{\operatorname{ObserDiam}}
|
\newcommand{\obdiam}{\operatorname{ObserDiam}}
|
||||||
\newcommand{\diam}{\operatorname{diam}}
|
\newcommand{\diam}{\operatorname{diam}}
|
||||||
|
|
||||||
|
|
||||||
%%%%%%%%%%%%%%%%%%%%%%
|
%%%%%%%%%%%%%%%%%%%%%%
|
||||||
% These commands create theorem-like environments.
|
% These commands create theorem-like environments.
|
||||||
\newtheorem{theorem}{Theorem}
|
\newtheorem{theorem}{Theorem}
|
||||||
\newtheorem{lemma}[theorem]{Lemma}
|
\newtheorem{lemma}[theorem]{Lemma}
|
||||||
\newtheorem{prop}[theorem]{Proposition}
|
\newtheorem{prop}[theorem]{Proposition}
|
||||||
\newtheorem{defn}[theorem]{Definition}
|
\newtheorem{defn}[theorem]{Definition}
|
||||||
|
|
||||||
\title{Concentration of Measure And Quantum Entanglement}
|
\title{Concentration of Measure And Quantum Entanglement}
|
||||||
\author{Zheyuan Wu}
|
\author{Zheyuan Wu}
|
||||||
\date{\today}
|
\date{\today}
|
||||||
|
|
||||||
\begin{document}
|
\begin{document}
|
||||||
\frontmatter
|
\frontmatter
|
||||||
\maketitle
|
\maketitle
|
||||||
\tableofcontents
|
\tableofcontents
|
||||||
\mainmatter
|
\mainmatter
|
||||||
|
|
||||||
% Each chapter is in its own file and included as a subfile.
|
% Each chapter is in its own file and included as a subfile.
|
||||||
% \subfile{preface}
|
% \subfile{preface}
|
||||||
\subfile{chapters/chap0}
|
\subfile{chapters/chap0}
|
||||||
\subfile{chapters/chap1}
|
\subfile{chapters/chap1}
|
||||||
\subfile{chapters/chap2}
|
\subfile{chapters/chap2}
|
||||||
% \subfile{chapters/chap3}
|
% \subfile{chapters/chap3}
|
||||||
|
|
||||||
\backmatter
|
\backmatter
|
||||||
\cleardoublepage
|
\cleardoublepage
|
||||||
\printbibliography[title={References}]
|
\printbibliography[title={References}]
|
||||||
|
|
||||||
\end{document}
|
\end{document}
|
||||||
|
|||||||
@@ -1,86 +1,86 @@
|
|||||||
% preface.tex
|
% preface.tex
|
||||||
\documentclass[main.tex]{subfiles}
|
\documentclass[main.tex]{subfiles}
|
||||||
|
|
||||||
\ifSubfilesClassLoaded{
|
\ifSubfilesClassLoaded{
|
||||||
\addbibresource{main.bib}
|
\addbibresource{main.bib}
|
||||||
}
|
}
|
||||||
|
|
||||||
\begin{document}
|
\begin{document}
|
||||||
|
|
||||||
\chapter*{Preface}
|
\chapter*{Preface}
|
||||||
\addcontentsline{toc}{chapter}{Preface}
|
\addcontentsline{toc}{chapter}{Preface}
|
||||||
|
|
||||||
Non-commutative probability theory is a branch of generalized probability theory that studies the probability of events in non-commutative algebras (e.g. the algebra of observables in quantum mechanics). In the 20th century, non-commutative probability theory has been applied to the study of quantum mechanics as the classical probability theory is not enough to describe quantum mechanics~\cite{kummer1998elements}.
|
Non-commutative probability theory is a branch of generalized probability theory that studies the probability of events in non-commutative algebras (e.g. the algebra of observables in quantum mechanics). In the 20th century, non-commutative probability theory has been applied to the study of quantum mechanics as the classical probability theory is not enough to describe quantum mechanics~\cite{kummer1998elements}.
|
||||||
|
|
||||||
Recently, the concentration of measure phenomenon has been applied to the study of non-commutative probability theory. Basically, the non-trivial observation, citing from Gromov's work~\cite{MGomolovs}, states that an arbitrary 1-Lipschitz function $f:S^n\to \mathbb{R}$ concentrates near a single value $a_0\in \mathbb{R}$ as strongly as the distance function does. That is,
|
Recently, the concentration of measure phenomenon has been applied to the study of non-commutative probability theory. Basically, the non-trivial observation, citing from Gromov's work~\cite{MGomolovs}, states that an arbitrary 1-Lipschitz function $f:S^n\to \mathbb{R}$ concentrates near a single value $a_0\in \mathbb{R}$ as strongly as the distance function does. That is,
|
||||||
|
|
||||||
$$
|
$$
|
||||||
\mu\{x\in S^n: |f(x)-a_0|\geq\epsilon\} < \kappa_n(\epsilon)\leq 2\exp\left(-\frac{(n-1)\epsilon^2}{2}\right)
|
\mu\{x\in S^n: |f(x)-a_0|\geq\epsilon\} < \kappa_n(\epsilon)\leq 2\exp\left(-\frac{(n-1)\epsilon^2}{2}\right)
|
||||||
$$
|
$$
|
||||||
|
|
||||||
is applied to computing the probability that, given a bipartite system $A\otimes B$, assume $\dim(B)\geq \dim(A)\geq 3$, as the dimension of the smaller system $A$ increases, with very high probability, a random pure state $\sigma=|\psi\rangle\langle\psi|$ selected from $A\otimes B$ is almost as good as the maximally entangled state.
|
is applied to computing the probability that, given a bipartite system $A\otimes B$, assume $\dim(B)\geq \dim(A)\geq 3$, as the dimension of the smaller system $A$ increases, with very high probability, a random pure state $\sigma=|\psi\rangle\langle\psi|$ selected from $A\otimes B$ is almost as good as the maximally entangled state.
|
||||||
|
|
||||||
Mathematically, that is:
|
Mathematically, that is:
|
||||||
|
|
||||||
Let $\psi\in \mathcal{P}(A\otimes B)$ be a random pure state on $A\otimes B$.
|
Let $\psi\in \mathcal{P}(A\otimes B)$ be a random pure state on $A\otimes B$.
|
||||||
|
|
||||||
If we define $\beta=\frac{1}{\ln(2)}\frac{d_A}{d_B}$, then we have
|
If we define $\beta=\frac{1}{\ln(2)}\frac{d_A}{d_B}$, then we have
|
||||||
|
|
||||||
$$
|
$$
|
||||||
\operatorname{Pr}[H(\psi_A) < \log_2(d_A)-\alpha-\beta] \leq \exp\left(-\frac{1}{8\pi^2\ln(2)}\frac{(d_Ad_B-1)\alpha^2}{(\log_2(d_A))^2}\right)
|
\operatorname{Pr}[H(\psi_A) < \log_2(d_A)-\alpha-\beta] \leq \exp\left(-\frac{1}{8\pi^2\ln(2)}\frac{(d_Ad_B-1)\alpha^2}{(\log_2(d_A))^2}\right)
|
||||||
$$
|
$$
|
||||||
|
|
||||||
where $d_B\geq d_A\geq 3$~\cite{Hayden_2006}.
|
where $d_B\geq d_A\geq 3$~\cite{Hayden_2006}.
|
||||||
|
|
||||||
In this report, we will show the process of my exploration of the concentration of measure phenomenon in the context of non-commutative probability theory. We assume the reader is an undergraduate student in mathematics and is familiar with the basic concepts of probability theory, measure theory, linear algebra, and some basic skills of mathematical analysis. To make the report more self-contained, we will add detailed annotated proofs that I understand and references for the original sources.
|
In this report, we will show the process of my exploration of the concentration of measure phenomenon in the context of non-commutative probability theory. We assume the reader is an undergraduate student in mathematics and is familiar with the basic concepts of probability theory, measure theory, linear algebra, and some basic skills of mathematical analysis. To make the report more self-contained, we will add detailed annotated proofs that I understand and references for the original sources.
|
||||||
|
|
||||||
\section*{How to use the dependency graph}
|
\section*{How to use the dependency graph}
|
||||||
|
|
||||||
Since our topic integrates almost everything I've learned during undergraduate study, I will try to make some dependency graph for reader and for me to keep track of what are the necessary knowledge to understand part of the report.
|
Since our topic integrates almost everything I've learned during undergraduate study, I will try to make some dependency graph for reader and for me to keep track of what are the necessary knowledge to understand part of the report.
|
||||||
|
|
||||||
One can imagine the project as a big tree, where the root is in undergrad math and branches out to the topics of the report, including many advanced topics and motivation to study them.
|
One can imagine the project as a big tree, where the root is in undergrad math and branches out to the topics of the report, including many advanced topics and motivation to study them.
|
||||||
|
|
||||||
\bigskip
|
\bigskip
|
||||||
|
|
||||||
% --- Dependency tree graph (TikZ) ---
|
% --- Dependency tree graph (TikZ) ---
|
||||||
\begin{figure}[ht]
|
\begin{figure}[ht]
|
||||||
\centering
|
\centering
|
||||||
\begin{tikzpicture}[
|
\begin{tikzpicture}[
|
||||||
node distance=10mm and 18mm,
|
node distance=10mm and 18mm,
|
||||||
box/.style={draw, rectangle, fill=white, align=center, inner sep=4pt},
|
box/.style={draw, rectangle, fill=white, align=center, inner sep=4pt},
|
||||||
arrow/.style={-Latex}
|
arrow/.style={-Latex}
|
||||||
]
|
]
|
||||||
|
|
||||||
% \node[box] (lin) {Linear Algebra\\(bases, maps, eigenvalues)};
|
% \node[box] (lin) {Linear Algebra\\(bases, maps, eigenvalues)};
|
||||||
% \node[box, right=of lin] (real) {Real Analysis\\(limits, continuity, measure-lite)};
|
% \node[box, right=of lin] (real) {Real Analysis\\(limits, continuity, measure-lite)};
|
||||||
% \node[box, below=of lin] (prob) {Probability\\(expectation, variance, concentration)};
|
% \node[box, below=of lin] (prob) {Probability\\(expectation, variance, concentration)};
|
||||||
% \node[box, below=of real] (top) {Topology/Geometry\\(metrics, compactness)};
|
% \node[box, below=of real] (top) {Topology/Geometry\\(metrics, compactness)};
|
||||||
|
|
||||||
% \node[box, below=12mm of prob] (func) {Functional Analysis\\($L^p$, Hilbert spaces, operators)};
|
% \node[box, below=12mm of prob] (func) {Functional Analysis\\($L^p$, Hilbert spaces, operators)};
|
||||||
% \node[box, below=12mm of top] (quant) {Quantum Formalism\\(states, observables, partial trace)};
|
% \node[box, below=12mm of top] (quant) {Quantum Formalism\\(states, observables, partial trace)};
|
||||||
|
|
||||||
% \node[box, below=14mm of func, xshift=25mm] (book) {This Book\\(Chapters 1--n)};
|
% \node[box, below=14mm of func, xshift=25mm] (book) {This Book\\(Chapters 1--n)};
|
||||||
% % draw arrows behind nodes
|
% % draw arrows behind nodes
|
||||||
% \begin{scope}[on background layer]
|
% \begin{scope}[on background layer]
|
||||||
% \draw[arrow] (lin) -- (func);
|
% \draw[arrow] (lin) -- (func);
|
||||||
% \draw[arrow] (real) -- (func);
|
% \draw[arrow] (real) -- (func);
|
||||||
% \draw[arrow] (prob) -- (func);
|
% \draw[arrow] (prob) -- (func);
|
||||||
% \draw[arrow] (func) -- (quant);
|
% \draw[arrow] (func) -- (quant);
|
||||||
% \draw[arrow] (lin) -- (quant);
|
% \draw[arrow] (lin) -- (quant);
|
||||||
% \draw[arrow] (top) -- (quant);
|
% \draw[arrow] (top) -- (quant);
|
||||||
|
|
||||||
% \draw[arrow] (func) -- (book);
|
% \draw[arrow] (func) -- (book);
|
||||||
% \draw[arrow] (quant) -- (book);
|
% \draw[arrow] (quant) -- (book);
|
||||||
% \draw[arrow] (prob) -- (book);
|
% \draw[arrow] (prob) -- (book);
|
||||||
% \end{scope}
|
% \end{scope}
|
||||||
|
|
||||||
\end{tikzpicture}
|
\end{tikzpicture}
|
||||||
\caption{Dependency tree: prerequisites and how they feed into the main text.}
|
\caption{Dependency tree: prerequisites and how they feed into the main text.}
|
||||||
\label{fig:dependency-tree}
|
\label{fig:dependency-tree}
|
||||||
\end{figure}
|
\end{figure}
|
||||||
|
|
||||||
\ifSubfilesClassLoaded{
|
\ifSubfilesClassLoaded{
|
||||||
\printbibliography[title={References}]
|
\printbibliography[title={References}]
|
||||||
}
|
}
|
||||||
|
|
||||||
\end{document}
|
\end{document}
|
||||||
|
|||||||
BIN
results/exp-20260311-154003/hist_cp_128x128.png
Normal file
|
After Width: | Height: | Size: 65 KiB |
BIN
results/exp-20260311-154003/hist_cp_16x16.png
Normal file
|
After Width: | Height: | Size: 57 KiB |
BIN
results/exp-20260311-154003/hist_cp_256x256.png
Normal file
|
After Width: | Height: | Size: 68 KiB |
BIN
results/exp-20260311-154003/hist_cp_32x32.png
Normal file
|
After Width: | Height: | Size: 64 KiB |
BIN
results/exp-20260311-154003/hist_cp_64x64.png
Normal file
|
After Width: | Height: | Size: 63 KiB |
BIN
results/exp-20260311-154003/hist_sphere_1024.png
Normal file
|
After Width: | Height: | Size: 46 KiB |
BIN
results/exp-20260311-154003/hist_sphere_128.png
Normal file
|
After Width: | Height: | Size: 51 KiB |
BIN
results/exp-20260311-154003/hist_sphere_16.png
Normal file
|
After Width: | Height: | Size: 51 KiB |
BIN
results/exp-20260311-154003/hist_sphere_2048.png
Normal file
|
After Width: | Height: | Size: 50 KiB |
BIN
results/exp-20260311-154003/hist_sphere_256.png
Normal file
|
After Width: | Height: | Size: 46 KiB |
BIN
results/exp-20260311-154003/hist_sphere_32.png
Normal file
|
After Width: | Height: | Size: 55 KiB |
BIN
results/exp-20260311-154003/hist_sphere_512.png
Normal file
|
After Width: | Height: | Size: 47 KiB |
BIN
results/exp-20260311-154003/hist_sphere_64.png
Normal file
|
After Width: | Height: | Size: 47 KiB |
BIN
results/exp-20260311-154003/tail_cp_128x128.png
Normal file
|
After Width: | Height: | Size: 56 KiB |
BIN
results/exp-20260311-154003/tail_cp_16x16.png
Normal file
|
After Width: | Height: | Size: 57 KiB |
BIN
results/exp-20260311-154003/tail_cp_256x256.png
Normal file
|
After Width: | Height: | Size: 55 KiB |
BIN
results/exp-20260311-154003/tail_cp_32x32.png
Normal file
|
After Width: | Height: | Size: 56 KiB |
BIN
results/exp-20260311-154003/tail_cp_64x64.png
Normal file
|
After Width: | Height: | Size: 56 KiB |
BIN
results/exp-20260311-154003/tail_sphere_1024.png
Normal file
|
After Width: | Height: | Size: 54 KiB |
BIN
results/exp-20260311-154003/tail_sphere_128.png
Normal file
|
After Width: | Height: | Size: 52 KiB |
BIN
results/exp-20260311-154003/tail_sphere_16.png
Normal file
|
After Width: | Height: | Size: 52 KiB |
BIN
results/exp-20260311-154003/tail_sphere_2048.png
Normal file
|
After Width: | Height: | Size: 53 KiB |
BIN
results/exp-20260311-154003/tail_sphere_256.png
Normal file
|
After Width: | Height: | Size: 55 KiB |
BIN
results/exp-20260311-154003/tail_sphere_32.png
Normal file
|
After Width: | Height: | Size: 52 KiB |
BIN
results/exp-20260311-154003/tail_sphere_512.png
Normal file
|
After Width: | Height: | Size: 53 KiB |
BIN
results/exp-20260311-154003/tail_sphere_64.png
Normal file
|
After Width: | Height: | Size: 55 KiB |