Survey: All h11=2 Calabi-Yau threefolds#

This notebook runs the full EKC construction on all 36 polytopes in the CYTools database with \(h^{1,1} = 2\), collecting statistics on phases, contraction types, Coxeter groups, and cone generators.

Uses the adaptive GV degree strategy (start at max_deg=4, bump if needed).

import cybir
from cybir import CYBirationalClass, patch_cytools
from cybir.core.types import ContractionType
import cytools
import numpy as np
from collections import Counter
import time

patch_cytools()

Load all h11=2 polytopes#

polys = cytools.fetch_polytopes(h11=2, lattice="N")
print(f"Loaded {len(polys)} polytopes with h11=2")
Loaded 36 polytopes with h11=2

Run EKC construction on all polytopes#

For each polytope, construct the birational class (fundamental domain), then apply the Coxeter orbit expansion.

results = []

for i, p in enumerate(polys):
    cy = p.triangulate().get_cy()
    
    t0 = time.perf_counter()
    ekc = CYBirationalClass.from_gv(cy, max_deg=4, verbose=False)
    n_fund = len(ekc.phases)
    
    ekc.apply_coxeter_orbit()
    n_total = len(ekc.phases)
    elapsed = time.perf_counter() - t0
    
    # Collect contraction type counts
    type_counts = Counter(
        c.contraction_type.display_name() for c in ekc.contractions
    )
    
    results.append({
        "idx": i,
        "ekc": ekc,
        "n_fund": n_fund,
        "n_total": n_total,
        "n_contractions": len(ekc.contractions),
        "type_counts": type_counts,
        "n_sym_flops": len(ekc._sym_flop_pairs),
        "coxeter_type": ekc.coxeter_type,
        "coxeter_order": ekc.coxeter_order,
        "n_inf_gens": len(ekc.infinity_cone_gens),
        "n_eff_gens": len(ekc.eff_cone_gens),
        "time": elapsed,
    })
    
    print(f"  #{i}: {elapsed:.2f}s  fund={n_fund} total={n_total}  "
          f"sym_flops={len(ekc._sym_flop_pairs)}  "
          f"coxeter={ekc.coxeter_type}")
  #0: 1.41s  fund=1 total=1  sym_flops=0  coxeter=None
  #1: 0.39s  fund=1 total=1  sym_flops=0  coxeter=None
  #2: 0.22s  fund=1 total=2  sym_flops=1  coxeter=[('A', 1, 2)]
  #3: 0.30s  fund=1 total=2  sym_flops=1  coxeter=[('A', 1, 2)]
  #4: 0.30s  fund=1 total=1  sym_flops=0  coxeter=None
  #5: 0.72s  fund=2 total=2  sym_flops=0  coxeter=None
  #6: 0.25s  fund=1 total=2  sym_flops=1  coxeter=[('A', 1, 2)]
  #7: 0.30s  fund=1 total=2  sym_flops=1  coxeter=[('A', 1, 2)]
  #8: 0.26s  fund=1 total=2  sym_flops=1  coxeter=[('A', 1, 2)]
  #9: 0.29s  fund=1 total=1  sym_flops=0  coxeter=None
  #10: 0.29s  fund=2 total=2  sym_flops=0  coxeter=None
  #11: 0.29s  fund=2 total=2  sym_flops=0  coxeter=None
  #12: 0.60s  fund=2 total=2  sym_flops=0  coxeter=None
  #13: 0.29s  fund=2 total=2  sym_flops=0  coxeter=None
  #14: 0.25s  fund=1 total=2  sym_flops=1  coxeter=[('A', 1, 2)]
  #15: 0.35s  fund=1 total=2  sym_flops=1  coxeter=[('A', 1, 2)]
  #16: 0.43s  fund=1 total=1  sym_flops=0  coxeter=None
  #17: 0.34s  fund=1 total=1  sym_flops=0  coxeter=None
  #18: 0.27s  fund=1 total=2  sym_flops=1  coxeter=[('A', 1, 2)]
  #19: 0.32s  fund=1 total=2  sym_flops=1  coxeter=[('A', 1, 2)]
  #20: 0.27s  fund=1 total=2  sym_flops=1  coxeter=[('A', 1, 2)]
  #21: 0.25s  fund=1 total=2  sym_flops=1  coxeter=[('A', 1, 2)]
  #22: 0.33s  fund=1 total=1  sym_flops=0  coxeter=None
  #23: 0.31s  fund=1 total=1  sym_flops=0  coxeter=None
  #24: 0.33s  fund=1 total=2  sym_flops=1  coxeter=[('A', 1, 2)]
  #25: 0.24s  fund=1 total=2  sym_flops=1  coxeter=[('A', 1, 2)]
  #26: 0.28s  fund=1 total=2  sym_flops=1  coxeter=[('A', 1, 2)]
  #27: 0.33s  fund=1 total=2  sym_flops=1  coxeter=[('A', 1, 2)]
  #28: 0.26s  fund=1 total=2  sym_flops=1  coxeter=[('A', 1, 2)]
  #29: 0.28s  fund=1 total=1  sym_flops=0  coxeter=None
  #30: 0.46s  fund=2 total=2  sym_flops=0  coxeter=None
  #31: 0.31s  fund=1 total=1  sym_flops=0  coxeter=None
  #32: 0.29s  fund=1 total=1  sym_flops=0  coxeter=None
  #33: 0.27s  fund=1 total=1  sym_flops=0  coxeter=None
  #34: 0.28s  fund=1 total=1  sym_flops=0  coxeter=None
  #35: 0.28s  fund=1 total=1  sym_flops=0  coxeter=None

