Self-similar singular solutions to the nonlinear Schrödinger and the complex Ginzburg-Landau equation
This repository contains the code for the computer-assisted parts of the proofs for the paper Self-similar singular solutions to the nonlinear Schrödinger and the complex Ginzburg-Landau equation.
The results of the paper are presented in 5 different
Pluto.jl notebooks, found in the
proof directory. These notebooks are responsible for
generating all the numbers and figures that appear in the paper. It is
possible to view the results of notebooks without running any code by
opening the corresponding HTML files found in the proof
directory. They can be opened in any browser such as Firefox. The five
notebooks are:
NLS-example.jl- This is the notebook version of Section 5.1 in the paper, and contains a detailed walkthrough of the proof of the existence of a self-similar singular solution to the 3D cubic NLS equation. The notebook follows the same layout as Section 5.1, but includes a bit more detail that is related to the evaluation of the code. All numbers and figures in Section 5.1 are from this notebook.NLS.jl- This notebook contains the full results for the NLS equation. Theorems 3.1, 3.2 and 3.3 as well as Tables 1 and 2 in Section 3 are based on this notebook.CGL-example.jl- The CGL version ofNLS-example.jl, it corresponds to Section 6.1 in the paper. All numbers and figures in Section 6.1 are from this notebook.CGL.jl- The CGL version ofNLS.jl, it presents the full results for the CGL equation. The results of Theorems 4.1 and 4.4, as well as all the figures in Sections 4 and 6.2 are from this notebook.CGL-pointwise.jl- This notebook gives pointwise results for the branches of the CGL equation in Case II. It corresponds to Section 9 in the paper.
The example notebooks, NLS-example.jl and CGL-example.jl, contain
a fairly detailed description of the computations performed, generally
following the same structure as the corresponding sections in the
paper. The other notebooks are primarily concerned with generating the
results and corresponding figures, and contain much less prose.
Explanations of the data and figures they generate are found in the
paper.
The proofs were generated with Julia version 1.12.6. This repository
contains the same Manifest.toml file as was used when running the
proofs; this allows installing exactly the same versions of the Julia
packages. Part of the computations are done using the C++ library
CAPD. There is no Julia package
wrapping the CAPD library, and programs therefore have to be compiled
outside of Julia, which complicates the setup process. Information
about how to install CAPD and compile the required code is found in
CAPD/README.md.
Once CAPD has been installed and the required programs compiled, the Julia part of the code can be set up by starting Julia from this directory and running
using Pkg
Pkg.activate(".")
Pkg.instantiate()This will likely take some time the first time you run it since it has
to download and compile all the packages. You can see if it seems to
work by running Pkg.test(). If the tests run successfully then you
should be good to go!
The proofs for the NLS equation require a relatively small amount of
computational time, and all of the computations are performed inside
the notebooks NLS-example.jl and NLS.jl (found in the proof
directory). To run the notebooks you first need to start Pluto.
Starting Julia from this directory, you can run
using Pkg
Pkg.activate(".")
using Pluto
Pluto.run()which should open a Pluto tab in your browser. Now you can open the
notebooks inside the proof directory through this and it should run
the proof. In the NLS-example.jl notebook, a lot of the intermediate
steps in the computations are shown and explained. For the NLS.jl
notebook only final results are presented.
The proofs for the CGL equation require significantly more
computational time, and it would not be feasible to do all of the
computations inside of the notebooks. The computations are instead run
on a separate HPC system, the output of these computations is then
saved and stored in the proof/data directory. The notebooks read
this precomputed data and generate the figures and numbers that
appear in the paper. In the case of the CGL-example.jl notebook, a
small part of the computations is also performed in the notebook, to
show what it looks like.
The procedure for generating the precomputed data is found in
HPC/README.md.
The code in this repository is spread out over four directories:
src/- This directory contains the vast majority of the code (around 10000 lines of code, though a large part of that is documentation). More information about it is given below.CAPD/src/- This directory contains the CAPD code, more information about it is found inCAPD/README.md.HPC/scripts/- This directory contains the scripts that are used for running computations on an HPC system. It is primarily glue code and does not handle any actual computations.proof/- As mentioned, this directory contains the notebooks. The code implemented here is primarily for presenting the generated results.
Some good information to have:
- Some of the parameters are fixed throughout the computations; these
are
$d$ ,$\omega$ ,$\sigma$ and$\delta$ . Their values depend on if we are considering Case I or Case II in the paper (though the code supports other values than that). To simplify the code, we store all of these in a struct,CGLParams, which is passed around under the nameΛ. - Many of the implemented functions contain documentation that
explains what they do. These occasionally refer to equations or
lemmas in the paper. For these references we use the notation "REF",
e.g., "Lemma REF(lemma:U)". We use labels, e.g.,
lemma:U, rather than numbers to make it easier to keep the code and the paper in sync. The labels are not directly seen in the PDF version of the paper, but can be accessed by downloading the LaTeX code for the paper from ArXiv. - Many of the functions have associated tests in
testthat serve to increase the confidence in the implementation. All of these tests can be run withPkg.test()as discussed above.
The parts of the code responsible for generating the proofs are found
in src/ and CAPD/src/. The CAPD code is, as mentioned, discussed
in CAPD/README.md. We here go through the code in
the src/ directory. The directory consists of 5
subdirectories
as well as a number of separate files found directly in src/.
Let us go through the most important parts.
-
CGLBranch/- This directory contains the BifurcationKit.jl code used for computing numerical approximations of the branches and is completely self-contained (it is implemented as a submodule). It supports computing the branches using both$\epsilon$ and$\kappa$ as continuation parameters, as well as two different approaches for approximating$Q_\infty$ . The paper only makes use of the continuation in$\epsilon$ and one of the approaches for approximating$Q_\infty$ ; the other versions were used in the development phase. -
Q_zero/- This directory is related to Section 8 in the paper and contains all the Julia code used for evaluating$Q_0$ . It consists of 5 files-
Q_zero/equation.jl- Implements the equation for the ODE as well as the recursion for computing the coefficients of the Taylor expansion. -
Q_zero/Q_float.jl- Contains the implementation of the non-rigorous evaluation of$Q_0$ . -
Q_zero/Q_taylor.jl- Contains the code for enclosing$Q_0$ using the Taylor expansion at zero. -
Q_zero/Q_capd.jl- Contains the Julia code that is responsible for calling the CAPD code, which then computes enclosures of$Q_0$ . -
Q_zero/Q.jl- Defines wrapper methods that call either theQ_float.jlmethods orQ_capd.jlmethods depending on the type of the input. This is the interface that is primarily used by the other parts of the code. It defines the functionsQ_zero,Q_zero_jacobian_kappaandQ_zero_jacobian_epsilon.
-
-
Q_infinity/- The Julia code used for evaluating$Q_\infty$ is found in this directory. It consists of 9 files, and is the most delicate part of the code.-
Q_infinity/parameters.jl- Contains code for computing$a$ ,$b$ ,$c$ ,$B_W$ ,$B_{W,\kappa}$ and$B_{W,\epsilon}$ . -
Q_infinity/functions.jl- Contains code for evaluating$P(\xi)$ ,$E(\xi)$ and related functions. The functions follow the same naming scheme as in the paper, with the derivatives denoted by a postfix, for example, the functionP_dξ_dξ_dκis used to compute$P_\kappa''$ . -
Q_infinity/function_bounds.jl- Responsible for computing the bounds that occur in Lemma 7.3 in the paper. The bounds are collected into one structC::FunctionBounds, from which the bounds can be accessed. For example,C.E_dξ_dξ_dξcorresponds to$C_{E'''}$ in the paper. -
Q_infinity/I_bounds.jl- The bounds from Sections 7.3.2 and 7.3.3 in the paper are implemented here. The bounds are collected into one structCI::IBounds, from which the bounds can be accessed. For example,CI.I_P_2_4corresponds to$C_{I_P,2,4}$ in the paper. -
Q_infinity/norm_bounds.jlandQ_infinity/norm_bounds_constants.jl- Contain the code for computing initial bounds of the norms of$Q_\infty$ and its derivatives. The bounds are collected into one structnorms::NormBounds, from which the bounds can be accessed. For example,norms.Q_dϵ_dξis a bound for $|Q_\epsilon'|\mathrm{v}$. For $|Q|\mathrm{v}$, the bounds are based on the fixed-point approach in Section 7.2. The other bounds are based on the results in Section 7.3.3. The constants are given inQ_infinity/norm_bounds_constants.jland the bounds are computed inQ_infinity/norm_bounds.jl. -
Q_infinity/I_P.jl- This code computes enclosures, not only bounds, for$I_P$ ,$I_{P,\gamma}$ ,$I_{P,\kappa}$ , and$I_{P,\epsilon}$ . It is based on the approach discussed in Section 7.3.4. -
Q_infinity/Q.jl- Puts all of the above code together to compute enclosures for$Q$ and its Jacobian. It defines the functionsQ_infinity,Q_infinity_jacobian_kappaandQ_infinity_jacobian_epsilon. -
Q_infinity/verify_monotonicity.jl- Implements the check for monotonicity on the interval$(\xi_2, \infty)$ that is described in Section 5.1. In particular it implements the bounds found in Section 7.4.
-
-
branch/- This directory contains the main logic for extending the methods applied to the NLS equation to handle the branches for the CGL equation. A lot of the code is tasked with handling dynamic bisection and distributing tasks to workers. It is structured to allow for efficient computations on an HPC cluster.-
branch/branch_points.jl- Handles pointwise verification along the branches. The results in Section 9 are produced with this. -
branch/branch_existence.jlandbranch/branch_segment_existence.jl- Dynamically splits the branches into small segments and proves local existence for each segment. -
branch/branch_continuation.jl- Takes the output ofbranch/branch_existence.jland checks that the segments can be joined together into one continuous curve, bisects segments further if required. -
branch/branch_critical_points.jl- Takes the output ofbranch/branch_continuation.jland computes the number of critical points for each segment. -
branch/proof_witness.jl- Responsible for taking the output of all above parts and joining it into one dataset that contains all the data that is required for the proofs. -
branch/data_handling.jl- Contains functions for creating, writing and reading dataframes containing the produced data.
-
-
orchestration/- Contains a significant amount of gluing code to make calling the functions inbranch/simpler. In particular these functions handle loading of precomputed data as well as formatting and storing the output. They are primarily intended to be used through the HPC interface, seeHPC/README.md. - The files in the root of the
src/directory handle a wide variety of tasks.-
arb.jl,helper.jl,special-functions.jl- These files implement a variety of convenience functions, such as formatting of output and progress logging, as well as some basic mathematical functions such as the rising factorial. -
verify_and_refine_root.jl- Implements the functions related to the interval Newton method. See the individual functions documentation for more details. -
U.jl,U_expansion.jl- Implements evaluation and expansion of the confluent hypergeometric function$U$ . In particular this makes use of the bounds from Lemmas 7.1 and 7.2. -
CGLParams.jl- Defines the typeCGLParamsthat is used for storing the parameters that are held fixed throughout the computations, that is$d$ ,$\omega$ ,$\sigma$ and$\delta$ . It also contains code to generate the initial guesses for the NLS equation. -
refine_approximation.jl- Contains the code for non-rigorous refinement of initial approximations. -
G.jl- Contains the code for enclosing the function$G$ . -
G_solve.jl- Wrapper functions for computing roots of$G$ with the help of functions fromverify_and_refine_root.jl. -
count_critical_points.jl- The procedure that is detailed in Section 5.1 for counting the number of critical points of$|Q|$ is implemented here.
-
Here are some incomplete, but potentially helpful, diagrams showing some of the dependencies in the code.
Dependencies of G_solve.jl:
graph TD;
Q_zero/Q.jl --> G.jl
Q_infinity/Q.jl --> G.jl
G.jl --> G_solve.jl
verify_and_refine_root.jl --> G_solve.jl