Classifications

RationalPolygons.jl provides implementations of the classification algorithms from [2]:

Moreover, we have reimplemented several other classifications of polygons:

Maximal rational polygons contained in $\mathbb{R}\times[-1,1]$

This is an implementation of Algorithm 3.4 from [2].

RationalPolygons.classify_maximal_polygons_m1p1Function
classify_maximal_polygons_m1p1(k :: T, i :: Int)

Return all maximal k-rational polygons with i interior lattice points that can be realized in $\mathbb{R} \times [-1,1]$.

Example:

Compute the numbers of polygons for 1 ≤ k ≤ 5 and 0 ≤ i ≤ 10.

julia> [length(classify_maximal_polygons_m1p1(k,i)) for k = 1 : 5, i = 0 :10]
5×11 Matrix{Int64}:
  1    2    4    5    6    7    8    9   10   11   12
  4    9   13   18   22   26   30   34   38   42   46
 12   26   41   54   68   81   94  107  120  133  146
 24   57   86  117  145  174  203  231  259  288  316
 54  132  209  280  353  422  493  562  631  701  771
source

Maximal rational polygons with no interior lattice points

This is an implementation of Algorithm 4.4 from [2].

RationalPolygons.classify_maximal_lattice_free_polygons_m1p2_squaresFunction
classify_maximal_lattice_free_polygons_m1p2_squares(k :: T) where {T <: Integer}

Return all k-maximal polygons with no interior lattice points that are contained in $A \cup \mathbb{R} \times [-1,2] \cup B$ where $A$ is the square with vertices $(0,1),(1,1),(1,2),(0,2)$ and B is the square with vertices $(0,0),(0,-1),(1,-1),(1,0)$.

source
RationalPolygons.classify_maximal_lattice_free_polygons_m1p2_trapezoidsFunction
classify_maximal_lattice_free_polygons_m1p2_trapezoids(k :: T) where {T <: Integer}

Return all k-maximal polygons with no interior lattice points that are contained in $A \cup \mathbb{R} \times [-1,2] \cup B$ where $A$ is the trapezoid with vertices $(-1,2),(0,1),(1,1),(1,2)$ and $B$ is the trapezoid with vertices $(0,0),(0,-1),(2,-1),(1,0)$, excluding the polygons from classify_maximal_lattice_free_polygons_m1p2_squares.

source
RationalPolygons.classify_maximal_lattice_free_polygonsFunction
classify_maximal_lattice_free_polygons(k :: T ; logging = false) where {T <: Integer}

Return all k-rational polygons with no interior lattice points.

Example:

Compute the numbers of polygons for 1 ≤ k ≤ 6:

julia> length.(classify_maximal_lattice_free_polygons.(1:6))
6-element Vector{Int64}:
   1
   4
  14
  39
 134
 299
source

Rational polygons with one interior lattice point

This is an implementation of Algorithm 5.4 of [2].

RationalPolygons.classify_maximal_polygons_genus_one_m1p1Function
classify_maximal_polygons_genus_one_m1p1(k :: T) where {T <: Integer}

Return all maximal k-rational polygons with exactly one interior lattice point that can be realized in $\mathbb{R} \times [-1,1]$. If primitive = true is passed, then only primitive polygons (i.e. ldp polygons) are returned.

source
RationalPolygons.classify_maximal_polygons_genus_one_m1p2Function
classify_maximal_polygons_genus_one_m1p2(k :: T) where {T <: Integer}

Return all maximal k-rational polygons with exactly one interior lattice point that can be realized in $\mathbb{R} \times [-1,2]$. If primitive = true is passed, then only primitive polygons (i.e. ldp polygons) are returned.

source
RationalPolygons.classify_maximal_polygons_genus_one_m2p2Function
classify_maximal_polygons_genus_one_m2p2(k :: T, q :: Int) where {T <: Integer}

Return all maximal k-rational polygons with exactly one interior lattice point that can be realized in $\mathbb{R} \times [-2,2]$ that have non-empty intersection with the q-th classification box, where 1 ≤ q ≤ 3. If primitive = true is passed, then only primitive polygons (i.e. ldp polygons) are returned.

source
RationalPolygons.classify_maximal_polygons_genus_oneFunction
classify_maximal_polygons_genus_one(k :: T) where {T <: Integer}

Return all maximal k-rational polygons with exactly one interior lattice point. If primitive = true is passed, then only primitive polygons (i.e. ldp polygons) are returned.

Example:

Compute the numbers of polygons for $k ≤ 3$.

julia> length.(classify_maximal_polygons_genus_one.(1:3))
4-element Vector{Int64}:
   3
  10
  39
source
RationalPolygons.classify_polygons_genus_oneFunction
classify_polygons_genus_one(k :: T) where {T <: Integer}

Compute all k-rational polygons with exactly one interior lattice point. The following keyword arguments are supported:

  • primitive :: Bool. If set to true, only primitive polygons (i.e. ldp polygons) are returned.
  • logging :: Bool. Controls whether to display logging messages showing the

current progress.

Example:

Reproduce the classifcation of all 5145 half-integral polygons with exactly one interior lattice point. It first computes all maximal polygons with classify_maximal_polygons_genus_one and then generates all their subpolygons.