Summary statistics#

n = len(results)
print(f"Polytopes: {n}")
print(f"Total time: {sum(r['time'] for r in results):.1f}s")
print(f"Avg time: {sum(r['time'] for r in results)/n:.2f}s")
print()

# Phase counts
fund_phases = [r["n_fund"] for r in results]
total_phases = [r["n_total"] for r in results]
print(f"Fundamental domain phases: min={min(fund_phases)} max={max(fund_phases)} "
      f"avg={sum(fund_phases)/n:.1f}")
print(f"Total phases (after orbit): min={min(total_phases)} max={max(total_phases)} "
      f"avg={sum(total_phases)/n:.1f}")
print()

# Coxeter groups
with_orbit = [r for r in results if r["coxeter_order"] and r["coxeter_order"] > 1]
print(f"Polytopes with nontrivial Coxeter group: {len(with_orbit)}/{n}")
if with_orbit:
    type_dist = Counter(str(r["coxeter_type"]) for r in with_orbit)
    for t, c in type_dist.most_common():
        print(f"  {t}: {c} polytopes")
Polytopes: 36
Total time: 12.6s
Avg time: 0.35s

Fundamental domain phases: min=1 max=2 avg=1.2
Total phases (after orbit): min=1 max=2 avg=1.6

Polytopes with nontrivial Coxeter group: 16/36
  [('A', 1, 2)]: 16 polytopes

Contraction type distribution#

# Aggregate contraction types across all polytopes
total_types = Counter()
for r in results:
    total_types.update(r["type_counts"])

print("Contraction types across all polytopes:")
for name, count in total_types.most_common():
    print(f"  {name}: {count}")
Contraction types across all polytopes:
  CFT: 34
  asymptotic: 32
  symmetric flop: 32
  generic flop: 12
  su(2) enhancement: 6

Per-polytope detail table#

print(f"{'#':>3}  {'Fund':>4}  {'Total':>5}  {'Contr':>5}  {'SymFlop':>7}  "
      f"{'InfGen':>6}  {'EffGen':>6}  {'Coxeter':>12}  {'Time':>5}")
print("-" * 72)
for r in results:
    cox_str = str(r['coxeter_type']) if r['coxeter_type'] else "-"
    print(f"{r['idx']:3d}  {r['n_fund']:4d}  {r['n_total']:5d}  "
          f"{r['n_contractions']:5d}  {r['n_sym_flops']:7d}  "
          f"{r['n_inf_gens']:6d}  {r['n_eff_gens']:6d}  "
          f"{cox_str:>12}  {r['time']:5.2f}s")
  #  Fund  Total  Contr  SymFlop  InfGen  EffGen       Coxeter   Time
