Refactor and document operators and periods in sage module #21
@@ -84,11 +84,11 @@ Note that for Calabi–Yau dimensions larger than four, the additional
|
|||||||
|
|
||||||
## Operators and periods
|
## Operators and periods
|
||||||
|
|
||||||
`operators.sage` and `period.sage` provide classes for working with Picard–Fuchs operators and their
|
`operators.sage` and `periods.sage` provide classes for working with Picard–Fuchs operators and their
|
||||||
period solutions: `PFOperator`, `PFIdeal` and `Period`, together with Ansatz variants of the first and
|
period solutions: `PFOperator`, `PFIdeal` and `Period`, together with Ansatz variants of the first and
|
||||||
last (`PFOperatorAnsatz`, `PeriodAnsatz`) used to search for unknown operators or periods of a given
|
last (`PFOperatorAnsatz`, `PeriodAnsatz`) used to search for unknown operators or periods of a given
|
||||||
z- and theta-degree. The operator classes live in `operators.sage`, the period classes in `period.sage`;
|
z- and theta-degree. The operator classes live in `operators.sage`, the period classes in `periods.sage`;
|
||||||
since the two depend on each other, load `period.sage`, which also loads `operators.sage`.
|
since the two depend on each other, load `periods.sage`, which also loads `operators.sage`.
|
||||||
|
|
||||||
A `PFOperator` is parsed from a string in the variables `z0, ..., z<n-1>` and `theta0, ..., theta<n-1>`,
|
A `PFOperator` is parsed from a string in the variables `z0, ..., z<n-1>` and `theta0, ..., theta<n-1>`,
|
||||||
the logarithmic derivatives theta_i = z_i d/dz_i. For example, the quintic's Picard–Fuchs operator:
|
the logarithmic derivatives theta_i = z_i d/dz_i. For example, the quintic's Picard–Fuchs operator:
|
||||||
|
|||||||
@@ -1,3 +1,24 @@
|
|||||||
|
"""
|
||||||
|
Picard-Fuchs operators and ideals in the logarithmic derivatives theta_i = z_i * d/dz_i.
|
||||||
|
|
||||||
|
Contents
|
||||||
|
--------
|
||||||
|
PFOperator
|
||||||
|
__init__ Construct from a string in z- and theta-variables
|
||||||
|
simplify Group by z-monomials and factorise theta-polynomials
|
||||||
|
change_coordinates Rewrite the operator in new coordinates
|
||||||
|
_operator_from_string Parse a string into the operator polynomial
|
||||||
|
|
||||||
|
PFOperatorAnsatz(PFOperator)
|
||||||
|
__init__ Ansatz of given theta- and z-multi-degrees
|
||||||
|
|
||||||
|
PFIdeal
|
||||||
|
__init__ Construct from a list of PFOperators
|
||||||
|
add_operator Append a PFOperator
|
||||||
|
remove_operator Remove a PFOperator
|
||||||
|
change_coordinates Rewrite all operators in new coordinates
|
||||||
|
find_power_series_solution Power series solutions at given indicials/order
|
||||||
|
"""
|
||||||
import copy
|
import copy
|
||||||
import logging
|
import logging
|
||||||
from sage.all import sage_eval, PolynomialRing, QQ, SR, function, prod, solve, var
|
from sage.all import sage_eval, PolynomialRing, QQ, SR, function, prod, solve, var
|
||||||
|
|||||||
@@ -1,3 +1,23 @@
|
|||||||
|
"""
|
||||||
|
Periods of Calabi-Yau manifolds as formal power series in z-variables and their logs.
|
||||||
|
|
||||||
|
Contents
|
||||||
|
--------
|
||||||
|
Period
|
||||||
|
__init__ Construct from a string or a coefficients dictionary
|
||||||
|
from_l_vectors (classmethod) Holomorphic period from GLSM/Mori charge vectors
|
||||||
|
apply_operator Apply a PFOperator, truncated to self.order
|
||||||
|
find_annihilating_operators Find PFOperator Ansätze annihilating this period
|
||||||
|
_initialise_ring Polynomial ring in z- and log-variables
|
||||||
|
_period_from_string Parse a string into a coefficients dictionary
|
||||||
|
_period_to_string Render the coefficients as a string
|
||||||
|
_max_z_degree Highest total z-degree among the coefficients
|
||||||
|
_truncate_coefficients Drop terms above a given total z-degree
|
||||||
|
_apply_theta Apply theta_i = z_i * d/dz_i to a coefficients dictionary
|
||||||
|
|
||||||
|
PeriodAnsatz(Period)
|
||||||
|
__init__ Ansatz of given z- and log-multi-degrees
|
||||||
|
"""
|
||||||
import logging
|
import logging
|
||||||
from sage.all import sage_eval, PolynomialRing, QQ, SR, ceil, factorial, floor, log, matrix, prod, var
|
from sage.all import sage_eval, PolynomialRing, QQ, SR, ceil, factorial, floor, log, matrix, prod, var
|
||||||
|
|
||||||
@@ -244,24 +264,8 @@ class Period:
|
|||||||
hypergeometric-type sum
|
hypergeometric-type sum
|
||||||
|
|
||||||
varpi_0(z) = sum_{a in Z_{>=0}^m}
|
varpi_0(z) = sum_{a in Z_{>=0}^m}
|
||||||
(prod_j Gamma(1 - l_num^(j).a)) / (prod_i Gamma(1 + l_den^(i).a)) * z^a,
|
(prod_j Gamma(1 - l_num^(j).a)) / (prod_i Gamma(1 + l_den^(i).a)) * z^a.
|
||||||
|
|
||||||
see e.g. Hosono-Klemm-Theisen-Yau. l_vectors is a list of the m charge vectors, each
|
|
||||||
given as [numerator part, denominator part]: the components landing in the numerator
|
|
||||||
resp. denominator Gamma-functions (for a Calabi-Yau hypersurface/CICY, these are the
|
|
||||||
nef-partition weight(s) resp. the toric divisor charges). For m = 1 the outer list may
|
|
||||||
be dropped, e.g. the quintic is given by [[-5], [1, 1, 1, 1, 1]], while P^4_{1,1,2,2,6}[12]
|
|
||||||
is given by [[[-6], [3, 2, 1, 0, 0, 0]], [[0], [0, 0, -3, 1, 1, 1]]].
|
|
||||||
|
|
||||||
For a Calabi-Yau charge vector the numerator Gamma-functions never hit a pole, since
|
|
||||||
their argument only grows as a grows; only the denominator factors can vanish - at a
|
|
||||||
non-positive-integer argument - which is exactly what truncates each a_k to a finite
|
|
||||||
range once the others are fixed. This makes summing directly over that range far
|
|
||||||
cheaper than solving the full Picard-Fuchs system term by term.
|
|
||||||
"""
|
"""
|
||||||
# A single charge vector [numerator part, denominator part] has integer entries in its parts.
|
|
||||||
if l_vectors and l_vectors[0] and not isinstance(l_vectors[0][0], (list, tuple)):
|
|
||||||
l_vectors = [l_vectors]
|
|
||||||
if any(len(l_vector) != 2 for l_vector in l_vectors):
|
if any(len(l_vector) != 2 for l_vector in l_vectors):
|
||||||
raise ValueError("Each charge vector must be given as [numerator part, denominator part].")
|
raise ValueError("Each charge vector must be given as [numerator part, denominator part].")
|
||||||
m = len(l_vectors)
|
m = len(l_vectors)
|
||||||
@@ -1,3 +1,48 @@
|
|||||||
|
"""
|
||||||
|
Topological data of Calabi-Yau hypersurfaces and CICYs in toric ambient spaces.
|
||||||
|
|
||||||
|
Contents
|
||||||
|
--------
|
||||||
|
Polytope
|
||||||
|
__init__ Construct from a list of defining points
|
||||||
|
_validate_points_and_get_dimension Check the points and return their dimension
|
||||||
|
_points_to_polytope Lattice points of the convex hull, minus codim-1 interiors
|
||||||
|
|
||||||
|
ToricPolytope(Polytope)
|
||||||
|
__init__ Construct with triangulation, nef partition and Mori cone
|
||||||
|
set_triangulation Select a fine star triangulation by index
|
||||||
|
set_nef_partition Set and validate the nef partition
|
||||||
|
set_Mori_cone Set the Mori cone (default or from given l-vectors)
|
||||||
|
disc A-discriminant (singular loci in Batyrev coordinates)
|
||||||
|
topdata Compute topological data and write it to JSON
|
||||||
|
_set_fine_star_triangulations Fine star triangulations of the polytope
|
||||||
|
_collect_linear_dependencies Linear relations among points in all faces
|
||||||
|
_append_origin_weight Add the origin weight to each relation
|
||||||
|
_setup_discriminant_symbols Symbolic variables for the discriminant
|
||||||
|
_build_equation_system Equation system for one block of relations
|
||||||
|
_eliminate_and_normalize Eliminate lambda-variables and normalise
|
||||||
|
_append_unique_discriminants Collect discriminant factors without duplicates
|
||||||
|
_compute_Kahler_generators Kähler cone generators dual to the Mori cone
|
||||||
|
_compute_intersection_ring Intersection ring polynomial of the CY
|
||||||
|
_intersection_substitution_rules Kähler monomial -> intersection number rules
|
||||||
|
_replace_intersection_monomials Substitute intersection numbers into an expression
|
||||||
|
_compute_Chern_character Total Chern class via adjunction
|
||||||
|
_compute_Chern_polynomials Chern polynomials with intersection numbers
|
||||||
|
_check_for_fibrations Detect possible elliptic fibrations
|
||||||
|
_get_polytope_and_glsm_table Table of polytope points and GLSM charges
|
||||||
|
_get_lvec_rows GLSM charge l-vectors as lists of ints
|
||||||
|
_get_output Dictionary of all topological data
|
||||||
|
_to_json_safe (staticmethod) Convert values into JSON-safe primitives
|
||||||
|
_write_output_json Write the output dictionary to JSON
|
||||||
|
|
||||||
|
ToricPolytopeCICY(ToricPolytope)
|
||||||
|
__init__ Construct from a CICY configuration matrix
|
||||||
|
_CICY_to_points Configuration matrix -> points and nef partition
|
||||||
|
|
||||||
|
ToricPolytopeProjectiveSpace(ToricPolytope)
|
||||||
|
__init__ Construct from weighted projective space weights
|
||||||
|
_compute_points_from_weights Weights -> polytope points
|
||||||
|
"""
|
||||||
import numpy as np
|
import numpy as np
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
|
|||||||
@@ -2,94 +2,7 @@ import os
|
|||||||
|
|
||||||
from sage.all import * # noqa: F401
|
from sage.all import * # noqa: F401
|
||||||
|
|
||||||
load(os.path.join(os.path.dirname(__file__), "..", "sage", "period.sage"))
|
load(os.path.join(os.path.dirname(__file__), "..", "sage", "periods.sage"))
|
||||||
|
|
||||||
|
|
||||||
def test_apply_operator_univariate():
|
|
||||||
# theta^2 - z applied to log(z) should give -z*log(z), since theta(log z) = 1
|
|
||||||
# and theta^2(log z) = theta(1) = 0.
|
|
||||||
period = Period(no_variables=1, coefficients={(1,): {(0,): 1}}, order=5)
|
|
||||||
op = PFOperator("theta0^2 - z0", no_variables=1)
|
|
||||||
|
|
||||||
result = period.apply_operator(op)
|
|
||||||
|
|
||||||
assert result.coefficients == {(1,): {(1,): -1}}
|
|
||||||
|
|
||||||
|
|
||||||
def test_apply_operator_mixes_variables():
|
|
||||||
# z0*theta1 applied to z0*log(z1): theta1 strips log(z1) down to a bare 1
|
|
||||||
# (leaving z0 untouched), then multiplying by z0 gives z0^2.
|
|
||||||
period = Period(no_variables=2, coefficients={(0, 1): {(1, 0): 1}}, order=5)
|
|
||||||
op = PFOperator("z0*theta1", no_variables=2)
|
|
||||||
|
|
||||||
result = period.apply_operator(op)
|
|
||||||
|
|
||||||
assert result.coefficients == {(0, 0): {(2, 0): 1}}
|
|
||||||
|
|
||||||
|
|
||||||
def test_apply_operator_truncates_to_order():
|
|
||||||
# Multiplying by z0^2 pushes some terms above the period's order, so they
|
|
||||||
# should be dropped rather than kept with a nonzero coefficient.
|
|
||||||
period = Period(no_variables=1, coefficients={(0,): {(0,): 1, (1,): 1, (2,): 1}}, order=2)
|
|
||||||
op = PFOperator("z0^2", no_variables=1)
|
|
||||||
|
|
||||||
result = period.apply_operator(op)
|
|
||||||
|
|
||||||
assert result.coefficients == {(0,): {(2,): 1}}
|
|
||||||
assert result.order == 2
|
|
||||||
|
|
||||||
|
|
||||||
def test_find_annihilating_operators_recovers_theta_squared():
|
|
||||||
# theta0^2 annihilates log(z0): theta0(log z0) = 1, theta0^2(log z0) = theta0(1) = 0.
|
|
||||||
# Among degree-(0, 2) Ansatze this should be the only solution, up to scaling.
|
|
||||||
period = Period(no_variables=1, coefficients={(1,): {(0,): 1}}, order=5)
|
|
||||||
|
|
||||||
ops = period.find_annihilating_operators(z_degree=0, theta_degree=2)
|
|
||||||
|
|
||||||
# A one-dimensional solution space means exactly one basis operator.
|
|
||||||
assert len(ops) == 1
|
|
||||||
assert period.apply_operator(ops[0]).coefficients == {}
|
|
||||||
assert str(ops[0].operator) == "theta0^2"
|
|
||||||
|
|
||||||
|
|
||||||
def test_find_annihilating_operators_recovers_geometric_series_operator():
|
|
||||||
# sum_{k=0}^{4} z0^k is annihilated (up to truncation order) by
|
|
||||||
# (1 - z0)*theta0 - z0, i.e. theta0 - z0*theta0 - z0.
|
|
||||||
period = Period(
|
|
||||||
no_variables=1,
|
|
||||||
coefficients={(0,): {(0,): 1, (1,): 1, (2,): 1, (3,): 1, (4,): 1}},
|
|
||||||
order=4,
|
|
||||||
)
|
|
||||||
|
|
||||||
ops = period.find_annihilating_operators(z_degree=1, theta_degree=1)
|
|
||||||
|
|
||||||
assert len(ops) == 1
|
|
||||||
assert period.apply_operator(ops[0]).coefficients == {}
|
|
||||||
|
|
||||||
|
|
||||||
def test_find_annihilating_operators_returns_empty_list_when_no_solution_exists():
|
|
||||||
# No degree-0 (constant) operator other than the zero operator can annihilate a
|
|
||||||
# nonzero constant period, so the linear system's only solution is trivial.
|
|
||||||
period = Period(no_variables=1, coefficients={(0,): {(0,): 1}}, order=0)
|
|
||||||
|
|
||||||
ops = period.find_annihilating_operators(z_degree=0, theta_degree=0)
|
|
||||||
|
|
||||||
assert ops == []
|
|
||||||
|
|
||||||
|
|
||||||
def test_simplify_factorises_theta_polynomial_per_z_monomial():
|
|
||||||
# theta0^4 - 5*z0*(5*theta0+1)*(5*theta0+2)*(5*theta0+3)*(5*theta0+4), expanded, is the
|
|
||||||
# quintic's Picard-Fuchs operator. simplify() should recover the factorised form: the
|
|
||||||
# z0^0 part (theta0^4) has no theta-factor to pull out, while the z0^1 part factorises
|
|
||||||
# into the four linear pieces.
|
|
||||||
expanded = "theta0^4 - 3125*z0*theta0^4 - 6250*z0*theta0^3 - 4375*z0*theta0^2 - 1250*z0*theta0 - 120*z0"
|
|
||||||
op = PFOperator(expanded, no_variables=1)
|
|
||||||
|
|
||||||
simplified = op.simplify()
|
|
||||||
|
|
||||||
# The underlying (expanded) operator is unchanged - only the display string differs.
|
|
||||||
assert simplified.operator == op.operator
|
|
||||||
assert simplified.operator_string == "-5*(5*theta0 + 4)*(5*theta0 + 3)*(5*theta0 + 2)*(5*theta0 + 1)*z0 + theta0^4"
|
|
||||||
|
|
||||||
|
|
||||||
def test_find_power_series_solution_recovers_quintic_period():
|
def test_find_power_series_solution_recovers_quintic_period():
|
||||||
@@ -190,14 +103,3 @@ def test_single_operator_recovers_itself_from_its_holomorphic_period():
|
|||||||
assert ratio != 0
|
assert ratio != 0
|
||||||
assert recovered[0].operator == ratio * L.operator
|
assert recovered[0].operator == ratio * L.operator
|
||||||
|
|
||||||
|
|
||||||
def test_change_coordinates_handles_non_monomial_denominator():
|
|
||||||
op = PFOperator("theta0^2 - z0", no_variables=1)
|
|
||||||
|
|
||||||
result = op.change_coordinates("z0/(1-z0)")
|
|
||||||
|
|
||||||
expected = PFOperator(
|
|
||||||
"(1+z0)^3*theta0^2 + z0*(1+z0)^2*theta0 - z0",
|
|
||||||
no_variables=1,
|
|
||||||
)
|
|
||||||
assert result.operator == expected.operator
|
|
||||||
|
|||||||
Reference in New Issue
Block a user