EKC Construction: h11=3 Example#

This notebook demonstrates constructing the extended Kahler cone (EKC) of a Calabi-Yau threefold with \(h^{1,1} = 3\). With three Kahler moduli, the birational geometry is richer: multiple flop phases, a more complex graph structure, and potentially non-trivial Coxeter group orbits.

See arXiv:2212.10573 and arXiv:2303.00757 for the theory.

import cybir
from cybir import CYBirationalClass, patch_cytools
import cytools
import numpy as np

# Activate CYTools integration
patch_cytools()

Load a Calabi-Yau threefold#

We fetch an \(h^{1,1} = 3\) polytope from the CYTools database.

# Load an h11=3 polytope from CYTools database
p = cytools.fetch_polytopes(h11=3, limit=1)[0]
cy = p.triangulate().get_cy()
print(f"h11 = {cy.h11()}, h21 = {cy.h21()}")
h11 = 3, h21 = 43

Construct the Extended Kahler Cone#

With \(h^{1,1} = 3\), expect more walls and potentially multiple flop chains.

ekc = CYBirationalClass.from_gv(cy, max_deg=10, verbose=True)
print(ekc)
CYBirationalClass(constructed, phases=1, contractions=3)

Inspect Phases#

With higher \(h^{1,1}\), the intersection number tensor is \(3 \times 3 \times 3\) and there are more Mori/Kahler cone generators.

for phase in ekc.phases:
    mori_gens = len(phase.mori_cone.extremal_rays()) if phase.mori_cone else 0
    kahler_gens = len(phase.kahler_cone.rays()) if phase.kahler_cone else 0
    print(f"{phase.label}: int_nums shape = {phase.int_nums.shape}, "
          f"mori gens = {mori_gens}, kahler gens = {kahler_gens}")
print(f"\nTotal phases: {len(ekc.phases)}")
CY_0: int_nums shape = (3, 3, 3), mori gens = 3, kahler gens = 3

Total phases: 1

Build Log#

The BFS construction log records each wall diagnosis and phase creation step.

for entry in ekc.build_log:
    print(entry)
{'action': 'classify', 'source': 'CY_0', 'curve': (0, 1, 0), 'type': 'symmetric_flop'}
{'action': 'classify', 'source': 'CY_0', 'curve': (0, 0, 1), 'type': 'asymptotic'}
{'action': 'classify', 'source': 'CY_0', 'curve': (1, 0, -2), 'type': 'symmetric_flop'}

Inspect Contractions#

With more walls, we expect a richer distribution of contraction types.

for c in ekc.contractions:
    print(f"  {c.contraction_type.display_name()}: curve = {c.contraction_curve}")
  symmetric flop: curve = [0 1 0]
  asymptotic: curve = [0 0 1]
  symmetric flop: curve = [ 1  0 -2]

Contraction Type Distribution#

Count how many contractions of each type appear.

from collections import Counter

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}")
  symmetric flop: 2
  asymptotic: 1

Phase Graph Structure#

The graph for \(h^{1,1} = 3\) can have a more intricate topology.

print(ekc.graph)
for phase in ekc.phases:
    neighbors = ekc.graph.neighbors(phase.label)
    print(f"{phase.label} -> {[n.label for n in neighbors]}")
CYGraph(phases=1, contractions=3)
CY_0 -> ['CY_0']

Coxeter Data#

if ekc.coxeter_matrix is not None:
    print("Coxeter matrix:")
    print(ekc.coxeter_matrix)
else:
    print("No Coxeter reflections found")
Coxeter matrix:
[[ 1  0  1]
 [ 2 -1  1]
 [ 0  0 -1]]

Coxeter Orbit Expansion#

For \(h^{1,1} = 3\), the Coxeter group from symmetric-flop reflections can be larger, potentially discovering many additional phases beyond the fundamental domain.

n_before = len(ekc.phases)
ekc.apply_coxeter_orbit()
n_after = len(ekc.phases)
print(f"Before orbit expansion: {n_before} phases")
print(f"After orbit expansion:  {n_after} phases")
print(f"New phases from reflections: {n_after - n_before}")
if ekc.coxeter_type:
    print(f"Coxeter type: {ekc.coxeter_type}")
    print(f"Group order: {ekc.coxeter_order}")
Before orbit expansion: 1 phases
After orbit expansion:  4 phases
New phases from reflections: 3
Coxeter type: [('A', 1, 2), ('A', 1, 2)]
Group order: 4