julia> classify_polygons_genus_one(2; logging=true);
[ Info: Found 9 maximal polygons in QQ x [-1,1]. New: 9, total: 9
[ Info: Found 2 maximal polygons in QQ x [-1,2]. New: 1, total: 10
[ Info: Found 0 maximal polygons in QQ x [-2,2], box 1. New: 0, total: 10
[ Info: Found 3 maximal polygons in QQ x [-2,2], box 2. New: 0, total: 10
[ Info: Found 3 maximal polygons in QQ x [-2,2], box 3. New: 0, total: 10
[ Info: [a = 36]. Polygons to peel: 2.
[ Info: [a = 36]. Peeling complete. New polygons: 2. Running total: 12
[ Info: [a = 35]. Polygons to peel: 2.
[ Info: [a = 35]. Peeling complete. New polygons: 5. Running total: 17
[ Info: [a = 34]. Polygons to peel: 5.
[ Info: [a = 34]. Peeling complete. New polygons: 10. Running total: 27
[ Info: [a = 33]. Polygons to peel: 9.
[ Info: [a = 33]. Peeling complete. New polygons: 19. Running total: 46
[ Info: [a = 32]. Polygons to peel: 23.
[ Info: [a = 32]. Peeling complete. New polygons: 45. Running total: 91
[ Info: [a = 31]. Polygons to peel: 31.
[ Info: [a = 31]. Peeling complete. New polygons: 69. Running total: 160
[ Info: [a = 30]. Polygons to peel: 60.
[ Info: [a = 30]. Peeling complete. New polygons: 115. Running total: 275
[ Info: [a = 29]. Polygons to peel: 84.
[ Info: [a = 29]. Peeling complete. New polygons: 170. Running total: 445
[ Info: [a = 28]. Polygons to peel: 137.
[ Info: [a = 28]. Peeling complete. New polygons: 239. Running total: 684
[ Info: [a = 27]. Polygons to peel: 171.
[ Info: [a = 27]. Peeling complete. New polygons: 285. Running total: 969
[ Info: [a = 26]. Polygons to peel: 240.
[ Info: [a = 26]. Peeling complete. New polygons: 364. Running total: 1333
[ Info: [a = 25]. Polygons to peel: 286.
[ Info: [a = 25]. Peeling complete. New polygons: 440. Running total: 1773
[ Info: [a = 24]. Polygons to peel: 356.
[ Info: [a = 24]. Peeling complete. New polygons: 466. Running total: 2239
[ Info: [a = 23]. Polygons to peel: 351.
[ Info: [a = 23]. Peeling complete. New polygons: 433. Running total: 2672
[ Info: [a = 22]. Polygons to peel: 396.
[ Info: [a = 22]. Peeling complete. New polygons: 439. Running total: 3111
[ Info: [a = 21]. Polygons to peel: 391.
[ Info: [a = 21]. Peeling complete. New polygons: 394. Running total: 3505
[ Info: [a = 20]. Polygons to peel: 390.
[ Info: [a = 20]. Peeling complete. New polygons: 338. Running total: 3843
[ Info: [a = 19]. Polygons to peel: 349.
[ Info: [a = 19]. Peeling complete. New polygons: 269. Running total: 4112
[ Info: [a = 18]. Polygons to peel: 357.
[ Info: [a = 18]. Peeling complete. New polygons: 249. Running total: 4361
[ Info: [a = 17]. Polygons to peel: 301.
[ Info: [a = 17]. Peeling complete. New polygons: 215. Running total: 4576
[ Info: [a = 16]. Polygons to peel: 292.
[ Info: [a = 16]. Peeling complete. New polygons: 178. Running total: 4754
[ Info: [a = 15]. Polygons to peel: 233.
[ Info: [a = 15]. Peeling complete. New polygons: 121. Running total: 4875
[ Info: [a = 14]. Polygons to peel: 191.
[ Info: [a = 14]. Peeling complete. New polygons: 91. Running total: 4966
[ Info: [a = 13]. Polygons to peel: 140.
[ Info: [a = 13]. Peeling complete. New polygons: 71. Running total: 5037
[ Info: [a = 12]. Polygons to peel: 121.
[ Info: [a = 12]. Peeling complete. New polygons: 40. Running total: 5077
[ Info: [a = 11]. Polygons to peel: 67.
[ Info: [a = 11]. Peeling complete. New polygons: 21. Running total: 5098
[ Info: [a = 10]. Polygons to peel: 56.
[ Info: [a = 10]. Peeling complete. New polygons: 14. Running total: 5112
[ Info: [a = 9]. Polygons to peel: 38.
[ Info: [a = 9]. Peeling complete. New polygons: 13. Running total: 5125
[ Info: [a = 8]. Polygons to peel: 31.
[ Info: [a = 8]. Peeling complete. New polygons: 13. Running total: 5138
[ Info: [a = 7]. Polygons to peel: 14.
[ Info: [a = 7]. Peeling complete. New polygons: 3. Running total: 5141
[ Info: [a = 6]. Polygons to peel: 13.
[ Info: [a = 6]. Peeling complete. New polygons: 3. Running total: 5144
[ Info: [a = 5]. Polygons to peel: 4.
[ Info: [a = 5]. Peeling complete. New polygons: 1. Running total: 5145
[ Info: [a = 4]. Polygons to peel: 3.
[ Info: [a = 4]. Peeling complete. New polygons: 0. Running total: 5145
[ Info: [a = 3]. Polygons to peel: 1.
[ Info: [a = 3]. Peeling complete. New polygons: 0. Running total: 5145
[ Info: [a = 2]. Polygons to peel: 0.
[ Info: [a = 2]. Peeling complete. New polygons: 0. Running total: 5145
[ Info: [a = 1]. Polygons to peel: 0.
[ Info: [a = 1]. Peeling complete. New polygons: 0. Running total: 5145
source

Almost $k$-hollow LDP polygons

We can instruct classify_polygons_genus_one to only output k-rational polygons with primitive vertices. These are exactly the almost $k$-hollow LDP polygons and they correspond to $1/k$-log canonical toric del Pezzo surfaces. In particular, we can reproduce the classification of the 48032 almost 3-hollow LDP polygons ($1/3$-log canonical toric del Pezzo surfaces) from Theorem 4.11 of [6]. See also Table 6 of [2] for the classification up to $k = 6$.

julia> Pss = [classify_polygons_genus_one(k; primitive=true) for k = 1 : 3];

julia> numbers_of_polygons = length.(Pss)
3-element Vector{Int64}:
    16
   505
 48032

julia> max_vertices = [maximum(number_of_vertices.(Pss[k])) for k = 1 : 3]
3-element Vector{Int64}:
  6
  8
 12

julia> max_volumes = [k^2 * maximum(euclidean_area.(Pss[k])) for k = 1 : 3]
3-element Vector{Rational{Int64}}:
 9//2
 17
 47

Lattice polygons by number of lattice points

R.J. Koelman [8] gave an algorithm to classify lattice polygons with a given number of lattice points and ran it up to $42$ lattice points, Table 4.4.3 of [8]. We have implemented their algorithm here, which successfully reproduces their numbers. See also A371917 on OEIS for the numbers up to $112$ lattice points.

RationalPolygons.height_one_pointsFunction
height_one_points(P :: RationalPolygon)

Given a lattice polygon P, return all lattice points that have lattice height one with respect to some edge of P. Equivalently, return the set of boundary lattice points of move_out_edges(P).

source
RationalPolygons.single_point_extensionsFunction
single_point_extensions(Ps :: Vector{<:RationalPolygon{T}}) where {T <: Integer}

Return all lattice polygons that can be obtained by adding a single height one point to a polygon of Ps, up to affine equivalence.

source
RationalPolygons.KoelmanStorageType
abstract type KoelmanStorage{T <: Integer} end

Abstract supertype of InMemoryKoelmanStorage and HDFKoelmanStorage. Both implement classify_next_number_of_lattice_points, which performs a single step in Koelman's classification of lattice polygons.

source
RationalPolygons.InMemoryKoelmanStorageType
mutable struct InMemoryKoelmanStorage{T <: Integer} <: KoelmanStorage{T}

A struct holding classification results of Koelman's classification of lattice polygons by number of lattice points. It has two fields polygons :: Vector{Vector{RationalPolygon{T}} and total_count :: Int.

source
RationalPolygons.HDFKoelmanStoragePreferencesType
struct HDFKoelmanStoragePreferences{T <: Integer}

A struct holding preferences for Koelman's classification using the HDF5 file format. It has four fields:

  • swmr :: Bool: Whether to use single-reader-multiple-writer mode for HDF5. Defaults to true.
  • maximum_number_of_vertices :: Int: An upper bound for the maximal number of vertices to be expected in the classification. This has to be set since every HDF5 file generated will have a dataset numbers_of_polygons storing the number of polygons for each number of vertices and the size of this dataset needs to be set beforehand. Defaults to 100, which should be more than enough for any feasable computation.
  • block_size :: Int: How many polygons should be read into memory at once during the extension process. Defaults to 10^6.
source
RationalPolygons.HDFKoelmanStorageType
mutable struct HDFKoelmanStorage{T <: Integer} <: KoelmanStorage{T}

A struct for managing classification results of Koelman's classification of lattice polygons using the HDF5 file format. It has the following fields:

  • preferences :: HDFKoelmanStoragePreferences{T}
  • directory_path :: String: The directory where the HDF5 files will be generated.
  • last_completed_number_of_lattice_points :: Int: The last completed step of the classification. Initially, this will be 3.
  • total_count :: Int
source
RationalPolygons.classify_next_number_of_lattice_pointsFunction
classify_next_number_of_lattice_points(st :: InMemoryKoelmanStorage{T}) where {T <: Integer}

Perform a single step in Koelman's classification of lattice polygons using in-memory storage.

Example:

Perform a single step of Koelmans classification using Int64. The result tells us that there are three lattice polygons with exactly four lattice points.

julia> st = InMemoryKoelmanStorage{Int64}();

julia> classify_next_number_of_lattice_points(st)
3

julia> st.polygons[4]
3-element Vector{RationalPolygon{Int64}}:
 Rational polygon of rationality 1 with 3 vertices.
 Rational polygon of rationality 1 with 4 vertices.
 Rational polygon of rationality 1 with 3 vertices.
source
classify_next_number_of_lattice_points(st :: HDFKoelmanStorage{T}; logging :: Bool = false) where {T <: Integer}

Perform a single step in Koelman's classification of lattice polygons using on-disk storage with HDF5.

source
RationalPolygons.classify_polygons_by_number_of_lattice_pointsFunction
classify_polygons_by_number_of_lattice_points(st :: KoelmanStorage{T}, max_number_of_lattice_points :: Int; logging :: Bool = false) where {T <: Integer}

Run Koelman's classification of lattice polygons by number of lattice points, up to max_number_of_lattice_points.

Example:

Reproduce Koelman's original classification in memory, see Table 4.4.3 of [8] or A371917 on OEIS. This should not take longer than a few minutes on modern hardware.

julia> st = InMemoryKoelmanStorage{Int}();

julia> classify_polygons_by_number_of_lattice_points(st, 42; logging=true);
[ Info: [l = 4]. New polygons: 3. Total: 4
[ Info: [l = 5]. New polygons: 6. Total: 10
[ Info: [l = 6]. New polygons: 13. Total: 23
[ Info: [l = 7]. New polygons: 21. Total: 44
[ Info: [l = 8]. New polygons: 41. Total: 85
[ Info: [l = 9]. New polygons: 67. Total: 152
[ Info: [l = 10]. New polygons: 111. Total: 263
[ Info: [l = 11]. New polygons: 175. Total: 438
[ Info: [l = 12]. New polygons: 286. Total: 724
[ Info: [l = 13]. New polygons: 419. Total: 1143
[ Info: [l = 14]. New polygons: 643. Total: 1786
[ Info: [l = 15]. New polygons: 938. Total: 2724
[ Info: [l = 16]. New polygons: 1370. Total: 4094
[ Info: [l = 17]. New polygons: 1939. Total: 6033
[ Info: [l = 18]. New polygons: 2779. Total: 8812
[ Info: [l = 19]. New polygons: 3819. Total: 12631
[ Info: [l = 20]. New polygons: 5293. Total: 17924
[ Info: [l = 21]. New polygons: 7191. Total: 25115
[ Info: [l = 22]. New polygons: 9752. Total: 34867
[ Info: [l = 23]. New polygons: 12991. Total: 47858
[ Info: [l = 24]. New polygons: 17321. Total: 65179
[ Info: [l = 25]. New polygons: 22641. Total: 87820
[ Info: [l = 26]. New polygons: 29687. Total: 117507
[ Info: [l = 27]. New polygons: 38533. Total: 156040
[ Info: [l = 28]. New polygons: 49796. Total: 205836
[ Info: [l = 29]. New polygons: 63621. Total: 269457
[ Info: [l = 30]. New polygons: 81300. Total: 350757
[ Info: [l = 31]. New polygons: 102807. Total: 453564
[ Info: [l = 32]. New polygons: 129787. Total: 583351
[ Info: [l = 33]. New polygons: 162833. Total: 746184
[ Info: [l = 34]. New polygons: 203642. Total: 949826
[ Info: [l = 35]. New polygons: 252898. Total: 1202724
[ Info: [l = 36]. New polygons: 313666. Total: 1516390
[ Info: [l = 37]. New polygons: 386601. Total: 1902991
[ Info: [l = 38]. New polygons: 475540. Total: 2378531
[ Info: [l = 39]. New polygons: 582216. Total: 2960747
[ Info: [l = 40]. New polygons: 710688. Total: 3671435
[ Info: [l = 41]. New polygons: 863552. Total: 4534987
[ Info: [l = 42]. New polygons: 1048176. Total: 5583163

Example:

Reproduce Koelman's classification and store the output to HDF5 files.

julia> st = HDFKoelmanStorage{Int}("/tmp");

julia> classify_polygons_by_number_of_lattice_points(st, 42);

The result will be HDF5 files named "l1.h5, l2.h5, ...", each containing one dataset of polygons for fixed number of vertices as well as a dataset "numbers_of_polygons" holding their numbers.

julia> using HDF5

julia> f = h5open("/tmp/test/l42.h5", "r")
🗂️ HDF5.File: (read-only) /tmp/test/l42.h5
├─ 🔢 n10
├─ 🔢 n11
├─ 🔢 n12
├─ 🔢 n3
├─ 🔢 n4
├─ 🔢 n5
├─ 🔢 n6
├─ 🔢 n7
├─ 🔢 n8
├─ 🔢 n9
└─ 🔢 numbers_of_polygons

julia> A = read_dataset(f, "numbers_of_polygons");

julia> sum(A) # The number of lattice polygons with 42 lattice points
1048176

julia> Ps = read_polygon_dataset(1, f, "n5"); # All pentagons with 42 lattice points.

julia> all(P -> number_of_lattice_points(P) == 42, Ps)
true
source

Lattice polygons by number of interior lattice points

Castryck [9] gave an algorithm to classify lattice polygons by number of interior lattice points and ran it up to 30 interior lattice points. Our implementation here successfully reproduces their numbers from Table 1 of [9], see also A322343 on OEIS.

RationalPolygons.CastryckStorageType
abstract type CastryckStorage{T <: Integer} end

Abstract supertype of InMemoryCastryckStorage and HDFCastryckStorage. Both implement classify_next_genus, which performs a single step in Castryck's classification of lattice polygons.

source
RationalPolygons.InMemoryCastryckStorageType
mutable struct InMemoryCastryckStorage{T <: Integer} <: CastryckStorage{T}

A struct holding classification results of Castryck's classification of lattice polygons by number of interior lattice points. It has the following fields:

  • maximum_genus :: Int: An upper bound for the maximum number of lattice points that the classification should run to. Defaults to 100.
  • maximal_polygons :: Vector{Vector{RationalPolygon{T}}},
  • all_polygons :: Vector{Vector{RationalPolygon{T}}},
  • total_count :: Int.
source
RationalPolygons.HDFCastryckStoragePreferencesType
struct HDFCastryckStoragePreferences{T <: Integer}

A struct holding preferences for Castryck's classification using the HDF5 file format. It has four fields:

  • swmr :: Bool: Whether to use single-reader-multiple-writer mode for HDF5. Defaults to true.
  • maximum_genus :: Int: An upper bound for the maximal number of interior lattice points to which the classification should be run. Defaults to 100.
  • maximum_number_of_vertices :: Int: An upper bound for the maximal number of vertices to be expected in the classification. This has to be set since every HDF5 file generated will have a dataset numbers_of_polygons storing the number of polygons for each number of vertices and the size of this dataset needs to be set beforehand. Defaults to 100, which should be more than enough for any feasable computation.
  • block_size :: Int: How many polygons should be read into memory at once during the computation of subpolygons and the moving-out process. Defaults to 10^6.
source
RationalPolygons.HDFCastryckStorageType
mutable struct HDFCastryckStorage{T <: Integer} <: CastryckStorage{T}

A struct for managing classification results of Castryck's classification of lattice polygons using the HDF5 file format. It has the following fields:

  • preferences :: HDFCastryckStoragePreferences{T}
  • directory_path :: String: The directory where the HDF5 files will be generated.
  • last_completed_genus :: Int: The last completed step of the classification. Initially, this will be 0.
  • total_count :: Int
source
RationalPolygons.classify_next_genusFunction
classify_next_genus(st :: InMemoryCastryckStorage{T}; logging :: Bool = false) where {T <: Integer}

Perform a single step in Castryck's classification of lattice polygons by number of interior lattice points, using in-memory storage. Returns a tuple where the first entry is the number of lattice polygons obtained and the second number is the number of maximal lattice polygons.

Example:

Perform two steps in Castryck's classification. The result tells us that there are 45 lattice polygons with exactly two interior lattice points, four of which are maximal.

julia> st = InMemoryCastryckStorage{Int}();

julia> classify_next_genus(st)
(16, 3)

julia> classify_next_genus(st)
(45, 4)
source
classify_next_genus(st :: HDFCastryckStorage{T}; logging :: Bool = false) where {T <: Integer}

Perform a single step in Castryck's classification of lattice polygons using on-disk storage with HDF5.

source
RationalPolygons.classify_lattice_polygons_by_genusFunction
classify_lattice_polygons_by_genus(st :: CastryckStorage{T}, max_genus :: Int; logging :: Bool = false) where {T <: Integer}

Run Castryck's classification of lattice polygons by number of interior lattice points, up to max_genus.

Example:

Reproduce Castryck's classification in memory, see Table 1 of [9] or A322343 on OEIS. This should not take longer than a few minutes on modern hardware.

julia> st = InMemoryCastryckStorage{Int}();

julia> classify_lattice_polygons_by_genus(st, 30; logging=true)
[ Info: [i = 1]. Got 3 maximal polygons.
[ Info: [i = 1]. Subpolygons complete. Num of polygons: 16
[ Info: [i = 1]. Moving out complete. New maximal polygons: 16
[ Info: [i = 2]. Got 4 maximal polygons.
[ Info: [i = 2]. Subpolygons complete. Num of polygons: 45
[ Info: [i = 2]. Moving out complete. New maximal polygons: 22
[ Info: [i = 3]. Got 6 maximal polygons.
[ Info: [i = 3]. Subpolygons complete. Num of polygons: 120
[ Info: [i = 3]. Moving out complete. New maximal polygons: 63
[ Info: [i = 4]. Got 9 maximal polygons.
[ Info: [i = 4]. Subpolygons complete. Num of polygons: 211
[ Info: [i = 4]. Moving out complete. New maximal polygons: 78
[ Info: [i = 5]. Got 11 maximal polygons.
[ Info: [i = 5]. Subpolygons complete. Num of polygons: 403
[ Info: [i = 5]. Moving out complete. New maximal polygons: 122
[ Info: [i = 6]. Got 13 maximal polygons.
[ Info: [i = 6]. Subpolygons complete. Num of polygons: 714
[ Info: [i = 6]. Moving out complete. New maximal polygons: 192
[ Info: [i = 7]. Got 16 maximal polygons.
[ Info: [i = 7]. Subpolygons complete. Num of polygons: 1023
[ Info: [i = 7]. Moving out complete. New maximal polygons: 239
[ Info: [i = 8]. Got 21 maximal polygons.
[ Info: [i = 8]. Subpolygons complete. Num of polygons: 1830
[ Info: [i = 8]. Moving out complete. New maximal polygons: 316
[ Info: [i = 9]. Got 27 maximal polygons.
[ Info: [i = 9]. Subpolygons complete. Num of polygons: 2700
[ Info: [i = 9]. Moving out complete. New maximal polygons: 508
[ Info: [i = 10]. Got 33 maximal polygons.
[ Info: [i = 10]. Subpolygons complete. Num of polygons: 3659
[ Info: [i = 10]. Moving out complete. New maximal polygons: 509
[ Info: [i = 11]. Got 38 maximal polygons.
[ Info: [i = 11]. Subpolygons complete. Num of polygons: 6125
[ Info: [i = 11]. Moving out complete. New maximal polygons: 700
[ Info: [i = 12]. Got 51 maximal polygons.
[ Info: [i = 12]. Subpolygons complete. Num of polygons: 8101
[ Info: [i = 12]. Moving out complete. New maximal polygons: 1044
[ Info: [i = 13]. Got 61 maximal polygons.
[ Info: [i = 13]. Subpolygons complete. Num of polygons: 11027
[ Info: [i = 13]. Moving out complete. New maximal polygons: 1113
[ Info: [i = 14]. Got 76 maximal polygons.
[ Info: [i = 14]. Subpolygons complete. Num of polygons: 17280
[ Info: [i = 14]. Moving out complete. New maximal polygons: 1429
[ Info: [i = 15]. Got 86 maximal polygons.
[ Info: [i = 15]. Subpolygons complete. Num of polygons: 21499
[ Info: [i = 15]. Moving out complete. New maximal polygons: 2052
[ Info: [i = 16]. Got 113 maximal polygons.
[ Info: [i = 16]. Subpolygons complete. Num of polygons: 28689
[ Info: [i = 16]. Moving out complete. New maximal polygons: 1962
[ Info: [i = 17]. Got 129 maximal polygons.
[ Info: [i = 17]. Subpolygons complete. Num of polygons: 43012
[ Info: [i = 17]. Moving out complete. New maximal polygons: 2651
[ Info: [i = 18]. Got 166 maximal polygons.
[ Info: [i = 18]. Subpolygons complete. Num of polygons: 52736
[ Info: [i = 18]. Moving out complete. New maximal polygons: 3543
[ Info: [i = 19]. Got 200 maximal polygons.
[ Info: [i = 19]. Subpolygons complete. Num of polygons: 68557
[ Info: [i = 19]. Moving out complete. New maximal polygons: 3638
[ Info: [i = 20]. Got 240 maximal polygons.
[ Info: [i = 20]. Subpolygons complete. Num of polygons: 97733
[ Info: [i = 20]. Moving out complete. New maximal polygons: 4594
[ Info: [i = 21]. Got 281 maximal polygons.
[ Info: [i = 21]. Subpolygons complete. Num of polygons: 117776
[ Info: [i = 21]. Moving out complete. New maximal polygons: 5996
[ Info: [i = 22]. Got 352 maximal polygons.
[ Info: [i = 22]. Subpolygons complete. Num of polygons: 152344
[ Info: [i = 22]. Moving out complete. New maximal polygons: 6364
[ Info: [i = 23]. Got 403 maximal polygons.
[ Info: [i = 23]. Subpolygons complete. Num of polygons: 209409
[ Info: [i = 23]. Moving out complete. New maximal polygons: 7922
[ Info: [i = 24]. Got 506 maximal polygons.
[ Info: [i = 24]. Subpolygons complete. Num of polygons: 248983
[ Info: [i = 24]. Moving out complete. New maximal polygons: 9692
[ Info: [i = 25]. Got 584 maximal polygons.
[ Info: [i = 25]. Subpolygons complete. Num of polygons: 319957
[ Info: [i = 25]. Moving out complete. New maximal polygons: 10208
[ Info: [i = 26]. Got 708 maximal polygons.
[ Info: [i = 26]. Subpolygons complete. Num of polygons: 420714
[ Info: [i = 26]. Moving out complete. New maximal polygons: 12727
[ Info: [i = 27]. Got 821 maximal polygons.
[ Info: [i = 27]. Subpolygons complete. Num of polygons: 497676
[ Info: [i = 27]. Moving out complete. New maximal polygons: 15431
[ Info: [i = 28]. Got 995 maximal polygons.
[ Info: [i = 28]. Subpolygons complete. Num of polygons: 641229
[ Info: [i = 28]. Moving out complete. New maximal polygons: 15918
[ Info: [i = 29]. Got 1121 maximal polygons.
[ Info: [i = 29]. Subpolygons complete. Num of polygons: 813814
[ Info: [i = 29]. Moving out complete. New maximal polygons: 20354
[ Info: [i = 30]. Got 1352 maximal polygons.
[ Info: [i = 30]. Subpolygons complete. Num of polygons: 957001
[ Info: [i = 30]. Moving out complete. New maximal polygons: 23873

Example:

Reproduce Castryck's classification and store the output to HDF5 files

julia> st = HDFCastryckStorage{Int}("/tmp");

julia> classify_lattice_polygons_by_genus(st, 30);

This will create two directories all and maximal in the target directory and populate them with HDF5 files i1.h5, i2.h5, etc., containing the polygons. The files in maximal contain datasets ordered by number of vertices. The files in all contain groups ordered by area, which contain datasets ordered by number of vertices. Every h5 file additionally contains a dataset numbers_of_polygons.

julia> using HDF5

julia> f = h5open("/tmp/all/i30.h5", "r");

julia> Ps = read_polygon_dataset(1, f, "a69/n8"); # Read in all octagons of genus 30 with normalized volume 69

julia> all(P -> number_of_interior_lattice_points(P) == 30, Ps)
true

julia> A = read_dataset(f, "numbers_of_polygons"); # The total number of lattice polygons with 30 interior lattice points

julia> sum(A) # The total number of lattice polygons with 30 interior lattice points.
957001
source

Lattice polygons contained in a square

Brown and Kasprzyk [10] authors considered lattice polygons that are contained in a square of fixed side length and classified them up to side length $7$. Their numbers (Table 1 of [10], see also A374975) can be reproduced with RationalPolygons.jl as follows:

julia> square(m) = convex_hull(LatticePoint{Int}[(0,0),(m,0),(0,m),(m,m)])
square (generic function with 1 method)

julia> Pss = [subpolygons(square(m); use_affine_normal_form = true, only_equal_number_of_interior_lattice_points = false) for m = 1 : 7];

julia> numbers_of_polygons = [length(Pss[m]) - length(Pss[m-1]) for m = 2 : 7]
6-element Vector{Int64}:
      15
     131
    1369
   13842
  129185
 1104895

julia> max_vertices = [maximum(number_of_vertices.(Pss[m])) for m = 1 : 7]
7-element Vector{Int64}:
  4
  6
  8
  9
 10
 12
 13

julia> [length(filter(P -> number_of_vertices(P) == max_vertices[m], Pss[m])) for m = 1 : 7]
7-element Vector{Int64}:
  1
  1
  1
  1
 15
  2
  3

LDP polygons by Gorenstein index

Kasprzyk, Kreuzer and Nill [11] gave an algorithm to classify LDP polygons by Gorenstein index. RationalPolygons.jl implements a version of their algorithm, which successfully reproduces their numbers (see Theorem 1.2 of [11]).

RationalPolygons.PartialLDPType
PartialLDP{T<:Integer,N,M}

A struct used in the classification of polygons by Gorenstein index. It contains three fields:

  • P :: RationalPolygon{T,N,M}: The polygon constructed so far.
  • initial_local_index : T: The local index of the special facet.
  • ymin : T: Lower bound for the y-value of the next vertex to be chosen, see Algorithm 6.3 of [11].
source
RationalPolygons.initial_special_facetsFunction
initial_special_facets(index :: T, initial_local_index :: T) where {T <: Integer}

Return all possible initial special facet to start the classification as in step (1) of Algorithm 6.3 of [11].

source
RationalPolygons.choose_next_vertexFunction
choose_next_vertex(ldps :: Vector{<:PartialLDP{T,N}}, index :: T) where {N, T <: Integer}

Perform a single step in the classification of lattice polygons by Gorenstein index as in step (2) of Algorithm 6.3 of [11].

source
RationalPolygons.classify_lattice_polygons_by_gorenstein_indexFunction
classify_lattice_polygons_by_gorenstein_index(index :: T; logging :: Bool = false) where {T <: Integer}

Return all lattice polygons with given Gorenstein index, using the Algorithm described in [11].

Example:

There are 91 LDP polygons of Gorenstein index four: 13 triangles, 48 quadrilaterals, 29 pentagons and one hexagon.

julia> Pss = classify_lattice_polygons_by_gorenstein_index(4);

julia> length.(Pss)
4-element Vector{Int64}:
 13
 48
 29
  1

julia> sum(ans)
91
source

LDP triangles by Gorenstein index

Bäuerle [12] gave an algorithm to classify Fano simplices by dimension and Gorenstein index. RationalPolygons.jl implements a version of his algorithm (specialized to the two-dimensional case), which reproduces his numbers successfully (see Theorem 1.4 of [12] and A145582).

RationalPolygons.unit_fraction_partitions_length_threeFunction
unit_fraction_partitions_length_three(ι :: T) where {T <: Integer}

Return all triples (a,b,c) such that 1//ι = 1//a + 1//b + 1//c and a ≤ b ≤ c. See also A004194 on OEIS.

Example:

julia> unit_fraction_partitions_length_three(2)
10-element Vector{Tuple{Int64, Int64, Int64}}:
 (3, 7, 42)
 (3, 8, 24)
 (3, 9, 18)
 (3, 10, 15)
 (3, 12, 12)
 (4, 5, 20)
 (4, 6, 12)
 (4, 8, 8)
 (5, 5, 10)
 (6, 6, 6)
source
RationalPolygons.InMemoryBaeuerleStorageType
mutable struct InMemoryBaeuerleStorage{T <: Integer} <: BaeuerleStorage{T}

A struct holding classification results of Bäuerle's classification of lattice triangles by Gorenstein index.

source
RationalPolygons.HDFBaeuerleStorageType
mutable struct HDFBaeuerleStorage{T <: Integer} <: BaeuerleStorage{T}

A struct for managing classification results of Baeuerle's classification of lattice triangles using the HDF5 file format. It has the following fields:

  • preferences :: HDFBaeuerleStoragePreferences{T}
  • file_path :: String: The path of the HDF file to be generated.
  • last_completed_gorenstein_index :: Int: The last completed step of the classification. Initially, this will be 0.
  • total_count :: Int
source
RationalPolygons.classify_lattice_triangles_by_gorenstein_indexFunction
classify_lattice_triangles_by_gorenstein_index(ι :: T) where {T <: Integer}

Return all lattice triangles with Gorenstein index ι.

Example:

There are five lattice triangles with Gorenstein index one:

julia> classify_lattice_triangles_by_gorenstein_index(1)
Set{RationalPolygon{Int64, 3}} with 5 elements:
  Rational polygon of rationality 1 with 3 vertices.
  Rational polygon of rationality 1 with 3 vertices.
  Rational polygon of rationality 1 with 3 vertices.
  Rational polygon of rationality 1 with 3 vertices.
  Rational polygon of rationality 1 with 3 vertices.
source
classify_lattice_triangles_by_gorenstein_index(st :: InMemoryBaeuerleStorage{T}, max_gorenstein_index :: T) where {T <: Integer}

Perform Bäuerle's classification of lattice triangles up go max_gorenstein_index, storing the results in memory.

Example:

Reproduce Bäuerle's original classification up to Gorenstein index 1000, see Theorem 1.4 of [12].

julia> st = InMemoryBaeuerleStorage{Int}()
InMemoryBaeuerleStorage{Int64}(Vector{RationalPolygon{Int64, 3, 6}}[], 0)

julia> classify_lattice_triangles_by_gorenstein_index(st, 1000);

julia> sum(length.(st.polygons))
2992229
source
classify_lattice_triangles_by_gorenstein_index(st :: HDFBaeuerleStorage{T}, max_gorenstein_index :: T; logging :: Bool = false) where {T <: Integer}

Perform Bäuerle's classification of lattice triangles up go max_gorenstein_index, storing the results in an HDF5 file

source

LDP triangles by Picard index

Springer [4] gave an algorithm to classify LDP triangles (toric log del Pezzo surfaces of rank one) by Picard index. RationalPolygons.jl implements a version of this algorithm, which successfully reproduces the numbers from Theorem 8.5 of [4].

RationalPolygons.HDFPicardIndexStorageType
mutable struct HDFPicardIndexStorage{T <: Integer} <: PicardIndexStorage{T}

A struct for managing classification results of Springer's classification of lattice triangles using the HDF5 file format. It has the following fields:

  • preferences :: HDFPicardIndexStoragePreferences{T}
  • file_path :: String: The path of the HDF file to be generated.
  • last_completed_picard_index :: Int: The last completed step of the classification. Initially, this will be 0.
  • total_count :: Int
source
RationalPolygons.classify_lattice_triangles_by_picard_indexFunction
classify_lattice_triangles_by_picard_index(p :: T) where {T <: Integer}

Return all lattice triangles with Picard index p.

Example:

There are two lattice triangles with Picard index 6:

julia> classify_lattice_triangles_by_picard_index(6)
Set{RationalPolygon{Int64, 3, 6}} with 2 elements:
  Rational polygon of rationality 1 with 3 vertices.
  Rational polygon of rationality 1 with 3 vertices.
source
classify_lattice_triangles_by_picard_index(st :: InMemoryPicardIndexStorage{T}, max_picard_index :: T) where {T <: Integer}

Perform Springer's classification of lattice triangles up go max_picard_index, storing the results in memory.

Example:

Reproduce Springer's original classification up to picard index 10000, see Theorem 1.2 of [4].

julia> st = InMemoryPicardIndexStorage{Int}()
InMemoryPicardIndexStorage{Int64}(Vector{RationalPolygon{Int64, 3, 6}}[], 0)

julia> classify_lattice_triangles_by_picard_index(st, 10000);

julia> sum(length.(st.polygons))
68053
source
classify_lattice_triangles_by_picard_index(st :: HDFPicardIndexStorage{T}, max_picard_index :: T; logging :: Bool = false) where {T <: Integer}

Perform Springer's classification of lattice triangles up go max_picard_index, storing the results in an HDF5 file

source

LDP triangles with integral degree

Hausen and Király [13] classified fake weighted projective planes having integral degree (=canonical self intersection). In terms of polygons, these can be described as LDP triangles such that twice the euclidean area of its dual is an integer. The attained values of this integer (which is the degree of the associated fake weighted projective plane) are the integers from $1$ to $9$, excluding $7$. In total, there are 24 infinite series of these triangles, where each of them is parameterized by the solution set of a squared Markov type equation (see Theorem 1.1 of [13]). These solution sets can be described as infinite binary trees with a unique root. RationalPolygons.jl uses this description to implement a classification algorithm for LDP triangles with integral degree. To make this classification finite, one has to provide a maximal depth to which the solution trees are traversed.

All methods used for this classification come with a parameter T <: Integer, which is the integer type to be used. Since the entries of the solution triples of squared Markov type equations grow very quickly with increasing depth, it is recommended to use BigInt here instead of fixed-size integer types (Int64 overflows already for depth = 4).

RationalPolygons.degreeMethod
degree(w :: SVector{3})

Return the degree of a fake weighted projective plane with given fake weight vector w. This is given by the formula sum(w)^2 // prod(w), see for instance Proposition 3.7 of [13].

source
RationalPolygons.fake_weight_vectorFunction
fake_weight_vector(P :: RationalPolygon{T,3}) where {T <: Integer}

Return the fake weight vector of the fake weighted projective plane associated to the LDP triangle P.

source
RationalPolygons.n_step_mutationsFunction
n_step_mutations(us :: Set{SVector{3,T}}, depth :: Int) where {T <: Integer}

Given solution triples us of a squared Markov type equation, return all solution triples that can be obtained from us by applying at most depth many mutations. This function returns a vector of length depth+1, containing for each level i = 0 : depth the set of solution triples after exactly i mutation steps.

Example:

Get all solutions to the squared Markov type equation $9xyz=(x+y+z)^2$ by starting with the initial solution $(1,1,1)$ and applying at most four mutations. Compare with $T(9)$ of Remark 2.5 of [13].

julia> us = Set([SVector{3,Int}(1,1,1)])
Set{SVector{3, Int64}} with 1 element:
  [1, 1, 1]

julia> n_step_mutations(us, 4)
5-element Vector{Set{SVector{3, Int64}}}:
 Set([[1, 1, 1]])
 Set([[1, 1, 4]])
 Set([[1, 4, 25]])
 Set([[4, 25, 841], [1, 25, 169]])
 Set([[25, 169, 37636], [25, 841, 187489], [1, 169, 1156], [4, 841, 28561]])
source
RationalPolygons.initial_tripleFunction
initial_triple(:: Val{A}, T :: Type{<:Integer} = BigInt)

Return the unique initial triple of the squared Markov type equation $Axyz = (x+y+z)^2$. Allowed values of A are 9, 8, 6 and 5.

Example:

The unique initial triples for all allowed values of A, see Theorem 2.2 of [13].

julia> [initial_triple(Val(A)) for A in [9,8,6,5]]
4-element Vector{SVector{3, BigInt}}:
 [1, 1, 1]
 [1, 1, 2]
 [1, 2, 3]
 [1, 4, 5]
source
RationalPolygons.adjust_tripleFunction
adjust_triple(::Val{A}, u :: SVector{3,T}) where {T <: Integer}
adjust_triple(u :: SVector{3,T}) where {T <: Integer}

Reorder a solution triple of a squared Markov type equation to make it adjusted, according to Definition 3.14 of [13]. Allowed values of A are 9, 8, 6 and 5. If A is not given, it is determined by calculating the degree of u.

Example:

The solution triple $(50,9,3481)$ for $A=8$ is not adjusted, since the even entry is not last.

julia> adjust_triple(Val(8), SVector{3,Int}(50,9,3481))
3-element SVector{3, Int64} with indices SOneTo(3):
    9
 3481
   50
source
RationalPolygons.classify_squared_markov_type_equation_solutionsFunction
classify_squared_markov_type_equation_solutions(::Val{A}, depth :: Int, T :: Type{<:Integer} = BigInt) where {A}

Return all solutions to the squared Markov type equation $Axyz = (x+y+z)^2$ by starting with the initial solution and applying at most depth many mutations. Allowed values of A are 9, 8, 6 and 5.

Example:

All solution triples to $8xyz = (x+y+z)^2$ with depth at most three.

julia> classify_squared_markov_type_equation_solutions(Val(8),3)
4-element Vector{Set{SVector{3, BigInt}}}:
 Set([[1, 1, 2]])
 Set([[1, 2, 9]])
 Set([[2, 9, 121], [1, 9, 50]])
 Set([[9, 50, 3481], [2, 121, 1681], [1, 50, 289], [9, 121, 8450]])
source
RationalPolygons.fake_weight_vectors_to_trianglesFunction
fake_weight_vectors_to_triangles(us :: Set{SVector{3,T}}, μ :: T) where {T <: Integer}

Given a set of triples us sharing the same integral degree A and an integer μ, return all LDP triangles having fake weight vector μ * u. Allowed values of A are 9, 8, 6 and 5. Moreover, μ must be a divisor of A. The resulting triangles will have degree A ÷ μ and multiplicity μ.

source
RationalPolygons.classify_lattice_triangles_integral_degreeFunction
classify_lattice_triangles_integral_degree(::Val{K}, ::Val{μ}, depth :: Int, T :: Type{<:Integer} = BigInt) where {K, μ}

Return all LDP triangles (= fake weighted projective planes) with integral degree K and class group torsion order μ, up to a given depth in the Markov tree. Essentially, this returns the triangles of the series (K-μ-*) according to the notation of Theorem 1.1 of [13]. Allowed values of K are 1, 2, 3, 4, 5, 6, 8 and 9. Allowed values of μ are all integers such that μ * K is 5, 6, 8 or 9.

Example:

Compute all LDP triangles of degree 1 and class group torsion order 9, up to Markov depth 5. These consist of the three series (1-9-2), (1-9-5) and (1-9-8) from Theorem 1.1 of [13]. Note that for depths zero and one (which correspond to solution triples (1,1,1) and (1,1,4) in the Markov tree), the series overlap, hence there are only one resp. two triangles in this case, which is also mentioned in the Theorem. After that, the number of triangles doubles with each additional step.

julia> Pss = classify_lattice_triangles_integral_degree(Val(1), Val(9), 5);

julia> length.(Pss)
6-element Vector{Int64}:
  1
  2
  3
  6
 12
 24
source
classify_lattice_triangles_integral_degree(::Val{K}, depth :: Int, T :: Type{<:Integer} = BigInt) where {K}

Return all LDP triangles (= fake weighted projective planes) with integral degree K, up to a given depth in the Markov tree. Essentially, this returns the triangles of the series (K - * - *) according to the notation of Theorem 1.1 of [13]. Allowed values of K are 1, 2, 3, 4, 5, 6, 8 and 9.

Example:

Print the numbers of LDP triangles with integral degree K, for all possible values of K, up to depth 10.

julia> [length.(classify_lattice_triangles_integral_degree(Val(K), 10)) for K in [1,2,3,4,5,6,8,9]]
8-element Vector{Vector{Int64}}:
 [10, 18, 35, 70, 140, 280, 560, 1120, 2240, 4480, 8960]
 [4, 6, 12, 24, 48, 96, 192, 384, 768, 1536, 3072]
 [2, 3, 5, 10, 20, 40, 80, 160, 320, 640, 1280]
 [1, 1, 2, 4, 8, 16, 32, 64, 128, 256, 512]
 [1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024]
 [1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024]
 [1, 1, 2, 4, 8, 16, 32, 64, 128, 256, 512]
 [1, 1, 1, 2, 4, 8, 16, 32, 64, 128, 256]
source
classify_lattice_triangles_integral_degree(depth :: Int, T :: Type{<:Integer} = BigInt)

Return all LDP triangles (= fake weighted projective planes) with integral degree, up to a given depth in the Markov tree. This returns the union of all 24 series classified in Theorem 1.1 of [13].

source

LDP quadrangles by Gorenstein index

The following is a classification of LDP quadrangles by Gorenstein index. A reference explaining the approach used will be added in the future.

RationalPolygons.modified_unit_fraction_solutionsFunction
modified_unit_fraction_solutions(r :: T, s :: T, c :: T, d :: T) where {T <: Integer}

Return all integral solutions $(x,y) ∈ \mathbb{Z}^2_{\geq 1}$ to the equation $r/s = 1/x + 1/y - c/(d*y)$. Returns an error if there are infinitely many solutions, which happens if and only if $c = d$.

source
RationalPolygons.classify_gorenstein_coefficientsFunction
classify_gorenstein_coefficients(ι :: T, ::Val{t})
classify_gorenstein_coefficients(ι :: T)

Classify Gorenstein coefficients associated to Fano ι-Gorenstein matrices. Optionally takes in a Val{t} argument, where t can be 1, 2, 3 or 4. In this case, only the Gorenstein coefficients of type t are classified.

source
RationalPolygons.classify_quadrilaterals_by_gorenstein_indexFunction
classify_quadrilaterals_by_gorenstein_index(ι :: Integer)

Return all LDP quadrilaterals with Gorenstein index ι.

Example:

There are 73725 distinct LDP quadrilaterals with Gorenstein index at most 50.

julia> Pss = classify_quadrilaterals_by_gorenstein_index.(1:50);

julia> sum(length.(Pss))
73725
source