This is a program that given a configuration of rational curves on an elliptic surface, does successions of blow ups in hopes to obtain configurations of resolutions of Wahl singularities (Wahl chains).
Specifically, it blows up exhaustively to obtain all possible* configurations of:
- one Wahl chain,
- two Wahl chains,
- one
$\mathbb Q \mathcal H \mathcal D^3$ plumbing graph, - one
$\mathbb Q \mathcal H \mathcal D^3$ plumbing graph and one Wahl chain.
An example is just a configuration of curves on a surface
The assumption of working on an elliptic surface is only used to calculate obstructions and nef-ness of the canonical class. As such, this program works in any abstract setting, for configurations of curves in arbitrary surfaces, with the disclaimer that both nef-ness and the obstruction calculation may not give correct results.
The program is written in standard C++17
.
The first step is to install a suitable C++
compiler. For Linux GNU C++
is usually installed by default, and for macOS, clang
is installed by default. Both can be tested in the command line by running
g++ --version
As for Windows, we have only tested the program using the 64-bit version of MinGW from here. This installation includes GNU C++
, which can be tested with the same command. We have seen some inconsistent behavior and occasional crashes with this version when compiled with multithread support, so it is not recommended.
The second step is to compile the program. For example, using GNU C++
with -Ofast
and -flto
optimizations, run from the terminal the line:
g++ -std=c++17 -Ofast -flto src/*.cpp -o Search.exe
The program has support for multi-threading. To use it with GNU C++
, run
g++ -std=c++17 -Ofast -flto -pthread -D MULTITHREAD src/*.cpp -o Search.exe
To set the maximum amount of threads, do for example
g++ -std=c++17 -Ofast -flto -pthread -D MULTITHREAD -D MAX_THREADS=8 src/*.cpp -o Search.exe
Alternatively, in the file config.hpp
uncomment the line
#define MULTITHREAD
optionally set the maximum number of threads by modifying
#define MAX_THREADS 4
and run
g++ -std=c++17 -Ofast -flto -pthread src/*.cpp -o Search.exe
The result will be an executable file called Search.exe
.
To test a configuration, a test file must be provided. For example, if the test file is called, test.txt
, one must run from the Windows terminal the line
Search.exe test.txt
or if using Linux or macOS,
./Search.exe test.txt
If test.txt
is a valid file, the testing will begin immediately. Afterwards, an example database file and a summary file will be created, depending on the settings provided in the test file.
The database file has extension .jsonl
and is meant to have all the necessary information of the examples to reconstruct them. It is not meant to be human readable. The summary file has extension .txt
or .tex
and is meant to be readable. It lists some numerical invariants and general information of the examples, each with a unique ID.
To view the complete information of an example and how to recover it from the original configuration, the Display.py
script is used. Run from the Windows terminal
Display.py
or on Linux or macOS,
./Display.py
or alternatively for any operating system,
python3 Display.py
A window should pop up. Open a .jsonl
file with the Open file
button or with Ctrl-O
. Then input the unique ID of the example in the box and press Enter
. Alternatively, the arrow keys can be used to navigate through all examples. The window will display the requested information.
Of course, python3
is required, but also tkinter
. If it is not installed, run
pip install tk
from the terminal.
A test file gives the program a list of rational curves on the surface and the intersections between them. To search for chains, the first step is to choose a subset of those curves, and consider only the sub-graph generated by this subset. This is called a sub-test
.
To efficiently describe thousands of sub-tests
, the test file describes one or more tests
: Within a test
, each curve is either fixed, ignored or tried. Fixed curves shall be contained in every sub-test of a the given test. Ignored shall not be included in any sub-test. Tried curves are both included and ignored in different sub-tests, such that every possibility of including try curves is probed. Thus the amount of sub-tests inside a test is exponential in the amount of try curves.
One more option for Fibers is provided. A discard fiber treats all its irreducible members as try curves, but excludes the case when all of them are included.
A test file consists of settings and curve definitions. All settings must be declared before starting the definitions of curves.
Single and multi-line comments are available loosely following Python
and C++
comment syntax.
- Single comments are done by starting the line with
#
or//
- Multiline comments begin with
/*
and end with*/
. Both symbols shall be at the start of the line.
# This is a valid comment
// This is also a valid comment
Something something // This is not a valid comment
/* This is
a valid
multiline comment
*/
/*
This one
is not */
There are several settings that affect the search in different ways. All of them are of the form
Setting: Option/value
Both settings and options are case-sensitive. Following is the full list of settings and their possible options:
-
Tests
: Takes a range of positive numbers, for example "2 - 5
". It determines a range of tests to be performed on the configuration.Can also take a single number
n
, which is effectively equivalent to the range "1 - n
".Values are clamped below the hard limit of
100
, given by the macroMAX_TESTS
inconfig.hpp
.Defaults to
1
.By putting
Tests: 0
no test is done. The program only dumps the information of the complete configuration to the.jsonl
file. -
Output
: Takes the name of the file where a database of examples will be exported. It will be of extension.jsonl
. For example if one writesOutput: filename
A file called
filename.jsonl
will be created. Unfortunately, the filename shall not contain white spaces.Defaults to
OUT
. -
Summary_Style
: Determines the style of the summary file. Takes two possible options-
LaTeX_Table
: Summary is exported as an easy to include table in Latex format. -
Plain_Text
: Summary is exported as a plain text file. -
skip
: Does not export summary.
Defaults to
Plain_Text
. -
-
Summary_Include_GCD
: For examples with two singularities, include in the summary the gcd of the common denominators for discrepancies. Useful when calculating fundamental groups. TakesY
as yes andN
as no. Defaults toN
. -
LaTeX_Include_Subsection
: When the summary is styled as latex tables, includes a\subsection
before each table with some invariants. TakesY
as yes andN
as no. Defaults toN
. -
Summary
: Takes the name of the file where a list of examples in human readable form will be exported. It will be of extension.txt
or.tex
depending onSummary_Style
. For example if one writesSummary: filename
A file called
filename.txt
will be created. Unfortunately, the filename shall not contain white spaces.Defaults to
SUMMARY
. -
Summary_Sort
: Determines how to sort the examples to export them to the summary file. Takes two possible options:-
By_N
: Sorts relative to the invariants of the chains in increasing order. -
By_Length
: Sorts by size of the chains in increasing order.
Defaults to
By_N
. -
-
Nef_Check
: Determines wether to check for nef-ness of the canonical class$K_S$ . Takes four possible options:-
Y
: Tests for nef-ness. It the test fails, discard the example. -
skip
: Same asY
. -
N
: Does not test for nef-ness. -
print
: Tests for nef-ness, but does not discard examples. Instead adds the result of this test to the summary file.
Defaults to
Y
. -
-
Effective_Check
: Determines wether to check for$\mathbb Q$ -effectiveness of the canonical class$K_S$ . Takes the same options asNef_Check
that act analogously. Defaults toY
. -
Obstruction_Check
: Determines wether to check if the examples have no global obstruction for smoothing. Takes the same options asNef_Check
that act analogously. Defaults toY
. -
Single_Chain
: Determines wether to search for one Wahl chain. TakesY
as yes andN
as no. Defaults toY
. -
Double_Chain
: Determines wether to search for two Wahl chain. TakesY
as yes andN
as no. Defaults toN
. -
Single_QHD
: Determines wether to search for one$\mathbb Q \mathcal H \mathcal D^3$ plumbing graph. TakesY
as yes andN
as no. Defaults toN
. -
Double_QHD
: Determines wether to search for one$\mathbb Q \mathcal H \mathcal D^3$ plumbing graph and one Wahl chain. TakesY
as yes andN
as no. Defaults toN
. -
Search_For
: Takes a space-separated list of numbers. Those are the$K_X^2$ that the program will aim for. For example,Search_For: 3 4
Defaults to
1 2 3 4
-
K2
: Sets the self intersection of the canonical class in the original surface. Defaults to0
. -
Keep_First
: Determines how to deal with multiple examples with the same invariants. Takes three options:-
local
: Within each sub-test, keep the first example with the given invariants. Since configurations are usually very symmetric, one can expect a huge number of repetitions, since equivalent although different sub-configurations will give equivalent results. -
global
: Keep the first example with the given invariants along all tests. -
N
: Keep all examples. Not only multiple examples may appear thanks to symmetries of the configuration, but within the same sub-test it is possible to obtain the exact same example more than once, due to fundamental limitations of the program, so this is highly unrecommended.
With
global
, when an example is obtained such that its invariants were already found, it gets immediately discarded. This means that if any check is set toprint
and the first example found did not pass the test, but the second example did, then only the less interesting example is included in the results. Thus an option other thanglobal
still has some merit.Defaults to
global
. -
-
Threads
: The amount of threads to spawn with multi thread support. Has a hard limit given by the macroMAX_THREADS
inconfig.hpp
, which is4
unless modified. Defaults toMAX_THREADS
. -
Sections_Input
: Determines the meaning of the parameter when adding curves. Takes two options:-
By_Self_Intersection
: The parameter for sections correspond to their self intersection in the original surface$Y$ . -
By_Canonical_Intersection
: The parameter corresponds to the intersection of the section with the canonical class in the original surface$Y$ .
This option is useful when dealing with highly singular multiple sections. For example if a curve
$C$ is sextuple section, then$C.K_Y = -6$ , but if it is too singular, perhaps it is not immediate knowing$C^2$ . -
-
Use_Exactly
: Takes a non-negative number or-1
. If-1
is used, nothing happens. Otherwise, every sub-test must have this exact number of curves to be tested.
Some debugging options are:
-
SubTests
: Takes a range of positive integers, for example "2 - 5
". It tests only in that range of sub-tests, which is useful for separating the load if there are too many sub-tests.Defaults to running the whole range.
-
Export_Pretests
: This allows the program to also print a list of pre-tests that pass the$K^2$ and number of chains tests. The maximum amount of tests exported is given by the macroMAX_PRETEST_EXPORTED
, which defaults to10000
. Takes three possible options:-
Y
: Export pre-tests. -
N
: Do not export pre-tests. -
only
: Only export pre-tests, do not actually test them.
-
-
Pretest_File
: Takes the name of the file where the pre-test information will be dumped.
There are three ways of adding curves. Either as complete fibers, as sections (which in practice can work with any kind of curves, not only sections) and as exceptional curves (or named points). A block of fibers is declared with Fibers:
. A block of sections is declared with Sections(n):
, where n
is a parameter whose meaning is given by the option Sections_Input
. A block of exceptional curves is declared with Name:
or Merge:
.
Additionally, there are two blocks for modifying some information about fibers and curves: MakeFibers:
and ForgetExceptionals:
.
A block ends when another block is declared, or when reaching the end of file. After declaring the first block, it will be impossible to declare further options.
Indentation makes no difference, it is just useful to make it more readable.
Each curve must be declared with a name, and each name must be unique.
-
Fiber
block: Within aFiber
block, fibers are declared. Each fiber declaration consists of two lines. Empty lines or comments are ignored, but the two lines of a fiber declaration must be contiguous, that is, no empty lines or comments may appear in between.The first line consists of the fiber type followed by a possibly empty list of space-separated test options. Fiber types follow Kodaira's notation of normal crossing singular elliptic fibers, namely,
-
I1
for a singular node of self intersection$0$ . Note that this fiber is special in that the curve has a double point. -
In
for a cycle of$n$ curves, each with self intersection$-2$ , for$n = 2,\ldots,18$ . -
In*
for X-shaped trees of$n + 5$ curves, each with self intersection$-2$ , for$n = 0,1,2,3,4$ . -
IV*
,III*
andII*
for the rest of the tree-shaped fibers, where each curve has also self intersection$-2$ .
(Types
II
,III
andIV
may still be declared, but require special treatment discussed later)The next line contains a space-separated list of names, used to identify the curves in the fiber. For cyclical fibers of type
In
, they are given in order. For non cyclical fibers, the order is as follows:-
In*
: The first$n+1$ curves correspond to the chain in the interior of the X-shape in order. The next two curves are the ones intersecting the first curve of the chain. The last two curves are the ones intersecting the last curve of the chain. -
IV*
,III*
andII*
: The first curve is the one with order 3 at the middle. Then come the branches in order from smallest branch to largest branch. Within each branch, the curves are ordered starting from the one intersecting the order 3 curve in the middle.
The options for the fiber in the first line are as follows:
-
Fix
orF
: Within the corresponding test, include every curve in every pre-test. -
Ign
orI
: Within the corresponding test, ignore every curve in every pre-test. -
Try
orT
: Within the corresponding test, try every possibility of including or ignoring each curve. -
Dis
orD
: Within the corresponding test, try every possibility of including or ignoring each curve, but ignore the case when including all of them.
If no options are included, it defaults to
Try
. If a test number is greater than the amount of options given, it defaults to the last option in the list.For example,
Fibers: III* Try Fix Dis A B C D E F G H I2 Dis Fix X Y I1 Z
declares three fibers, and the graph of the
III*
is given byB | E - D - C - A - F - G - H
In the first test, all possibilities for the curves in
III*
andI1
, and only those possibilities including$0$ or$1$ curve from theI2
are tested. Assuming there are no more curves defined, the second test does two sub-tests: One including all curves, and other including all curves except forZ
. The third and further tests always includeX
andY
, tries both possibilities forZ
, and all possibilities for theIII*
, except the case including all of its curves.Curves declared through
Fibers
cannot be declared to intersect other curves (including already defined sections), so fibers should usually be declared at the beginning. -
-
Sections(n)
block: Within aSections
block, (multi-)sections are declared. Each section declaration consists of two lines. Empty lines or comments are ignored, but the two lines of a section declaration must be contiguous, that is, no empty lines or comments may appear in between.The first line consists of the name of the new section followed by a possibly empty list of space-separated options, which can be:
-
Fix
orF
: to include the curve throughout the test. -
Ign
orI
: to ignore the curve throughout the test. -
Try
orT
: to test both possibilities.
If no options are included, it defaults to
Try
. If a test number is greater than the amount of options given, it defaults to the last option in the list.The second line contains a possibly empty list of space-separated names, all of which must correspond to curves already declared, be them part of fibers, other sections or exceptionals, all of which can be repeated. The section itself can be included in the list. Each time it appears, it represents a general double point in the curve, and increase its arithmetic genus by one.
The parameter
n
represents either the self intersection of all sections in the block, or their intersection with the canonical class, depending onSections_Input
. This value is calculated in the original surface$Y$ .For simplicity reasons,
DoubleSections
is a synonym ofSections(0)
(resp.Sections(-2)
) whenSections_Input
isBy_Self_Intersection
(resp.By_Canonical_Intersection
).Also,
Sections
is a synonym ofSections(-1)
. -
-
Name
orMerge
block: Within aName
block, named points are declared (and more generally, a merge operation is performed). The way in which points are named is by blowing up a point (usually an intersection) and naming the exceptional divisor instead. Each name declaration consists of two lines. Empty lines or comments are ignored, but the two lines of a name declaration must be contiguous, that is, no empty lines or comments may appear in between.The first line consists of the name of the new exceptional followed by a possibly empty list of space-separated options, which can be:
-
Fix
orF
: to include the curve throughout the test. -
Ign
orI
: to ignore the curve throughout the test. -
Try
orT
: to test both possibilities.
If no options are included, it defaults to
Try
. If a test number is greater than the amount of options given, it defaults to the last option in the list.The second line contains a possibly empty list of space-separated names, all of which must correspond to curves already declared, be them part of fibers, sections or other exceptionals, all of which can be repeated. An exceptional cannot have double points, thus it is illegal to include the exceptional itself in the list. The curves in the list must intersect each other in a way made precise later.
When the list has at most two curves (possibly both the same one), a normal blow up is done:
- If the list is empty, the blowing up is done at a general point outside all other curves.
- If the list contains only one curve, the blowup is done at a general point inside the curve, decreasing its self intersection by one.
- If the list contains two different curves, these curves are expected to have been intersecting at least one point. The blowup then separates these curves at some intersection and decreases their self intersections.
- If the list only contains a curve twice, the curve is expected to contain at least a double point (for example be a
I1
). The blowup is done at one such double point, solving the singularity and decreasing its self intersection accordingly.
This process is generalized to include more curves by means of a merge operation. Essentially declares that through a point there pass precisely the curves in the list with multiplicities given by the amount of times they appear in the list, where before the operation, those intersections were assumed to be in general position. This declaration makes it so that after blowing up the point and naming the exceptional, all curves in the list intersect the exceptional in general points instead of intersecting each other.
This operation specializes a configuration that was in a more general position, and so we ask that the intersection between the total transforms of pairs of curves remain the same. Thus,
- For every curve
$C$ that appears$a$ times in the list,$C$ must have at least$\frac{a(a-1)}{2}$ double points, which will be solved after the operation. It will end up intersecting the exceptional$a$ times in general points. - For every curve
$C$ that appears$a$ times in the list and every curve$D$ that appears$b$ times, they must intersect at least$a \cdot b$ times. After the operation, they will intersect each other$a \cdot b$ less times.
By realizing the merge operation multiple times, any resolution of plane curve singularity can be achieved. As an example, we can simulate
II
,III
andIV
fibers in the following way:// Fiber of type IV Fibers: I3 A B C Merge: E A B C
The result is given by
A(-3) B(-3) \ / E(-1) | C(-3)
Which correctly represents the log resolution of a
IV
fiber.// Fiber of type III Fibers: I2 A B Merge: E A B F A B E
The result is given by
A(-4) B(-4) \ / F(-1) | E(-2)
Which correctly represents the log resolution of a
III
fiber.// Fiber of type II Fibers: I1 A Merge: E A A F A E G A E F
The result is given by
A(-6) E(-3) \ / G(-1) | F(-2)
Which correctly represents the log resolution of a
II
fiber.Disclaimer: This simulation is still just a trick that fools the computer into working with these fibers. In reality it keeps believing the fibers are of types
I3
,I2
orI1
. A consequence of this is that it will probably give false positives for the effective check in the case ofIV
.Even after blowing up, the parameter
n
ofSections(n)
is a value calculated in the original surface$Y$ , not in the surface after blowups done inName
. -
-
MakeFibers
block: Within aMakeFiber
block, one can declare that a set of previously defined curves form a fiber. Each Make fiber declaration consists of two lines. Empty lines or comments are ignored, but the two lines of a name declaration must be contiguous, that is, no empty lines or comments may appear in between. The contents of these lines have analogous meanings as the contents of aFiber
block declaration. For example, doingSections(-2): A Try B Try A A MakeFibers: I2 Try A B
is effectively the same as
Fibers: I2 Try A B
The type of fiber, in this case
I2
, can be any non empty string, even types not supported by the program. The curves that appear in the declaration of the fiber can be any section or exceptional which was previously defined, except a curve that is already part of a fiber.MakeFiber
does not modify the self intersection of the curves and neither the intersections between curves. It also does not check wether the the given intersections or self intersections are consistent with the type of fiber, thus making this operation quite flexible. TheTry/Ignore/Fix
attribute of each curve is overwritten with the attribute given by the new fiber declaration. If an exceptional curve is part of aMakeFiber
declaration, then its status as exceptional is forgotten in the sense ofForgetExceptional
. -
ForgetExceptionals
block: Within aForgetExceptional
block, curves previously defined in amerge/name
block are stripped of their status as exceptional curves and become equivalent as other curves or sections. This means that they are not taken into account in the Nef and Obstruction check. They are not contracted if within a sub-test they are an isolated (-1)-curve.Each
ForgetExceptional
declaration consists of a single line. Each line consists of a list of space separated names, which correspond to exceptionals that are to be forgotten.
Testing cannot start if there are curves with double points. Every singularity must be solved.
Several test files are provided in this repository as examples of test files.
This checks for
As long as every complete fiber is of type In
, this should not give false positives.
This checks for nef-ness of
This checks if the global obstruction for smoothing the singularities in
- At most two complete fibers are included in the example.
- after all blowups as declared by
Merge
operations, every curve that is not exceptional or fiber has self intersection at least$-1$ .
Sometimes it is useful to know why the discrepancy is not zero. Therefore if Obstruction_Check
is set to print
, whenever an example fails this check, the number of complete fibers in the configuration is also included in the summary.
As long as every complete fiber is of type In
, this should not give false positives. It could however give many false negatives, specially when dealing with infinitely near blowups.
Note that all three checks really only make sense when the original surface is an elliptic surface with sections, under the assumption that every fiber component is declared in the a Fiber
block. This program could be used in a more abstract setting, but the three checks would become invalid.
It is sometimes useful to know if the curves in the sub-configuration are linearly independent, so the intersection matrix of all curves in the sub-test and its determinant are included when running Display.py
.
About the exhaustiveness of the search, some restrictions are taken: The original aim is to find Wahl singularities with effective / ample canonical class, then blowing up non singular points in the configuration would immediately invalidate that example. Also, no examples will appear that have a (-1)-curve intersecting both ends of a Wahl chain. These conditions are used extensively during the search, so possible examples that require wilder blowing up would not be found.