------------------------------------------------------------------------
  0     1      1      2        0       2       2             -   1.41s
  1     1      1      2        0       2       3             -   0.39s
  2     1      2      4        1       2       5  [('A', 1, 2)]   0.22s
  3     1      2      4        1       2       5  [('A', 1, 2)]   0.30s
  4     1      1      2        0       2       2             -   0.30s
  5     2      2      4        0       2       5             -   0.72s
  6     1      2      4        1       2       3  [('A', 1, 2)]   0.25s
  7     1      2      4        1       2       3  [('A', 1, 2)]   0.30s
  8     1      2      4        1       2       3  [('A', 1, 2)]   0.26s
  9     1      1      2        0       1       3             -   0.29s
 10     2      2      4        0       2       3             -   0.29s
 11     2      2      4        0       1       4             -   0.29s
 12     2      2      4        0       2       4             -   0.60s
 13     2      2      4        0       1       4             -   0.29s
 14     1      2      4        1       2       5  [('A', 1, 2)]   0.25s
 15     1      2      4        1       2       5  [('A', 1, 2)]   0.35s
 16     1      1      2        0       2       3             -   0.43s
 17     1      1      2        0       1       3             -   0.34s
 18     1      2      4        1       2       5  [('A', 1, 2)]   0.27s
 19     1      2      4        1       2       5  [('A', 1, 2)]   0.32s
 20     1      2      4        1       2       5  [('A', 1, 2)]   0.27s
 21     1      2      4        1       2       5  [('A', 1, 2)]   0.25s
 22     1      1      2        0       2       3             -   0.33s
 23     1      1      2        0       1       4             -   0.31s
 24     1      2      4        1       2       5  [('A', 1, 2)]   0.33s
 25     1      2      4        1       2       5  [('A', 1, 2)]   0.24s
 26     1      2      4        1       2       5  [('A', 1, 2)]   0.28s
 27     1      2      4        1       2       3  [('A', 1, 2)]   0.33s
 28     1      2      4        1       2       3  [('A', 1, 2)]   0.26s
 29     1      1      2        0       2       2             -   0.28s
 30     2      2      4        0       2       4             -   0.46s
 31     1      1      2        0       1       3             -   0.31s
 32     1      1      2        0       2       3             -   0.29s
 33     1      1      2        0       2       3             -   0.27s
 34     1      1      2        0       2       3             -   0.28s
 35     1      1      2        0       2       3             -   0.28s

Inspect a polytope with nontrivial Coxeter group#

Pick the first polytope that has symmetric flops and show its full structure.

# Find first polytope with symmetric flops
sym_example = next((r for r in results if r["n_sym_flops"] > 0), None)

if sym_example:
    ekc = sym_example["ekc"]
    print(f"Polytope #{sym_example['idx']}")
    print(f"Coxeter type: {ekc.coxeter_type}")
    print(f"Coxeter group order: {ekc.coxeter_order}")
    print(f"Fundamental phases: {sym_example['n_fund']}")
    print(f"Total phases: {sym_example['n_total']}")
    print()
    
    print("Phases:")
    for phase in ekc.phases:
        print(f"  {phase.label}: int_nums shape = {phase.int_nums.shape}")
    
    print()
    print("Contractions:")
    for c in ekc.contractions:
        print(f"  {c.contraction_type.display_name()}: "
              f"curve = {c.contraction_curve}")
    
    print()
    print(f"Infinity cone generators: {ekc.infinity_cone_gens}")
    print(f"Effective cone generators: {ekc.eff_cone_gens}")
    
    if ekc.coxeter_matrix is not None:
        print(f"\nCoxeter matrix:\n{ekc.coxeter_matrix}")
else:
    print("No polytopes with symmetric flops found.")
Polytope #2
Coxeter type: [('A', 1, 2)]
Coxeter group order: 2
Fundamental phases: 1
Total phases: 2

Phases:
  CY_0: int_nums shape = (2, 2, 2)
  CY_1: int_nums shape = (2, 2, 2)

Contractions:
  CFT: curve = [ 1 -1]
  symmetric flop: curve = [1 0]
  CFT: curve = [-2 -1]
  symmetric flop: curve = [-1  0]

Infinity cone generators: frozenset({(-1, 1), (-2, -1)})
Effective cone generators: frozenset({(0, 1), (-1, 0), (1, 0), (1, 1), (-1, 2)})

Coxeter matrix:
[[-1  1]
 [ 0  1]]

Inspect the most complex polytope#

The one with the most phases in the fundamental domain.

most_phases = max(results, key=lambda r: r["n_fund"])
ekc = most_phases["ekc"]

print(f"Polytope #{most_phases['idx']}: {most_phases['n_fund']} phases")
print()

# Graph structure
print("Phase graph:")
for phase in ekc.phases:
    neighbors = ekc.graph.neighbors(phase.label)
    print(f"  {phase.label} -> {[n.label for n in neighbors]}")

print()
print("Contraction types:")
type_counts = Counter(c.contraction_type.display_name() for c in ekc.contractions)
for name, count in type_counts.most_common():
    print(f"  {name}: {count}")
Polytope #5: 2 phases

Phase graph:
  CY_0 -> ['CY_1', 'CY_0']
  CY_1 -> ['CY_0', 'CY_1']

Contraction types:
  generic flop: 2
  CFT: 2