diff --git a/sage/operators.sage b/sage/operators.sage index c72c392..34b6e2e 100644 --- a/sage/operators.sage +++ b/sage/operators.sage @@ -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 logging from sage.all import sage_eval, PolynomialRing, QQ, SR, function, prod, solve, var diff --git a/sage/period.sage b/sage/periods.sage similarity index 91% rename from sage/period.sage rename to sage/periods.sage index b407bbe..c85864b 100644 --- a/sage/period.sage +++ b/sage/periods.sage @@ -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 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 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, - - 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] + (prod_j Gamma(1 - l_num^(j).a)) / (prod_i Gamma(1 + l_den^(i).a)) * z^a. + """ 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].") m = len(l_vectors) diff --git a/sage/toric_topdata.sage b/sage/toric_topdata.sage index 597a1bd..7fa4c22 100644 --- a/sage/toric_topdata.sage +++ b/sage/toric_topdata.sage @@ -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 logging import os diff --git a/tests/test_period_computation.py b/tests/test_period_computation.py index 253a5b4..1aac36e 100644 --- a/tests/test_period_computation.py +++ b/tests/test_period_computation.py @@ -5,93 +5,6 @@ from sage.all import * # noqa: F401 load(os.path.join(os.path.dirname(__file__), "..", "sage", "period.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(): # The quintic's Picard-Fuchs operator has indicial equation theta0^4 = 0 at z0 = 0 # (a quadruple root at 0), so its holomorphic (non-logarithmic) power series solution @@ -190,14 +103,3 @@ def test_single_operator_recovers_itself_from_its_holomorphic_period(): assert ratio != 0 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