diff --git a/.github/workflows/Docstrings.yml b/.github/workflows/Docstrings.yml
new file mode 100644
index 000000000000..c3ae6a2f5780
--- /dev/null
+++ b/.github/workflows/Docstrings.yml
@@ -0,0 +1,29 @@
+name: docstring test
+
+on:
+ push:
+ branches:
+ - master
+ - 'release-*'
+ pull_request:
+ workflow_dispatch:
+
+concurrency:
+ # group by workflow and ref; the last slightly strange component ensures that for pull
+ # requests, we limit to 1 concurrent job, but for the master branch we don't
+ group: ${{ github.workflow }}-${{ github.ref }}-${{ github.ref != 'refs/heads/master' || github.run_number }}
+ # Cancel intermediate builds, but only if it is a pull request build.
+ cancel-in-progress: ${{ startsWith(github.ref, 'refs/pull/') }}
+
+jobs:
+ check-docstrings:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+ - uses: julia-actions/setup-julia@v2
+ - uses: julia-actions/cache@v2
+ - name: Build package
+ uses: julia-actions/julia-buildpkg@v1
+ - name: 'Check issues in docstrings'
+ run: |
+ julia --project=. -e 'using Oscar; include("etc/check_docstrings.jl")'
diff --git a/CITATION.cff b/CITATION.cff
index ae3fec3e3f8e..91973eafb428 100644
--- a/CITATION.cff
+++ b/CITATION.cff
@@ -41,7 +41,6 @@ preferred-citation:
interested researchers from graduate students through established
experts.
year: 2024
- month: 8
edition: 1
issn: "1431-1550"
url: "https://link.springer.com/book/9783031621260"
diff --git a/LICENSE.md b/LICENSE.md
index d5ab55d1895a..2faf769ff70e 100644
--- a/LICENSE.md
+++ b/LICENSE.md
@@ -1,6 +1,11 @@
The Oscar.jl package is licensed under the GNU Public License, Version 3.0+:
-> Copyright (c) 2019 The OSCAR Development Team.
+> Copyright (c) 2019-2024 The OSCAR Development Team
+>
+> See for a list of OSCAR
+> Development Team members. Note that this list may occasionally be slightly
+> outdated. Additional contributors may be found in the `git log` of the main
+> OSCAR repository and other related repositories.
> This program is free software: you can redistribute it and/or modify
> it under the terms of the GNU General Public License as published by
> the Free Software Foundation, either version 3 of the License, or
diff --git a/Project.toml b/Project.toml
index 2af6c6f1974b..c5b2f30b3504 100644
--- a/Project.toml
+++ b/Project.toml
@@ -1,7 +1,7 @@
name = "Oscar"
uuid = "f1435218-dba5-11e9-1e4d-f1a5fab5fc13"
authors = ["The OSCAR Team "]
-version = "1.2.0-DEV"
+version = "1.3.0-DEV"
[deps]
AbstractAlgebra = "c3fe647b-3220-5bb0-a1ea-a7954cac585d"
@@ -25,11 +25,11 @@ UUIDs = "cf7118a7-6976-5b1a-9a39-7adc72f591a4"
cohomCalg_jll = "5558cf25-a90e-53b0-b813-cadaa3ae7ade"
[compat]
-AbstractAlgebra = "0.43.7"
+AbstractAlgebra = "0.43.11"
AlgebraicSolving = "0.8.0"
Distributed = "1.6"
GAP = "0.12.0"
-Hecke = "0.34.3"
+Hecke = "0.34.7"
JSON = "^0.20, ^0.21"
JSON3 = "1.13.2"
LazyArtifacts = "1.6"
diff --git a/README.md b/README.md
index 3936e5575f81..70f0b3d3033a 100644
--- a/README.md
+++ b/README.md
@@ -37,7 +37,7 @@ julia> using Oscar
/ _ \ / ___| / ___| / \ | _ \ | Combining ANTIC, GAP, Polymake, Singular
| | | |\___ \| | / _ \ | |_) | | Type "?Oscar" for more information
| |_| | ___) | |___ / ___ \| _ < | Manual: https://docs.oscar-system.org
- \___/ |____/ \____/_/ \_\_| \_\ | Version 1.2.0-DEV
+ \___/ |____/ \____/_/ \_\_| \_\ | Version 1.3.0-DEV
julia> k, a = quadratic_field(-5)
(Imaginary quadratic field defined by x^2 + 5, sqrt(-5))
@@ -70,34 +70,28 @@ Free module of rank 1 over R
julia> s = sub(F, [f*F[1]])[1]
Submodule with 1 generator
-1 -> (x1^2 + x2)*e[1]
-represented as subquotient with no relations.
+ 1: (x1^2 + x2)*e[1]
+represented as subquotient with no relations
julia> H, mH = hom(s, quo(F, s)[1])
-(hom of (s, Subquotient of
-1 -> e[1]
-by
-1 -> (x1^2 + x2)*e[1]), Map: H -> set of all homomorphisms from s to subquotient of Submodule with 1 generator
-1 -> e[1]
-by Submodule with 1 generator
-1 -> (x1^2 + x2)*e[1])
+(hom of (s, Subquotient of submodule with 1 generator
+ 1: e[1]
+by submodule with 1 generator
+ 1: (x1^2 + x2)*e[1]), Map: H -> set of all homomorphisms from s to subquotient of submodule with 1 generator
+ 1: e[1]
+by submodule with 1 generator
+ 1: (x1^2 + x2)*e[1])
julia> mH(H[1])
-Map with following data
-Domain:
-=======
-Submodule with 1 generator
-1 -> (x1^2 + x2)*e[1]
-represented as subquotient with no relations.
-Codomain:
-=========
-Subquotient of Submodule with 1 generator
-1 -> e[1]
-by Submodule with 1 generator
-1 -> (x1^2 + x2)*e[1]
+Module homomorphism
+ from s
+ to subquotient of submodule with 1 generator
+ 1: e[1]
+ by submodule with 1 generator
+ 1: (x1^2 + x2)*e[1]
```
-Of course, the cornerstones are also available directly:
+Of course, the cornerstones are also available directly. For example:
```
julia> C = Polymake.polytope.cube(3);
@@ -120,7 +114,7 @@ pm::Array >
If you have used OSCAR in the preparation of a paper please cite it as described below:
[OSCAR]
- OSCAR -- Open Source Computer Algebra Research system, Version 1.2.0-DEV,
+ OSCAR -- Open Source Computer Algebra Research system, Version 1.3.0-DEV,
The OSCAR Team, 2024. (https://www.oscar-system.org)
[OSCAR-book]
Wolfram Decker, Christian Eder, Claus Fieker, Max Horn, Michael Joswig, eds.
@@ -133,7 +127,7 @@ If you are using BibTeX, you can use the following BibTeX entries:
key = {OSCAR},
organization = {The OSCAR Team},
title = {OSCAR -- Open Source Computer Algebra Research system,
- Version 1.2.0-DEV},
+ Version 1.3.0-DEV},
year = {2024},
url = {https://www.oscar-system.org},
}
@@ -147,7 +141,6 @@ If you are using BibTeX, you can use the following BibTeX entries:
volume = {32},
edition = {1},
url = {https://link.springer.com/book/9783031621260},
- month = {8},
issn = {1431-1550},
}
diff --git a/docs/Project.toml b/docs/Project.toml
index 07d7ae149a80..6dad0075f817 100644
--- a/docs/Project.toml
+++ b/docs/Project.toml
@@ -1,7 +1,9 @@
[deps]
Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4"
DocumenterCitations = "daee34ce-89f3-4625-b898-19384cb65244"
+JSON = "682c06a0-de6a-54ab-a142-c8b1cf79cde6"
[compat]
Documenter = "1.1"
DocumenterCitations = "~1.3.4"
+JSON = "0.21.4"
diff --git a/docs/doc.main b/docs/doc.main
index 4d16abb281b3..7dcbde1f057d 100644
--- a/docs/doc.main
+++ b/docs/doc.main
@@ -198,6 +198,7 @@
],
"Surfaces" => [
"AlgebraicGeometry/Surfaces/K3Surfaces.md",
+ "AlgebraicGeometry/Surfaces/EllipticSurface.md",
"AlgebraicGeometry/Surfaces/AdjunctionProcess.md",
"AlgebraicGeometry/Surfaces/ParametrizationSurfaces.md",
"AlgebraicGeometry/Surfaces/SurfacesP4.md",
diff --git a/docs/make_work.jl b/docs/make_work.jl
index b3a0aec16741..91efab27a67c 100644
--- a/docs/make_work.jl
+++ b/docs/make_work.jl
@@ -4,7 +4,7 @@
#
module BuildDoc
-using Documenter, DocumenterCitations
+using Documenter, DocumenterCitations, JSON
include("documenter_helpers.jl")
include("citation_style.jl")
@@ -210,6 +210,56 @@ function doit(
dstbase = normpath(Oscar.oscardir, "docs", "src", string(nameof(pkg)))
rm(dstbase; recursive=true, force=true)
end
+
+ # postprocessing, for the search index
+ docspath = normpath(joinpath(Oscar.oscardir, "docs"))
+ @info "Patching search index."
+ # extract valid json from search_index.js
+ run(pipeline(`sed -n '2p;3q' $(joinpath(docspath, "build", "search_index.js"))`, stdout=(joinpath(docspath, "build", "search_index.json")))) # imperfect file, but JSON parses it
+
+ # extract paths from doc.main
+ filelist=String[]
+ docmain = include(joinpath(docspath, "doc.main"))
+ while !isempty(docmain)
+ n = pop!(docmain)
+ if n isa Pair
+ push!(docmain, last(n))
+ elseif n isa String
+ push!(filelist, n)
+ elseif n isa Array{String}
+ append!(filelist,n)
+ elseif n isa Array
+ append!(docmain,n)
+ else
+ error("err: $(typeof(n))")
+ end
+ end
+ suffix = local_build ? ".html" : "/"
+ filelist = replace.(filelist, r"\.md$"=>suffix)
+
+ # read these files
+ iosearchindex = open(joinpath(docspath, "build", "search_index.json"), "r")
+ searchindex = JSON.parse(iosearchindex)
+ close(iosearchindex)
+
+ newsearchindex = []
+
+ for item in searchindex
+ if split(item["location"], "#")[1] in filelist
+ push!(newsearchindex, item)
+ end
+ end
+
+
+ # combine this to valid javascript again, and overwrite input
+ ionewsearchindex = open(joinpath(docspath, "build", "search_index.js"), "w")
+ write(ionewsearchindex, """var documenterSearchIndex = {"docs":\n""")
+ JSON.print(ionewsearchindex, newsearchindex)
+ write(ionewsearchindex, "\n}")
+ close(ionewsearchindex)
+
+ # clean up
+ rm(joinpath(docspath, "build", "search_index.json"))
end
end # module BuildDoc
diff --git a/docs/oscar_references.bib b/docs/oscar_references.bib
index c6e93053f394..9f4ea57cbe04 100644
--- a/docs/oscar_references.bib
+++ b/docs/oscar_references.bib
@@ -34,7 +34,7 @@ @Article{AG10
number = {1},
pages = {3--24},
year = {2010},
- eprint = {0810.1148}
+ doi = {10.1070/SM2010v201n01ABEH004063}
}
@InProceedings{AGK96,
@@ -155,6 +155,7 @@ @InProceedings{BDLP19
booktitle = {MEGA 2019 - International Conference on Effective Methods in Algebraic Geometry},
address = {Madrid, Spain},
year = {2019},
+ doi = {10.1016/j.jsc.2020.07.007},
archiveprefix = {HAL},
eprint = {hal-02912148}
}
@@ -171,6 +172,19 @@ @Article{BDLPSS13
doi = {10.1016/j.jsc.2012.07.002}
}
+@Article{BE23,
+ author = {Brandhorst, Simon and Elkies, Noam D.},
+ title = {Equations for a K3 Lehmer map},
+ mrnumber = {4652575},
+ journal = {J. Algebraic Geom.},
+ fjournal = {Journal of Algebraic Geometry},
+ volume = {32},
+ number = {4},
+ pages = {641--675},
+ year = {2023},
+ doi = {10.1090/jag/810}
+}
+
@Misc{BEO23,
author = {Besche, Hans Ulrich and Eick, Bettina and O'Brien, Eamonn},
title = {SmallGrp, The GAP Small Groups Library, Version 1.5.3},
@@ -193,13 +207,17 @@ @InProceedings{BES-E-D21
location = {Virtual Event, Russian Federation}
}
-@Misc{BES19,
+@Article{BES23,
author = {Backman, Spencer and Eur, Christopher and Simpson, Connor},
title = {Simplicial generation of Chow rings of matroids},
- year = {2019},
- eprint = {1905.07114},
- archiveprefix = {arXiv},
- primaryclass = {math.CO}
+ journal = {JEMS},
+ fjournal = {Journal of the European Mathematical Society},
+ volume = {26},
+ number = {11},
+ pages = {4491--4535},
+ year = {2023},
+ month = jun,
+ doi = {10.4171/jems/1350}
}
@Book{BGV03,
@@ -236,13 +254,15 @@ @Article{BH23
doi = {10.1017/fms.2023.50}
}
-@Misc{BHMPW20,
+@Article{BHMPW22,
author = {Braden, Tom and Huh, June and Matherne, Jacob P. and Proudfoot, Nicholas and Wang, Botong},
title = {A semi-small decomposition of the Chow ring of a matroid},
- year = {2020},
- eprint = {2002.03341},
- archiveprefix = {arXiv},
- primaryclass = {math.AG}
+ journal = {Advances in Mathematics},
+ volume = {409},
+ pages = {108646},
+ year = {2022},
+ month = nov,
+ doi = {10.1016/j.aim.2022.108646}
}
@Book{BHPV-D-V04,
@@ -254,6 +274,7 @@ @Book{BHPV-D-V04
publisher = {Berlin: Springer},
edition = {2nd enlarged ed.},
year = {2004},
+ doi = {10.1007/978-3-642-57739-0},
fseries = {Ergebnisse der Mathematik und ihrer Grenzgebiete. 3. Folge},
language = {English},
zbmath = {2008523}
@@ -357,6 +378,15 @@ @Article{BS09
doi = {10.1016/j.aim.2009.06.009}
}
+@Misc{BZ23,
+ author = {Brandhorst, Simon and Zach, Matthias},
+ title = {Elliptic fibrations on Vinberg's most algebraic K3 surface},
+ year = {2023},
+ eprint = {2311.11766},
+ archiveprefix = {arXiv},
+ primaryclass = {math.AG}
+}
+
@Book{Ben93,
author = {Benson, David J.},
title = {Polynomial invariants of finite groups},
@@ -364,7 +394,8 @@ @Book{Ben93
volume = {190},
address = {Cambridge},
publisher = {Cambridge University Press},
- year = {1993}
+ year = {1993},
+ doi = {10.1017/CBO9780511565809}
}
@MastersThesis{Bhm99,
@@ -409,14 +440,15 @@ @Article{Bis96
doi = {10.1112/S0025579300011773}
}
-@Book{Bur55,
+@Book{Bur11,
author = {Burnside, W.},
title = {Theory of groups of finite order},
mrnumber = {69818},
note = {2d ed},
publisher = {Dover Publications, Inc., New York},
pages = {xxiv+512},
- year = {1955}
+ year = {1911},
+ doi = {10.1017/CBO9781139237253}
}
@Book{C-MLS20,
@@ -625,6 +657,18 @@ @Article{Cor21
doi = {10.1007/s00029-021-00679-6}
}
+@Book{Cut04,
+ author = {Cutkosky, Steven Dale},
+ title = {Resolution of singularities},
+ mrnumber = {2058431},
+ series = {Graduate Studies in Mathematics},
+ volume = {63},
+ publisher = {American Mathematical Society, Providence, RI},
+ pages = {viii+186},
+ year = {2004},
+ doi = {10.1090/gsm/063}
+}
+
@InCollection{DE02,
author = {Decker, Wolfram and Eisenbud, David},
title = {Sheaf algorithms using the exterior algebra},
@@ -633,6 +677,7 @@ @InCollection{DE02
publisher = {Berlin: Springer},
pages = {215--249},
year = {2002},
+ doi = {10.1007/978-3-662-04851-1_9},
language = {English},
zbmath = {1693054}
}
@@ -742,7 +787,8 @@ @Article{DK17
fjournal = {Journal of Algebra},
volume = {472},
pages = {546--572},
- year = {2017}
+ year = {2017},
+ doi = {10.1016/j.jalgebra.2016.10.042}
}
@Book{DL06,
@@ -803,6 +849,7 @@ @Book{DSS09
volume = {39},
publisher = {Basel: Birkhäuser},
year = {2009},
+ doi = {10.1007/978-3-7643-8905-5},
fseries = {Oberwolfach Seminars},
language = {English},
zbmath = {5303649}
@@ -1001,10 +1048,24 @@ @InProceedings{FLINT
publisher = {Springer-Verlag},
pages = {88--91},
year = {2010},
+ doi = {10.1007/978-3-642-15582-6_18},
location = {Kobe, Japan},
numpages = {4}
}
+@Article{FRS21,
+ author = {Frühbis-Krüger, Anne and Ristau, Lukas and Schober, Bernd},
+ title = {Embedded desingularization for arithmetic surfaces---toward a parallel implementation},
+ mrnumber = {4273121},
+ journal = {Math. Comp.},
+ fjournal = {Mathematics of Computation},
+ volume = {90},
+ number = {330},
+ pages = {1957--1997},
+ year = {2021},
+ doi = {10.1090/mcom/3624}
+}
+
@Article{FY04,
author = {Feichtner, Eva Maria and Yuzvinsky, Sergey},
title = {Chow rings of toric varieties defined by atomic lattices},
@@ -1050,7 +1111,8 @@ @Book{Ful97
note = {With applications to representation theory and geometry},
publisher = {Cambridge University Press, Cambridge},
pages = {x+260},
- year = {1997}
+ year = {1997},
+ doi = {10.1017/CBO9780511626241}
}
@Book{Ful98,
@@ -1087,7 +1149,8 @@ @InProceedings{GHJ16
address = {Cham},
publisher = {Springer International Publishing},
pages = {403--410},
- year = {2016}
+ year = {2016},
+ doi = {10.1007/978-3-319-42432-3_50}
}
@Article{GIR96,
@@ -1133,7 +1196,8 @@ @InProceedings{GK14
booktitle = {Proceedings of the fifteenth ACM conference on Economics and computation},
publisher = {Association for Computing Machinery, New York},
pages = {259--276},
- year = {2014}
+ year = {2014},
+ doi = {10.1145/2600057.2602883}
}
@Book{GLS07,
@@ -1347,6 +1411,30 @@ @Book{Har77
doi = {10.1007/978-1-4757-3849-0}
}
+@Article{Has37,
+ author = {Hasse, H.},
+ title = {Noch eine Begründung der Theorie der höheren Differentialquotienten in einem algebraischen
+ Funktionenkörper einer Unbestimmten. (Nach einer brieflichen Mitteilung von F. K. Schmidt in Jena)},
+ mrnumber = {1581557},
+ journal = {J. Reine Angew. Math.},
+ fjournal = {Journal für die Reine und Angewandte Mathematik. [Crelle's Journal]},
+ volume = {177},
+ pages = {215--237},
+ year = {1937},
+ doi = {10.1515/crll.1937.177.215}
+}
+
+@Article{Haz12,
+ author = {Hazewinkel, Michiel},
+ title = {Hasse-Schmidt Derivations and the Hopf Algebra of Non-Commutative Symmetric Functions},
+ journal = {Axioms},
+ volume = {1},
+ number = {2},
+ pages = {149--154},
+ year = {2012},
+ doi = {10.3390/axioms1020149}
+}
+
@Article{Hul22,
author = {Hulpke, Alexander},
title = {The perfect groups of order up to two million},
@@ -1418,7 +1506,8 @@ @Article{JKS22
number = {4},
publisher = {SIAM},
pages = {711--739},
- year = {2022}
+ year = {2022},
+ doi = {10.1137/21M1441286}
}
@Article{JLLT22,
@@ -1522,7 +1611,8 @@ @Book{Jos21
volume = {219},
address = {Providence, RI},
publisher = {American Mathematical Society},
- year = {2021}
+ year = {2021},
+ doi = {10.1090/gsm/219}
}
@Article{Jow11,
@@ -1616,7 +1706,8 @@ @InCollection{KS99
volume = {173},
publisher = {Birkhäuser, Basel},
pages = {267--285},
- year = {1999}
+ year = {1999},
+ doi = {10.1007/978-3-0348-8716-8_17}
}
@Article{Kah10,
@@ -1692,6 +1783,7 @@ @Book{Kol13
note = {With a collaboration of Sándor Kovács},
publisher = {Cambridge University Press},
year = {2013},
+ doi = {10.1017/CBO9781139547895},
location = {Cambridge}
}
@@ -1774,7 +1866,8 @@ @Book{Loo84
volume = {77},
publisher = {Cambridge University Press, Cambridge},
pages = {xi+200},
- year = {1984}
+ year = {1984},
+ doi = {10.1017/CBO9780511662720}
}
@Misc{MNP24,
@@ -1834,7 +1927,8 @@ @Book{MS15
volume = {161},
publisher = {Providence, RI: American Mathematical Society (AMS)},
pages = {xii + 363},
- year = {2015}
+ year = {2015},
+ doi = {10.1090/gsm/161}
}
@Book{MS21,
@@ -2012,7 +2106,8 @@ @Article{Pos09
number = {6},
publisher = {OUP},
pages = {1026--1106},
- year = {2009}
+ year = {2009},
+ doi = {10.1093/imrn/rnn153}
}
@Article{Pos18,
@@ -2048,13 +2143,14 @@ @Article{RR10
doi = {10.1063/1.3501135}
}
-@Article{RSS03,
+@InBook{RSS03,
author = {Rote, Günter and Santos, Francisco and Streinu, Ileana},
title = {Expansive motions and the polytope of pointed pseudo-triangulations},
- journal = {Discrete and Computational Geometry: The Goodman-Pollack Festschrift},
+ booktitle = {Discrete and Computational Geometry},
publisher = {Springer},
pages = {699--736},
- year = {2003}
+ year = {2003},
+ doi = {10.1007/978-3-642-55566-4_33}
}
@Article{Rin13,
@@ -2078,6 +2174,7 @@ @Book{SS03
volume = {24},
publisher = {Oxford University Press},
year = {2003},
+ doi = {10.1093/oso/9780198509424.001.0001},
fseries = {Oxford Lecture Series in Mathematics and its Applications}
}
@@ -2093,6 +2190,19 @@ @Article{SS12
doi = {10.1016/j.jcta.2011.12.005}
}
+@Book{SS19,
+ author = {Schütt, Matthias and Shioda, Tetsuji},
+ title = {Mordell-Weil lattices},
+ mrnumber = {3970314},
+ series = {Ergebnisse der Mathematik und ihrer Grenzgebiete. 3. Folge. A Series of Modern Surveys in Mathematics
+ [Results in Mathematics and Related Areas. 3rd Series. A Series of Modern Surveys in Mathematics]},
+ volume = {70},
+ publisher = {Springer, Singapore},
+ pages = {xvi+431},
+ year = {2019},
+ doi = {10.1007/978-981-32-9301-4}
+}
+
@Article{SV-D-V87,
author = {Sommese, Andrew John and Van de Ven, A.},
title = {On the adjunction mapping},
@@ -2191,7 +2301,8 @@ @Article{Sta79
volume = {1},
number = {3},
pages = {475--511},
- year = {1979}
+ year = {1979},
+ doi = {10.1090/S0273-0979-1979-14597-X}
}
@Misc{Stacks,
diff --git a/docs/src/AlgebraicGeometry/AlgebraicSets/AffineAlgebraicSet.md b/docs/src/AlgebraicGeometry/AlgebraicSets/AffineAlgebraicSet.md
index e32762182099..0b9e522514dc 100644
--- a/docs/src/AlgebraicGeometry/AlgebraicSets/AffineAlgebraicSet.md
+++ b/docs/src/AlgebraicGeometry/AlgebraicSets/AffineAlgebraicSet.md
@@ -1,9 +1,6 @@
```@meta
CurrentModule = Oscar
-```
-
-```@setup oscar
-using Oscar
+DocTestSetup = Oscar.doctestsetup()
```
# Affine Algebraic Sets
diff --git a/docs/src/AlgebraicGeometry/AlgebraicSets/ProjectiveAlgebraicSet.md b/docs/src/AlgebraicGeometry/AlgebraicSets/ProjectiveAlgebraicSet.md
index f127036cb3df..f7b0b60bb1aa 100644
--- a/docs/src/AlgebraicGeometry/AlgebraicSets/ProjectiveAlgebraicSet.md
+++ b/docs/src/AlgebraicGeometry/AlgebraicSets/ProjectiveAlgebraicSet.md
@@ -1,9 +1,6 @@
```@meta
CurrentModule = Oscar
-```
-
-```@setup oscar
-using Oscar
+DocTestSetup = Oscar.doctestsetup()
```
# Projective Algebraic Sets
diff --git a/docs/src/AlgebraicGeometry/AlgebraicVarieties/AffineVariety.md b/docs/src/AlgebraicGeometry/AlgebraicVarieties/AffineVariety.md
index c79b8d363b4c..9c4a2b29f919 100644
--- a/docs/src/AlgebraicGeometry/AlgebraicVarieties/AffineVariety.md
+++ b/docs/src/AlgebraicGeometry/AlgebraicVarieties/AffineVariety.md
@@ -1,9 +1,6 @@
```@meta
CurrentModule = Oscar
-```
-
-```@setup oscar
-using Oscar
+DocTestSetup = Oscar.doctestsetup()
```
# Affine Varieties
diff --git a/docs/src/AlgebraicGeometry/AlgebraicVarieties/ProjectiveVariety.md b/docs/src/AlgebraicGeometry/AlgebraicVarieties/ProjectiveVariety.md
index c754a8878ce2..720f2fff00a9 100644
--- a/docs/src/AlgebraicGeometry/AlgebraicVarieties/ProjectiveVariety.md
+++ b/docs/src/AlgebraicGeometry/AlgebraicVarieties/ProjectiveVariety.md
@@ -1,9 +1,6 @@
```@meta
CurrentModule = Oscar
-```
-
-```@setup oscar
-using Oscar
+DocTestSetup = Oscar.doctestsetup()
```
# Projective Varieties
diff --git a/docs/src/AlgebraicGeometry/Schemes/RationalPointsAffine.md b/docs/src/AlgebraicGeometry/Schemes/RationalPointsAffine.md
index 428864035015..de0b6480c16f 100644
--- a/docs/src/AlgebraicGeometry/Schemes/RationalPointsAffine.md
+++ b/docs/src/AlgebraicGeometry/Schemes/RationalPointsAffine.md
@@ -1,9 +1,6 @@
```@meta
CurrentModule = Oscar
-```
-
-```@setup oscar
-using Oscar
+DocTestSetup = Oscar.doctestsetup()
```
# Rational Points on Affine Schemes
diff --git a/docs/src/AlgebraicGeometry/Schemes/RationalPointsProjective.md b/docs/src/AlgebraicGeometry/Schemes/RationalPointsProjective.md
index 0c672102d644..8960a3ea0930 100644
--- a/docs/src/AlgebraicGeometry/Schemes/RationalPointsProjective.md
+++ b/docs/src/AlgebraicGeometry/Schemes/RationalPointsProjective.md
@@ -1,9 +1,6 @@
```@meta
CurrentModule = Oscar
-```
-
-```@setup oscar
-using Oscar
+DocTestSetup = Oscar.doctestsetup()
```
# Rational Points on Projective Schemes
diff --git a/docs/src/AlgebraicGeometry/Surfaces/EllipticSurface.md b/docs/src/AlgebraicGeometry/Surfaces/EllipticSurface.md
new file mode 100644
index 000000000000..a76c7cad6d1a
--- /dev/null
+++ b/docs/src/AlgebraicGeometry/Surfaces/EllipticSurface.md
@@ -0,0 +1,97 @@
+```@meta
+CurrentModule = Oscar
+```
+
+# Elliptic Surfaces
+See [SS19](@cite) for the theory of elliptic surfaces.
+
+```@docs
+EllipticSurface
+```
+
+## Constructors
+```@docs
+elliptic_surface
+kodaira_neron_model(E::EllipticCurve)
+```
+
+## Attributes
+```@docs
+generic_fiber(S::EllipticSurface)
+zero_section(S::EllipticSurface)
+euler_characteristic(X::EllipticSurface)
+fibration(X::EllipticSurface)
+weierstrass_chart(X::EllipticSurface)
+weierstrass_chart_on_minimal_model(X::EllipticSurface)
+weierstrass_model(X::EllipticSurface)
+weierstrass_contraction(X::EllipticSurface)
+fibration_on_weierstrass_model(X::EllipticSurface)
+```
+
+## Reducible fibers and the trivial lattice
+```@docs
+trivial_lattice(X::EllipticSurface)
+reducible_fibers(S::EllipticSurface)
+fiber_cartier(S::EllipticSurface, P::Vector = ZZ.([0,1]))
+fiber_components(S::EllipticSurface, P; algorithm=:exceptional_divisors)
+```
+
+## Mordell Weil group and related lattices
+Since we require that ``\pi \colon X \to C`` has a section, the generic fibre of ``\pi`` is an elliptic curve ``E/k(C)``. The group ``E(k(C))`` of its rational points is called the Mordell-Weil group. It is a finitely generated abelian group. In general it is difficult to compute.
+
+The height paring gives the free part of the Mordell-Weil group the structure of a quadratic lattice over the integers -- the so called Mordell-Weil lattice.
+
+```@docs
+algebraic_lattice(X::EllipticSurface)
+mordell_weil_sublattice(S::EllipticSurface)
+mordell_weil_torsion(S::EllipticSurface)
+section(X::EllipticSurface, P::EllipticCurvePoint)
+basis_representation(X::EllipticSurface, D::AbsWeilDivisor)
+```
+
+### Updating the Mordell Weil group
+Since the Mordell-Weil group is hard to compute, the user has to provide its generators, or at least generators of a subgroup
+at construction of the surface. In some cases it may be convenient to enter the basis after creation, although it is in general not recommended. The following function are meant for this purpose.
+```@docs
+set_mordell_weil_basis!(X::EllipticSurface, mwl_basis::Vector{<:EllipticCurvePoint})
+update_mwl_basis!(S::EllipticSurface, mwl_gens::Vector{<:EllipticCurvePoint})
+algebraic_lattice_primitive_closure!(S::EllipticSurface)
+algebraic_lattice_primitive_closure(S::EllipticSurface, p)
+```
+
+## Morphisms
+```@docs
+isomorphism_from_generic_fibers
+isomorphisms(X::EllipticSurface, Y::EllipticSurface)
+translation_morphism(X::EllipticSurface, P::EllipticCurvePoint)
+```
+
+## Fibration hopping
+The methods in this section are available only for elliptically fibered K3 surfaces.
+A K3 surface ``X`` may admit several elliptic fibrations
+```math
+\pi \colon X \to \mathbb{P}^1.
+```
+Fibration hopping is a way to compute them.
+See e.g. [BE23](@cite) and [BZ23](@cite).
+
+A divisor ``F`` on ``X`` is called elliptic if it is primitive, isotropic and nef.
+The linear system ``|F|`` of an elliptic divisor ``F`` induces a genus one fibration on ``X``.
+Conversely, the class of a fiber ``F`` of an elliptic fibration is an elliptic divisor.
+Two elliptic fibrations on ``X`` with elliptic divisors ``F_1`` and ``F_2`` are called ``n``-neighbors if their intersection number is ``F_1.F_2=n``.
+
+```@docs
+linear_system(X::EllipticSurface, P::EllipticCurvePoint, k::Int)
+two_neighbor_step(X::EllipticSurface, F::Vector{QQFieldElem})
+elliptic_parameter(X::EllipticSurface, F::Vector{QQFieldElem})
+pushforward_on_algebraic_lattices(f::MorphismFromRationalFunctions{<:EllipticSurface, <:EllipticSurface})
+```
+## Contact
+
+Please direct questions about this part of OSCAR to the following people:
+* [Simon Brandhorst](https://www.math.uni-sb.de/ag/brandhorst/index.php?lang=en).
+* [Matthias Zach](https://math.rptu.de/en/wgs/agag/people/members),
+
+You can ask questions in the [OSCAR Slack](https://www.oscar-system.org/community/#slack).
+
+Alternatively, you can [raise an issue on github](https://www.oscar-system.org/community/#how-to-report-issues).
diff --git a/docs/src/AlgebraicGeometry/ToricVarieties/CohomologyClasses.md b/docs/src/AlgebraicGeometry/ToricVarieties/CohomologyClasses.md
index ba5ea52a853d..6538f5e2a2ba 100644
--- a/docs/src/AlgebraicGeometry/ToricVarieties/CohomologyClasses.md
+++ b/docs/src/AlgebraicGeometry/ToricVarieties/CohomologyClasses.md
@@ -66,4 +66,5 @@ volume_form(v::NormalToricVariety)
intersection_form(v::NormalToricVariety)
chern_class(v::NormalToricVariety, k::Int; check::Bool = true)
chern_classes(v::NormalToricVariety; check::Bool = true)
+basis_of_h4(v::NormalToricVariety; check::Bool = true)
```
diff --git a/docs/src/CommutativeAlgebra/GroebnerBases/groebner_bases_integers.md b/docs/src/CommutativeAlgebra/GroebnerBases/groebner_bases_integers.md
index 8fdb31cd4611..5bc623d2c42c 100644
--- a/docs/src/CommutativeAlgebra/GroebnerBases/groebner_bases_integers.md
+++ b/docs/src/CommutativeAlgebra/GroebnerBases/groebner_bases_integers.md
@@ -60,11 +60,11 @@ Ideal generated by
julia> G = groebner_basis(I, ordering = lex(R))
Gröbner basis with elements
- 1 -> 28*y^3 - 35*y
- 2 -> 4*x*y^2 - 5*x
- 3 -> 15*x^2 + 28*y^2
- 4 -> 3*x^2*y + 7*y
- 5 -> x^2*y^2 - 5*x^2 - 7*y^2
+ 1: 28*y^3 - 35*y
+ 2: 4*x*y^2 - 5*x
+ 3: 15*x^2 + 28*y^2
+ 4: 3*x^2*y + 7*y
+ 5: x^2*y^2 - 5*x^2 - 7*y^2
with respect to the ordering
lex([x, y])
```
diff --git a/docs/src/CommutativeAlgebra/ModulesOverMultivariateRings/complexes.md b/docs/src/CommutativeAlgebra/ModulesOverMultivariateRings/complexes.md
index a3735244c6ab..0a2f3b20922d 100644
--- a/docs/src/CommutativeAlgebra/ModulesOverMultivariateRings/complexes.md
+++ b/docs/src/CommutativeAlgebra/ModulesOverMultivariateRings/complexes.md
@@ -50,25 +50,15 @@ julia> range(C)
5:-1:3
julia> C[5]
-Subquotient of Submodule with 1 generator
-1 -> e[1]
-by Submodule with 1 generator
-1 -> x^4*e[1]
+Subquotient of submodule with 1 generator
+ 1: e[1]
+by submodule with 1 generator
+ 1: x^4*e[1]
julia> delta = map(C, 5)
-Map with following data
-Domain:
-=======
-Subquotient of Submodule with 1 generator
-1 -> e[1]
-by Submodule with 1 generator
-1 -> x^4*e[1]
-Codomain:
-=========
-Subquotient of Submodule with 1 generator
-1 -> e[1]
-by Submodule with 1 generator
-1 -> x^3*e[1]
+Module homomorphism
+ from A
+ to B
julia> matrix(delta)
[x^2]
diff --git a/docs/src/CommutativeAlgebra/ModulesOverMultivariateRings/subquotients.md b/docs/src/CommutativeAlgebra/ModulesOverMultivariateRings/subquotients.md
index 71f38afd34a5..45ee02b52e85 100644
--- a/docs/src/CommutativeAlgebra/ModulesOverMultivariateRings/subquotients.md
+++ b/docs/src/CommutativeAlgebra/ModulesOverMultivariateRings/subquotients.md
@@ -96,13 +96,13 @@ julia> B = R[x^2; y^3; z^4]
[z^4]
julia> M = SubquoModule(F, A, B)
-Subquotient of Submodule with 2 generators
-1 -> x*e[1]
-2 -> y*e[1]
-by Submodule with 3 generators
-1 -> x^2*e[1]
-2 -> y^3*e[1]
-3 -> z^4*e[1]
+Subquotient of submodule with 2 generators
+ 1: x*e[1]
+ 2: y*e[1]
+by submodule with 3 generators
+ 1: x^2*e[1]
+ 2: y^3*e[1]
+ 3: z^4*e[1]
julia> base_ring(M)
Multivariate polynomial ring in 3 variables x, y, z
@@ -134,12 +134,12 @@ julia> relations(M)
z^4*e[1]
julia> ambient_module(M)
-Subquotient of Submodule with 1 generator
-1 -> e[1]
-by Submodule with 3 generators
-1 -> x^2*e[1]
-2 -> y^3*e[1]
-3 -> z^4*e[1]
+Subquotient of submodule with 1 generator
+ 1: e[1]
+by submodule with 3 generators
+ 1: x^2*e[1]
+ 2: y^3*e[1]
+ 3: z^4*e[1]
```
In the graded case, we also have:
@@ -191,13 +191,13 @@ julia> B = R[x^2; y^3; z^4]
[z^4]
julia> M = SubquoModule(F, A, B)
-Subquotient of Submodule with 2 generators
-1 -> x*e[1]
-2 -> y*e[1]
-by Submodule with 3 generators
-1 -> x^2*e[1]
-2 -> y^3*e[1]
-3 -> z^4*e[1]
+Subquotient of submodule with 2 generators
+ 1: x*e[1]
+ 2: y*e[1]
+by submodule with 3 generators
+ 1: x^2*e[1]
+ 2: y^3*e[1]
+ 3: z^4*e[1]
julia> m = M(sparse_row(R, [(1,z),(2,one(R))]))
(x*z + y)*e[1]
@@ -247,25 +247,25 @@ julia> B = R[x^2; y^3; z^4]
[z^4]
julia> M = SubquoModule(F, A, B)
-Subquotient of Submodule with 2 generators
-1 -> x*e[1]
-2 -> y*e[1]
-by Submodule with 3 generators
-1 -> x^2*e[1]
-2 -> y^3*e[1]
-3 -> z^4*e[1]
+Subquotient of submodule with 2 generators
+ 1: x*e[1]
+ 2: y*e[1]
+by submodule with 3 generators
+ 1: x^2*e[1]
+ 2: y^3*e[1]
+ 3: z^4*e[1]
julia> m = z*M[1] + M[2]
(x*z + y)*e[1]
julia> parent(m)
-Subquotient of Submodule with 2 generators
-1 -> x*e[1]
-2 -> y*e[1]
-by Submodule with 3 generators
-1 -> x^2*e[1]
-2 -> y^3*e[1]
-3 -> z^4*e[1]
+Subquotient of submodule with 2 generators
+ 1: x*e[1]
+ 2: y*e[1]
+by submodule with 3 generators
+ 1: x^2*e[1]
+ 2: y^3*e[1]
+ 3: z^4*e[1]
julia> coordinates(m)
Sparse row with positions [1, 2] and values QQMPolyRingElem[z, 1]
@@ -362,6 +362,19 @@ annihilator(N::SubquoModule{T}) where T
quotient(M::SubquoModule{T}, N::SubquoModule{T}) where T
```
+```@docs
+quotient(M::SubquoModule, J::Ideal)
+```
+
+```@docs
+saturation(M:: SubquoModule, J::Ideal)
+```
+
+```@docs
+saturation_with_index(M:: SubquoModule, J::Ideal)
+```
+
+
## Submodules and Quotients
```@docs
diff --git a/docs/src/CommutativeAlgebra/affine_algebras.md b/docs/src/CommutativeAlgebra/affine_algebras.md
index ed54c6f60af0..4c48d54b1aa0 100644
--- a/docs/src/CommutativeAlgebra/affine_algebras.md
+++ b/docs/src/CommutativeAlgebra/affine_algebras.md
@@ -171,6 +171,10 @@ simplify(f::MPolyQuoRingElem)
==(f::MPolyQuoRingElem{T}, g::MPolyQuoRingElem{T}) where T
```
+```@docs
+is_invertible_with_inverse(f::MPolyQuoRingElem)
+```
+
In the graded case, we additionally have:
```@docs
@@ -292,7 +296,6 @@ minimal_generating_set(I::MPolyQuoIdeal{<:MPolyDecRingElem})
```@docs
intersect(a::MPolyQuoIdeal{T}, bs::MPolyQuoIdeal{T}...) where T
-intersect(V::Vector{MPolyQuoIdeal{T}}) where T
```
#### Ideal Quotients
diff --git a/docs/src/CommutativeAlgebra/ideals.md b/docs/src/CommutativeAlgebra/ideals.md
index e04ad1a591c5..f7d1347fe6a0 100644
--- a/docs/src/CommutativeAlgebra/ideals.md
+++ b/docs/src/CommutativeAlgebra/ideals.md
@@ -134,7 +134,7 @@ Given two ideals $I, J$ of a ring $R$, the saturation of $I$ with respect to $J$
$I:J^{\infty} = \bigl\{ f \in R \:\big|\: f J^k \!\subset I {\text{ for some }}k\geq 1 \bigr\} = \textstyle{\bigcup\limits_{k=1}^{\infty} (I:J^k)}.$
```@docs
-saturation(I::MPolyIdeal{T}, J::MPolyIdeal{T}) where T
+saturation(I::MPolyIdeal{T}, J::MPolyIdeal{T}; iteration::Bool=false) where T
saturation_with_index(I::MPolyIdeal{T}, J::MPolyIdeal{T}) where T
```
diff --git a/docs/src/DeveloperDocumentation/caching.md b/docs/src/DeveloperDocumentation/caching.md
index 00db05dcb431..220c6344e3d8 100644
--- a/docs/src/DeveloperDocumentation/caching.md
+++ b/docs/src/DeveloperDocumentation/caching.md
@@ -96,9 +96,9 @@ like `cyclotomic_polynomial`
```
module Globals
using Hecke
- const Qx, _ = polynomial_ring(FlintQQ, :x, cached = false)
- const Zx, _ = polynomial_ring(FlintZZ, :x, cached = false)
- const Zxy, _ = polynomial_ring(FlintZZ, [:x, :y], cached = false)
+ const Qx, _ = polynomial_ring(QQ, :x, cached = false)
+ const Zx, _ = polynomial_ring(ZZ, :x, cached = false)
+ const Zxy, _ = polynomial_ring(ZZ, [:x, :y], cached = false)
end
```
You can use these in your own code as well, or imitate this pattern if convenient.
diff --git a/docs/src/Groups/action.md b/docs/src/Groups/action.md
index 83304a9b5fa9..abf584b3a965 100644
--- a/docs/src/Groups/action.md
+++ b/docs/src/Groups/action.md
@@ -39,6 +39,9 @@ on_tuples
on_sets
permuted
on_indeterminates
+on_lines
+on_echelon_form_mats
+on_subgroups
```
diff --git a/docs/src/Groups/basics.md b/docs/src/Groups/basics.md
index a8d9ff001ece..120c883a4157 100644
--- a/docs/src/Groups/basics.md
+++ b/docs/src/Groups/basics.md
@@ -21,6 +21,7 @@ has_gens(::GAPGroup)
number_of_generators(G::GAPGroup)
gen(::GAPGroup, i::Int)
small_generating_set(G::GAPGroup)
+minimal_size_generating_set(G::GAPGroup)
Base.rand(G::GAPGroup)
rand_pseudo(G::GAPGroup)
```
diff --git a/docs/src/Groups/subgroups.md b/docs/src/Groups/subgroups.md
index fccfea3e6bc8..811a95dcd917 100644
--- a/docs/src/Groups/subgroups.md
+++ b/docs/src/Groups/subgroups.md
@@ -112,24 +112,31 @@ subgroup_classes(G::GAPGroup)
```@docs
GroupCoset
+group(C::GroupCoset)
+acting_group(C::GroupCoset)
+representative(C::GroupCoset)
right_coset(H::GAPGroup, g::GAPGroupElem)
left_coset(H::GAPGroup, g::GAPGroupElem)
-is_right(c::GroupCoset)
-is_left(c::GroupCoset)
-is_bicoset(C::GroupCoset)
-acting_domain(C::GroupCoset)
-representative(C::GroupCoset)
+is_right(C::GroupCoset)
+is_left(C::GroupCoset)
right_cosets(G::GAPGroup, H::GAPGroup; check::Bool=true)
left_cosets(G::GAPGroup, H::GAPGroup; check::Bool=true)
right_transversal(G::T1, H::T2; check::Bool=true) where T1 <: GAPGroup where T2 <: GAPGroup
left_transversal(G::T1, H::T2; check::Bool=true) where T1 <: GAPGroup where T2 <: GAPGroup
+is_bicoset(C::GroupCoset)
+```
+
+```@docs
GroupDoubleCoset{T <: GAPGroup, S <: GAPGroupElem}
-double_coset(G::GAPGroup, g::GAPGroupElem, H::GAPGroup)
-double_cosets(G::T, H::GAPGroup, K::GAPGroup; check::Bool=true) where T <: GAPGroup
+group(C::GroupDoubleCoset)
left_acting_group(C::GroupDoubleCoset)
right_acting_group(C::GroupDoubleCoset)
representative(C::GroupDoubleCoset)
+double_coset(G::GAPGroup, g::GAPGroupElem, H::GAPGroup)
+double_cosets(G::T, H::GAPGroup, K::GAPGroup; check::Bool=true) where T <: GAPGroup
+```
+
+```@docs
order(C::Union{GroupCoset,GroupDoubleCoset})
Base.rand(C::Union{GroupCoset,GroupDoubleCoset})
-intersect(V::AbstractVector{Union{<: GAPGroup, GroupCoset, GroupDoubleCoset}})
```
diff --git a/docs/src/Groups/tom.md b/docs/src/Groups/tom.md
index fb04e7274c40..c871d647c8bd 100644
--- a/docs/src/Groups/tom.md
+++ b/docs/src/Groups/tom.md
@@ -6,13 +6,13 @@ DocTestSetup = Oscar.doctestsetup()
# Tables of Marks
The concept of a *Table of Marks* was introduced by W. Burnside in his book
-Theory of Groups of Finite Order [Bur55](@cite).
+Theory of Groups of Finite Order [Bur11](@cite).
Therefore a table of marks is sometimes called a *Burnside matrix*.
The table of marks of a finite group ``G`` is a matrix whose rows and columns
are labelled by the conjugacy classes of subgroups of ``G`` and where for
two subgroups ``H`` and ``K`` the ``(H, K)``-entry is the number of
-fixed points of ``K`` in the transitive action of ``G`` on the cosets of ``H``
-in ``G``.
+fixed points of ``K`` in the transitive action of ``G`` on the right cosets
+of ``H`` in ``G``.
So the table of marks characterizes the set of all permutation representations
of ``G``.
Moreover, the table of marks gives a compact description of the
diff --git a/docs/src/NoncommutativeAlgebra/PBWAlgebras/ideals.md b/docs/src/NoncommutativeAlgebra/PBWAlgebras/ideals.md
index 6ac2f6e4d4a2..c4f67c8fba42 100644
--- a/docs/src/NoncommutativeAlgebra/PBWAlgebras/ideals.md
+++ b/docs/src/NoncommutativeAlgebra/PBWAlgebras/ideals.md
@@ -35,13 +35,13 @@ If `I` is an ideal of a PBW-algebra `A`, then
```jldoctest
julia> D, (x, y, dx, dy) = weyl_algebra(QQ, ["x", "y"])
-(Weyl-algebra over Rational field in variables (x, y), PBWAlgElem{QQFieldElem, Singular.n_Q}[x, y, dx, dy])
+(Weyl-algebra over rational field in variables (x, y), PBWAlgElem{QQFieldElem, Singular.n_Q}[x, y, dx, dy])
julia> I = left_ideal(D, [x, dx])
left_ideal(x, dx)
julia> base_ring(I)
-Weyl-algebra over Rational field in variables (x, y)
+Weyl-algebra over rational field in variables (x, y)
julia> gens(I)
2-element Vector{PBWAlgElem{QQFieldElem, Singular.n_Q}}:
diff --git a/docs/src/NoncommutativeAlgebra/PBWAlgebras/quotients.md b/docs/src/NoncommutativeAlgebra/PBWAlgebras/quotients.md
index 9d59afdcaafe..46de0d53ece3 100644
--- a/docs/src/NoncommutativeAlgebra/PBWAlgebras/quotients.md
+++ b/docs/src/NoncommutativeAlgebra/PBWAlgebras/quotients.md
@@ -67,7 +67,7 @@ julia> I = two_sided_ideal(A, [x^2, y^2, z^2]);
julia> Q, q = quo(A, I);
julia> base_ring(Q)
-PBW-algebra over Rational field in x, y, z with relations y*x = -x*y, z*x = -x*z, z*y = -y*z
+PBW-algebra over rational field in x, y, z with relations y*x = -x*y, z*x = -x*z, z*y = -y*z
julia> modulus(Q)
two_sided_ideal(x^2, y^2, z^2)
diff --git a/docs/src/PolyhedralGeometry/Polyhedra/constructions.md b/docs/src/PolyhedralGeometry/Polyhedra/constructions.md
index 4eefdeffd57d..fac07af46b3a 100644
--- a/docs/src/PolyhedralGeometry/Polyhedra/constructions.md
+++ b/docs/src/PolyhedralGeometry/Polyhedra/constructions.md
@@ -26,13 +26,13 @@ julia> P = polyhedron(([-1 0; 1 0], [0,1]), ([0 1], [0]))
Polyhedron in ambient dimension 2
julia> facets(P)
-2-element SubObjectIterator{AffineHalfspace{QQFieldElem}} over the Halfspaces of R^2 described by:
+2-element SubObjectIterator{AffineHalfspace{QQFieldElem}} over the halfspaces of R^2 described by:
-x_1 <= 0
x_1 <= 1
julia> affine_hull(P)
-1-element SubObjectIterator{AffineHyperplane{QQFieldElem}} over the Hyperplanes of R^2 described by:
+1-element SubObjectIterator{AffineHyperplane{QQFieldElem}} over the hyperplanes of R^2 described by:
x_2 = 0
diff --git a/docs/src/PolyhedralGeometry/intro.md b/docs/src/PolyhedralGeometry/intro.md
index f11eeb31b51e..e9e383063254 100644
--- a/docs/src/PolyhedralGeometry/intro.md
+++ b/docs/src/PolyhedralGeometry/intro.md
@@ -159,7 +159,13 @@ Some methods will require input or return output in form of an `IncidenceMatrix`
IncidenceMatrix
```
-From the example it can be seen that this type supports `julia`'s matrix functionality. There are also functions to retrieve specific rows or columns as a `Set` over the non-zero indices.
+The unique nature of the `IncidenceMatrix` allows for different ways of construction:
+
+```@docs
+incidence_matrix
+```
+
+From the examples it can be seen that this type supports `julia`'s matrix functionality. There are also functions to retrieve specific rows or columns as a `Set` over the non-zero indices.
```@docs
row(i::IncidenceMatrix, n::Int)
diff --git a/etc/check_docstrings.jl b/etc/check_docstrings.jl
new file mode 100644
index 000000000000..72caa4d49495
--- /dev/null
+++ b/etc/check_docstrings.jl
@@ -0,0 +1,107 @@
+# this can be run from the command line with:
+# > julia --project=. -e 'using Oscar; include("etc/check_docstrings.jl")'
+#
+# it is also possible to test more packages at once (as long as Main.X exists)
+# > julia --project=. -e 'using Oscar; include("etc/check_docstrings.jl")' Nemo Singular Hecke Polymake GAP Oscar
+#
+# note: the @main function requires julia 1.11 or newer
+
+
+using Markdown
+
+admonition_types = string.((:note, :info, :tip, :danger, :warning, :compat, :todo, :details))
+
+# this might not catch all broken jldoctests but seems to work for now
+function has_broken_doctest(md::Markdown.MD)
+ todo = copy(md.content)
+ while !isempty(todo)
+ elem = popfirst!(todo)
+ # nested
+ if elem isa Markdown.MD
+ append!(todo, elem.content)
+ else
+ # proper docstrings are in a Markdown.Code block
+ if elem isa Markdown.Paragraph
+ for block in elem.content
+ # unterminated jldoctests seem to end up inside some string in a Paragraph block
+ if contains(string(block),"```jldoctest")
+ return "Unterminated jldoctest: $(string(block))"
+ end
+ end
+ elseif elem isa Markdown.Admonition
+ if !(elem.category in admonition_types)
+ return "Unknown admonition category: $(string(elem.category))"
+ end
+ end
+ end
+ end
+ return nothing
+end
+
+function find_docstr_src(docs)
+ locs = []
+ res = docs.meta[:results]
+ for i in 1:length(docs.content)
+ msg = has_broken_doctest(docs.content[i])
+ if msg !== nothing
+ file = res[i].data[:path]
+ line = res[i].data[:linenumber]
+ mod = res[i].data[:module]
+ push!(locs, (mod, file, line, msg))
+ end
+ end
+ return locs
+end
+
+function get_broken_docstrings(m::Module)
+ allpairs = collect(zip(Iterators.repeated(m), names(m; all=true, imported=false)));
+ broken = []
+ locs = []
+ done = [m]
+
+ while !isempty(allpairs)
+ (src, name) = popfirst!(allpairs)
+ memberobj = try
+ getfield(src,name)
+ catch
+ nothing
+ end
+ if memberobj isa Module
+ if !(memberobj in done)
+ push!(done, memberobj)
+ # we only want to consider one pkg
+ # but note that we still seem to pick up some reexported names
+ # even though imported=false and the check below
+ if (pkgdir(memberobj) == pkgdir(m))
+ newnames = names(memberobj; all=true, imported=false)
+ filter!(x->!((memberobj, x) in allpairs || x in done), newnames)
+ append!(allpairs, collect(zip(Iterators.repeated(memberobj), newnames)))
+ end
+ end
+ elseif !isnothing(memberobj)
+ docs = Base.Docs.doc(memberobj)
+ if docs isa Markdown.MD
+ if has_broken_doctest(docs) !== nothing && !(memberobj in broken)
+ loc = find_docstr_src(docs)
+ push!(broken, memberobj)
+ # we could filter out docs from other packages via startswith(x, pkgdir(m))
+ append!(locs, loc)
+ end
+ end
+ end
+ end
+ return locs
+end
+
+function (@main)(args)
+ modnames = length(args) > 0 ? args : ["Oscar"]
+ mod = getfield.(Ref(Main), Symbol.(modnames))
+ locs = reduce(vcat, get_broken_docstrings.(mod))
+ isempty(locs) && exit(0)
+ for (mod, file, line, msg) in locs
+ dir = joinpath(pkgdir(mod),"") # add trailing /
+ relfile = replace(file, dir => "")
+ println("::error file=$relfile,line=$line,title=$(string(mod))::$msg")
+ end
+ exit(-1)
+end
diff --git a/experimental/AlgebraicStatistics/docs/src/phylogenetics.md b/experimental/AlgebraicStatistics/docs/src/phylogenetics.md
index 77d8d9c36ff1..d27b4f269c64 100644
--- a/experimental/AlgebraicStatistics/docs/src/phylogenetics.md
+++ b/experimental/AlgebraicStatistics/docs/src/phylogenetics.md
@@ -2,6 +2,7 @@
CurrentModule = Oscar
DocTestSetup = Oscar.doctestsetup()
```
+
# Algebraic Phylogenetics
The Algebraic Phylogenetics part of OSCAR provides functionality for
diff --git a/experimental/BasisLieHighestWeight/src/BasisLieHighestWeight.jl b/experimental/BasisLieHighestWeight/src/BasisLieHighestWeight.jl
index e43f319d2fe6..85105ae1e52d 100644
--- a/experimental/BasisLieHighestWeight/src/BasisLieHighestWeight.jl
+++ b/experimental/BasisLieHighestWeight/src/BasisLieHighestWeight.jl
@@ -1,32 +1,30 @@
module BasisLieHighestWeight
using ..Oscar
-using ..Oscar: GAPWrap
using ..Oscar: IntegerUnion
using ..Oscar: _is_weighted
+using Oscar.LieAlgebras:
+ _character,
+ _root_system_type_string,
+ lie_algebra_simple_module_struct_consts_gap
+
using AbstractAlgebra.PrettyPrinting
import Oscar: dim
-import Oscar: dim_of_simple_module
import Oscar: monomial_ordering
import Oscar: monomials
-import Oscar: number_of_positive_roots, n_positive_roots
import Base: length
# Long-term TODO's:
-# - Use Oscar-Lie-Algebra type instead of LieAlgebraStructure
# - Test if ZZx should be a graded_polynomial_ring with weights_w as weights
# - Maybe export and docstring:
-# - get_dim_weightspace
-# - orbit_weylgroup
# - get_lattice_points_of_weightspace
# - convert_lattice_points_to_monomials
# - convert_monomials_to_lattice_points
# - action_matrices_of_operators
# - weights_for_operators
-# - Data-Type for weights of Lie-Algebras? Two types, in alpha_i and w_i, conversion is defined in RootConversion
# - the list of Minkowski gens contains too many elements, only include those that give us something new
include("LieAlgebras.jl")
@@ -35,13 +33,13 @@ include("MonomialBasis.jl")
include("NewMonomial.jl")
include("TensorModels.jl")
include("MonomialOrder.jl")
-include("RootConversion.jl")
include("WeylPolytope.jl")
include("MainAlgorithm.jl")
include("UserFunctions.jl")
export MonomialBasis
+export birational_sequence
export basis_coordinate_ring_kodaira
export basis_coordinate_ring_kodaira_ffl
export basis_lie_highest_weight_operators
@@ -59,6 +57,7 @@ export BasisLieHighestWeight
export MonomialBasis
+export birational_sequence
export basis_coordinate_ring_kodaira
export basis_coordinate_ring_kodaira_ffl
export basis_lie_highest_weight_operators
diff --git a/experimental/BasisLieHighestWeight/src/BirationalSequence.jl b/experimental/BasisLieHighestWeight/src/BirationalSequence.jl
index 0d0de239c830..3a99f411d140 100644
--- a/experimental/BasisLieHighestWeight/src/BirationalSequence.jl
+++ b/experimental/BasisLieHighestWeight/src/BirationalSequence.jl
@@ -1,12 +1,51 @@
struct BirationalSequence
- operators::Vector{GAP.Obj}
- operators_vectors::Vector{Vector{Any}}
- weights_w::Vector{Vector{ZZRingElem}}
- weights_alpha::Vector{Vector{QQFieldElem}}
+ operator_roots::Vector{RootSpaceElem}
+ operator_weights::Vector{WeightLatticeElem}
+
+ function BirationalSequence(
+ operator_roots::Vector{RootSpaceElem}, operator_weights::Vector{WeightLatticeElem}
+ )
+ @req length(operator_roots) == length(operator_weights) "Different lengths"
+ return new(operator_roots, operator_weights)
+ end
+end
+
+function birational_sequence(
+ operator_roots::Vector{RootSpaceElem}, operator_weights::Vector{WeightLatticeElem}
+)
+ return BirationalSequence(operator_roots, operator_weights)
+end
+
+function birational_sequence(operator_roots::Vector{RootSpaceElem})
+ return birational_sequence(operator_roots, WeightLatticeElem.(operator_roots))
end
-function Base.show(io::IO, birational_sequence::BirationalSequence)
+function birational_sequence(operator_weights::Vector{WeightLatticeElem})
+ return birational_sequence(RootSpaceElem.(operator_weights), operator_weights)
+end
+
+function Base.show(io::IO, birational_seq::BirationalSequence)
println(io, "BirationalSequence")
- println(io, "Operators: ", birational_sequence.operators)
- print(io, "Weights in alpha_i:", birational_sequence.weights_alpha)
+ println(io, "Operators: ", operators_as_roots(birational_seq))
+ print(io, "Operators as weights:", operators_as_weights(birational_seq))
+end
+
+function length(birational_seq::BirationalSequence)
+ return length(birational_seq.operator_roots)
+end
+
+function operators_as_roots(birational_seq::BirationalSequence)
+ return birational_seq.operator_roots
+end
+
+function operator_as_root(birational_seq::BirationalSequence, i::Int)
+ return birational_seq.operator_roots[i]
+end
+
+function operators_as_weights(birational_seq::BirationalSequence)
+ return birational_seq.operator_weights
+end
+
+function operator_as_weight(birational_seq::BirationalSequence, i::Int)
+ return birational_seq.operator_weights[i]
end
diff --git a/experimental/BasisLieHighestWeight/src/LieAlgebras.jl b/experimental/BasisLieHighestWeight/src/LieAlgebras.jl
index 2f4b5a35ac9c..d624b905c72c 100644
--- a/experimental/BasisLieHighestWeight/src/LieAlgebras.jl
+++ b/experimental/BasisLieHighestWeight/src/LieAlgebras.jl
@@ -1,93 +1,22 @@
-@attributes mutable struct LieAlgebraStructure
- lie_type::Symbol
- rank::Int
- lie_algebra_gap::GAP.Obj
- chevalley_basis::NTuple{3,Vector{GAP.Obj}}
-
- function LieAlgebraStructure(lie_type::Symbol, rank::Int)
- lie_algebra_gap = GAP.Globals.SimpleLieAlgebra(
- GAP.Obj(lie_type), rank, GAP.Globals.Rationals
- )
- chevalley_basis = NTuple{3,Vector{GAP.Obj}}(GAP.Globals.ChevalleyBasis(lie_algebra_gap))
- return new(lie_type, rank, lie_algebra_gap, chevalley_basis)
- end
-end
-
-rank(L::LieAlgebraStructure) = L.rank
-
-@attr QQMatrix function cartan_matrix(L::LieAlgebraStructure)
- R = GAPWrap.RootSystem(L.lie_algebra_gap)
- C = matrix(QQ, GAP.Globals.CartanMatrix(R))
- return C
-end
-
-@attr QQMatrix function inv_cartan_matrix(L::LieAlgebraStructure)
- return inv(cartan_matrix(L))
-end
-
-function Base.show(io::IO, L::LieAlgebraStructure)
- io = pretty(io)
- print(io, LowercaseOff(), "Lie algebra of type $(L.lie_type)$(L.rank)")
-end
-
-function lie_algebra(type::Symbol, rk::Int)
- return LieAlgebraStructure(type, rk)
-end
-
-function chevalley_basis_gap(L::LieAlgebraStructure)
- return L.chevalley_basis
-end
-
-function cartan_sub_basis(L::LieAlgebraStructure)
- return L.chevalley_basis[3]
-end
-
-function root_system_gap(L::LieAlgebraStructure)
- return GAPWrap.RootSystem(L.lie_algebra_gap)
-end
-
-function number_of_positive_roots(L::LieAlgebraStructure)
- return length(GAP.Globals.PositiveRoots(root_system_gap(L)))
-end
-
-function dim_of_simple_module(T::Type, L::LieAlgebraStructure, hw::Vector{<:IntegerUnion})
- hw_ = Int.(hw)
- @req Oscar.LieAlgebras.is_dominant_weight(hw_) "Not a dominant weight."
- return T(GAPWrap.DimensionOfHighestWeightModule(L.lie_algebra_gap, GAP.Obj(Int.(hw_))))
-end
-
-function dim_of_simple_module(L::LieAlgebraStructure, hw::Vector{<:IntegerUnion})
- return dim_of_simple_module(Int, L, hw)
-end
-
-function matrices_of_operators_gap(
- L::LieAlgebraStructure, highest_weight::Vector{ZZRingElem}, operators::Vector{GAP.Obj}
+function matrices_of_operators(
+ L::LieAlgebra, highest_weight::WeightLatticeElem, operators::Vector{RootSpaceElem}
)
# used in tensor_matrices_of_operators
- M = GAP.Globals.HighestWeightModule(L.lie_algebra_gap, GAP.Obj(Int.(highest_weight)))
- matrices_of_operators = [
- sparse_matrix(matrix(QQ, GAP.Globals.MatrixOfAction(GAPWrap.Basis(M), o))) for
- o in operators
+ R = root_system(L)
+ struct_consts = lie_algebra_simple_module_struct_consts_gap(L, highest_weight)
+ dimV = size(struct_consts, 2)
+ transformation_matrices = [
+ sparse_matrix(coefficient_ring(L), dimV, dimV) for _ in 1:number_of_positive_roots(R)
]
- denominators = map(y -> denominator(y[2]), union(union(matrices_of_operators...)...))
- common_denominator = lcm(denominators)# // 1
- matrices_of_operators =
- (A -> change_base_ring(ZZ, common_denominator * A)).(matrices_of_operators)
- return matrices_of_operators
-end
+ for i in 1:number_of_positive_roots(R), j in 1:dimV
+ transformation_matrices[i][j] = struct_consts[i + number_of_positive_roots(R), j] # take f_alpha for positive root alpha
+ end
-@doc raw"""
- weight(L::LieAlgebraStructure, operator::GAP.Obj) -> Vector{ZZRingElem}
+ matrices_of_operators = map(operators) do op
+ fl, i = is_positive_root_with_index(op)
+ @assert fl
+ change_base_ring(ZZ, transformation_matrices[i])
+ end
-Calculate the weight of `operator` w.r.t. the fundamental weights w_i.
-"""
-function weight(L::LieAlgebraStructure, operator::GAP.Obj)
- @req !iszero(operator) "Operators should be non-zero"
- basis = GAPWrap.Basis(L.lie_algebra_gap)
- basis_ind = GAP.Globals.Position(basis, operator)
- denom = GAPWrap.Coefficients(basis, operator)[basis_ind]
- return [
- ZZ(GAPWrap.Coefficients(basis, h * operator)[basis_ind]//denom) for
- h in cartan_sub_basis(L)
- ]
+ return matrices_of_operators
end
diff --git a/experimental/BasisLieHighestWeight/src/MainAlgorithm.jl b/experimental/BasisLieHighestWeight/src/MainAlgorithm.jl
index cf71d0954bdb..310c4629d834 100644
--- a/experimental/BasisLieHighestWeight/src/MainAlgorithm.jl
+++ b/experimental/BasisLieHighestWeight/src/MainAlgorithm.jl
@@ -1,7 +1,7 @@
function basis_lie_highest_weight_compute(
- L::LieAlgebraStructure,
+ L::LieAlgebra,
highest_weight::Vector{Int},
- operators::Vector{<:GAP.Obj}, # operators are represented by our monomials. x_i is connected to operators[i]
+ operators::Vector{RootSpaceElem}, # monomial x_i is corresponds to f_operators[i]
monomial_ordering_symb::Symbol,
)
# Pseudocode:
@@ -23,45 +23,35 @@ function basis_lie_highest_weight_compute(
# return set_mon
# add_by_hand(highest_weight, set_mon)
- # add_known_monomials(set_mon)
+ # add all monomials from set_mon to basis
# go through all weightspaces that are not full
# add_new_monomials(weightspace, set_mon)
# return set_mon
- # add_known_monomials(set_mon)
- # add all monomials from set_mon to basis
-
# add_new_monomials(weightspace, set_mon)
# calculate monomials with weight in weightspace
# go through them one by one in monomial_ordering until basis is full
# return set_mon
- highest_weight = ZZ.(highest_weight)
- # The function precomputes objects that are independent of the highest weight and that can be used in all recursion
- # steps. Then it starts the recursion and returns the result.
+ R = root_system(L)
+ highest_weight = WeightLatticeElem(R, highest_weight)
- weights_w = [weight(L, op) for op in operators] # weights of the operators
- weights_alpha = [w_to_alpha(L, weight_w) for weight_w in weights_w] # other root system
-
- asVec(v) = GAP.gap_to_julia(GAPWrap.ExtRepOfObj(v)) # TODO
- birational_sequence = BirationalSequence(
- operators, [asVec(v) for v in operators], weights_w, weights_alpha
- )
+ birational_seq = birational_sequence(operators)
ZZx, _ = polynomial_ring(ZZ, length(operators)) # for our monomials
- monomial_ordering = get_monomial_ordering(monomial_ordering_symb, ZZx, weights_alpha)
+ monomial_ordering = get_monomial_ordering(monomial_ordering_symb, ZZx, operators)
# save computations from recursions
- calc_highest_weight = Dict{Vector{ZZRingElem},Set{ZZMPolyRingElem}}(
- [ZZ(0) for i in 1:rank(L)] => Set([ZZx(1)])
+ calc_highest_weight = Dict{WeightLatticeElem,Set{ZZMPolyRingElem}}(
+ zero(WeightLatticeElem, R) => Set([ZZx(1)])
)
# save all highest weights, for which the Minkowski-sum did not suffice to gain all monomials
- no_minkowski = Set{Vector{ZZRingElem}}()
+ no_minkowski = Set{WeightLatticeElem}()
# start recursion over highest_weight
monomials = compute_monomials(
L,
- birational_sequence,
+ birational_seq,
ZZx,
highest_weight,
monomial_ordering,
@@ -69,9 +59,12 @@ function basis_lie_highest_weight_compute(
no_minkowski,
)
# monomials = sort(collect(monomials); lt=((m1, m2) -> cmp(monomial_ordering, m1, m2) < 0))
- minkowski_gens = sort(collect(no_minkowski); by=(gen -> (sum(gen), reverse(gen))))
+ minkowski_gens = sort(
+ collect(no_minkowski);
+ by=(gen -> (sum(coefficients(gen)), reverse(Oscar._vec(coefficients(gen))))),
+ )
# output
- mb = MonomialBasis(L, highest_weight, birational_sequence, monomial_ordering, monomials)
+ mb = MonomialBasis(L, highest_weight, birational_seq, monomial_ordering, monomials)
set_attribute!(
mb, :algorithm => basis_lie_highest_weight_compute, :minkowski_gens => minkowski_gens
)
@@ -79,10 +72,10 @@ function basis_lie_highest_weight_compute(
end
function basis_coordinate_ring_kodaira_compute(
- L::LieAlgebraStructure,
+ L::LieAlgebra,
highest_weight::Vector{Int},
degree::Int,
- operators::Vector{<:GAP.Obj}, # operators are represented by our monomials. x_i is connected to operators[i]
+ operators::Vector{RootSpaceElem}, # monomial x_i is corresponds to f_operators[i]
monomial_ordering_symb::Symbol,
)
# Pseudocode:
@@ -95,28 +88,21 @@ function basis_coordinate_ring_kodaira_compute(
# of smaller multiples, the missing monomials
@req degree > 0 "Degree must be positive"
- highest_weight = ZZ.(highest_weight)
- # The function precomputes objects that are independent of the highest weight and that can be used in all recursion
- # steps. Then it starts the recursion and returns the result.
+ R = root_system(L)
+ highest_weight = WeightLatticeElem(R, highest_weight)
- weights_w = [weight(L, op) for op in operators] # weights of the operators
- weights_alpha = [w_to_alpha(L, weight_w) for weight_w in weights_w] # other root system
-
- asVec(v) = GAP.gap_to_julia(GAPWrap.ExtRepOfObj(v)) # TODO
- birational_sequence = BirationalSequence(
- operators, [asVec(v) for v in operators], weights_w, weights_alpha
- )
+ birational_seq = birational_sequence(operators)
ZZx, _ = polynomial_ring(ZZ, length(operators)) # for our monomials
- monomial_ordering = get_monomial_ordering(monomial_ordering_symb, ZZx, weights_alpha)
+ monomial_ordering = get_monomial_ordering(monomial_ordering_symb, ZZx, operators)
# save computations from recursions
- calc_highest_weight = Dict{Vector{ZZRingElem},Set{ZZMPolyRingElem}}(
- [ZZ(0) for i in 1:rank(L)] => Set([ZZx(1)])
+ calc_highest_weight = Dict{WeightLatticeElem,Set{ZZMPolyRingElem}}(
+ zero(WeightLatticeElem, R) => Set([ZZx(1)])
)
# save all highest weights, for which the Minkowski-sum did not suffice to gain all monomials
- no_minkowski = Set{Vector{ZZRingElem}}()
+ no_minkowski = Set{WeightLatticeElem}()
monomials_k = Set{ZZMPolyRingElem}[] # monomial basis of the module k*highest_weight
monomials_new_k = Vector{ZZMPolyRingElem}[] # store the monomials that are not products of basis monomials of smaller degree
sizehint!(monomials_k, degree)
@@ -143,7 +129,7 @@ function basis_coordinate_ring_kodaira_compute(
@vprintln :BasisLieHighestWeight "for $(Int.(i * highest_weight)) we have $(length(monomials_minkowski_sum)) and need $(dim_i) monomials"
monomials = compute_monomials(
L,
- birational_sequence,
+ birational_seq,
ZZx,
i * highest_weight,
monomial_ordering,
@@ -154,11 +140,14 @@ function basis_coordinate_ring_kodaira_compute(
@vprintln :BasisLieHighestWeight "for $(Int.(i * highest_weight)) we added $(length(monomials_new)) monomials "
# monomials = sort(collect(monomials); lt=((m1, m2) -> cmp(monomial_ordering, m1, m2) < 0))
- minkowski_gens = sort(collect(no_minkowski); by=(gen -> (sum(gen), reverse(gen))))
+ minkowski_gens = sort(
+ collect(no_minkowski);
+ by=(gen -> (sum(coefficients(gen)), reverse(Oscar._vec(coefficients(gen))))),
+ )
end
mb = MonomialBasis(
- L, i * highest_weight, birational_sequence, monomial_ordering, monomials
+ L, i * highest_weight, birational_seq, monomial_ordering, monomials
)
set_attribute!(mb, :algorithm => basis_coordinate_ring_kodaira_compute)
monomials_new_sorted = sort(
@@ -184,13 +173,13 @@ function basis_coordinate_ring_kodaira_compute(
end
function compute_monomials(
- L::LieAlgebraStructure,
- birational_sequence::BirationalSequence,
+ L::LieAlgebra,
+ birational_seq::BirationalSequence,
ZZx::ZZMPolyRing,
- highest_weight::Vector{ZZRingElem},
+ highest_weight::WeightLatticeElem,
monomial_ordering::MonomialOrdering,
- calc_highest_weight::Dict{Vector{ZZRingElem},Set{ZZMPolyRingElem}},
- no_minkowski::Set{Vector{ZZRingElem}},
+ calc_highest_weight::Dict{WeightLatticeElem,Set{ZZMPolyRingElem}},
+ no_minkowski::Set{WeightLatticeElem},
)
# This function calculates the monomial basis M_{highest_weight} recursively. The recursion saves all computed
# results in calc_highest_weight and we first check, if we already encountered this highest weight in a prior step.
@@ -206,41 +195,38 @@ function compute_monomials(
# we already computed the highest_weight result in a prior recursion step
if haskey(calc_highest_weight, highest_weight)
return calc_highest_weight[highest_weight]
- elseif highest_weight == [ZZ(0) for i in 1:(L.rank)] # we mathematically know the solution
+ elseif is_zero(highest_weight) # we mathematically know the solution
return Set(ZZx(1))
end
# calculation required
- # gap_dim is number of monomials that we need to find, i.e. |M_{highest_weight}|.
+ # dim is number of monomials that we need to find, i.e. |M_{highest_weight}|.
# if highest_weight is not a fundamental weight, partition into smaller summands is possible. This is the basecase of
# the recursion.
- gap_dim = dim_of_simple_module(L, highest_weight)
- if is_fundamental(highest_weight) || sum(abs.(highest_weight)) == 0
+ dim = dim_of_simple_module(L, highest_weight)
+ if is_zero(highest_weight) || is_fundamental(highest_weight)
push!(no_minkowski, highest_weight)
monomials = add_by_hand(
- L, birational_sequence, ZZx, highest_weight, monomial_ordering, Set{ZZMPolyRingElem}()
+ L, birational_seq, ZZx, highest_weight, monomial_ordering, Set{ZZMPolyRingElem}()
)
push!(calc_highest_weight, highest_weight => monomials)
return monomials
else
# use Minkowski-Sum for recursion
monomials = Set{ZZMPolyRingElem}()
- i = 0
- sub_weights_w = compute_sub_weights(highest_weight)
- l = length(sub_weights_w)
- # go through all partitions lambda_1 + lambda_2 = highest_weight until we have enough monomials or used all
- # partitions
- while length(monomials) < gap_dim && i < l
- i += 1
- lambda_1 = sub_weights_w[i]
- lambda_2 = highest_weight .- lambda_1
-
- if lambda_1 > lambda_2
- continue
- end
+ sub_weights = sub_weights_proper(highest_weight)
+ sort!(sub_weights; by=x -> sum(coefficients(x) .^ 2))
+ # go through all partitions lambda_1 + lambda_2 = highest_weight until we have enough monomials or used all partitions
+ for (ind_lambda_1, lambda_1) in enumerate(sub_weights)
+ length(monomials) >= dim && break
+
+ lambda_2 = highest_weight - lambda_1
+ ind_lambda_2 = findfirst(==(lambda_2), sub_weights)::Int
+
+ ind_lambda_1 > ind_lambda_2 && continue
mon_lambda_1 = compute_monomials(
L,
- birational_sequence,
+ birational_seq,
ZZx,
lambda_1,
monomial_ordering,
@@ -249,7 +235,7 @@ function compute_monomials(
)
mon_lambda_2 = compute_monomials(
L,
- birational_sequence,
+ birational_seq,
ZZx,
lambda_2,
monomial_ordering,
@@ -258,15 +244,14 @@ function compute_monomials(
)
# Minkowski-sum: M_{lambda_1} + M_{lambda_2} \subseteq M_{highest_weight}, if monomials get identified with
# points in ZZ^n
- monomials_minkowski_sum = Set([p * q for p in mon_lambda_1 for q in mon_lambda_2])
- union!(monomials, monomials_minkowski_sum)
+ union!(monomials, (p * q for p in mon_lambda_1 for q in mon_lambda_2))
end
# check if we found enough monomials
- if length(monomials) < gap_dim
+ if length(monomials) < dim
push!(no_minkowski, highest_weight)
monomials = add_by_hand(
- L, birational_sequence, ZZx, highest_weight, monomial_ordering, monomials
+ L, birational_seq, ZZx, highest_weight, monomial_ordering, monomials
)
end
@@ -275,40 +260,18 @@ function compute_monomials(
end
end
-function add_known_monomials!(
- weight_w::Vector{ZZRingElem},
- monomials_in_weightspace::Dict{Vector{ZZRingElem},Set{ZZMPolyRingElem}},
- matrices_of_operators::Vector{<:SMat{ZZRingElem}},
- space::Dict{Vector{ZZRingElem},<:SMat{QQFieldElem}},
- v0::SRow{ZZRingElem},
-)
- # By using the Minkowski-sum, we know that all monomials in monomials_in_weightspace are in our basis. Since we want to
- # extend the weightspace with missing monomials, we need to calculate and add the vector of each monomial to our
- # basis.
-
- for mon in monomials_in_weightspace[weight_w]
- # calculate the vector vec associated with mon
- vec = calc_vec(v0, mon, matrices_of_operators)
-
- # check if vec extends the basis
- if !haskey(space, weight_w)
- space[weight_w] = sparse_matrix(QQ)
- end
- Hecke._add_row_to_rref!(space[weight_w], change_base_ring(QQ, vec))
- end
-end
-
function add_new_monomials!(
- L::LieAlgebraStructure,
- birational_sequence::BirationalSequence,
+ L::LieAlgebra,
+ birational_seq::BirationalSequence,
ZZx::ZZMPolyRing,
matrices_of_operators::Vector{<:SMat{ZZRingElem}},
monomial_ordering::MonomialOrdering,
- weightspaces::Dict{Vector{ZZRingElem},Int},
+ weightspaces::Dict{WeightLatticeElem,Int},
dim_weightspace::Int,
- weight_w::Vector{ZZRingElem},
- monomials_in_weightspace::Dict{Vector{ZZRingElem},Set{ZZMPolyRingElem}},
- space::Dict{Vector{ZZRingElem},<:SMat{QQFieldElem}},
+ weight_w::WeightLatticeElem,
+ highest_weight::WeightLatticeElem,
+ monomials_in_weightspace::Dict{WeightLatticeElem,Set{ZZMPolyRingElem}},
+ space::Dict{WeightLatticeElem,<:SMat{QQFieldElem}},
v0::SRow{ZZRingElem},
basis::Set{ZZMPolyRingElem},
zero_coordinates::Vector{Int},
@@ -323,7 +286,8 @@ function add_new_monomials!(
poss_mon_in_weightspace = convert_lattice_points_to_monomials(
ZZx,
get_lattice_points_of_weightspace(
- birational_sequence.weights_alpha, w_to_alpha(L, weight_w), zero_coordinates
+ operators_as_roots(birational_seq), RootSpaceElem(highest_weight - weight_w),
+ zero_coordinates,
),
)
isempty(poss_mon_in_weightspace) && error("The input seems to be invalid.")
@@ -333,7 +297,7 @@ function add_new_monomials!(
# check which monomials should get added to the basis
i = 0
- if weight_w == 0 # check if [0 0 ... 0] already in basis
+ if highest_weight == weight_w # check if [0 0 ... 0] already in basis
i += 1
end
number_mon_in_weightspace = length(monomials_in_weightspace[weight_w])
@@ -350,9 +314,9 @@ function add_new_monomials!(
for i in 1:(nvars(ZZx) - 1)
if !haskey(
weightspaces,
- sum(
+ highest_weight - sum(
exp * weight for (exp, weight) in
- Iterators.drop(zip(degrees(mon), birational_sequence.weights_w), i)
+ Iterators.drop(zip(degrees(mon), operators_as_weights(birational_seq)), i)
),
)
cancel = true
@@ -382,10 +346,10 @@ function add_new_monomials!(
end
function add_by_hand(
- L::LieAlgebraStructure,
- birational_sequence::BirationalSequence,
+ L::LieAlgebra,
+ birational_seq::BirationalSequence,
ZZx::ZZMPolyRing,
- highest_weight::Vector{ZZRingElem},
+ highest_weight::WeightLatticeElem,
monomial_ordering::MonomialOrdering,
basis::Set{ZZMPolyRingElem},
)
@@ -394,59 +358,63 @@ function add_by_hand(
# initialization
# matrices g_i for (g_1^a_1 * ... * g_k^a_k)*v
+ R = root_system(L)
matrices_of_operators = tensor_matrices_of_operators(
- L, highest_weight, birational_sequence.operators
+ L, highest_weight, operators_as_roots(birational_seq)
)
- space = Dict(ZZ(0) * birational_sequence.weights_w[1] => sparse_matrix(QQ)) # span of basis vectors to keep track of the basis
+ space = Dict(zero(WeightLatticeElem, R) => sparse_matrix(QQ)) # span of basis vectors to keep track of the basis
v0 = sparse_row(ZZ, [(1, 1)]) # starting vector v
push!(basis, ZZx(1))
# required monomials of each weightspace
- weightspaces = get_dim_weightspace(L, highest_weight)
+ weightspaces = _character(R, highest_weight)
# sort the monomials from the minkowski-sum by their weightspaces
- monomials_in_weightspace = Dict{Vector{ZZRingElem},Set{ZZMPolyRingElem}}()
+ monomials_in_weightspace = Dict{WeightLatticeElem,Set{ZZMPolyRingElem}}()
for (weight_w, _) in weightspaces
monomials_in_weightspace[weight_w] = Set{ZZMPolyRingElem}()
end
for mon in basis
- weight_w = weight(mon, birational_sequence.weights_w)
- push!(monomials_in_weightspace[weight_w], mon)
+ push!(monomials_in_weightspace[highest_weight - weight(mon, birational_seq)], mon)
end
# only inspect weightspaces with missing monomials
- weights_with_non_full_weightspace = Set{Vector{ZZRingElem}}()
+ weights_with_non_full_weightspace = Set{WeightLatticeElem}()
for (weight_w, dim_weightspace) in weightspaces
if length(monomials_in_weightspace[weight_w]) != dim_weightspace
push!(weights_with_non_full_weightspace, weight_w)
end
end
- # The weightspaces could be calculated completely indepent (except for
- # the caching). This is not implemented, since I used the package Distributed.jl for this, which is not in the
- # Oscar dependendencies. But I plan to reimplement this.
- # insert known monomials into basis
-
+ # add all images from `monomials_in_weightspace` on `v0` to `space`
for weight_w in weights_with_non_full_weightspace
- add_known_monomials!(
- weight_w, monomials_in_weightspace, matrices_of_operators, space, v0
- )
+ for mon in monomials_in_weightspace[weight_w]
+ # calculate the vector vec associated with mon
+ vec = calc_vec(v0, mon, matrices_of_operators)
+
+ # check if vec extends the basis
+ if !haskey(space, weight_w)
+ space[weight_w] = sparse_matrix(QQ)
+ end
+ Hecke._add_row_to_rref!(space[weight_w], change_base_ring(QQ, vec))
+ end
end
# identify coordinates that are trivially zero because of the action on the generator
- zero_coordinates = compute_zero_coordinates(birational_sequence, highest_weight)
+ zero_coordinates = compute_zero_coordinates(birational_seq, highest_weight)
# calculate new monomials
for weight_w in weights_with_non_full_weightspace
dim_weightspace = weightspaces[weight_w]
add_new_monomials!(
L,
- birational_sequence,
+ birational_seq,
ZZx,
matrices_of_operators,
monomial_ordering,
weightspaces,
dim_weightspace,
weight_w,
+ highest_weight,
monomials_in_weightspace,
space,
v0,
@@ -457,48 +425,33 @@ function add_by_hand(
return basis
end
+function operators_asc_height(L::LieAlgebra)
+ return positive_roots(root_system(L))
+end
+
function operators_by_index(
- L::LieAlgebraStructure,
- chevalley_basis::NTuple{3,Vector{GAP.Obj}},
- birational_sequence::Vector{Int},
+ L::LieAlgebra,
+ birational_seq::Vector{Int},
)
- @req all(i -> 1 <= i <= number_of_positive_roots(L), birational_sequence) "Entry of birational_sequence out of bounds"
-
- return [chevalley_basis[1][i] for i in birational_sequence] # TODO: change to [2]
+ return operators_asc_height(L)[birational_seq]
end
function operators_by_simple_roots(
- L::LieAlgebraStructure,
- chevalley_basis::NTuple{3,Vector{GAP.Obj}},
- birational_sequence::Vector{Vector{Int}},
+ L::LieAlgebra,
+ birational_seq::Vector{Vector{Int}},
)
- rs = root_system_gap(L)
- simple_roots = Vector{Vector{Int}}(GAP.Globals.SimpleSystem(rs))
- positive_roots = Vector{Vector{Int}}(GAP.Globals.PositiveRoots(rs))
-
- root_inds = Int[]
- for whgt_alpha in birational_sequence
- @req length(whgt_alpha) == rank(L) "Length mismatch"
- @req all(>=(0), whgt_alpha) "Only positive roots are allowed as input"
- root = sum(whgt_alpha .* simple_roots)
- root_ind = findfirst(==(root), positive_roots)
- @req !isnothing(root_ind) "$whgt_alpha is not a positive root"
- push!(root_inds, root_ind)
+ R = root_system(L)
+ operators = map(birational_seq) do whgt_alpha
+ root = RootSpaceElem(R, whgt_alpha)
+ fl = is_positive_root(root)
+ @req fl "Only positive roots are allowed as input"
+ root
end
- return operators_by_index(L, chevalley_basis, root_inds)
-end
-
-function operators_lusztig(
- L::LieAlgebraStructure,
- chevalley_basis::NTuple{3,Vector{GAP.Obj}},
- reduced_expression::Vector{Int},
-)
- root_inds = operators_lusztig_indices(L, reduced_expression)
- return operators_by_index(L, chevalley_basis, root_inds)
+ return operators
end
-function operators_lusztig_indices(L::LieAlgebraStructure, word::Vector{Int})
+function operators_lusztig(L::LieAlgebra, reduced_expression::Vector{Int})
# Computes the operators for the lusztig polytopes for a longest weyl-word
# reduced_expression.
@@ -509,44 +462,21 @@ function operators_lusztig_indices(L::LieAlgebraStructure, word::Vector{Int})
# \beta_2 = \alpha_1 + \alpha_2
# \beta_3 = \alpha_2
- rs = root_system_gap(L)
-
- simple_roots = GAP.Globals.SimpleSystem(rs)
- positive_roots = Vector{Vector{Int}}(GAP.Globals.PositiveRoots(rs))
- sparse_cartan_matrix = GAP.Globals.SparseCartanMatrix(GAPWrap.WeylGroup(rs))
-
- root_inds = Int[]
-
- for k in 1:length(word)
- # Calculate betas by applying simple reflections step-by-step.
- root = copy(simple_roots[word[k]])
- for j in (k - 1):-1:1
- GAP.Globals.ApplySimpleReflection(sparse_cartan_matrix, word[j], root)
- end
- root_ind = findfirst(==(Vector{Int}(root)), positive_roots)
- @req !isnothing(root_ind) "$root is not a positive root"
- push!(root_inds, root_ind)
+ R = root_system(L)
+ W = weyl_group(R)
+ operators = map(1:length(reduced_expression)) do k
+ root = W(reduced_expression[1:(k - 1)]) * simple_root(R, reduced_expression[k])
+ fl = is_positive_root(root)
+ @req fl "Only positive roots may occur here"
+ root
end
- return root_inds
+ return operators
end
-@doc """
- is_fundamental(highest_weight::Vector{IntegerUnion}) -> Bool
-
-Return if ``highest_weight`` is fundamental, i.e. [0, ..., 1, ..., 0].
-
-# Examples
-```jldoctest
-julia> BasisLieHighestWeight.is_fundamental([0, 1, 0])
-true
-
-julia> BasisLieHighestWeight.is_fundamental([0, 1, 1])
-false
-```
-"""
-function is_fundamental(highest_weight::Vector{<:IntegerUnion})
+# TODO: upstream to LieAlgebras/RootSystem.jl
+function is_fundamental(highest_weight::WeightLatticeElem)
hasone = false
- for i in highest_weight
+ for i in coefficients(highest_weight)
if iszero(i)
continue
elseif isone(i)
@@ -559,19 +489,16 @@ function is_fundamental(highest_weight::Vector{<:IntegerUnion})
return hasone
end
-function compute_sub_weights(highest_weight::Vector{ZZRingElem})
- # returns list of weights w != 0, highest_weight with 0 <= w <= highest_weight elementwise, ordered by l_2-norm
-
- sub_weights_w = []
- foreach(Iterators.product((0:x for x in highest_weight)...)) do i
- push!(sub_weights_w, [i...])
- end
- if isempty(sub_weights_w) || length(sub_weights_w) == 1 # case [] or [[0, ..., 0]]
- return []
- else
- popfirst!(sub_weights_w) # [0, ..., 0]
- pop!(sub_weights_w) # highest_weight
- sort!(sub_weights_w; by=x -> sum((x) .^ 2))
- return sub_weights_w
+function sub_weights(w::WeightLatticeElem)
+ # returns list of weights v != 0, highest_weight with 0 <= v <= w elementwise
+ @req is_dominant(w) "The input must be a dominant weight"
+ R = root_system(w)
+ map(AbstractAlgebra.ProductIterator([0:w[i] for i in 1:rank(R)])) do coeffs
+ WeightLatticeElem(R, coeffs)
end
end
+
+function sub_weights_proper(w::WeightLatticeElem)
+ # returns list of weights v != 0, highest_weight with 0 <= v <= w elementwise, but neither 0 nor w
+ return filter(x -> !iszero(x) && x != w, sub_weights(w))
+end
diff --git a/experimental/BasisLieHighestWeight/src/MonomialBasis.jl b/experimental/BasisLieHighestWeight/src/MonomialBasis.jl
index 84d4e535f7a6..57d0b0d8047e 100644
--- a/experimental/BasisLieHighestWeight/src/MonomialBasis.jl
+++ b/experimental/BasisLieHighestWeight/src/MonomialBasis.jl
@@ -1,23 +1,23 @@
@attributes mutable struct MonomialBasis
- lie_algebra::LieAlgebraStructure
- highest_weight::Vector{Int}
- birational_sequence::BirationalSequence
+ lie_algebra::AbstractLieAlgebra{QQFieldElem}
+ highest_weight::WeightLatticeElem
+ birational_seq::BirationalSequence
monomial_ordering::MonomialOrdering
dimension::Int
monomials::Set{ZZMPolyRingElem}
monomials_parent::ZZMPolyRing
function MonomialBasis(
- lie_algebra::LieAlgebraStructure,
- highest_weight::Vector{<:IntegerUnion},
- birational_sequence::BirationalSequence,
+ lie_algebra::AbstractLieAlgebra{QQFieldElem},
+ highest_weight::WeightLatticeElem,
+ birational_seq::BirationalSequence,
monomial_ordering::MonomialOrdering,
monomials::Set{ZZMPolyRingElem},
)
return new(
lie_algebra,
- Int.(highest_weight),
- birational_sequence,
+ highest_weight,
+ birational_seq,
monomial_ordering,
length(monomials),
monomials,
@@ -37,15 +37,35 @@ monomials(basis::MonomialBasis) = basis.monomials
monomial_ordering(basis::MonomialBasis) = basis.monomial_ordering
-birational_sequence(basis::MonomialBasis) = basis.birational_sequence
+birational_sequence(basis::MonomialBasis) = basis.birational_seq
function Base.show(io::IO, ::MIME"text/plain", basis::MonomialBasis)
io = pretty(io)
print(io, "Monomial basis of a highest weight module")
- print(io, Indent(), "\nof highest weight $(highest_weight(basis))", Dedent())
+ print(
+ io,
+ Indent(),
+ "\nof highest weight $(Int.(Oscar._vec(coefficients(highest_weight(basis)))))",
+ Dedent(),
+ )
print(io, Indent(), "\nof dimension $(dim(basis))", Dedent())
print(io, Indent(), "\nwith monomial ordering $(monomial_ordering(basis))", Dedent())
- print(io, "\nover ", Lowercase(), base_lie_algebra(basis))
+ # TODO: use the following line instead of printing workaround below
+ # print(io, "\nover ", Lowercase(), base_lie_algebra(basis))
+ # begin of workaround
+ L = base_lie_algebra(basis)
+ print(io, "\nover Lie algebra")
+ if has_root_system(L)
+ rs = root_system(L)
+ if has_root_system_type(rs)
+ type, ord = root_system_type_with_ordering(rs)
+ print(io, " of type ", _root_system_type_string(type))
+ if !issorted(ord)
+ print(io, " (non-canonical ordering)")
+ end
+ end
+ end
+ # end of workaround
if get_attribute(basis, :algorithm, nothing) === basis_lie_highest_weight_compute
print(
io,
@@ -53,8 +73,8 @@ function Base.show(io::IO, ::MIME"text/plain", basis::MonomialBasis)
"\nwhere the used birational sequence consists of the following roots (given as coefficients w.r.t. alpha_i):",
Indent(),
)
- for weight in birational_sequence(basis).weights_alpha
- print(io, '\n', Int.(weight))
+ for root in operators_as_roots(birational_sequence(basis))
+ print(io, '\n', Int.(Oscar._vec(coefficients(root))))
end
print(io, Dedent(), Dedent())
print(
@@ -64,7 +84,7 @@ function Base.show(io::IO, ::MIME"text/plain", basis::MonomialBasis)
Indent(),
)
for gen in get_attribute(basis, :minkowski_gens)
- print(io, '\n', Int.(gen))
+ print(io, '\n', Int.(Oscar._vec(coefficients(gen))))
end
print(io, Dedent(), Dedent())
elseif get_attribute(basis, :algorithm, nothing) === basis_coordinate_ring_kodaira_compute
@@ -74,8 +94,8 @@ function Base.show(io::IO, ::MIME"text/plain", basis::MonomialBasis)
"\nwhere the used birational sequence consists of the following roots (given as coefficients w.r.t. alpha_i):",
Indent(),
)
- for weight in birational_sequence(basis).weights_alpha
- print(io, '\n', Int.(weight))
+ for root in operators_as_roots(birational_sequence(basis))
+ print(io, '\n', Int.(Oscar._vec(coefficients(root))))
end
print(io, Dedent(), Dedent())
print(
@@ -85,7 +105,7 @@ function Base.show(io::IO, ::MIME"text/plain", basis::MonomialBasis)
Indent(),
)
for gen in get_attribute(basis, :minkowski_gens)
- print(io, '\n', Int.(gen))
+ print(io, '\n', Int.(Oscar._vec(coefficients(gen))))
end
print(io, Dedent(), Dedent())
end
@@ -98,8 +118,23 @@ function Base.show(io::IO, basis::MonomialBasis)
io = pretty(io)
print(
io,
- "Monomial basis of a highest weight module with highest weight $(highest_weight(basis)) over ",
+ "Monomial basis of a highest weight module with highest weight $(Int.(Oscar._vec(coefficients(highest_weight(basis))))) over ",
)
- print(terse(io), Lowercase(), base_lie_algebra(basis))
+ # TODO: use the following line instead of printing workaround below
+ # print(terse(io), Lowercase(), base_lie_algebra(basis))
+ # begin of workaround
+ L = base_lie_algebra(basis)
+ print(io, "Lie algebra")
+ if has_root_system(L)
+ rs = root_system(L)
+ if has_root_system_type(rs)
+ type, ord = root_system_type_with_ordering(rs)
+ print(io, " of type ", _root_system_type_string(type))
+ if !issorted(ord)
+ print(io, " (non-canonical ordering)")
+ end
+ end
+ end
+ # end of workaround
end
end
diff --git a/experimental/BasisLieHighestWeight/src/MonomialOrder.jl b/experimental/BasisLieHighestWeight/src/MonomialOrder.jl
index b1dbb134798d..43443e61d289 100644
--- a/experimental/BasisLieHighestWeight/src/MonomialOrder.jl
+++ b/experimental/BasisLieHighestWeight/src/MonomialOrder.jl
@@ -1,11 +1,11 @@
function get_monomial_ordering(
ordering_input::Union{Symbol,Function},
ZZx::ZZMPolyRing,
- weights_alpha::Vector{Vector{QQFieldElem}},
+ operators::Vector{RootSpaceElem},
)
if _is_weighted(ordering_input)
choosen_monomial_order = monomial_ordering(
- ZZx, ordering_input, Int[Int(sum(w)) for w in weights_alpha]
+ ZZx, ordering_input, [Int(height(alpha)) for alpha in operators]
)
else
choosen_monomial_order = monomial_ordering(ZZx, ordering_input)
diff --git a/experimental/BasisLieHighestWeight/src/NewMonomial.jl b/experimental/BasisLieHighestWeight/src/NewMonomial.jl
index 3af1055a78c8..3f28c032e5b0 100644
--- a/experimental/BasisLieHighestWeight/src/NewMonomial.jl
+++ b/experimental/BasisLieHighestWeight/src/NewMonomial.jl
@@ -1,6 +1,9 @@
-function weight(mon::ZZMPolyRingElem, weights_w::Vector{Vector{ZZRingElem}})
- @assert length(weights_w) == length(degrees(mon))
- return sum(exp * weight for (exp, weight) in zip(degrees(mon), weights_w))
+function weight(mon::ZZMPolyRingElem, birational_seq::BirationalSequence)
+ @assert length(birational_seq) == nvars(parent(mon))
+ return sum(
+ exp * weight for
+ (exp, weight) in zip(degrees(mon), operators_as_weights(birational_seq))
+ )
end
function calc_vec(
diff --git a/experimental/BasisLieHighestWeight/src/RootConversion.jl b/experimental/BasisLieHighestWeight/src/RootConversion.jl
deleted file mode 100644
index c1f83d9a0964..000000000000
--- a/experimental/BasisLieHighestWeight/src/RootConversion.jl
+++ /dev/null
@@ -1,9 +0,0 @@
-function w_to_alpha(
- L::LieAlgebraStructure, weight_w::Union{Vector{ZZRingElem},Vector{QQFieldElem}}
-)
- return weight_w * inv_cartan_matrix(L)
-end
-
-function alpha_to_w(L::LieAlgebraStructure, weight_alpha::Vector{QQFieldElem})
- return weight_alpha * cartan_matrix(L)
-end
diff --git a/experimental/BasisLieHighestWeight/src/TensorModels.jl b/experimental/BasisLieHighestWeight/src/TensorModels.jl
index c154d006e890..a8eb645dccd8 100644
--- a/experimental/BasisLieHighestWeight/src/TensorModels.jl
+++ b/experimental/BasisLieHighestWeight/src/TensorModels.jl
@@ -14,7 +14,7 @@ function _tensor_power(A, k)
end
@doc raw"""
- tensor_matrices_of_operators(L::LieAlgebraStructure, highest_weight::Vector{ZZRingElem}, operators::Vector{GAP.Obj}) -> Vector{SMat{ZZRingElem}}
+ tensor_matrices_of_operators(L::LieAlgebra, highest_weight::WeightLatticeElem, operators::Vector{RootSpaceElem}) -> Vector{SMat{ZZRingElem}}
Calculates the action matrices of the operators in `operators` on
the tensor product of multiples of the fundamental modules (with multiplicities in `highest_weight`).
@@ -22,20 +22,19 @@ Note that the highest weight module with highest weight `highest_weight` is a su
We use multiples of fundamentals to reduce the total dimension of the ambient space
"""
function tensor_matrices_of_operators(
- L::LieAlgebraStructure, highest_weight::Vector{ZZRingElem}, operators::Vector{GAP.Obj}
+ L::LieAlgebra, highest_weight::WeightLatticeElem, operators::Vector{RootSpaceElem}
)
- matrices_of_operators = [zero_matrix(SMat, ZZ, 1) for _ in operators]
- for (i, highest_weight_i) in enumerate(Int.(highest_weight))
- if highest_weight_i <= 0
- continue
- end
- wi = ZZ.(1:length(highest_weight) .== i) # i-th fundamental weight
- matrices_of_operators = [
+ R = root_system(L)
+ mats = [zero_matrix(SMat, ZZ, 1) for _ in operators]
+ for i in 1:rank(R)
+ highest_weight_i = highest_weight[i]
+ iszero(highest_weight_i) && continue
+ mats = [
_tensor_product(mat_temp, mat_wi) for (mat_temp, mat_wi) in zip(
- matrices_of_operators,
- matrices_of_operators_gap(L, highest_weight_i * wi, operators),
+ mats,
+ matrices_of_operators(L, highest_weight_i * fundamental_weight(R, i), operators),
)
]
end
- return matrices_of_operators
+ return mats
end
diff --git a/experimental/BasisLieHighestWeight/src/UserFunctions.jl b/experimental/BasisLieHighestWeight/src/UserFunctions.jl
index 8a69177f94dc..1e2db62f0eb3 100644
--- a/experimental/BasisLieHighestWeight/src/UserFunctions.jl
+++ b/experimental/BasisLieHighestWeight/src/UserFunctions.jl
@@ -17,11 +17,8 @@ julia> basis_lie_highest_weight_operators(:B, 2)
```
"""
function basis_lie_highest_weight_operators(type::Symbol, rank::Int)
- L = lie_algebra(type, rank)
- chevalley_basis = chevalley_basis_gap(L)
- operators = chevalley_basis[1] # TODO: change to [2]
- weights_alpha = [w_to_alpha(L, weight(L, op)) for op in operators]
- return collect(enumerate(weights_alpha))
+ R = root_system(type, rank)
+ return collect(enumerate(map(r -> Oscar._vec(coefficients(r)), positive_roots(R)))) # TODO: clean up
end
@doc raw"""
@@ -112,8 +109,8 @@ over Lie algebra of type C3
[0, 0, 1]
[1, 1, 0]
[0, 1, 1]
- [1, 1, 1]
[0, 2, 1]
+ [1, 1, 1]
[1, 2, 1]
[2, 2, 1]
and the basis was generated by Minkowski sums of the bases of the following highest weight modules:
@@ -127,9 +124,8 @@ over Lie algebra of type C3
function basis_lie_highest_weight(
type::Symbol, rank::Int, highest_weight::Vector{Int}; monomial_ordering::Symbol=:degrevlex
)
- L = lie_algebra(type, rank)
- chevalley_basis = chevalley_basis_gap(L)
- operators = chevalley_basis[1] # TODO: change to [2]
+ L = lie_algebra(QQ, type, rank)
+ operators = operators_asc_height(L)
return basis_lie_highest_weight_compute(L, highest_weight, operators, monomial_ordering)
end
@@ -140,9 +136,8 @@ function basis_lie_highest_weight(
birational_sequence::Vector{Int};
monomial_ordering::Symbol=:degrevlex,
)
- L = lie_algebra(type, rank)
- chevalley_basis = chevalley_basis_gap(L)
- operators = operators_by_index(L, chevalley_basis, birational_sequence)
+ L = lie_algebra(QQ, type, rank)
+ operators = operators_by_index(L, birational_sequence)
return basis_lie_highest_weight_compute(L, highest_weight, operators, monomial_ordering)
end
@@ -153,9 +148,8 @@ function basis_lie_highest_weight(
birational_sequence::Vector{Vector{Int}};
monomial_ordering::Symbol=:degrevlex,
)
- L = lie_algebra(type, rank)
- chevalley_basis = chevalley_basis_gap(L)
- operators = operators_by_simple_roots(L, chevalley_basis, birational_sequence)
+ L = lie_algebra(QQ, type, rank)
+ operators = operators_by_simple_roots(L, birational_sequence)
return basis_lie_highest_weight_compute(L, highest_weight, operators, monomial_ordering)
end
@@ -205,9 +199,8 @@ function basis_lie_highest_weight_lusztig(
type::Symbol, rank::Int, highest_weight::Vector{Int}, reduced_expression::Vector{Int}
)
monomial_ordering = :wdegrevlex
- L = lie_algebra(type, rank)
- chevalley_basis = chevalley_basis_gap(L)
- operators = operators_lusztig(L, chevalley_basis, reduced_expression)
+ L = lie_algebra(QQ, type, rank)
+ operators = operators_lusztig(L, reduced_expression)
return basis_lie_highest_weight_compute(L, highest_weight, operators, monomial_ordering)
end
@@ -276,9 +269,8 @@ function basis_lie_highest_weight_string(
type::Symbol, rank::Int, highest_weight::Vector{Int}, reduced_expression::Vector{Int}
)
monomial_ordering = :neglex
- L = lie_algebra(type, rank)
- chevalley_basis = chevalley_basis_gap(L)
- operators = operators_by_index(L, chevalley_basis, reduced_expression)
+ L = lie_algebra(QQ, type, rank)
+ operators = operators_by_index(L, reduced_expression)
return basis_lie_highest_weight_compute(L, highest_weight, operators, monomial_ordering)
end
@@ -316,9 +308,8 @@ over Lie algebra of type A3
"""
function basis_lie_highest_weight_ffl(type::Symbol, rank::Int, highest_weight::Vector{Int})
monomial_ordering = :degrevlex
- L = lie_algebra(type, rank)
- chevalley_basis = chevalley_basis_gap(L)
- operators = reverse(chevalley_basis[1]) # TODO: change to [2]
+ L = lie_algebra(QQ, type, rank)
+ operators = reverse(operators_asc_height(L))
# we reverse the order here to have simple roots at the right end, this is then a good ordering.
# simple roots at the right end speed up the program very much
return basis_lie_highest_weight_compute(L, highest_weight, operators, monomial_ordering)
@@ -389,9 +380,8 @@ function basis_lie_highest_weight_nz(
type::Symbol, rank::Int, highest_weight::Vector{Int}, reduced_expression::Vector{Int}
)
monomial_ordering = :degrevlex
- L = lie_algebra(type, rank)
- chevalley_basis = chevalley_basis_gap(L)
- operators = operators_by_index(L, chevalley_basis, reduced_expression)
+ L = lie_algebra(QQ, type, rank)
+ operators = operators_by_index(L, reduced_expression)
return basis_lie_highest_weight_compute(L, highest_weight, operators, monomial_ordering)
end
@@ -406,7 +396,7 @@ with highest weight `highest_weight` for a simple Lie algebra $L$ of type `type`
Furthermore, for each degree, return the monomials that are not contained in the Minkowski sum
of the bases of the lower degrees.
-!!! warn
+!!! warning
Currently, this function expects $-w_0(\lambda)$ instead of $\lambda$ as the `highest_weight` input.
This might change in a minor release.
@@ -466,9 +456,8 @@ function basis_coordinate_ring_kodaira(
degree::Int;
monomial_ordering::Symbol=:degrevlex,
)
- L = lie_algebra(type, rank)
- chevalley_basis = chevalley_basis_gap(L)
- operators = chevalley_basis[1] # TODO: change to [2]
+ L = lie_algebra(QQ, type, rank)
+ operators = operators_asc_height(L)
return basis_coordinate_ring_kodaira_compute(
L, highest_weight, degree, operators, monomial_ordering
)
@@ -482,9 +471,8 @@ function basis_coordinate_ring_kodaira(
birational_sequence::Vector{Int};
monomial_ordering::Symbol=:degrevlex,
)
- L = lie_algebra(type, rank)
- chevalley_basis = chevalley_basis_gap(L)
- operators = operators_by_index(L, chevalley_basis, birational_sequence)
+ L = lie_algebra(QQ, type, rank)
+ operators = operators_by_index(L, birational_sequence)
return basis_coordinate_ring_kodaira_compute(
L, highest_weight, degree, operators, monomial_ordering
)
@@ -498,9 +486,8 @@ function basis_coordinate_ring_kodaira(
birational_sequence::Vector{Vector{Int}};
monomial_ordering::Symbol=:degrevlex,
)
- L = lie_algebra(type, rank)
- chevalley_basis = chevalley_basis_gap(L)
- operators = operators_by_simple_roots(L, chevalley_basis, birational_sequence)
+ L = lie_algebra(QQ, type, rank)
+ operators = operators_by_simple_roots(L, birational_sequence)
return basis_coordinate_ring_kodaira_compute(
L, highest_weight, degree, operators, monomial_ordering
)
@@ -515,7 +502,7 @@ with highest weight `highest_weight` for a simple Lie algebra $L$ of type `type`
Furthermore, for each degree, return the monomials that are not contained in the Minkowski sum
of the bases of the lower degrees.
-!!! warn
+!!! warning
Currently, this function expects $-w_0(\lambda)$ instead of $\lambda$ as the `highest_weight` input.
This might change in a minor release.
@@ -564,9 +551,8 @@ function basis_coordinate_ring_kodaira_ffl(
type::Symbol, rank::Int, highest_weight::Vector{Int}, degree::Int
)
monomial_ordering = :degrevlex
- L = lie_algebra(type, rank)
- chevalley_basis = chevalley_basis_gap(L)
- operators = reverse(chevalley_basis[1]) # TODO: change to [2]
+ L = lie_algebra(QQ, type, rank)
+ operators = reverse(operators_asc_height(L))
# we reverse the order here to have simple roots at the right end, this is then a good ordering.
# simple roots at the right end speed up the program very much
return basis_coordinate_ring_kodaira_compute(
diff --git a/experimental/BasisLieHighestWeight/src/WeylPolytope.jl b/experimental/BasisLieHighestWeight/src/WeylPolytope.jl
index 72cbeec859c2..066d60c262a6 100644
--- a/experimental/BasisLieHighestWeight/src/WeylPolytope.jl
+++ b/experimental/BasisLieHighestWeight/src/WeylPolytope.jl
@@ -1,51 +1,3 @@
-
-@doc raw"""
- orbit_weylgroup(L::LieAlgebraStructure, weight_w::Vector{ZZRingElem}) -> Vector{Vector{ZZRingElem}}
-
-Computes the orbit of the weight `weight_w` given as coefficients to the fundamental weights
-$\omega_i$ under the action of the Weyl group of the Lie algebra `L`.
-"""
-function orbit_weylgroup(L::LieAlgebraStructure, weight_w::Vector{ZZRingElem})
- # initialization
- weyl_group = GAPWrap.WeylGroup(GAPWrap.RootSystem(L.lie_algebra_gap))
- orbit_iterator = GAPWrap.WeylOrbitIterator(weyl_group, GAP.Obj(Int.(weight_w)))
- vertices = Vector{ZZRingElem}[]
-
- # operate with the weylgroup on weight_vector
- while !(GAPWrap.IsDoneIterator(orbit_iterator))
- w = GAPWrap.NextIterator(orbit_iterator)
- push!(vertices, Vector{ZZRingElem}(w))
- end
-
- return vertices
-end
-
-@doc raw"""
- get_dim_weightspace(L::LieAlgebraStructure, highest_weight::Vector{ZZRingElem}) -> Dict{Vector{ZZRingElem},Int}
-
-Computes the dimension of the weight spaces of the Lie algebra `L` module with highest weight `highest_weight`.
-For all dominant weights, the dimension is computed with GAP. For the remaining weights, the dimension is
-calculated by checking which dominant weight lies in the orbit of the weight under the action of the Weyl group.
-
-The weights are given as coefficients to the fundamental weights $\omega_i$.
-"""
-function get_dim_weightspace(L::LieAlgebraStructure, highest_weight::Vector{ZZRingElem})
- # calculate dimension for dominant weights with GAP
- root_system = root_system_gap(L)
- dominant_char = GAP.Globals.DominantCharacter(root_system, GAP.Obj(Int.(highest_weight)))
- dominant_weights = map(weight -> ZZ.(weight), dominant_char[1])
- dominant_weights_dim = Int.(dominant_char[2])
- weightspaces = Dict{Vector{ZZRingElem},Int}()
-
- # calculate dimension for the rest by checking which dominant weight lies in the orbit
- for (dominant_weight, dim) in zip(dominant_weights, dominant_weights_dim)
- for weight in orbit_weylgroup(L, dominant_weight)
- weightspaces[highest_weight - weight] = dim
- end
- end
- return weightspaces
-end
-
function convert_lattice_points_to_monomials(
ZZx::ZZMPolyRing, lattice_points_weightspace::Vector{Vector{ZZRingElem}}
)
@@ -62,62 +14,59 @@ where the coordinates in `zero_coordinates` are set to zero.
All weights are given as coefficients to the simple roots $\alpha_i$.
"""
function get_lattice_points_of_weightspace(
- root_weights::Vector{Vector{QQFieldElem}},
- weight::Vector{QQFieldElem},
+ root_weights::Vector{RootSpaceElem},
+ weight::RootSpaceElem,
zero_coordinates::Vector{Int},
)
# calculate all integer solutions to the following linear program:
- # [ | | ] [ x ]
+ # [ | | ] [ x ]
# [root_weights[1]...root_weights[k]] * [ | ] = weight
- # [ | | ] [ res ]
- # [ | | ] [ | ]
+ # [ | | ] [ res ]
+ # [ | | ] [ | ]
# where res[i] >= 0 for all i
n = length(root_weights)
- m = length(weight)
-
- A = zero_matrix(QQ, 2m + n + length(zero_coordinates), n)
- b = [zero(QQ) for _ in 1:(2m + n + length(zero_coordinates))]
+ m = rank(root_system(weight))
# equalities
+ A_eq = zero_matrix(QQ, m + length(zero_coordinates), n)
+ b_eq = [zero(QQ) for _ in 1:(m + length(zero_coordinates))]
for i in 1:n
- w = matrix(QQ, m, 1, root_weights[i])
- A[1:m, i] = w
- A[(m + 1):(2m), i] = -w
- end
-
- b[1:m] = weight
- b[(m + 1):(2m)] = -weight
- # non-negativity
- for i in 1:n
- A[2m + i, i] = -1
+ A_eq[1:m, i] = transpose(coefficients(root_weights[i]))
end
+ b_eq[1:m] = view(coefficients(weight), 1, :)
for (j, i) in enumerate(zero_coordinates)
- A[2m + n + j, i] = 1
- b[2m + n + j] = 0
+ A_eq[m + j, i] = 1
end
- sol = Vector{ZZRingElem}.(lattice_points(polyhedron(A, b)))
+
+ # non-negativity
+ A_ineq = -identity_matrix(QQ, n)
+ b_ineq = [zero(QQ) for _ in 1:n]
+
+ sol = Vector{ZZRingElem}.(lattice_points(polyhedron((A_ineq, b_ineq), (A_eq, b_eq))))
return sol
end
@doc raw"""
- compute_zero_coordinates(bir_sequence::BirationalSequence, highest_weight::Vector{ZZRingElem})
+ compute_zero_coordinates(bir_sequence::BirationalSequence, highest_weight::WeightLatticeElem)
This function returns all indices into the birational sequence `bir_sequence` that correspond to
root vectors that are in the annihilator of the submodule generated by everything on their right
on the highest weight vector.
"""
function compute_zero_coordinates(
- bir_sequence::BirationalSequence, highest_weight::Vector{ZZRingElem}
+ bir_sequence::BirationalSequence, highest_weight::WeightLatticeElem
)
- n = length(bir_sequence.weights_alpha)
- m = length(highest_weight)
- non_zeros = Set{Int}(findall(!iszero, highest_weight))
+ n = length(bir_sequence)
+ m = rank(root_system(highest_weight))
+ non_zeros = Set(findall(!iszero, coefficients(highest_weight)))
zero_coordinates = Int[]
for c in n:-1:1
length(non_zeros) == m && break
- if !isdisjoint(non_zeros, findall(!iszero, bir_sequence.weights_alpha[c]))
- union!(non_zeros, findall(<(0), bir_sequence.weights_w[c]))
+ if !isdisjoint(
+ non_zeros, findall(!iszero, coefficients(operator_as_root(bir_sequence, c)))
+ )
+ union!(non_zeros, findall(<(0), coefficients(operator_as_weight(bir_sequence, c))))
else
push!(zero_coordinates, c)
end
diff --git a/experimental/BasisLieHighestWeight/test/MBOld.jl b/experimental/BasisLieHighestWeight/test/MBOld.jl
index fe9c9760c27b..fc6f0eab8ec9 100644
--- a/experimental/BasisLieHighestWeight/test/MBOld.jl
+++ b/experimental/BasisLieHighestWeight/test/MBOld.jl
@@ -71,7 +71,7 @@ end
#### Lie algebras
function lieAlgebra(t::String, n::Int)
- L = GAP.Globals.SimpleLieAlgebra(GAP.Obj(t), n, GAP.Globals.Rationals)
+ L = codomain(Oscar.iso_oscar_gap(Oscar.lie_algebra(QQ, Symbol(t), n)))
return L, NTuple{3,Vector{GAP.Obj}}(GAP.Globals.ChevalleyBasis(L))
end
@@ -214,9 +214,10 @@ function compute(v0, mats, wts::Vector{Vector{Int}})
newPos = length(monomials)
deg = deg + 1
newMons(deg)
- for i in 1:m, di in deg:-1:1
+ # iteration in degrevlex ordering
+ for i in m:-1:1, di in deg:-1:1
for p in startPos:newPos
- if !all(monomials[p][1:(i - 1)] .== 0)
+ if !all(monomials[p][(i + 1):m] .== 0)
continue
end
diff --git a/experimental/BasisLieHighestWeight/test/MainAlgorithm-test.jl b/experimental/BasisLieHighestWeight/test/MainAlgorithm-test.jl
index 4b9e06bb02e8..88eae9d1ddaa 100644
--- a/experimental/BasisLieHighestWeight/test/MainAlgorithm-test.jl
+++ b/experimental/BasisLieHighestWeight/test/MainAlgorithm-test.jl
@@ -31,43 +31,53 @@ function check_dimension(
@test gap_dim == dim(basis) == length(monomials(basis)) # check if dimension is correct
end
-@testset "Test BasisLieHighestWeight" begin
- @testset "is_fundamental" begin
- @test BasisLieHighestWeight.is_fundamental([ZZ(0), ZZ(1), ZZ(0)])
- @test !BasisLieHighestWeight.is_fundamental([ZZ(0), ZZ(1), ZZ(1)])
- end
+@testset "is_fundamental" begin
+ R = root_system(:B, 3)
+ @test BasisLieHighestWeight.is_fundamental(WeightLatticeElem(R, [ZZ(0), ZZ(1), ZZ(0)]))
+ @test !BasisLieHighestWeight.is_fundamental(WeightLatticeElem(R, [ZZ(0), ZZ(1), ZZ(1)]))
+end
- @testset "compute_sub_weights" begin
- @test isequal(BasisLieHighestWeight.compute_sub_weights([ZZ(0), ZZ(0), ZZ(0)]), [])
- sub_weights = Vector{Vector{ZZRingElem}}([
- [1, 0, 0],
- [0, 1, 0],
+@testset "sub_weights(_proper)" begin
+ sub_weights = BasisLieHighestWeight.sub_weights
+ sub_weights_proper = BasisLieHighestWeight.sub_weights_proper
+ R = root_system(:B, 3)
+
+ w_zero = zero(WeightLatticeElem, R)
+ @test issetequal(sub_weights(w_zero), [w_zero])
+ @test isempty(sub_weights_proper(w_zero))
+
+ w_231 = WeightLatticeElem(R, [2, 3, 1])
+ sub_weights_proper_231 = [
+ WeightLatticeElem(R, coeffs) for coeffs in [
[0, 0, 1],
- [1, 1, 0],
- [1, 0, 1],
+ [0, 1, 0],
[0, 1, 1],
- [1, 1, 1],
- [2, 0, 0],
[0, 2, 0],
- [2, 1, 0],
+ [0, 2, 1],
+ [0, 3, 0],
+ [0, 3, 1],
+ [1, 0, 0],
+ [1, 0, 1],
+ [1, 1, 0],
+ [1, 1, 1],
[1, 2, 0],
+ [1, 2, 1],
+ [1, 3, 0],
+ [1, 3, 1],
+ [2, 0, 0],
[2, 0, 1],
- [0, 2, 1],
+ [2, 1, 0],
[2, 1, 1],
- [1, 2, 1],
[2, 2, 0],
- [0, 3, 0],
[2, 2, 1],
- [1, 3, 0],
- [0, 3, 1],
- [1, 3, 1],
[2, 3, 0],
- ])
- @test isequal(
- BasisLieHighestWeight.compute_sub_weights([ZZ(2), ZZ(3), ZZ(1)]), sub_weights
- )
- end
+ ]
+ ]
+ @test issetequal(sub_weights(w_231), [w_zero, w_231, sub_weights_proper_231...])
+ @test issetequal(sub_weights_proper(w_231), sub_weights_proper_231)
+end
+@testset "Test BasisLieHighestWeight" begin
@testset "Known examples basis_lie_highest_weight" begin
base = basis_lie_highest_weight(:A, 2, [1, 0])
mons = monomials(base)
diff --git a/experimental/BasisLieHighestWeight/test/NewMonomial-test.jl b/experimental/BasisLieHighestWeight/test/NewMonomial-test.jl
index a2f78f125a10..966b99ad68e4 100644
--- a/experimental/BasisLieHighestWeight/test/NewMonomial-test.jl
+++ b/experimental/BasisLieHighestWeight/test/NewMonomial-test.jl
@@ -2,11 +2,14 @@
weight = BasisLieHighestWeight.weight
calc_vec = BasisLieHighestWeight.calc_vec
+ R = root_system(:A, 2)
ZZx, _ = polynomial_ring(ZZ, 2)
x = gens(ZZx)
mon1 = ZZx(1)
mon2 = x[1]^2 * x[2]
- weights = [[ZZ(1), ZZ(1)], [ZZ(2), ZZ(1)]]
+ birational_seq = birational_sequence([
+ WeightLatticeElem(R, [ZZ(1), ZZ(1)]), WeightLatticeElem(R, [ZZ(2), ZZ(1)])
+ ])
A = sparse_matrix(ZZ, 2, 2) # [0, 2; 1, 1]
setindex!(A, sparse_row(ZZ, [2], [ZZ(2)]), 1)
setindex!(A, sparse_row(ZZ, [1, 2], [ZZ(1), ZZ(1)]), 2)
@@ -19,12 +22,12 @@
mon2_vec = sparse_row(ZZ, [1, 2], [2, 2])
@testset "weight" begin
- @test isequal(weight(mon1, weights), [ZZ(0), ZZ(0)])
- @test isequal(weight(mon2, weights), [ZZ(4), ZZ(3)])
+ @test weight(mon1, birational_seq) == WeightLatticeElem(R, [ZZ(0), ZZ(0)])
+ @test weight(mon2, birational_seq) == WeightLatticeElem(R, [ZZ(4), ZZ(3)])
end
@testset "calc_vec" begin
- @test isequal(calc_vec(v0, mon1, matrices_of_operators), v0)
- @test isequal(calc_vec(v0, mon2, matrices_of_operators), mon2_vec)
+ @test calc_vec(v0, mon1, matrices_of_operators) == v0
+ @test calc_vec(v0, mon2, matrices_of_operators) == mon2_vec
end
end
diff --git a/experimental/BasisLieHighestWeight/test/RootConversion-test.jl b/experimental/BasisLieHighestWeight/test/RootConversion-test.jl
deleted file mode 100644
index 558d0039f698..000000000000
--- a/experimental/BasisLieHighestWeight/test/RootConversion-test.jl
+++ /dev/null
@@ -1,27 +0,0 @@
-
-@testset "Test RootConversion" begin
- w_to_alpha = BasisLieHighestWeight.w_to_alpha
- alpha_to_w = BasisLieHighestWeight.alpha_to_w
-
- function test_inverse_alpha_w(L, weight)
- @test w_to_alpha(L, alpha_to_w(L, weight)) == weight # alpha -> w -> alpha
- @test alpha_to_w(L, w_to_alpha(L, weight)) == weight # w -> alpha -> w
- end
-
- @testset "Dynkin type $dynkin" for dynkin in (:A, :B, :C, :D, :E, :F, :G)
- @testset "n = $n" for n in 1:10
- if (
- !(dynkin == :B && n < 2) &&
- !(dynkin == :C && n < 2) &&
- !(dynkin == :D && n < 4) &&
- !(dynkin == :E && !(n == 6 || n == 7 || n == 8)) &&
- !(dynkin == :F && n != 4) &&
- !(dynkin == :G && (n != 2))
- )
- weight = [rand(QQ, -10:10) for _ in 1:n]
- L = BasisLieHighestWeight.lie_algebra(dynkin, n)
- test_inverse_alpha_w(L, weight)
- end
- end
- end
-end
diff --git a/experimental/BasisLieHighestWeight/test/runtests.jl b/experimental/BasisLieHighestWeight/test/runtests.jl
index b07a9d40abbe..4d7a059cc49b 100644
--- a/experimental/BasisLieHighestWeight/test/runtests.jl
+++ b/experimental/BasisLieHighestWeight/test/runtests.jl
@@ -1,3 +1,2 @@
include("NewMonomial-test.jl")
-include("RootConversion-test.jl")
include("MainAlgorithm-test.jl")
diff --git a/experimental/DoubleAndHyperComplexes/docs/src/advice_for_the_programmer.md b/experimental/DoubleAndHyperComplexes/docs/src/advice_for_the_programmer.md
index fa240099606b..709b13d0f9b1 100644
--- a/experimental/DoubleAndHyperComplexes/docs/src/advice_for_the_programmer.md
+++ b/experimental/DoubleAndHyperComplexes/docs/src/advice_for_the_programmer.md
@@ -1,3 +1,8 @@
+```@meta
+CurrentModule = Oscar
+DocTestSetup = Oscar.doctestsetup()
+```
+
# Advice for the programmer
## How to implement my custom double complex?
diff --git a/experimental/DoubleAndHyperComplexes/docs/src/user_interface.md b/experimental/DoubleAndHyperComplexes/docs/src/user_interface.md
index c96bf85fb017..691c34d6020a 100644
--- a/experimental/DoubleAndHyperComplexes/docs/src/user_interface.md
+++ b/experimental/DoubleAndHyperComplexes/docs/src/user_interface.md
@@ -1,6 +1,8 @@
```@meta
CurrentModule = Oscar
+DocTestSetup = Oscar.doctestsetup()
```
+
# Double complexes -- the user's interface
We briefly review the mathematical notion of a double complex.
Let ``\mathcal A`` be an Abelian category. A double complex
diff --git a/experimental/DoubleAndHyperComplexes/src/Morphisms/simplified_complexes.jl b/experimental/DoubleAndHyperComplexes/src/Morphisms/simplified_complexes.jl
index f37708b45121..e0e9ef965493 100644
--- a/experimental/DoubleAndHyperComplexes/src/Morphisms/simplified_complexes.jl
+++ b/experimental/DoubleAndHyperComplexes/src/Morphisms/simplified_complexes.jl
@@ -496,7 +496,7 @@ function _simplify_matrix!(A::SMat; find_pivot=nothing)
# clear the q-th column
for (i, b) in a_col_del
#A[i] = A[i] - uinv*b*a_row # original operation, replaced by inplace arithmetic below
- Hecke.add_scaled_row!(a_row, A[i], -uinv*b)
+ addmul!(A[i], a_row, -uinv*b)
end
A[p] = sparse_row(R, [(q, u)])
@@ -505,7 +505,7 @@ function _simplify_matrix!(A::SMat; find_pivot=nothing)
v = S[p]
for (i, b) in a_col_del
#S[i] = S[i] - uinv*b*v # original operation, replaced by inplace arithmetic below
- Hecke.add_scaled_row!(v, S[i], -uinv*b)
+ addmul!(S[i], v, -uinv*b)
end
# Adjust Sinv_transp
@@ -513,23 +513,23 @@ function _simplify_matrix!(A::SMat; find_pivot=nothing)
inc_row = sparse_row(R)
for (i, a) in a_col_del
#is_zero(Sinv_transp[i]) && continue # can not be true since S is invertible
- Hecke.add_scaled_row!(Sinv_transp[i], inc_row, a)
+ addmul!(inc_row, Sinv_transp[i], a)
end
- Hecke.add_scaled_row!(inc_row, Sinv_transp[p], uinv)
+ addmul!(Sinv_transp[p], inc_row, uinv)
# Adjust T
#T[q] = T[q] + sum(uinv*a*T[i] for (i, a) in a_row_del; init=sparse_row(R))
inc_row = sparse_row(R)
for (i, a) in a_row_del
# is_zero(T[i]) && continue # can not be true since T is invertible
- Hecke.add_scaled_row!(T[i], inc_row, a)
+ addmul!(inc_row, T[i], a)
end
- Hecke.add_scaled_row!(inc_row, T[q], uinv)
+ addmul!(T[q], inc_row, uinv)
# Adjust Tinv_transp
v = deepcopy(Tinv_transp[q])
for (j, b) in a_row_del
- Hecke.add_scaled_row!(v, Tinv_transp[j], -uinv*b)
+ addmul!(Tinv_transp[j], v, -uinv*b)
end
# Kept here for debugging. These must be true:
diff --git a/experimental/ExteriorAlgebra/src/ExteriorAlgebra.jl b/experimental/ExteriorAlgebra/src/ExteriorAlgebra.jl
index 17433aec1d35..d9e115feb27f 100644
--- a/experimental/ExteriorAlgebra/src/ExteriorAlgebra.jl
+++ b/experimental/ExteriorAlgebra/src/ExteriorAlgebra.jl
@@ -84,15 +84,26 @@ function exterior_algebra(K::Ring, varnames::Vector{Symbol})
ExtAlg_singular = Singular.create_ring_from_singular_ring(SINGULAR_PTR)
# Create Quotient ring with special implementation:
ExtAlg, _ = quo(PBW, I; special_impl=ExtAlg_singular) # 2nd result is a QuoMap, apparently not needed
- return ExtAlg, gens(ExtAlg)
+ generators = gens(ExtAlg)
else
ExtAlg, QuoMap = quo(PBW, I)
- return ExtAlg, QuoMap.(PBW_indets)
+ generators = QuoMap.(PBW_indets)
end
+ set_attribute!(ExtAlg, :show, show_exterior_algebra)
+ return ExtAlg, generators
end
AbstractAlgebra.@varnames_interface exterior_algebra(K::Ring, varnames) macros = :no
+function show_exterior_algebra(io::IO, E::PBWAlgQuo)
+ x = symbols(E)
+ io = pretty(io)
+ print(io, "Exterior algebra over ", Lowercase(), coefficient_ring(E))
+ print(io, " in (")
+ join(io, x, ", ")
+ print(io, ")")
+end
+
# # BUGS/DEFICIENCIES (2023-02-13):
# # (1) Computations with elements DO NOT AUTOMATICALLY REDUCE
# # modulo the squares of the generators.
diff --git a/experimental/FTheoryTools/docs/src/g4.md b/experimental/FTheoryTools/docs/src/g4.md
index a6c5c8095da5..ce69a5483f7a 100644
--- a/experimental/FTheoryTools/docs/src/g4.md
+++ b/experimental/FTheoryTools/docs/src/g4.md
@@ -1,5 +1,6 @@
```@meta
CurrentModule = Oscar
+DocTestSetup = Oscar.doctestsetup()
```
# G4-Fluxes
@@ -32,4 +33,44 @@ passes_elementary_quantization_checks(gf::G4Flux)
```
-## Methods
+## Ambient Space Models for G4-Fluxes
+
+Focus on 4-dimensional F-theory models $m$, such that the resolution $\widehat{Y}_4$
+of the defining singular elliptically fibered CY 4-fold $\Y_4 \twoheadrightarrow B_3$
+is defined as hypersurface in a complete and simplicial toric variety $X_\Sigma$. In
+such a setup, it is convenient to focus on $G_4$-fluxes modelled from the restriction
+of elements of $H^{(2,2)}( X_\Sigma, \mathbb{Q})$ to $\widehat{Y}_4$. This method
+identifies a basis of $H^{(2,2)}( X_\Sigma, \mathbb{Q})$ and filters out elements,
+whose restricton to $\widehat{Y}_4$ is obviously trivial.
+
+It is important to elaborate a bit more on the meaning of "obviously". To this end, fix a
+basis element of $H^{(2,2)}( X_\Sigma, \mathbb{Q})$. Let us denote a corresponding algebraic
+cycle by $A = \mathbb{V}(x_i, x_j) \subset X_\Sigma$, where $x_i$, $x_j$ are suitable
+homogeneous coordinates. Furthermore, let $\widehat{Y}_4 = \mathbb{V}( p ) \subset X_\Sigma$.
+Then of course, we can look at the set-theoretic intersection $\mathbb{V}( p, x_i, x_j)$.
+Provided that $p(x_i = 0, x_j = 0)$ is a non-zero constant, this set-theoretic intersection
+is trivial. This is exactly the check conducted by the method `ambient_space_models_of_g4_fluxes`
+below. However, for reasons of simplicity, this approach is avoid a number of sutleties.
+
+Namely, we really have to work out the intersection in the Chow ring, that is we should consider
+the rational equivalence class of the algebraic cycle $A$ and intersect this class with the
+rational equivalence class of the algebraic cycle $\mathbb{V}( p )$. In particular, for
+"unlucky" choices of $i, j$, the algebraic cycles $\mathbb{V}( p )$ and $\mathbb{V}(x_i, x_j)$
+may not intersect transversely. This is for instance the case if $i = j$. Such phenomena are
+addressed in theory by "moving the algebraic cycles into general position", but in practice this
+somewhat tricky. Instances include the following:
+1. $i = j$: Then apparently, a self-intersection of $\mathbb{V}(x_i)$ is involved.
+2. $p(x_i, x_j) \equiv 0$: This is unexpected for dimensional reasons, and indicates a
+non-transverse intersection.
+
+In both instances, one makes use of the linear relations of $X_\Sigma$ to replace the cycle
+ $\mathbb{V}(x_i)$ (and/or $\mathbb{V}(x_j)$) with a rational combination of algebraic cycles
+$R = \sum_{k = 1}^{N}{c_k \cdot A_k}$, such that $R$ is rationally equivalent to $\mathbb{V}(x_i)$.
+From experience, it is then rather common that $R$ and $\mathbb{V}(x_i)$ intersect transversely.
+And if not, then modify the non-transverse intersections by using the linear relations again to
+replace an involved algebraic cycle.
+
+```@docs
+ambient_space_models_of_g4_fluxes(m::AbstractFTheoryModel; check::Bool = true)
+basis_of_h22(v::NormalToricVariety; check::Bool = true)
+```
diff --git a/experimental/FTheoryTools/docs/src/generalities.md b/experimental/FTheoryTools/docs/src/generalities.md
index 007287ac2f46..579577a57a5f 100644
--- a/experimental/FTheoryTools/docs/src/generalities.md
+++ b/experimental/FTheoryTools/docs/src/generalities.md
@@ -1,5 +1,6 @@
```@meta
CurrentModule = Oscar
+DocTestSetup = Oscar.doctestsetup()
```
# Functionality for all F-theory models
diff --git a/experimental/FTheoryTools/docs/src/hypersurface.md b/experimental/FTheoryTools/docs/src/hypersurface.md
index 905a868e24ed..329b67a6d9d5 100644
--- a/experimental/FTheoryTools/docs/src/hypersurface.md
+++ b/experimental/FTheoryTools/docs/src/hypersurface.md
@@ -1,5 +1,6 @@
```@meta
CurrentModule = Oscar
+DocTestSetup = Oscar.doctestsetup()
```
# Hypersurface models
diff --git a/experimental/FTheoryTools/docs/src/introduction.md b/experimental/FTheoryTools/docs/src/introduction.md
index 2a0102c31170..c30d217dea4f 100644
--- a/experimental/FTheoryTools/docs/src/introduction.md
+++ b/experimental/FTheoryTools/docs/src/introduction.md
@@ -1,5 +1,6 @@
```@meta
CurrentModule = Oscar
+DocTestSetup = Oscar.doctestsetup()
```
# Welcome to FTheoryTools
diff --git a/experimental/FTheoryTools/docs/src/literature.md b/experimental/FTheoryTools/docs/src/literature.md
index 3450523bdf87..ddc1ee0f58a1 100644
--- a/experimental/FTheoryTools/docs/src/literature.md
+++ b/experimental/FTheoryTools/docs/src/literature.md
@@ -1,5 +1,6 @@
```@meta
CurrentModule = Oscar
+DocTestSetup = Oscar.doctestsetup()
```
# Literature constructions
diff --git a/experimental/FTheoryTools/docs/src/tate.md b/experimental/FTheoryTools/docs/src/tate.md
index b48f59b4f072..946084fc10f3 100644
--- a/experimental/FTheoryTools/docs/src/tate.md
+++ b/experimental/FTheoryTools/docs/src/tate.md
@@ -1,5 +1,6 @@
```@meta
CurrentModule = Oscar
+DocTestSetup = Oscar.doctestsetup()
```
# Global Tate models
diff --git a/experimental/FTheoryTools/docs/src/weierstrass.md b/experimental/FTheoryTools/docs/src/weierstrass.md
index 008aa1e50b6c..9b423261ea9c 100644
--- a/experimental/FTheoryTools/docs/src/weierstrass.md
+++ b/experimental/FTheoryTools/docs/src/weierstrass.md
@@ -1,5 +1,6 @@
```@meta
CurrentModule = Oscar
+DocTestSetup = Oscar.doctestsetup()
```
# Weierstrass models
diff --git a/experimental/FTheoryTools/src/AbstractFTheoryModels/attributes.jl b/experimental/FTheoryTools/src/AbstractFTheoryModels/attributes.jl
index 85896d9f251a..494b360cf663 100644
--- a/experimental/FTheoryTools/src/AbstractFTheoryModels/attributes.jl
+++ b/experimental/FTheoryTools/src/AbstractFTheoryModels/attributes.jl
@@ -1052,7 +1052,7 @@ julia> qsm_model = literature_model(arxiv_id = "1903.00009", model_parameters =
Hypersurface model over a concrete base
julia> zero_section_class(qsm_model)
-Cohomology class on a normal toric variety given by x32 + 2*x33 + 3*x34 + x35 - x36
+Cohomology class on a normal toric variety given by e2 + 2*u + 3*e4 + e1 - w
```
"""
function zero_section_class(m::AbstractFTheoryModel)
diff --git a/experimental/FTheoryTools/src/FTheoryTools.jl b/experimental/FTheoryTools/src/FTheoryTools.jl
index d8d4cccfa42f..f345d829f8c4 100644
--- a/experimental/FTheoryTools/src/FTheoryTools.jl
+++ b/experimental/FTheoryTools/src/FTheoryTools.jl
@@ -29,6 +29,7 @@ include("LiteratureModels/create_index.jl")
include("G4Fluxes/constructors.jl")
include("G4Fluxes/attributes.jl")
include("G4Fluxes/properties.jl")
+include("G4Fluxes/special_attributes.jl")
include("Serialization/tate_models.jl")
include("Serialization/weierstrass_models.jl")
diff --git a/experimental/FTheoryTools/src/G4Fluxes/special_attributes.jl b/experimental/FTheoryTools/src/G4Fluxes/special_attributes.jl
new file mode 100644
index 000000000000..49e20bc07bcd
--- /dev/null
+++ b/experimental/FTheoryTools/src/G4Fluxes/special_attributes.jl
@@ -0,0 +1,264 @@
+@doc raw"""
+ basis_of_h22(v::NormalToricVariety; check::Bool = true)::Vector{CohomologyClass}
+
+By virtue of Theorem 12.4.1 in [CLS11](@cite), one can compute a monomial
+basis of $H^4(X, \mathbb{Q})$ for a simplicial, complete toric variety $X$
+by truncating its cohomology ring to degree $2$. Inspired by this, this
+method identifies a basis of $H^{(2,2)}(X, \mathbb{Q})$ by multiplying
+pairs of cohomology classes associated with toric coordinates.
+
+By definition, $H^{(2,2)}(X, \mathbb{Q})$ is a subset of $H^{4}(X, \mathbb{Q})$.
+However, by Theorem 9.3.2 in [CLS11](@cite), for complete and simplicial
+toric varieties and $p \neq q$ it holds $H^{(p,q)}(X, \mathbb{Q}) = 0$. It follows
+that for such varieties $H^{(2,2)}(X, \mathbb{Q}) = H^4(X, \mathbb{Q})$ and the
+vector space dimension of those spaces agrees with the Betti number $b_4(X)$.
+
+Note that it can be computationally very demanding to check if a toric variety
+$X$ is complete (and simplicial). The optional argument `check` can be set
+to `false` to skip these tests.
+
+# Examples
+```jldoctest
+julia> Y1 = hirzebruch_surface(NormalToricVariety, 2)
+Normal toric variety
+
+julia> Y2 = hirzebruch_surface(NormalToricVariety, 2)
+Normal toric variety
+
+julia> Y = Y1 * Y2
+Normal toric variety
+
+julia> h22_basis = basis_of_h22(Y, check = false)
+6-element Vector{CohomologyClass}:
+ Cohomology class on a normal toric variety given by xx2*yx2
+ Cohomology class on a normal toric variety given by xt2*yt2
+ Cohomology class on a normal toric variety given by xx2*yt2
+ Cohomology class on a normal toric variety given by xt2*yx2
+ Cohomology class on a normal toric variety given by yx2^2
+ Cohomology class on a normal toric variety given by xx2^2
+
+julia> betti_number(Y, 4) == length(h22_basis)
+true
+```
+"""
+function basis_of_h22(v::NormalToricVariety; check::Bool = true)::Vector{CohomologyClass}
+
+ # (0) Some initial checks
+ if check
+ @req is_complete(v) "Computation of basis of H22 is currently only supported for complete toric varieties"
+ @req is_simplicial(v) "Computation of basis of H22 is currently only supported for simplicial toric varieties"
+ end
+ if dim(v) < 4
+ set_attribute!(v, :basis_of_h22, Vector{CohomologyClass}())
+ end
+ if has_attribute(v, :basis_of_h22)
+ return get_attribute(v, :basis_of_h22)
+ end
+
+ # (1) Prepare some data of the variety
+ mnf = Oscar._minimal_nonfaces(v)
+ ignored_sets = Set([Tuple(sort(Vector{Int}(Polymake.row(mnf, i)))) for i in 1:Polymake.nrows(mnf)])
+
+ # (2) Prepare the linear relations
+ N_lin_rel, my_mat = rref(transpose(matrix(QQ, rays(v))))
+ @req N_lin_rel == nrows(my_mat) "Cannot remove as many variables as there are linear relations - weird!"
+ bad_positions = [findfirst(!iszero, row) for row in eachrow(my_mat)]
+ lin_rels = Dict{Int, Vector{QQFieldElem}}()
+ for k in 1:nrows(my_mat)
+ my_relation = (-1) * my_mat[k, :]
+ my_relation[bad_positions[k]] = 0
+ @req all(k -> k == 0, my_relation[bad_positions]) "Inconsistency!"
+ lin_rels[bad_positions[k]] = my_relation
+ end
+
+ # (3) Prepare a list of those variables that we keep, a.k.a. a basis of H^(1,1)
+ good_positions = setdiff(1:n_rays(v), bad_positions)
+ n_good_positions = length(good_positions)
+
+ # (4) Make a list of all quadratic elements in the cohomology ring, which are not generators of the SR-ideal.
+ N_filtered_quadratic_elements = 0
+ dict_of_filtered_quadratic_elements = Dict{Tuple{Int64, Int64}, Int64}()
+ for k in 1:n_good_positions
+ for l in k:n_good_positions
+ my_tuple = (min(good_positions[k], good_positions[l]), max(good_positions[k], good_positions[l]))
+ if !(my_tuple in ignored_sets)
+ N_filtered_quadratic_elements += 1
+ dict_of_filtered_quadratic_elements[my_tuple] = N_filtered_quadratic_elements
+ end
+ end
+ end
+
+ # (5) We only care about the SR-ideal gens of degree 2. Above, we took care of all relations,
+ # (5) for which both variables are not replaced by one of the linear relations. So, let us identify
+ # (5) all remaining relations of the SR-ideal, and apply the linear relations to them.
+ remaining_relations = Vector{Vector{QQFieldElem}}()
+ for my_tuple in ignored_sets
+
+ # The generator must have degree 2 and at least one variable is to be replaced
+ if length(my_tuple) == 2 && (my_tuple[1] in bad_positions || my_tuple[2] in bad_positions)
+
+ # Represent first variable by list of coefficients, after plugging in the linear relation
+ var1 = zeros(QQ, ncols(my_mat))
+ var1[my_tuple[1]] = 1
+ if my_tuple[1] in bad_positions
+ var1 = lin_rels[my_tuple[1]]
+ end
+
+ # Represent second variable by list of coefficients, after plugging in the linear relation
+ var2 = zeros(QQ, ncols(my_mat))
+ var2[my_tuple[2]] = 1
+ if my_tuple[2] in bad_positions
+ var2 = lin_rels[my_tuple[2]]
+ end
+
+ # Compute the product of the two variables, which represents the new relation
+ prod = zeros(QQ, N_filtered_quadratic_elements)
+ for k in 1:length(var1)
+ if var1[k] != 0
+ for l in 1:length(var2)
+ if var2[l] != 0
+ my_tuple = (min(k, l), max(k, l))
+ if haskey(dict_of_filtered_quadratic_elements, my_tuple)
+ prod[dict_of_filtered_quadratic_elements[my_tuple]] += var1[k] * var2[l]
+ end
+ end
+ end
+ end
+ end
+
+ # Remember the result
+ push!(remaining_relations, prod)
+
+ end
+
+ end
+
+ # (9) Identify variables that we can remove with the remaining relations
+ new_good_positions = 1:N_filtered_quadratic_elements
+ if length(remaining_relations) != 0
+ remaining_relations_matrix = matrix(QQ, remaining_relations)
+ r, new_mat = rref(remaining_relations_matrix)
+ @req r == nrows(remaining_relations_matrix) "Cannot remove a variable via linear relations - weird!"
+ new_bad_positions = [findfirst(!iszero, row) for row in eachrow(new_mat)]
+ new_good_positions = setdiff(1:N_filtered_quadratic_elements, new_bad_positions)
+ end
+
+ # (10) Return the basis elements in terms of cohomology classes
+ S = cohomology_ring(v, check = check)
+ c_ds = [k.f for k in gens(S)]
+ final_list_of_tuples = []
+ for (key, value) in dict_of_filtered_quadratic_elements
+ if value in new_good_positions
+ push!(final_list_of_tuples, key)
+ end
+ end
+ basis_of_h22 = [cohomology_class(v, MPolyQuoRingElem(c_ds[my_tuple[1]]*c_ds[my_tuple[2]], S)) for my_tuple in final_list_of_tuples]
+ set_attribute!(v, :basis_of_h22, basis_of_h22)
+ return basis_of_h22
+
+end
+
+
+@doc raw"""
+ ambient_space_models_of_g4_fluxes(m::AbstractFTheoryModel; check::Bool = true)::Vector{CohomologyClass}
+
+Given an F-theory model $m$ defined as hypersurface in a simplicial and
+complete toric base, we this method first computes a basis of
+$H^(2,2)(X, \mathbb{Q})$ (by use of the method `basis_of_h22` below) and then filters
+out "some" basis elements whose restriction to the hypersurface in question
+is trivial. The exact meaning of "some" is explained above this method.
+
+Note that it can be computationally very demanding to check if a toric variety
+$X$ is complete (and simplicial). The optional argument `check` can be set
+to `false` to skip these tests.
+
+# Examples
+```jldoctest; setup = :(Oscar.LazyArtifacts.ensure_artifact_installed("QSMDB", Oscar.LazyArtifacts.find_artifacts_toml(Oscar.oscardir)))
+julia> B3 = projective_space(NormalToricVariety, 3)
+Normal toric variety
+
+julia> Kbar = anticanonical_divisor_class(B3)
+Divisor class on a normal toric variety
+
+julia> t = literature_model(arxiv_id = "1109.3454", equation = "3.1", base_space = B3, defining_classes = Dict("w"=>Kbar))
+Construction over concrete base may lead to singularity enhancement. Consider computing singular_loci. However, this may take time!
+
+Global Tate model over a concrete base -- SU(5)xU(1) restricted Tate model based on arXiv paper 1109.3454 Eq. (3.1)
+
+julia> g4_amb_list = ambient_space_models_of_g4_fluxes(t)
+2-element Vector{CohomologyClass}:
+ Cohomology class on a normal toric variety given by z^2
+ Cohomology class on a normal toric variety given by y^2
+
+julia> qsm_model = literature_model(arxiv_id = "1903.00009", model_parameters = Dict("k" => 8))
+Hypersurface model over a concrete base
+
+julia> g4_amb_list = ambient_space_models_of_g4_fluxes(qsm_model, check = false);
+
+julia> length(g4_amb_list) == 172
+true
+```
+"""
+function ambient_space_models_of_g4_fluxes(m::AbstractFTheoryModel; check::Bool = true)::Vector{CohomologyClass}
+
+ # Entry check
+ @req base_space(m) isa NormalToricVariety "Base space must be a toric variety for computation of ambient space G4 candidates"
+ if has_attribute(m, :ambient_space_models_of_g4_fluxes)
+ return get_attribute(m, :ambient_space_models_of_g4_fluxes)
+ end
+
+ # Execute entry tests in computation of basis_of_h22. If any of these fail, no need to proceed. Hence, do this first.
+ filtered_h22_basis = basis_of_h22(ambient_space(m), check = check)
+
+ # Prepare data of the toric ambient space
+ gS = gens(cox_ring(ambient_space(m)))
+ mnf = Oscar._minimal_nonfaces(ambient_space(m))
+ sr_ideal_pos = [Vector{Int}(Polymake.row(mnf, i)) for i in 1:Polymake.nrows(mnf)]
+
+ # Filter out basis elements
+ for a in length(filtered_h22_basis):-1:1
+
+ # Find non-zero exponent positions in the polynomial filtered_h22_basis[a]
+ exp_list = collect(exponents(polynomial(filtered_h22_basis[a]).f))[1]
+ vanishing_vars_pos = findall(!=(0), exp_list)
+
+ # Simplify the hypersurface polynomial by setting relevant variables to zero
+ new_pt = divrem(hypersurface_equation(m), gS[vanishing_vars_pos[1]])[2]
+ if length(vanishing_vars_pos) == 2
+ new_pt = divrem(new_pt, gS[vanishing_vars_pos[2]])[2]
+ end
+
+ # If all coefficient of `new_pt` sum to zero, keep this generator.
+ if sum(coefficients(new_pt)) == 0
+ continue
+ end
+
+ # Determine remaining variables, after scaling "away" others.
+ remaining_vars_list = Set(1:length(gS))
+ for my_exps in sr_ideal_pos
+ len_my_exps = length(my_exps)
+ inter_len = count(idx -> idx in vanishing_vars_pos, my_exps)
+ if (len_my_exps == 2 && inter_len == 1) || (len_my_exps == 3 && inter_len == 2)
+ delete!(remaining_vars_list, my_exps[findfirst(idx -> !(idx in vanishing_vars_pos), my_exps)])
+ end
+ end
+ remaining_vars_list = collect(remaining_vars_list)
+
+ # If one monomial of `new_pt` has unset positions, then keep this generator.
+ delete_it = true
+ for exps in exponents(new_pt)
+ if any(x -> x != 0, exps[remaining_vars_list])
+ delete_it = false
+ break
+ end
+ end
+ if delete_it
+ deleteat!(filtered_h22_basis, a)
+ end
+
+ end
+
+ set_attribute!(m, :ambient_space_models_of_g4_fluxes, filtered_h22_basis)
+ return filtered_h22_basis
+
+end
diff --git a/experimental/FTheoryTools/src/exports.jl b/experimental/FTheoryTools/src/exports.jl
index cdcb5d4fa449..6a3f2b2acd41 100644
--- a/experimental/FTheoryTools/src/exports.jl
+++ b/experimental/FTheoryTools/src/exports.jl
@@ -23,6 +23,7 @@ export add_weighted_resolution
export add_weighted_resolution_generating_section
export add_weighted_resolution_zero_section
export ambient_space
+export ambient_space_models_of_g4_fluxes
export analyze_fibers
export arxiv_doi
export arxiv_id
@@ -33,7 +34,9 @@ export arxiv_model_section
export arxiv_version
export associated_literature_models
export base_space
+export basis_of_h22
export blow_up
+export birational_literature_models
export calabi_yau_hypersurface
export chern_class
export chern_classes
@@ -142,7 +145,6 @@ export passes_tadpole_cancellation_check
export passes_verticality_checks
export polytope_index
export put_over_concrete_base
-export birational_literature_models
export resolution_generating_sections
export resolution_zero_sections
export resolutions
diff --git a/experimental/GroebnerWalk/docs/src/introduction.md b/experimental/GroebnerWalk/docs/src/introduction.md
index 2583cb9056cd..de159085f9d3 100644
--- a/experimental/GroebnerWalk/docs/src/introduction.md
+++ b/experimental/GroebnerWalk/docs/src/introduction.md
@@ -1,5 +1,6 @@
```@meta
CurrentModule = Oscar
+DocTestSetup = Oscar.doctestsetup()
```
# Usage
diff --git a/experimental/GroebnerWalk/docs/src/special-ideals.md b/experimental/GroebnerWalk/docs/src/special-ideals.md
index 6c58ef1fe75a..9ca4066b54e1 100644
--- a/experimental/GroebnerWalk/docs/src/special-ideals.md
+++ b/experimental/GroebnerWalk/docs/src/special-ideals.md
@@ -1,5 +1,6 @@
```@meta
CurrentModule = Oscar
+DocTestSetup = Oscar.doctestsetup()
```
# Special ideals used for benchmarking
diff --git a/experimental/GroebnerWalk/src/common.jl b/experimental/GroebnerWalk/src/common.jl
index bf19b1053ce4..6f4d08f99920 100644
--- a/experimental/GroebnerWalk/src/common.jl
+++ b/experimental/GroebnerWalk/src/common.jl
@@ -30,15 +30,15 @@ julia> I = ideal([y^4+ x^3-x^2+x,x^4]);
julia> groebner_walk(I, lex(R))
Gröbner basis with elements
- 1 -> x + y^12 - y^8 + y^4
- 2 -> y^16
+ 1: x + y^12 - y^8 + y^4
+ 2: y^16
with respect to the ordering
lex([x, y])
julia> groebner_walk(I, lex(R); algorithm=:generic)
Gröbner basis with elements
- 1 -> y^16
- 2 -> x + y^12 - y^8 + y^4
+ 1: y^16
+ 2: x + y^12 - y^8 + y^4
with respect to the ordering
lex([x, y])
@@ -46,15 +46,15 @@ julia> set_verbosity_level(:groebner_walk, 1);
julia> groebner_walk(I, lex(R))
Results for standard_walk
-Crossed Cones in:
+Crossed Cones in:
ZZRingElem[1, 1]
ZZRingElem[4, 3]
ZZRingElem[4, 1]
ZZRingElem[12, 1]
Cones crossed: 4
Gröbner basis with elements
- 1 -> x + y^12 - y^8 + y^4
- 2 -> y^16
+ 1: x + y^12 - y^8 + y^4
+ 2: y^16
with respect to the ordering
lex([x, y])
diff --git a/experimental/HasseSchmidt/src/HasseSchmidt.jl b/experimental/HasseSchmidt/src/HasseSchmidt.jl
new file mode 100644
index 000000000000..4ca17d4d37cb
--- /dev/null
+++ b/experimental/HasseSchmidt/src/HasseSchmidt.jl
@@ -0,0 +1,160 @@
+export hasse_derivatives
+
+### We consider Hasse-Schmidt derivatives of polynomials as seen in
+###
+### [FRS21](@cite) Fruehbis-Krueger, Ristau, Schober: 'Embedded desingularization for arithmetic surfaces -- toward a parallel implementation'
+###
+### This is a special case of a more general definition of a Hasse-Schmidt derivative. These more general and rigorous definitions can be found in the following sources:
+###
+### [Cut04](@cite) Cutkosky: 'Resolution of Singularities'
+### [Haz12](@cite) Michiel Hazewinkel: 'Hasse-Schmidt derivations and the Hopf algebra of noncommutative symmetric functions'
+###
+
+################################################################################
+### HASSE-SCHMIDT derivatives for single polynomials
+
+@doc raw"""
+ hasse_derivatives(f::MPolyRingElem)
+
+Return a list of Hasse-Schmidt derivatives of `f`, each with a multiindex `[a_1, ..., a_n]`, where `a_i` describes the number of times `f` was derived w.r.t. the `i`-th variable.
+
+Hasse-Schmidt derivatives as seen in [FRS21](@cite).
+For more general and rigorous definition see [Cut04](@cite) or [Haz12](@cite).
+
+# Examples
+```jldoctest
+julia> R, (x, y) = polynomial_ring(ZZ, ["x", "y"]);
+
+julia> f = 5*x^2 + 3*y^5;
+
+julia> hasse_derivatives(f)
+8-element Vector{Vector{Any}}:
+ [[0, 5], 3]
+ [[0, 4], 15*y]
+ [[0, 3], 30*y^2]
+ [[2, 0], 5]
+ [[0, 2], 30*y^3]
+ [[1, 0], 10*x]
+ [[0, 1], 15*y^4]
+ [[0, 0], 5*x^2 + 3*y^5]
+```
+"""
+function hasse_derivatives(f::MPolyRingElem)
+ R = parent(f)
+ Rtemp, t = polynomial_ring(R, :t => 1:ngens(R))
+ F = evaluate(f, gens(R) + t)
+ return [[degrees(monomial(term, 1)), coeff(term, 1)] for term in terms(F)]
+end
+
+function hasse_derivatives(f::MPolyQuoRingElem)
+ error("Not implemented. For experts, however, there is an internal function called _hasse_derivatives, which works for elements of type MPolyQuoRingElem")
+end
+
+function hasse_derivatives(f::Oscar.MPolyLocRingElem)
+ error("Not implemented. For experts, however, there is an internal function called _hasse_derivatives, which works for elements of type Oscar.MPolyLocRingElem")
+end
+
+function hasse_derivatives(f::Oscar.MPolyQuoLocRingElem)
+ error("Not implemented. For experts, however, there is an internal function called _hasse_derivatives, which works for elements of type Oscar.MPolyQuoLocRingElem")
+end
+
+
+
+
+################################################################################
+### internal functions for expert use
+
+# MPolyQuoRingElem (internal, expert use only)
+@doc raw"""
+ _hasse_derivatives(f::MPolyQuoRingElem)
+
+Return a list of Hasse-Schmidt derivatives of lift of `f`, each with a multiindex `[a_1, ..., a_n]`, where `a_i` describes the number of times `f` was derived w.r.t. the `i`-th variable.
+
+# Examples
+```jldoctest
+julia> R, (x, y) = polynomial_ring(ZZ, ["x", "y"]);
+
+julia> I = ideal(R, [x - 1]);
+
+julia> RQ, phi = quo(R, I);
+
+julia> f = phi(2*y^4);
+
+julia> Oscar._hasse_derivatives(f)
+5-element Vector{Vector{Any}}:
+ [[0, 4], 2]
+ [[0, 3], 8*y]
+ [[0, 2], 12*y^2]
+ [[0, 1], 8*y^3]
+ [[0, 0], 2*y^4]
+```
+"""
+function _hasse_derivatives(f::MPolyQuoRingElem)
+ return hasse_derivatives(lift(f))
+end
+
+# Oscar.MPolyLocRingElem (internal, expert use only)
+@doc raw"""
+ _hasse_derivatives(f::Oscar.MPolyLocRingElem)
+
+Return a list of Hasse-Schmidt derivatives of numerator of `f`, each with a multiindex `[a_1, ..., a_n]`, where `a_i` describes the number of times `f` was derived w.r.t. the `i`-th variable.
+
+# Examples
+```jldoctest
+julia> R, (x, y, z) = polynomial_ring(QQ, ["x", "y", "z"]);
+
+julia> m = ideal(R, [x - 3, y - 2, z + 1]);
+
+julia> U = complement_of_prime_ideal(m);
+
+julia> Rloc, phi = localization(R, U);
+
+julia> f = phi(2*z^5);
+
+julia> Oscar._hasse_derivatives(f)
+6-element Vector{Vector{Any}}:
+ [[0, 0, 5], 2]
+ [[0, 0, 4], 10*z]
+ [[0, 0, 3], 20*z^2]
+ [[0, 0, 2], 20*z^3]
+ [[0, 0, 1], 10*z^4]
+ [[0, 0, 0], 2*z^5]
+```
+"""
+function _hasse_derivatives(f::Oscar.MPolyLocRingElem)
+ return hasse_derivatives(numerator(f))
+end
+
+# Oscar.MPolyQuoLocRingElem (internal, expert use only)
+@doc raw"""
+ _hasse_derivatives(f::Oscar.MPolyQuoLocRingElem)
+
+Return a list of Hasse-Schmidt derivatives of lifted numerator of `f`, each with a multiindex `[a_1, ..., a_n]`, where `a_i` describes the number of times `f` was derived w.r.t. the `i`-th variable.
+
+# Examples
+```jldoctest
+julia> R, (x, y, z) = polynomial_ring(QQ, ["x", "y", "z"]);
+
+julia> I = ideal(R, [x^3 - 1]);
+
+julia> RQ, phi = quo(R, I);
+
+julia> p = ideal(R, [z]);
+
+julia> U = complement_of_prime_ideal(p);
+
+julia> RQL, iota = localization(RQ, U);
+
+julia> f = iota(phi(4*y^3));
+
+julia> Oscar._hasse_derivatives(f)
+4-element Vector{Vector{Any}}:
+ [[0, 3, 0], 4]
+ [[0, 2, 0], 12*y]
+ [[0, 1, 0], 12*y^2]
+ [[0, 0, 0], 4*y^3]
+```
+"""
+function _hasse_derivatives(f::Oscar.MPolyQuoLocRingElem)
+ return hasse_derivatives(lifted_numerator(f))
+end
diff --git a/experimental/HasseSchmidt/test/runtests.jl b/experimental/HasseSchmidt/test/runtests.jl
new file mode 100644
index 000000000000..574a01ff5728
--- /dev/null
+++ b/experimental/HasseSchmidt/test/runtests.jl
@@ -0,0 +1,117 @@
+@testset "hasse_derivatives" begin
+ R, (x, y) = polynomial_ring(ZZ, ["x", "y"]);
+
+ result_a1 = [ [[3, 0], 1],
+ [[2, 0], 3*x],
+ [[1, 0], 3*x^2],
+ [[0, 0], x^3]]
+ @test result_a1 == hasse_derivatives(x^3)
+
+ result_a2 = [ [[0, 5], 3],
+ [[0, 4], 15*y],
+ [[0, 3], 30*y^2],
+ [[2, 0], 5],
+ [[0, 2], 30*y^3],
+ [[1, 0], 10*x],
+ [[0, 1], 15*y^4],
+ [[0, 0], 5*x^2 + 3*y^5]]
+ @test result_a2 == hasse_derivatives(5*x^2 + 3*y^5)
+
+ result_a3 = [ [[2, 3], 1],
+ [[2, 2], 3*y],
+ [[1, 3], 2*x],
+ [[2, 1], 3*y^2],
+ [[1, 2], 6*x*y],
+ [[0, 3], x^2],
+ [[2, 0], y^3],
+ [[1, 1], 6*x*y^2],
+ [[0, 2], 3*x^2*y],
+ [[1, 0], 2*x*y^3],
+ [[0, 1], 3*x^2*y^2],
+ [[0, 0], x^2*y^3]]
+ @test result_a3 == hasse_derivatives(x^2*y^3)
+
+ result_a4 = [ [[4, 0], 1],
+ [[3, 0], 4*x],
+ [[2, 0], 6*x^2],
+ [[0, 2], 1],
+ [[1, 0], 4*x^3],
+ [[0, 1], 2*y],
+ [[0, 0], x^4 + y^2]]
+ @test result_a4 == hasse_derivatives(x^4 + y^2)
+
+ result_a5 = [ [[2, 1], 1],
+ [[1, 2], 1],
+ [[2, 0], y],
+ [[1, 1], 2*x + 2*y],
+ [[0, 2], x],
+ [[1, 0], 2*x*y + y^2],
+ [[0, 1], x^2 + 2*x*y],
+ [[0, 0], x^2*y + x*y^2]]
+ @test result_a5 == hasse_derivatives(x^2*y + x*y^2)
+end
+
+@testset "hasse_derivatives finite fields" begin
+ R, (x, y, z) = polynomial_ring(GF(3), ["x", "y", "z"]);
+
+ result_b1 = [ [[2, 0, 0], 1],
+ [[0, 2, 0], 1],
+ [[1, 0, 0], 2*x],
+ [[0, 1, 0], 2*y],
+ [[0, 0, 0], x^2 + y^2]]
+ @test result_b1 == hasse_derivatives(x^2 + y^2)
+
+ result_b2 = [ [[0, 0, 6], 1],
+ [[2, 1, 0], 1],
+ [[0, 0, 3], 2*z^3],
+ [[2, 0, 0], y],
+ [[1, 1, 0], 2*x],
+ [[1, 0, 0], 2*x*y],
+ [[0, 1, 0], x^2],
+ [[0, 0, 0], x^2*y + z^6]]
+ @test result_b2 == hasse_derivatives(x^2*y + z^6)
+end
+
+@testset "_hasse_derivatives MPolyQuoRingElem" begin
+ R, (x, y, z) = polynomial_ring(ZZ, ["x", "y", "z"]);
+ I = ideal(R, [x^2 - 1]);
+ RQ, _ = quo(R, I);
+
+ result_c1 = [ [[0, 4, 0], 3],
+ [[0, 3, 0], 12*y],
+ [[0, 2, 0], 18*y^2],
+ [[0, 1, 0], 12*y^3],
+ [[0, 0, 0], 3*y^4]]
+ @test result_c1 == Oscar._hasse_derivatives(RQ(3y^4))
+end
+
+@testset "_hasse_derivatives Oscar.MPolyLocRingElem" begin
+ R, (x, y, z) = polynomial_ring(ZZ, ["x", "y", "z"]);
+ m = ideal(R, [x, y, z]); # max ideal
+ U = complement_of_prime_ideal(m);
+ RL, _ = localization(R, U);
+
+ result_d1 = [ [[3, 0, 0], 5],
+ [[2, 0, 0], 15*x],
+ [[1, 0, 0], 15*x^2],
+ [[0, 0, 0], 5*x^3]]
+ @test result_d1 == Oscar._hasse_derivatives(RL(5x^3))
+end
+
+@testset "_hasse_derivatives Oscar.MPolyQuoLocRingElem" begin
+ R, (x, y, z) = polynomial_ring(ZZ, ["x", "y", "z"]);
+ I = ideal(R, [x^2 - 1]);
+ RQ, _ = quo(R, I);
+ m = ideal(R, [x, y, z]); # max ideal
+ U = complement_of_prime_ideal(m);
+ RQL, _ = localization(RQ, U);
+
+ result_e1 = [ [[0, 0, 5], 2],
+ [[0, 0, 4], 10*z],
+ [[0, 0, 3], 20*z^2],
+ [[0, 0, 2], 20*z^3],
+ [[0, 0, 1], 10*z^4],
+ [[0, 0, 0], 2*z^5]]
+ @test result_e1 == Oscar._hasse_derivatives(RQL(2z^5))
+end
+
diff --git a/experimental/IntersectionTheory/docs/src/AbstractBundles.md b/experimental/IntersectionTheory/docs/src/AbstractBundles.md
index 8377ecfd9435..804a67e15334 100644
--- a/experimental/IntersectionTheory/docs/src/AbstractBundles.md
+++ b/experimental/IntersectionTheory/docs/src/AbstractBundles.md
@@ -1,5 +1,6 @@
```@meta
CurrentModule = Oscar
+DocTestSetup = Oscar.doctestsetup()
```
# Abstract Bundles
@@ -39,7 +40,7 @@ top_chern_class(F::AbstractBundle)
```
```@docs
-segre_class(F::AbstractBundle)
+total_segre_class(F::AbstractBundle)
```
```@docs
@@ -66,7 +67,6 @@ euler_characteristic(F::AbstractBundle)
hilbert_polynomial(F::AbstractBundle)
```
-
## Operations on Abstract Bundles
```@docs
@@ -88,3 +88,17 @@ exterior_power(F::AbstractBundle, k::Int)
```@docs
symmetric_power(F::AbstractBundle, k::Int)
```
+
+```@docs
+pullback(f::AbstractVarietyMap, F::AbstractBundle)
+```
+
+```@docs
+pushforward(f::AbstractVarietyMap, F::AbstractBundle)
+```
+
+## Tests on Abstract Bundles
+
+```@docs
+==(F::AbstractBundle, G::AbstractBundle)
+```
diff --git a/experimental/IntersectionTheory/docs/src/AbstractVarieties.md b/experimental/IntersectionTheory/docs/src/AbstractVarieties.md
index 5ad8d7d66434..be2d44f769b6 100644
--- a/experimental/IntersectionTheory/docs/src/AbstractVarieties.md
+++ b/experimental/IntersectionTheory/docs/src/AbstractVarieties.md
@@ -156,7 +156,7 @@ product(X::AbstractVariety, Y::AbstractVariety)
## Integrate Chow Ring Elements
```@julia
-integral(x::MPolyDecRingElem)
+integral(x::Union{MPolyDecRingElem, MPolyQuoRingElem})
```
Given an element `x` of the Chow ring of an abstract variety `X`, say, return the integral of `x`.
diff --git a/experimental/IntersectionTheory/docs/src/AbstractVarietyMaps.md b/experimental/IntersectionTheory/docs/src/AbstractVarietyMaps.md
index 0612ae170fa0..d2c3bf83c3aa 100644
--- a/experimental/IntersectionTheory/docs/src/AbstractVarietyMaps.md
+++ b/experimental/IntersectionTheory/docs/src/AbstractVarietyMaps.md
@@ -1,5 +1,6 @@
```@meta
CurrentModule = Oscar
+DocTestSetup = Oscar.doctestsetup()
```
# Abstract Variety Maps
@@ -7,7 +8,11 @@ CurrentModule = Oscar
## Constructors
```@docs
-hom(X::AbstractVariety, Y::AbstractVariety, fˣ::Vector, fₓ = nothing; inclusion::Bool = false, symbol::String = "x")
+map(X::AbstractVariety, Y::AbstractVariety, fˣ::Vector, fₓ = nothing; inclusion::Bool = false, symbol::String = "x")
+```
+
+```@docs
+identity_map(X::AbstractVariety)
```
## Underlying Data of an Abstract Variety Map
@@ -27,7 +32,7 @@ dim(f::AbstractVarietyMap)
```
```@docs
-pullback(f::AbstractVarietyMap, x::MPolyDecRingElem)
+pullback(f::AbstractVarietyMap, y::MPolyDecRingElem)
```
```@docs
diff --git a/experimental/IntersectionTheory/docs/src/BlowUps.md b/experimental/IntersectionTheory/docs/src/BlowUps.md
index 0fa72b3be318..8032f3f39c77 100644
--- a/experimental/IntersectionTheory/docs/src/BlowUps.md
+++ b/experimental/IntersectionTheory/docs/src/BlowUps.md
@@ -1,5 +1,6 @@
```@meta
CurrentModule = Oscar
+DocTestSetup = Oscar.doctestsetup()
```
# Blowups
diff --git a/experimental/IntersectionTheory/docs/src/BottFormulas.md b/experimental/IntersectionTheory/docs/src/BottFormulas.md
index 941ab97232bf..501f6e677d27 100644
--- a/experimental/IntersectionTheory/docs/src/BottFormulas.md
+++ b/experimental/IntersectionTheory/docs/src/BottFormulas.md
@@ -1,5 +1,6 @@
```@meta
CurrentModule = Oscar
+DocTestSetup = Oscar.doctestsetup()
```
# Bott Formulas
diff --git a/experimental/IntersectionTheory/docs/src/examples.md b/experimental/IntersectionTheory/docs/src/examples.md
index dcc97a382f7e..7aa595197e25 100644
--- a/experimental/IntersectionTheory/docs/src/examples.md
+++ b/experimental/IntersectionTheory/docs/src/examples.md
@@ -65,7 +65,7 @@ h
julia> H = gens(P5)[1]
H
-julia> i = hom(P2, P5, [2*h])
+julia> i = map(P2, P5, [2*h])
AbstractVarietyMap from AbstractVariety of dim 2 to AbstractVariety of dim 5
julia> Bl, E, j = blowup(i)
diff --git a/experimental/IntersectionTheory/docs/src/intro.md b/experimental/IntersectionTheory/docs/src/intro.md
index 7b546bf82902..7ab02028622a 100644
--- a/experimental/IntersectionTheory/docs/src/intro.md
+++ b/experimental/IntersectionTheory/docs/src/intro.md
@@ -1,5 +1,6 @@
```@meta
CurrentModule = Oscar
+DocTestSetup = Oscar.doctestsetup()
```
# Introduction
diff --git a/experimental/IntersectionTheory/docs/src/schubert.md b/experimental/IntersectionTheory/docs/src/schubert.md
index ffd1f54102f1..47944cdbbc89 100644
--- a/experimental/IntersectionTheory/docs/src/schubert.md
+++ b/experimental/IntersectionTheory/docs/src/schubert.md
@@ -1,5 +1,6 @@
```@meta
CurrentModule = Oscar
+DocTestSetup = Oscar.doctestsetup()
```
# Schubert Calculus
diff --git a/experimental/IntersectionTheory/src/IntersectionTheory.jl b/experimental/IntersectionTheory/src/IntersectionTheory.jl
index c2ae9b1886c4..ac34405a95a9 100644
--- a/experimental/IntersectionTheory/src/IntersectionTheory.jl
+++ b/experimental/IntersectionTheory/src/IntersectionTheory.jl
@@ -6,7 +6,7 @@ import ..Oscar: AffAlgHom, Ring, MPolyDecRingElem, symmetric_power, exterior_pow
import ..Oscar: basis, betti_numbers, chow_ring, codomain, degree, det, dim, domain, dual, gens, hilbert_polynomial, hom, integral, rank, signature, partitions
import ..Oscar.AbstractAlgebra: combinations
import ..Oscar.AbstractAlgebra.Generic: FunctionalMap
-import ..Oscar: pullback, pushforward, base, OO, product, compose
+import ..Oscar: pullback, pushforward, base, OO, product, compose, identity_map, map
import ..Oscar: trivial_line_bundle
import ..Oscar: intersection_matrix
import ..Oscar: chern_class
@@ -41,10 +41,13 @@ export dual_basis
export euler
export euler_pairing
export graph
+export hom
export hyperplane_class
+export identity_map
export l_genus
export linear_subspaces_on_hypersurface
export line_bundle
+export map
export OO
export point_class
export pontryagin_class
@@ -55,6 +58,7 @@ export pushforward
export schubert_class
export schubert_classes
export schur_functor
+export total_segre_class
export segre_class
export structure_map
export tangent_bundle
@@ -119,11 +123,14 @@ export dual_basis
export euler
export euler_pairing
export graph
+export hom
export hyperplane_class
export intersection_matrix
+export identity_map
export l_genus
export linear_subspaces_on_hypersurface
export line_bundle
+export map
export OO
export point_class
export pontryagin_class
@@ -134,6 +141,7 @@ export pushforward
export schubert_class
export schubert_classes
export schur_functor
+export total_segre_class
export segre_class
export structure_map
export tangent_bundle
diff --git a/experimental/IntersectionTheory/src/Main.jl b/experimental/IntersectionTheory/src/Main.jl
index d2a1dd5406ea..36e04ad1f0aa 100644
--- a/experimental/IntersectionTheory/src/Main.jl
+++ b/experimental/IntersectionTheory/src/Main.jl
@@ -50,8 +50,28 @@ true
abstract_bundle(X::AbstractVariety, ch::MPolyDecRingOrQuoElem) = AbstractBundle(X, ch)
abstract_bundle(X::AbstractVariety, r::RingElement, c::MPolyDecRingOrQuoElem) = AbstractBundle(X, r, c)
+#######################################################
+@doc raw"""
+ ==(F::AbstractBundle, G::AbstractBundle)
+
+Return `true` if `F` is equal to `G`, and `false` otherwise.
+
+# Examples
+```jldoctest
+julia> P2 = abstract_projective_space(2)
+AbstractVariety of dim 2
+
+julia> 3*OO(P2, 1) - OO(P2) == tangent_bundle(P2) # Euler sequence
+true
+
+```
+"""
==(F::AbstractBundle, G::AbstractBundle) = chern_character(F) == chern_character(G)
+function Base.hash(F::AbstractBundle, h::UInt)
+ return hash(chern_character(F), h)
+end
+
@doc raw"""
chern_character(F::AbstractBundle)
@@ -90,6 +110,12 @@ AbstractBundle of rank 2 on AbstractVariety of dim 6
julia> total_chern_class(Q)
c[1]^2 - c[1] - c[2] + 1
+julia> chern_class(Q, 1)
+-c[1]
+
+julia> chern_class(Q, 2)
+c[1]^2 - c[2]
+
```
"""
total_chern_class(F::AbstractBundle) = (
@@ -161,23 +187,91 @@ julia> top_chern_class(F)
top_chern_class(F::AbstractBundle) = chern_class(F, F.rank)
@doc raw"""
- segre_class(F::AbstractBundle)
+ total_segre_class(F::AbstractBundle)
Return the total Segre class of `F`.
+
+# Examples
+```jldoctest
+julia> G = abstract_grassmannian(3,5)
+AbstractVariety of dim 6
+
+julia> Q = tautological_bundles(G)[2]
+AbstractBundle of rank 2 on AbstractVariety of dim 6
+
+julia> C = total_chern_class(Q)
+c[1]^2 - c[1] - c[2] + 1
+
+julia> S = total_segre_class(Q)
+c[1] + c[2] + c[3] + 1
+
+julia> C*S
+1
+
+```
"""
-segre_class(F::AbstractBundle) = inv(total_chern_class(F))
+total_segre_class(F::AbstractBundle) = inv(total_chern_class(F))
@doc raw"""
segre_class(F::AbstractBundle, k::Int)
-Retuen the `k`-th Segre class of `F`.
+Return the `k`-th Segre class of `F`.
+
+# Examples
+```jldoctest
+julia> G = abstract_grassmannian(3,5)
+AbstractVariety of dim 6
+
+julia> Q = tautological_bundles(G)[2]
+AbstractBundle of rank 2 on AbstractVariety of dim 6
+
+julia> segre_class(Q,0)
+1
+
+julia> segre_class(Q,1)
+c[1]
+
+julia> segre_class(Q,2)
+c[2]
+
+julia> segre_class(Q,3)
+c[3]
+
+```
"""
-segre_class(F::AbstractBundle, k::Int) = segre_class(F)[k]
+segre_class(F::AbstractBundle, k::Int) = total_segre_class(F)[k]
@doc raw"""
todd_class(F::AbstractBundle)
Return the Todd class of `F`.
+
+# Examples
+```jldoctest
+julia> P = abstract_projective_space(4, symbol = "H"); # Hartshorne, p. 433
+
+julia> F = exterior_power(cotangent_bundle(P), 3)*OO(P,3);
+
+julia> G = OO(P, 1)+4*OO(P);
+
+julia> Z = degeneracy_locus(F, G, 3) # rational surface in P4
+AbstractVariety of dim 2
+
+julia> TZ = tangent_bundle(Z);
+
+julia> K = canonical_class(Z)
+z - H
+
+julia> chern_class(TZ, 1) == -K
+true
+
+julia> tc = todd_class(TZ)
+-1//2*z + 1//8*H^2 + 1//2*H + 1
+
+julia> tc == 1-1//2*K+1//12*(K^2+chern_class(TZ, 2))
+true
+
+```
"""
todd_class(F::AbstractBundle) = _todd_class(chern_character(F))
@@ -206,6 +300,36 @@ pontryagin_class(F::AbstractBundle, k::Int) = total_pontryagin_class(F)[2k]
Return the holomorphic Euler characteristic $\chi(F)$ and the Euler pairing
$\chi(F,G)$, respectively.
+
+# Examples
+```jldoctest
+julia> P = abstract_projective_space(4, symbol = "H"); # Hartshorne, p. 433
+
+julia> F = exterior_power(cotangent_bundle(P), 3)*OO(P,3);
+
+julia> G = OO(P, 1)+4*OO(P);
+
+julia> Z = degeneracy_locus(F, G, 3) # rational surface in P4
+AbstractVariety of dim 2
+
+julia> TZ = tangent_bundle(Z);
+
+julia> tc = todd_class(TZ)
+-1//2*z + 1//8*H^2 + 1//2*H + 1
+
+julia> K = canonical_class(Z)
+z - H
+
+julia> H = hyperplane_class(Z)
+H
+
+julia> ec = euler_characteristic(OO(Z, H))
+4
+
+julia> ec == integral(1//2*H*(H-K)+1//12*(K^2+chern_class(TZ, 2)))
+true
+
+```
"""
Oscar.euler_characteristic(F::AbstractBundle) = integral(chern_character(F) * todd_class(F.parent)) # Hirzebruch-Riemann-Roch
euler_pairing(F::AbstractBundle, G::AbstractBundle) = begin
@@ -218,15 +342,15 @@ end
# AbstractVarietyMap
#
@doc raw"""
- hom(X::AbstractVariety, Y::AbstractVariety, fˣ::Vector, fₓ = nothing; inclusion::Bool = false, symbol::String = "x")
+ map(X::AbstractVariety, Y::AbstractVariety, fˣ::Vector, fₓ = nothing; inclusion::Bool = false, symbol::String = "x")
Return an abstract variety map `X` $\rightarrow$ `Y` by specifying the pullbacks of
the generators of the Chow ring of `Y`.
!!! note
- The corresponding pushforward can be automatically computed in certain cases.
+ The corresponding pushforward will be automatically computed in certain cases.
-In case of an inclusion $i:X\hookrightarrow Y$ where the class of `X` is not
+In the case of an inclusion `X` $\hookrightarrow$ `Y` where the class of `X` is not
present in the Chow ring of `Y`, use the argument `inclusion = true`. Then,
a copy of `Y` will be created, with extra classes added so that one can
pushforward all classes on `X`.
@@ -237,20 +361,29 @@ pushforward all classes on `X`.
julia> P2xP2 = abstract_projective_space(2, symbol = "k")*abstract_projective_space(2, symbol = "l")
AbstractVariety of dim 4
-julia> P8 = abstract_projective_space(8)
-AbstractVariety of dim 8
-
julia> k, l = gens(P2xP2)
2-element Vector{MPolyQuoRingElem{MPolyDecRingElem{QQFieldElem, QQMPolyRingElem}}}:
k
l
-julia> Se = hom(P2xP2, P8, [k+l]) # Segre embedding
+julia> P8 = abstract_projective_space(8)
+AbstractVariety of dim 8
+
+julia> h = gens(P8)[1]
+h
+
+julia> Se = map(P2xP2, P8, [k+l]) # Segre embedding
AbstractVarietyMap from AbstractVariety of dim 4 to AbstractVariety of dim 8
-```
+julia> pullback(Se, h)
+k + l
+
+julia> pushforward(Se, k+l)
+6*h^5
+
+```
"""
-function hom(X::AbstractVariety, Y::AbstractVariety, fˣ::Vector, fₓ = nothing; inclusion::Bool = false, symbol::String = "x")
+function map(X::AbstractVariety, Y::AbstractVariety, fˣ::Vector, fₓ = nothing; inclusion::Bool = false, symbol::String = "x")
AbstractVarietyMap(X, Y, fˣ, fₓ)
# !inclusion && return AbstractVarietyMap(X, Y, fˣ, fₓ)
# _inclusion(AbstractVarietyMap(X, Y, fˣ), symbol=symbol)
@@ -274,7 +407,7 @@ AbstractVariety of dim 5
julia> h = gens(P2)[1]
h
-julia> i = hom(P2, P5, [2*h])
+julia> i = map(P2, P5, [2*h])
AbstractVarietyMap from AbstractVariety of dim 2 to AbstractVariety of dim 5
julia> dim(i)
@@ -301,13 +434,13 @@ AbstractBundle of rank 2 on AbstractVariety of dim 2
julia> PT = abstract_projective_bundle(T)
AbstractVariety of dim 3
-julia> pi = structure_map(PT)
+julia> pr = structure_map(PT)
AbstractVarietyMap from AbstractVariety of dim 3 to AbstractVariety of dim 2
-julia> PBT = pullback(pi, T)
+julia> PBT = pullback(pr, T)
AbstractBundle of rank 2 on AbstractVariety of dim 3
-julia> PBT*OO(PT, 1) - OO(PT) == tangent_bundle(pi) # relative Euler sequence
+julia> PBT*OO(PT, 1) - OO(PT) == tangent_bundle(pr) # relative Euler sequence
true
```
@@ -345,12 +478,12 @@ AbstractVariety of dim 5
julia> h = gens(P2)[1]
h
+julia> i = map(P2, P5, [2*h])
+AbstractVarietyMap from AbstractVariety of dim 2 to AbstractVariety of dim 5
+
julia> H = gens(P5)[1]
H
-julia> i = hom(P2, P5, [2*h])
-AbstractVarietyMap from AbstractVariety of dim 2 to AbstractVariety of dim 5
-
julia> pullback(i, H)
2*h
@@ -362,6 +495,29 @@ pullback(f::AbstractVarietyMap, x::MPolyDecRingOrQuoElem) = f.pullback(x)
pullback(f::AbstractVarietyMap, F::AbstractBundle)
Return the pullback of `F` via `f`.
+
+# Examples
+
+```jldoctest
+julia> P2 = abstract_projective_space(2)
+AbstractVariety of dim 2
+
+julia> P5 = abstract_projective_space(5, symbol = "H")
+AbstractVariety of dim 5
+
+julia> h = gens(P2)[1]
+h
+
+julia> i = map(P2, P5, [2*h])
+AbstractVarietyMap from AbstractVariety of dim 2 to AbstractVariety of dim 5
+
+julia> E = pullback(i, OO(P2,1))
+AbstractBundle of rank 1 on AbstractVariety of dim 2
+
+julia> total_chern_class(E)
+2*h + 1
+
+```
"""
pullback(f::AbstractVarietyMap, F::AbstractBundle) = AbstractBundle(f.domain, f.pullback(chern_character(F)))
@@ -382,7 +538,7 @@ AbstractVariety of dim 5
julia> h = gens(P2)[1]
h
-julia> i = hom(P2, P5, [2*h])
+julia> i = map(P2, P5, [2*h])
AbstractVarietyMap from AbstractVariety of dim 2 to AbstractVariety of dim 5
julia> pushforward(i, h)
@@ -395,10 +551,38 @@ pushforward(f::AbstractVarietyMap, x::MPolyDecRingOrQuoElem) = f.pushforward(x)
pushforward(f::AbstractVarietyMap, F::AbstractBundle)
Return the pushforward of `F` via `f`, that is, return the alternating sum of all direct images of `F` via `f`.
+
+# Examples
+
+```jldoctest
+julia> P2 = abstract_projective_space(2)
+AbstractVariety of dim 2
+
+julia> P5 = abstract_projective_space(5, symbol = "H")
+AbstractVariety of dim 5
+
+julia> h = gens(P2)[1]
+h
+
+julia> i = map(P2, P5, [2*h])
+AbstractVarietyMap from AbstractVariety of dim 2 to AbstractVariety of dim 5
+
+julia> E = pushforward(i, OO(P2,1))
+AbstractBundle of rank 0 on AbstractVariety of dim 5
+
+julia> total_chern_class(E)
+168*H^5 + 42*H^4 + 8*H^3 + 1
+
+```
"""
pushforward(f::AbstractVarietyMap, F::AbstractBundle) = AbstractBundle(f.codomain, f.pushforward(chern_character(F) * todd_class(f))) # Grothendieck-Hirzebruch-Riemann-Roch
-function identity_hom(X::V) where V <: AbstractVarietyT
+@doc raw"""
+ identity_map(X::AbstractVariety)
+
+Return the identity map on `X`.
+"""
+function identity_map(X::AbstractVariety)
AbstractVarietyMap(X, X, gens(X.ring), map_from_func(identity, X.ring, X.ring))
end
@@ -732,7 +916,7 @@ structure_map(X::AbstractVariety) = X.struct_map
@doc raw"""
line_bundle(X::AbstractVariety, n::RingElement)
- line_bundle(X::AbstractVariety, D::MPolyDecRingElem)
+ line_bundle(X::AbstractVariety, D::Union{MPolyDecRingElem, MPolyQuoRingElem})
Return the line bundle $\mathcal O_X(n)$ on `X` if `X` has been given a
hyperplane class, or a line bundle $\mathcal O_X(D)$ with first Chern class $D$.
@@ -746,13 +930,19 @@ AbstractVariety of dim 2
julia> tautological_bundles(P2)[1] == OO(P2, -1)
true
+julia> h = gens(P2)[1]
+h
+
+julia> OO(P2, h) == OO(P2, 1)
+true
+
```
"""
line_bundle(X::AbstractVariety, n::RingElement) = AbstractBundle(X, 1, 1+n*X.O1)
-line_bundle(X::AbstractVariety, D::MPolyDecRingElem) = AbstractBundle(X, 1, 1+D[1])
+line_bundle(X::AbstractVariety, D::Union{MPolyDecRingElem, MPolyQuoRingElem}) = AbstractBundle(X, 1, 1+D[1])
(OO)(X::AbstractVariety, n::RingElement) = line_bundle(X, n)
-OO(X::AbstractVariety, D::MPolyDecRingElem) = line_bundle(X, D)
+OO(X::AbstractVariety, D::Union{MPolyDecRingElem, MPolyQuoRingElem}) = line_bundle(X, D)
@doc raw"""
degree(X::AbstractVariety)
@@ -1044,8 +1234,8 @@ julia> hilbert_polynomial(P2)
hilbert_polynomial(X::AbstractVariety) = hilbert_polynomial(trivial_line_bundle(X))
# find canonically defined morphism from X to Y
-function _hom(X::AbstractVariety, Y::AbstractVariety)
- X == Y && return identity_hom(X)
+function _map(X::AbstractVariety, Y::AbstractVariety)
+ X == Y && return identity_map(X)
# first handle the case where X is a (fibered) product
projs = get_attribute(X, :projections)
if projs !== nothing
@@ -1066,14 +1256,14 @@ end
# morphisms for points are convenient, but are not desired when doing coercion
@doc raw"""
- hom(X::AbstractVariety, Y::AbstractVariety)
+ map(X::AbstractVariety, Y::AbstractVariety)
-Return a canonically defined morphism from `X` to `Y`.
+Return a canonically defined map from `X` to `Y`.
"""
-function hom(X::AbstractVariety, Y::AbstractVariety)
- get_attribute(Y, :point) !== nothing && return hom(X, Y, [X(0)]) # Y is a point
- get_attribute(X, :point) !== nothing && return hom(X, Y, repeat([X(0)], length(gens(Y.ring)))) # X is a point
- _hom(X, Y)
+function map(X::AbstractVariety, Y::AbstractVariety)
+ get_attribute(Y, :point) !== nothing && return map(X, Y, [X(0)]) # Y is a point
+ get_attribute(X, :point) !== nothing && return map(X, Y, repeat([X(0)], length(gens(Y.ring)))) # X is a point
+ _map(X, Y)
end
# product abstract_variety
@@ -1151,7 +1341,7 @@ inclusion of the graph into the product.
"""
function graph(f::AbstractVarietyMap)
X, Y = f.domain, f.codomain
- hom(X, X * Y, vcat(gens(X), f.pullback.image))
+ map(X, X * Y, vcat(gens(X), f.pullback.image))
end
###############################################################################
@@ -1261,10 +1451,10 @@ function _coerce(F::AbstractBundle, G::AbstractBundle)
X, Y = F.parent, G.parent
X == Y && return F, G
try
- return F, pullback(_hom(X, Y), G)
+ return F, pullback(_map(X, Y), G)
catch
try
- return pullback(_hom(Y, X), F), G
+ return pullback(_map(Y, X), F), G
catch
error("the sheaves are not on compatible varieties")
end
@@ -1426,7 +1616,7 @@ julia> basis(P2xP2)
betti_numbers(X::AbstractVariety) = length.(basis(X))
@doc raw"""
- integral(x::MPolyDecRingElem)
+ integral(x:::Union{MPolyDecRingElem, MPolyQuoRingElem})
Given an element `x` of the Chow ring of an abstract variety `X`, say, return the integral of `x`.
@@ -1919,7 +2109,7 @@ function degeneracy_locus(F::AbstractBundle, G::AbstractBundle, k::Int; class::B
Gr = (m-k == 1) ? abstract_projective_bundle(F) : abstract_flag_bundle(F, m-k)
S = Gr.bundles[1]
D = zero_locus_section(dual(S) * G)
- D.struct_map = hom(D, F.parent) # skip the flag abstract_variety
+ D.struct_map = map(D, F.parent) # skip the flag abstract_variety
if isdefined(F.parent, :O1)
D.O1 = pullback(D.struct_map, F.parent.O1)
end
@@ -2017,7 +2207,7 @@ function abstract_projective_space(n::Int; base::Ring=QQ, symbol::String="h")
S = AbstractBundle(P, 1, 1-h)
Q = trivial_line_bundle(P)*(n+1) - S
P.bundles = [S, Q]
- P.struct_map = hom(P, abstract_point(base=base), [P(1)])
+ P.struct_map = map(P, abstract_point(base=base), [P(1)])
set_attribute!(P, :description => "Projective space of dim $n")
set_attribute!(P, :grassmannian => :absolute)
set_attribute!(P, :alg => true)
@@ -2215,7 +2405,7 @@ function abstract_grassmannian(k::Int, n::Int; base::Ring = QQ, symbol::String =
Gr.point = Gr((-1)^d*c[end]^(n-k))
Gr.T = dual(S) * Q
Gr.bundles = [S, Q]
- Gr.struct_map = hom(Gr, abstract_point(base=base), [Gr(1)])
+ Gr.struct_map = map(Gr, abstract_point(base=base), [Gr(1)])
set_attribute!(Gr, :description => "Grassmannian Gr($k, $n)")
set_attribute!(Gr, :grassmannian => :absolute)
set_attribute!(Gr, :alg => true)
@@ -2284,7 +2474,7 @@ function abs_flag(dims::Vector{Int}; base::Ring=QQ, symbol::String="c")
Fl.O1 = simplify(sum((i-1)*chern_class(Fl.bundles[i], 1) for i in 1:l))
Fl.point = prod(top_chern_class(E)^dims[i] for (i,E) in enumerate(Fl.bundles[2:end]))
Fl.T = sum(dual(Fl.bundles[i]) * sum([Fl.bundles[j] for j in i+1:l]) for i in 1:l-1)
- Fl.struct_map = hom(Fl, abstract_point(base=base), [Fl(1)])
+ Fl.struct_map = map(Fl, abstract_point(base=base), [Fl(1)])
set_attribute!(Fl, :description => "Flag abstract_variety Flag$(tuple(dims...))")
if l == 2 set_attribute!(Fl, :grassmannian => :absolute) end
set_attribute!(Fl, :alg => true)
diff --git a/experimental/IntersectionTheory/src/blowup.jl b/experimental/IntersectionTheory/src/blowup.jl
index 01fe613897b7..d21404c040fc 100644
--- a/experimental/IntersectionTheory/src/blowup.jl
+++ b/experimental/IntersectionTheory/src/blowup.jl
@@ -244,7 +244,7 @@ h
julia> H = gens(P5)[1]
H
-julia> i = hom(P2, P5, [2*h])
+julia> i = map(P2, P5, [2*h])
AbstractVarietyMap from AbstractVariety of dim 2 to AbstractVariety of dim 5
julia> Bl, E, j = blowup(i)
@@ -437,10 +437,10 @@ function blowup_points(X::AbstractVariety, n::Int; symbol::String = "e")
Bl = X
P = abstract_point(base = X.base)
for i in 1:n
- Bl = blowup(hom(P, Bl, [zero(P.ring) for j = 1:i]), symbol=symbs[i])[1]
+ Bl = blowup(map(P, Bl, [zero(P.ring) for j = 1:i]), symbol=symbs[i])[1]
end
set_attribute!(Bl, :description => "Blowup of $X at $n points")
- Bl.struct_map = hom(Bl, X)
+ Bl.struct_map = map(Bl, X)
if get_attribute(X, :alg) == true
set_attribute!(Bl, :alg => true)
end
diff --git a/experimental/IntersectionTheory/test/runtests.jl b/experimental/IntersectionTheory/test/runtests.jl
index f14742ffab53..529d31b8aabf 100644
--- a/experimental/IntersectionTheory/test/runtests.jl
+++ b/experimental/IntersectionTheory/test/runtests.jl
@@ -32,7 +32,7 @@ let pushforward = IntersectionTheory.pushforward
@test schur_functor(A, [1,1]) == exterior_power(A, 2)
@test schur_functor(A, [2]) == symmetric_power(A, 2)
D = degeneracy_locus(A, B, 2)
- @test pushforward(hom(D, X), D(1)) == degeneracy_locus(A, B, 2, class=true)
+ @test pushforward(map(D, X), D(1)) == degeneracy_locus(A, B, 2, class=true)
# characteristic classes
t = todd_class(2)
@@ -51,11 +51,11 @@ let pushforward = IntersectionTheory.pushforward
p = abstract_point()
P2 = abstract_projective_space(2)
- i = hom(P2, P2)
+ i = map(P2, P2)
@test i.domain == P2
@test i.codomain == P2
- i = hom(p, P2)
+ i = map(p, P2)
@test pushforward(i, p(1)) == P2.point
@test pullback(i, P2.O1) == 0
@test i.T === tangent_bundle(i)
@@ -81,7 +81,7 @@ let pushforward = IntersectionTheory.pushforward
P5 = abstract_projective_space(5, symbol="H")
h, H = P2.O1, P5.O1
- v = hom(P2, P5, [2h])
+ v = map(P2, P5, [2h])
@test pullback(v, H) == 2h
@test pullback(v, P5.point) == 0
@test v.pushforward(h) == 2H^4
@@ -91,14 +91,14 @@ let pushforward = IntersectionTheory.pushforward
# test that hom works for product
P, Q = abstract_projective_space(1), abstract_projective_space(1)
PxQ = P * Q
- p, q = hom(PxQ, P), hom(PxQ, Q)
+ p, q = map(PxQ, P), map(PxQ, Q)
@test pushforward(p, PxQ.point) == P.point
@test integral(pullback(p, P.point) * pullback(q, Q.point)) == 1
# # cubic containing a plane
# P2 = abstract_projective_space(2)
# Y = complete_intersection(abstract_projective_space(5), 3)
- # i = hom(P2, Y, [P2.O1], inclusion=true)
+ # i = map(P2, Y, [P2.O1], inclusion=true)
# Y1 = i.codomain
# p = pushforward(i, P2(1))
# h = Y1.O1
@@ -243,7 +243,7 @@ let pushforward = IntersectionTheory.pushforward
# blowup Veronese
P2 = abstract_projective_space(2)
P5 = abstract_projective_space(5)
- i = hom(P2, P5, [2P2.O1])
+ i = map(P2, P5, [2P2.O1])
Bl, E, j = blowup(i)
c = top_chern_class(tangent_bundle(Bl))
@test integral(pushforward(structure_map(Bl), c)) == 12
@@ -257,7 +257,7 @@ let pushforward = IntersectionTheory.pushforward
# blowup point in P2
P2 = abstract_projective_space(2)
P = abstract_point(base = P2.base)
- Bl, E, j = blowup(hom(P, P2, [zero(P.ring)]))
+ Bl, E, j = blowup(map(P, P2, [zero(P.ring)]))
e = pushforward(j, E(1))
@test integral(e^2) == -1
@test integral(pullback(j, e)) == -1
@@ -266,14 +266,14 @@ let pushforward = IntersectionTheory.pushforward
# blowup point in P7
P7 = abstract_projective_space(7)
P = abstract_point(base = P2.base)
- Bl, E, j = blowup(hom(P, P7, [zero(P.ring)]))
+ Bl, E, j = blowup(map(P, P7, [zero(P.ring)]))
e = pushforward(j, E(1))
@test euler(Bl) == 14
# blowup twisted cubic
P1 = abstract_projective_space(1)
P3 = abstract_projective_space(3)
- i = hom(P1, P3, [3P1.O1])
+ i = map(P1, P3, [3P1.O1])
Bl, E, j = blowup(i)
e = pushforward(j, E(1))
quad = pullback(structure_map(Bl), 2P3.O1) - e
@@ -287,7 +287,7 @@ let pushforward = IntersectionTheory.pushforward
(r, s, t) = gens(F)
P1 = abstract_projective_space(1, base = F)
P3 = abstract_projective_space(3, base = F)
- i = hom(P1, P3, [3P1.O1])
+ i = map(P1, P3, [3P1.O1])
Bl, E, j = blowup(i)
e = pushforward(j, E(1))
rH, sH, tH = [pullback(structure_map(Bl), x * P3.O1) - e for x in [r,s,t]]
@@ -295,7 +295,7 @@ let pushforward = IntersectionTheory.pushforward
G = abstract_grassmannian(2, 5)
P9 = abstract_projective_space(9)
- i = hom(G, P9, [G.O1])
+ i = map(G, P9, [G.O1])
Bl, E, j = blowup(i)
e = pushforward(j, E(1))
quad = pullback(structure_map(Bl), 2P9.O1)-e
@@ -310,7 +310,7 @@ let pushforward = IntersectionTheory.pushforward
P3 = abstract_projective_space(3, base = F)
C = zero_locus_section(OO(P2,d))
C.point = 1//(2-2g) * chern_class(C, 1)
- i = hom(C, P3, [d * C.point])
+ i = map(C, P3, [d * C.point])
Bl, E, j = blowup(i)
e = pushforward(j, E(1))
rH, sH, tH = [pullback(structure_map(Bl), x * P3.O1) - e for x in [r,s,t]]
diff --git a/experimental/LieAlgebras/docs/src/cartan_matrix.md b/experimental/LieAlgebras/docs/src/cartan_matrix.md
index 2ca1b72d53b8..4f15e3cf32c9 100644
--- a/experimental/LieAlgebras/docs/src/cartan_matrix.md
+++ b/experimental/LieAlgebras/docs/src/cartan_matrix.md
@@ -1,8 +1,6 @@
```@meta
CurrentModule = Oscar
-DocTestSetup = quote
-using Oscar
-end
+DocTestSetup = Oscar.doctestsetup()
```
# Cartan Matrices
@@ -15,4 +13,4 @@ cartan_symmetrizer(::ZZMatrix; check::Bool)
cartan_bilinear_form(::ZZMatrix; check::Bool)
cartan_type(::ZZMatrix; check::Bool)
cartan_type_with_ordering(::ZZMatrix; check::Bool)
-```
\ No newline at end of file
+```
diff --git a/experimental/LieAlgebras/src/AbstractLieAlgebra.jl b/experimental/LieAlgebras/src/AbstractLieAlgebra.jl
index 9fa34cbfe69a..0bb3157d9322 100644
--- a/experimental/LieAlgebras/src/AbstractLieAlgebra.jl
+++ b/experimental/LieAlgebras/src/AbstractLieAlgebra.jl
@@ -28,9 +28,19 @@ function Base.show(io::IO, mime::MIME"text/plain", L::AbstractLieAlgebra)
@show_special(io, mime, L)
io = pretty(io)
println(io, "Abstract Lie algebra")
- println(io, Indent(), "of dimension $(dim(L))", Dedent())
- print(io, "over ")
- print(io, Lowercase(), coefficient_ring(L))
+ if has_root_system(L)
+ rs = root_system(L)
+ if has_root_system_type(rs)
+ type, ord = root_system_type_with_ordering(rs)
+ print(io, Indent(), "of type ", _root_system_type_string(type))
+ if !issorted(ord)
+ print(io, " (non-canonical ordering)")
+ end
+ println(io, Dedent())
+ end
+ end
+ println(io, Indent(), "of dimension ", dim(L), Dedent())
+ print(io, "over ", Lowercase(), coefficient_ring(L))
end
function Base.show(io::IO, L::AbstractLieAlgebra)
@@ -40,8 +50,18 @@ function Base.show(io::IO, L::AbstractLieAlgebra)
print(io, "Abstract Lie algebra")
else
io = pretty(io)
- print(io, "Abstract Lie algebra over ", Lowercase())
- print(terse(io), coefficient_ring(L))
+ print(io, "Abstract Lie algebra")
+ if has_root_system(L)
+ rs = root_system(L)
+ if has_root_system_type(rs)
+ type, ord = root_system_type_with_ordering(rs)
+ print(io, " of type ", _root_system_type_string(type))
+ if !issorted(ord)
+ print(io, " (non-canonical ordering)")
+ end
+ end
+ end
+ print(terse(io), " over ", Lowercase(), coefficient_ring(L))
end
end
@@ -68,12 +88,15 @@ function bracket(
) where {C<:FieldElem}
check_parent(x, y)
L = parent(x)
- mat = sum(
- cxi * cyj * _struct_consts(L)[i, j] for (i, cxi) in enumerate(coefficients(x)),
- (j, cyj) in enumerate(coefficients(y));
- init=sparse_row(coefficient_ring(L)),
- )
- return L(mat)
+ vec = sparse_row(coefficient_ring(L))
+ for (i, cxi) in enumerate(coefficients(x))
+ iszero(cxi) && continue
+ for (j, cyj) in enumerate(coefficients(y))
+ iszero(cyj) && continue
+ vec = addmul!(vec, _struct_consts(L)[i, j], cxi * cyj)
+ end
+ end
+ return L(vec)
end
###############################################################################
@@ -253,6 +276,15 @@ via the kwarg `extraspecial_pair_signs::Vector{Bool}` to specify the concrete Li
If $(\alpha,\beta)$ is the extraspecial pair for the non-simple root `root(rs, i)`,
then $\varepsilon_{\alpha,\beta} = 1$ iff `extraspecial_pair_signs[i - n_simple_roots(rs)] = true`.
For the used notation and the definition of extraspecial pairs, see [CMT04](@cite).
+
+# Examples
+```jldoctest
+julia> L = lie_algebra(QQ, root_system(:B, 4))
+Abstract Lie algebra
+ of type B4
+ of dimension 36
+over rational field
+```
"""
function lie_algebra(
R::Field,
@@ -423,6 +455,15 @@ end
Construct a simple Lie algebra over the field `R` with Dynkin type given by `fam` and `rk`.
See `cartan_matrix(fam::Symbol, rk::Int)` for allowed combinations.
The internally used basis of this Lie algebra is the Chevalley basis.
+
+# Examples
+```jldoctest
+julia> L = lie_algebra(QQ, :C, 4)
+Abstract Lie algebra
+ of type C4
+ of dimension 36
+over rational field
+```
"""
function lie_algebra(R::Field, S::Symbol, n::Int)
rs = root_system(S, n)
diff --git a/experimental/LieAlgebras/src/GapWrapper.jl b/experimental/LieAlgebras/src/GapWrapper.jl
index 0945275eceb1..e943a594f00a 100644
--- a/experimental/LieAlgebras/src/GapWrapper.jl
+++ b/experimental/LieAlgebras/src/GapWrapper.jl
@@ -4,7 +4,18 @@
#
################################################################################
-function lie_algebra_simple_module_struct_consts_gap(L::LieAlgebra, weight::Vector{Int})
+function lie_algebra_simple_module_struct_consts_gap(
+ L::LieAlgebra, weight::WeightLatticeElem
+)
+ @req root_system(weight) == root_system(L) "Incompatible root systems"
+ return lie_algebra_simple_module_struct_consts_gap(
+ L, Int.(Oscar._vec(coefficients(weight)))
+ )
+end
+
+function lie_algebra_simple_module_struct_consts_gap(
+ L::LieAlgebra{C}, weight::Vector{Int}
+) where {C<:FieldElem}
R = coefficient_ring(L)
isoR = Oscar.iso_oscar_gap(R)
@@ -16,7 +27,7 @@ function lie_algebra_simple_module_struct_consts_gap(L::LieAlgebra, weight::Vect
dimV = GAPWrap.Dimension(gapV)
basisV = GAPWrap.Basis(gapV)
- struct_consts = Matrix{sparse_row_type(R)}(undef, dimL, dimV)
+ struct_consts = Matrix{sparse_row_type(C)}(undef, dimL, dimV)
for i in 1:dimL, j in 1:dimV
struct_consts[i, j] = sparse_row(
R,
diff --git a/experimental/LieAlgebras/src/LieAlgebra.jl b/experimental/LieAlgebras/src/LieAlgebra.jl
index 011aadbceb8f..93ec1080c25d 100644
--- a/experimental/LieAlgebras/src/LieAlgebra.jl
+++ b/experimental/LieAlgebras/src/LieAlgebra.jl
@@ -776,6 +776,19 @@ function chevalley_basis(L::LieAlgebra) # to be implemented by subtypes
throw(Hecke.NotImplemented())
end
+@doc raw"""
+ cartan_matrix(L::LieAlgebra) -> ZZMatrix
+
+Return the Cartan matrix of the root system of `L`.
+"""
+function cartan_matrix(L::LieAlgebra{C}) where {C<:FieldElem}
+ return cartan_matrix(root_system(L))
+end
+
+function cartan_matrix_inv(L::LieAlgebra{C}) where {C<:FieldElem}
+ return cartan_matrix_inv(root_system(L))
+end
+
@doc raw"""
cartan_subalgebra(L::LieAlgebra{C}) where {C<:FieldElem} -> LieSubalgebra{C,elem_type(L)}
@@ -832,6 +845,33 @@ end
#
###############################################################################
+@doc raw"""
+ abelian_lie_algebra(R::Field, n::Int) -> LinearLieAlgebra{elem_type(R)}
+ abelian_lie_algebra(::Type{LinearLieAlgebra}, R::Field, n::Int) -> LinearLieAlgebra{elem_type(R)}
+ abelian_lie_algebra(::Type{AbstractLieAlgebra}, R::Field, n::Int) -> AbstractLieAlgebra{elem_type(R)}
+
+Return the abelian Lie algebra of dimension `n` over the field `R`.
+The first argument can be optionally provided to specify the type of the returned
+Lie algebra.
+
+# Example
+```jldoctest
+julia> abelian_lie_algebra(LinearLieAlgebra, QQ, 3)
+Linear Lie algebra with 3x3 matrices
+ of dimension 3
+over rational field
+
+julia> abelian_lie_algebra(AbstractLieAlgebra, QQ, 3)
+Abstract Lie algebra
+ of dimension 3
+over rational field
+```
+"""
+function abelian_lie_algebra(R::Field, n::Int)
+ @req n >= 0 "Dimension must be non-negative."
+ return abelian_lie_algebra(LinearLieAlgebra, R, n)
+end
+
@doc raw"""
lie_algebra(gapL::GapObj, s::Vector{<:VarName}) -> LieAlgebra{elem_type(R)}
diff --git a/experimental/LieAlgebras/src/LieAlgebraModule.jl b/experimental/LieAlgebras/src/LieAlgebraModule.jl
index 69a8f19200a0..a66743167284 100644
--- a/experimental/LieAlgebras/src/LieAlgebraModule.jl
+++ b/experimental/LieAlgebras/src/LieAlgebraModule.jl
@@ -1385,6 +1385,7 @@ end
# TODO: add semisimplicity check once that is available
+# TODO: move to RootSystem.jl
function is_dominant_weight(hw::Vector{<:IntegerUnion})
return all(>=(0), hw)
end
@@ -1405,6 +1406,7 @@ end
@doc raw"""
dim_of_simple_module([T = Int], L::LieAlgebra{C}, hw::Vector{<:IntegerUnion}) -> T
+ dim_of_simple_module([T = Int], L::LieAlgebra{C}, hw::WeightLatticeElem) -> T
Compute the dimension of the simple module of the Lie algebra `L` with highest weight `hw`
using Weyl's dimension formula.
@@ -1427,8 +1429,18 @@ function dim_of_simple_module(L::LieAlgebra, hw::Vector{<:IntegerUnion})
return dim_of_simple_module(Int, L, hw)
end
+function dim_of_simple_module(T::Type, L::LieAlgebra, hw::WeightLatticeElem)
+ R = root_system(L)
+ return dim_of_simple_module(T, R, hw)
+end
+
+function dim_of_simple_module(L::LieAlgebra, hw::WeightLatticeElem)
+ return dim_of_simple_module(Int, L, hw)
+end
+
@doc raw"""
dominant_weights([T,] L::LieAlgebra{C}, hw::Vector{<:IntegerUnion}) -> Vector{T}
+ dominant_weights([T,] L::LieAlgebra{C}, hw::WeightLatticeElem) -> Vector{T}
Computes the dominant weights occurring in the simple module of the Lie algebra `L` with highest weight `hw`,
sorted ascendingly by the total height of roots needed to reach them from `hw`.
@@ -1445,8 +1457,8 @@ julia> dominant_weights(L, [1, 0, 3])
7-element Vector{Vector{Int64}}:
[1, 0, 3]
[1, 1, 1]
- [2, 0, 1]
[0, 0, 3]
+ [2, 0, 1]
[0, 1, 1]
[1, 0, 1]
[0, 0, 1]
@@ -1461,8 +1473,18 @@ function dominant_weights(L::LieAlgebra, hw::Vector{<:IntegerUnion})
return dominant_weights(Vector{Int}, L, hw)
end
+function dominant_weights(T::Type, L::LieAlgebra, hw::WeightLatticeElem)
+ R = root_system(L)
+ return dominant_weights(T, R, hw)
+end
+
+function dominant_weights(L::LieAlgebra, hw::WeightLatticeElem)
+ return dominant_weights(Vector{Int}, L, hw)
+end
+
@doc raw"""
dominant_character(L::LieAlgebra{C}, hw::Vector{<:IntegerUnion}) -> Dict{Vector{Int}, Int}
+ dominant_character(L::LieAlgebra{C}, hw::WeightLatticeElem) -> Dict{Vector{Int}, Int}
Computes the dominant weights occurring in the simple module of the Lie algebra `L` with highest weight `hw`,
together with their multiplicities.
@@ -1488,8 +1510,14 @@ function dominant_character(L::LieAlgebra, hw::Vector{<:IntegerUnion})
return dominant_character(R, hw)
end
+function dominant_character(L::LieAlgebra, hw::WeightLatticeElem)
+ R = root_system(L)
+ return dominant_character(R, hw)
+end
+
@doc raw"""
character(L::LieAlgebra{C}, hw::Vector{<:IntegerUnion}) -> Dict{Vector{Int}, Int}
+ character(L::LieAlgebra{C}, hw::WeightLatticeElem) -> Dict{Vector{Int}, Int}
Computes all weights occurring in the simple module of the Lie algebra `L` with highest weight `hw`,
together with their multiplicities.
@@ -1509,10 +1537,10 @@ Dict{Vector{Int64}, Int64} with 10 entries:
[-1, 1, -1] => 1
[-2, 2, 0] => 1
[1, -1, 1] => 1
- [-1, 0, 1] => 1
[1, 0, -1] => 1
- [2, 0, 0] => 1
+ [-1, 0, 1] => 1
[0, -1, 0] => 1
+ [2, 0, 0] => 1
```
"""
function character(L::LieAlgebra, hw::Vector{<:IntegerUnion})
@@ -1520,8 +1548,14 @@ function character(L::LieAlgebra, hw::Vector{<:IntegerUnion})
return character(R, hw)
end
+function character(L::LieAlgebra, hw::WeightLatticeElem)
+ R = root_system(L)
+ return character(R, hw)
+end
+
@doc raw"""
tensor_product_decomposition(L::LieAlgebra, hw1::Vector{<:IntegerUnion}, hw2::Vector{<:IntegerUnion}) -> MSet{Vector{Int}}
+ tensor_product_decomposition(L::LieAlgebra, hw1::WeightLatticeElem, hw2::WeightLatticeElem) -> MSet{Vector{Int}}
Computes the decomposition of the tensor product of the simple modules of the Lie algebra `L` with highest weights `hw1` and `hw2`
into simple modules with their multiplicities.
@@ -1553,3 +1587,10 @@ function tensor_product_decomposition(
R = root_system(L)
return tensor_product_decomposition(R, hw1, hw2)
end
+
+function tensor_product_decomposition(
+ L::LieAlgebra, hw1::WeightLatticeElem, hw2::WeightLatticeElem
+)
+ R = root_system(L)
+ return tensor_product_decomposition(R, hw1, hw2)
+end
diff --git a/experimental/LieAlgebras/src/LieAlgebras.jl b/experimental/LieAlgebras/src/LieAlgebras.jl
index d6cd094e36c6..e866dfbd8e64 100644
--- a/experimental/LieAlgebras/src/LieAlgebras.jl
+++ b/experimental/LieAlgebras/src/LieAlgebras.jl
@@ -74,6 +74,7 @@ import ..Oscar:
ngens,
order,
parent_type,
+ permutation_group,
rank,
root,
roots,
diff --git a/experimental/LieAlgebras/src/LinearLieAlgebra.jl b/experimental/LieAlgebras/src/LinearLieAlgebra.jl
index 19ae7921d7f3..80cb4c0cba33 100644
--- a/experimental/LieAlgebras/src/LinearLieAlgebra.jl
+++ b/experimental/LieAlgebras/src/LinearLieAlgebra.jl
@@ -44,28 +44,105 @@ function Base.show(io::IO, mime::MIME"text/plain", L::LinearLieAlgebra)
@show_name(io, L)
@show_special(io, mime, L)
io = pretty(io)
- println(io, _lie_algebra_type_to_string(get_attribute(L, :type, :unknown), L.n))
- println(io, Indent(), "of dimension $(dim(L))", Dedent())
+ type_string = _lie_algebra_type_to_string(get_attribute(L, :type, :unknown), L.n)
+ if !isnothing(type_string)
+ println(io, type_string)
+ else
+ println(io, "Linear Lie algebra with $(L.n)x$(L.n) matrices")
+ if has_root_system(L)
+ rs = root_system(L)
+ if has_root_system_type(rs)
+ type, ord = root_system_type_with_ordering(rs)
+ print(io, Indent(), "of type ", _root_system_type_string(type))
+ if !issorted(ord)
+ print(io, " (non-canonical ordering)")
+ end
+ println(io, Dedent())
+ end
+ end
+ end
+ println(io, Indent(), "of dimension ", dim(L), Dedent())
+ print(io, "over ", Lowercase(), coefficient_ring(L))
+end
+
+function Base.show(io::IO, L::LinearLieAlgebra)
+ @show_name(io, L)
+ @show_special(io, L)
+ if is_terse(io)
+ type_string_compact = _lie_algebra_type_to_compact_string(
+ get_attribute(L, :type, :unknown), L.n
+ )
+ if !isnothing(type_string_compact)
+ print(io, type_string_compact)
+ else
+ print(io, "Linear Lie algebra")
+ end
+ else
+ io = pretty(io)
+ type_string = _lie_algebra_type_to_string(get_attribute(L, :type, :unknown), L.n)
+ if !isnothing(type_string)
+ print(io, type_string)
+ else
+ print(io, "Linear Lie algebra with $(L.n)x$(L.n) matrices")
+ if has_root_system(L)
+ rs = root_system(L)
+ if has_root_system_type(rs)
+ type, ord = root_system_type_with_ordering(rs)
+ print(io, " of type ", _root_system_type_string(type))
+ if !issorted(ord)
+ print(io, " (non-canonical ordering)")
+ end
+ end
+ end
+ end
+ print(terse(io), " over ", Lowercase(), coefficient_ring(L))
+ end
+end
+
+#=
+function Base.show(io::IO, mime::MIME"text/plain", L::AbstractLieAlgebra)
+ @show_name(io, L)
+ @show_special(io, mime, L)
+ io = pretty(io)
+ println(io, "Abstract Lie algebra")
+ if has_root_system(L)
+ rs = root_system(L)
+ if has_root_system_type(rs)
+ type, ord = root_system_type_with_ordering(rs)
+ print(io, Indent(), "of type ", _root_system_type_string(type))
+ if !issorted(ord)
+ print(io, " (non-canonical ordering)")
+ end
+ println(io, Dedent())
+ end
+ end
+ println(io, Indent(), "of dimension ", dim(L), Dedent())
print(io, "over ")
print(io, Lowercase(), coefficient_ring(L))
end
-function Base.show(io::IO, L::LinearLieAlgebra)
+function Base.show(io::IO, L::AbstractLieAlgebra)
@show_name(io, L)
@show_special(io, L)
if is_terse(io)
- print(io, _lie_algebra_type_to_compact_string(get_attribute(L, :type, :unknown), L.n))
+ print(io, "Abstract Lie algebra")
else
io = pretty(io)
- print(
- io,
- _lie_algebra_type_to_string(get_attribute(L, :type, :unknown), L.n),
- " over ",
- Lowercase(),
- )
- print(terse(io), coefficient_ring(L))
+ print(io, "Abstract Lie algebra")
+ if has_root_system(L)
+ rs = root_system(L)
+ if has_root_system_type(rs)
+ type, ord = root_system_type_with_ordering(rs)
+ print(io, " of type ", _root_system_type_string(type))
+ if !issorted(ord)
+ print(io, " (non-canonical ordering)")
+ end
+ end
+ end
+ print(terse(io), " over ", Lowercase(), coefficient_ring(L))
end
end
+=#
function _lie_algebra_type_to_string(type::Symbol, n::Int)
if type == :general_linear
@@ -76,9 +153,8 @@ function _lie_algebra_type_to_string(type::Symbol, n::Int)
return "Special orthogonal Lie algebra of degree $n"
elseif type == :symplectic
return "Symplectic Lie algebra of degree $n"
- else
- return "Linear Lie algebra with $(n)x$(n) matrices"
end
+ return nothing
end
function _lie_algebra_type_to_compact_string(type::Symbol, n::Int)
@@ -88,9 +164,8 @@ function _lie_algebra_type_to_compact_string(type::Symbol, n::Int)
return "sl_$n"
elseif type == :special_orthogonal
return "so_$n"
- else
- return "Linear Lie algebra"
end
+ return nothing
end
function symbols(L::LinearLieAlgebra)
@@ -188,6 +263,40 @@ given by `s`. The basis elements must be square matrices of size `n`.
We require `basis` to be linearly independent, and to contain the Lie bracket of any
two basis elements in its span (this is currently not checked).
Setting `check=false` disables these checks (once they are in place).
+
+# Examples
+```jldoctest
+julia> e = matrix(QQ, [0 0 1; 0 0 0; 0 0 0]);
+
+julia> f = matrix(QQ, [0 0 0; 0 0 0; 1 0 0]);
+
+julia> h = matrix(QQ, [1 0 0; 0 0 0; 0 0 -1]);
+
+julia> L = lie_algebra(QQ, 3, [e, f, h], [:e, :f, :h])
+Linear Lie algebra with 3x3 matrices
+ of dimension 3
+over rational field
+
+julia> root_system(L);
+
+julia> L
+Linear Lie algebra with 3x3 matrices
+ of type A1
+ of dimension 3
+over rational field
+
+julia> basis(L)
+3-element Vector{LinearLieAlgebraElem{QQFieldElem}}:
+ e
+ f
+ h
+
+julia> matrix_repr_basis(L)
+3-element Vector{QQMatrix}:
+ [0 0 1; 0 0 0; 0 0 0]
+ [0 0 0; 0 0 0; 1 0 0]
+ [1 0 0; 0 0 0; 0 0 -1]
+```
"""
function lie_algebra(
R::Field,
@@ -215,20 +324,6 @@ function lie_algebra(
return lie_algebra(R, L.n, matrix_repr.(basis), s; check)
end
-@doc raw"""
- abelian_lie_algebra(R::Field, n::Int) -> LinearLieAlgebra{elem_type(R)}
- abelian_lie_algebra(::Type{LinearLieAlgebra}, R::Field, n::Int) -> LinearLieAlgebra{elem_type(R)}
- abelian_lie_algebra(::Type{AbstractLieAlgebra}, R::Field, n::Int) -> AbstractLieAlgebra{elem_type(R)}
-
-Return the abelian Lie algebra of dimension `n` over the field `R`.
-The first argument can be optionally provided to specify the type of the returned
-Lie algebra.
-"""
-function abelian_lie_algebra(R::Field, n::Int)
- @req n >= 0 "Dimension must be non-negative."
- return abelian_lie_algebra(LinearLieAlgebra, R, n)
-end
-
function abelian_lie_algebra(::Type{T}, R::Field, n::Int) where {T<:LinearLieAlgebra}
@req n >= 0 "Dimension must be non-negative."
basis = [(b = zero_matrix(R, n, n); b[i, i] = 1; b) for i in 1:n]
diff --git a/experimental/LieAlgebras/src/RootSystem.jl b/experimental/LieAlgebras/src/RootSystem.jl
index c6e07e744ce6..720777c74d38 100644
--- a/experimental/LieAlgebras/src/RootSystem.jl
+++ b/experimental/LieAlgebras/src/RootSystem.jl
@@ -11,6 +11,21 @@
Construct the root system defined by the Cartan matrix.
If `check` is `true`, checks that `cartan_matrix` is a generalized Cartan matrix.
Passing `detect_type=false` will skip the detection of the root system type.
+
+# Examples
+```jldoctest
+julia> root_system([2 -1; -1 2])
+Root system of rank 2
+ of type A2
+
+julia> root_system(matrix(ZZ, 2, 2, [2, -1, -1, 2]); detect_type=false)
+Root system of rank 2
+ of unknown type
+
+julia> root_system(matrix(ZZ, [2 -1 -2; -1 2 0; -1 0 2]))
+Root system of rank 3
+ of type C3 (with non-canonical ordering of simple roots)
+```
"""
function root_system(cartan_matrix::ZZMatrix; check::Bool=true, detect_type::Bool=true)
return RootSystem(cartan_matrix; check, detect_type)
@@ -28,9 +43,8 @@ Construct the root system of the given type. See `cartan_matrix(fam::Symbol, rk:
# Examples
```jldoctest
julia> root_system(:A, 2)
-Root system defined by Cartan matrix
- [ 2 -1]
- [-1 2]
+Root system of rank 2
+ of type A2
```
"""
function root_system(fam::Symbol, rk::Int)
@@ -40,6 +54,22 @@ function root_system(fam::Symbol, rk::Int)
return R
end
+@doc raw"""
+ root_system(type::Vector{Tuple{Symbol,Int}}) -> RootSystem
+
+Construct the root system of the given type. See `cartan_matrix(fam::Symbol, rk::Int)` for allowed combinations of tuples.
+
+# Examples
+```jldoctest
+julia> root_system([(:A, 2), (:F, 4)])
+Root system of rank 6
+ of type A2 x F4
+
+julia> root_system(Tuple{Symbol,Int}[])
+Root system of rank 0
+ of type []
+```
+"""
function root_system(type::Vector{Tuple{Symbol,Int}})
cartan = cartan_matrix(type)
R = root_system(cartan; check=false, detect_type=false)
@@ -55,9 +85,18 @@ function Base.show(io::IO, mime::MIME"text/plain", R::RootSystem)
@show_name(io, R)
@show_special(io, mime, R)
io = pretty(io)
- println(io, "Root system defined by Cartan matrix")
- print(io, Indent())
- show(io, mime, cartan_matrix(R))
+ print(io, "Root system")
+ print(io, " of rank ", rank(R))
+ println(io, Indent())
+ if has_root_system_type(R)
+ type, ord = root_system_type_with_ordering(R)
+ print(io, "of type ", _root_system_type_string(type))
+ if !issorted(ord)
+ print(io, " (with non-canonical ordering of simple roots)")
+ end
+ else
+ print(io, "of unknown type")
+ end
print(io, Dedent())
end
@@ -67,10 +106,27 @@ function Base.show(io::IO, R::RootSystem)
if is_terse(io)
print(io, "Root system")
else
- print(io, "Root system defined by Cartan matrix $(cartan_matrix(R))")
+ print(io, "Root system")
+ if has_root_system_type(R) &&
+ ((type, ord) = root_system_type_with_ordering(R); !isempty(type))
+ type, ord = root_system_type_with_ordering(R)
+ print(io, " of type ", _root_system_type_string(type))
+ if !issorted(ord)
+ print(io, " (non-canonical ordering)")
+ end
+ else
+ print(io, " of rank ", rank(R))
+ end
end
end
+function _root_system_type_string(type::Vector{Tuple{Symbol,Int}})
+ isempty(type) && return "[]"
+ return join(
+ [string(t[1]) * string(t[2]) for t in type], is_unicode_allowed() ? " × " : " x "
+ )
+end
+
@attr ZZMatrix function bilinear_form(R::RootSystem)
return cartan_bilinear_form(cartan_matrix(R); check=false)
end
@@ -148,13 +204,21 @@ end
function fundamental_weight(R::RootSystem, i::Int)
@req 1 <= i <= rank(R) "invalid index"
- return WeightLatticeElem(R, matrix(ZZ, rank(R), 1, i .== 1:rank(R)))
+ return WeightLatticeElem(R, matrix(ZZ, 1, rank(R), i .== 1:rank(R)))
end
@doc raw"""
fundamental_weights(R::RootSystem) -> Vector{WeightLatticeElem}
Return the fundamental weights corresponding to the `simple_roots` of `R`.
+
+# Examples
+```jldoctest
+julia> fundamental_weights(root_system(:A, 2))
+2-element Vector{WeightLatticeElem}:
+ w_1
+ w_2
+```
"""
function fundamental_weights(R::RootSystem)
return [fundamental_weight(R, i) for i in 1:rank(R)]
@@ -203,6 +267,15 @@ Also see: `negative_root`.
This function does not return a copy of the asked for object,
but the internal field of the root system.
Mutating the returned object will lead to undefined behavior.
+
+# Examples
+```jldoctest
+julia> negative_roots(root_system(:A, 2))
+3-element Vector{RootSpaceElem}:
+ -a_1
+ -a_2
+ -a_1 - a_2
+```
"""
function negative_roots(R::RootSystem)
return [-r for r in positive_roots(R)]
@@ -228,14 +301,23 @@ end
@doc raw"""
negative_coroot(R::RootSystem, i::Int) -> RootSpaceElem
-Returns the coroots corresponding to the negative roots of `R`
+Returns the negative coroots of `R`. The $i$-th element of the returned vector is the negative coroot corresponding to the $i$-th positive coroot.
-Also see: `negative_coroots`.
+Also see: `negative_coroot`.
!!! note
This function does not return a copy of the asked for object,
but the internal field of the root system.
Mutating the returned object will lead to undefined behavior.
+
+# Examples
+```jldoctest
+julia> negative_coroots(root_system(:A, 2))
+3-element Vector{DualRootSpaceElem}:
+ -a^v_1
+ -a^v_2
+ -a^v_1 - a^v_2
+```
"""
function negative_coroots(R::RootSystem)
return [-r for r in positive_coroots(R)]
@@ -303,6 +385,15 @@ Also see: `positive_root`, `number_of_positive_roots`.
This function does not return a copy of the asked for object,
but the internal field of the root system.
Mutating the returned object will lead to undefined behavior.
+
+# Examples
+```jldoctest
+julia> positive_roots(root_system(:A, 2))
+3-element Vector{RootSpaceElem}:
+ a_1
+ a_2
+ a_1 + a_2
+```
"""
function positive_roots(R::RootSystem)
return R.positive_roots::Vector{RootSpaceElem}
@@ -336,6 +427,15 @@ Also see: `positive_coroots`.
This function does not return a copy of the asked for object,
but the internal field of the root system.
Mutating the returned object will lead to undefined behavior.
+
+# Examples
+```jldoctest
+julia> positive_coroots(root_system(:A, 2))
+3-element Vector{DualRootSpaceElem}:
+ a^v_1
+ a^v_2
+ a^v_1 + a^v_2
+```
"""
function positive_coroots(R::RootSystem)
return R.positive_coroots::Vector{DualRootSpaceElem}
@@ -351,11 +451,12 @@ function rank(R::RootSystem)
end
function root_system_type(R::RootSystem)
- has_root_system_type(R) || error("Root system type not known and cannot be determined")
+ assure_root_system_type(R)
return R.type
end
function root_system_type_with_ordering(R::RootSystem)
+ assure_root_system_type(R)
return R.type, R.type_ordering
end
@@ -363,6 +464,12 @@ function has_root_system_type(R::RootSystem)
return isdefined(R, :type) && isdefined(R, :type_ordering)
end
+function assure_root_system_type(R::RootSystem)
+ has_root_system_type(R) && return nothing
+ @req is_finite(weyl_group(R)) "Root system type cannot be determined for infinite Weyl groups"
+ set_root_system_type!(R, cartan_type_with_ordering(cartan_matrix(R))...)
+end
+
function set_root_system_type!(R::RootSystem, type::Vector{Tuple{Symbol,Int}})
return set_root_system_type!(R, type, 1:sum(t[2] for t in type; init=0))
end
@@ -375,10 +482,6 @@ function set_root_system_type!(
return nothing
end
-function root_system_type_string(R::RootSystem)
- return join([string(t[1]) * string(t[2]) for t in root_system_type(R)], " x ")
-end
-
@doc raw"""
root(R::RootSystem, i::Int) -> RootSpaceElem
@@ -489,6 +592,24 @@ end
weyl_group(R::RootSystem) -> WeylGroup
Return the Weyl group of `R`.
+
+# Examples
+```jldoctest
+julia> weyl_group(root_system([2 -1; -1 2]))
+Weyl group
+ of root system of rank 2
+ of type A2
+
+julia> weyl_group(root_system(matrix(ZZ, 2, 2, [2, -1, -1, 2]); detect_type=false))
+Weyl group
+ of root system of rank 2
+ of unknown type
+
+julia> weyl_group(root_system(matrix(ZZ, [2 -1 -2; -1 2 0; -1 0 2])))
+Weyl group
+ of root system of rank 3
+ of type C3 (with non-canonical ordering of simple roots)
+```
"""
function weyl_group(R::RootSystem)
return R.weyl_group::WeylGroup
@@ -501,7 +622,7 @@ Return the Weyl vector $\rho$ of `R`, which is the sum of all fundamental weight
or half the sum of all positive roots.
"""
function weyl_vector(R::RootSystem)
- return WeightLatticeElem(R, matrix(ZZ, rank(R), 1, fill(1, rank(R))))
+ return WeightLatticeElem(R, matrix(ZZ, 1, rank(R), fill(1, rank(R))))
end
###############################################################################
@@ -514,14 +635,10 @@ function RootSpaceElem(root_system::RootSystem, vec::Vector{<:RationalUnion})
return RootSpaceElem(root_system, matrix(QQ, 1, length(vec), vec))
end
-function RootSpaceElem(R::RootSystem, w::WeightLatticeElem)
- @req root_system(w) === R "Root system mismatch"
- coeffs = transpose!(cartan_matrix_inv(R) * coefficients(w))
- return RootSpaceElem(R, matrix(QQ, coeffs))
-end
-
function RootSpaceElem(w::WeightLatticeElem)
- return RootSpaceElem(root_system(w), w)
+ R = root_system(w)
+ coeffs = coefficients(w) * cartan_matrix_inv_tr(R)
+ return RootSpaceElem(R, matrix(QQ, coeffs))
end
function zero(::Type{RootSpaceElem}, R::RootSystem)
@@ -622,6 +739,23 @@ function dot(r1::RootSpaceElem, r2::RootSpaceElem)
)
end
+function expressify(r::RootSpaceElem; context=nothing)
+ if is_unicode_allowed()
+ return expressify(r, :α; context)
+ else
+ return expressify(r, :a; context)
+ end
+end
+
+function expressify(r::RootSpaceElem, s; context=nothing)
+ sum = Expr(:call, :+)
+ for i in 1:length(r.vec)
+ push!(sum.args, Expr(:call, :*, expressify(r.vec[i]; context), "$(s)_$(i)"))
+ end
+ return sum
+end
+@enable_all_show_via_expressify RootSpaceElem
+
@doc raw"""
height(r::RootSpaceElem) -> QQFieldElem
@@ -696,9 +830,9 @@ function reflect(r::RootSpaceElem, s::Int)
end
function reflect!(r::RootSpaceElem, s::Int)
- r.vec -=
- dot(view(cartan_matrix(root_system(r)), s, :), r.vec) *
- simple_root(root_system(r), s).vec
+ sub!(
+ Nemo.mat_entry_ptr(r.vec, 1, s), dot(view(cartan_matrix(root_system(r)), s, :), r.vec)
+ )
return r
end
@@ -805,6 +939,23 @@ function coeff(r::DualRootSpaceElem, i::Int)
return r.vec[i]
end
+function expressify(r::DualRootSpaceElem; context=nothing)
+ if is_unicode_allowed()
+ return expressify(r, :α̌; context)
+ else
+ return expressify(r, Symbol("a^v"); context)
+ end
+end
+
+function expressify(r::DualRootSpaceElem, s; context=nothing)
+ sum = Expr(:call, :+)
+ for i in 1:length(r.vec)
+ push!(sum.args, Expr(:call, :*, expressify(r.vec[i]; context), "$(s)_$(i)"))
+ end
+ return sum
+end
+@enable_all_show_via_expressify DualRootSpaceElem
+
@doc raw"""
height(r::DualRootSpaceElem) -> QQFieldElem
@@ -890,22 +1041,18 @@ end
Return the weight defined by the coefficients `v` of the fundamental weights with respect to the root system `R`.
"""
function WeightLatticeElem(R::RootSystem, v::Vector{<:IntegerUnion})
- return WeightLatticeElem(R, matrix(ZZ, rank(R), 1, v))
+ return WeightLatticeElem(R, matrix(ZZ, 1, rank(R), v))
end
-function WeightLatticeElem(R::RootSystem, r::RootSpaceElem)
- @req root_system(r) === R "Root system mismatch"
- coeffs = transpose!(coefficients(r) * cartan_matrix_tr(R))
+function WeightLatticeElem(r::RootSpaceElem)
+ R = root_system(r)
+ coeffs = coefficients(r) * cartan_matrix_tr(R)
@req all(is_integer, coeffs) "RootSpaceElem does not correspond to a weight"
return WeightLatticeElem(R, matrix(ZZ, coeffs))
end
-function WeightLatticeElem(r::RootSpaceElem)
- return WeightLatticeElem(root_system(r), r)
-end
-
function zero(::Type{WeightLatticeElem}, R::RootSystem)
- return WeightLatticeElem(R, zero_matrix(ZZ, rank(R), 1))
+ return WeightLatticeElem(R, zero_matrix(ZZ, 1, rank(R)))
end
function zero(r::WeightLatticeElem)
@@ -1065,14 +1212,22 @@ function dot(w1::WeightLatticeElem, w2::WeightLatticeElem)
return dot(
coefficients(w1),
- cartan_matrix_inv_tr(R) * (_cartan_symmetrizer_mat(R) * coefficients(w2)),
+ (coefficients(w2) * _cartan_symmetrizer_mat(R)) * cartan_matrix_inv(R),
)
end
-function expressify(w::WeightLatticeElem, s=:w; context=nothing)
+function expressify(w::WeightLatticeElem; context=nothing)
+ if is_unicode_allowed()
+ return expressify(w, :ω; context)
+ else
+ return expressify(w, :w; context)
+ end
+end
+
+function expressify(w::WeightLatticeElem, s; context=nothing)
sum = Expr(:call, :+)
for i in 1:length(w.vec)
- push!(sum.args, Expr(:call, :*, expressify(w.vec[i]; context), "$s$i"))
+ push!(sum.args, Expr(:call, :*, expressify(w.vec[i]; context), "$(s)_$(i)"))
end
return sum
end
@@ -1097,7 +1252,7 @@ end
Reflects the `w` at the `s`-th simple root in place and returns `w`.
"""
function reflect!(w::WeightLatticeElem, s::Int)
- addmul!(w.vec, view(cartan_matrix(root_system(w)), :, s:s), -w.vec[s])
+ w.vec = addmul!(w.vec, view(cartan_matrix_tr(root_system(w)), s:s, :), -w.vec[s]) # change to submul! once available
return w
end
@@ -1112,7 +1267,7 @@ function dot(r::RootSpaceElem, w::WeightLatticeElem)
@req root_system(r) === root_system(w) "parent root system mismatch"
R = root_system(r)
- return dot(coefficients(r), _cartan_symmetrizer_mat(R), coefficients(w))
+ return dot(coefficients(r) * _cartan_symmetrizer_mat(R), coefficients(w))
end
function dot(w::WeightLatticeElem, r::RootSpaceElem)
@@ -1193,8 +1348,8 @@ julia> dominant_weights(Vector{Int}, R, [3, 0, 1])
7-element Vector{Vector{Int64}}:
[3, 0, 1]
[1, 1, 1]
- [2, 0, 1]
[0, 0, 3]
+ [2, 0, 1]
[0, 1, 1]
[1, 0, 1]
[0, 0, 1]
@@ -1248,10 +1403,8 @@ function _action_matrices_on_weights(W::WeylGroup)
R = root_system(W)
return map(1:rank(R)) do i
x = gen(W, i)
- transpose!(
- matrix(
- ZZ, reduce(hcat, coefficients(x * fundamental_weight(R, j)) for j in 1:rank(R))
- ),
+ matrix(
+ ZZ, reduce(vcat, coefficients(x * fundamental_weight(R, j)) for j in 1:rank(R))
)
end
end
@@ -1280,6 +1433,15 @@ Dict{Vector{Int64}, Int64} with 4 entries:
```
"""
function dominant_character(R::RootSystem, hw::WeightLatticeElem)
+ char = _dominant_character(R, hw)
+ return Dict(Int.(_vec(coefficients(w))) => m for (w, m) in char)
+end
+
+function dominant_character(R::RootSystem, hw::Vector{<:IntegerUnion})
+ return dominant_character(R, WeightLatticeElem(R, hw))
+end
+
+function _dominant_character(R::RootSystem, hw::WeightLatticeElem)
T = Int
@req root_system(hw) === R "parent root system mismatch"
@req is_dominant(hw) "not a dominant weight"
@@ -1290,7 +1452,7 @@ function dominant_character(R::RootSystem, hw::WeightLatticeElem)
pos_roots = positive_roots(R)
pos_roots_w = WeightLatticeElem.(positive_roots(R))
- pos_roots_w_coeffs = transpose.(coefficients.(pos_roots_w))
+ pos_roots_w_coeffs = coefficients.(pos_roots_w)
char = Dict(hw => T(1))
@@ -1309,7 +1471,7 @@ function dominant_character(R::RootSystem, hw::WeightLatticeElem)
(
WeightLatticeElem(
R,
- transpose(first(intersect(elements(o), pos_roots_w_coeffs))),
+ first(intersect(elements(o), pos_roots_w_coeffs)),
),
length(o),
) for o in O
@@ -1337,12 +1499,7 @@ function dominant_character(R::RootSystem, hw::WeightLatticeElem)
end
end
end
- # return char
- return Dict(Int.(_vec(coefficients(w))) => m for (w, m) in char)
-end
-
-function dominant_character(R::RootSystem, hw::Vector{<:IntegerUnion})
- return dominant_character(R, WeightLatticeElem(R, hw))
+ return char
end
@doc raw"""
@@ -1366,31 +1523,34 @@ Dict{Vector{Int64}, Int64} with 8 entries:
[0, 0, 1] => 1
[1, -1, 1] => 1
[-1, 0, 1] => 1
- [0, -1, 1] => 1
- [0, 0, -1] => 1
[1, 0, -1] => 1
+ [0, 0, -1] => 1
+ [0, -1, 1] => 1
```
"""
function character(R::RootSystem, hw::WeightLatticeElem)
+ char = _character(R, hw)
+ return Dict(Int.(_vec(coefficients(w))) => m for (w, m) in char)
+end
+
+function character(R::RootSystem, hw::Vector{<:IntegerUnion})
+ return character(R, WeightLatticeElem(R, hw))
+end
+
+function _character(R::RootSystem, hw::WeightLatticeElem)
T = Int
@req root_system(hw) === R "parent root system mismatch"
@req is_dominant(hw) "not a dominant weight"
- dom_char = dominant_character(R, hw)
+ dom_char = _dominant_character(R, hw)
char = Dict{WeightLatticeElem,T}()
- for (w_, m) in dom_char
- w = WeightLatticeElem(R, w_)
+ for (w, m) in dom_char
for w_conj in weyl_orbit(w)
push!(char, w_conj => m)
end
end
- # return char
- return Dict(Int.(_vec(coefficients(w))) => m for (w, m) in char)
-end
-
-function character(R::RootSystem, hw::Vector{<:IntegerUnion})
- return character(R, WeightLatticeElem(R, hw))
+ return char
end
@doc raw"""
diff --git a/experimental/LieAlgebras/src/Types.jl b/experimental/LieAlgebras/src/Types.jl
index 7f7546c46bab..8acf63cf1d32 100644
--- a/experimental/LieAlgebras/src/Types.jl
+++ b/experimental/LieAlgebras/src/Types.jl
@@ -35,9 +35,7 @@
)
R.weyl_group = WeylGroup(finite, refl, R)
- detect_type &&
- is_finite(weyl_group(R)) &&
- set_root_system_type!(R, cartan_type_with_ordering(mat)...)
+ detect_type && is_finite(weyl_group(R)) && assure_root_system_type(R)
return R
end
end
@@ -64,10 +62,10 @@ end
mutable struct WeightLatticeElem
root_system::RootSystem
- vec::ZZMatrix # the coordinate (column) vector with respect to the fundamental weights
+ vec::ZZMatrix # the coordinate (row) vector with respect to the fundamental weights
function WeightLatticeElem(root_system::RootSystem, vec::ZZMatrix)
- @req size(vec) == (rank(root_system), 1) "Invalid dimension"
+ @req size(vec) == (1, rank(root_system)) "Invalid dimension"
return new(root_system, vec)
end
end
@@ -183,13 +181,13 @@ abstract type LieAlgebraElem{C<:FieldElem} <: AbstractAlgebra.SetElem end
begin
row = sparse_row(R)
for (k, k_val) in struct_consts[i, j]
- Hecke.add_scaled_row!(struct_consts[k, l], row, k_val)
+ row = addmul!(row, k_val, struct_consts[k, l])
end
for (k, k_val) in struct_consts[j, l]
- Hecke.add_scaled_row!(struct_consts[k, i], row, k_val)
+ row = addmul!(row, k_val, struct_consts[k, i])
end
for (k, k_val) in struct_consts[l, i]
- Hecke.add_scaled_row!(struct_consts[k, j], row, k_val)
+ row = addmul!(row, k_val, struct_consts[k, j])
end
row
end for i in 1:dimL, j in 1:dimL, l in 1:dimL
diff --git a/experimental/LieAlgebras/src/WeylGroup.jl b/experimental/LieAlgebras/src/WeylGroup.jl
index 821fe43e161e..fff0ca142754 100644
--- a/experimental/LieAlgebras/src/WeylGroup.jl
+++ b/experimental/LieAlgebras/src/WeylGroup.jl
@@ -24,7 +24,9 @@ Returns the Weyl group of the given type. See `cartan_matrix(fam::Symbol, rk::In
# Examples
```jldoctest
julia> weyl_group(:A, 2)
-Weyl group for root system defined by Cartan matrix [2 -1; -1 2]
+Weyl group
+ of root system of rank 2
+ of type A2
```
"""
function weyl_group(fam::Symbol, rk::Int)
@@ -92,10 +94,25 @@ function Base.one(W::WeylGroup)
return W(UInt8[]; normalize=false)
end
+function Base.show(io::IO, mime::MIME"text/plain", W::WeylGroup)
+ @show_name(io, W)
+ @show_special(io, mime, W)
+ io = pretty(io)
+ println(io, LowercaseOff(), "Weyl group")
+ print(io, Indent(), "of ", Lowercase())
+ show(io, mime, root_system(W))
+ print(io, Dedent())
+end
+
function Base.show(io::IO, W::WeylGroup)
@show_name(io, W)
@show_special(io, W)
- print(pretty(io), LowercaseOff(), "Weyl group for ", Lowercase(), W.root_system)
+ io = pretty(io)
+ if is_terse(io)
+ print(io, LowercaseOff(), "Weyl group")
+ else
+ print(io, LowercaseOff(), "Weyl group of ", Lowercase(), root_system(W))
+ end
end
function coxeter_matrix(W::WeylGroup)
@@ -204,26 +221,26 @@ function Base.:(*)(x::WeylGroupElem, y::WeylGroupElem)
return p
end
-function Base.:(*)(x::WeylGroupElem, r::RootSpaceElem)
- @req root_system(parent(x)) === root_system(r) "Incompatible root systems"
+function Base.:(*)(x::WeylGroupElem, rw::Union{RootSpaceElem,WeightLatticeElem})
+ @req root_system(parent(x)) === root_system(rw) "Incompatible root systems"
- r2 = deepcopy(r)
+ rw2 = deepcopy(rw)
for s in Iterators.reverse(word(x))
- reflect!(r2, Int(s))
+ reflect!(rw2, Int(s))
end
- return r2
+ return rw2
end
-function Base.:(*)(x::WeylGroupElem, w::WeightLatticeElem)
- @req root_system(parent(x)) === root_system(w) "Incompatible root systems"
+function Base.:(*)(rw::Union{RootSpaceElem,WeightLatticeElem}, x::WeylGroupElem)
+ @req root_system(parent(x)) === root_system(rw) "Incompatible root systems"
- w2 = deepcopy(w)
- for s in Iterators.reverse(word(x))
- reflect!(w2, Int(s))
+ rw2 = deepcopy(rw)
+ for s in word(x)
+ reflect!(rw2, Int(s))
end
- return w2
+ return rw2
end
# to be removed once GroupCore is supported
@@ -474,6 +491,59 @@ function isomorphism(::Type{FPGroup}, W::WeylGroup; set_properties::Bool=true)
return MapFromFunc(W, G, iso, isoinv)
end
+function permutation_group(W::WeylGroup; set_properties::Bool=true)
+ return codomain(isomorphism(PermGroup, W; set_properties))
+end
+
+function isomorphism(::Type{PermGroup}, W::WeylGroup; set_properties::Bool=true)
+ @req is_finite(W) "Weyl group is not finite"
+ R = root_system(W)
+ type, ordering = root_system_type_with_ordering(R)
+
+ if length(type) != 1
+ error("Not implemented (yet)")
+ end
+ if !issorted(ordering)
+ error("Not implemented (yet)")
+ end
+ coxeter_type, n = only(type)
+ if coxeter_type == :A
+ G = symmetric_group(n + 1)
+
+ iso = function (w::WeylGroupElem)
+ reduce(*, [cperm(G, [i, i + 1]) for i in word(w)]; init=cperm(G))
+ end
+
+ isoinv = function (p::PermGroupElem)
+ word = UInt8[]
+ for cycle in cycles(p)
+ transpositions = [
+ sort([c, cycle[i + 1]]) for (i, c) in enumerate(cycle) if i < length(cycle)
+ ]
+ for t in transpositions
+ word = reduce(
+ vcat,
+ [
+ [i for i in t[1]:(t[2] - 1)],
+ [i for i in reverse(t[1]:(t[2] - 2))],
+ word,
+ ],
+ )
+ end
+ end
+ return W(word)
+ end
+ else
+ error("Not implemented (yet)")
+ end
+
+ if set_properties
+ set_order(G, order(W))
+ end
+
+ return MapFromFunc(W, G, iso, isoinv)
+end
+
###############################################################################
# ReducedExpressionIterator
diff --git a/experimental/LieAlgebras/src/iso_gap_oscar.jl b/experimental/LieAlgebras/src/iso_gap_oscar.jl
index 7e5e259a3b86..f011aeb72694 100644
--- a/experimental/LieAlgebras/src/iso_gap_oscar.jl
+++ b/experimental/LieAlgebras/src/iso_gap_oscar.jl
@@ -26,9 +26,7 @@ function _iso_gap_oscar_abstract_lie_algebra(
LO = _abstract_lie_algebra_from_GAP(LG, coeffs_iso, s)
finv, f = _iso_oscar_gap_lie_algebra_functions(LO, LG, inv(coeffs_iso))
- iso = MapFromFunc(LG, LO, f, finv)
- set_attribute!(LO, :iso_oscar_gap => inv(iso))
- return iso
+ return MapFromFunc(LG, LO, f, finv)
end
function _iso_gap_oscar_linear_lie_algebra(
@@ -39,9 +37,7 @@ function _iso_gap_oscar_linear_lie_algebra(
LO = _linear_lie_algebra_from_GAP(LG, coeffs_iso, s)
finv, f = _iso_oscar_gap_lie_algebra_functions(LO, LG, inv(coeffs_iso))
- iso = MapFromFunc(LG, LO, f, finv)
- set_attribute!(LO, :iso_oscar_gap => inv(iso))
- return iso
+ return MapFromFunc(LG, LO, f, finv)
end
function _abstract_lie_algebra_from_GAP(
diff --git a/experimental/LieAlgebras/src/iso_oscar_gap.jl b/experimental/LieAlgebras/src/iso_oscar_gap.jl
index 1b8aa40ac95e..b01734970c02 100644
--- a/experimental/LieAlgebras/src/iso_oscar_gap.jl
+++ b/experimental/LieAlgebras/src/iso_oscar_gap.jl
@@ -22,7 +22,7 @@ function _iso_oscar_gap_lie_algebra_functions(
return (f, finv)
end
-function _iso_oscar_gap(LO::LinearLieAlgebra)
+function _iso_oscar_gap(LO::LinearLieAlgebra; set_attributes::Bool=true)
coeffs_iso = Oscar.iso_oscar_gap(coefficient_ring(LO))
LG = GAP.Globals.LieAlgebra(
codomain(coeffs_iso),
@@ -32,6 +32,12 @@ function _iso_oscar_gap(LO::LinearLieAlgebra)
f, finv = _iso_oscar_gap_lie_algebra_functions(LO, LG, coeffs_iso)
+ if set_attributes && has_root_system(LO)
+ # we need to construct the root system in GAP as otherwise it may detect a different order of simple roots
+ RO = root_system(LO)
+ _iso_oscar_gap_set_root_system(LG, RO)
+ end
+
return MapFromFunc(LO, LG, f, finv)
end
@@ -41,17 +47,17 @@ function _iso_oscar_gap(LO::AbstractLieAlgebra; set_attributes::Bool=true)
[
[
begin
- pairs = filter(pair -> !iszero(last(pair)), collect(enumerate(_matrix(xi * xj))))
- (map(first, pairs), GAP.Obj[coeffs_iso(c) for c in map(last, pairs)])
- end for xj in basis(LO)
- ] for xi in basis(LO)
+ pairs = collect(LO.struct_consts[i, j])
+ (first.(pairs), GAP.Obj[coeffs_iso(c) for c in last.(pairs)])
+ end for j in 1:dim(LO)
+ ] for i in 1:dim(LO)
]
-1
coeffs_iso(zero(coefficient_ring(LO)))
]
- LG = GAP.Globals.LieAlgebraByStructureConstants(
- codomain(coeffs_iso), GAP.Obj(sc_table_G; recursive=true)
+ LG = GAPWrap.LieAlgebraByStructureConstants(
+ codomain(coeffs_iso), GapObj(sc_table_G; recursive=true)
)
f, finv = _iso_oscar_gap_lie_algebra_functions(LO, LG, coeffs_iso)
@@ -59,34 +65,38 @@ function _iso_oscar_gap(LO::AbstractLieAlgebra; set_attributes::Bool=true)
if set_attributes && has_root_system(LO)
# we need to construct the root system in GAP as otherwise it may detect a different order of simple roots
RO = root_system(LO)
- RG = GAP.Globals.Objectify(
- GAP.Globals.NewType(
- GAP.Globals.NewFamily(GAP.Obj("RootSystemFam"), GAP.Globals.IsObject),
- GAP.evalstr("IsAttributeStoringRep and IsRootSystemFromLieAlgebra")),
- GAP.GapObj(Dict{Symbol,Any}()))
- GAP.Globals.SetUnderlyingLieAlgebra(RG, LG)
-
- cartan_trO = transpose(cartan_matrix(RO))
- transform_root(r::RootSpaceElem) = GAP.Obj(coefficients(r) * cartan_trO)[1]
- GAP.Globals.SetPositiveRoots(RG, GAP.Obj(transform_root.(positive_roots(RO))))
- GAP.Globals.SetNegativeRoots(RG, GAP.Obj(transform_root.(negative_roots(RO))))
- GAP.Globals.SetSimpleSystem(RG, GAP.Obj(transform_root.(simple_roots(RO))))
- can_basisG = GAP.Globals.CanonicalBasis(LG)
- pos_root_vectorsG = can_basisG[1:n_positive_roots(RO)]
- neg_root_vectorsG = can_basisG[(n_positive_roots(RO) + 1):(2 * n_positive_roots(RO))]
- csa_basisG = can_basisG[(2 * n_positive_roots(RO) + 1):end]
- GAP.Globals.SetPositiveRootVectors(RG, pos_root_vectorsG)
- GAP.Globals.SetNegativeRootVectors(RG, neg_root_vectorsG)
- GAP.Globals.SetCanonicalGenerators(
- RG, GAP.Obj([pos_root_vectorsG, neg_root_vectorsG, csa_basisG])
- )
- GAP.Globals.SetChevalleyBasis(
- LG, GAP.Obj([pos_root_vectorsG, neg_root_vectorsG, csa_basisG])
- )
-
- GAP.Globals.SetCartanMatrix(RG, GAP.Obj(cartan_trO))
- GAP.Globals.SetRootSystem(LG, RG)
+ _iso_oscar_gap_set_root_system(LG, RO)
end
return MapFromFunc(LO, LG, f, finv)
end
+
+function _iso_oscar_gap_set_root_system(LG::GapObj, RO::RootSystem)
+ RG = GAP.Globals.Objectify(
+ GAP.Globals.NewType(
+ GAP.Globals.NewFamily(GAP.Obj("RootSystemFam"), GAP.Globals.IsObject),
+ GAP.evalstr("IsAttributeStoringRep and IsRootSystemFromLieAlgebra")),
+ GAP.GapObj(Dict{Symbol,Any}()))
+ GAP.Globals.SetUnderlyingLieAlgebra(RG, LG)
+
+ cartan_trO = transpose(cartan_matrix(RO))
+ transform_root(r::RootSpaceElem) = GAP.Obj(coefficients(r) * cartan_trO)[1]
+ GAP.Globals.SetPositiveRoots(RG, GAP.Obj(transform_root.(positive_roots(RO))))
+ GAP.Globals.SetNegativeRoots(RG, GAP.Obj(transform_root.(negative_roots(RO))))
+ GAP.Globals.SetSimpleSystem(RG, GAP.Obj(transform_root.(simple_roots(RO))))
+ can_basisG = GAP.Globals.CanonicalBasis(LG)
+ pos_root_vectorsG = can_basisG[1:n_positive_roots(RO)]
+ neg_root_vectorsG = can_basisG[(n_positive_roots(RO) + 1):(2 * n_positive_roots(RO))]
+ csa_basisG = can_basisG[(2 * n_positive_roots(RO) + 1):end]
+ GAP.Globals.SetPositiveRootVectors(RG, pos_root_vectorsG)
+ GAP.Globals.SetNegativeRootVectors(RG, neg_root_vectorsG)
+ GAP.Globals.SetCanonicalGenerators(
+ RG, GAP.Obj([pos_root_vectorsG, neg_root_vectorsG, csa_basisG])
+ )
+ GAP.Globals.SetChevalleyBasis(
+ LG, GAP.Obj([pos_root_vectorsG, neg_root_vectorsG, csa_basisG])
+ )
+
+ GAP.Globals.SetCartanMatrix(RG, GAP.Obj(cartan_trO))
+ GAP.Globals.SetRootSystem(LG, RG)
+end
diff --git a/experimental/LieAlgebras/src/serialization.jl b/experimental/LieAlgebras/src/serialization.jl
index 52b76c7dc997..e3f8f8cea085 100644
--- a/experimental/LieAlgebras/src/serialization.jl
+++ b/experimental/LieAlgebras/src/serialization.jl
@@ -255,7 +255,7 @@ function save_object(s::SerializerState, R::RootSystem)
if has_root_system_type(R)
type, type_ordering = root_system_type_with_ordering(R)
save_object(s, type, :type)
- if type_ordering != 1:length(type_ordering) # don't save if it's the default
+ if !issorted(type_ordering) # don't save if it's the default
save_object(s, type_ordering, :type_ordering)
end
end
diff --git a/experimental/LieAlgebras/test/RootSystem-test.jl b/experimental/LieAlgebras/test/RootSystem-test.jl
index 71cd8001372f..58263e4c2c12 100644
--- a/experimental/LieAlgebras/test/RootSystem-test.jl
+++ b/experimental/LieAlgebras/test/RootSystem-test.jl
@@ -30,6 +30,10 @@
end
@testset "property tests" begin
+ Main.equality(a::RootSpaceElem, b::RootSpaceElem) = a == b
+ Main.equality(a::DualRootSpaceElem, b::DualRootSpaceElem) = a == b
+ Main.equality(a::WeightLatticeElem, b::WeightLatticeElem) = a == b
+
function root_system_property_tests(R::RootSystem, rk::Int, npositive_roots::Int)
W = weyl_group(R)
@@ -136,72 +140,17 @@
RootSpaceElem, DualRootSpaceElem, WeightLatticeElem
)
rk = rank(R)
+ for _ in 1:10
+ a = T(R, rand(-10:10, rk))
+ b = T(R, rand(-10:10, rk))
+ c = T(R, rand(-10:10, rk))
- x1 = T(R, rand(-10:10, rk))
- x2 = T(R, rand(-10:10, rk))
- x3 = T(R, rand(-10:10, rk))
- x1c = deepcopy(x1)
- x2c = deepcopy(x2)
- x3c = deepcopy(x3)
-
- for (f, f!) in ((zero, zero!),)
- x1 = f!(x1)
- @test x1 == f(x1c)
- x1 = deepcopy(x1c)
- end
-
- for (f, f!) in ((-, neg!),)
- x1 = f!(x1, x2)
- @test x1 == f(x2c)
- @test x2 == x2c
- x1 = deepcopy(x1c)
- x2 = deepcopy(x2c)
+ test_mutating_op_like_zero(zero, zero!, a)
- x1 = f!(x1)
- @test x1 == f(x1c)
- x1 = deepcopy(x1c)
- end
+ test_mutating_op_like_neg(-, neg!, a)
- for (f, f!) in ((+, add!), (-, sub!))
- x1 = f!(x1, x2, x3)
- @test x1 == f(x2c, x3c)
- @test x2 == x2c
- @test x3 == x3c
- x1 = deepcopy(x1c)
- x2 = deepcopy(x2c)
- x3 = deepcopy(x3c)
-
- x1 = f!(x1, x1, x2)
- @test x1 == f(x1c, x2c)
- @test x2 == x2c
- x1 = deepcopy(x1c)
- x2 = deepcopy(x2c)
-
- x1 = f!(x1, x2, x1)
- @test x1 == f(x2c, x1c)
- @test x2 == x2c
- x1 = deepcopy(x1c)
- x2 = deepcopy(x2c)
-
- x1 = f!(x1, x2, x2)
- @test x1 == f(x2c, x2c)
- @test x2 == x2c
- x1 = deepcopy(x1c)
- x2 = deepcopy(x2c)
-
- x1 = f!(x1, x1, x1)
- @test x1 == f(x1c, x1c)
- x1 = deepcopy(x1c)
-
- x1 = f!(x1, x2)
- @test x1 == f(x1c, x2c)
- @test x2 == x2c
- x1 = deepcopy(x1c)
- x2 = deepcopy(x2c)
-
- x1 = f!(x1, x1)
- @test x1 == f(x1c, x1c)
- x1 = deepcopy(x1c)
+ test_mutating_op_like_add(+, add!, a, b)
+ test_mutating_op_like_add(-, sub!, a, b)
end
end
diff --git a/experimental/LieAlgebras/test/WeylGroup-test.jl b/experimental/LieAlgebras/test/WeylGroup-test.jl
index 76178206bce4..18c39e2766d2 100644
--- a/experimental/LieAlgebras/test/WeylGroup-test.jl
+++ b/experimental/LieAlgebras/test/WeylGroup-test.jl
@@ -52,6 +52,7 @@ include(
@testset "WeylGroup Group conformace test for $(Wname)" for (Wname, W) in [
("A1", weyl_group(:A, 1)),
+ ("A5", weyl_group(:A, 5)),
("B4", weyl_group(root_system(:B, 4))),
("D5", weyl_group(cartan_matrix(:D, 5))),
("F4+G2", weyl_group((:F, 4), (:G, 2))),
@@ -111,9 +112,55 @@ include(
if is_finite(W) # remove once rand(W) is implemented for infinite groups
w = rand(W)
@test w == inv(iso)(iso(w))
+ v = rand(W)
+ @test iso(v * w) == iso(v) * iso(w)
+ @test v * w == inv(iso)(iso(v) * iso(w))
end
g = rand_pseudo(G)
@test g == iso(inv(iso)(g))
+ h = rand_pseudo(G)
+ @test inv(iso)(h * g) == inv(iso)(h) * inv(iso)(g)
+ @test h * g == iso(inv(iso)(h) * inv(iso)(g))
+ end
+ end
+ end
+ end
+
+ if has_root_system_type(root_system(W))
+ type, ordering = root_system_type_with_ordering(root_system(W))
+ if length(type) == 1 && issorted(ordering) && only(type)[1] == :A # only implemented for A_n (yet)
+ @testset "isomorphism(PermGroup, ::WeylGroup; set_properties=$set_properties)" for set_properties in
+ [
+ false, true
+ ]
+ G = permutation_group(W; set_properties)
+ if (is_finite(W) && ngens(W) < 6) || set_properties #= for sane runtime =#
+ @test is_finite(G) == is_finite(W)
+ is_finite(W) && @test order(G) == order(W)
+ end
+
+ iso = isomorphism(PermGroup, W; set_properties)
+ @test W == domain(iso)
+ G = codomain(iso)
+ if (is_finite(W) && ngens(W) < 6) || set_properties #= for sane runtime =#
+ @test is_finite(G) == is_finite(W)
+ is_finite(W) && @test order(G) == order(W)
+ if ngens(W) < 10 #= for sane runtime =#
+ for _ in 1:5
+ if is_finite(W) # remove once rand(W) is implemented for infinite groups
+ w = rand(W)
+ @test w == inv(iso)(iso(w))
+ v = rand(W)
+ @test iso(v * w) == iso(v) * iso(w)
+ @test v * w == inv(iso)(iso(v) * iso(w))
+ end
+ g = rand_pseudo(G)
+ @test g == iso(inv(iso)(g))
+ h = rand_pseudo(G)
+ @test inv(iso)(h * g) == inv(iso)(h) * inv(iso)(g)
+ @test h * g == iso(inv(iso)(h) * inv(iso)(g))
+ end
+ end
end
end
end
@@ -241,9 +288,9 @@ include(
@test ngens(weyl_group(:F, 4)) == 4
@test ngens(weyl_group(:G, 2)) == 2
- @test ngens(weyl_group((:A, 2), (:B, 4))) == 6
- @test ngens(weyl_group((:C, 3), (:E, 7))) == 10
- @test ngens(weyl_group((:F, 4), (:G, 2))) == 6
+ @test ngens(weyl_group((:A, 2), (:B, 4))) == 2 + 4
+ @test ngens(weyl_group((:C, 3), (:E, 7))) == 3 + 7
+ @test ngens(weyl_group((:F, 4), (:G, 2))) == 4 + 2
end
@testset "Base.:(*)(x::WeylGroupElem, y::WeylGroupElem)" begin
@@ -300,20 +347,30 @@ include(
@test w^-4 == inv(w) * inv(w) * inv(w) * inv(w)
end
- @testset "Base.:(*)(x::WeylGroupElem, w::RootSpaceElem)" begin
+ @testset "action on RootSpaceElem" begin
let R = root_system(:A, 2)
W = weyl_group(R)
a = positive_root(R, n_positive_roots(R)) # highest root
@test one(W) * a == a
+ @test a * one(W) == a
@test W([1]) * a == simple_root(R, 2)
+ @test a * W([1]) == simple_root(R, 2)
@test W([2]) * a == simple_root(R, 1)
+ @test a * W([2]) == simple_root(R, 1)
@test longest_element(W) * a == -a
+ @test a * longest_element(W) == -a
+ @test W([1, 2]) * a == -simple_root(R, 1)
+ @test a * W([1, 2]) == -simple_root(R, 2)
+ @test W([1, 2]) * a != a * W([1, 2])
a_copy = deepcopy(a)
b = W([1]) * a
@test a != b
@test a == a_copy
+ b = a * W([1])
+ @test a != b
+ @test a == a_copy
b = reflect(a, 1)
@test a != b
@test a == a_copy
@@ -324,24 +381,42 @@ include(
a = positive_root(R, n_positive_roots(R)) # highest (long) root
@test one(W) * a == a
+ @test a * one(W) == a
@test W([1]) * a == a
+ @test a * W([1]) == a
@test W([2]) * a == simple_root(R, 1)
+ @test a * W([2]) == simple_root(R, 1)
@test longest_element(W) * a == -a
+ @test a * longest_element(W) == -a
+ @test W([1, 2]) * a == -simple_root(R, 1)
+ @test a * W([1, 2]) == simple_root(R, 1)
+ @test W([1, 2]) * a != a * W([1, 2])
a = simple_root(R, 1)
@test one(W) * a == a
+ @test a * one(W) == a
@test W([1]) * a == -a
+ @test a * W([1]) == -a
@test W([2]) * a == positive_root(R, n_positive_roots(R))
+ @test a * W([2]) == positive_root(R, n_positive_roots(R))
@test longest_element(W) * a == -a
+ @test a * longest_element(W) == -a
+ @test W([1, 2]) * a == positive_root(R, n_positive_roots(R))
+ @test a * W([1, 2]) == -positive_root(R, n_positive_roots(R))
+ @test W([1, 2]) * a != a * W([1, 2])
end
end
- @testset "Base.:(*)(x::WeylGroupElem, w::WeightLatticeElem)" begin
+ @testset "action on WeightLatticeElem" begin
R = root_system(:A, 2)
W = weyl_group(R)
rho = weyl_vector(R)
@test longest_element(W) * rho == -rho
+ @test rho * longest_element(W) == -rho
+
+ x = W([1, 2])
+ @test x * rho != rho * x
end
@testset "parent(::WeylGroupElem)" begin
diff --git a/experimental/LieAlgebras/test/iso_gap_oscar-test.jl b/experimental/LieAlgebras/test/iso_gap_oscar-test.jl
index 6870438dfc5a..206d5b2d3ba9 100644
--- a/experimental/LieAlgebras/test/iso_gap_oscar-test.jl
+++ b/experimental/LieAlgebras/test/iso_gap_oscar-test.jl
@@ -6,8 +6,6 @@ function test_iso_gap_oscar(LG, oscarT; num_random_tests::Int=10)
LO = codomain(iso)
@test LO isa oscarT
- @test codomain(Oscar.iso_oscar_gap(LO)) === LG
-
@test iso === Oscar.iso_gap_oscar(LG) # test caching
for _ in 1:num_random_tests
diff --git a/experimental/LieAlgebras/test/iso_oscar_gap-test.jl b/experimental/LieAlgebras/test/iso_oscar_gap-test.jl
index f01c34998365..06682e11a2bf 100644
--- a/experimental/LieAlgebras/test/iso_oscar_gap-test.jl
+++ b/experimental/LieAlgebras/test/iso_oscar_gap-test.jl
@@ -5,7 +5,6 @@ function test_iso_oscar_gap(LO::LieAlgebra; num_random_tests::Int=10)
@test domain(iso) === LO
LG = codomain(iso)
@test GAPWrap.IsLieAlgebra(LG)
- # @test codomain(Oscar.iso_gap_oscar(LG)) === LO
@test iso === Oscar.iso_oscar_gap(LO) # test caching
diff --git a/experimental/LieAlgebras/test/setup_tests.jl b/experimental/LieAlgebras/test/setup_tests.jl
index 80dc1590266c..8c13d241e7cc 100644
--- a/experimental/LieAlgebras/test/setup_tests.jl
+++ b/experimental/LieAlgebras/test/setup_tests.jl
@@ -4,6 +4,14 @@ if !isdefined(Main, :GAPWrap)
import Oscar: GAPWrap
end
+if !isdefined(Main, :test_mutating_op_like_zero)
+ include(
+ joinpath(
+ pathof(Oscar.Nemo.AbstractAlgebra), "..", "..", "test", "Rings-conformance-tests.jl"
+ ),
+ )
+end
+
if !isdefined(Main, :lie_algebra_conformance_test) || isinteractive()
function lie_algebra_conformance_test(
L::LieAlgebra{C}, parentT::DataType, elemT::DataType; num_random_tests::Int=10
diff --git a/experimental/LinearQuotients/docs/src/cox_rings.md b/experimental/LinearQuotients/docs/src/cox_rings.md
index d1e7d0123214..561f9353339c 100644
--- a/experimental/LinearQuotients/docs/src/cox_rings.md
+++ b/experimental/LinearQuotients/docs/src/cox_rings.md
@@ -1,5 +1,6 @@
```@meta
CurrentModule = Oscar
+DocTestSetup = Oscar.doctestsetup()
```
# Cox rings
diff --git a/experimental/LinearQuotients/docs/src/introduction.md b/experimental/LinearQuotients/docs/src/introduction.md
index 36199c781961..6cea3b695daf 100644
--- a/experimental/LinearQuotients/docs/src/introduction.md
+++ b/experimental/LinearQuotients/docs/src/introduction.md
@@ -1,5 +1,6 @@
```@meta
CurrentModule = Oscar
+DocTestSetup = Oscar.doctestsetup()
```
# Introduction
diff --git a/experimental/LinearQuotients/docs/src/linear_quotients.md b/experimental/LinearQuotients/docs/src/linear_quotients.md
index 61f8fd288b16..79ca7301cf6a 100644
--- a/experimental/LinearQuotients/docs/src/linear_quotients.md
+++ b/experimental/LinearQuotients/docs/src/linear_quotients.md
@@ -1,5 +1,6 @@
```@meta
CurrentModule = Oscar
+DocTestSetup = Oscar.doctestsetup()
```
# Construction and basic functionality
diff --git a/experimental/OrthogonalDiscriminants/docs/src/introduction.md b/experimental/OrthogonalDiscriminants/docs/src/introduction.md
index d7c9a8f27abb..7c02bf553d71 100644
--- a/experimental/OrthogonalDiscriminants/docs/src/introduction.md
+++ b/experimental/OrthogonalDiscriminants/docs/src/introduction.md
@@ -1,5 +1,6 @@
```@meta
CurrentModule = Oscar
+DocTestSetup = Oscar.doctestsetup()
```
# Introduction
diff --git a/experimental/PartitionedPermutations/docs/src/introduction.md b/experimental/PartitionedPermutations/docs/src/introduction.md
index 7893dd848568..439ae48e34ff 100644
--- a/experimental/PartitionedPermutations/docs/src/introduction.md
+++ b/experimental/PartitionedPermutations/docs/src/introduction.md
@@ -1,5 +1,6 @@
```@meta
CurrentModule = Oscar
+DocTestSetup = Oscar.doctestsetup()
```
# Partitioned Permutations
diff --git a/experimental/QuadFormAndIsom/docs/src/enumeration.md b/experimental/QuadFormAndIsom/docs/src/enumeration.md
index 1925c96243e1..444c183afbb9 100644
--- a/experimental/QuadFormAndIsom/docs/src/enumeration.md
+++ b/experimental/QuadFormAndIsom/docs/src/enumeration.md
@@ -1,5 +1,6 @@
```@meta
CurrentModule = Oscar
+DocTestSetup = Oscar.doctestsetup()
```
# Enumeration of isometries
diff --git a/experimental/QuadFormAndIsom/docs/src/introduction.md b/experimental/QuadFormAndIsom/docs/src/introduction.md
index fc96d4cc147b..f1fb978c0fb2 100644
--- a/experimental/QuadFormAndIsom/docs/src/introduction.md
+++ b/experimental/QuadFormAndIsom/docs/src/introduction.md
@@ -1,3 +1,8 @@
+```@meta
+CurrentModule = Oscar
+DocTestSetup = Oscar.doctestsetup()
+```
+
# Quadratic forms and isometries
This project is a complement to the code about *hermitian lattices* available
diff --git a/experimental/QuadFormAndIsom/docs/src/latwithisom.md b/experimental/QuadFormAndIsom/docs/src/latwithisom.md
index 7fb9347224c8..98abc956b8f5 100644
--- a/experimental/QuadFormAndIsom/docs/src/latwithisom.md
+++ b/experimental/QuadFormAndIsom/docs/src/latwithisom.md
@@ -1,5 +1,6 @@
```@meta
CurrentModule = Oscar
+DocTestSetup = Oscar.doctestsetup()
```
# Lattices with isometry
diff --git a/experimental/QuadFormAndIsom/docs/src/primembed.md b/experimental/QuadFormAndIsom/docs/src/primembed.md
index 3bf01561bdde..4343a00f7d99 100644
--- a/experimental/QuadFormAndIsom/docs/src/primembed.md
+++ b/experimental/QuadFormAndIsom/docs/src/primembed.md
@@ -1,5 +1,6 @@
```@meta
CurrentModule = Oscar
+DocTestSetup = Oscar.doctestsetup()
```
We introduce here the necessary definitions and results which lie behind the
diff --git a/experimental/QuadFormAndIsom/docs/src/spacewithisom.md b/experimental/QuadFormAndIsom/docs/src/spacewithisom.md
index 91f8ddbb423d..d65e79d41505 100644
--- a/experimental/QuadFormAndIsom/docs/src/spacewithisom.md
+++ b/experimental/QuadFormAndIsom/docs/src/spacewithisom.md
@@ -1,5 +1,6 @@
```@meta
CurrentModule = Oscar
+DocTestSetup = Oscar.doctestsetup()
```
# Quadratic spaces with isometry
diff --git a/experimental/QuadFormAndIsom/src/embeddings.jl b/experimental/QuadFormAndIsom/src/embeddings.jl
index ee934c79666b..da388cd0424a 100644
--- a/experimental/QuadFormAndIsom/src/embeddings.jl
+++ b/experimental/QuadFormAndIsom/src/embeddings.jl
@@ -1286,25 +1286,27 @@ of $M$ into lattices in $G$.
"""
function primitive_embeddings(G::ZZGenus, M::ZZLat; classification::Symbol = :sub)
@req is_integral(scale(G)) && is_integral(M) "Only available for integral lattices"
- @req !iseven(G) || iseven(M) "Cannot embed an odd lattice into an even lattice"
@req classification in Symbol[:none, :emb, :sub, :first] "Wrong symbol for classification"
+ results = Tuple{ZZLat, ZZLat, ZZLat}[]
+
+ (iseven(G) && !iseven(M)) && return false, results
+ (rank(M) > rank(G)) && return false, results
+
even = is_even(G)
posL, _, negL = signature_tuple(G)
posM, _, negM = signature_tuple(M)
posN = posL - posM
negN = negL - negM
- @req (posN >= 0 && negN >= 0) "Incompatible signatures for the embeddings"
- results = Tuple{ZZLat, ZZLat, ZZLat}[]
+ (posN < 0 || negN < 0) && return false, results
+
if rank(M) == rank(G)
genus(M) != G && return false, results
push!(results, (M, M, orthogonal_submodule(M, M)))
return true, results
end
- @req rank(M) < rank(G) "The rank of M must be smaller or equal than the one of the lattices in G"
-
if classification == :sub
cs = :subsub
elseif classification == :emb
@@ -1666,7 +1668,7 @@ function admissible_equivariant_primitive_extensions(A::ZZLatWithIsom,
p::IntegerUnion,
q::IntegerUnion = p; check::Bool = true)
# p and q can be equal, and they will be most of the time
- @req is_prime(p) && is_prime(q) "p and q must be a prime number"
+ @req is_prime(p) && is_prime(q) "p and q must be prime numbers"
# Requirements for [BH23]
same_ambient = ambient_space(lattice(A)) === ambient_space(lattice(B)) === ambient_space(lattice(C))
diff --git a/experimental/QuadFormAndIsom/src/enumeration.jl b/experimental/QuadFormAndIsom/src/enumeration.jl
index b1d85ed06f1c..219f02d15463 100644
--- a/experimental/QuadFormAndIsom/src/enumeration.jl
+++ b/experimental/QuadFormAndIsom/src/enumeration.jl
@@ -347,7 +347,7 @@ function admissible_triples(G::ZZGenus, p::IntegerUnion; pA::Int = -1, nA::Int =
elseif nA >= 0
r1 >= nA || continue
end
- m = min(ep, r1)
+ m = Int(min(ep, r1))
D = _find_D(dG, m, p)
while !is_empty(D)
d1, dp = pop!(D)
@@ -616,6 +616,7 @@ function representatives_of_hermitian_type(G::ZZGenus, chi::Union{ZZPolyRingElem
append!(gene, hermitian_genera(E, rk, sign, dd; min_scale=inv(DE), max_scale=numerator(dd)*DE))
end
unique!(gene)
+ isempty(gene) && return reps
# In the cyclotomic case, the Galois group of the fixed field K acts on the
# set of genera by "change of fixed primitive root of unity".
diff --git a/experimental/QuadFormAndIsom/test/runtests.jl b/experimental/QuadFormAndIsom/test/runtests.jl
index 766594875221..a72b1f114981 100644
--- a/experimental/QuadFormAndIsom/test/runtests.jl
+++ b/experimental/QuadFormAndIsom/test/runtests.jl
@@ -48,7 +48,7 @@ end
@test evaluate(minimal_polynomial(Vf), -1) == 0
@test evaluate(characteristic_polynomial(Vf), 0) == 1
- G = matrix(FlintQQ, 6, 6 ,[3, 1, -1, 1, 0, 0, 1, 3, 1, 1, 1, 1, -1, 1, 3, 0, 0, 1, 1, 1, 0, 4, 2, 2, 0, 1, 0, 2, 4, 2, 0, 1, 1, 2, 2, 4])
+ G = matrix(QQ, 6, 6 ,[3, 1, -1, 1, 0, 0, 1, 3, 1, 1, 1, 1, -1, 1, 3, 0, 0, 1, 1, 1, 0, 4, 2, 2, 0, 1, 0, 2, 4, 2, 0, 1, 1, 2, 2, 4])
V = quadratic_space(QQ, G)
f = matrix(QQ, 6, 6, [1 0 0 0 0 0; 0 0 -1 0 0 0; -1 1 -1 0 0 0; 0 0 0 1 0 -1; 0 0 0 0 0 -1; 0 0 0 0 1 -1])
Vf = @inferred quadratic_space_with_isometry(V, f)
@@ -301,7 +301,7 @@ end
ok, sv = primitive_embeddings(rescale(E8, 2), rescale(k, QQ(1//2)); check=false)
@test !ok
@test is_empty(sv)
- @test_throws ArgumentError primitive_embeddings(rescale(E8, -1), k; check=false)
+ @test isempty(primitive_embeddings(rescale(E8, -1), k; check=false)[2])
k = integer_lattice(; gram=matrix(QQ,1,1,[6]))
E7 = root_lattice(:E, 7)
@@ -386,8 +386,8 @@ end
@test length(reps) == 1
## Odd case
- B = matrix(FlintQQ, 5, 5 ,[1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1]);
- G = matrix(FlintQQ, 5, 5 ,[3, 1, 0, 0, 0, 1, 3, 1, 1, -1, 0, 1, 3, 0, 0, 0, 1, 0, 3, 0, 0, -1, 0, 0, 3]);
+ B = matrix(QQ, 5, 5 ,[1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1]);
+ G = matrix(QQ, 5, 5 ,[3, 1, 0, 0, 0, 1, 3, 1, 1, -1, 0, 1, 3, 0, 0, 0, 1, 0, 3, 0, 0, -1, 0, 0, 3]);
L = integer_lattice(B, gram = G);
k = lattice_in_same_ambient_space(L, B[2:2, :])
N = orthogonal_submodule(L, k)
diff --git a/experimental/Schemes/src/Schemes.jl b/experimental/Schemes/src/Schemes.jl
index 215ff86cd640..6a79c72052db 100644
--- a/experimental/Schemes/src/Schemes.jl
+++ b/experimental/Schemes/src/Schemes.jl
@@ -3,12 +3,8 @@ include("CoveredScheme.jl")
include("ProjectiveModules.jl")
include("SpaceGerms.jl")
include("Tjurina.jl")
-include("CoveredProjectiveSchemes.jl")
include("Auxiliary.jl")
-include("BlowupMorphismTypes.jl")
-include("BlowupMorphism.jl")
-include("elliptic_surface.jl")
include("critical_locus.jl")
include("ToricIdealSheaves/auxiliary.jl")
@@ -65,6 +61,7 @@ export is_finitely_determined
export determinacy_bound
export sharper_determinacy_bound
export is_contact_equivalent
+export tjurina_module
# Deprecated after 0.15
diff --git a/experimental/Schemes/src/Tjurina.jl b/experimental/Schemes/src/Tjurina.jl
index 368cdf553ecb..48c5d5bae723 100644
--- a/experimental/Schemes/src/Tjurina.jl
+++ b/experimental/Schemes/src/Tjurina.jl
@@ -738,3 +738,96 @@ function is_contact_equivalent(X::HypersurfaceGerm, Y::HypersurfaceGerm)
g = defining_ideal(Y)[1]
return is_contact_equivalent(f, g)
end
+
+
+
+
+################################################################################
+
+##### Tjurina module #####
+
+################################################################################
+
+
+@doc raw"""
+ tjurina_module(X::CompleteIntersectionGerm)
+
+Return the Tjurina module of the complete intersection germ `(X,p)` at the point `p`.
+# Examples
+```jldoctest
+julia> R, (x,y,z) = QQ["x","y","z"];
+
+julia> I = ideal(R, [x^2+y^2-z^2, x*y]);
+
+julia> X = CompleteIntersectionGerm(spec(quo(R, I)[1]), [0,0,0])
+Spectrum
+ of localization
+ of quotient
+ of multivariate polynomial ring in 3 variables x, y, z
+ over rational field
+ by ideal (x^2 + y^2 - z^2, x*y)
+ at complement of maximal ideal of point (0, 0, 0)
+
+julia> T = tjurina_module(X)
+Subquotient of submodule with 2 generators
+ 1: e[1]
+ 2: e[2]
+by submodule with 7 generators
+ 1: 2*x*e[1] + y*e[2]
+ 2: 2*y*e[1] + x*e[2]
+ 3: -2*z*e[1]
+ 4: (x^2 + y^2 - z^2)*e[1]
+ 5: (x^2 + y^2 - z^2)*e[2]
+ 6: x*y*e[1]
+ 7: x*y*e[2]
+
+julia> vector_space_basis(T)
+5-element Vector{Any}:
+ e[1]
+ e[2]
+ y*e[1]
+ y*e[2]
+ z*e[2]
+```
+"""
+function tjurina_module(X::CompleteIntersectionGerm)
+ I = defining_ideal(X)
+ k = ngens(I)
+ R = base_ring(I)
+ M = free_module(R, k)
+ J = jacobian_matrix(gens(I))
+ S = sub(M,J)[1] + (I*M)[1]
+ return quo(M, S)[1]
+end
+
+
+
+@doc raw"""
+ tjurina_number(X::CompleteIntersectionGerm)
+
+Return Tjurina number of the complete intersection germ `(X,p)` at the point `p`.
+# Examples
+```jldoctest
+julia> R, (x,y,z) = QQ["x","y","z"];
+
+julia> I = ideal(R, [x^2+y^2-z^2, x*y]);
+
+julia> X = CompleteIntersectionGerm(spec(quo(R, I)[1]), [0,0,0])
+Spectrum
+ of localization
+ of quotient
+ of multivariate polynomial ring in 3 variables x, y, z
+ over rational field
+ by ideal (x^2 + y^2 - z^2, x*y)
+ at complement of maximal ideal of point (0, 0, 0)
+
+julia> tjurina_number(X)
+5
+```
+"""
+function tjurina_number(X::CompleteIntersectionGerm)
+ d = vector_space_dimension(tjurina_module(X))
+ return d == -1 ? PosInf() : d
+end
+
+
diff --git a/experimental/Schemes/src/ToricBlowups/constructors.jl b/experimental/Schemes/src/ToricBlowups/constructors.jl
index c9a192240382..0263c5d0028c 100644
--- a/experimental/Schemes/src/ToricBlowups/constructors.jl
+++ b/experimental/Schemes/src/ToricBlowups/constructors.jl
@@ -137,7 +137,7 @@ julia> rs = [1 1; -1 1]
1 1
-1 1
-julia> max_cones = IncidenceMatrix([[1, 2]])
+julia> max_cones = incidence_matrix([[1, 2]])
1×2 IncidenceMatrix
[1, 2]
diff --git a/experimental/Schemes/src/Types.jl b/experimental/Schemes/src/Types.jl
index 59396ce9c518..e69de29bb2d1 100644
--- a/experimental/Schemes/src/Types.jl
+++ b/experimental/Schemes/src/Types.jl
@@ -1,185 +0,0 @@
-export AbsProjectiveScheme
-export EmptyScheme
-export ProjectiveScheme
-export ProjectiveSchemeMor
-export VarietyFunctionField
-export VarietyFunctionFieldElem
-
-abstract type AbsProjectiveGluing{
- GluingType<:AbsGluing,
- }
-end
-
-@doc raw"""
- LazyProjectiveGluing(
- X::AbsProjectiveScheme,
- Y::AbsProjectiveScheme,
- BG::AbsGluing,
- compute_function::Function,
- gluing_data
- )
-
-Produce a container `pg` to host a non-computed `ProjectiveGluing` of ``X`` with ``Y``.
-
-The arguments consist of
-
- * the patches ``X`` and ``Y`` to be glued;
- * a gluing `BG` of the `base_scheme`s of ``X`` and ``Y`` over which the
- `ProjectiveGluing` to be computed sits;
- * a function `compute_function` which takes a single argument `gluing_data`
- of arbitrary type and actually carries out the computation;
- * an arbitrary struct `gluing_data` that the user can fill with whatever
- information is needed to properly feed their `compute_function`.
-
-The container `pg` can then be stored as the gluing of ``X`` and ``Y``. As soon
-as it is asked about any data on the gluing beyond its two `patches`, it will
-invoke the internally stored `compute_function` to actually carry out the computation
-of the gluing and then serve the incoming request on the basis of that result.
-The latter actual `ProjectiveGluing` will then be cached.
-"""
-mutable struct LazyProjectiveGluing{
- GluingType<:AbsGluing,
- GluingDataType
- } <: AbsProjectiveGluing{GluingType}
- base_gluing::GluingType
- patches::Tuple{AbsProjectiveScheme, AbsProjectiveScheme}
- compute_function::Function
- gluing_data::GluingDataType
- underlying_gluing::AbsProjectiveGluing
-
- function LazyProjectiveGluing(
- X::AbsProjectiveScheme,
- Y::AbsProjectiveScheme,
- BG::AbsGluing,
- compute_function::Function,
- gluing_data
- )
- (base_scheme(X), base_scheme(Y)) == patches(BG) || error("gluing is incompatible with provided patches")
- return new{typeof(BG), typeof(gluing_data)}(BG, (X, Y), compute_function, gluing_data)
- end
-end
-
-@doc raw"""
- ProjectiveGluing(
- G::GluingType,
- incP::IncType, incQ::IncType,
- f::IsoType, g::IsoType;
- check::Bool=true
- ) where {GluingType<:AbsGluing, IncType<:ProjectiveSchemeMor, IsoType<:ProjectiveSchemeMor}
-
-The `AbsProjectiveSchemeMorphism`s `incP` and `incQ` are open embeddings over open
-embeddings of their respective `base_scheme`s.
-
- PX ↩ PU ≅ QV ↪ QY
- π ↓ ↓ ↓ ↓ π
- G : X ↩ U ≅ V ↪ Y
-
-This creates a gluing of the projective schemes `codomain(incP)` and `codomain(incQ)`
-over a gluing `G` of their `base_scheme`s along the morphisms of `AbsProjectiveScheme`s
-`f` and `g`, identifying `domain(incP)` and `domain(incQ)`, respectively.
-"""
-mutable struct ProjectiveGluing{
- GluingType<:AbsGluing,
- IsoType1<:ProjectiveSchemeMor,
- IncType1<:ProjectiveSchemeMor,
- IsoType2<:ProjectiveSchemeMor,
- IncType2<:ProjectiveSchemeMor,
- } <: AbsProjectiveGluing{GluingType}
- G::GluingType # the underlying gluing of the base schemes
- inc_to_P::IncType1
- inc_to_Q::IncType2
- f::IsoType1
- g::IsoType2
-
- ###
- # Given two relative projective schemes and a gluing
- #
- # PX ↩ PU ≅ QV ↪ QY
- # π ↓ ↓ ↓ ↓ π
- # G : X ↩ U ≅ V ↪ Y
- #
- # this constructs the gluing of PX and QY along
- # their open subsets PU and QV, given the two inclusions
- # and isomorphisms over the gluing G in the base schemes.
- function ProjectiveGluing(
- G::GluingType,
- incP::IncType1, incQ::IncType2,
- f::IsoType1, g::IsoType2;
- check::Bool=true
- ) where {GluingType<:AbsGluing, IncType1<:ProjectiveSchemeMor,IncType2<:ProjectiveSchemeMor, IsoType1<:ProjectiveSchemeMor, IsoType2<:ProjectiveSchemeMor}
- (X, Y) = patches(G)
- (U, V) = gluing_domains(G)
- @vprint :Gluing 1 "computing projective gluing\n"
- @vprint :Gluing 2 "$(X), coordinates $(ambient_coordinates(X))\n"
- @vprint :Gluing 2 "and\n"
- @vprint :Gluing 2 "$(Y) coordinates $(ambient_coordinates(X))\n"
- (fb, gb) = gluing_morphisms(G)
- (PX, QY) = (codomain(incP), codomain(incQ))
- (PU, QV) = (domain(incP), domain(incQ))
- (base_scheme(PX) === X && base_scheme(QY) === Y) || error("base gluing is incompatible with the projective schemes")
- domain(f) === codomain(g) === PU && domain(g) === codomain(f) === QV || error("maps are not compatible")
- SPU = homogeneous_coordinate_ring(domain(f))
- SQV = homogeneous_coordinate_ring(codomain(f))
- @check begin
- # check the commutativity of the pullbacks
- all(y->(pullback(f)(SQV(OO(V)(y))) == SPU(pullback(fb)(OO(V)(y)))), gens(base_ring(OO(Y)))) || error("maps do not commute")
- all(x->(pullback(g)(SPU(OO(U)(x))) == SQV(pullback(gb)(OO(U)(x)))), gens(base_ring(OO(X)))) || error("maps do not commute")
- fc = map_on_affine_cones(f, check=false)
- gc = map_on_affine_cones(g, check=false)
- idCPU = compose(fc, gc)
- idCPU == identity_map(domain(fc)) || error("composition of maps is not the identity")
- idCQV = compose(gc, fc)
- idCQV == identity_map(domain(gc)) || error("composition of maps is not the identity")
- # idPU = compose(f, g)
- # all(t->(pullback(idPU)(t) == t), gens(SPU)) || error("composition of maps is not the identity")
- # idQV = compose(g, f)
- # all(t->(pullback(idQV)(t) == t), gens(SQV)) || error("composition of maps is not the identity")
- end
- @vprint :Gluing 1 "done computing the projective gluing\n"
- return new{GluingType, IsoType1, IncType1, IsoType2, IncType2}(G, incP, incQ, f, g)
- end
-end
-
-### Proper schemes π : Z → X over a covered base scheme X
-#
-# When {Uᵢ} is an affine covering of X, the datum stored
-# consists of a list of projective schemes
-#
-# Zᵢ ⊂ ℙʳ⁽ⁱ⁾(𝒪(Uᵢ)) → Uᵢ
-#
-# with varying ambient spaces ℙʳ⁽ⁱ⁾(𝒪(Uᵢ)) and a list of
-# identifications (transitions)
-#
-# Zᵢ ∩ π⁻¹(Uⱼ) ≅ Zⱼ ∩ π⁻¹(Uᵢ)
-#
-# of projective schemes over Uᵢ∩ Uⱼ for all pairs (i,j).
-#
-# These structs are designed to accommodate blowups of
-# covered schemes along arbitrary centers, as well as
-# projective bundles.
-
-@attributes mutable struct CoveredProjectiveScheme{BRT} <: Scheme{BRT}
- Y::AbsCoveredScheme # the base scheme
- BC::Covering # the reference covering of the base scheme
- patches::IdDict{AbsAffineScheme, AbsProjectiveScheme} # the projective spaces over the affine patches in the base covering
- gluings::IdDict{Tuple{AbsAffineScheme, AbsAffineScheme}, AbsProjectiveGluing} # the transitions sitting over the affine patches in the gluing domains of the base scheme
-
- function CoveredProjectiveScheme(
- Y::AbsCoveredScheme,
- C::Covering,
- projective_patches::IdDict{AbsAffineScheme, AbsProjectiveScheme},
- projective_gluings::IdDict{Tuple{AbsAffineScheme, AbsAffineScheme}, AbsProjectiveGluing};
- check::Bool=true
- )
- C in coverings(Y) || error("covering not listed")
- for P in values(projective_patches)
- any(x->x===base_scheme(P), patches(C)) || error("base scheme not found in covering")
- end
- for (U, V) in keys(gluings(C))
- (U, V) in keys(projective_gluings) || error("not all projective gluings were provided")
- end
- return new{base_ring_type(Y)}(Y, C, projective_patches, projective_gluings)
- end
-end
-
-
diff --git a/experimental/Schemes/src/elliptic_surface.jl b/experimental/Schemes/src/elliptic_surface.jl
deleted file mode 100644
index bb99e06b8639..000000000000
--- a/experimental/Schemes/src/elliptic_surface.jl
+++ /dev/null
@@ -1,2984 +0,0 @@
-export elliptic_surface, trivial_lattice, weierstrass_model, weierstrass_chart, algebraic_lattice, zero_section, section, weierstrass_contraction, fiber_components, generic_fiber, reducible_fibers, fibration_type, mordell_weil_lattice, elliptic_parameter, set_mordell_weil_basis!, EllipticSurface, weierstrass_chart_on_minimal_model, transform_to_weierstrass
-
-@doc raw"""
- EllipticSurface{BaseField<:Field, BaseCurveFieldType} <: AbsCoveredScheme{BaseField}
-
-The type of a relatively minimal elliptic surface.
-
-A genus $1$-fibration is a proper map
-$\pi \colon X \to C$ to a curve $C$ whose fibers are curves of
-(arithmetic) genus $1$.
-The fibration is relatively minimal if its fibers do not contain any ``(-1)``-curves.
-We call the fibration elliptic if it comes equipped with a section.
-This turns the generic fiber of $\pi$ into an elliptic curve $E/k(C)$ where
-$k(C)$ is the function field of the curve $C$.
-
-For now functionality is restricted to $C = \mathbb{P}^1$.
-"""
-@attributes mutable struct EllipticSurface{BaseField<:Field, BaseCurveFieldType} <: AbsCoveredSurface{BaseField}
- Y::CoveredScheme{BaseField} # the underlying_scheme
- E::EllipticCurve{BaseCurveFieldType}
- MWL::Vector{EllipticCurvePoint{BaseCurveFieldType}} # basis for the mordell weil group
- MWLtors::Vector{EllipticCurvePoint{BaseCurveFieldType}} # torsion sections
- Weierstrasschart::AbsAffineScheme
- Weierstrassmodel::CoveredScheme
- inc_Weierstrass::CoveredClosedEmbedding # inclusion of the weierstrass chart in its ambient projective bundle
- inc_Y::CoveredClosedEmbedding # inclusion of Y in its ambient blown up projective bundle
- euler_characteristic::Int
- resolution_strategy::Symbol
- # the following are temporary until we have a dedicated type for
- # iterated blow ups
- blowup::AbsCoveredSchemeMorphism
- blowups::Vector{<:AbsCoveredSchemeMorphism}
- # exceptionals not used for now
- ambient_blowups::Vector{<:BlowupMorphism}
- ambient_exceptionals::Vector{<:EffectiveCartierDivisor}
- fibration::AbsCoveredSchemeMorphism # the projection to IP^1
- fibration_weierstrass_model::AbsCoveredSchemeMorphism # the projection from the Weierstrass model
-
- function EllipticSurface(
- generic_fiber::EllipticCurve{F},
- euler_characteristic::Int,
- mwl_basis::Vector{<:EllipticCurvePoint};
- resolution_strategy::Symbol=:iterative
- ) where F
- B = typeof(coefficient_ring(base_ring(base_field(generic_fiber))))
- S = new{B,F}()
- S.E = generic_fiber
- S.MWL = mwl_basis
- S.euler_characteristic = euler_characteristic
- set_attribute!(S, :is_irreducible=>true)
- set_attribute!(S, :is_reduced=>true)
- set_attribute!(S, :is_integral=>true)
- set_attribute!(S, :is_equidimensional=>true)
- S.resolution_strategy = resolution_strategy
- return S
- end
-
-end
-
-base_ring(X::EllipticSurface) = coefficient_ring(base_ring(base_field(generic_fiber(X))))
-
-@doc raw"""
- set_mordell_weil_basis!(X::EllipticSurface, mwl_basis::Vector{EllipticCurvePoint})
-
-Set a basis for the Mordell-Weil lattice of ``X`` or at least of a sublattice.
-
-This invalidates previous computations depending on the generators of the
-Mordell Weil lattice such as the `algebraic_lattice`. Use with care.
-
-The points in `mwl_basis` must be linearly independent.
-"""
-function set_mordell_weil_basis!(X::EllipticSurface, mwl_basis::Vector{<:EllipticCurvePoint})
- @req all(parent(P) == generic_fiber(X) for P in mwl_basis) "points must lie on the generic fiber"
- X.MWL = mwl_basis
- # clear old computations
- if has_attribute(X, :algebraic_lattice)
- delete!(X.__attrs, :algebraic_lattice)
- end
- if has_attribute(X, :mordell_weil_lattice)
- delete!(X.__attrs, :mordell_weil_lattice)
- end
-end
-
-@doc raw"""
- elliptic_surface(generic_fiber::EllipticCurve,
- euler_characteristic::Int,
- mwl_gens::Vector{<:EllipticCurvePoint}=EllipticCurvePoint[];
- is_basis::Bool=true)
- -> EllipticSurface
-
-Return the relatively minimal elliptic surface with generic fiber ``E/k(t)``.
-
-This is also known as the Kodaira-Néron model of ``E``.
-
-Input:
-- `generic_fiber` -- an elliptic curve over a function field
-- `euler_characteristic` -- the Euler characteristic of the Kodaira-Néron model of ``E``.
-- `mwl_gens` -- a vector of rational points of the generic fiber
-- `is_basis` -- if set to `false` compute an LLL-reduced basis from `mwl_gens`
-
-
-# Examples
-```jldoctest
-julia> Qt, t = polynomial_ring(QQ, :t);
-
-julia> Qtf = fraction_field(Qt);
-
-julia> E = elliptic_curve(Qtf, [0,0,0,0,t^5*(t-1)^2]);
-
-julia> X3 = elliptic_surface(E, 2)
-Elliptic surface
- over rational field
-with generic fiber
- -x^3 + y^2 - t^7 + 2*t^6 - t^5
-
-```
-"""
-function elliptic_surface(generic_fiber::EllipticCurve{BaseField},
- euler_characteristic::Int,
- mwl_gens::Vector{<:EllipticCurvePoint}=EllipticCurvePoint[];
- resolution_strategy::Symbol=:iterative,
- is_basis::Bool=true) where {
- BaseField <: FracFieldElem{<:PolyRingElem{<:FieldElem}}}
- @req all(parent(i)==generic_fiber for i in mwl_gens) "not a vector of points on $(generic_fiber)"
- S = EllipticSurface(generic_fiber, euler_characteristic, mwl_gens; resolution_strategy)
- if is_basis
- return S
- end
- update_mwl_basis!(S, mwl_gens)
- return S
-end
-
-@doc raw"""
- update_mwl_basis!(S::EllipticSurface, mwl_gens::Vector{<:EllipticCurvePoint})
-
-Compute a reduced basis of the sublattice of the Mordell-Weil lattice spanned
-by `mwl_gens` and set these as the new generators of the Mordell-Weil lattice of
-`S`.
-"""
-function update_mwl_basis!(S::EllipticSurface, mwl_gens::Vector{<:EllipticCurvePoint})
- mwl, mwl_basis = _compute_mwl_basis(S, mwl_gens)
- set_mordell_weil_basis!(S, mwl_basis)
-end
-
-@doc raw"""
- algebraic_lattice_primitive_closure(S::EllipticSurface, p) -> Vector{<:EllipticCurvePoint}
-
-Return sections ``P_1,\dots P_n`` of the generic fiber, such that together with
-the generators of the algebraic lattice ``A``, they generate
-``(1/p A \cap N)`` where ``N`` is the numerical lattice of ``S``.
-
-This proceeds by computing division points in the Mordell-Weil group
-and using information coming from the discriminant group of the algebraic lattice
-to do so.
-"""
-algebraic_lattice_primitive_closure(S::EllipticSurface, p) = algebraic_lattice_primitive_closure(S, ZZ(p))
-
-function algebraic_lattice_primitive_closure(S::EllipticSurface, p::ZZRingElem)
- L = algebraic_lattice(S)[3]
- @req is_even(L) "not implemented"
- Ld = intersect(dual(L) , (1//p * L))
- D = torsion_quadratic_module(Ld, L, modulus = 1, modulus_qf=2)
- candidates = [x for x in D if !iszero(x) && iszero(quadratic_product(x))]
- t = length(trivial_lattice(S)[1])
- r = rank(L)
- cc = [(x->mod(x,p)).(p*lift(c)[t+1:end]) for c in candidates]
- unique!(cc)
- cc = [c for c in cc if !iszero(c)]
- pts = [division_points(sum(v[i]*S.MWL[i] for i in 1:(r-t)),p) for v in cc]
- return [i[1] for i in pts if length(i)>0]
-end
-
-function algebraic_lattice_primitive_closure!(S::EllipticSurface, prime)
- pts = algebraic_lattice_primitive_closure(S, prime)
- update_mwl_basis!(S, vcat(pts, S.MWL))
- return pts
-end
-
-@doc raw"""
- algebraic_lattice_primitive_closure!(S::EllipticSurface)
-
-Compute the primitive closure of the algebraic lattice of `S` inside its
-numerical lattice and update the generators of its Mordell--Weil group accordingly.
-
-The algorithm works by computing suitable divison points in its Mordell Weil group.
-"""
-function algebraic_lattice_primitive_closure!(S::EllipticSurface)
- L = algebraic_lattice(S)[3]
- for p in prime_divisors(ZZ(det(L)))
- while true
- pts = algebraic_lattice_primitive_closure!(S, p)
- if length(pts)==0
- break
- end
- end
- end
- return S
-end
-
-kodaira_neron_model(E::EllipticCurve) = elliptic_surface(E)
-
-function underlying_scheme(S::EllipticSurface)
- if isdefined(S,:Y)
- return S.Y
- end
- # trigger the computation
- weierstrass_contraction(S)
- return underlying_scheme(S)
-end
-
-@doc raw"""
- generic_fiber(S::EllipticSurface) -> EllipticCurve
-
-Return the generic fiber as an elliptic curve.
-"""
-generic_fiber(S::EllipticSurface) = S.E
-
-@doc raw"""
- weierstrass_chart(X::EllipticSurface)
-
-Return the Weierstrass chart of ``X`` on its `weierstrass_model`.
-"""
-weierstrass_chart(X::EllipticSurface) = weierstrass_model(X)[1][1][1]
-
-@doc raw"""
- weierstrass_chart_on_minimal_model(X::EllipticSurface)
-
-Return an affine chart ``U`` of ``X`` which is isomorphic to the `weierstrass_chart`
-of ``X`` on its `weierstrass_model`, but with all singular fibers removed.
-
-More precisely, the affine coordinates of ``U`` are ``(x,y,t)`` and the chart is
-constructed as the vanishing locus of
-``y^2 + a_1(t) xy + a_3 y = x^3 + a_2 x^2 + a_4 x + a_6``
-minus the reducible singular fibers.
-"""
-weierstrass_chart_on_minimal_model(X::EllipticSurface) = X[1][1]
-
-@doc raw"""
- euler_characteristic(X::EllipticSurface) -> Int
-
-Return $\chi(\mathcal{O}_X)$.
-"""
-euler_characteristic(X::EllipticSurface) = X.euler_characteristic
-
-@doc raw"""
- algebraic_lattice(X) -> Vector{WeilDivisor}, ZZLat
-
-Return the sublattice `L` of ``Num(X)`` spanned by fiber components,
-torsion sections and the sections provided at the construction of ``X``.
-
-The first return value is the basis of the ambient space of `L`.
-The second consists of additional generators for `L` coming from torsion sections.
-The third is ``L``.
-"""
-@attr Any function algebraic_lattice(X::EllipticSurface)
- return _algebraic_lattice(X,X.MWL)
-end
-
-function _algebraic_lattice(X::EllipticSurface, mwl_basis::Vector{<:EllipticCurvePoint})
- basisTriv, GTriv = trivial_lattice(X)
- r = length(basisTriv)
- l = length(mwl_basis)
- sections = [section(X, i) for i in mwl_basis]
- n = l+r
- GA = zero_matrix(ZZ, n, n)
- GA[1:r,1:r] = GTriv
- GA[r+1:n,r+1:n] = -euler_characteristic(X)*identity_matrix(ZZ, l)
- basisA = vcat(basisTriv, sections)
- @vprint :EllipticSurface 2 "computing intersection numbers\n"
- for i in 1:n
- @vprint :EllipticSurface 3 "\nrow $(i): \n"
- for j in max(i + 1, r + 1):n
- if i!=2 && i <= r
- I = components(basisA[i])[1]
- J = components(basisA[j])[1]
- if isone(I+J)
- ij = 0
- else
- ij = 1
- end
- else
- @vprint :EllipticSurface 4 "$(j) "
- ij = intersect(basisA[i],basisA[j])
- end
- GA[i,j] = ij
- GA[j,i] = GA[i,j]
- end
- end
- GA_QQ = change_base_ring(QQ,GA)
- # primitive closure of the trivial lattice comes from torsion sections
- tors = [section(X, h) for h in mordell_weil_torsion(X)]
- torsV = QQMatrix[]
- for T in tors
- @vprint :EllipticSurface 2 "computing basis representation of torsion point $(T)\n"
- vT = zero_matrix(QQ, 1, n)
- for i in 1:r
- if i== 2
- vT[1,i] = intersect(basisA[i], T)
- else
- @assert length(components(basisTriv[i])) == 1
- I = sum(components(basisA[i]))
- J = components(T)[1]
- if !isone(I+J)
- @assert i!=2 # O does not meet any torsion section
- vT[1,i] = 1
- end
- end
- end
- for i in r+1:n
- vT[1,i] = intersect(T,basisA[i])
- end
- push!(torsV, solve(GA_QQ, vT; side=:left))
- end
- gen_tors = zip(tors, torsV)
- push!(torsV, identity_matrix(QQ,n))
- V = quadratic_space(QQ,GA)
- L = lattice(V, reduce(vcat,torsV), isbasis=false)
- return basisA, collect(gen_tors), L
-end
-
-@doc raw"""
- mordell_weil_lattice(S::EllipticSurface) -> Vector{EllipticCurvePoint}, ZZLat
-
-Return the (sublattice) of the Mordell-Weil lattice of ``S`` spanned
-by the sections of ``S`` supplied at its construction.
-
-The Mordell Weil-Lattice is represented in the same vector space as the
-algebraic lattice (with quadratic form rescaled by ``-1``).
-"""
-@attr ZZLat function mordell_weil_lattice(S::EllipticSurface)
- NS = algebraic_lattice(S)[3]
- t = length(trivial_lattice(S)[1])
- trivNS = basis_matrix(NS)[1:t,:]
- R = basis_matrix(NS)[t+1:end,:]
- V = ambient_space(NS)
- P = orthogonal_projection(V, trivNS)
- mwl = rescale(lattice(V,R*P.matrix),-1)
- return mwl
-end
-
-@doc raw"""
- mordell_weil_torsion(S::EllipticSurface) -> Vector{EllipticCurvePoint}
-
-Return the torsion part of the Mordell-Weil group of the generic fiber of ``S``.
-"""
-@attr Any function mordell_weil_torsion(S::EllipticSurface)
- E = generic_fiber(S)
- O = E([0,1,0])
- N = trivial_lattice(S)[2]
- tors = EllipticCurvePoint[]
- d = det(N)
- for p in prime_divisors(d)
- if valuation(d, p) == 1
- continue
- end
- r = 1
- i = 0
- dp = typeof(O)[]
- while true
- i = i+1
- @vprint :EllipticSurface 2 "computing $(p^i)-torsion"
- dp = division_points(O, p^i)
- if length(dp) == r
- break
- end
- r = length(dp)
- end
- for pt in dp
- if pt != O
- push!(tors, pt)
- end
- end
- end
- return tors
-end
-
-function Base.show(io::IO, S::EllipticSurface)
- io = pretty(io)
- if is_terse(io)
- print(io, "Elliptic surface")
- else
- E = generic_fiber(S)
- print(io, "Elliptic surface with generic fiber ", equation(E))
- end
-end
-
-function Base.show(io::IO, ::MIME"text/plain", S::EllipticSurface)
- io = pretty(io)
- println(io, "Elliptic surface")
- println(io, Indent(), "over ", Lowercase(), base_ring(S))
- println(io, Dedent(), "with generic fiber")
- print(io, Indent(), Lowercase(), equation(generic_fiber(S)), Dedent())
- if isdefined(S, :Y)
- println(io)
- println(io, "and relatively minimal model")
- print(io, Indent(), Lowercase(), S.Y, Dedent())
- end
- print(io, Dedent())
-end
-
-@doc raw"""
- weierstrass_model(X::EllipticSurface) -> CoveredScheme, CoveredClosedEmbedding
-
-Return the Weierstrass model ``S`` of ``X`` and the inclusion in
-its ambient projective bundle
-$$S\subseteq \mathbb{P}( \mathcal{O}_{\mathbb{P}^1}(-2s) \oplus \mathcal{O}_{\mathbb{P}^1}(-3s) \oplus \mathcal{O}_{\mathbb{P}^1}).$$
-"""
-function weierstrass_model(X::EllipticSurface)
- if isdefined(X, :Weierstrassmodel)
- return X.Weierstrassmodel, X.inc_Weierstrass
- end
-
- s = euler_characteristic(X)
- E = generic_fiber(X)
-
- kt = base_ring(base_field(E))
- k = coefficient_ring(kt)
-
- IP1 = projective_space(k, 1)
- c = standard_covering(IP1)
- # rename the variables on the affine charts
- # to a more readable version
- if k isa FqField
- OO(c[1]).data.S = [:t]
- OO(c[2]).data.S = [:s]
- else
- OO(c[1]).S = [:t]
- OO(c[2]).S = [:s]
- end
-
- O0 = twisting_sheaf(IP1, 0)
- O4 = twisting_sheaf(IP1, -2*s)
- O6 = twisting_sheaf(IP1, -3*s)
-
- bundleE = direct_sum([O0, O4, O6])
-
- P_proj = projectivization(bundleE, var_names=[:z, :x, :y])
- P = covered_scheme(P_proj)
- pr = covered_projection_to_base(P_proj)
- @assert has_decomposition_info(default_covering(P))
-
- # Create the singular Weierstrass model S of the elliptic K3 surface X
- a = a_invariants(E)
- U = affine_charts(P)[1] # the standard Weierstrass chart
- (x, y, t) = gens(OO(U))
- @assert all(denominator(i)==1 for i in a)
- a = [numerator(a)(t) for a in a]
- (a1,a2,a3,a4,a6) = a
- ft = y^2 + a1*x*y + a3*y - (x^3 + a2*x^2 + a4*x+a6)
- I = IdealSheaf(P, U, [ft]; check=false)
-
- inc_S = CoveredClosedEmbedding(P, I)
- Scov = domain(inc_S) # The ADE singular elliptic K3 surface
- X.Weierstrasschart = Scov[1][1]
- X.fibration_weierstrass_model = compose(inc_S, pr)
-
- X.Weierstrassmodel = Scov
- X.inc_Weierstrass = inc_S
-
- set_attribute!(Scov, :is_irreducible=>true)
- set_attribute!(Scov, :is_reduced=>true)
- set_attribute!(Scov, :is_integral=>true)
- set_attribute!(Scov, :is_equidimensional=>true)
- return Scov, inc_S
-end
-
-@doc raw"""
- _separate_singularities!(X::EllipticSurface) -> Covering
-
-Create a covering of the ambient projective bundle $P$
-of the Weierstrass model $S$ of $X$ such that each chart
-(of $X$) contains at most one singular point of $S$.
-Append this covering to the list of coverings of $X$ and return it.
-"""
-function _separate_singularities!(X::EllipticSurface)
- S, inc_S = weierstrass_model(X)
- P = codomain(inc_S)
-
- I_sing = ideal_sheaf_of_singular_locus(S)
- I_sing_P = SimplifiedIdealSheaf(pushforward(inc_S)(I_sing))
-
- # Refine the covering over the reducible singular fibers
- # to make sure that there is only a single singular point in each chart
- refined_charts = AbsAffineScheme[]
- U = P[1][1] # the weierstrass_chart
- IsingU = I_sing_P(U)::MPolyIdeal
- if isone(IsingU)
- # we want one smooth weierstrass chart
- push!(refined_charts, U)
- set_attribute!(U, :is_smooth => true)
- else
- # there is at most one singularity in every fiber
- # project the singular locus to an affine chart of P1
- disc = gens(eliminate(IsingU, coordinates(U)[1:2]))[1]
- # The t-coordinates of the reducible fibers
- redfib = [f[1] for f in factor(disc)]
- # One chart with all reducible fibers taken out
- UU = PrincipalOpenSubset(U, redfib)
- set_attribute!(UU, :is_smooth => true)
- push!(refined_charts, UU)
- if length(redfib)==1
- # We need to recreate U as a PrincipalOpenSubset of itself here
- # in order to maintain the correct tree-structure for refinements.
- # In any Covering no patch is allowed to be an ancestor of another.
- push!(refined_charts, PrincipalOpenSubset(U, one(OO(U))))
- else
- for i in 1:length(redfib)
- # We take out all but the i-th singular fiber
- r = copy(redfib)
- g = r[i]
- deleteat!(r, i)
- Uref = PrincipalOpenSubset(U, r)
- push!(refined_charts, Uref)
- end
- end
- end
-
- # Create a chart which contains the fiber over s=0
- # and no other reducible singular fibers
- # these are visible in the charts that we have already
- # i.e. we add the fiber at s=0 and remove all other singular fibers
- V = P[1][4]
- IsingV = I_sing_P(V)
- if isone(IsingV)
- push!(refined_charts, V)
- else
- # reducible singular fibers
- disc = gens(eliminate(IsingV, coordinates(V)[1:2]))[1]
- (x,y,s) = coordinates(V)
- b, d = divides(disc, s)
- if b
- disc = d
- end
- redfib = [f[1] for f in factor(disc)]
- if length(redfib)> 0
- push!(refined_charts, PrincipalOpenSubset(V, redfib))
- else
- push!(refined_charts, V)
- end
- end
-
- # no extra singularities in the X = 1 chart
- # therefore we just exclude all the singularities visible here
- for W in [P[1][2],P[1][5]]
- Ising = I_sing_P(W)
- if isone(Ising)
- push!(refined_charts, W)
- continue
- end
- (z,y,s_or_t) = coordinates(W)
- # reducible singular fibers
- local disc = gens(eliminate(Ising, [z, s_or_t]))[1]
- local redfib = [p for (p,e) in factor(disc)]
- push!(refined_charts, PrincipalOpenSubset(W, redfib))
- end
-
- # no extra singularities on the the zero section
- # This is the Y = 1 chart
- # therefore we just exclude all the singularities visible here
- for W in [P[1][3],P[1][6]]
- local Ising = I_sing_P(W)
- if isone(Ising)
- push!(refined_charts, W)
- continue
- end
- local (z,x,s_or_t) = coordinates(W)
- # reducible singular fibers
- local disc = gens(eliminate(Ising, [x, s_or_t]))[1]
- local redfib = [p for (p,e) in factor(disc)]
- push!(refined_charts, PrincipalOpenSubset(W, redfib))
- end
-
-
- Cref = Covering(refined_charts)
- inherit_gluings!(Cref, P[1])
- push!(P.coverings, Cref)
- @assert has_decomposition_info(default_covering(P))
- inherit_decomposition_info!(P, Cref)
- @assert has_decomposition_info(Cref)
- # Now we have an extra covering where each chart just contains a single singularity
-
- @assert scheme(I_sing) === S
- @assert scheme(I_sing_P) === P
- return Cref
-end
-
-@doc raw"""
- weierstrass_contraction(X::EllipticSurface) -> SchemeMor
-
-Return the contraction morphism of ``X`` to its Weierstrass model.
-
-This triggers the computation of the `underlying_scheme` of ``X``
-as a blowup from its Weierstrass model. It may take a few minutes.
-"""
-function weierstrass_contraction(X::EllipticSurface)
- algorithm = X.resolution_strategy
- if algorithm == :iterative
- return weierstrass_contraction_iterative(X)
- elseif algorithm == :simultaneous
- return weierstrass_contraction_simultaneous(X)
- else
- error("algorithm not recognized")
- end
-end
-
-function weierstrass_contraction_simultaneous(Y::EllipticSurface)
- if isdefined(Y, :blowup)
- return Y.blowup
- end
- S, inc_S = weierstrass_model(Y)
- @assert has_attribute(S, :is_equidimensional) && get_attribute(S, :is_equidimensional) === true
-
- X0 = codomain(inc_S)
- Y0 = S
- set_attribute!(Y0, :is_reduced=>true)
- set_attribute!(Y0, :is_irreducible=>true)
- set_attribute!(Y0, :is_equidimensional=>true)
- inc_Y0 = inc_S
- I_sing_Y0 = AbsIdealSheaf[ideal_sheaf_of_singular_locus(Y0)]
- #I_sing_Y0 = AbsIdealSheaf[simplify(ideal_sheaf_of_singular_locus(Y0))]
- I_sing_X0 = simplify.(pushforward(inc_Y0).(I_sing_Y0))
-
- # Prepare a covering which has a permanent weierstrass chart
- U0 = X0[1][1]
- disc = numerator(discriminant(generic_fiber(Y)))
- U = PrincipalOpenSubset(U0, evaluate(disc, gens(OO(U0))[3]))
- _find_chart(U, default_covering(X0))
- Cref = Covering(vcat([U], affine_charts(X0)))
- inherit_gluings!(Cref, X0[1])
- push!(X0.coverings, Cref)
- @assert has_decomposition_info(default_covering(X0))
- inherit_decomposition_info!(X0, Cref)
- @assert has_decomposition_info(Cref)
-
- ambient_exceptionals = EffectiveCartierDivisor[]
- varnames = [:a,:b,:c,:d,:e,:f,:g,:h,:i,:j,:k,:l,:m,:n,:o,:p,:q,:r,:u,:v,:w]
- projectionsX = BlowupMorphism[]
- projectionsY = AbsCoveredSchemeMorphism[]
- count = 0
-
- @vprint :EllipticSurface 2 "Blowing up Weierstrass model simultaneously in all singular points\n"
- while true
- count = count+1
- @vprint :EllipticSurface 1 "blowup number: $(count)\n"
- @vprint :EllipticSurface 1 "number of ideal sheaves to be blown up: $(length(I_sing_X0))\n"
- if length(I_sing_X0)==0
- # stop if smooth
- break
- end
- # make sure we have a Weierstrass chart kept.
- if count == 1
- cov = Cref
- else
- cov = simplified_covering(X0)
- end
- # take the first ideal sheaf and blow it up
- J = SimplifiedIdealSheaf(I_sing_X0[1])
- pr_X1 = blow_up(J, covering=cov, var_name=varnames[1+mod(count, length(varnames))])
-
- X1 = domain(pr_X1)
- @vprint :EllipticSurface 1 "$(X1)\n"
- E1 = exceptional_divisor(pr_X1)
-
- @vprint :EllipticSurface 2 "computing strict transforms\n"
- # compute the exceptional divisors
- ambient_exceptionals = EffectiveCartierDivisor[strict_transform(pr_X1, e) for e in ambient_exceptionals]
- # move the divisors coming originally from S up to the next chart
- push!(ambient_exceptionals, E1)
-
- Y1, inc_Y1, pr_Y1 = strict_transform(pr_X1, inc_Y0)
- # Speed up the computation of singular loci
- set_attribute!(Y1, :is_irreducible=> true)
- set_attribute!(Y1, :is_reduced=>true)
- set_attribute!(Y1, :is_integral=>true)
- set_attribute!(Y1, :is_equidimensional=>true)
-
- # transform the singular loci
- I_sing_X0 = AbsIdealSheaf[pullback(pr_X1, J) for J in I_sing_X0[2:end]]
-
- # Add eventual new components
- @vprint :EllipticSurface 2 "computing singular locus\n"
- I_sing_new = ideal_sheaf_of_singular_locus(Y1; focus=pullback(inc_Y1, ideal_sheaf(E1)))
- #I_sing_new = pushforward(inc_Y1, I_sing_new) + ideal_sheaf(E1) # new components only along the exc. set
- I_sing_new = simplify(pushforward(inc_Y1, I_sing_new))
-
- @vprint :EllipticSurface 2 "decomposing singular locus\n"
- !is_one(I_sing_new) && push!(I_sing_X0, I_sing_new)
-
- push!(projectionsX, pr_X1)
- push!(projectionsY, pr_Y1)
- simplify!(Y1)
-
- # set up for the next iteration
- Y0 = Y1
- inc_Y0 = inc_Y1
- X0 = X1
- # Speed up the computation of singular loci
- set_attribute!(Y0, :is_irreducible=> true)
- set_attribute!(Y0, :is_reduced=>true)
- set_attribute!(Y0, :is_integral=>true)
- set_attribute!(Y0, :is_equidimensional=>true)
- set_attribute!(X0, :is_irreducible=> true)
- set_attribute!(X0, :is_reduced=>true)
- set_attribute!(X0, :is_integral=>true)
- end
- Y.Y = Y0
- Y.blowups = projectionsY
-
- # We need to rewrap the last maps so that the domain is really Y
- last_pr = pop!(projectionsY)
- last_pr_wrap = CoveredSchemeMorphism(Y, codomain(last_pr), covering_morphism(last_pr))
-
- push!(projectionsY, last_pr_wrap)
- Y.ambient_blowups = projectionsX
-
- Y.ambient_exceptionals = ambient_exceptionals
- piY = CompositeCoveredSchemeMorphism(reverse(projectionsY))
- Y.blowup = piY
-
- inc_Y0_wrap = CoveredClosedEmbedding(Y, codomain(inc_Y0), covering_morphism(inc_Y0), check=false)
- Y.inc_Y = inc_Y0_wrap
-
- set_attribute!(Y, :is_irreducible=> true)
- set_attribute!(Y, :is_reduced=>true)
- set_attribute!(Y, :is_integral=>true)
- return piY
-end
-
-
-function weierstrass_contraction_iterative(Y::EllipticSurface)
- if isdefined(Y, :blowup)
- return Y.blowup
- end
- S, inc_S = weierstrass_model(Y)
- @assert has_attribute(S, :is_equidimensional) && get_attribute(S, :is_equidimensional) === true
- Crefined = _separate_singularities!(Y)
- # Blow up singular points (one at a time) until smooth
- # and compute the strict transforms of the `divisors`
- # collect the exceptional divisors
- # blowup ambient spaces: X0 → X ⊂
- # blowup pi: Y → (S singular weierstrass model)
- #
- # initialization for the while loop
- X0 = codomain(inc_S)
- Y0 = S
- set_attribute!(Y0, :is_reduced=>true)
- set_attribute!(Y0, :is_irreducible=>true)
- set_attribute!(Y0, :is_equidimensional=>true)
- inc_Y0 = inc_S
- I_sing_Y0 = maximal_associated_points(ideal_sheaf_of_singular_locus(Y0))::Vector{<:AbsIdealSheaf}
- I_sing_X0 = pushforward(inc_Y0).(I_sing_Y0)
-
-
- ambient_exceptionals = EffectiveCartierDivisor[]
- varnames = [:a,:b,:c,:d,:e,:f,:g,:h,:i,:j,:k,:l,:m,:n,:o,:p,:q,:r,:u,:v,:w]
- projectionsX = BlowupMorphism[]
- projectionsY = AbsCoveredSchemeMorphism[]
- count = 0
-
- @vprint :EllipticSurface 2 "Blowing up Weierstrass model\n"
- @vprint :EllipticSurface 2 "in $(Crefined)\n"
- while true
- count = count+1
- @vprint :EllipticSurface 1 "blowup number: $(count)\n"
- @vprint :EllipticSurface 1 "number of singular points: $(length(I_sing_X0))\n"
- if length(I_sing_X0)==0
- # stop if smooth
- break
- end
- # make sure there is only one singular point per chart
- if count == 1
- cov = Crefined
- else
- # the following leads to difficult bugs
- cov = simplified_covering(X0)
- end
- # take the first singular point and blow it up
- J = SimplifiedIdealSheaf(I_sing_X0[1])
- pr_X1 = blow_up(J, covering=cov, var_name=varnames[1+mod(count, length(varnames))])
-
- # Set the attribute so that the strict_transform does some extra work
- #isomorphism_on_open_subset(pr_X1)
-
- X1 = domain(pr_X1)
- @vprint :EllipticSurface 1 "$(X1)\n"
- E1 = exceptional_divisor(pr_X1)
-
- @vprint :EllipticSurface 2 "computing strict transforms\n"
- # compute the exceptional divisors
- ambient_exceptionals = EffectiveCartierDivisor[strict_transform(pr_X1, e) for e in ambient_exceptionals]
- # move the divisors coming originally from S up to the next chart
- push!(ambient_exceptionals, E1)
-
- Y1, inc_Y1, pr_Y1 = strict_transform(pr_X1, inc_Y0)
- # Speed up the computation of singular loci
- set_attribute!(Y1, :is_irreducible=> true)
- set_attribute!(Y1, :is_reduced=>true)
- set_attribute!(Y1, :is_integral=>true)
- set_attribute!(Y1, :is_equidimensional=>true)
-
- # transform the singular loci
- I_sing_X0 = AbsIdealSheaf[pullback(pr_X1, J) for J in I_sing_X0[2:end]]
-
- # Add eventual new components
- @vprint :EllipticSurface 2 "computing singular locus\n"
- I_sing_new = ideal_sheaf_of_singular_locus(Y1; focus=pullback(inc_Y1, ideal_sheaf(E1)))
- #I_sing_new = pushforward(inc_Y1, I_sing_new) + ideal_sheaf(E1) # new components only along the exc. set
- I_sing_new = pushforward(inc_Y1, I_sing_new)
-
- @vprint :EllipticSurface 2 "decomposing singular locus\n"
- I_sing_X0 = vcat(I_sing_X0, maximal_associated_points(I_sing_new))
-
- push!(projectionsX, pr_X1)
- push!(projectionsY, pr_Y1)
- simplify!(Y1)
-
- # set up for the next iteration
- Y0 = Y1
- inc_Y0 = inc_Y1
- X0 = X1
- # Speed up the computation of singular loci
- set_attribute!(Y0, :is_irreducible=> true)
- set_attribute!(Y0, :is_reduced=>true)
- set_attribute!(Y0, :is_integral=>true)
- set_attribute!(Y0, :is_equidimensional=>true)
- set_attribute!(X0, :is_irreducible=> true)
- set_attribute!(X0, :is_reduced=>true)
- set_attribute!(X0, :is_integral=>true)
- end
- Y.Y = Y0
- Y.blowups = projectionsY
-
- # We need to rewrap the last maps so that the domain is really Y
- last_pr = pop!(projectionsY)
- last_pr_wrap = CoveredSchemeMorphism(Y, codomain(last_pr), covering_morphism(last_pr))
- #set_attribute!(last_pr_wrap, :isomorphism_on_open_subset, get_attribute(last_pr, :isomorphism_on_open_subset))
-
- push!(projectionsY, last_pr_wrap)
- Y.ambient_blowups = projectionsX
-
- Y.ambient_exceptionals = ambient_exceptionals
- piY = CompositeCoveredSchemeMorphism(reverse(projectionsY))
- Y.blowup = piY
-
- inc_Y0_wrap = CoveredClosedEmbedding(Y, codomain(inc_Y0), covering_morphism(inc_Y0), check=false)
- Y.inc_Y = inc_Y0_wrap
-
- set_attribute!(Y, :is_irreducible=> true)
- set_attribute!(Y, :is_reduced=>true)
- set_attribute!(Y, :is_integral=>true)
- return piY
-end
-
-function _reducible_fibers_disc(X::EllipticSurface; sort::Bool=true)
- E = generic_fiber(X)
- j = j_invariant(E)
- d = numerator(discriminant(E))
- kt = parent(d)
- k = coefficient_ring(kt)
- sing = Vector{elem_type(k)}[]
- for (p,v) in factor(d)
- if v == 1
- continue
- end
- r = k.(roots(p))
- if length(r) == 0
- error("not all reducible fibers are visible over $(base_ring(S))")
- end
- @assert length(r) ==1
- rt = r[1]
- if v == 2
- # not a type II fiber
- if j!=0
- push!(sing, [rt,k(1)])
- end
- end
- if v > 2
- push!(sing, [rt,k(1)])
- end
- end
- if sort
- sort!(sing, by=x->by_total_order(x[1]))
- end
- # fiber over infinity is always last (if it is there)
- if degree(d) <= 12*euler_characteristic(X) - 2
- push!(sing, k.([1, 0]))
- end
- return sing
-end
-
-function by_total_order(x::FqFieldElem)
- return [lift(ZZ, i) for i in absolute_coordinates(x)]
-end
-
-by_total_order(x::QQFieldElem) = x
-
-function by_total_order(x::NumFieldElem)
- return absolute_coordinates(x)
-end
-
-# global divisors0 = [strict_transform(pr_X1, e) for e in divisors0]
-# exceptionals_res = [pullback(inc_Y0)(e) for e in exceptionals]
-@doc raw"""
- _trivial_lattice(S::EllipticSurface; reducible_singular_fibers_in_PP1=_reducible_fibers_disc(S))
-
-Internal function. Returns a list consisting of:
-- basis of the trivial lattice
-- gram matrix
-- fiber_components without multiplicities
-
-The keyword argument `reducible_singular_fibers_in_PP1` must be a list of vectors of length `2` over
-the base field representing the points in projective space over which there are reducible fibers.
-Specify it to force this ordering of the basis vectors of the ambient space of the `algebraic_lattice`
-"""
-function _trivial_lattice(S::EllipticSurface; reducible_singular_fibers_in_PP1=_reducible_fibers_disc(S))
- get_attribute!(S, :_trivial_lattice) do
- O = zero_section(S)
- pt0, F = fiber(S)
- set_attribute!(components(O)[1], :_self_intersection, -euler_characteristic(S))
- basisT = [F, O]
- grams = [ZZ[0 1;1 -euler_characteristic(S)]]
- sing = reducible_singular_fibers_in_PP1
- f = [[pt, fiber_components(S,pt)] for pt in sing]
- fiber_componentsS = []
- for (pt, ft) in f
- @vprint :EllipticSurface 2 "normalizing fiber: over $pt \n"
- Ft0 = standardize_fiber(S, ft)
- @vprint :EllipticSurface 2 "$(Ft0[1]) \n"
- append!(basisT , Ft0[3][2:end])
- push!(grams,Ft0[4][2:end,2:end])
- push!(fiber_componentsS, vcat([pt], collect(Ft0)))
- end
- G = block_diagonal_matrix(grams)
- # make way for some more pretty printing
- for (pt,root_type,_,comp) in fiber_componentsS
- for (i,I) in enumerate(comp)
- name = string(root_type[1], root_type[2])
- set_attribute!(components(I)[1], :name, string("Component ", name, "_", i-1," of fiber over ", Tuple(pt)))
- set_attribute!(components(I)[1], :_self_intersection, -2)
- end
- end
- return basisT, G, fiber_componentsS
- end
-end
-
-@doc raw"""
- trivial_lattice(X::EllipticSurface) -> Vector{WeilDivisor}, ZZMatrix
-
-Return a basis for the trivial lattice as well as its gram matrix.
-
-The trivial lattice is the lattice spanned by fiber components and
-the zero section of $X$.
-"""
-function trivial_lattice(X::EllipticSurface)
- T = _trivial_lattice(X)[1:2]
- return T
-end
-
-@doc raw"""
- reducible_fibers(S::EllipticSurface)
-
-Return the reducible fibers of $S$.
-
-The output format is the following:
-A list [F1, ..., Fn] where each entry Fi represents a reducible fiber.
-
-The list $F$ has the following entries:
-- A point $P \in \mathbb{P}^{1}$ such that $F = \pi^{-1}(P)$;
-- The ADE-type of the fiber;
-- The fiber $F$ as a Weil divisor, including its multiplicities;
-- The irreducible components of the fiber. The first component intersects the zero section;
-- Their intersection matrix.
-"""
-function reducible_fibers(S::EllipticSurface)
- return _trivial_lattice(S)[3]
-end
-
-
-@doc raw"""
- standardize_fiber(S::EllipticSurface, f::Vector{<:WeilDivisor})
-
-Internal method. Used to prepare for [`reducible_fibers`](@ref).
-`f` must be the list of the components of the reducible fiber `F`.
-Output a list of tuples with each tuple as follows
-- the root type of ``F``, e.g. `(:A, 3)`
-- the class of ``F`` as a divisor with the appropriate multiplicities
-- the irreducible components `[F0,...Fn]` of `F` sorted such that the first entry `F0` is the one intersecting the zero section. The others are sorted in some standard way
-- gram matrix of the intersection of [F0,...,Fn], it is an extended ADE-lattice.
-"""
-function standardize_fiber(S::EllipticSurface, f::Vector{<:WeilDivisor})
- @hassert :EllipticSurface 2 all(is_prime(i) for i in f)
- f = copy(f)
- O = components(zero_section(S))[1]
- local f0
- for (i,D) in enumerate(f)
- if !isone(O+components(D)[1])
- f0 = D
- deleteat!(f,i)
- break
- end
- end
- r = length(f)
- G = -2*identity_matrix(ZZ, r)
- @vprintln :EllipticSurface 2 "computing intersections:"
- for i in 1:r
- @vprint :EllipticSurface 3 "\nrow $(i): \n"
- for j in 1:i-1
- @vprint :EllipticSurface 4 "$(j) "
- # we know the intersections are 0 or 1, so we can replace the line below by a shortcut.
- # G[i, j] = G[j, i] = intersect(f[i], f[j])
- # In the examples treated, this led to roughly a factor 3 in speed and memory consumption.
- if isone(components(f[i])[1]+components(f[j])[1])
- G[i,j] = 0
- else
- G[i,j] = 1
- end
- G[j,i] = G[i,j]
- end
- end
- L = integer_lattice(gram=G)
- rt,_ = root_lattice_recognition(L)
- @assert length(rt)==1
- rt = rt[1]
- R = root_lattice(rt[1], rt[2])
- b, I = _is_equal_up_to_permutation_with_permutation(G, -gram_matrix(R))
- @assert b
- gensF = vcat([f0], f[I])
- Gext, v = extended_ade(rt[1],rt[2])
- Fdiv = sum(v[i]*gensF[i] for i in 1:length(gensF))
- return rt, Fdiv, gensF, Gext
-end
-
-@doc raw"""
- fiber_cartier(S::EllipticSurface, P::Vector = ZZ.([0,1])) -> EffectiveCartierDivisor
-
-Return the fiber of $\pi\colon X \to C$ over $P\in C$ as a Cartier divisor.
-"""
-function fiber_cartier(S::EllipticSurface, P::Vector = ZZ.([0,1]))
- S0,_ = weierstrass_model(S)
- underlying_scheme(S) # cache stuff
- D = IdDict{AbsAffineScheme, RingElem}()
- k = base_ring(S0)
- P = k.(P)
-
- if P[1]!=0 && P[2]!=0
- t0 = P[1] * inv(P[2])
- for i in 1:3
- U = S0[1][i]
- (_,_,t) = coordinates(U)
- D[U] = t-t0
- end
- s0 = inv(t0)
- for i in 4:6
- U = S0[1][i]
- (_,_,s) = coordinates(U)
- D[U] = s - s0
- end
- elseif P[1] != 0
- # it is the fiber at [1:0]
- for i in 4:6
- U = S0[1][i]
- (_,_,s) = coordinates(U)
- D[U] = s
- end
- for i in 1:3
- U = S0[1][i]
- (_,_,t) = coordinates(U)
- D[U] = one(parent(t))
- end
- elseif P[2] != 0
- # the fiber at [0:1]
- for i in 1:3
- U = S0[1][i]
- (_,_,t) = coordinates(U)
- D[U] = t
- end
- for i in 4:6
- U = S0[1][i]
- (_,_,s) = coordinates(U)
- D[U] = one(parent(s))
- end
- else
- error("[0,0] is not a point in projective space")
- end
- F = EffectiveCartierDivisor(S0, D, trivializing_covering=S0[1], check=false)
- return pullback(S.blowup)(F)
-end
-
-@doc raw"""
- fiber_components(S::EllipticSurface, P) -> Vector{<:WeilDivisor}
-
-Return the fiber components of the fiber over the point $P \in C$.
-"""
-function fiber_components(S::EllipticSurface, P; algorithm=:exceptional_divisors)
- @vprint :EllipticSurface 2 "computing fiber components over $(P)\n"
- P = base_ring(S).(P)
- W = codomain(S.inc_Weierstrass)
- Fcart = fiber_cartier(S, P)
- if isone(P[2])
- U = default_covering(W)[1]
- (x,y,t) = coordinates(U)
- F = PrimeIdealSheafFromChart(W, U, ideal(t - P[1]))
- elseif isone(P[1])
- U = default_covering(W)[4]
- (x,y,s) = coordinates(U)
- F = PrimeIdealSheafFromChart(W, U, ideal(s - P[2]))
- end
- FF = ideal_sheaf(Fcart)
- EE = exceptional_divisors(S)
- EP = filter(E->issubset(FF, E), EE)
- for bl in S.ambient_blowups
- F = strict_transform(bl, F)
- end
- F = pullback(S.inc_Y, F)
- F = weil_divisor(F, ZZ)
- fiber_components = [weil_divisor(E, ZZ; check=false) for E in EP]
- push!(fiber_components, F)
- return fiber_components
-end
-
-@attr Vector{<:AbsIdealSheaf} function exceptional_divisors(S::EllipticSurface)
- PP = AbsIdealSheaf[]
- @vprintln :EllipticSurface 2 "computing exceptional divisors"
- # If we have resolution_strategy=:simultaneous, then the following is a non-trivial preprocessing step.
- ambient_pts = reduce(vcat, maximal_associated_points.(ideal_sheaf.(S.ambient_exceptionals)))
- for I in ambient_pts
- @vprintln :EllipticSurface 4 "decomposing divisor "
- mp = maximal_associated_points(pullback(S.inc_Y, I); use_decomposition_info=true)
- append!(PP, mp)
- end
- @vprintln :EllipticSurface 3 "done"
- return PP
-end
-
-function fiber(X::EllipticSurface)
- b, pt, F = irreducible_fiber(X)
- if b
- W = weil_divisor(F)
- # we manually set the self-intersection
- set_attribute!(components(W)[1], :_self_intersection, 0)
- else
- # all fibers are reducible pick the one over [0 : 1]
- k = base_ring(X)
- pt = [k(0),k(1)]
- f = fiber_components(X, pt)
- fiber_type, W, componentsW, gramW = standardize_fiber(X, f)
- end
- set_attribute!(W, :name=> "Fiber over ($(pt[1]), $(pt[2]))")
- return pt, W
-end
-
-
-@doc raw"""
- irreducible_fiber(S::EllipticSurface) -> Bool, Point, EffectiveCartierDivisor
-
-Return an irreducible fiber as a cartier divisor and whether it exists.
-
-The return value is a triple `(b, pt, F)` where
-
-- `b` is `true` if an irreducible fiber exists over the base field of `S`
-- `pt` the base point of the fiber
-- `F` the irreducible fiber which projects to `pt`
-"""
-function irreducible_fiber(S::EllipticSurface)
- W = weierstrass_model(S)
- d = numerator(discriminant(generic_fiber(S)))
- kt = parent(d)
- k = coefficient_ring(kt)
- r = [k.(roots(i[1])) for i in factor(d) if i[2]>=2]
- sing = reduce(append!,r, init=[])
- pt = k.([0,0]) # initialize
- found = false
- if is_finite(k)
- for i in k
- if !(i in sing) # true if the fiber over [i,1] is irreducible
- pt = k.([i,1])
- found = true
- break
- end
- end
- if !found && (degree(d) >= 12*euler_characteristic(S) - 1) # irreducible at infinity?
- pt = k.([1, 0])
- found = true
- end
- else
- i = k(0)
- while true
- i = i+1
- if !(i in sing)
- pt = k.([i,1])
- found = true
- break
- end
- end
- end
- F = fiber_cartier(S, pt)
- return found, pt, F
-end
-
-@doc raw"""
- section(X::EllipticSurface, P::EllipticCurvePoint)
-
-Given a rational point $P\in E(C)$ of the generic fiber $E/C$ of $\pi\colon X \to C$,
-return its closure in $X$ as a `WeilDivisor`.
-"""
-function section(X::EllipticSurface, P::EllipticCurvePoint)
- if iszero(P[1])&&iszero(P[3])
- return zero_section(X)
- end
- return _section(X, P)
-end
-
-function _section_on_weierstrass_ambient_space(X::EllipticSurface, P::EllipticCurvePoint)
- S0,incS0 = weierstrass_model(X)
- X0 = codomain(incS0)
- if P[3] == 0
- # zero section
- V = X0[1][3]
- (z,x,t) = coordinates(V)
- return IdealSheaf(X0, V, [x,z])
- end
- U = X0[1][1]
- (x,y,t) = coordinates(U)
- b = P
- return ideal_sheaf(X0,U,[OO(U)(i) for i in [x*denominator(b[1])(t)-numerator(b[1])(t),y*denominator(b[2])(t)-numerator(b[2])(t)]]; check=false)
-end
-
-function _section(X::EllipticSurface, P::EllipticCurvePoint)
- @vprint :EllipticSurface 3 "Computing a section from a point on the generic fiber\n"
- weierstrass_contraction(X) # trigger required computations
- PX = _section_on_weierstrass_ambient_space(X, P)
- for f in X.ambient_blowups
- PX = strict_transform(f , PX)
- end
- PY = pullback(X.inc_Y, PX)
- set_attribute!(PY, :name, string("section: (",P[1]," : ",P[2]," : ",P[3],")"))
- set_attribute!(PY, :_self_intersection, -euler_characteristic(X))
- W = WeilDivisor(PY, check=false)
- set_attribute!(W, :is_prime=>true)
- I = first(components(W))
- set_attribute!(I, :is_prime=>true)
- set_attribute!(W, :point=>P)
- return W
-end
-
-@doc raw"""
- zero_section(S::EllipticSurface) -> WeilDivisor
-
-Return the zero section of the relatively minimal elliptic
-fibration \pi\colon X \to C$.
-"""
-@attr Any zero_section(S::EllipticSurface) = _section(S, generic_fiber(S)([0,1,0]))
-
-################################################################################
-#
-# Some linear systems on elliptic surfaces
-#
-################################################################################
-
-@doc raw"""
- _prop217(E::EllipticCurve, P::EllipticCurvePoint, k)
-
-Compute a basis for the linear system
-``|O + P + kF|``
-on the minimal elliptic (K3) surface defined by E.
-Here F is the class of a fiber O the zero section
-and P any non-torsion section.
-
-The return value is a list of pairs ``(a(t),b(t))``
-
-```jldoctest
-julia> kt,t = polynomial_ring(GF(29),:t);
-
-julia> ktfield = fraction_field(kt);
-
-julia> bk = [((17*t^4 + 23*t^3 + 18*t^2 + 2*t + 6, 8*t^5 + 2*t^4 + 6*t^3 + 25*t^2 + 24*t + 5 )),
- ((17*t^6 + 3*t^5 + 16*t^4 + 4*t^3 + 13*t^2 + 6*t + 5)//(t^2 + 12*t + 7), (4*t^8 + 19*t^7 + 14*t^6 + 18*t^5 + 27*t^4 + 13*t^3 + 9*t^2 + 14*t + 12)//(t^3 + 18*t^2 + 21*t + 13) ),
- ((17*t^6 + 10*t^5 + 24*t^4 + 15*t^3 + 22*t^2 + 27*t + 5)//(t^2 + 16*t + 6), (20*t^8 + 24*t^7 + 22*t^6 + 12*t^5 + 21*t^4 + 21*t^3 + 9*t^2 + 21*t + 12)//(t^3 + 24*t^2 + 18*t + 19) ),
- ((17*t^8 + 21*t^7 + 20*t^5 + 24*t^4 + 21*t^3 + 4*t^2 + 9*t + 13)//(t^4 + 17*t^3 + 12*t^2 + 28*t + 28), (23*t^11 + 25*t^10 + 8*t^9 + 7*t^8 + 28*t^7 + 16*t^6 + 7*t^5 + 23*t^4 + 9*t^3 + 27*t^2 + 13*t + 13)//(t^6 + 11*t^5 + 14*t^4 + 13*t^3 + 6*t^2 + 18*t + 12) )];
-
-julia> E = elliptic_curve(ktfield,[3*t^8+24*t^7+22*t^6+15*t^5+28*t^4+20*t^3+16*t^2+26*t+16, 24*t^12+27*t^11+28*t^10+8*t^9+6*t^8+16*t^7+2*t^6+10*t^5+3*t^4+22*t^3+27*t^2+10*t+3]);
-
-julia> bk = [E(collect(i)) for i in bk];
-
-julia> Oscar._prop217(E,bk[2],2)
-5-element Vector{Tuple{FqPolyRingElem, FqPolyRingElem}}:
- (t^2 + 12*t + 7, 0)
- (t^3 + 8*t + 3, 0)
- (t^4 + 23*t + 2, 0)
- (25*t + 22, 1)
- (12*t + 28, t)
-
-julia> Oscar._prop217(E,bk[1],1)
-2-element Vector{Tuple{FqPolyRingElem, FqPolyRingElem}}:
- (1, 0)
- (t, 0)
-```
-"""
-function _prop217(E::EllipticCurve, P::EllipticCurvePoint, k)
- @req !iszero(P[3]) "P must not be torsion" # seems like we cannot check this
- xn = numerator(P[1])
- xd = denominator(P[1])
- yn = numerator(P[2])
- yd = denominator(P[2])
- OP = divexact(max(degree(xd), degree(xn) - 4), 2)
- dega = k + 2*OP
- degb = k + 2*OP - 2 - divexact(degree(xd), 2) #?
- base = base_field(E)
- Bt = base_ring(base)
- B = coefficient_ring(Bt)
-
- R,ab = polynomial_ring(base,vcat([Symbol(:a,i) for i in 0:dega],[Symbol(:b,i) for i in 0:degb]),cached=false)
- Rt, t1 = polynomial_ring(R,:t)
- a = reduce(+,(ab[i+1]*t1^i for i in 0:dega), init=zero(Rt))
- b = reduce(+,(ab[2+dega+j]*t1^j for j in 0:degb), init=zero(Rt))
- c = a*xn(t1) - b*yn(t1)
- r = mod(c, xd(t1))
- # setup the linear equations for coefficients of r to vanish
- # and for the degree of c to be bounded above by
- # k + 2*OP + 4 + degree(xd)
- eq1 = collect(coefficients(r))
- eq2 = [coeff(c,i) for i in (k + 2*OP + 4 + degree(xd) + 1):degree(c)]
- eqns = vcat(eq1, eq2)
-
- # collect the equations as a matrix
- cc = [[coeff(j, abi) for abi in ab] for j in eqns]
- M = matrix(B, length(eqns), length(ab), reduce(vcat,cc, init=elem_type(base)[]))
- # @assert M == matrix(base, cc) # does not work if length(eqns)==0
- K = kernel(M; side = :right)
- kerdim = ncols(K)
- result = Tuple{elem_type(Bt),elem_type(Bt)}[]
- t = gen(Bt)
- for j in 1:kerdim
- aa = reduce(+, (K[i+1,j]*t^i for i in 0:dega), init=zero(Bt))
- bb = reduce(+, (K[dega+i+2,j]*t^i for i in 0:degb), init=zero(Bt))
- push!(result, (aa, bb))
- end
- # confirm the computation
- @assert kerdim == 2*k + OP # prediced by Riemann-Roch
- for (a,b) in result
- @assert mod(a*xn - b*yn, xd) == 0
- @assert degree(a) <= k + 2*OP
- @assert degree(b) <= k + 2*OP - 2 - 1//2*degree(xd)
- @assert degree(a*xn - b*yn) <= k + 2*OP + 4 + degree(xd)
- end
- return result
-end
-
-function iszero(P::EllipticCurvePoint)
- return iszero(P[1]) && isone(P[2]) && iszero(P[3])
-end
-
-@doc raw"""
- linear_system(X::EllipticSurface, P::EllipticCurvePoint, k::Int64) -> LinearSystem
-
-Compute the linear system ``|O + P + k F|`` on the elliptic surface ``X``.
-Here ``F`` is the class of the fiber over ``[0:1]``, ``O`` the zero section
-and ``P`` any section given as a point on the generic fiber.
-
-The linear system is represented in terms of the Weierstrass coordinates.
-"""
-function linear_system(X::EllipticSurface, P::EllipticCurvePoint, k::Int64)
- euler_characteristic(X) == 2 || error("linear system implemented only for elliptic K3s")
- #FS = function_field(weierstrass_model(X)[1])
- FS = function_field(X)
- U = weierstrass_chart_on_minimal_model(X)
- (x,y,t) = ambient_coordinates(U)
-
- sections = elem_type(FS)[]
- if iszero(P[3])
- append!(sections, [FS(t)^(i-k) for i in 0:k])
- append!(sections, [FS(t)^(i-k)*FS(x) for i in 0:k-4])
- else
- xn = numerator(P[1])
- xd = denominator(P[1])
- yn = numerator(P[2])
- yd = denominator(P[2])
-
- I = saturated_ideal(defining_ideal(U))
- IP = ideal([x*xd(t)-xn(t),y*yd(t)-yn(t)])
- issubset(I, IP) || error("P does not define a point on the Weierstrasschart")
-
- @assert gcd(xn, xd)==1
- @assert gcd(yn, yd)==1
- ab = _prop217(generic_fiber(X), P, k)
- d = divexact(yd, xd)(t)
- den = t^k*(x*xd(t) - xn(t))
- for (a,b) in ab
- c = divexact(b*yn - a*xn, xd)
- num = a(t)*x+b(t)*d*y + c(t)
- push!(sections, FS(num//den))
- end
- end
- return sections
-end
-
-@doc raw"""
- two_neighbor_step(X::EllipticSurface, F1::Vector{QQFieldElem})
-
-Given an isotropic nef divisor ``F1`` with ``F1.F = 2``,
-compute the linear system ``|F1|`` and return the corresponding generic fiber
-as a double cover `C` of the projective line branched over four points.
-
-Input:
-``F1`` is represented as a vector in the `algebraic_lattice(X)`
-
-Output:
-A tuple `(C, (x1, y1, t1))` defined as follows.
-- `C` is given by a polynomial `y1^2 - q(x1)` in `k(t)[x1,y1]` with `q` of degree 3 or 4.
-- (x1,y1,t1) are expressed as rational functions in terms of the weierstrass coordinates `(x,y,t)`.
-"""
-function two_neighbor_step(X::EllipticSurface, F::Vector{QQFieldElem})
- E = generic_fiber(X)
- basisNS, tors, NS = algebraic_lattice(X)
- V = ambient_space(NS)
- @req inner_product(V, F, F)==0 "not an isotropic divisor"
- @req euler_characteristic(X) == 2 "not a K3 surface"
- F0 = zeros(QQ,degree(NS)); F0[1]=1
-
- @req inner_product(V, F, F0) == 2 "not a 2-neighbor"
-
- D1, D, P, l, c = horizontal_decomposition(X, F)
- u = _elliptic_parameter(X, D1, D, P, l, c)
- @assert scheme(parent(u)) === X
- pr = weierstrass_contraction(X)
- WX, _ = weierstrass_model(X)
- # The following is a cheating version of the command u = pushforward(pr)(u)
- u = function_field(WX)(u[weierstrass_chart_on_minimal_model(X)])
- @assert scheme(parent(u)) === weierstrass_model(X)[1]
-
- # Helper function
- my_const(u::MPolyRingElem) = is_zero(u) ? zero(coefficient_ring(parent(u))) : first(coefficients(u))
-
- # transform to a quartic y'^2 = q(x)
- if iszero(P[3]) # P = O
- eqn1, phi1 = _elliptic_parameter_conversion(X, u, case=:case1)
- eqn2, phi2 = _normalize_hyperelliptic_curve(eqn1)
-# function phi_func(x)
-# y = phi1(x)
-# n = numerator(y)
-# d = denominator(y)
-# return phi2(n)//phi2(d)
-# end
-# phi = MapFromFunc(domain(phi1), codomain(phi2), phi_func)
-# # TODO: Verify that the construction below also works and replace by that, eventually.
-# phi_alt = compose(phi1, extend_domain_to_fraction_field(phi2))
-# @assert phi.(gens(domain(phi))) == phi_alt.(gens(domain(phi)))
- phi = compose(phi1, extend_domain_to_fraction_field(phi2))
- elseif iszero(2*P) # P is a 2-torsion section
- eqn1, phi1 = _elliptic_parameter_conversion(X, u, case=:case3)
- #eqn1, phi1 = _conversion_case_3(X, u)
- (x2, y2) = gens(parent(eqn1))
-
- # Make sure the coefficient of y² is one (or a square) so that
- # completing the square works.
- c = my_const(coeff(eqn1, [x2, y2], [0, 2]))::AbstractAlgebra.Generic.FracFieldElem
- eqn1 = inv(unit(factor(c)))*eqn1
-
- eqn2, phi2 = _normalize_hyperelliptic_curve(eqn1)
- phi = compose(phi1, extend_domain_to_fraction_field(phi2))
- else # P has infinite order
- eqn1, phi1 = _elliptic_parameter_conversion(X, u, case=:case2)
- #eqn1, phi1 = _conversion_case_2(X, u)
- (x2, y2) = gens(parent(eqn1))
-
- # Make sure the coefficient of y² is one (or a square) so that
- # completing the square works.
- c = my_const(coeff(eqn1, [x2, y2], [0, 2]))::AbstractAlgebra.Generic.FracFieldElem
- eqn1 = inv(unit(factor(c)))*eqn1
-
- eqn2, phi2 = _normalize_hyperelliptic_curve(eqn1)
- phi = compose(phi1, extend_domain_to_fraction_field(phi2))
- end
-
- return eqn2, phi
-end
-
-@doc raw"""
- horizontal_decomposition(X::EllipticSurface, L::Vector{QQFieldElem}) -> WeilDivisor, EllipticCurvePoint
-
-Given a divisor ``L`` as a vector in the `algebraic_lattice(X)`
-find a linearly equivalent divisor ``(n-1) O + P + V = D ~ L`` where
-``O`` is the zero section, ``P`` is any section and ``V`` is vertical.
-
-Returns a tuple `(D1, D, P, l, c)` where `D` and `P` are as above and
-``D <= D1 = (n-1)O + P + n_1F_1 + ... n_k F_k`` with ``l = n_1 + ... n_k`` minimal
-and the `F_i` are some other fibers.
-The rational function `c=c(t)` has divisor of zeros and poles``
-(c) = lF - n_0F_1 + ... n_k F_k``
-"""
-function horizontal_decomposition(X::EllipticSurface, F::Vector{QQFieldElem})
- E = generic_fiber(X)
- basisNS, tors, NS = algebraic_lattice(X)
- V = ambient_space(NS)
- @req F in algebraic_lattice(X)[3] "not in the algebraic lattice"
- @req inner_product(V, F, F)==0 "not an isotropic divisor"
- @req euler_characteristic(X) == 2 "not a K3 surface"
- # how to give an ample divisor automagically in general?
- # @req is_nef(X, F) "F is not nef"
- l = F[1]
- rk_triv = nrows(trivial_lattice(X)[2])
- n = rank(NS)
- @assert degree(NS) == rank(NS)
- p, P = _vertical_part(X,F)
- D = section(X, P)
- F2 = F - p
- @vprint :EllipticSurface 4 "F2 = $(F2)\n"
- D = D + ZZ(F2[2])*zero_section(X)
- D1 = D
- F2 = ZZ.(F2); F2[2] = 0
- l = F2[1] # number of fibers that we need
- # find the fiber components meeting O necessary
- F3 = F2
- (_,_,t) = ambient_coordinates(weierstrass_chart_on_minimal_model(X))
- c = t^0
- for (pt, rt, fiber, comp, gram) in reducible_fibers(X)
- Fib0 = comp[1]
- f0 = zeros(QQFieldElem, length(basisNS))
- for i in 1:length(basisNS)
- if !isone(components(Fib0)[1]+components(basisNS[i])[1])
- if length(comp)==2 && 2=0 for i in 1:length(basisNS))
- D = D + sum(ZZ(F4[i])*basisNS[i] for i in 1:length(basisNS))
- @assert D<=D1
- l = Int(l)
- return D1, D, P, l, c
-end
-
-@doc raw"""
- elliptic_parameter(X::EllipticSurface, F::Vector{QQFieldElem}) -> LinearSystem
-
-Return the elliptic parameter ``u`` of the divisor class `F`.
-
-The input `F` must be given with respect to the basis of
-`algebraic_lattice(X)` and be an isotropic nef divisor.
-This method assumes that $X$ is a K3 surface.
-"""
-function elliptic_parameter(X::EllipticSurface, F::Vector{QQFieldElem})
- D1, D, P, l, c = horizontal_decomposition(X, F)
- return _elliptic_parameter(X, D1, D, P, l, c)
-end
-
-@doc raw"""
- _elliptic_parameter(X::EllipticSurface, D::WeilDivisor, l, c)
-
-Compute the linear system of ``D = (n-1) O + P + V``.
-where V is vertical and `l` is the coefficient of the fiber class.
-Assumes `D` nef and `D^2=0`.
-Typically ``D`` is the output of `horizontal_decomposition`.
-"""
-function _elliptic_parameter(X::EllipticSurface, D1::WeilDivisor, D::WeilDivisor, P::EllipticCurvePoint, l::Int, c)
- S, piS = weierstrass_model(X);
- piX = weierstrass_contraction(X)
- c = function_field(X)(c)
- L = [i*c for i in linear_system(X, P, l)];
- LonX = linear_system(L, D1, check=false);
-
- LsubF, Tmat = subsystem(LonX, D);
- LsubFonS = [sum(Tmat[i,j]*L[j] for j in 1:ncols(Tmat)) for i in 1:nrows(Tmat)]
-
- @assert length(LsubFonS)==2
- u2 = LsubFonS[2]//LsubFonS[1]
- return u2
-end
-
-
-@doc raw"""
- extended_ade(ADE::Symbol, n::Int)
-
-Return the dual intersection matrix of an extended ade Dynkin diagram
-as well as the isotropic vector (with positive coefficients in the roots).
-"""
-function extended_ade(ADE::Symbol, n::Int)
- R = change_base_ring(ZZ,gram_matrix(root_lattice(ADE,n)))
- G = block_diagonal_matrix([ZZ[2;],R])
- if ADE == :E && n == 8
- G[1,n] = -1
- G[n,1] = -1
- end
- if ADE == :E && n == 7
- G[1,2] = -1
- G[2,1] = -1
- end
- if ADE == :E && n == 6
- G[1,n+1] = -1
- G[n+1,1] = -1
- end
- if ADE == :A && n > 0
- G[1,2] = -1
- G[2,1] = -1
- G[1,n+1] = -1
- G[n+1,1] = -1
- end
- if ADE == :A && n ==1 0
- G[1,2]= -2
- G[2,1] = -2
- end
- if ADE == :D
- G[1,n] = -1
- G[n,1] = -1
- end
- @assert rank(G) == n
- return -G, kernel(G; side = :left)
-end
-
-# This function allows to store a reduction map to positive characteristic,
-# e.g. for computing intersection numbers.
-function reduction_to_pos_char(X::EllipticSurface, red_map::Map)
- return get_attribute!(X, :reduction_to_pos_char) do
- kk0 = base_ring(X)
- @assert domain(red_map) === kk0
- kkp = codomain(red_map)
- @assert characteristic(kkp) > 0
- _, result = base_change(red_map, X)
- return red_map, result
- end::Tuple{<:Map, <:Map}
-end
-
-@doc raw"""
- basis_representation(X::EllipticSurface, D::WeilDivisor)
-
-Return the vector representing the numerical class of `D`
-with respect to the basis of the ambient space of `algebraic_lattice(X)`.
-"""
-function basis_representation(X::EllipticSurface, D::WeilDivisor)
- basis_ambient,_, NS = algebraic_lattice(X)
- G = gram_matrix(ambient_space(NS))
- n = length(basis_ambient)
- v = zeros(ZZRingElem, n)
- @vprint :EllipticSurface 3 "computing basis representation of $D\n"
- kk = base_ring(X)
- if iszero(characteristic(kk)) && has_attribute(X, :reduction_to_pos_char)
- red_map, bc = get_attribute(X, :reduction_to_pos_char)
- for i in 1:n
- @vprintln :EllipticSurface 4 "intersecting with $(i): $(basis_ambient[i])"
-
- v[i] = intersect(base_change(red_map, basis_ambient[i]; scheme_base_change=bc),
- base_change(red_map, D; scheme_base_change=bc))
- end
- else
- for i in 1:n
- @vprintln :EllipticSurface 4 "intersecting with $(i): $(basis_ambient[i])"
-
- v[i] = intersect(basis_ambient[i], D)
- end
- end
- @vprint :EllipticSurface 3 "done computing basis representation\n"
- return v*inv(G)
-end
-
-################################################################################
-#
-# patches for Oscar
-#
-################################################################################
-
-
-########################################################################
-# Internal functionality for Weierstrass transformation
-########################################################################
-
-
-@doc raw"""
- _normalize_hyperelliptic_curve(g::MPolyRingElem, parent=nothing)
-
-Transform ``a(x)y^2 + b(x)y - h(x)`` in ``K(t)[x,y]`` to ``y'^2 - h(x')``
-"""
-function _normalize_hyperelliptic_curve(g::MPolyRingElem; parent::Union{MPolyRing, Nothing}=parent(g))
- R = Oscar.parent(g)
- @assert ngens(R) == 2 "polynomial must be bivariate"
- F = fraction_field(R)
- kt = coefficient_ring(R)
- (x, y) = gens(R)
-
- # Prepare the output ring
- if parent===nothing
- R1, (x1, y1) = R, gens(R)
- else
- R1 = parent
- @assert coefficient_ring(R1) == coefficient_ring(R) "coefficient ring of output is incompatible with input"
- (x1, y1) = gens(R1)
- end
-
- # Get the coefficients of g as a univariate polynomial in y
- ktx, X = polynomial_ring(kt, :X, cached=false)
- ktxy, Y = polynomial_ring(ktx, :y, cached=false)
-
- # Maps to transform to univariate polynomials in y
- split_map_R = hom(R, ktxy, [ktxy(X), Y])
- split_map_R1 = hom(R1, ktxy, [ktxy(X), Y])
- G = split_map_R(g)
- @assert degree(G) == 2 "polynomial must be of degree 2 in its second variable"
-
- #complete the square
- h, b, a = collect(coefficients(G))
- h = -h
- u = unit(factor(a))
- a = inv(u)*a
- b = inv(u)*b
- success, sqa = is_square_with_sqrt(a)
- @assert success "leading coefficient as univariate polynomial in the second variable must be a square"
-
- F1 = fraction_field(R1)
- psi = hom(R1, F, F.([x, (2*evaluate(a, x)*y + evaluate(b, x))//(2*evaluate(sqa, x))]))
- conv = MapFromFunc(ktx, R1, f->evaluate(f, x1))
- (a1, b1, sqa1) = conv.([a, b, sqa])
- phi = hom(R, F1, F1.([x1, (2*sqa1*y1-b1)//(2*a1)]))
- phiF = MapFromFunc(F, F1, x-> phi(numerator(x))//phi(denominator(x)))
- # the inverse map if wanted
- # psiF = MapFromFunc(F1, F, x-> psi(numerator(x))//psi(denominator(x)))
- # @assert all(phiF(psiF(F1(i)))==i for i in gens(R1))
-
- # absorb squares into y1
- g1 = numerator(phi(g))
- G1 = split_map_R1(g1)
- ff = factor(first(coefficients(G1)))
- c = prod([p^div(i, 2) for (p, i) in ff], init=one(ktx))
- #d = sqrt(my_coeff(g1, y1, 2))
- d = last(coefficients(split_map_R1(g1)))
- success, d = is_square_with_sqrt(d)
- @assert success "leading coefficient must be a square"
-
- phi1 = hom(R1, F1, [F1(x1), F1(evaluate(c, x1), evaluate(d, x1))*y1])
- phiF1 = MapFromFunc(F1, F1, x-> phi1(numerator(x))//phi1(denominator(x)))
- phi2 = compose(phi, phiF1)
- g2 = numerator(phi1(g1))
- #c = my_coeff(g2, y1, 2)
- c = last(coefficients(split_map_R1(g2)))
- g2 = divexact(g2, evaluate(c, x1))
- @assert degree(g2, gen(parent, 1)) <= 4 "degree in the first variable is too high"
- @assert degree(g2, gen(parent, 1)) >= 3 "degree in the first variable is too low"
- return g2, phi2
-end
-
-
-@doc raw"""
- elliptic_surface(g::MPolyRingElem, P::Vector{<:RingElem})
-
-Transform a bivariate polynomial `g` of the form `y^2 - Q(x)` with `Q(x)` of
-degree at most ``4`` to Weierstrass form, apply Tate's algorithm and
-return the corresponding relatively minimal elliptic surface
-as well as the coordinate transformation.
-"""
-function elliptic_surface(
- g::MPolyRingElem, P::Vector{<:RingElem};
- minimize::Bool=true, resolution_strategy::Symbol=:iterative
- )
- R = parent(g)
- (x, y) = gens(R)
- P = base_ring(R).(P)
- g2, phi2 = transform_to_weierstrass(g, x, y, P);
- Y2, phi1 = _elliptic_surface_with_trafo(g2; minimize)
- return Y2, phi2 * phi1
-end
-
-@doc raw"""
- transform_to_weierstrass(g::MPolyRingElem, x::MPolyRingElem, y::MPolyRingElem, P::Vector{<:RingElem})
-
-Transform a bivariate polynomial `g` of the form `y^2 - Q(x)` with `Q(x)` of degree ``≤ 4``
-to Weierstrass form. This returns a pair `(f, trans)` where `trans` is an endomorphism of the
-`fraction_field` of `parent(g)` and `f` is the transform. The input `P` must be a rational point
-on the curve defined by `g`, i.e. `g(P) == 0`.
-"""
-function transform_to_weierstrass(g::MPolyRingElem, x::MPolyRingElem, y::MPolyRingElem, P::Vector{<:RingElem})
- R = parent(g)
- F = fraction_field(R)
- @assert ngens(R) == 2 "input polynomial must be bivariate"
- @assert x in gens(R) "second argument must be a variable of the parent of the first"
- @assert y in gens(R) "third argument must be a variable of the parent of the first"
- # In case of variables in the wrong order, switch and transform the result.
- if x == R[2] && y == R[1]
- switch = hom(R, R, reverse(gens(R)))
- g_trans, trans = transform_to_weierstrass(switch(g), y, x, reverse(P))
- new_trans = MapFromFunc(F, F, f->begin
- switch_num = switch(numerator(f))
- switch_den = switch(denominator(f))
- interm_res = trans(F(switch_num))//trans(F(switch_den))
- num = numerator(interm_res)
- den = denominator(interm_res)
- switch(num)//switch(den)
- end
- )
- return switch(g_trans), new_trans
- end
-
- g = inv(coeff(g,[0,2]))*g # normalise g
- kk = coefficient_ring(R)
- kkx, X = polynomial_ring(kk, :x, cached=false)
- kkxy, Y = polynomial_ring(kkx, :y, cached=false)
-
- imgs = [kkxy(X), Y]
- split_map = hom(R, kkxy, imgs)
-
- G = split_map(g)
- @assert degree(G) == 2 "input polynomial must be of degree 2 in y"
- @assert all(h->degree(h)<=4, coefficients(G)) "input polynomial must be of degree <= 4 in x"
- @assert iszero(coefficients(G)[1]) "coefficient of linear term in y must be zero"
- @assert isone(coefficients(G)[2]) "leading coefficient in y must be one"
-
- if length(P) == 3 && isone(P[3])
- P = P[1:2]
- end
-
-
- if length(P) == 2
- @assert iszero(evaluate(g, P)) "point does not lie on the hypersurface"
- (px, py) = P
- else
- px = P[1]
- end
- # assert g.subs({x:px,y:py})==0
- gx = -evaluate(g, [X + px, zero(X)])
- coeff_gx = collect(coefficients(gx))
- A = coeff(gx, 4)
- B = coeff(gx, 3)
- C = coeff(gx, 2)
- D = coeff(gx, 1)
- E = coeff(gx, 0)
- #E, D, C, B, A = coeff_gx
- if length(P)==3
- @req all(h->degree(h)<=3, coefficients(G)) "infinity (0:1:0) is not a point of this hypersurface"
- # y^2 = B*x^3+C*x^2+C*x+D
- x1 = F(inv(B)*x)
- y1 = F(inv(B)*y)
- trans = MapFromFunc(F, F, f->evaluate(numerator(f), [x1, y1])//evaluate(denominator(f), [x1, y1]))
- f_trans = B^2*trans(F(g))
- result = numerator(B^2*f_trans)
- return result, trans
- elseif !iszero(E)
- b = py
- a4, a3, a2, a1, a0 = A,B,C,D,E
- A = b
- B = a1//(2*b)
- C = (4*a2*b^2-a1^2)//(8*b^3)
- D = -2*b
-
- x1 = x//y
- y1 = (A*y^2+B*x*y+C*x^2+D*x^3)//y^2
- x1 = x1+px
-
- # TODO: The following are needed for the inverse. To be added eventually.
- # x2 = (y-(A+B*x+C*x^2))//(D*x^2)
- # y2 = x2//x
- # x2 = evaluate(x2, [x-px, y])
- # y2 = evaluate(y2, [x-px, y])
-
- # @assert x == evaluate(x1, [x2, y2])
- # @assert y == evaluate(y1, [x2, y2])
- else
- # TODO compute the inverse transformation (x2,y2)
- x1 = 1//x
- y1 = y//x^2
- g1 = numerator(evaluate(g, [x1, y1]))
- c = coeff(g1, [x], [3])
- x1 = evaluate(x1, [-x//c, y//c])
- y1 = evaluate(y1, [-x//c, y//c])
- x1 = x1+px
- #@assert x == evaluate(x1, [x2, y2])
- #@assert y == evaluate(y1, [x2, y2])
- end
- @assert F === parent(x1) "something is wrong with caching of fraction fields"
- # TODO: eventually add the inverse.
- trans = MapFromFunc(F, F, f->evaluate(numerator(f), [x1, y1])//evaluate(denominator(f), [x1, y1]))
- f_trans = trans(F(g))
- fac = [a[1] for a in factor(numerator(f_trans)) if isone(a[2]) && _is_in_weierstrass_form(a[1])]
- isone(length(fac)) || error("transform to weierstrass form did not succeed")
-
- # normalize the output
- result = first(fac)
- result = inv(first(coefficients(coeff(result, gens(parent(result)), [3, 0]))))*result
-
- return result, trans
-end
-
-function _is_in_weierstrass_form(f::MPolyRingElem)
- R = parent(f)
- @req ngens(R) == 2 "polynomial must be bivariate"
- # Helper function
- my_const(u::MPolyRingElem) = is_zero(u) ? zero(coefficient_ring(parent(u))) : first(coefficients(u))
-
- (x, y) = gens(R)
- f = -inv(my_const(coeff(f, [x, y], [0, 2]))) * f
- isone(-coeff(f, [x, y], [0, 2])) || return false
- isone(coeff(f, [x, y], [3, 0])) || return false
-
- a6 = coeff(f, [x,y], [0,0])
- a4 = coeff(f, [x,y], [1,0])
- a2 = coeff(f, [x,y], [2,0])
- a3 = -coeff(f, [x,y], [0,1])
- a1 = -coeff(f, [x,y], [1,1])
- a_invars = [my_const(i) for i in [a1,a2,a3,a4,a6]]
- (a1,a2,a3,a4,a6) = a_invars
- return f == (-(y^2 + a1*x*y + a3*y) + (x^3 + a2*x^2 + a4*x + a6))
-end
-
-function evaluate(f::AbstractAlgebra.Generic.FracFieldElem{<:MPolyRingElem}, a::Vector{T}) where {T<:RingElem}
- return evaluate(numerator(f), a)//evaluate(denominator(f), a)
-end
-
-function evaluate(f::AbstractAlgebra.Generic.FracFieldElem{<:PolyRingElem}, a::RingElem)
- return evaluate(numerator(f), a)//evaluate(denominator(f), a)
-end
-
-function extend_domain_to_fraction_field(phi::Map{<:MPolyRing, <:Ring})
- ext_dom = fraction_field(domain(phi))
- return MapFromFunc(ext_dom, codomain(phi), x->phi(numerator(x))*inv(phi(denominator(x))))
-end
-
-########################################################################
-# The three conversions from Section 39.1 in
-# A. Kumar: "Elliptic Fibrations on a generic Jacobian Kummer surface"
-# pp. 44--45.
-########################################################################
-
-function _elliptic_parameter_conversion(X::EllipticSurface, u::VarietyFunctionFieldElem;
- case::Symbol=:case1, names=[:x, :y, :t]
- )
- @req variety(parent(u)) === weierstrass_model(X)[1] "function field element must live on the weierstrass model of the first argument"
- @req length(names) == 3 "need 3 variable names x, y, t"
- U = weierstrass_chart(X)
- R = ambient_coordinate_ring(U)
- x, y, t = gens(R)
- loc_eqn = first(gens(modulus(OO(U))))
- E = generic_fiber(X)::EllipticCurve
- f = equation(E)
- kk = base_ring(X)
- kkt_frac_XY = parent(f)::MPolyRing
- (xx, yy) = gens(kkt_frac_XY)
- kkt_frac = coefficient_ring(kkt_frac_XY)::AbstractAlgebra.Generic.FracField
- kkt = base_ring(kkt_frac)::PolyRing
- T = first(gens(kkt))
-
-# kk = base_ring(U)
-# kkt, T = polynomial_ring(kk, :T, cached=false)
-# kkt_frac = fraction_field(kkt)
-# kkt_frac_XY, (xx, yy) = polynomial_ring(kkt_frac, [:X, :Y], cached=false)
- R_to_kkt_frac_XY = hom(R, kkt_frac_XY, [xx, yy, kkt_frac_XY(T)])
-
- f_loc = first(gens(modulus(OO(U))))
- @assert f == R_to_kkt_frac_XY(f_loc) && _is_in_weierstrass_form(f) "local equation is not in Weierstrass form"
- a = a_invariants(E)
-
- u_loc = u[U]::AbstractAlgebra.Generic.FracFieldElem # the representative on the Weierstrass chart
-
- # Set up the ambient_coordinate_ring of the new Weierstrass-chart
- kkt2, t2 = polynomial_ring(kk, names[3], cached=false)
- kkt2_frac = fraction_field(kkt2)
- S, (x2, y2) = polynomial_ring(kkt2_frac, names[1:2], cached=false)
- FS = fraction_field(S)
-
- # Helper function
- my_const(u::MPolyRingElem) = is_zero(u) ? zero(coefficient_ring(parent(u))) : first(coefficients(u))
-
- # We verify the assumptions made on p. 44 of
- # A. Kumar: "Elliptic Fibrations on a generic Jacobian Kummer surface"
- # for the first case considered there.
- @assert all(x->isone(denominator(x)), a) "local equation does not have the correct form"
- a = numerator.(a)
- @assert iszero(a[1]) "local equation does not have the correct form"
- @assert degree(a[2]) <= 4 "local equation does not have the correct form"
- @assert iszero(a[3]) "local equation does not have the correct form"
- @assert degree(a[4]) <= 8 "local equation does not have the correct form"
- @assert degree(a[5]) <= 12 "local equation does not have the correct form" # This is really a₆ in the notation of the paper, a₅ does not exist.
- # reduce fraction
- u_frac = R_to_kkt_frac_XY(numerator(u_loc))//R_to_kkt_frac_XY(denominator(u_loc))
- u_num = numerator(u_frac)
- u_den = denominator(u_frac)
- if case == :case1
- # D = 2O
- u_poly = u_num*inv(u_den) # Will throw if the latter is not a unit
- # Extract a(t) and b(t) as in the notation of the paper
- a_t = my_const(coeff(u_poly, [xx, yy], [0, 0]))
- b_t = my_const(coeff(u_poly, [xx, yy], [1, 0]))
-
- a_t = evaluate(a_t, x2)
- b_t = evaluate(b_t, x2)
- phi = hom(R, FS, FS.([(t2 - a_t)//b_t, y2, x2]))
- f_trans = phi(f_loc)
- return numerator(f_trans), phi
- elseif case == :old
- # D = O + P
- @assert degree(u_num, 2) == 1 && degree(u_num, 1) <= 1 "numerator does not have the correct degree"
- @assert degree(u_den, 1) == 1 && degree(u_den, 2) == 0 "denominator does not have the correct degree"
-
- # We expect a form as on p. 44, l. -4
- denom_unit = my_const(coeff(u_den, [xx, yy], [1, 0]))
- x0 = -inv(denom_unit)*my_const(coeff(u_den, [xx, yy], [0, 0]))
- b_t = inv(denom_unit)*my_const(coeff(u_num, [xx, yy], [0, 1]))
- u_num = u_num - denom_unit * b_t * yy
- a_t = inv(denom_unit)*my_const(coeff(u_num, [xx, yy], [1, 0]))
- u_num = u_num - denom_unit * a_t * (xx - x0)
- @assert is_constant(u_num) "numerator is not in the correct form"
- y0 = my_const(coeff(u_num, [xx, yy], [0, 0])) * inv(denom_unit * b_t)
-
- @assert a_t + b_t*(yy + y0)//(xx - x0) == u_frac "decomposition failed"
- # We have
- #
- # y ↦ (u - a_t) * (x - x₀) / b_t - y₀ = (t₂ - a_t(x₂)) * (y₂ - x₀(x₂)) / b_t(x₂) - y₀(x₂)
- # x ↦ y₂
- # t ↦ x₂
- phi = hom(R, FS, FS.([y2, (t2 - evaluate(a_t, x2)) * (y2 - evaluate(x0, x2)) // evaluate(b_t, x2) - evaluate(y0, x2), x2]))
- f_trans = phi(f_loc)
- eqn1 = numerator(f_trans)
- # According to
- # A. Kumar: "Elliptic Fibrations on a generic Jacobian Kummer surface"
- # p. 45, l. 1 we expect the following cancelation to be possible:
- divisor_num = evaluate(numerator(x0), x2)
- divisor_den = evaluate(denominator(x0), x2)
- divisor = divisor_den * y2 - divisor_num
- success, eqn1 = divides(eqn1, divisor) # This division must only be possible in the ring K(x2)[y2].
- # Hence, multiplying by the denominator `divisor_den` is
- # merely an educated guess.
- @assert success "division failed"
- return eqn1, phi
- elseif case == :case3
- # D = O + T
-
- @assert u_den == xx "elliptic parameter was not brought to the correct form"
- @assert degree(u_num, 1) <= 1 && degree(u_num, 2) <= 1 "numerator does not have the correct degrees"
- a_t = my_const(coeff(u_num, [xx, yy], [1, 0]))
- b_t = my_const(coeff(u_num, [xx, yy], [0, 1]))
-
- # New Weierstrass equation is of the form
- #
- # x^2 = h(t, u)
- #
- # so y₂ = x, x₂ = t, and t₂ = u.
- #
- # We have u = a_t + b_t * y/x ⇒ y = (u - a_t) * x / b_t = (t₂ - a_t(x₂)) * y₂ / b_t(x₂)
- phi = hom(R, FS, FS.([y2, (t2 - evaluate(a_t, x2)) * y2 // evaluate(b_t, x2), x2]))
- f_trans = phi(f_loc)
- eqn1 = numerator(f_trans)
- # According to
- # A. Kumar: "Elliptic Fibrations on a generic Jacobian Kummer surface"
- # p. 45, l. 15 we expect the following cancelation to be possible:
- success, eqn1 = divides(eqn1, y2)
- @assert success "equation did not come out in the anticipated form"
- return eqn1, phi
- elseif case == :case2
- # D = O + P
- @assert degree(u_num, 2) == 1 && degree(u_num, 1) <= 1 "numerator does not have the correct degree"
- @assert degree(u_den, 1) == 1 && degree(u_den, 2) <= 1 "denominator does not have the correct degree"
-
- # u = (ax + by + c)/(a'x + b'y + c')
- an = my_const(coeff(u_num, [xx, yy], [1, 0]))
- bn = my_const(coeff(u_num, [xx, yy], [0, 1]))
- cn = my_const(coeff(u_num, [xx, yy], [0, 0]))
-
- ad = my_const(coeff(u_den, [xx, yy], [1, 0]))
- bd = my_const(coeff(u_den, [xx, yy], [0, 1]))
- cd = my_const(coeff(u_den, [xx, yy], [0, 0]))
-
- @assert (an*xx+bn*yy+cn)//(ad*xx+bd*yy+cd) == u_frac "decomposition failed"
-
-
- v = solve(matrix(parent(an), 2, 2, [-an, bn,-ad, bd]), matrix(parent(an), 2, 1, [cn, cd]); side=:right)
- x0 = v[1,1]
- y0 = v[2,1]
- @assert evaluate(f_loc,[x0,y0,gen(parent(x0))])==0
-
- ad = evaluate(ad,x2)
- an = evaluate(an,x2)
- bd = evaluate(bd,x2)
- bn = evaluate(bn,x2)
- cn = evaluate(cn,x2)
- cd = evaluate(cd,x2)
- #x0 = evaluate(x0,x2)
- #y0 = evaluate(y0,x2)
-
-
- imgy = -FS(((ad*t2 - an )*y2 + (cd*t2 -cn)) //(bd*t2 -bn))
-
- # We have
- #
- # y ↦ -((ad u - an )x + (cd u -cn)) // (bd*u -bn)
- # x ↦ y₂
- # t ↦ x₂
- phi = hom(R, FS, [y2, imgy, x2])
- f_trans = phi(f_loc)
- eqn1 = numerator(f_trans)
- # According to
- # A. Kumar: "Elliptic Fibrations on a generic Jacobian Kummer surface"
- # p. 45, l. 1 we expect the following cancellation to be possible:
- divisor_num = evaluate(numerator(x0), x2)
- divisor_den = evaluate(denominator(x0), x2)
- divisor = divisor_den * y2 - divisor_num
- success, eqn1 = divides(eqn1, divisor) # This division must only be possible in the ring K(x2)[y2].
- # Hence, multiplying by the denominator `divisor_den` is
- # merely an educated guess.
- @assert success "division failed"
- return eqn1, phi
- else
- error("case not recognized")
- end
-end
-
-@doc raw"""
- _compute_mwl_basis(X::EllipticSurface, mwl_gens::Vector{<:EllipticCurvePoint}) -> ZZLat, Vector{<:EllipticCurvePoint}
-
-Return a tuple `(M, B)` where `B` is an LLL-reduced basis of the sublattice `M` of the
-Mordell-Weil lattice of ``X`` generated by `mwl_gens`.
-"""
-function _compute_mwl_basis(X::EllipticSurface, mwl_gens::Vector{<:EllipticCurvePoint})
- # it would be good to have the height pairing implemented
- basis,tors, SX = _algebraic_lattice(X, mwl_gens)
- basisTriv, GTriv = trivial_lattice(X)
- r = length(basisTriv)
- l = length(mwl_gens)
- V = ambient_space(SX)
- rk = rank(V)
- G = ZZ.(gram_matrix(V))
- # project away from the trivial lattice
- pr_mwl = orthogonal_projection(V,basis_matrix(SX)[1:r, :])
- BMWL = pr_mwl.matrix[r+1:end, :]
- GB = gram_matrix(V,BMWL)
- @assert rank(GB) == rk-r
- _, u = hnf_with_transform(ZZ.(denominator(GB) * GB))
- B = u[1:rk-r,:] * BMWL
-
- MWL = lll(lattice(V, B, isbasis=false))
- u = solve(BMWL, basis_matrix(MWL); side=:left)
- u = ZZ.(u)
- mwl_basis = [sum(u[i,j] * mwl_gens[j] for j in 1:length(mwl_gens)) for i in 1:nrows(u)]
- return MWL, mwl_basis
-end
-
-function fibration_on_weierstrass_model(X::EllipticSurface)
- if !isdefined(X, :fibration_weierstrass_model)
- weierstrass_model(X) # trigger caching
- end
- return X.fibration_weierstrass_model
-end
-
-function fibration(X::EllipticSurface)
- if !isdefined(X, :fibration)
- X.fibration = compose(weierstrass_contraction(X), fibration_on_weierstrass_model(X))
- end
- return X.fibration
-end
-
-function _local_pushforward(loc_map::AbsAffineSchemeMor, I::Ideal)
- U_sub = domain(loc_map)
- E, inc_E = sub(U_sub, I) # The subscheme of the divisor
- E_simp = simplify(E) # Eliminate superfluous variables
- id, id_inv = identification_maps(E_simp)
-
- comp = compose(compose(id, inc_E), loc_map)
-
- pb = pullback(comp)
- K = kernel(pb)
- return K
-end
-
-function _pushforward_lattice_along_isomorphism(step::MorphismFromRationalFunctions{<:EllipticSurface, <:EllipticSurface})
- @assert is_isomorphism(step) "morphism must be an isomorphism"
- X = domain(step)
- Y = codomain(step)
- UX = weierstrass_chart_on_minimal_model(X)
- UY = weierstrass_chart_on_minimal_model(Y)
- @assert codomain_chart(step) === UY
- fracs = coordinate_images(step)
-
- WY, _ = weierstrass_model(Y)
- UWY = weierstrass_chart(Y)
-
- to_weierstrass_Y = morphism_from_rational_functions(X, WY, UX, UWY, fracs, check=false)
-
- fibration_proj_Y = fibration(Y)
-
- BY = codomain(fibration_proj_Y)
- UBY = codomain(covering_morphism(fibration_proj_Y)[UY])
-
- composit = morphism_from_rational_functions(X, BY, UX, UBY, [fracs[3]], check=false)
-
- lat_X = algebraic_lattice(X)[1]
- if !has_attribute(lat_X[1], :is_prime)
- ex, pt, F = irreducible_fiber(X)
- ex || error("no irreducible fiber found; case not implemented")
- lat_X[1] = weil_divisor(F)
- set_attribute!(lat_X[1], :is_prime=>true)
- set_attribute!(first(components(lat_X[1])), :is_prime=>true)
- end
-
- # We first estimate for every element in the lattic of X whether its image
- # will be a fiber component, or a (multi-)section.
- pre_select = IdDict{AbsWeilDivisor, AbsIdealSheaf}()
-
- for D in lat_X
- @assert length(components(D)) == 1 "divisors in the algebraic lattice must be prime"
- I = first(components(D))
- @assert has_is_prime(I) && is_prime(I) "ideal sheaf must be known to be prime"
- pre_select[D] = _pushforward_prime_divisor(composit, I)
- end
-
-
- # Now we map them one by one using the knowledge gained above
- result = IdDict{AbsWeilDivisor, AbsWeilDivisor}()
- co_ring = coefficient_ring(zero_section(Y))
-
- n = length(lat_X)
- mwr = rank(mordell_weil_lattice(X))
- for (i, D) in enumerate(lat_X)
- @vprint :EllipticSurface 2 "$((i, D, pre_select[D]))\n"
- # D is a non-section
- Q = pre_select[D]
- I = first(components(D))
- @vprint :EllipticSurface 2 "$(typeof(I))\n"
- dom_chart = _find_good_representative_chart(I)
- if i > n - mwr # if this is a section
- dom_chart = weierstrass_chart_on_minimal_model(X)
- end
-
- if dim(Q) == 0
- # find the fiber
- if is_one(Q(UBY)) # fiber over infinity
- # collect all components
- comps = AbsWeilDivisor[]
- for (pt, _, F, E, _) in reducible_fibers(Y)
- if is_zero(pt[2]) # if this is in the fiber over the point at ∞ ∈ ℙ¹
- append!(comps, E[2:end])
- end
- end
-
- # collect all charts
- codomain_charts = AbsAffineScheme[]
- if is_empty(comps) # The fiber over infinity
- codomain_charts = affine_charts(Y) # TODO: How can we restrict the charts then?
- else
- codomain_charts = AbsAffineScheme[V for V in affine_charts(Y) if any(D->!isone(first(components(D))(V)), comps)]
- end
-
- if i > n - mwr # If D is a section
- pt = X.MWL[i-(n-mwr)]
- res = _pushforward_section(step, pt; divisor=D, codomain_charts)
- result[D] = WeilDivisor(Y, co_ring, IdDict{AbsIdealSheaf, elem_type(co_ring)}(res::AbsIdealSheaf => one(co_ring)); check=false)
- else
- loc_map, dom_chart, cod_chart = _prepare_pushforward_prime_divisor(step, I; domain_chart = dom_chart, codomain_charts)
-
- loc_map === nothing && error("pushforward preparation did not succeed")
- K = _local_pushforward(loc_map, I(domain(loc_map)))
-
- JJ = ideal(OO(cod_chart), gens(K))
- res = PrimeIdealSheafFromChart(Y, cod_chart, JJ)
-
- result[D] = WeilDivisor(Y, co_ring, IdDict{AbsIdealSheaf, elem_type(co_ring)}(res::AbsIdealSheaf => one(co_ring)); check=false)
- end
- continue
- end
-
- # fiber over some point ≂̸ ∞.
- t = first(gens(OO(UBY)))
-
- codomain_charts = copy(affine_charts(Y))
-
- # Restrict the codomain charts if applicable
- for (i, (p, _, F, E, _)) in enumerate(reducible_fibers(Y))
- p[2] == 0 && continue # Fiber over infinity already caught above
- t0 = p[1]//p[2]
- ideal(OO(UBY), t - t0) == Q(UBY) || continue
-
- # Collect all patches
- codomain_charts = AbsAffineScheme[V for V in affine_charts(Y) if any(I->!isone(I(V)), components(F))]
- break
- end
-
- if i > n - mwr # If D is a section
- pt = X.MWL[i-(n-mwr)]
- res = _pushforward_section(step, pt; divisor=D, codomain_charts)
- result[D] = WeilDivisor(Y, co_ring, IdDict{AbsIdealSheaf, elem_type(co_ring)}(res::AbsIdealSheaf => one(co_ring)); check=false)
- else
- loc_map, dom_chart, cod_chart = _prepare_pushforward_prime_divisor(step, I; codomain_charts)
- loc_map === nothing && error("preparation for pushforward did not succeed")
-
- K = _local_pushforward(loc_map, I(domain(loc_map)))
- JJ = ideal(OO(cod_chart), gens(K))
- res = PrimeIdealSheafFromChart(Y, cod_chart, JJ)
-
- result[D] = WeilDivisor(Y, co_ring, IdDict{AbsIdealSheaf, elem_type(co_ring)}(res::AbsIdealSheaf => one(co_ring)); check=false)
- end
- else
- # "pushforward will be a section"
- if i > n - mwr # If D is a section
- pt = X.MWL[i-(n-mwr)]
- res = _pushforward_section(step, pt; divisor=D, codomain_charts=[weierstrass_chart_on_minimal_model(Y)])
- if res === nothing
- # The only section not visible in the weierstrass chart is the zero section
- result[D] = zero_section(Y)
- continue
- end
-
- result[D] = WeilDivisor(Y, co_ring, IdDict{AbsIdealSheaf, elem_type(co_ring)}(res::AbsIdealSheaf => one(co_ring)); check=false)
- else
- loc_map, dom_chart, cod_chart = _prepare_pushforward_prime_divisor(step, I, domain_chart = dom_chart, codomain_charts = [weierstrass_chart_on_minimal_model(Y)])
-
- if loc_map === nothing
- # The only section not visible in the weierstrass chart is the zero section
- result[D] = zero_section(Y)
- continue
- end
-
- K = _local_pushforward(loc_map, I(domain(loc_map)))
- JJ = ideal(OO(cod_chart), gens(K))
- res = PrimeIdealSheafFromChart(Y, cod_chart, JJ)
-
- result[D] = WeilDivisor(Y, co_ring, IdDict{AbsIdealSheaf, elem_type(co_ring)}(res::AbsIdealSheaf => one(co_ring)); check=false)
- end
- end
- end
-
- res = WeilDivisor[result[D] for D in lat_X]
- for a in res
- set_attribute!(first(components(a)), :_self_intersection, -2)
- end
- # the first one is the class of the fiber; set that one back
- set_attribute!(first(components(first(res))), :_self_intersection, 0)
- return res
-end
-
-#=
-# The map is not dominant and can hence not be realized as a MorphismFromRationalFunctions.
-# We keep the code for the moment as it will probably help us to reconstruct this map as a
-# proper CoveredSchemeMorphism, once this is needed.
-=#
-function morphism_from_section(
- X::EllipticSurface, P::EllipticCurvePoint;
- divisor::AbsWeilDivisor=_section(X, P)
- )
- U = weierstrass_chart_on_minimal_model(X)
- II = first(components(divisor))
-
- # For the zero section we can not use the Weierstrass chart
- if P.is_infinite
- return identity_map(X)
- end
- @assert !is_one(II(U))
-
- C, inc_C = sub(II)
-
- UC = domain(first(maps_with_given_codomain(inc_C, U)))
-
- B = codomain(fibration(X))
- V = codomain(fibration(X)[weierstrass_chart_on_minimal_model(X)])
-
- kkt = OO(V)::MPolyRing
- @assert ngens(kkt) == 1
- t = first(gens(kkt))
- img_gens = [evaluate(P.coordx, t), evaluate(P.coordy, t), t]
-
- Fkkt = fraction_field(kkt)
- img_gens2 = Fkkt.(img_gens)
- # TODO: Cache?
- iso = morphism_from_rational_functions(B, C, V, UC, img_gens2, check=false)
- return iso, inc_C
-end
-
-########################################################################
-# Translations by sections #
-########################################################################
-
-function translation_morphism(X::EllipticSurface, P::EllipticCurvePoint;
- divisor::AbsWeilDivisor=_section(X, P)
- )
- E = generic_fiber(X)
- @assert parent(P) === E "point does not lay on the underlying elliptic curve"
- U = weierstrass_chart_on_minimal_model(X)
- is_zero(P) && return identity_map(X)
-
- # We construct the translation by P as a morphism of rational functions
- kT = base_field(E)
- T = first(gens(kT))
-
- R = ambient_coordinate_ring(U)
- x, y, t = gens(R)
-
- a1, a2, a3, a4, a6 = [evaluate(a, t) for a in a_invariants(E)]
-
- p_x = evaluate(P[1], t)
- p_y = evaluate(P[2], t)
-
- # Formulas adapted from Hecke/src/EllCrv/EllCrv.jl
- m = (p_y - y)//(p_x - x)
- pb_x = - x - p_x - a2 + a1*m + m^2
- pb_y = - y - m*(pb_x - x) - a1*pb_x - a3
-
- F = fraction_field(R)
-
- result = morphism_from_rational_functions(X, X, U, U, F.([pb_x, pb_y, t]), check=true)
- set_attribute!(result, :is_isomorphism=>true)
- return result
-end
-
-function _pushforward_section(
- phi::MorphismFromRationalFunctions{<:EllipticSurface, <:EllipticSurface},
- P::EllipticCurvePoint;
- divisor::AbsWeilDivisor=_section(domain(phi), P),
- codomain_charts::Vector{<:AbsAffineScheme} = affine_charts(codomain(phi))
- )
- X = domain(phi)::EllipticSurface
- Y = codomain(phi)::EllipticSurface
- D = divisor
- I = first(components(D))
- iso, inc = morphism_from_section(X, P; divisor=D)
- U = weierstrass_chart_on_minimal_model(X)
- inc_loc = first(maps_with_given_codomain(inc, U))
- U_C = domain(inc_loc)
- phi_loc, _, V = _prepare_pushforward_prime_divisor(phi, I; domain_chart=U, codomain_charts)
- phi_loc === nothing && return nothing # Indicate that the given selection of codomain charts did not lead to a result
- W = codomain(fibration(X)[U])
- iso_loc = _restrict_properly(cheap_realization(iso, W, U_C), U_C)
- inc_dom_phi_loc = inclusion_morphism(domain(phi_loc))
- UU, to_U_C, to_U = fiber_product(inc_loc, inc_dom_phi_loc)
- WW, a, b = fiber_product(iso_loc, to_U_C)
- psi_loc = compose(compose(b, to_U), phi_loc)
- K = kernel(pullback(psi_loc))
- J = ideal(OO(V), gens(K))
- JJ = PrimeIdealSheafFromChart(Y, V, J)
- return JJ
-end
-
-# Find a moebius transformation which sends a given set of three points in ℙ¹ to another set
-# of three points.
-function find_moebius_transformation(
- orig_pts::Vector{<:Vector{<:FieldElem}},
- new_pts::Vector{<:Vector{<:FieldElem}}
- )
- kk = parent(first(orig_pts))
- a = [a[1] for a in orig_pts]
- b = [b[1] for b in new_pts]
- @assert all(a->isone(a[2]), orig_pts) "not implemented for non-normalized or infinite points"
- @assert all(a->isone(a[2]), new_pts) "not implemented for non-normalized or infinite points"
- return find_moebius_transformation(a, b)
-end
-
-function find_moebius_transformation(
- orig_pts::Vector{<:FieldElem},
- new_pts::Vector{<:FieldElem}
- )
- length(orig_pts) == 3 || error("exactly three points are needed")
- @assert length(orig_pts) == length(new_pts) "number of points must coincide"
- kk = parent(first(orig_pts))
- a = orig_pts
- b = new_pts
-
- # Set up the matrix mapping the first three points to 0, 1, ∞
- A = kk[(a[2] - a[3]) (-a[1]*(a[2] - a[3])); (a[2] - a[1]) (-a[3]*(a[2] - a[1]))]
-
- # Set up the matrix mapping the second three points to 0, 1, ∞
- B = kk[(b[2] - b[3]) (-b[1]*(b[2] - b[3])); (b[2] - b[1]) (-b[3]*(b[2] - b[1]))]
-
- C = inv(B)*A
- return x->(C[1,1]*x + C[1, 2], C[2,1]*x + C[2,2])
-end
-
-# Given a bivariate polynomial over a univariate function field,
-# normalize the associated elliptic curve so that the usual constructor
-# for elliptic surfaces digests it, and then return it, together with the
-# transformation on the algebraic side.
-#
-# The transformation is a morphism from the fraction field of the
-# parent of g to the fraction field of the `ambient_coordinate_ring`
-# of the `weierstrass_chart` of the resulting surface.
-function _elliptic_surface_with_trafo(g::MPolyRingElem{<:AbstractAlgebra.Generic.FracFieldElem}; minimize::Bool=true)
- x, y = gens(parent(g))
- E = elliptic_curve(g, x, y)
- kkt = base_field(E)
- kk = coefficient_ring(base_ring(kkt))
-
- FFt, t = rational_function_field(kk, :t)
-
- # The following three commands won't work unless we convert to a rational_function_field
- EE = base_change(x->evaluate(x, t), E)
- if minimize
- EE = tates_algorithm_global(EE)
- EE, _ = short_weierstrass_model(EE)
- EE, _ = integral_model(EE)
- end
-
- # ...and back.
- E2 = base_change(x->evaluate(x, gen(kkt)), EE)
-
- @assert is_isomorphic(E, E2)
- a, b, _ = rational_maps(isomorphism(E2, E))
-
- eq_E = equation(E)
- eq_E2 = equation(E2)
-
- h = evaluate(eq_E, [a, b])
- @assert divides(h, eq_E2)[1]
-
- cod = parent(a)::MPolyRing
-
- #phi = hom(R, cod, cod.([a, b]))
- #Phi = extend_domain_to_fraction_field(phi)
-
- result = elliptic_surface(E2, 2)
- W = weierstrass_chart(result)
- R = ambient_coordinate_ring(W)
- FR = fraction_field(R)
-
- help_map = hom(cod, FR, t->evaluate(t, FR(R[3])), FR.([R[1], R[2]]))
- A = help_map(a)
- B = help_map(b)
-
- res_map = hom(parent(g), FR, t->evaluate(t, FR(R[3])), [A, B])
- return result, extend_domain_to_fraction_field(res_map)
-end
-
-# Given two abstractly isomorphic elliptic surfaces X and Y over ℙ¹,
-# find all moebius transformation of the base which preserve the critical
-# values of the projections, try to lift them to morphisms X -> Y and
-# return the list of such morphisms for which the lift was successful.
-function admissible_moebius_transformations(
- X::EllipticSurface,
- Y::EllipticSurface
- )
- EX = generic_fiber(X)
- EY = generic_fiber(Y)
-
-# kkt = base_field(EX)
-# @assert kkt === base_field(EY) "base fields of the generic fibers must coincide"
- kk = base_ring(X)
- @assert kk === base_ring(Y) "elliptic surfaces must be defined over the same field"
-
- dX = numerator(discriminant(EX))::PolyRingElem
- dY = numerator(discriminant(EY))::PolyRingElem
-
- vX = roots(dX)
- @assert all(is_one(degree(a)) for (a, k) in factor(dX)) "not all critical values are rational over the given ground field"
-
- vY = roots(dY)
- @assert all(is_one(degree(a)) for (a, k) in factor(dY)) "not all critical values are rational over the given ground field"
-
- for (c, _) in reducible_fibers(X)
- @assert !is_zero(c[2]) "the case of reducible fibers over the point at infinity is not implemented"
- end
- for (c, _) in reducible_fibers(Y)
- @assert !is_zero(c[2]) "the case of reducible fibers over the point at infinity is not implemented"
- end
-
- # Use the first three elements of vX and map them to three elements of vY.
- # Then check whether the resulting transformation preserves everything.
-
- candidates = Function[]
-
- @assert length(vX) >= 3 "at least three reducible fibers are needed"
- length(vX) == length(vY) || return candidates # No moebius transformation is possible in this case
-
- p1 = vX[1:3]
- for i in vY
- for j in vY
- i == j && continue
- for k in vY
- (i == k || j == k) && continue
- p2 = [i, j, k]
- mt = find_moebius_transformation(p1, p2)
- any(is_zero(mt(x)[2]) for x in vX) && continue # reducible fibers over ∞ are not implemented at the moment.
- any(!(mt(x)[1]//mt(x)[2] in vY) for x in vX) && continue # the transformation does not preserve all admissible fibers in this case
- push!(candidates, mt)
- end
- end
- end
-
- result = MorphismFromRationalFunctions[]
-
- # Set up some variables
- kkt = base_field(EX)
- t = gen(kkt)
- WX = weierstrass_chart_on_minimal_model(X)
- RX = ambient_coordinate_ring(WX)
- FRX = fraction_field(RX)
- WY = weierstrass_chart_on_minimal_model(Y)
- RY = ambient_coordinate_ring(WY)
- FRY = fraction_field(RY)
-
- # Go through the candidates again and for those which do indeed lead to isomorphic
- # surfaces, construct the isomorphism.
- for mt in candidates
- p, q = mt(t)
- img_t = (p//q)::typeof(t)
- EYbc = base_change(f->evaluate(f, img_t), EY)
- is_isomorphic(EYbc, EX) || continue
- # Construct the isomorphism of elliptic surfaces explicitly
- iso_ell = isomorphism(EX, EYbc)
-
- a, b, _ = rational_maps(iso_ell)
- kkTxy = parent(a)
- to_FRX = hom(kkTxy, FRX, x->evaluate(x, FRX(RX[3])), FRX.([RX[1], RX[2]]))
- A = to_FRX(a)
- B = to_FRX(b)
- P, Q = mt(FRX(RX[3]))
- img_T = (P//Q)::elem_type(FRX)
- img_gens = [A, B, img_T]
- loc_res = morphism_from_rational_functions(X, Y, WX, WY, img_gens; check=true)
- set_attribute!(loc_res, :is_isomorphism=>true)
- push!(result, loc_res)
- end
-
- return result
-end
-
-# An internal helper routine to verify that a given isomorphism of elliptic surfaces
-# does indeed give an isomorphism on their generic fibers.
-function check_isomorphism_on_generic_fibers(phi::MorphismFromRationalFunctions{<:EllipticSurface, <:EllipticSurface})
- X = domain(phi)
- Y = codomain(phi)
- @assert domain_chart(phi) === weierstrass_chart_on_minimal_model(X)
- @assert codomain_chart(phi) === weierstrass_chart_on_minimal_model(Y)
- EX = generic_fiber(X)
- EY = generic_fiber(Y)
- a, b, c = coordinate_images(phi)
-
- hX = equation(EX)
- RX = parent(hX)
- FX = fraction_field(RX)
- kktX = coefficient_ring(RX)
-
- hY = equation(EY)
- RY = parent(hY)
- FY = fraction_field(RY)
- kktY = coefficient_ring(RY)
-
- A = evaluate(a, [RX[1], RX[2], RX(gen(kktX))])
- B = evaluate(b, [RX[1], RX[2], RX(gen(kktX))])
- C = evaluate(c, [RX[1], RX[2], RX(gen(kktX))])
-
- help_map = hom(RY, FX, t->evaluate(t, C), [A, B])
-
- hh = help_map(hY)
-
- return divides(hX, numerator(hh))[1]
-end
-
-function isomorphism_from_generic_fibers(
- X::EllipticSurface, Y::EllipticSurface, f::Hecke.EllCrvIso
- )
- EX = generic_fiber(X)
- EY = generic_fiber(Y)
- iso_ell = f
- @req domain(f) == EX "must be an isomorphism of the generic fibers"
- @req codomain(f) == EY "must be an isomorphism of the generic fibers"
- a, b, _ = rational_maps(iso_ell)
- kt = base_field(EX)
- t = gen(kt)
-
- # Make sure we got something reasonable
- h2 = equation(EY)
- pb_h2 = evaluate(h2, [a, b])
- @assert divides(pb_h2, equation(parent(pb_h2), EX))[1]
-
- WX = weierstrass_chart_on_minimal_model(X)
- RX = ambient_coordinate_ring(WX)
- FRX = fraction_field(RX)
- WY = weierstrass_chart_on_minimal_model(Y)
- RY = ambient_coordinate_ring(WY)
- FRY = fraction_field(RY)
-
- kkTxy = parent(a)
- to_FRX = hom(kkTxy, FRX, x->evaluate(x, FRX(RX[3])), FRX.([RX[1], RX[2]]))
- A = to_FRX(a)
- B = to_FRX(b)
- img_gens = [A, B, FRX(RX[3])]
- m = morphism_from_rational_functions(X, Y, WX, WY, FRX.(img_gens); check=false)
- set_attribute!(m, :is_isomorphism=>true)
- return m
-end
-
-# Given two elliptic surfaces X and Y with abstractly isomorphic generic
-# fibers, construct the corresponding isomorphism X -> Y.
-function isomorphism_from_generic_fibers(
- X::EllipticSurface, Y::EllipticSurface
- )
- EX = generic_fiber(X)
- EY = generic_fiber(Y)
- is_isomorphic(EX, EY) || error("generic fibers are not isomorphic")
- iso_ell = isomorphism(EX, EY)
- return isomorphism_from_generic_fibers(X, Y, iso_ell)
-end
-
-
-"""
- pushforward_on_algebraic_lattices(f::MorphismFromRationalFunctions{<:EllipticSurface, <:EllipticSurface}) -> QQMatrix
-
-Return the pushforward `f_*: V_1 -> V_2` where `V_i` is the ambient quadratic space of the `algebraic_lattice`.
-
-This assumes that the image `f_*(V_1)` is contained in `V_2`. If this is not the case, you will get
-``f_*`` composed with the orthogonal projection to `V_2`.
-"""
-function pushforward_on_algebraic_lattices(f::MorphismFromRationalFunctions{<:EllipticSurface, <:EllipticSurface})
- imgs_divs = _pushforward_lattice_along_isomorphism(f)
- M = matrix([basis_representation(codomain(f),i) for i in imgs_divs])
- V1 = ambient_space(algebraic_lattice(domain(f))[3])
- V2 = ambient_space(algebraic_lattice(codomain(f))[3])
- # keep the check on since it is simple compared to all the other computations done here
- fstar = hom(V1,V2, M; check=true)
- return fstar
-end
-
-# Given an irreducible divisor D on an elliptic surface X, try to extract a point
-# on the generic fiber from it. The return value is `nothing` in case this does not succeed.
-function point_on_generic_fiber_from_divisor(I::AbsIdealSheaf{<:EllipticSurface}; check::Bool=true)
- X = scheme(I)
- @check dim(I) == 1 "ideal sheaf must be of dimension one"
- return point_on_generic_fiber_from_divisor(WeilDivisor(X, I; check=false); check)
-end
-
-function point_on_generic_fiber_from_divisor(D::AbsWeilDivisor{<:EllipticSurface}; check::Bool=true)
- X = ambient_scheme(D)
- E = generic_fiber(X)
- ex, pt, F = irreducible_fiber(X)
- WF = weil_divisor(F)
- # TODO: Also cover this case by considering the class of a reducible fiber?
- !ex && error("no irreducible fiber exists on this algebraic surface")
- @assert length(components(D)) == 1 "divisor must be irreducible"
-
- I = first(components(D))
- fib = fibration(X)
-
- # Check a necessary criterion for being a section
- # J = pushforward(fib, I)
- # is_one(dim(J)) || return nothing
- is_zero(intersect(D, WF)) && return nothing
-# @check begin
-# J = pushforward(fib, I)
-# is_one(dim(J))
-# end "given divisor can not be a section"
-
- #@check is_one(intersect(D, WF)) "intersection number with irreducible fiber is not one"
-
- WX = weierstrass_chart_on_minimal_model(X)
- IWX = I(WX)
- is_one(IWX) && return infinity(E) # Point must be the zero section
- R = ambient_coordinate_ring(WX)
- (x, y, t) = gens(R)
-
- # In case of a multisection do some extra preparation; see below.
- !is_one(intersect(D, WF)) && return point_on_generic_fiber_from_divisor(_prepare_section(D))
-
- g = gens(groebner_basis(saturated_ideal(IWX), ordering=lex(gens(R))))
-
- # extract the coefficients for the section
- kkt = base_field(E)
-
- # First extract the y-coordinate
- i = findfirst(f->(is_zero(degree(f, 1)) && is_one(degree(f, 2))), g)
- i === nothing && return nothing
- #i === nothing && error("no suitable polynomial found to read off point coordinates")
- f = g[i]
- y_coord = one(kkt)
- ev_vals = [zero(kkt), one(kkt), gen(kkt)]
- num = zero(kkt)
- den = zero(kkt)
- for t in terms(f)
- degree(t, 2) == 1 && (den = den - evaluate(t, ev_vals))
- degree(t, 2) == 0 && (num = num + evaluate(t, ev_vals))
- end
- y_coord = num//den
-
- # Now extract the x-coordinate
- i = findfirst(f->(is_one(degree(f, 1))), g)
- i === nothing && return nothing
- #i === nothing && error("no suitable polynomial found to read off point coordinates")
- f = g[i]
- x_coord = one(kkt)
- ev_vals = [one(kkt), y_coord, gen(kkt)]
- num = zero(kkt)
- den = zero(kkt)
- for t in terms(f)
- degree(t, 1) == 1 && (den = den - evaluate(t, ev_vals))
- degree(t, 1) == 0 && (num = num + evaluate(t, ev_vals))
- end
- x_coord = num//den
-
- is_zero(evaluate(equation(E), [x_coord, y_coord])) || return nothing
- #@assert is_zero(evaluate(equation(E), [x_coord, y_coord])) "esteemed point does not lie on the curve"
- P = E([x_coord, y_coord])
- return P
-end
-
-# Given an isomorphism phi : X -> Y of elliptic surfaces and a full algebraic lattice L on X,
-# push forward the divisors D from L to Y and try to extract points on the generic fiber from
-# them.
-#
-# This returns a list consisting of the points on the generic fiber.
-function extract_mordell_weil_basis(phi::MorphismFromRationalFunctions{<:EllipticSurface, <:EllipticSurface})
- X = domain(phi)
- Y = codomain(phi)
- is_isomorphism(phi) || error("morphism must be an isomorphism")
- pf_lat = _pushforward_lattice_along_isomorphism(phi)
- points = EllipticCurvePoint[]
- for D in pf_lat
- P = point_on_generic_fiber_from_divisor(D)
- P === nothing && continue
- push!(points, P)
- end
- return points
-end
-
-function _prepare_section(D::AbsWeilDivisor{<:EllipticSurface})
- X = ambient_scheme(D)
- WX = weierstrass_chart_on_minimal_model(X)
- R = ambient_coordinate_ring(WX)
- I = first(components(D))
- IWX = I(WX)
- # We have a multisection in this case.
- # To get a section from it, apply arXiv:2103.15101, Algorithm 1.
-
- # Build up a helper ring
- kkt = base_field(generic_fiber(X))
- f = equation(generic_fiber(X))
- kktXY = parent(f)
- (xx, yy) = gens(kktXY)
- for (c, e) in zip(coefficients(f), exponents(f))
- if e == [0, 2]
- @assert is_one(c) "polynomial is not normalized"
- end
- end
- f = yy^2 - f # prepare the f from the Lemma
- #kktXY, (xx, yy) = polynomial_ring(kkt, [:X, :Y]; cached=false)
-
- @assert coefficient_ring(R) === coefficient_ring(base_ring(kkt))
- help_map = hom(R, kktXY, [xx, yy, kktXY(gen(kkt))])
-
- J = ideal(kktXY, help_map.(gens(saturated_ideal(IWX))))
-
- J_gens = gens(groebner_basis(J, ordering=lex([yy, xx])))
- i = findfirst(f->degree(f, 2) == 0, J_gens)
- i === nothing && error("assertion of Lemma could not be verified")
- g = J_gens[i]
- i = findfirst(f->degree(f, 2) == 1, J_gens)
- i === nothing && error("assertion of Lemma could not be verified")
- h = J_gens[i]
- c = zero(kkt)
- for t in terms(h)
- if degree(t, 2) == 1
- c = c + evaluate(t, [zero(kkt), one(kkt)])
- end
- end
- !isone(c) && (h = inv(c)*h)
- h = yy - h
- @assert J == ideal(kktXY, [g, yy-h])
- ff = equation(kktXY, generic_fiber(X))
- @assert parent(ff) === parent(f)
- @assert ff == yy^2 - f
- while total_degree(g) > 1
- g = divexact(h^2 - f, g)
- p, q = divrem(h, g)
- h = q
- end
-
- F = fraction_field(R)
- help_map_back = hom(kktXY, F, u->evaluate(u, F(R[3])), F.([R[1], R[2]]))
- new_gens = [help_map_back(g), help_map_back(yy - h)]
- sec_ideal = ideal(OO(WX), numerator.(new_gens))
- @assert dim(sec_ideal) == 1
- @assert is_prime(sec_ideal)
-
- # overwrite the local variables
- I = PrimeIdealSheafFromChart(X, WX, sec_ideal)
- return weil_divisor(I)
-end
-
-# internal method used for two neighbor steps
-# in the horizontal_decomposition
-function _vertical_part(X::EllipticSurface, v::QQMatrix)
- @req nrows(v)==1 "not a row vector"
- _,tors, NS = algebraic_lattice(X)
- E = generic_fiber(X)
- @req ncols(v)==degree(NS) "vector of wrong size $(ncols(v))"
- @req v in NS "not an element of the lattice"
- mwl_rank = length(X.MWL)
- rk_triv = rank(NS)-mwl_rank
- n = rank(NS)
- P = sum([ZZ(v[1,i])*X.MWL[i-rk_triv] for i in (rk_triv+1):n], init = E([0,1,0]))
- p = zero_matrix(QQ, 1, rank(NS)) # the section part
- p[1,end-mwl_rank+1:end] = v[1,end-mwl_rank+1:end]
- p[1,2] = 1 - sum(p) # assert p.F = 1 by adding a multiple of the zero section O
-
- # P meets exactly one fiber component per fiber
- # and that one must be simple, it can be the one meeting O or not
- # assert this by adding fiber components under the additional condition that p stays in the algebraic lattice
- simples = []
- E = identity_matrix(QQ,rank(NS))
- z = zero_matrix(QQ,1, rank(NS))
- r = 2
- for fiber in _trivial_lattice(X)[3]
- fiber_type = fiber[2]
- fiber_rk = fiber_type[2]
- h = highest_root(fiber_type...)
- simple_indices = [r+i for i in 1:ncols(h) if isone(h[1,i])]
- simple_or_zero = [E[i:i,:] for i in simple_indices]
- push!(simple_or_zero, z)
- push!(simples,simple_or_zero)
- r += fiber_rk
- end
- G = gram_matrix(ambient_space(NS))
- pG = (p*G)[1:1,3:r]
- T = Tuple(simples)
- GF = G[3:r,3:r]
- candidates = QQMatrix[]
- for s in Base.Iterators.ProductIterator(T)
- g = sum(s)[:,3:r]
- y = (g - pG)
- xx = solve(GF,y;side=:left)
- x = zero_matrix(QQ,1, rank(NS))
- x[:,3:r] = xx
- if x in NS
- push!(candidates,p+x)
- end
- end
- @assert length(candidates)>0
- # Select the candidate congruent to v modulo Triv
- mwg = _mordell_weil_group(X)
- vmwg = mwg(vec(collect(v)))
- candidates2 = [mwg(vec(collect(x))) for x in candidates]
- i = findfirst(==(vmwg), candidates2)
- t = mwg(vec(collect(p - candidates[i])))
- mwl_tors_gens = [mwg(vec(collect(i[2]))) for i in tors]
- ag = abelian_group(zeros(ZZ,length(tors)))
- mwlAb = abelian_group(mwg)
- phi = hom(ag, mwlAb, mwlAb.(mwl_tors_gens))
- a = preimage(phi, mwlAb(t))
- for i in 1:ngens(ag)
- P += a[i]*get_attribute(tors[i][1],:point)
- end
-
- p = candidates[i]
- k = (p*G*transpose(p))[1,1]
- # assert p^2 = -2
- p[1,1] = -k/2-1
- V = ambient_space(NS)
- @hassert :EllipticSurface 1 inner_product(V, p, p)[1,1]== -2
- @hassert :EllipticSurface 1 mwg(vec(collect(p))) == mwg(vec(collect(p)))
- @hassert :EllipticSurface 3 basis_representation(X,section(X,P))==vec(collect(p))
- return p, P
-end
-
-function _vertical_part(X::EllipticSurface, v::Vector{QQFieldElem})
- vv = matrix(QQ,1,length(v),v)
- p, P = _vertical_part(X,vv)
- pp = vec(collect(p))
- return pp, P
-end
-
-# TODO: Instead return an abelian group A and two maps.
-# algebraic_lattice -> A
-# A -> MWL= E(k(t))
-function _mordell_weil_group(X)
- N = algebraic_lattice(X)[3]
- V = ambient_space(N)
- t = nrows(trivial_lattice(X)[2])
- Triv = lattice(V, identity_matrix(QQ,dim(V))[1:t,:])
- return torsion_quadratic_module(N, Triv;modulus=1, modulus_qf=1, check=false)
-end
diff --git a/experimental/SetPartitions/src/SetPartition.jl b/experimental/SetPartitions/src/SetPartition.jl
index dab1433dc8d7..3bb6a44ec548 100644
--- a/experimental/SetPartitions/src/SetPartition.jl
+++ b/experimental/SetPartitions/src/SetPartition.jl
@@ -84,6 +84,7 @@ julia> lower_points(set_partition([2, 4], [4, 99]))
2-element Vector{Int64}:
2
3
+```
"""
function lower_points(p::SetPartition)
return p.lower_points
diff --git a/gap/OscarInterface/PackageInfo.g b/gap/OscarInterface/PackageInfo.g
index 975c342cf939..651dee91d3ea 100644
--- a/gap/OscarInterface/PackageInfo.g
+++ b/gap/OscarInterface/PackageInfo.g
@@ -10,8 +10,8 @@ SetPackageInfo( rec(
PackageName := "OscarInterface",
Subtitle := "GAP interface to OSCAR",
-Version := "1.2.0-DEV",
-Date := "18/06/2024", # dd/mm/yyyy format
+Version := "1.3.0-DEV",
+Date := "30/10/2024", # dd/mm/yyyy format
License := "GPL-2.0-or-later",
Persons := [
diff --git a/src/AlgebraicGeometry/AlgebraicGeometry.jl b/src/AlgebraicGeometry/AlgebraicGeometry.jl
index 9e8392363439..09c30e3ce922 100644
--- a/src/AlgebraicGeometry/AlgebraicGeometry.jl
+++ b/src/AlgebraicGeometry/AlgebraicGeometry.jl
@@ -8,6 +8,11 @@ include("Surfaces/K3Auto.jl")
include("Surfaces/AdjunctionProcess/AdjunctionProcess.jl")
include("Surfaces/ParaRatSurfaces/ParametrizationSurfaces.jl")
include("Surfaces/SurfacesP4.jl")
+include("Surfaces/EllipticSurface/Types.jl")
+include("Surfaces/EllipticSurface/EllipticSurface.jl")
+include("Surfaces/EllipticSurface/NeighborStep.jl")
+include("Surfaces/EllipticSurface/Morphisms.jl")
+include("Surfaces/EllipticSurface/MoveMeToHecke.jl")
include("RationalPoint/Types.jl")
include("RationalPoint/PointSet.jl")
include("RationalPoint/AffineRationalPoint.jl")
diff --git a/src/AlgebraicGeometry/Schemes/AffineSchemes/Objects/Attributes.jl b/src/AlgebraicGeometry/Schemes/AffineSchemes/Objects/Attributes.jl
index dd775e171fad..2d48a7f2ebfb 100644
--- a/src/AlgebraicGeometry/Schemes/AffineSchemes/Objects/Attributes.jl
+++ b/src/AlgebraicGeometry/Schemes/AffineSchemes/Objects/Attributes.jl
@@ -399,52 +399,14 @@ julia> dim(Y) # one dimension comes from ZZ and two from x1 and x2
3
```
"""
-dim(X::AbsAffineScheme)
-
-@attr Any function dim(X::AbsAffineScheme{<:Ring, <:MPolyQuoLocRing})
- error("Not implemented")
-end
-
-@attr Any function dim(X::AbsAffineScheme{<:Ring, <:MPolyQuoLocRing{<:Any,<:Any,<:MPolyRing,<:MPolyRingElem, <:MPolyPowersOfElement}})
- return dim(closure(X))
-end
-
-@attr Any function dim(X::AbsAffineScheme{<:Ring, <:MPolyQuoLocRing{<:Any,<:Any,<:MPolyRing,<:MPolyRingElem, <:Union{MPolyComplementOfPrimeIdeal, MPolyComplementOfKPointIdeal}}})
- # Spec (R / I)_P
- R = OO(X)
- P = prime_ideal(inverted_set(R))
- I = saturated_ideal(modulus(R))
- return dim(I) - dim(P)
-end
-
-@attr Any function dim(X::AbsAffineScheme{<:Ring, <:MPolyLocRing})
- error("Not implemented")
-end
-
-@attr Any function dim(X::AbsAffineScheme{<:Ring, <:MPolyLocRing{<:Any,<:Any,<:MPolyRing,<:MPolyRingElem, <:MPolyPowersOfElement}})
- # zariski open subset of A^n
- return dim(closure(X))
-end
-
-@attr Any function dim(X::AbsAffineScheme{<:Ring, <:MPolyLocRing{<:Any,<:Any,<:MPolyRing,<:MPolyRingElem, <:Union{MPolyComplementOfPrimeIdeal, MPolyComplementOfKPointIdeal}}})
- P = prime_ideal(inverted_set(OO(X)))
- return codim(P)
-end
-
-@attr Any function dim(X::AbsAffineScheme{<:Ring, <:MPolyRing})
- return dim(ideal(ambient_coordinate_ring(X), [zero(ambient_coordinate_ring(X))]))
-end
-
-@attr Any function dim(X::AbsAffineScheme{<:Ring, <:MPolyQuoRing})
- return dim(modulus(OO(X)))
-end
+dim(X::AbsAffineScheme) = dim(OO(X))
@doc raw"""
codim(X::AbsAffineScheme)
Return the codimension of ``X`` in its ambient affine space.
-Throws and error if ``X`` does not have an ambient affine space.
+Throws an error if ``X`` does not have an ambient affine space.
# Examples
```jldoctest
diff --git a/src/AlgebraicGeometry/Schemes/AffineSchemes/Objects/Methods.jl b/src/AlgebraicGeometry/Schemes/AffineSchemes/Objects/Methods.jl
index 724c56802dcf..6319cd4d9887 100644
--- a/src/AlgebraicGeometry/Schemes/AffineSchemes/Objects/Methods.jl
+++ b/src/AlgebraicGeometry/Schemes/AffineSchemes/Objects/Methods.jl
@@ -473,3 +473,8 @@ function _change_base_ring(phi::Any,
@assert _has_coefficient_map(res_map)
return L_red, res_map
end
+
+function Base.hash(X::Scheme, u::UInt)
+ return u
+end
+
diff --git a/experimental/Schemes/src/BlowupMorphism.jl b/src/AlgebraicGeometry/Schemes/BlowupMorphism/BlowupMorphism.jl
similarity index 97%
rename from experimental/Schemes/src/BlowupMorphism.jl
rename to src/AlgebraicGeometry/Schemes/BlowupMorphism/BlowupMorphism.jl
index 9498e0586c56..17b72a3f9462 100644
--- a/experimental/Schemes/src/BlowupMorphism.jl
+++ b/src/AlgebraicGeometry/Schemes/BlowupMorphism/BlowupMorphism.jl
@@ -1,8 +1,3 @@
-export BlowupMorphism
-export center
-export exceptional_divisor
-export projection
-
########################################################################
# `AbsDesingMor` and `AbsBlowupMorphism`
#
@@ -644,18 +639,18 @@ function produce_object_on_affine_chart(I::StrictTransformIdealSheaf, U::AbsAffi
f_loc = covering_morphism(f)[U]
V = codomain(f_loc)
IE_loc = IE(U)
- @assert isone(ngens(IE_loc)) "ideal sheaf of exceptional locus is not principal"
- tot = pullback(f_loc)(J(V))
- #return saturation_with_index(tot, IE_loc)
# It is usually better to pass to the simplified covering to do the computations
simp_cov = simplified_covering(X)
U_simp = first([V for V in patches(simp_cov) if original(V) === U])
a, b = identification_maps(U_simp)
- # This used to be the following line. But we don't use the index, so we
- # switch to the more performant version
- # result, _ = saturation_with_index(pullback(a)(tot), pullback(a)(IE_loc))
- result = _iterative_saturation(pullback(a)(tot), elem_type(OO(U_simp))[pullback(a)(u) for (u, _) in factor(lifted_numerator(first(gens(IE_loc))))])
- return pullback(b)(result)
+ tot = pullback(f_loc)(J(V))
+ if isone(ngens(IE_loc))
+ result = _iterative_saturation(pullback(a)(tot), elem_type(OO(U_simp))[pullback(a)(u) for (u, _) in factor(lifted_numerator(first(gens(IE_loc))))])
+ return pullback(b)(result)
+ else
+ result, _ = saturation_with_index(pullback(a)(tot), pullback(a)(IE_loc))
+ return result
+ end
end
@attr Bool function is_prime(I::StrictTransformIdealSheaf)
diff --git a/experimental/Schemes/src/BlowupMorphismTypes.jl b/src/AlgebraicGeometry/Schemes/BlowupMorphism/Types.jl
similarity index 100%
rename from experimental/Schemes/src/BlowupMorphismTypes.jl
rename to src/AlgebraicGeometry/Schemes/BlowupMorphism/Types.jl
diff --git a/experimental/Schemes/src/CoveredProjectiveSchemes.jl b/src/AlgebraicGeometry/Schemes/CoveredProjectiveScheme/CoveredProjectiveScheme.jl
similarity index 100%
rename from experimental/Schemes/src/CoveredProjectiveSchemes.jl
rename to src/AlgebraicGeometry/Schemes/CoveredProjectiveScheme/CoveredProjectiveScheme.jl
diff --git a/src/AlgebraicGeometry/Schemes/CoveredProjectiveScheme/Types.jl b/src/AlgebraicGeometry/Schemes/CoveredProjectiveScheme/Types.jl
new file mode 100644
index 000000000000..40656fff78d7
--- /dev/null
+++ b/src/AlgebraicGeometry/Schemes/CoveredProjectiveScheme/Types.jl
@@ -0,0 +1,178 @@
+abstract type AbsProjectiveGluing{
+ GluingType<:AbsGluing,
+ }
+end
+
+@doc raw"""
+ LazyProjectiveGluing(
+ X::AbsProjectiveScheme,
+ Y::AbsProjectiveScheme,
+ BG::AbsGluing,
+ compute_function::Function,
+ gluing_data
+ )
+
+Produce a container `pg` to host a non-computed `ProjectiveGluing` of ``X`` with ``Y``.
+
+The arguments consist of
+
+ * the patches ``X`` and ``Y`` to be glued;
+ * a gluing `BG` of the `base_scheme`s of ``X`` and ``Y`` over which the
+ `ProjectiveGluing` to be computed sits;
+ * a function `compute_function` which takes a single argument `gluing_data`
+ of arbitrary type and actually carries out the computation;
+ * an arbitrary struct `gluing_data` that the user can fill with whatever
+ information is needed to properly feed their `compute_function`.
+
+The container `pg` can then be stored as the gluing of ``X`` and ``Y``. As soon
+as it is asked about any data on the gluing beyond its two `patches`, it will
+invoke the internally stored `compute_function` to actually carry out the computation
+of the gluing and then serve the incoming request on the basis of that result.
+The latter actual `ProjectiveGluing` will then be cached.
+"""
+mutable struct LazyProjectiveGluing{
+ GluingType<:AbsGluing,
+ GluingDataType
+ } <: AbsProjectiveGluing{GluingType}
+ base_gluing::GluingType
+ patches::Tuple{AbsProjectiveScheme, AbsProjectiveScheme}
+ compute_function::Function
+ gluing_data::GluingDataType
+ underlying_gluing::AbsProjectiveGluing
+
+ function LazyProjectiveGluing(
+ X::AbsProjectiveScheme,
+ Y::AbsProjectiveScheme,
+ BG::AbsGluing,
+ compute_function::Function,
+ gluing_data
+ )
+ (base_scheme(X), base_scheme(Y)) == patches(BG) || error("gluing is incompatible with provided patches")
+ return new{typeof(BG), typeof(gluing_data)}(BG, (X, Y), compute_function, gluing_data)
+ end
+end
+
+@doc raw"""
+ ProjectiveGluing(
+ G::GluingType,
+ incP::IncType, incQ::IncType,
+ f::IsoType, g::IsoType;
+ check::Bool=true
+ ) where {GluingType<:AbsGluing, IncType<:ProjectiveSchemeMor, IsoType<:ProjectiveSchemeMor}
+
+The `AbsProjectiveSchemeMorphism`s `incP` and `incQ` are open embeddings over open
+embeddings of their respective `base_scheme`s.
+
+ PX ↩ PU ≅ QV ↪ QY
+ π ↓ ↓ ↓ ↓ π
+ G : X ↩ U ≅ V ↪ Y
+
+This creates a gluing of the projective schemes `codomain(incP)` and `codomain(incQ)`
+over a gluing `G` of their `base_scheme`s along the morphisms of `AbsProjectiveScheme`s
+`f` and `g`, identifying `domain(incP)` and `domain(incQ)`, respectively.
+"""
+mutable struct ProjectiveGluing{
+ GluingType<:AbsGluing,
+ IsoType1<:ProjectiveSchemeMor,
+ IncType1<:ProjectiveSchemeMor,
+ IsoType2<:ProjectiveSchemeMor,
+ IncType2<:ProjectiveSchemeMor,
+ } <: AbsProjectiveGluing{GluingType}
+ G::GluingType # the underlying gluing of the base schemes
+ inc_to_P::IncType1
+ inc_to_Q::IncType2
+ f::IsoType1
+ g::IsoType2
+
+ ###
+ # Given two relative projective schemes and a gluing
+ #
+ # PX ↩ PU ≅ QV ↪ QY
+ # π ↓ ↓ ↓ ↓ π
+ # G : X ↩ U ≅ V ↪ Y
+ #
+ # this constructs the gluing of PX and QY along
+ # their open subsets PU and QV, given the two inclusions
+ # and isomorphisms over the gluing G in the base schemes.
+ function ProjectiveGluing(
+ G::GluingType,
+ incP::IncType1, incQ::IncType2,
+ f::IsoType1, g::IsoType2;
+ check::Bool=true
+ ) where {GluingType<:AbsGluing, IncType1<:ProjectiveSchemeMor,IncType2<:ProjectiveSchemeMor, IsoType1<:ProjectiveSchemeMor, IsoType2<:ProjectiveSchemeMor}
+ (X, Y) = patches(G)
+ (U, V) = gluing_domains(G)
+ @vprint :Gluing 1 "computing projective gluing\n"
+ @vprint :Gluing 2 "$(X), coordinates $(ambient_coordinates(X))\n"
+ @vprint :Gluing 2 "and\n"
+ @vprint :Gluing 2 "$(Y) coordinates $(ambient_coordinates(X))\n"
+ (fb, gb) = gluing_morphisms(G)
+ (PX, QY) = (codomain(incP), codomain(incQ))
+ (PU, QV) = (domain(incP), domain(incQ))
+ (base_scheme(PX) === X && base_scheme(QY) === Y) || error("base gluing is incompatible with the projective schemes")
+ domain(f) === codomain(g) === PU && domain(g) === codomain(f) === QV || error("maps are not compatible")
+ SPU = homogeneous_coordinate_ring(domain(f))
+ SQV = homogeneous_coordinate_ring(codomain(f))
+ @check begin
+ # check the commutativity of the pullbacks
+ all(y->(pullback(f)(SQV(OO(V)(y))) == SPU(pullback(fb)(OO(V)(y)))), gens(base_ring(OO(Y)))) || error("maps do not commute")
+ all(x->(pullback(g)(SPU(OO(U)(x))) == SQV(pullback(gb)(OO(U)(x)))), gens(base_ring(OO(X)))) || error("maps do not commute")
+ fc = map_on_affine_cones(f, check=false)
+ gc = map_on_affine_cones(g, check=false)
+ idCPU = compose(fc, gc)
+ idCPU == identity_map(domain(fc)) || error("composition of maps is not the identity")
+ idCQV = compose(gc, fc)
+ idCQV == identity_map(domain(gc)) || error("composition of maps is not the identity")
+ # idPU = compose(f, g)
+ # all(t->(pullback(idPU)(t) == t), gens(SPU)) || error("composition of maps is not the identity")
+ # idQV = compose(g, f)
+ # all(t->(pullback(idQV)(t) == t), gens(SQV)) || error("composition of maps is not the identity")
+ end
+ @vprint :Gluing 1 "done computing the projective gluing\n"
+ return new{GluingType, IsoType1, IncType1, IsoType2, IncType2}(G, incP, incQ, f, g)
+ end
+end
+
+### Proper schemes π : Z → X over a covered base scheme X
+#
+# When {Uᵢ} is an affine covering of X, the datum stored
+# consists of a list of projective schemes
+#
+# Zᵢ ⊂ ℙʳ⁽ⁱ⁾(𝒪(Uᵢ)) → Uᵢ
+#
+# with varying ambient spaces ℙʳ⁽ⁱ⁾(𝒪(Uᵢ)) and a list of
+# identifications (transitions)
+#
+# Zᵢ ∩ π⁻¹(Uⱼ) ≅ Zⱼ ∩ π⁻¹(Uᵢ)
+#
+# of projective schemes over Uᵢ∩ Uⱼ for all pairs (i,j).
+#
+# These structs are designed to accommodate blowups of
+# covered schemes along arbitrary centers, as well as
+# projective bundles.
+
+@attributes mutable struct CoveredProjectiveScheme{BRT} <: Scheme{BRT}
+ Y::AbsCoveredScheme # the base scheme
+ BC::Covering # the reference covering of the base scheme
+ patches::IdDict{AbsAffineScheme, AbsProjectiveScheme} # the projective spaces over the affine patches in the base covering
+ gluings::IdDict{Tuple{AbsAffineScheme, AbsAffineScheme}, AbsProjectiveGluing} # the transitions sitting over the affine patches in the gluing domains of the base scheme
+
+ function CoveredProjectiveScheme(
+ Y::AbsCoveredScheme,
+ C::Covering,
+ projective_patches::IdDict{AbsAffineScheme, AbsProjectiveScheme},
+ projective_gluings::IdDict{Tuple{AbsAffineScheme, AbsAffineScheme}, AbsProjectiveGluing};
+ check::Bool=true
+ )
+ C in coverings(Y) || error("covering not listed")
+ for P in values(projective_patches)
+ any(x->x===base_scheme(P), patches(C)) || error("base scheme not found in covering")
+ end
+ for (U, V) in keys(gluings(C))
+ (U, V) in keys(projective_gluings) || error("not all projective gluings were provided")
+ end
+ return new{base_ring_type(Y)}(Y, C, projective_patches, projective_gluings)
+ end
+end
+
+
diff --git a/src/AlgebraicGeometry/Schemes/CoveredSchemes/Morphisms/MorphismFromRationalFunctions/Methods.jl b/src/AlgebraicGeometry/Schemes/CoveredSchemes/Morphisms/MorphismFromRationalFunctions/Methods.jl
index b4b10284f6f5..6567b6ec396e 100644
--- a/src/AlgebraicGeometry/Schemes/CoveredSchemes/Morphisms/MorphismFromRationalFunctions/Methods.jl
+++ b/src/AlgebraicGeometry/Schemes/CoveredSchemes/Morphisms/MorphismFromRationalFunctions/Methods.jl
@@ -308,9 +308,9 @@ This method is cheap in the sense that it simply inverts all representatives of
the denominators occurring in the `realization_preview(Phi, U, V)`.
"""
function cheap_realization(Phi::MorphismFromRationalFunctions, U::AbsAffineScheme, V::AbsAffineScheme)
- if haskey(cheap_realizations(Phi), (U, V))
- return cheap_realizations(Phi)[(U, V)]
- end
+ #if haskey(cheap_realizations(Phi), (U, V))
+ # return cheap_realizations(Phi)[(U, V)]
+ #end
img_gens_frac = realization_preview(Phi, U, V)
# Try to cancel the fractions heuristically; turns out it was too expensive in some applications due to slow divide
# for (k, f) in enumerate(img_gens_frac)
@@ -574,7 +574,7 @@ function pushforward(Phi::MorphismFromRationalFunctions, D::AbsAlgebraicCycle)
error("not implemented")
end
-function pushforward(Phi::MorphismFromRationalFunctions, D::WeilDivisor)
+function pushforward(Phi::MorphismFromRationalFunctions, D::AbsWeilDivisor)
is_isomorphism(Phi) || error("method not implemented unless for the case of an isomorphism")
#is_proper(Phi) || error("morphism must be proper")
all(is_prime, components(D)) || error("divisor must be given in terms of irreducible components")
@@ -839,7 +839,7 @@ function _pullback(phi::MorphismFromRationalFunctions, I::AbsIdealSheaf)
error("ideal sheaf could not be pulled back")
end
-function pullback(phi::MorphismFromRationalFunctions, D::WeilDivisor)
+function pullback(phi::MorphismFromRationalFunctions, D::AbsWeilDivisor)
return WeilDivisor(pullback(phi)(underlying_cycle(D)), check=false)
end
@@ -872,7 +872,7 @@ end
function _find_good_representative_chart(I::AbsIdealSheaf; covering::Covering=default_covering(scheme(I)))
# We assume that I is prime
# TODO: Make this an hassert?
- @assert is_prime(I)
+ @hassert :IdealSheaves 2 is_prime(I)
X = scheme(I)
# Some heuristics to choose a reasonably "easy" chart
@@ -905,6 +905,7 @@ function _prepare_pushforward_prime_divisor(
domain_chart::AbsAffineScheme = _find_good_representative_chart(I),
codomain_charts::Vector{<:AbsAffineScheme} = copy(patches(codomain_covering(phi)))
)
+ @assert !is_one(I(domain_chart))
U = domain_chart
X = domain(phi)
Y = codomain(phi)
diff --git a/src/AlgebraicGeometry/Schemes/Divisors/AlgebraicCycles.jl b/src/AlgebraicGeometry/Schemes/Divisors/AlgebraicCycles.jl
index 82806d80c191..ea7b74e85290 100644
--- a/src/AlgebraicGeometry/Schemes/Divisors/AlgebraicCycles.jl
+++ b/src/AlgebraicGeometry/Schemes/Divisors/AlgebraicCycles.jl
@@ -534,3 +534,7 @@ function integral(W::AbsAlgebraicCycle; check::Bool=true)
return result
end
+function Base.hash(X::AbsAlgebraicCycle, u::UInt)
+ return u
+end
+
diff --git a/src/AlgebraicGeometry/Schemes/Divisors/CartierDivisor.jl b/src/AlgebraicGeometry/Schemes/Divisors/CartierDivisor.jl
index 34c5e1255791..36f7e74ae448 100644
--- a/src/AlgebraicGeometry/Schemes/Divisors/CartierDivisor.jl
+++ b/src/AlgebraicGeometry/Schemes/Divisors/CartierDivisor.jl
@@ -530,3 +530,12 @@ function _show_semi_compact(io::IO, C::CartierDivisor, cov::Covering, n::String)
print(io, Dedent())
end
end
+
+function Base.hash(X::CartierDivisor, u::UInt)
+ return u
+end
+
+function Base.hash(X::EffectiveCartierDivisor, u::UInt)
+ return u
+end
+
diff --git a/src/AlgebraicGeometry/Schemes/Divisors/WeilDivisor.jl b/src/AlgebraicGeometry/Schemes/Divisors/WeilDivisor.jl
index 0e4af4ca0e0e..33a5ce98411e 100644
--- a/src/AlgebraicGeometry/Schemes/Divisors/WeilDivisor.jl
+++ b/src/AlgebraicGeometry/Schemes/Divisors/WeilDivisor.jl
@@ -5,12 +5,12 @@ underlying_cycle(D::AbsWeilDivisor) = underlying_cycle(underlying_divisor(D))
underlying_cycle(D::WeilDivisor) = D.C
### type getters
-scheme_type(D::WeilDivisor{S, U, V}) where{S, U, V} = S
-scheme_type(::Type{WeilDivisor{S, U, V}}) where{S, U, V} = S
-coefficient_ring_type(D::WeilDivisor{S, U, V}) where{S, U, V} = U
-coefficient_ring_type(::Type{WeilDivisor{S, U, V}}) where{S, U, V} = U
-coefficient_type(D::WeilDivisor{S, U, V}) where{S, U, V} = V
-coefficient_type(::Type{WeilDivisor{S, U, V}}) where{S, U, V} = V
+scheme_type(D::AbsWeilDivisor{S, U}) where{S, U} = S
+scheme_type(::Type{AbsWeilDivisor{S, U}}) where{S, U} = S
+coefficient_ring_type(D::AbsWeilDivisor{S, U}) where{S, U} = U
+coefficient_ring_type(::Type{AbsWeilDivisor{S, U}}) where{S, U} = U
+coefficient_type(D::AbsWeilDivisor{S, U}) where{S, U} = elem_type(U)
+coefficient_type(::Type{AbsWeilDivisor{S, U}}) where{S, U} = elem_type(U)
@doc raw"""
WeilDivisor(X::CoveredScheme, R::Ring)
@@ -338,7 +338,7 @@ function intersect(D::AbsWeilDivisor, E::AbsWeilDivisor;
I = c1 + c2
if !has_dimension_leq_zero(I) # potentially faster for localized ideals
if c1 == c2
- result = result + a1*a2*_self_intersection(c1)
+ result = result + a1*a2* (has_attribute(c1, :_self_intersection) ? _self_intersection(c1) : _self_intersection(c2))
else
error("self intersection unknown")
end
@@ -352,7 +352,7 @@ function intersect(D::AbsWeilDivisor, E::AbsWeilDivisor;
end
-function pushforward(inc::CoveredClosedEmbedding, W::WeilDivisor)
+function pushforward(inc::CoveredClosedEmbedding, W::AbsWeilDivisor)
X = domain(inc)
Y = codomain(inc)
X === ambient_scheme(W) || error("divisor not defined on the domain")
@@ -420,7 +420,7 @@ end
@doc raw"""
- is_in_linear_system(f::VarietyFunctionFieldElem, D::WeilDivisor; regular_on_complement::Bool=true, check::Bool=true) -> Bool
+ is_in_linear_system(f::VarietyFunctionFieldElem, D::AbsWeilDivisor; regular_on_complement::Bool=true, check::Bool=true) -> Bool
Return whether the rational function `f` is in the linear system ``|D|``, i.e. if $(f) + D \geq 0$.
diff --git a/src/AlgebraicGeometry/Schemes/Gluing/Methods.jl b/src/AlgebraicGeometry/Schemes/Gluing/Methods.jl
index 7024fc902e00..70b9e81c97e4 100644
--- a/src/AlgebraicGeometry/Schemes/Gluing/Methods.jl
+++ b/src/AlgebraicGeometry/Schemes/Gluing/Methods.jl
@@ -236,3 +236,7 @@ function base_change(phi::Any, G::AbsGluing;
return LazyGluing(domain(patch_change1), domain(patch_change2), gd)
end
+function Base.hash(X::AbsGluing, u::UInt)
+ return u
+end
+
diff --git a/src/AlgebraicGeometry/Schemes/ProjectiveSchemes/Objects/Methods.jl b/src/AlgebraicGeometry/Schemes/ProjectiveSchemes/Objects/Methods.jl
index 20e2c51d5841..cb9bbb3b3543 100644
--- a/src/AlgebraicGeometry/Schemes/ProjectiveSchemes/Objects/Methods.jl
+++ b/src/AlgebraicGeometry/Schemes/ProjectiveSchemes/Objects/Methods.jl
@@ -433,5 +433,8 @@ function Base.union(comp::Vector{<:AbsProjectiveScheme})
return result
end
+function Base.hash(X::AbsProjectiveScheme, u::UInt)
+ return u
+end
diff --git a/src/AlgebraicGeometry/Schemes/Sheaves/CoherentSheaves.jl b/src/AlgebraicGeometry/Schemes/Sheaves/CoherentSheaves.jl
index 57f50b262b50..cdd99771ec45 100644
--- a/src/AlgebraicGeometry/Schemes/Sheaves/CoherentSheaves.jl
+++ b/src/AlgebraicGeometry/Schemes/Sheaves/CoherentSheaves.jl
@@ -264,10 +264,10 @@ Coherent sheaf of modules
3: [(s0//s2), (s1//s2), (s3//s2)] affine 3-space
4: [(s0//s3), (s1//s3), (s2//s3)] affine 3-space
with restrictions
- 1: free module of rank 1 over Multivariate polynomial ring in 3 variables over QQ
- 2: free module of rank 1 over Multivariate polynomial ring in 3 variables over QQ
- 3: free module of rank 1 over Multivariate polynomial ring in 3 variables over QQ
- 4: free module of rank 1 over Multivariate polynomial ring in 3 variables over QQ
+ 1: free module of rank 1 over multivariate polynomial ring in 3 variables over QQ
+ 2: free module of rank 1 over multivariate polynomial ring in 3 variables over QQ
+ 3: free module of rank 1 over multivariate polynomial ring in 3 variables over QQ
+ 4: free module of rank 1 over multivariate polynomial ring in 3 variables over QQ
```
"""
function twisting_sheaf(IP::AbsProjectiveScheme{<:Field}, d::Int)
@@ -325,10 +325,10 @@ Coherent sheaf of modules
3: [(s0//s2), (s1//s2), (s3//s2)] affine 3-space
4: [(s0//s3), (s1//s3), (s2//s3)] affine 3-space
with restrictions
- 1: free module of rank 1 over Multivariate polynomial ring in 3 variables over QQ
- 2: free module of rank 1 over Multivariate polynomial ring in 3 variables over QQ
- 3: free module of rank 1 over Multivariate polynomial ring in 3 variables over QQ
- 4: free module of rank 1 over Multivariate polynomial ring in 3 variables over QQ
+ 1: free module of rank 1 over multivariate polynomial ring in 3 variables over QQ
+ 2: free module of rank 1 over multivariate polynomial ring in 3 variables over QQ
+ 3: free module of rank 1 over multivariate polynomial ring in 3 variables over QQ
+ 4: free module of rank 1 over multivariate polynomial ring in 3 variables over QQ
```
"""
function tautological_bundle(IP::AbsProjectiveScheme{<:Field})
@@ -1116,4 +1116,7 @@ function projectivization(E::AbsCoherentSheaf;
return CoveredProjectiveScheme(X, C, on_patches, projective_gluings, check=false)
end
+function Base.hash(X::AbsCoherentSheaf, u::UInt)
+ return u
+end
diff --git a/src/AlgebraicGeometry/Schemes/Sheaves/IdealSheaves.jl b/src/AlgebraicGeometry/Schemes/Sheaves/IdealSheaves.jl
index 7628da425b3b..bba517f1af49 100644
--- a/src/AlgebraicGeometry/Schemes/Sheaves/IdealSheaves.jl
+++ b/src/AlgebraicGeometry/Schemes/Sheaves/IdealSheaves.jl
@@ -345,6 +345,7 @@ end
end
@attr Bool function has_dimension_leq_zero(I::Ideal)
+ is_one(I) && return true
return dim(I) <= 0
end
@@ -353,6 +354,7 @@ end
P = base_ring(R)::MPolyRing
J = ideal(P, numerator.(gens(I)))
has_dimension_leq_zero(J) && return true
+ is_one(I) && return true
return dim(I) <= 0
end
@@ -1691,6 +1693,7 @@ function produce_object(
algorithm::Symbol=:pullback # Either :pushforward or :pullback
# This determines how to extend through the gluings.
)
+ U2 === original_chart(F) && return F.P
# Initialize some local variables
X = scheme(F)
OOX = OO(X)
diff --git a/src/AlgebraicGeometry/Schemes/main.jl b/src/AlgebraicGeometry/Schemes/main.jl
index 4777e8b57e97..e1cb678a1fee 100644
--- a/src/AlgebraicGeometry/Schemes/main.jl
+++ b/src/AlgebraicGeometry/Schemes/main.jl
@@ -191,3 +191,11 @@ include("Divisors/AlgebraicCycles.jl")
include("Divisors/WeilDivisor.jl")
include("Divisors/CartierDivisor.jl")
include("Divisors/base_change.jl")
+
+########################################################################
+# Blowups
+########################################################################
+include("CoveredProjectiveScheme/Types.jl")
+include("CoveredProjectiveScheme/CoveredProjectiveScheme.jl")
+include("BlowupMorphism/Types.jl")
+include("BlowupMorphism/BlowupMorphism.jl")
diff --git a/src/AlgebraicGeometry/Surfaces/AdjunctionProcess/AdjunctionProcess.jl b/src/AlgebraicGeometry/Surfaces/AdjunctionProcess/AdjunctionProcess.jl
index 872035f826e5..3e5dd6aa8118 100644
--- a/src/AlgebraicGeometry/Surfaces/AdjunctionProcess/AdjunctionProcess.jl
+++ b/src/AlgebraicGeometry/Surfaces/AdjunctionProcess/AdjunctionProcess.jl
@@ -141,18 +141,17 @@ Given a smooth projective variety `X`, return a module whose sheafification is t
# Examples
-```
+```jldoctest
julia> R, x = graded_polynomial_ring(QQ, :x => (1:6));
julia> I = ideal(R, [x[1]*x[6] - x[2]*x[5] + x[3]*x[4]]);
-julia> GRASSMANNIAN = variety(I);
+julia> GRASSMANNIAN = variety(I);
julia> Omega = canonical_bundle(GRASSMANNIAN)
-Graded subquotient of submodule of R^1 generated by
-1 -> e[1]
-by submodule of R^1 generated by
-1 -> (x[1]*x[6] - x[2]*x[5] + x[3]*x[4])*e[1]
+Graded submodule of R^1 with 1 generator
+ 1: e[1]
+represented as subquotient with no relations
julia> degrees_of_generators(Omega)
1-element Vector{FinGenAbGroupElem}:
@@ -167,10 +166,9 @@ julia> I = ideal(R, [y^2*z + x*y*z - x^3 - x*z^2 - z^3]);
julia> ELLCurve = variety(I);
julia> Omega = canonical_bundle(ELLCurve)
-Graded subquotient of submodule of R^1 generated by
-1 -> e[1]
-by submodule of R^1 generated by
-1 -> (x^3 - x*y*z + x*z^2 - y^2*z + z^3)*e[1]
+Graded submodule of R^1 with 1 generator
+ 1: e[1]
+represented as subquotient with no relations
julia> degrees_of_generators(Omega)
1-element Vector{FinGenAbGroupElem}:
diff --git a/src/AlgebraicGeometry/Surfaces/EllipticSurface/EllipticSurface.jl b/src/AlgebraicGeometry/Surfaces/EllipticSurface/EllipticSurface.jl
new file mode 100644
index 000000000000..d48976ebad50
--- /dev/null
+++ b/src/AlgebraicGeometry/Surfaces/EllipticSurface/EllipticSurface.jl
@@ -0,0 +1,1360 @@
+###################################################################################################################
+#
+# Constructors
+#
+###################################################################################################################
+
+@doc raw"""
+ elliptic_surface(generic_fiber::EllipticCurve,
+ euler_characteristic::Int,
+ mwl_gens::Vector{<:EllipticCurvePoint}=EllipticCurvePoint[];
+ is_basis::Bool=true)
+ -> EllipticSurface
+
+Return the relatively minimal elliptic surface with generic fiber ``E/k(t)``.
+
+This is also known as the Kodaira-Néron model of ``E``.
+
+Input:
+- `generic_fiber` -- an elliptic curve over a function field
+- `euler_characteristic` -- the Euler characteristic of the Kodaira-Néron model of ``E``.
+- `mwl_gens` -- a vector of rational points of the generic fiber
+- `is_basis` -- if set to `false` compute a reduced basis from `mwl_gens`
+
+# Examples
+```jldoctest
+julia> Qt, t = polynomial_ring(QQ, :t);
+
+julia> Qtf = fraction_field(Qt);
+
+julia> E = elliptic_curve(Qtf, [0,0,0,0,t^5*(t-1)^2]);
+
+julia> X3 = elliptic_surface(E, 2)
+Elliptic surface
+ over rational field
+with generic fiber
+ -x^3 + y^2 - t^7 + 2*t^6 - t^5
+
+```
+"""
+function elliptic_surface(generic_fiber::EllipticCurve{BaseField},
+ euler_characteristic::Int,
+ mwl_gens::Vector{<:EllipticCurvePoint}=EllipticCurvePoint[];
+ resolution_strategy::Symbol=:iterative,
+ is_basis::Bool=true) where {
+ BaseField <: FracFieldElem{<:PolyRingElem{<:FieldElem}}}
+ @req all(parent(i)==generic_fiber for i in mwl_gens) "not a vector of points on $(generic_fiber)"
+ S = EllipticSurface(generic_fiber, euler_characteristic, mwl_gens; resolution_strategy)
+ if is_basis
+ return S
+ end
+ update_mwl_basis!(S, mwl_gens)
+ return S
+end
+
+@doc raw"""
+ kodaira_neron_model(E::EllipticCurve) -> EllipticSurface
+
+Return the Kodaira-Neron model of the elliptic curve `E`.
+"""
+kodaira_neron_model(E::EllipticCurve) = elliptic_surface(E)
+
+@doc raw"""
+ elliptic_surface(g::MPolyRingElem, P::Vector{<:RingElem})
+
+Transform a bivariate polynomial `g` of the form `y^2 - Q(x)` with `Q(x)` of
+degree at most ``4`` to Weierstrass form, apply Tate's algorithm and
+return the corresponding relatively minimal elliptic surface
+as well as the coordinate transformation.
+"""
+function elliptic_surface(
+ g::MPolyRingElem, P::Vector{<:RingElem};
+ minimize::Bool=true, resolution_strategy::Symbol=:iterative
+ )
+ R = parent(g)
+ (x, y) = gens(R)
+ P = base_ring(R).(P)
+ g2, phi2 = transform_to_weierstrass(g, x, y, P);
+ Y2, phi1 = _elliptic_surface_with_trafo(g2; minimize)
+ return Y2, phi2 * phi1
+end
+
+@doc raw"""
+ fibration_on_weierstrass_model(X::EllipticSurface)
+
+Return the elliptic fibration ``W \to \mathbb{P}^1`` where ``W`` is the Weierstrass model of ``X``.
+"""
+function fibration_on_weierstrass_model(X::EllipticSurface)
+ if !isdefined(X, :fibration_weierstrass_model)
+ weierstrass_model(X) # trigger caching
+ end
+ return X.fibration_weierstrass_model
+end
+
+@doc raw"""
+ fibration(X::EllipticSurface)
+
+Return the elliptic fibration ``X \to \mathbb{P}^1``.
+"""
+function fibration(X::EllipticSurface)
+ if !isdefined(X, :fibration)
+ X.fibration = compose(weierstrass_contraction(X), fibration_on_weierstrass_model(X))
+ end
+ return X.fibration
+end
+
+###################################################################################################################
+#
+# Basic attributes, properties
+#
+###################################################################################################################
+
+# Unlocks Scheme functionality
+function underlying_scheme(X::EllipticSurface)
+ S = X
+ if isdefined(S,:Y)
+ return S.Y
+ end
+ # trigger the computation
+ weierstrass_contraction(S)
+ return underlying_scheme(S)
+end
+
+base_ring(X::EllipticSurface) = coefficient_ring(base_ring(base_field(generic_fiber(X))))
+
+@doc raw"""
+ generic_fiber(X::EllipticSurface) -> EllipticCurve
+
+Return the generic fiber as an elliptic curve.
+"""
+generic_fiber(X::EllipticSurface) = X.E
+
+@doc raw"""
+ weierstrass_chart(X::EllipticSurface)
+
+Return the Weierstrass chart of ``X`` on its `weierstrass_model`.
+"""
+weierstrass_chart(X::EllipticSurface) = weierstrass_model(X)[1][1][1]
+
+@doc raw"""
+ euler_characteristic(X::EllipticSurface) -> Int
+
+Return the Euler characteristic ``\chi(\mathcal{O}_X)``.
+"""
+euler_characteristic(X::EllipticSurface) = X.euler_characteristic
+
+
+########################################################################################################
+#
+# Printing
+#
+########################################################################################################
+
+function Base.show(io::IO, X::EllipticSurface)
+ io = pretty(io)
+ if is_terse(io)
+ print(io, "Elliptic surface")
+ else
+ E = generic_fiber(X)
+ print(io, "Elliptic surface with generic fiber ", equation(E))
+ end
+end
+
+function Base.show(io::IO, ::MIME"text/plain", X::EllipticSurface)
+ io = pretty(io)
+ println(io, "Elliptic surface")
+ println(io, Indent(), "over ", Lowercase(), base_ring(X))
+ println(io, Dedent(), "with generic fiber")
+ print(io, Indent(), Lowercase(), equation(generic_fiber(X)), Dedent())
+ if isdefined(X, :Y)
+ println(io)
+ println(io, "and relatively minimal model")
+ print(io, Indent(), Lowercase(), X.Y, Dedent())
+ end
+ print(io, Dedent())
+end
+
+########################################################################################################
+#
+# Updating the Mordell-Weil generators.
+#
+########################################################################################################
+@doc raw"""
+ set_mordell_weil_basis!(X::EllipticSurface, mwl_basis::Vector{EllipticCurvePoint})
+
+Set a basis for the Mordell-Weil sublattice of ``X`` or at least of a sublattice.
+
+This invalidates previous computations depending on the generators of the
+Mordell Weil lattice such as the `algebraic_lattice`. Use with care.
+
+The points in `mwl_basis` must be linearly independent.
+"""
+function set_mordell_weil_basis!(X::EllipticSurface, mwl_basis::Vector{<:EllipticCurvePoint})
+ @req all(parent(P) == generic_fiber(X) for P in mwl_basis) "points must lie on the generic fiber"
+ X.MWL = mwl_basis
+ # clear old computations
+ if has_attribute(X, :algebraic_lattice)
+ delete!(X.__attrs, :algebraic_lattice)
+ end
+ if has_attribute(X, :mordell_weil_sublattice)
+ delete!(X.__attrs, :mordell_weil_sublattice)
+ end
+end
+
+@doc raw"""
+ _compute_mwl_basis(X::EllipticSurface, mwl_gens::Vector{<:EllipticCurvePoint}) -> ZZLat, Vector{<:EllipticCurvePoint}
+
+Return a tuple `(M, B)` where `B` is an LLL-reduced basis of the sublattice `M` of the
+Mordell-Weil lattice of ``X`` generated by `mwl_gens`.
+"""
+function _compute_mwl_basis(X::EllipticSurface, mwl_gens::Vector{<:EllipticCurvePoint})
+ # it would be good to have the height pairing implemented
+ basis,tors, SX = _algebraic_lattice(X, mwl_gens)
+ basisTriv, GTriv = trivial_lattice(X)
+ r = length(basisTriv)
+ l = length(mwl_gens)
+ V = ambient_space(SX)
+ rk = rank(V)
+ G = ZZ.(gram_matrix(V))
+ # project away from the trivial lattice
+ pr_mwl = orthogonal_projection(V,basis_matrix(SX)[1:r, :])
+ BMWL = pr_mwl.matrix[r+1:end, :]
+ GB = gram_matrix(V,BMWL)
+ @assert rank(GB) == rk-r
+ _, u = hnf_with_transform(ZZ.(denominator(GB) * GB))
+ B = u[1:rk-r,:] * BMWL
+
+ MWL = lll(lattice(V, B, isbasis=false))
+ u = solve(BMWL, basis_matrix(MWL); side=:left)
+ u = ZZ.(u)
+ mwl_basis = [sum(u[i,j] * mwl_gens[j] for j in 1:length(mwl_gens)) for i in 1:nrows(u)]
+ return MWL, mwl_basis
+end
+
+@doc raw"""
+ update_mwl_basis!(X::EllipticSurface, mwl_gens::Vector{<:EllipticCurvePoint})
+
+Compute a reduced basis of the sublattice of the Mordell-Weil lattice spanned
+by `mwl_gens` and set these as the new generators of the Mordell-Weil lattice of
+``X``.
+"""
+function update_mwl_basis!(X::EllipticSurface, mwl_gens::Vector{<:EllipticCurvePoint})
+ mwl, mwl_basis = _compute_mwl_basis(X, mwl_gens)
+ set_mordell_weil_basis!(X, mwl_basis)
+end
+
+@doc raw"""
+ algebraic_lattice_primitive_closure(X::EllipticSurface, p) -> Vector{<:EllipticCurvePoint}
+
+Return sections ``P_1,\dots P_n`` of the generic fiber, such that together with
+the generators of the algebraic lattice ``A``, they generate
+```math
+\frac{1}{p} A \cap N
+```
+where ``N`` is the numerical lattice of ``X``.
+
+The algorithm proceeds by computing division points in the Mordell-Weil subgroup of `X`
+and using information coming from the discriminant group of the algebraic lattice
+to do so.
+"""
+algebraic_lattice_primitive_closure(X::EllipticSurface, p) = algebraic_lattice_primitive_closure(X, ZZ(p))
+
+function algebraic_lattice_primitive_closure(X::EllipticSurface, p::ZZRingElem)
+ S = X
+ L = algebraic_lattice(S)[3]
+ @req is_even(L) "not implemented"
+ Ld = intersect(dual(L) , (1//p * L))
+ D = torsion_quadratic_module(Ld, L, modulus = 1, modulus_qf=2)
+ candidates = [x for x in D if !iszero(x) && iszero(quadratic_product(x))]
+ t = length(trivial_lattice(S)[1])
+ r = rank(L)
+ cc = [(x->mod(x,p)).(p*lift(c)[t+1:end]) for c in candidates]
+ unique!(cc)
+ cc = [c for c in cc if !iszero(c)]
+ pts = [division_points(sum(v[i]*S.MWL[i] for i in 1:(r-t)),p) for v in cc]
+ return [i[1] for i in pts if length(i)>0]
+end
+
+function algebraic_lattice_primitive_closure!(X::EllipticSurface, prime)
+ pts = algebraic_lattice_primitive_closure(X, prime)
+ update_mwl_basis!(X, vcat(pts, X.MWL))
+ return pts
+end
+
+@doc raw"""
+ algebraic_lattice_primitive_closure!(X::EllipticSurface)
+
+Compute the primitive closure of the algebraic lattice of ``X`` inside its
+numerical lattice and update the generators of its Mordell--Weil group accordingly.
+
+The algorithm works by computing suitable divison points in its Mordell Weil group.
+"""
+function algebraic_lattice_primitive_closure!(X::EllipticSurface)
+ S = X
+ L = algebraic_lattice(S)[3]
+ for p in prime_divisors(ZZ(det(L)))
+ while true
+ pts = algebraic_lattice_primitive_closure!(S, p)
+ if length(pts)==0
+ break
+ end
+ end
+ end
+ return S
+end
+
+
+###################################################################################################################
+#
+# Kodaira-Néron Model
+#
+###################################################################################################################
+
+
+
+@doc raw"""
+ weierstrass_chart_on_minimal_model(X::EllipticSurface)
+
+Return an affine chart ``U`` of ``X`` which is isomorphic to the `weierstrass_chart`
+of ``X`` on its `weierstrass_model`, but with all singular fibers removed.
+
+More precisely, the affine coordinates of ``U`` are ``(x,y,t)`` and the chart is
+constructed as the vanishing locus of
+```math
+y^2 + a_1(t) xy + a_3 y = x^3 + a_2 x^2 + a_4 x + a_6
+```
+minus the reducible singular fibers.
+"""
+weierstrass_chart_on_minimal_model(X::EllipticSurface) = X[1][1]
+
+@doc raw"""
+ weierstrass_model(X::EllipticSurface) -> CoveredScheme, CoveredClosedEmbedding
+
+Return the Weierstrass model ``W`` of ``X`` and the inclusion in
+its ambient projective bundle
+```math
+S\subseteq \mathbb{P}( \mathcal{O}_{\mathbb{P}^1}(-2s) \oplus \mathcal{O}_{\mathbb{P}^1}(-3s) \oplus \mathcal{O}_{\mathbb{P}^1}).
+```
+"""
+function weierstrass_model(X::EllipticSurface)
+ if isdefined(X, :Weierstrassmodel)
+ return X.Weierstrassmodel, X.inc_Weierstrass
+ end
+
+ s = euler_characteristic(X)
+ E = generic_fiber(X)
+
+ kt = base_ring(base_field(E))
+ k = coefficient_ring(kt)
+
+ IP1 = projective_space(k, 1)
+ c = standard_covering(IP1)
+ # rename the variables on the affine charts
+ # to a more readable version
+ if k isa FqField
+ OO(c[1]).data.S = [:t]
+ OO(c[2]).data.S = [:s]
+ else
+ OO(c[1]).S = [:t]
+ OO(c[2]).S = [:s]
+ end
+
+ O0 = twisting_sheaf(IP1, 0)
+ O4 = twisting_sheaf(IP1, -2*s)
+ O6 = twisting_sheaf(IP1, -3*s)
+
+ bundleE = direct_sum([O0, O4, O6])
+
+ P_proj = projectivization(bundleE, var_names=[:z, :x, :y])
+ P = covered_scheme(P_proj)
+ pr = covered_projection_to_base(P_proj)
+ @assert has_decomposition_info(default_covering(P))
+
+ # Create the singular Weierstrass model S of the elliptic K3 surface X
+ a = a_invariants(E)
+ U = affine_charts(P)[1] # the standard Weierstrass chart
+ (x, y, t) = gens(OO(U))
+ @assert all(denominator(i)==1 for i in a)
+ a = [numerator(a)(t) for a in a]
+ (a1,a2,a3,a4,a6) = a
+ ft = y^2 + a1*x*y + a3*y - (x^3 + a2*x^2 + a4*x+a6)
+ I = IdealSheaf(P, U, [ft]; check=false)
+
+ inc_S = CoveredClosedEmbedding(P, I)
+ Scov = domain(inc_S) # The ADE singular elliptic K3 surface
+ X.Weierstrasschart = Scov[1][1]
+ X.fibration_weierstrass_model = compose(inc_S, pr)
+
+ X.Weierstrassmodel = Scov
+ X.inc_Weierstrass = inc_S
+
+ set_attribute!(Scov, :is_irreducible=>true)
+ set_attribute!(Scov, :is_reduced=>true)
+ set_attribute!(Scov, :is_integral=>true)
+ set_attribute!(Scov, :is_equidimensional=>true)
+ return Scov, inc_S
+end
+
+@doc raw"""
+ weierstrass_contraction(X::EllipticSurface) -> SchemeMor
+
+Return the contraction morphism of ``X`` to its Weierstrass model.
+
+This triggers the computation of the `underlying_scheme` of ``X``
+as a blowup from its Weierstrass model. It may take a few minutes.
+"""
+function weierstrass_contraction(X::EllipticSurface)
+ algorithm = X.resolution_strategy
+ if algorithm == :iterative
+ return weierstrass_contraction_iterative(X)
+ elseif algorithm == :simultaneous
+ return weierstrass_contraction_simultaneous(X)
+ else
+ error("algorithm not recognized")
+ end
+end
+
+@doc raw"""
+ _separate_singularities!(X::EllipticSurface) -> Covering
+
+Create a covering of the ambient projective bundle ``P``
+of the Weierstrass model ``W`` of ``X`` such that each chart
+(of ``X``) contains at most one singular point of ``W``.
+Append this covering to the list of coverings of ``X`` and return it.
+"""
+function _separate_singularities!(X::EllipticSurface)
+ S, inc_S = weierstrass_model(X)
+ P = codomain(inc_S)
+
+ I_sing = ideal_sheaf_of_singular_locus(S)
+ I_sing_P = SimplifiedIdealSheaf(pushforward(inc_S)(I_sing))
+
+ # Refine the covering over the reducible singular fibers
+ # to make sure that there is only a single singular point in each chart
+ refined_charts = AbsAffineScheme[]
+ U = P[1][1] # the weierstrass_chart
+ IsingU = I_sing_P(U)::MPolyIdeal
+ if isone(IsingU)
+ # we want one smooth weierstrass chart
+ push!(refined_charts, U)
+ set_attribute!(U, :is_smooth => true)
+ else
+ # there is at most one singularity in every fiber
+ # project the singular locus to an affine chart of P1
+ disc = gens(eliminate(IsingU, coordinates(U)[1:2]))[1]
+ # The t-coordinates of the reducible fibers
+ redfib = [f[1] for f in factor(disc)]
+ # One chart with all reducible fibers taken out
+ UU = PrincipalOpenSubset(U, redfib)
+ set_attribute!(UU, :is_smooth => true)
+ push!(refined_charts, UU)
+ if length(redfib)==1
+ # We need to recreate U as a PrincipalOpenSubset of itself here
+ # in order to maintain the correct tree-structure for refinements.
+ # In any Covering no patch is allowed to be an ancestor of another.
+ push!(refined_charts, PrincipalOpenSubset(U, one(OO(U))))
+ else
+ for i in 1:length(redfib)
+ # We take out all but the i-th singular fiber
+ r = copy(redfib)
+ g = r[i]
+ deleteat!(r, i)
+ Uref = PrincipalOpenSubset(U, r)
+ push!(refined_charts, Uref)
+ end
+ end
+ end
+
+ # Create a chart which contains the fiber over s=0
+ # and no other reducible singular fibers
+ # these are visible in the charts that we have already
+ # i.e. we add the fiber at s=0 and remove all other singular fibers
+ V = P[1][4]
+ IsingV = I_sing_P(V)
+ if isone(IsingV)
+ push!(refined_charts, V)
+ else
+ # reducible singular fibers
+ disc = gens(eliminate(IsingV, coordinates(V)[1:2]))[1]
+ (x,y,s) = coordinates(V)
+ b, d = divides(disc, s)
+ if b
+ disc = d
+ end
+ redfib = [f[1] for f in factor(disc)]
+ if length(redfib)> 0
+ push!(refined_charts, PrincipalOpenSubset(V, redfib))
+ else
+ push!(refined_charts, V)
+ end
+ end
+
+ # no extra singularities in the X = 1 chart
+ # therefore we just exclude all the singularities visible here
+ for W in [P[1][2],P[1][5]]
+ Ising = I_sing_P(W)
+ if isone(Ising)
+ push!(refined_charts, W)
+ continue
+ end
+ (z,y,s_or_t) = coordinates(W)
+ # reducible singular fibers
+ local disc = gens(eliminate(Ising, [z, s_or_t]))[1]
+ local redfib = [p for (p,e) in factor(disc)]
+ push!(refined_charts, PrincipalOpenSubset(W, redfib))
+ end
+
+ # no extra singularities on the the zero section
+ # This is the Y = 1 chart
+ # therefore we just exclude all the singularities visible here
+ for W in [P[1][3],P[1][6]]
+ local Ising = I_sing_P(W)
+ if isone(Ising)
+ push!(refined_charts, W)
+ continue
+ end
+ local (z,x,s_or_t) = coordinates(W)
+ # reducible singular fibers
+ local disc = gens(eliminate(Ising, [x, s_or_t]))[1]
+ local redfib = [p for (p,e) in factor(disc)]
+ push!(refined_charts, PrincipalOpenSubset(W, redfib))
+ end
+
+
+ Cref = Covering(refined_charts)
+ inherit_gluings!(Cref, P[1])
+ push!(P.coverings, Cref)
+ @assert has_decomposition_info(default_covering(P))
+ inherit_decomposition_info!(P, Cref)
+ @assert has_decomposition_info(Cref)
+ # Now we have an extra covering where each chart just contains a single singularity
+
+ @assert scheme(I_sing) === S
+ @assert scheme(I_sing_P) === P
+ return Cref
+end
+
+
+function weierstrass_contraction_simultaneous(Y::EllipticSurface)
+ if isdefined(Y, :blowup)
+ return Y.blowup
+ end
+ S, inc_S = weierstrass_model(Y)
+ @assert has_attribute(S, :is_equidimensional) && get_attribute(S, :is_equidimensional) === true
+
+ X0 = codomain(inc_S)
+ Y0 = S
+ set_attribute!(Y0, :is_reduced=>true)
+ set_attribute!(Y0, :is_irreducible=>true)
+ set_attribute!(Y0, :is_equidimensional=>true)
+ inc_Y0 = inc_S
+ I_sing_Y0 = AbsIdealSheaf[ideal_sheaf_of_singular_locus(Y0)]
+ #I_sing_Y0 = AbsIdealSheaf[simplify(ideal_sheaf_of_singular_locus(Y0))]
+ I_sing_X0 = simplify.(pushforward(inc_Y0).(I_sing_Y0))
+
+ # Prepare a covering which has a permanent weierstrass chart
+ U0 = X0[1][1]
+ disc = numerator(discriminant(generic_fiber(Y)))
+ U = PrincipalOpenSubset(U0, evaluate(disc, gens(OO(U0))[3]))
+ _find_chart(U, default_covering(X0))
+ Cref = Covering(vcat([U], affine_charts(X0)))
+ inherit_gluings!(Cref, X0[1])
+ push!(X0.coverings, Cref)
+ @assert has_decomposition_info(default_covering(X0))
+ inherit_decomposition_info!(X0, Cref)
+ @assert has_decomposition_info(Cref)
+
+ ambient_exceptionals = EffectiveCartierDivisor[]
+ varnames = [:a,:b,:c,:d,:e,:f,:g,:h,:i,:j,:k,:l,:m,:n,:o,:p,:q,:r,:u,:v,:w]
+ projectionsX = BlowupMorphism[]
+ projectionsY = AbsCoveredSchemeMorphism[]
+ count = 0
+
+ @vprint :EllipticSurface 2 "Blowing up Weierstrass model simultaneously in all singular points\n"
+ while true
+ count = count+1
+ @vprint :EllipticSurface 1 "blowup number: $(count)\n"
+ @vprint :EllipticSurface 1 "number of ideal sheaves to be blown up: $(length(I_sing_X0))\n"
+ if length(I_sing_X0)==0
+ # stop if smooth
+ break
+ end
+ # make sure we have a Weierstrass chart kept.
+ if count == 1
+ cov = Cref
+ else
+ cov = simplified_covering(X0)
+ end
+ # take the first ideal sheaf and blow it up
+ J = SimplifiedIdealSheaf(I_sing_X0[1])
+ pr_X1 = blow_up(J, covering=cov, var_name=varnames[1+mod(count, length(varnames))])
+
+ X1 = domain(pr_X1)
+ @vprint :EllipticSurface 1 "$(X1)\n"
+ E1 = exceptional_divisor(pr_X1)
+
+ @vprint :EllipticSurface 2 "computing strict transforms\n"
+ # compute the exceptional divisors
+ ambient_exceptionals = EffectiveCartierDivisor[strict_transform(pr_X1, e) for e in ambient_exceptionals]
+ # move the divisors coming originally from S up to the next chart
+ push!(ambient_exceptionals, E1)
+
+ Y1, inc_Y1, pr_Y1 = strict_transform(pr_X1, inc_Y0)
+ # Speed up the computation of singular loci
+ set_attribute!(Y1, :is_irreducible=> true)
+ set_attribute!(Y1, :is_reduced=>true)
+ set_attribute!(Y1, :is_integral=>true)
+ set_attribute!(Y1, :is_equidimensional=>true)
+
+ # transform the singular loci
+ I_sing_X0 = AbsIdealSheaf[pullback(pr_X1, J) for J in I_sing_X0[2:end]]
+
+ # Add eventual new components
+ @vprint :EllipticSurface 2 "computing singular locus\n"
+ I_sing_new = ideal_sheaf_of_singular_locus(Y1; focus=pullback(inc_Y1, ideal_sheaf(E1)))
+ #I_sing_new = pushforward(inc_Y1, I_sing_new) + ideal_sheaf(E1) # new components only along the exc. set
+ I_sing_new = simplify(pushforward(inc_Y1, I_sing_new))
+
+ @vprint :EllipticSurface 2 "decomposing singular locus\n"
+ !is_one(I_sing_new) && push!(I_sing_X0, I_sing_new)
+
+ push!(projectionsX, pr_X1)
+ push!(projectionsY, pr_Y1)
+ simplify!(Y1)
+
+ # set up for the next iteration
+ Y0 = Y1
+ inc_Y0 = inc_Y1
+ X0 = X1
+ # Speed up the computation of singular loci
+ set_attribute!(Y0, :is_irreducible=> true)
+ set_attribute!(Y0, :is_reduced=>true)
+ set_attribute!(Y0, :is_integral=>true)
+ set_attribute!(Y0, :is_equidimensional=>true)
+ set_attribute!(X0, :is_irreducible=> true)
+ set_attribute!(X0, :is_reduced=>true)
+ set_attribute!(X0, :is_integral=>true)
+ end
+ Y.Y = Y0
+ Y.blowups = projectionsY
+
+ # We need to rewrap the last maps so that the domain is really Y
+ last_pr = pop!(projectionsY)
+ last_pr_wrap = CoveredSchemeMorphism(Y, codomain(last_pr), covering_morphism(last_pr))
+
+ push!(projectionsY, last_pr_wrap)
+ Y.ambient_blowups = projectionsX
+
+ Y.ambient_exceptionals = ambient_exceptionals
+ piY = CompositeCoveredSchemeMorphism(reverse(projectionsY))
+ Y.blowup = piY
+
+ inc_Y0_wrap = CoveredClosedEmbedding(Y, codomain(inc_Y0), covering_morphism(inc_Y0), check=false)
+ Y.inc_Y = inc_Y0_wrap
+
+ set_attribute!(Y, :is_irreducible=> true)
+ set_attribute!(Y, :is_reduced=>true)
+ set_attribute!(Y, :is_integral=>true)
+ return piY
+end
+
+
+function weierstrass_contraction_iterative(Y::EllipticSurface)
+ if isdefined(Y, :blowup)
+ return Y.blowup
+ end
+ S, inc_S = weierstrass_model(Y)
+ @assert has_attribute(S, :is_equidimensional) && get_attribute(S, :is_equidimensional) === true
+ Crefined = _separate_singularities!(Y)
+ # Blow up singular points (one at a time) until smooth
+ # and compute the strict transforms of the `divisors`
+ # collect the exceptional divisors
+ # blowup ambient spaces: X0 → X ⊂
+ # blowup pi: Y → (S singular weierstrass model)
+ #
+ # initialization for the while loop
+ X0 = codomain(inc_S)
+ Y0 = S
+ set_attribute!(Y0, :is_reduced=>true)
+ set_attribute!(Y0, :is_irreducible=>true)
+ set_attribute!(Y0, :is_equidimensional=>true)
+ inc_Y0 = inc_S
+ I_sing_Y0 = maximal_associated_points(ideal_sheaf_of_singular_locus(Y0))::Vector{<:AbsIdealSheaf}
+ I_sing_X0 = pushforward(inc_Y0).(I_sing_Y0)
+
+
+ ambient_exceptionals = EffectiveCartierDivisor[]
+ varnames = [:a,:b,:c,:d,:e,:f,:g,:h,:i,:j,:k,:l,:m,:n,:o,:p,:q,:r,:u,:v,:w]
+ projectionsX = BlowupMorphism[]
+ projectionsY = AbsCoveredSchemeMorphism[]
+ count = 0
+
+ @vprint :EllipticSurface 2 "Blowing up Weierstrass model\n"
+ @vprint :EllipticSurface 2 "in $(Crefined)\n"
+ while true
+ count = count+1
+ @vprint :EllipticSurface 1 "blowup number: $(count)\n"
+ @vprint :EllipticSurface 1 "number of singular points: $(length(I_sing_X0))\n"
+ if length(I_sing_X0)==0
+ # stop if smooth
+ break
+ end
+ # make sure there is only one singular point per chart
+ if count == 1
+ cov = Crefined
+ else
+ # the following leads to difficult bugs
+ cov = simplified_covering(X0)
+ end
+ # take the first singular point and blow it up
+ J = SimplifiedIdealSheaf(I_sing_X0[1])
+ pr_X1 = blow_up(J, covering=cov, var_name=varnames[1+mod(count, length(varnames))])
+
+ # Set the attribute so that the strict_transform does some extra work
+ #isomorphism_on_open_subset(pr_X1)
+
+ X1 = domain(pr_X1)
+ @vprint :EllipticSurface 1 "$(X1)\n"
+ E1 = exceptional_divisor(pr_X1)
+
+ @vprint :EllipticSurface 2 "computing strict transforms\n"
+ # compute the exceptional divisors
+ ambient_exceptionals = EffectiveCartierDivisor[strict_transform(pr_X1, e) for e in ambient_exceptionals]
+ # move the divisors coming originally from S up to the next chart
+ push!(ambient_exceptionals, E1)
+
+ Y1, inc_Y1, pr_Y1 = strict_transform(pr_X1, inc_Y0)
+ # Speed up the computation of singular loci
+ set_attribute!(Y1, :is_irreducible=> true)
+ set_attribute!(Y1, :is_reduced=>true)
+ set_attribute!(Y1, :is_integral=>true)
+ set_attribute!(Y1, :is_equidimensional=>true)
+
+ # transform the singular loci
+ I_sing_X0 = AbsIdealSheaf[pullback(pr_X1, J) for J in I_sing_X0[2:end]]
+
+ # Add eventual new components
+ @vprint :EllipticSurface 2 "computing singular locus\n"
+ I_sing_new = ideal_sheaf_of_singular_locus(Y1; focus=pullback(inc_Y1, ideal_sheaf(E1)))
+ #I_sing_new = pushforward(inc_Y1, I_sing_new) + ideal_sheaf(E1) # new components only along the exc. set
+ I_sing_new = pushforward(inc_Y1, I_sing_new)
+
+ @vprint :EllipticSurface 2 "decomposing singular locus\n"
+ I_sing_X0 = vcat(I_sing_X0, maximal_associated_points(I_sing_new))
+
+ push!(projectionsX, pr_X1)
+ push!(projectionsY, pr_Y1)
+ simplify!(Y1)
+
+ # set up for the next iteration
+ Y0 = Y1
+ inc_Y0 = inc_Y1
+ X0 = X1
+ # Speed up the computation of singular loci
+ set_attribute!(Y0, :is_irreducible=> true)
+ set_attribute!(Y0, :is_reduced=>true)
+ set_attribute!(Y0, :is_integral=>true)
+ set_attribute!(Y0, :is_equidimensional=>true)
+ set_attribute!(X0, :is_irreducible=> true)
+ set_attribute!(X0, :is_reduced=>true)
+ set_attribute!(X0, :is_integral=>true)
+ end
+ Y.Y = Y0
+ Y.blowups = projectionsY
+
+ # We need to rewrap the last maps so that the domain is really Y
+ last_pr = pop!(projectionsY)
+ last_pr_wrap = CoveredSchemeMorphism(Y, codomain(last_pr), covering_morphism(last_pr))
+ #set_attribute!(last_pr_wrap, :isomorphism_on_open_subset, get_attribute(last_pr, :isomorphism_on_open_subset))
+
+ push!(projectionsY, last_pr_wrap)
+ Y.ambient_blowups = projectionsX
+
+ Y.ambient_exceptionals = ambient_exceptionals
+ piY = CompositeCoveredSchemeMorphism(reverse(projectionsY))
+ Y.blowup = piY
+
+ inc_Y0_wrap = CoveredClosedEmbedding(Y, codomain(inc_Y0), covering_morphism(inc_Y0), check=false)
+ Y.inc_Y = inc_Y0_wrap
+
+ set_attribute!(Y, :is_irreducible=> true)
+ set_attribute!(Y, :is_reduced=>true)
+ set_attribute!(Y, :is_integral=>true)
+ return piY
+end
+
+###################################################################################################################
+#
+# Intersection theory, Neron-Severi-lattice, Mordell-Weil lattice
+#
+###################################################################################################################
+
+@doc raw"""
+ algebraic_lattice(X) -> Vector{AbsWeilDivisor}, ZZLat
+
+Return the sublattice ``L`` of the numerical lattice spanned by fiber components,
+torsion sections and the sections provided at the construction of ``X``.
+
+The first return value is a list ``B`` of vectors corresponding to the standard basis of the ambient space of `L`.
+The second consists of generators ``T`` for the torsion part of the Mordell-Weil group.
+Together ``B`` and ``L`` generate the algebraic lattice. However, they are linearly dependent.
+The third return value is the lattice ``L``.
+
+!!! warning
+ The ordering of the fiber components is in general not canonical and may change in between sessions.
+"""
+@attr Any function algebraic_lattice(X::EllipticSurface)
+ return _algebraic_lattice(X,X.MWL)
+end
+
+function _algebraic_lattice(X::EllipticSurface, mwl_basis::Vector{<:EllipticCurvePoint})
+ basisTriv, GTriv = trivial_lattice(X)
+ r = length(basisTriv)
+ l = length(mwl_basis)
+ sections = [section(X, i) for i in mwl_basis]
+ n = l+r
+ GA = zero_matrix(ZZ, n, n)
+ GA[1:r,1:r] = GTriv
+ GA[r+1:n,r+1:n] = -euler_characteristic(X)*identity_matrix(ZZ, l)
+ basisA = vcat(basisTriv, sections)
+ @vprint :EllipticSurface 2 "computing intersection numbers\n"
+ for i in 1:n
+ @vprint :EllipticSurface 3 "\nrow $(i): \n"
+ for j in max(i + 1, r + 1):n
+ if i!=2 && i <= r
+ I = components(basisA[i])[1]
+ J = components(basisA[j])[1]
+ if isone(I+J)
+ ij = 0
+ else
+ ij = 1
+ end
+ else
+ @vprint :EllipticSurface 4 "$(j) "
+ ij = intersect(basisA[i],basisA[j])
+ end
+ GA[i,j] = ij
+ GA[j,i] = GA[i,j]
+ end
+ end
+ GA_QQ = change_base_ring(QQ,GA)
+ # primitive closure of the trivial lattice comes from torsion sections
+ tors = [section(X, h) for h in mordell_weil_torsion(X)]
+ torsV = QQMatrix[]
+ for T in tors
+ @vprint :EllipticSurface 2 "computing basis representation of torsion point $(T)\n"
+ vT = zero_matrix(QQ, 1, n)
+ for i in 1:r
+ if i== 2
+ vT[1,i] = intersect(basisA[i], T)
+ else
+ @assert length(components(basisTriv[i])) == 1
+ I = sum(components(basisA[i]))
+ J = components(T)[1]
+ if !isone(I+J)
+ @assert i!=2 # O does not meet any torsion section
+ vT[1,i] = 1
+ end
+ end
+ end
+ for i in r+1:n
+ vT[1,i] = intersect(T,basisA[i])
+ end
+ push!(torsV, solve(GA_QQ, vT; side=:left))
+ end
+ gen_tors = zip(tors, torsV)
+ push!(torsV, identity_matrix(QQ,n))
+ V = quadratic_space(QQ,GA)
+ L = lattice(V, reduce(vcat,torsV), isbasis=false)
+ return basisA, collect(gen_tors), L
+end
+
+@doc raw"""
+ mordell_weil_sublattice(X::EllipticSurface) -> Vector{EllipticCurvePoint}, ZZLat
+
+Return the (sublattice) of the Mordell-Weil lattice of ``X`` spanned
+by the sections of ``X`` supplied at its construction.
+
+The Mordell-Weil lattice is represented in the same vector space as the
+algebraic lattice (with quadratic form rescaled by ``-1``).
+"""
+@attr ZZLat function mordell_weil_sublattice(X::EllipticSurface)
+ S = X
+ NS = algebraic_lattice(S)[3]
+ t = length(trivial_lattice(S)[1])
+ trivNS = basis_matrix(NS)[1:t,:]
+ R = basis_matrix(NS)[t+1:end,:]
+ V = ambient_space(NS)
+ P = orthogonal_projection(V, trivNS)
+ mwl = rescale(lattice(V,R*P.matrix),-1)
+ return mwl
+end
+
+@doc raw"""
+ mordell_weil_torsion(X::EllipticSurface) -> Vector{EllipticCurvePoint}
+
+Return the torsion part of the Mordell-Weil group of the generic fiber of ``X``.
+"""
+@attr Vector{EllipticCurvePoint} function mordell_weil_torsion(X::EllipticSurface)
+ S = X
+ E = generic_fiber(S)
+ O = E([0,1,0])
+ N = trivial_lattice(S)[2]
+ tors = EllipticCurvePoint[]
+ d = det(N)
+ for p in prime_divisors(d)
+ if valuation(d, p) == 1
+ continue
+ end
+ r = 1
+ i = 0
+ dp = typeof(O)[]
+ while true
+ i = i+1
+ @vprint :EllipticSurface 2 "computing $(p^i)-torsion"
+ dp = division_points(O, p^i)
+ if length(dp) == r
+ break
+ end
+ r = length(dp)
+ end
+ for pt in dp
+ if pt != O
+ push!(tors, pt)
+ end
+ end
+ end
+ return tors
+end
+
+@doc raw"""
+ section(X::EllipticSurface, P::EllipticCurvePoint) -> EllipticSurfaceSection
+
+Given a rational point ``P\in E(C)`` of the generic fiber ``E/C`` of ``\pi\colon X \to C``,
+return its closure in ``X`` as a `AbsWeilDivisor`.
+"""
+function section(X::EllipticSurface, P::EllipticCurvePoint)
+ if iszero(P[1])&&iszero(P[3])
+ return zero_section(X)
+ end
+ return EllipticSurfaceSection(X, P)
+end
+
+
+function _section_on_weierstrass_ambient_space(X::EllipticSurface, P::EllipticCurvePoint)
+ S0,incS0 = weierstrass_model(X)
+ X0 = codomain(incS0)
+ if P[3] == 0
+ # zero section
+ V = X0[1][3]
+ (z,x,t) = coordinates(V)
+ return IdealSheaf(X0, V, [x,z])
+ end
+ U = X0[1][1]
+ (x,y,t) = coordinates(U)
+ b = P
+ return ideal_sheaf(X0,U,[OO(U)(i) for i in [x*denominator(b[1])(t)-numerator(b[1])(t),y*denominator(b[2])(t)-numerator(b[2])(t)]]; check=false)
+end
+
+
+@doc raw"""
+ zero_section(X::EllipticSurface) -> AbsWeilDivisor
+
+Return the zero section of the relatively minimal elliptic
+fibration ``\pi\colon X \to C``.
+"""
+@attr EllipticSurfaceSection zero_section(X::EllipticSurface) = EllipticSurfaceSection(X, generic_fiber(X)([0,1,0]))
+
+
+@doc raw"""
+ basis_representation(X::EllipticSurface, D::AbsWeilDivisor)
+
+Return the vector representing the numerical class of ``D``
+with respect to the basis of the ambient space of `algebraic_lattice(X)`.
+"""
+function basis_representation(X::EllipticSurface, D::AbsWeilDivisor)
+ basis_ambient,_, NS = algebraic_lattice(X)
+ G = gram_matrix(ambient_space(NS))
+ n = length(basis_ambient)
+ v = zeros(ZZRingElem, n)
+ @vprint :EllipticSurface 3 "computing basis representation of $D\n"
+ kk = base_ring(X)
+ if iszero(characteristic(kk)) && has_attribute(X, :good_reduction_map)
+ X_red_raw, bc = raw_good_reduction(X)
+ red_dict = IdDict{AbsWeilDivisor, AbsWeilDivisor}(D=>_reduce_as_prime_divisor(bc, D) for D in basis_ambient)
+ D_red = _reduce_as_prime_divisor(bc, D)
+ for (i, E) in enumerate(basis_ambient)
+ @vprintln :EllipticSurface 4 "intersecting in positive characteristic with $(i): $(basis_ambient[i])"
+ v[i] = intersect(red_dict[E], D_red)
+ end
+ else
+ for i in 1:n
+ @vprintln :EllipticSurface 4 "intersecting with $(i): $(basis_ambient[i])"
+
+ v[i] = intersect(basis_ambient[i], D)
+ end
+ end
+ @vprint :EllipticSurface 3 "done computing basis representation\n"
+ return v*inv(G)
+end
+
+
+###################################################################################################################
+#
+# Fibers and trivial lattice
+#
+###################################################################################################################
+
+@doc raw"""
+ trivial_lattice(X::EllipticSurface) -> Vector{AbsWeilDivisor}, ZZMatrix
+
+Return a basis for the trivial lattice as well as its Gram matrix.
+
+The trivial lattice is the sublattice of the numerical lattice spanned by fiber components and
+the zero section of ``X``.
+
+!!! warning
+ The ordering of the basis is in general not canonical and may change in between sessions.
+"""
+function trivial_lattice(X::EllipticSurface)
+ T = _trivial_lattice(X)[1:2]
+ return T
+end
+
+@doc raw"""
+ _trivial_lattice(X::EllipticSurface; reducible_singular_fibers_in_PP1=_reducible_fibers_disc(S))
+
+Internal function. Returns a list consisting of:
+- basis of the trivial lattice
+- gram matrix
+- fiber_components without multiplicities
+
+The keyword argument `reducible_singular_fibers_in_PP1` must be a list of vectors of length `2` over
+the base field representing the points in projective space over which there are reducible fibers.
+Specify it to force this ordering of the basis vectors of the ambient space of the `algebraic_lattice`
+"""
+function _trivial_lattice(X::EllipticSurface; reducible_singular_fibers_in_PP1=_reducible_fibers_disc(X))
+ S = X
+ get_attribute!(S, :_trivial_lattice) do
+ O = zero_section(S)
+ pt0, F = fiber(S)
+ set_attribute!(components(O)[1], :_self_intersection, -euler_characteristic(S))
+ basisT = [F, O]
+ grams = [ZZ[0 1;1 -euler_characteristic(S)]]
+ sing = reducible_singular_fibers_in_PP1
+ f = [[pt, fiber_components(S,pt)] for pt in sing]
+ fiber_componentsS = []
+ for (pt, ft) in f
+ @vprint :EllipticSurface 2 "normalizing fiber: over $pt \n"
+ Ft0 = standardize_fiber(S, ft)
+ @vprint :EllipticSurface 2 "$(Ft0[1]) \n"
+ append!(basisT , Ft0[3][2:end])
+ push!(grams,Ft0[4][2:end,2:end])
+ push!(fiber_componentsS, vcat([pt], collect(Ft0)))
+ end
+ G = block_diagonal_matrix(grams)
+ # make way for some more pretty printing
+ for (pt,root_type,_,comp) in fiber_componentsS
+ for (i,I) in enumerate(comp)
+ name = string(root_type[1], root_type[2])
+ set_attribute!(components(I)[1], :name, string("Component ", name, "_", i-1," of fiber over ", Tuple(pt)))
+ set_attribute!(components(I)[1], :_self_intersection, -2)
+ end
+ end
+ return basisT, G, fiber_componentsS
+ end
+end
+
+function _reducible_fibers_disc(X::EllipticSurface; sort::Bool=true)
+ E = generic_fiber(X)
+ j = j_invariant(E)
+ d = numerator(discriminant(E))
+ kt = parent(d)
+ k = coefficient_ring(kt)
+ sing = Vector{elem_type(k)}[]
+ for (p,v) in factor(d)
+ if v == 1
+ continue
+ end
+ r = k.(roots(p))
+ if length(r) == 0
+ error("not all reducible fibers are visible over $(base_ring(S))")
+ end
+ @assert length(r) ==1
+ rt = r[1]
+ if v == 2
+ # not a type II fiber
+ if j!=0
+ push!(sing, [rt,k(1)])
+ end
+ end
+ if v > 2
+ push!(sing, [rt,k(1)])
+ end
+ end
+ if sort
+ sort!(sing, by=x->by_total_order(x[1]))
+ end
+ # fiber over infinity is always last (if it is there)
+ if degree(d) <= 12*euler_characteristic(X) - 2
+ push!(sing, k.([1, 0]))
+ end
+ return sing
+end
+
+function by_total_order(x::FqFieldElem)
+ return [lift(ZZ, i) for i in absolute_coordinates(x)]
+end
+
+by_total_order(x::QQFieldElem) = x
+
+function by_total_order(x::NumFieldElem)
+ return absolute_coordinates(x)
+end
+
+
+@doc raw"""
+ reducible_fibers(X::EllipticSurface)
+
+Return the reducible fibers of ``X``.
+
+The output format is the following:
+A list `[F1, ..., Fn]` where each entry `Fi` represents a reducible fiber.
+
+The list ``F`` has the following entries:
+- A point ``P \in \mathbb{P}^{1}`` such that ``F = \pi^{-1}(P)``;
+- The ADE-type of the fiber;
+- The fiber ``F`` as a Weil divisor, including its multiplicities;
+- The irreducible components of the fiber. The first component intersects the zero section;
+- Their intersection matrix.
+"""
+function reducible_fibers(X::EllipticSurface)
+ return _trivial_lattice(X)[3]
+end
+
+
+@doc raw"""
+ standardize_fiber(X::EllipticSurface, f::Vector{<:AbsWeilDivisor})
+
+Internal method. Used to prepare for [`reducible_fibers`](@ref).
+`f` must be the list of the components of the reducible fiber `F`.
+Output a list of tuples with each tuple as follows
+- the root type of ``F``, e.g. `(:A, 3)`
+- the class of ``F`` as a divisor with the appropriate multiplicities
+- the irreducible components `[F0,...Fn]` of `F` sorted such that the first entry `F0` is the one intersecting the zero section. The others are sorted in some standard way
+- gram matrix of the intersection of [F0,...,Fn], it is an extended ADE-lattice.
+"""
+function standardize_fiber(X::EllipticSurface, f::Vector{<:AbsWeilDivisor})
+ S = X
+ @hassert :EllipticSurface 2 all(is_prime(i) for i in f)
+ f = copy(f)
+ O = components(zero_section(S))[1]
+ local f0
+ for (i,D) in enumerate(f)
+ if !isone(O+components(D)[1])
+ f0 = D
+ deleteat!(f,i)
+ break
+ end
+ end
+ r = length(f)
+ G = -2*identity_matrix(ZZ, r)
+ @vprintln :EllipticSurface 2 "computing intersections:"
+ for i in 1:r
+ @vprint :EllipticSurface 3 "\nrow $(i): \n"
+ for j in 1:i-1
+ @vprint :EllipticSurface 4 "$(j) "
+ # we know the intersections are 0 or 1, so we can replace the line below by a shortcut.
+ # G[i, j] = G[j, i] = intersect(f[i], f[j])
+ # In the examples treated, this led to roughly a factor 3 in speed and memory consumption.
+ if isone(components(f[i])[1]+components(f[j])[1])
+ G[i,j] = 0
+ else
+ G[i,j] = 1
+ end
+ G[j,i] = G[i,j]
+ end
+ end
+ L = integer_lattice(gram=G)
+ rt,_ = root_lattice_recognition(L)
+ @assert length(rt)==1
+ rt = rt[1]
+ R = root_lattice(rt[1], rt[2])
+ b, I = _is_equal_up_to_permutation_with_permutation(G, -gram_matrix(R))
+ @assert b
+ gensF = vcat([f0], f[I])
+ Gext, v = extended_ade(rt[1],rt[2])
+ Fdiv = sum(v[i]*gensF[i] for i in 1:length(gensF))
+ return rt, Fdiv, gensF, Gext
+end
+
+@doc raw"""
+ fiber_cartier(X::EllipticSurface, P::Vector = ZZ.([0,1])) -> EffectiveCartierDivisor
+
+Return the fiber of ``\pi\colon X \to C`` over ``P\in C`` as a Cartier divisor.
+"""
+function fiber_cartier(X::EllipticSurface, P::Vector = ZZ.([0,1]))
+ S = X
+ S0,_ = weierstrass_model(S)
+ underlying_scheme(S) # cache stuff
+ D = IdDict{AbsAffineScheme, RingElem}()
+ k = base_ring(S0)
+ P = k.(P)
+
+ if P[1]!=0 && P[2]!=0
+ t0 = P[1] * inv(P[2])
+ for i in 1:3
+ U = S0[1][i]
+ (_,_,t) = coordinates(U)
+ D[U] = t-t0
+ end
+ s0 = inv(t0)
+ for i in 4:6
+ U = S0[1][i]
+ (_,_,s) = coordinates(U)
+ D[U] = s - s0
+ end
+ elseif P[1] != 0
+ # it is the fiber at [1:0]
+ for i in 4:6
+ U = S0[1][i]
+ (_,_,s) = coordinates(U)
+ D[U] = s
+ end
+ for i in 1:3
+ U = S0[1][i]
+ (_,_,t) = coordinates(U)
+ D[U] = one(parent(t))
+ end
+ elseif P[2] != 0
+ # the fiber at [0:1]
+ for i in 1:3
+ U = S0[1][i]
+ (_,_,t) = coordinates(U)
+ D[U] = t
+ end
+ for i in 4:6
+ U = S0[1][i]
+ (_,_,s) = coordinates(U)
+ D[U] = one(parent(s))
+ end
+ else
+ error("[0,0] is not a point in projective space")
+ end
+ F = EffectiveCartierDivisor(S0, D, trivializing_covering=S0[1], check=false)
+ return pullback(S.blowup)(F)
+end
+
+@doc raw"""
+ fiber_components(X::EllipticSurface, P) -> Vector{<:AbsWeilDivisor}
+
+Return the fiber components of the fiber over the point ``P \in C``.
+"""
+function fiber_components(X::EllipticSurface, P; algorithm=:exceptional_divisors)
+ S = X
+ @vprint :EllipticSurface 2 "computing fiber components over $(P)\n"
+ P = base_ring(S).(P)
+ W = codomain(S.inc_Weierstrass)
+ Fcart = fiber_cartier(S, P)
+ if isone(P[2])
+ U = default_covering(W)[1]
+ (x,y,t) = coordinates(U)
+ F = PrimeIdealSheafFromChart(W, U, ideal(t - P[1]))
+ elseif isone(P[1])
+ U = default_covering(W)[4]
+ (x,y,s) = coordinates(U)
+ F = PrimeIdealSheafFromChart(W, U, ideal(s - P[2]))
+ end
+ FF = ideal_sheaf(Fcart)
+ EE = exceptional_divisors(S)
+ EP = filter(E->issubset(FF, E), EE)
+ for bl in S.ambient_blowups
+ F = strict_transform(bl, F)
+ end
+ F = pullback(S.inc_Y, F)
+ F = weil_divisor(F, ZZ)
+ fiber_components = [weil_divisor(E, ZZ; check=false) for E in EP]
+ push!(fiber_components, F)
+ return fiber_components
+end
+
+@attr Vector{<:AbsIdealSheaf} function exceptional_divisors(X::EllipticSurface)
+ S = X
+ PP = AbsIdealSheaf[]
+ @vprintln :EllipticSurface 2 "computing exceptional divisors"
+ # If we have resolution_strategy=:simultaneous, then the following is a non-trivial preprocessing step.
+ ambient_pts = reduce(vcat, maximal_associated_points.(ideal_sheaf.(S.ambient_exceptionals)))
+ for I in ambient_pts
+ @vprintln :EllipticSurface 4 "decomposing divisor "
+ mp = maximal_associated_points(pullback(S.inc_Y, I); use_decomposition_info=true)
+ append!(PP, mp)
+ end
+ @vprintln :EllipticSurface 3 "done"
+ return PP
+end
+
+function fiber(X::EllipticSurface)
+ b, pt, F = irreducible_fiber(X)
+ if b
+ W = weil_divisor(F)
+ # we manually set the self-intersection
+ set_attribute!(components(W)[1], :_self_intersection, 0)
+ else
+ # all fibers are reducible pick the one over [0 : 1]
+ k = base_ring(X)
+ pt = [k(0),k(1)]
+ f = fiber_components(X, pt)
+ fiber_type, W, componentsW, gramW = standardize_fiber(X, f)
+ end
+ set_attribute!(W, :name=> "Fiber over ($(pt[1]), $(pt[2]))")
+ return pt, W
+end
+
+
+@doc raw"""
+ irreducible_fiber(X::EllipticSurface) -> Bool, Point, EffectiveCartierDivisor
+
+Return an irreducible fiber as a cartier divisor and whether it exists.
+
+The return value is a triple `(b, pt, F)` where
+
+- `b` is `true` if an irreducible fiber exists over the base field of `S`
+- `pt` the base point of the fiber
+- `F` the irreducible fiber which projects to `pt`
+"""
+function irreducible_fiber(X::EllipticSurface)
+ S = X
+ W = weierstrass_model(S)
+ d = numerator(discriminant(generic_fiber(S)))
+ kt = parent(d)
+ k = coefficient_ring(kt)
+ r = [k.(roots(i[1])) for i in factor(d) if i[2]>=2]
+ sing = reduce(append!,r, init=[])
+ pt = k.([0,0]) # initialize
+ found = false
+ if is_finite(k)
+ for i in k
+ if !(i in sing) # true if the fiber over [i,1] is irreducible
+ pt = k.([i,1])
+ found = true
+ break
+ end
+ end
+ if !found && (degree(d) >= 12*euler_characteristic(S) - 1) # irreducible at infinity?
+ pt = k.([1, 0])
+ found = true
+ end
+ else
+ i = k(0)
+ while true
+ i = i+1
+ if !(i in sing)
+ pt = k.([i,1])
+ found = true
+ break
+ end
+ end
+ end
+ F = fiber_cartier(S, pt)
+ return found, pt, F
+end
diff --git a/src/AlgebraicGeometry/Surfaces/EllipticSurface/Morphisms.jl b/src/AlgebraicGeometry/Surfaces/EllipticSurface/Morphisms.jl
new file mode 100644
index 000000000000..ba8f47810feb
--- /dev/null
+++ b/src/AlgebraicGeometry/Surfaces/EllipticSurface/Morphisms.jl
@@ -0,0 +1,956 @@
+########################################################################
+# Reduction to positive characteristic
+#
+# We allow to store a reduction of an elliptic surface `X` to positive
+# characteristic. The user needs to know what they're doing here!
+#
+# The functionality can be made available by specifying a reduction
+# map for the `base_ring` (actually a field) of `X` to a field of
+# positive characteristic. This can then be stored in `X` via
+# `set_good_reduction_map!`. The latter unlocks certain features such
+# as computation of intersection numbers in positive characteristic.
+########################################################################
+function set_good_reduction_map!(X::EllipticSurface, red_map::Map)
+ has_attribute(X, :good_reduction_map) && error("reduction map has already been set")
+ kk0 = base_ring(X)
+ @assert domain(red_map) === kk0
+ kkp = codomain(red_map)
+ @assert characteristic(kkp) > 0
+ set_attribute!(X, :good_reduction_map=>red_map)
+end
+
+function get_good_reduction_map(X::EllipticSurface)
+ is_zero(characteristic(base_ring(X))) || error("reduction to positive characteristic is only possible from characteristic zero")
+ has_attribute(X, :good_reduction_map) || error("no reduction map is available; please set it manually via `set_good_reduction_map!`")
+ return get_attribute(X, :good_reduction_map)::Map
+end
+
+@attr Tuple{<:AbsCoveredScheme, <:AbsCoveredSchemeMorphism} function raw_good_reduction(X::EllipticSurface)
+ red_map = get_good_reduction_map(X)
+ X_red, bc_map = base_change(red_map, X)
+ set_attribute!(X_red, :is_irreducible=>true)
+ set_attribute!(X_red, :is_reduced=>true)
+ set_attribute!(X_red, :is_integral=>true)
+ set_attribute!(X_red, :is_equidimensional=>true)
+ return X_red, bc_map
+end
+
+@attr Map function good_reduction_function_fields(X::EllipticSurface)
+ red_map = get_good_reduction_map(X)
+ E = generic_fiber(X)
+ Ft = base_field(E)
+ Pt = base_ring(Ft)
+ kk = coefficient_ring(Pt)
+ kk_red = codomain(red_map)
+ Pt_red, _ = polynomial_ring(kk_red, first(symbols(Pt)); cached=false)
+ Ft_red = fraction_field(Pt_red)
+ Ft_to_Ft_red = map_from_func(fr->Ft_red(map_coefficients(red_map, numerator(fr); parent=Pt_red), map_coefficients(red_map, denominator(fr); parent=Pt_red)), Ft, Ft_red)
+ return Ft_to_Ft_red
+end
+
+@attr EllipticCurve function good_reduction_generic_fiber(X::EllipticSurface)
+ red_map = get_good_reduction_map(X)
+ E = generic_fiber(X)
+ Ft_to_Ft_red = good_reduction_function_fields(X)
+ E_red = base_change(Ft_to_Ft_red, E)
+ return E_red
+end
+
+@attr Vector{<:EllipticCurvePoint} function good_reduction_rational_points(X::EllipticSurface)
+ red_map = good_reduction_function_fields(X)
+ result = Vector{EllipticCurvePoint}()
+ E_red = good_reduction_generic_fiber(X)
+ for P in X.MWL # TODO: Do we have a getter for this?
+ if is_infinite(P)
+ push!(result, infinity(E_red))
+ continue
+ end
+ push!(result, E_red([red_map(P[1]), red_map(P[2])]))
+ end
+ return result
+end
+
+@attr EllipticSurface function good_reduction(X::EllipticSurface)
+ red_map = get_good_reduction_map(X)
+ E_red = good_reduction_generic_fiber(X)
+ mwl_red = good_reduction_rational_points(X)
+ X_red = EllipticSurface(E_red, 2, mwl_red; resolution_strategy=X.resolution_strategy)
+end
+
+@attr Tuple{<:MorphismFromRationalFunctions, <:MorphismFromRationalFunctions} function identifications_with_raw_good_reduction(X::EllipticSurface)
+ X_red = good_reduction(X)
+ W_red = weierstrass_chart_on_minimal_model(X_red)
+ X_red_raw, red_raw = raw_good_reduction(X)
+ red_raw_cov = covering_morphism(red_raw)
+ W_red_raw = domain(first(maps_with_given_codomain(red_raw_cov, weierstrass_chart_on_minimal_model(X))))
+
+ R_red = ambient_coordinate_ring(W_red)
+ R_red_raw = ambient_coordinate_ring(W_red_raw)
+ raw_to_red = morphism_from_rational_functions(X_red_raw, X_red, W_red_raw, W_red, fraction_field(R_red_raw).(gens(R_red_raw)); check=false)
+ set_attribute!(raw_to_red, :is_isomorphism=>true)
+ red_to_raw = morphism_from_rational_functions(X_red, X_red_raw, W_red, W_red_raw, fraction_field(R_red).(gens(R_red)); check=false)
+ set_attribute!(red_to_raw, :is_isomorphism=>true)
+ return raw_to_red, red_to_raw
+end
+
+
+function raw_reduction_of_algebraic_lattice(X::EllipticSurface)
+ return get_attribute!(X, :raw_reduction_of_algebraic_lattice) do
+ X_red_raw, bc = raw_good_reduction(X)
+ basis_ambient, _, _= algebraic_lattice(X)
+ return red_dict = IdDict{AbsWeilDivisor, AbsWeilDivisor}(D=>_reduce_as_prime_divisor(bc, D) for D in basis_ambient)
+ end::IdDict
+end
+
+@attr ZZMatrix function good_reduction_algebraic_lattice(X::EllipticSurface)
+ div_red = raw_reduction_of_algebraic_lattice(X)
+ from, to = identifications_with_raw_good_reduction(X)
+ div_red_pf = IdDict{AbsWeilDivisor, AbsWeilDivisor}(D=>pushforward(from, E) for (D, E) in div_red)
+ basis, _, _= algebraic_lattice(X)
+ X_red = good_reduction(X)
+ red_basis, _, _= algebraic_lattice(X_red)
+ result = matrix(ZZ, [div_red_pf[D] == E ? one(ZZ) : zero(ZZ) for D in basis, E in red_basis])
+ result[1, 1] = one(ZZ) # identify the generic fibers
+ return result
+end
+
+@attr MorphismFromRationalFunctions function good_reduction(
+ f::MorphismFromRationalFunctions{<:EllipticSurface, <:EllipticSurface}
+ )
+ X = domain(f)
+ @assert X === codomain(f) "reduction to positive characteristic is only implemented for automorphisms"
+ W = weierstrass_chart_on_minimal_model(X)
+ @assert W === domain_chart(f) === codomain_chart(f) "morphism must be defined on the Weierstrass charts"
+ img_gens = coordinate_images(f)
+ red_map = get_good_reduction_map(X)
+
+ X_red = good_reduction(X)
+ W_red = weierstrass_chart_on_minimal_model(X_red)
+ R = ambient_coordinate_ring(W_red)
+ FR = fraction_field(R)
+
+ psi = fr -> FR(map_coefficients(red_map, numerator(fr); parent=R), map_coefficients(red_map, denominator(fr); parent=R))
+
+ img_gens_red = psi.(img_gens)
+ result = morphism_from_rational_functions(X_red, X_red, W_red, W_red, img_gens_red; check=false)
+ has_attribute(f, :is_isomorphism) && get_attribute(f, :is_isomorphism)===true && set_attribute!(result, :is_isomorphism=>true)
+ return result
+end
+
+
+### Some functions to do custom pullback of divisors along reduction maps.
+# We assume that primeness is preserved along the reduction. In particular, the
+# user is responsible for this to hold for all cases used!
+# They specify the "good reduction" in the end.
+function _reduce_as_prime_divisor(bc::AbsCoveredSchemeMorphism, D::AbsWeilDivisor)
+ return WeilDivisor(domain(bc), coefficient_ring(D),
+ IdDict{AbsIdealSheaf, elem_type(coefficient_ring(D))}(
+ _reduce_as_prime_divisor(bc, I) => c for (I, c) in coefficient_dict(D)
+ )
+ )
+end
+
+function _reduce_as_prime_divisor(bc::AbsCoveredSchemeMorphism, D::EllipticSurfaceSection)
+ P = rational_point(D)
+ is_infinite(P) && return _reduce_as_prime_divisor(bc, underlying_divisor(D))
+ X = codomain(bc)
+ @assert parent(P) === generic_fiber(X)
+ W = weierstrass_chart_on_minimal_model(X)
+ R = ambient_coordinate_ring(W)
+ (x, y, t) = gens(R)
+ I = ideal(R, R.([evaluate(denominator(P[1]), t)*x-evaluate(numerator(P[1]), t),
+ evaluate(denominator(P[2]), t)*y-evaluate(numerator(P[2]), t)])
+ )
+ bc_loc = first(maps_with_given_codomain(covering_morphism(bc), W))
+ bc_I = pullback(bc_loc)(I)
+ @assert is_one(dim(bc_I))
+ set_attribute!(bc_I, :is_prime=>true)
+ J = PrimeIdealSheafFromChart(domain(bc), domain(bc_loc), bc_I)
+ return WeilDivisor(domain(bc), coefficient_ring(D),
+ IdDict{AbsIdealSheaf, elem_type(coefficient_ring(D))}(J => one(coefficient_ring(D)))
+ )
+end
+
+function _reduce_as_prime_divisor(bc::AbsCoveredSchemeMorphism, I::AbsIdealSheaf)
+ result = pullback(bc, I)
+ has_attribute(I, :_self_intersection) && set_attribute!(result, :_self_intersection=>
+ (get_attribute(I, :_self_intersection)::Int))
+ return result
+end
+
+function _reduce_as_prime_divisor(bc::AbsCoveredSchemeMorphism, I::PrimeIdealSheafFromChart)
+ U = original_chart(I)
+ bc_cov = covering_morphism(bc)
+ V = __find_chart(U, codomain(bc_cov))
+ IV = I(V)
+ bc_loc = first(maps_with_given_codomain(bc_cov, V))
+ J = pullback(bc_loc)(IV)
+ set_attribute!(J, :is_prime=>true)
+ return PrimeIdealSheafFromChart(domain(bc), domain(bc_loc), J)
+end
+
+################################################################################################
+#
+# Given a rational map f:X --> Y compute f_*: NS(X) -> NS(Y)
+#
+################################################################################################
+
+function _local_pushforward(loc_map::AbsAffineSchemeMor, I::Ideal)
+ U_sub = domain(loc_map)
+ E, inc_E = sub(U_sub, I) # The subscheme of the divisor
+ E_simp = simplify(E) # Eliminate superfluous variables
+ id, id_inv = identification_maps(E_simp)
+
+ comp = compose(compose(id, inc_E), loc_map)
+
+ pb = pullback(comp)
+ K = kernel(pb)
+ return K
+end
+
+function _pushforward_lattice_along_isomorphism(step::MorphismFromRationalFunctions{<:EllipticSurface, <:EllipticSurface})
+ @assert is_isomorphism(step) "morphism must be an isomorphism"
+ X = domain(step)
+ Y = codomain(step)
+ UX = weierstrass_chart_on_minimal_model(X)
+ UY = weierstrass_chart_on_minimal_model(Y)
+ @assert codomain_chart(step) === UY
+ fracs = coordinate_images(step)
+
+ WY, _ = weierstrass_model(Y)
+ UWY = weierstrass_chart(Y)
+
+ to_weierstrass_Y = morphism_from_rational_functions(X, WY, UX, UWY, fracs, check=false)
+
+ fibration_proj_Y = fibration(Y)
+
+ BY = codomain(fibration_proj_Y)
+ UBY = codomain(covering_morphism(fibration_proj_Y)[UY])
+
+ composit = morphism_from_rational_functions(X, BY, UX, UBY, [fracs[3]], check=false)
+
+ lat_X = algebraic_lattice(X)[1]
+ if !has_attribute(lat_X[1], :is_prime)
+ ex, pt, F = irreducible_fiber(X)
+ ex || error("no irreducible fiber found; case not implemented")
+ lat_X[1] = weil_divisor(F)
+ set_attribute!(lat_X[1], :is_prime=>true)
+ set_attribute!(first(components(lat_X[1])), :is_prime=>true)
+ end
+
+ # We first estimate for every element in the lattic of X whether its image
+ # will be a fiber component, or a (multi-)section.
+ pre_select = IdDict{AbsWeilDivisor, AbsIdealSheaf}()
+
+ for D in lat_X
+ @assert length(components(D)) == 1 "divisors in the algebraic lattice must be prime"
+ I = first(components(D))
+ @assert has_is_prime(I) && is_prime(I) "ideal sheaf must be known to be prime"
+ pre_select[D] = _pushforward_prime_divisor(composit, I)
+ end
+
+
+ # Now we map them one by one using the knowledge gained above
+ result = IdDict{AbsWeilDivisor, AbsWeilDivisor}()
+ co_ring = coefficient_ring(zero_section(Y))
+
+ n = length(lat_X)
+ mwr = rank(mordell_weil_sublattice(X))
+ for (i, D) in enumerate(lat_X)
+ @vprint :EllipticSurface 2 "$((i, D, pre_select[D]))\n"
+ # D is a non-section
+ Q = pre_select[D]
+ I = first(components(D))
+ @vprint :EllipticSurface 2 "$(typeof(I))\n"
+ dom_chart = _find_good_representative_chart(I)
+ if i > n - mwr # if this is a section
+ dom_chart = weierstrass_chart_on_minimal_model(X)
+ end
+
+ if dim(Q) == 0
+ @vprint :EllipticSurface 3 "image will be a fiber component\n"
+ # find the fiber
+ if is_one(Q(UBY)) # fiber over infinity
+ # collect all components
+ comps = AbsWeilDivisor[]
+ for (pt, _, F, E, _) in reducible_fibers(Y)
+ if is_zero(pt[2]) # if this is in the fiber over the point at ∞ ∈ ℙ¹
+ append!(comps, E[2:end])
+ end
+ end
+ @vprint :EllipticSurface 3 "found total of $(length(comps)) possible components\n"
+
+ # collect all charts
+ codomain_charts = AbsAffineScheme[]
+ if is_empty(comps) # The fiber over infinity
+ @vprint :EllipticSurface 3 "the image must be the fiber over infinity"
+ codomain_charts = affine_charts(Y) # TODO: How can we restrict the charts then?
+ else
+ codomain_charts = AbsAffineScheme[V for V in affine_charts(Y) if any(D->!isone(first(components(D))(V)), comps)]
+ end
+ @vprint :EllipticSurface 3 "found $(length(codomain_charts)) charts where these components are visible"
+
+ if i > n - mwr # If D is a section
+ @vprint :EllipticSurface 3 "divisor to be mapped is a section\n"
+ pt = X.MWL[i-(n-mwr)]
+ res = _pushforward_section(step, pt; divisor=D, codomain_charts)
+ result[D] = WeilDivisor(Y, co_ring, IdDict{AbsIdealSheaf, elem_type(co_ring)}(res::AbsIdealSheaf => one(co_ring)); check=false)
+ else
+ @vprint :EllipticSurface 3 "divisor to be mapped is NOT a section\n"
+ loc_map, dom_chart, cod_chart = _prepare_pushforward_prime_divisor(step, I; domain_chart = dom_chart, codomain_charts)
+
+ loc_map === nothing && error("pushforward preparation did not succeed")
+ @assert !is_one(I(domain(loc_map)))
+ K = _local_pushforward(loc_map, I(domain(loc_map)))
+ @assert !is_one(K)
+
+ JJ = ideal(OO(cod_chart), gens(K))
+ res = PrimeIdealSheafFromChart(Y, cod_chart, JJ)
+
+ result[D] = WeilDivisor(Y, co_ring, IdDict{AbsIdealSheaf, elem_type(co_ring)}(res::AbsIdealSheaf => one(co_ring)); check=false)
+ end
+ continue
+ end
+ @vprint :EllipticSurface 3 "image will not be in the fiber over infinity\n"
+
+ # fiber over some point ≂̸ ∞.
+ t = first(gens(OO(UBY)))
+
+ codomain_charts = copy(affine_charts(Y))
+
+ # Restrict the codomain charts if applicable
+ for (i, (p, _, F, E, _)) in enumerate(reducible_fibers(Y))
+ p[2] == 0 && continue # Fiber over infinity already caught above
+ t0 = p[1]//p[2]
+ ideal(OO(UBY), t - t0) == Q(UBY) || continue
+
+ # Collect all patches
+ codomain_charts = AbsAffineScheme[V for V in affine_charts(Y) if any(I->!isone(I(V)), components(F))]
+ break
+ end
+ @vprint :EllipticSurface 3 "found $(length(codomain_charts)) charts where these components are visible\n"
+
+ if i > n - mwr # If D is a section
+ @vprint :EllipticSurface 3 "divisor to be mapped is a section\n"
+ pt = X.MWL[i-(n-mwr)]
+ res = _pushforward_section(step, pt; divisor=D, codomain_charts)
+ result[D] = WeilDivisor(Y, co_ring, IdDict{AbsIdealSheaf, elem_type(co_ring)}(res::AbsIdealSheaf => one(co_ring)); check=false)
+ else
+ @vprint :EllipticSurface 3 "divisor to be mapped is NOT a section\n"
+ loc_map, dom_chart, cod_chart = _prepare_pushforward_prime_divisor(step, I; codomain_charts)
+ loc_map === nothing && error("preparation for pushforward did not succeed")
+
+ @assert !is_one(I(domain(loc_map)))
+ K = _local_pushforward(loc_map, I(domain(loc_map)))
+ @assert !is_one(K)
+ JJ = ideal(OO(cod_chart), gens(K))
+ res = PrimeIdealSheafFromChart(Y, cod_chart, JJ)
+
+ result[D] = WeilDivisor(Y, co_ring, IdDict{AbsIdealSheaf, elem_type(co_ring)}(res::AbsIdealSheaf => one(co_ring)); check=false)
+ end
+ else
+ # "pushforward will be a section"
+ if i > n - mwr # If D is a section
+ pt = X.MWL[i-(n-mwr)]
+ res = _pushforward_section(step, pt; divisor=D, codomain_charts=[weierstrass_chart_on_minimal_model(Y)])
+ if res === nothing
+ # The only section not visible in the weierstrass chart is the zero section
+ result[D] = zero_section(Y)
+ continue
+ end
+
+ result[D] = WeilDivisor(Y, co_ring, IdDict{AbsIdealSheaf, elem_type(co_ring)}(res::AbsIdealSheaf => one(co_ring)); check=false)
+ else
+ loc_map, dom_chart, cod_chart = _prepare_pushforward_prime_divisor(step, I, domain_chart = dom_chart, codomain_charts = [weierstrass_chart_on_minimal_model(Y)])
+
+ if loc_map === nothing
+ # The only section not visible in the weierstrass chart is the zero section
+ result[D] = zero_section(Y)
+ continue
+ end
+
+ @assert !is_one(I(domain(loc_map)))
+ K = _local_pushforward(loc_map, I(domain(loc_map)))
+ @assert !is_one(K)
+ JJ = ideal(OO(cod_chart), gens(K))
+ res = PrimeIdealSheafFromChart(Y, cod_chart, JJ)
+
+ result[D] = WeilDivisor(Y, co_ring, IdDict{AbsIdealSheaf, elem_type(co_ring)}(res::AbsIdealSheaf => one(co_ring)); check=false)
+ end
+ end
+ end
+
+ res = AbsWeilDivisor[result[D] for D in lat_X]
+ for a in res
+ set_attribute!(first(components(a)), :_self_intersection, -2)
+ end
+ # the first one is the class of the fiber; set that one back
+ set_attribute!(first(components(first(res))), :_self_intersection, 0)
+ return res
+end
+
+function _pushforward_section(
+ phi::MorphismFromRationalFunctions{<:EllipticSurface, <:EllipticSurface},
+ P::EllipticCurvePoint;
+ divisor::AbsWeilDivisor=EllipticSurfaceSection(domain(phi), P),
+ codomain_charts::Vector{<:AbsAffineScheme} = affine_charts(codomain(phi))
+ )
+ X = domain(phi)::EllipticSurface
+ Y = codomain(phi)::EllipticSurface
+ D = divisor
+ I = first(components(D))
+ iso, inc = morphism_from_section(X, P; divisor=D)
+ U = weierstrass_chart_on_minimal_model(X)
+ inc_loc = first(maps_with_given_codomain(inc, U))
+ U_C = domain(inc_loc)
+ phi_loc, _, V = _prepare_pushforward_prime_divisor(phi, I; domain_chart=U, codomain_charts)
+ phi_loc === nothing && return nothing # Indicate that the given selection of codomain charts did not lead to a result
+ W = codomain(fibration(X)[U])
+ iso_loc = _restrict_properly(cheap_realization(iso, W, U_C), U_C)
+ inc_dom_phi_loc = inclusion_morphism(domain(phi_loc))
+ UU, to_U_C, to_U = fiber_product(inc_loc, inc_dom_phi_loc)
+ WW, a, b = fiber_product(iso_loc, to_U_C)
+ psi_loc = compose(compose(b, to_U), phi_loc)
+ K = kernel(pullback(psi_loc))
+ J = ideal(OO(V), gens(K))
+ JJ = PrimeIdealSheafFromChart(Y, V, J)
+ return JJ
+end
+
+@doc raw"""
+ pushforward_on_algebraic_lattices(f::MorphismFromRationalFunctions{<:EllipticSurface, <:EllipticSurface}) -> QQMatrix
+
+Return the pushforward ``f_*: V_1 \to V_2`` where ``V_i`` is the ambient quadratic space of the `algebraic_lattice`.
+
+This assumes that the image ``f_*(V_1)`` is contained in ``V_2``. If this is not the case, you will get
+``f_*`` composed with the orthogonal projection to ``V_2``.
+"""
+function pushforward_on_algebraic_lattices(f::MorphismFromRationalFunctions{<:EllipticSurface, <:EllipticSurface})
+ imgs_divs = _pushforward_lattice_along_isomorphism(f)
+ M = matrix([basis_representation(codomain(f),i) for i in imgs_divs])
+ V1 = ambient_space(algebraic_lattice(domain(f))[3])
+ V2 = ambient_space(algebraic_lattice(codomain(f))[3])
+ # keep the check on since it is simple compared to all the other computations done here
+ fstar = hom(V1,V2, M; check=true)
+ return fstar
+end
+
+# Given an irreducible divisor D on an elliptic surface X, try to extract a point
+# on the generic fiber from it. The return value is `nothing` in case this does not succeed.
+function point_on_generic_fiber_from_divisor(I::AbsIdealSheaf{<:EllipticSurface}; check::Bool=true)
+ X = scheme(I)
+ @check dim(I) == 1 "ideal sheaf must be of dimension one"
+ return point_on_generic_fiber_from_divisor(WeilDivisor(X, I; check=false); check)
+end
+
+function point_on_generic_fiber_from_divisor(D::AbsWeilDivisor{<:EllipticSurface}; check::Bool=true)
+ X = ambient_scheme(D)
+ E = generic_fiber(X)
+ ex, pt, F = irreducible_fiber(X)
+ WF = weil_divisor(F)
+ # TODO: Also cover this case by considering the class of a reducible fiber?
+ !ex && error("no irreducible fiber exists on this algebraic surface")
+ @assert length(components(D)) == 1 "divisor must be irreducible"
+
+ I = first(components(D))
+ fib = fibration(X)
+
+ # Check a necessary criterion for being a section
+ # J = pushforward(fib, I)
+ # is_one(dim(J)) || return nothing
+ is_zero(intersect(D, WF)) && return nothing
+# @check begin
+# J = pushforward(fib, I)
+# is_one(dim(J))
+# end "given divisor can not be a section"
+
+ #@check is_one(intersect(D, WF)) "intersection number with irreducible fiber is not one"
+
+ WX = weierstrass_chart_on_minimal_model(X)
+ IWX = I(WX)
+ is_one(IWX) && return infinity(E) # Point must be the zero section
+ R = ambient_coordinate_ring(WX)
+ (x, y, t) = gens(R)
+
+ # In case of a multisection do some extra preparation; see below.
+ !is_one(intersect(D, WF)) && return point_on_generic_fiber_from_divisor(_prepare_section(D))
+
+ g = gens(groebner_basis(saturated_ideal(IWX), ordering=lex(gens(R))))
+
+ # extract the coefficients for the section
+ kkt = base_field(E)
+
+ # First extract the y-coordinate
+ i = findfirst(f->(is_zero(degree(f, 1)) && is_one(degree(f, 2))), g)
+ i === nothing && return nothing
+ #i === nothing && error("no suitable polynomial found to read off point coordinates")
+ f = g[i]
+ y_coord = one(kkt)
+ ev_vals = [zero(kkt), one(kkt), gen(kkt)]
+ num = zero(kkt)
+ den = zero(kkt)
+ for t in terms(f)
+ degree(t, 2) == 1 && (den = den - evaluate(t, ev_vals))
+ degree(t, 2) == 0 && (num = num + evaluate(t, ev_vals))
+ end
+ y_coord = num//den
+
+ # Now extract the x-coordinate
+ i = findfirst(f->(is_one(degree(f, 1))), g)
+ i === nothing && return nothing
+ #i === nothing && error("no suitable polynomial found to read off point coordinates")
+ f = g[i]
+ x_coord = one(kkt)
+ ev_vals = [one(kkt), y_coord, gen(kkt)]
+ num = zero(kkt)
+ den = zero(kkt)
+ for t in terms(f)
+ degree(t, 1) == 1 && (den = den - evaluate(t, ev_vals))
+ degree(t, 1) == 0 && (num = num + evaluate(t, ev_vals))
+ end
+ x_coord = num//den
+
+ is_zero(evaluate(equation(E), [x_coord, y_coord])) || return nothing
+ #@assert is_zero(evaluate(equation(E), [x_coord, y_coord])) "esteemed point does not lie on the curve"
+ P = E([x_coord, y_coord])
+ return P
+end
+
+# Given an isomorphism phi : X -> Y of elliptic surfaces and a full algebraic lattice L on X,
+# push forward the divisors D from L to Y and try to extract points on the generic fiber from
+# them.
+#
+# This returns a list consisting of the points on the generic fiber.
+function extract_mordell_weil_basis(phi::MorphismFromRationalFunctions{<:EllipticSurface, <:EllipticSurface})
+ X = domain(phi)
+ Y = codomain(phi)
+ is_isomorphism(phi) || error("morphism must be an isomorphism")
+ pf_lat = _pushforward_lattice_along_isomorphism(phi)
+ points = EllipticCurvePoint[]
+ for D in pf_lat
+ P = point_on_generic_fiber_from_divisor(D)
+ P === nothing && continue
+ push!(points, P)
+ end
+ return points
+end
+
+function _prepare_section(D::AbsWeilDivisor{<:EllipticSurface})
+ X = ambient_scheme(D)
+ WX = weierstrass_chart_on_minimal_model(X)
+ R = ambient_coordinate_ring(WX)
+ I = first(components(D))
+ IWX = I(WX)
+ # We have a multisection in this case.
+ # To get a section from it, apply arXiv:2103.15101, Algorithm 1.
+
+ # Build up a helper ring
+ kkt = base_field(generic_fiber(X))
+ f = equation(generic_fiber(X))
+ kktXY = parent(f)
+ (xx, yy) = gens(kktXY)
+ for (c, e) in zip(coefficients(f), exponents(f))
+ if e == [0, 2]
+ @assert is_one(c) "polynomial is not normalized"
+ end
+ end
+ f = yy^2 - f # prepare the f from the Lemma
+ #kktXY, (xx, yy) = polynomial_ring(kkt, [:X, :Y]; cached=false)
+
+ @assert coefficient_ring(R) === coefficient_ring(base_ring(kkt))
+ help_map = hom(R, kktXY, [xx, yy, kktXY(gen(kkt))])
+
+ J = ideal(kktXY, help_map.(gens(saturated_ideal(IWX))))
+
+ J_gens = gens(groebner_basis(J, ordering=lex([yy, xx])))
+ i = findfirst(f->degree(f, 2) == 0, J_gens)
+ i === nothing && error("assertion of Lemma could not be verified")
+ g = J_gens[i]
+ i = findfirst(f->degree(f, 2) == 1, J_gens)
+ i === nothing && error("assertion of Lemma could not be verified")
+ h = J_gens[i]
+ c = zero(kkt)
+ for t in terms(h)
+ if degree(t, 2) == 1
+ c = c + evaluate(t, [zero(kkt), one(kkt)])
+ end
+ end
+ !isone(c) && (h = inv(c)*h)
+ h = yy - h
+ @assert J == ideal(kktXY, [g, yy-h])
+ ff = equation(kktXY, generic_fiber(X))
+ @assert parent(ff) === parent(f)
+ @assert ff == yy^2 - f
+ while total_degree(g) > 1
+ g = divexact(h^2 - f, g)
+ p, q = divrem(h, g)
+ h = q
+ end
+
+ F = fraction_field(R)
+ help_map_back = hom(kktXY, F, u->evaluate(u, F(R[3])), F.([R[1], R[2]]))
+ new_gens = [help_map_back(g), help_map_back(yy - h)]
+ sec_ideal = ideal(OO(WX), numerator.(new_gens))
+ @assert dim(sec_ideal) == 1
+ @assert is_prime(sec_ideal)
+
+ # overwrite the local variables
+ I = PrimeIdealSheafFromChart(X, WX, sec_ideal)
+ return weil_divisor(I)
+end
+
+#=
+# The map is not dominant and can hence not be realized as a MorphismFromRationalFunctions.
+# We keep the code for the moment as it will probably help us to reconstruct this map as a
+# proper CoveredSchemeMorphism, once this is needed.
+=#
+function morphism_from_section(
+ X::EllipticSurface, P::EllipticCurvePoint;
+ divisor::AbsWeilDivisor=EllipticSurfaceSection(X, P)
+ )
+ U = weierstrass_chart_on_minimal_model(X)
+ II = first(components(divisor))
+
+ # For the zero section we can not use the Weierstrass chart
+ if is_infinite(P)
+ return identity_map(X)
+ end
+ @assert !is_one(II(U))
+
+ C, inc_C = sub(II)
+
+ UC = domain(first(maps_with_given_codomain(inc_C, U)))
+
+ B = codomain(fibration(X))
+ V = codomain(fibration(X)[weierstrass_chart_on_minimal_model(X)])
+
+ kkt = OO(V)::MPolyRing
+ @assert ngens(kkt) == 1
+ t = first(gens(kkt))
+ img_gens = [evaluate(P.coordx, t), evaluate(P.coordy, t), t]
+
+ Fkkt = fraction_field(kkt)
+ img_gens2 = Fkkt.(img_gens)
+ # TODO: Cache?
+ iso = morphism_from_rational_functions(B, C, V, UC, img_gens2, check=false)
+ return iso, inc_C
+end
+
+########################################################################
+# Translations by sections #
+########################################################################
+
+@doc raw"""
+ translation_morphism(X::EllipticSurface, P::EllipticCurvePoint) -> MorphismFromRationalFunctions
+
+Return the automorphism of ``X`` defined by fiberwise translation by the section ``P``.
+"""
+function translation_morphism(X::EllipticSurface, P::EllipticCurvePoint)
+ E = generic_fiber(X)
+ @assert parent(P) === E "point does not lay on the underlying elliptic curve"
+ U = weierstrass_chart_on_minimal_model(X)
+ is_zero(P) && return identity_map(X)
+
+ # We construct the translation by P as a morphism of rational functions
+ kT = base_field(E)
+ T = first(gens(kT))
+
+ R = ambient_coordinate_ring(U)
+ x, y, t = gens(R)
+
+ a1, a2, a3, a4, a6 = [evaluate(a, t) for a in a_invariants(E)]
+
+ p_x = evaluate(P[1], t)
+ p_y = evaluate(P[2], t)
+
+ # Formulas adapted from Hecke/src/EllCrv/EllCrv.jl
+ m = (p_y - y)//(p_x - x)
+ pb_x = - x - p_x - a2 + a1*m + m^2
+ pb_y = - y - m*(pb_x - x) - a1*pb_x - a3
+
+ F = fraction_field(R)
+
+ result = morphism_from_rational_functions(X, X, U, U, F.([pb_x, pb_y, t]), check=true)
+ set_attribute!(result, :is_isomorphism=>true)
+ return result
+end
+
+########################################################################
+# Möbius transformations #
+########################################################################
+
+# Find a moebius transformation which sends a given set of three points in ℙ¹ to another set
+# of three points.
+function find_moebius_transformation(
+ orig_pts::Vector{<:Vector{<:FieldElem}},
+ new_pts::Vector{<:Vector{<:FieldElem}}
+ )
+ kk = parent(first(orig_pts))
+ a = [a[1] for a in orig_pts]
+ b = [b[1] for b in new_pts]
+ @assert all(a->isone(a[2]), orig_pts) "not implemented for non-normalized or infinite points"
+ @assert all(a->isone(a[2]), new_pts) "not implemented for non-normalized or infinite points"
+ return find_moebius_transformation(a, b)
+end
+
+function find_moebius_transformation(
+ orig_pts::Vector{<:FieldElem},
+ new_pts::Vector{<:FieldElem}
+ )
+ length(orig_pts) == 3 || error("exactly three points are needed")
+ @assert length(orig_pts) == length(new_pts) "number of points must coincide"
+ kk = parent(first(orig_pts))
+ a = orig_pts
+ b = new_pts
+
+ # Set up the matrix mapping the first three points to 0, 1, ∞
+ A = kk[(a[2] - a[3]) (-a[1]*(a[2] - a[3])); (a[2] - a[1]) (-a[3]*(a[2] - a[1]))]
+
+ # Set up the matrix mapping the second three points to 0, 1, ∞
+ B = kk[(b[2] - b[3]) (-b[1]*(b[2] - b[3])); (b[2] - b[1]) (-b[3]*(b[2] - b[1]))]
+
+ C = inv(B)*A
+ return x->(C[1,1]*x + C[1, 2], C[2,1]*x + C[2,2])
+end
+
+# Given two abstractly isomorphic elliptic surfaces X and Y over ℙ¹,
+# find all moebius transformation of the base which preserve the critical
+# values of the projections, try to lift them to morphisms X -> Y and
+# return the list of such morphisms for which the lift was successful.
+@doc raw"""
+ isomorphisms(X::EllipticSurface, Y::EllipticSurface) -> Vector{MorphismFromRationalFunctions}
+
+Given two elliptic surfaces `` X \to \mathbb{P}^1`` and `` Y \to \mathbb{P}^1`` return all
+isomorphisms ``X \to Y`` such that there exists Möbius transformation ``\mathbb{P}^1 \to \mathbb{P}^1``
+fitting in the following commutative diagram.
+```math
+\begin{array}{ccc}
+ X & \to & Y \\
+ \downarrow & & \downarrow\\
+ \mathbb{P}^1 & \to & \mathbb{P}^1
+\end{array}
+```
+"""
+isomorphisms(X::EllipticSurface, Y::EllipticSurface) = admissible_moebius_transformations(X, Y)
+
+isomorphisms_on_weierstrass_chart(X::EllipticSurface, Y::EllipticSurface) = admissible_moebius_transformations_on_weierstrass_chart(X, Y)
+
+function admissible_moebius_transformations(
+ X::EllipticSurface,
+ Y::EllipticSurface
+ )
+ result = MorphismFromRationalFunctions[]
+ for img_gens in _admissible_moebius_transformations(X, Y; on_weierstrass_model=false)
+ push!(result, _moebius_to_morphism_from_rational_functions(X, Y, img_gens))
+ end
+ return result
+end
+
+function admissible_moebius_transformations_on_weierstrass_chart(
+ X::EllipticSurface,
+ Y::EllipticSurface
+ )
+ result = MapFromFunc[]
+ for img_gens in _admissible_moebius_transformations(X, Y; on_weierstrass_model=true)
+ push!(result, _moebius_to_pullback_on_weierstrass_chart(X, Y, img_gens))
+ end
+ return result
+end
+
+function _admissible_moebius_transformations(
+ X::EllipticSurface,
+ Y::EllipticSurface; on_weierstrass_model=true
+ )
+ EX = generic_fiber(X)
+ EY = generic_fiber(Y)
+
+# kkt = base_field(EX)
+# @assert kkt === base_field(EY) "base fields of the generic fibers must coincide"
+ kk = base_ring(X)
+ @assert kk === base_ring(Y) "elliptic surfaces must be defined over the same field"
+
+ dX = numerator(discriminant(EX))::PolyRingElem
+ dY = numerator(discriminant(EY))::PolyRingElem
+
+ vX = roots(dX)
+ @assert all(is_one(degree(a)) for (a, k) in factor(dX)) "not all critical values are rational over the given ground field"
+
+ vY = roots(dY)
+ @assert all(is_one(degree(a)) for (a, k) in factor(dY)) "not all critical values are rational over the given ground field"
+
+# for (c, _) in reducible_fibers(X)
+# @assert !is_zero(c[2]) "the case of reducible fibers over the point at infinity is not implemented"
+# end
+# for (c, _) in reducible_fibers(Y)
+# @assert !is_zero(c[2]) "the case of reducible fibers over the point at infinity is not implemented"
+# end
+
+ # Use the first three elements of vX and map them to three elements of vY.
+ # Then check whether the resulting transformation preserves everything.
+
+ candidates = []
+
+ @assert length(vX) >= 3 "at least three reducible fibers are needed"
+ length(vX) == length(vY) || return candidates # No moebius transformation is possible in this case
+ kkt = base_field(EX)
+ t = gen(kkt)
+ p1 = vX[1:3]
+ for i in vY
+ for j in vY
+ i == j && continue
+ for k in vY
+ (i == k || j == k) && continue
+ p2 = [i, j, k]
+ mt = find_moebius_transformation(p1, p2)
+ any(is_zero(mt(x)[2]) for x in vX) && continue # reducible fibers over ∞ are not implemented at the moment.
+ any(!(mt(x)[1]//mt(x)[2] in vY) for x in vX) && continue # the transformation does not preserve all admissible fibers in this case
+ p, q = mt(t)
+ img_t = (p//q)::typeof(t)
+ EYbc = base_change(f->evaluate(f, img_t), EY)
+ is_isomorphic(EYbc, EX) || continue
+ iso_ell = isomorphism(EX, EYbc)
+ push!(candidates, _to_weierstrass_morphism(X, Y, mt, iso_ell; on_weierstrass_model))
+ end
+ end
+ end
+ return candidates
+end
+
+function _to_weierstrass_morphism(X, Y, mt, iso_ell; on_weierstrass_model)
+ EX = generic_fiber(X)
+ EY = generic_fiber(Y)
+ # Set up some variables
+ kkt = base_field(EX)
+ t = gen(kkt)
+ if on_weierstrass_model
+ WX = weierstrass_chart(X)
+ WY = weierstrass_chart(Y)
+ else
+ WX = weierstrass_chart_on_minimal_model(X)
+ WY = weierstrass_chart_on_minimal_model(Y)
+ end
+ RX = ambient_coordinate_ring(WX)
+ FRX = fraction_field(RX)
+ RY = ambient_coordinate_ring(WY)
+ FRY = fraction_field(RY)
+
+ # Construct the isomorphism of elliptic surfaces explicitly
+
+ a, b, _ = rational_maps(iso_ell)
+ kkTxy = parent(a)
+ to_FRX = hom(kkTxy, FRX, x->evaluate(x, FRX(RX[3])), FRX.([RX[1], RX[2]]))
+ A = to_FRX(a)
+ B = to_FRX(b)
+ P, Q = mt(FRX(RX[3]))
+ img_T = (P//Q)::elem_type(FRX)
+ img_gens = [A, B, img_T]
+ return img_gens
+end
+
+function _moebius_to_pullback_on_weierstrass_chart(X, Y, img_gens)
+ WY = weierstrass_chart(Y)
+ WX = weierstrass_chart(X)
+ RX = ambient_coordinate_ring(WX)
+ FRX = fraction_field(RX)
+ RY = ambient_coordinate_ring(WY)
+ FRY = fraction_field(RY)
+
+ return extend_domain_to_fraction_field(hom(RY, FRX, img_gens))
+end
+
+function _moebius_to_morphism_from_rational_functions(X, Y, img_gens)
+ WY = weierstrass_chart_on_minimal_model(Y)
+ WX = weierstrass_chart_on_minimal_model(X)
+
+ loc_res = morphism_from_rational_functions(X, Y, WX, WY, img_gens; check=true)
+ set_attribute!(loc_res, :is_isomorphism=>true)
+ return loc_res
+end
+
+# An internal helper routine to verify that a given isomorphism of elliptic surfaces
+# does indeed give an isomorphism on their generic fibers.
+function check_isomorphism_on_generic_fibers(phi::MorphismFromRationalFunctions{<:EllipticSurface, <:EllipticSurface})
+ X = domain(phi)
+ Y = codomain(phi)
+ @assert domain_chart(phi) === weierstrass_chart_on_minimal_model(X)
+ @assert codomain_chart(phi) === weierstrass_chart_on_minimal_model(Y)
+ EX = generic_fiber(X)
+ EY = generic_fiber(Y)
+ a, b, c = coordinate_images(phi)
+
+ hX = equation(EX)
+ RX = parent(hX)
+ FX = fraction_field(RX)
+ kktX = coefficient_ring(RX)
+
+ hY = equation(EY)
+ RY = parent(hY)
+ FY = fraction_field(RY)
+ kktY = coefficient_ring(RY)
+
+ A = evaluate(a, [RX[1], RX[2], RX(gen(kktX))])
+ B = evaluate(b, [RX[1], RX[2], RX(gen(kktX))])
+ C = evaluate(c, [RX[1], RX[2], RX(gen(kktX))])
+
+ help_map = hom(RY, FX, t->evaluate(t, C), [A, B])
+
+ hh = help_map(hY)
+
+ return divides(hX, numerator(hh))[1]
+end
+
+@doc raw"""
+ isomorphism_from_generic_fibers(X::EllipticSurface, Y::EllipticSurface, f::Hecke.EllCrvIso) -> MorphismFromRationalFunctions
+
+Given an isomorphism ``f`` between the generic fibers of ``X`` and ``Y``, return the corresponding
+isomorphism of ``X`` and ``Y`` over ``\mathbb{P}^1``.
+"""
+function isomorphism_from_generic_fibers(
+ X::EllipticSurface, Y::EllipticSurface, f::Hecke.EllCrvIso
+ )
+ EX = generic_fiber(X)
+ EY = generic_fiber(Y)
+ iso_ell = f
+ @req domain(f) == EX "must be an isomorphism of the generic fibers"
+ @req codomain(f) == EY "must be an isomorphism of the generic fibers"
+ a, b, _ = rational_maps(iso_ell)
+ kt = base_field(EX)
+ t = gen(kt)
+
+ # Make sure we got something reasonable
+ h2 = equation(EY)
+ pb_h2 = evaluate(h2, [a, b])
+ @assert divides(pb_h2, equation(parent(pb_h2), EX))[1]
+
+ WX = weierstrass_chart_on_minimal_model(X)
+ RX = ambient_coordinate_ring(WX)
+ FRX = fraction_field(RX)
+ WY = weierstrass_chart_on_minimal_model(Y)
+ RY = ambient_coordinate_ring(WY)
+ FRY = fraction_field(RY)
+
+ kkTxy = parent(a)
+ to_FRX = hom(kkTxy, FRX, x->evaluate(x, FRX(RX[3])), FRX.([RX[1], RX[2]]))
+ A = to_FRX(a)
+ B = to_FRX(b)
+ img_gens = [A, B, FRX(RX[3])]
+ m = morphism_from_rational_functions(X, Y, WX, WY, FRX.(img_gens); check=false)
+ set_attribute!(m, :is_isomorphism=>true)
+ return m
+end
+
+@doc raw"""
+ isomorphism_from_generic_fibers(X::EllipticSurface, Y::EllipticSurface) -> MorphismFromRationalFunctions
+
+Given given two elliptic surfaces ``X`` and ``Y`` whose generic fibers are isomorphic,
+return the corresponding isomorphism of ``X`` and ``Y`` over ``\mathbb{P}^1``.
+"""
+function isomorphism_from_generic_fibers(
+ X::EllipticSurface, Y::EllipticSurface
+ )
+ EX = generic_fiber(X)
+ EY = generic_fiber(Y)
+ is_isomorphic(EX, EY) || error("generic fibers are not isomorphic")
+ iso_ell = isomorphism(EX, EY)
+ return isomorphism_from_generic_fibers(X, Y, iso_ell)
+end
diff --git a/src/AlgebraicGeometry/Surfaces/EllipticSurface/MoveMeToHecke.jl b/src/AlgebraicGeometry/Surfaces/EllipticSurface/MoveMeToHecke.jl
new file mode 100644
index 000000000000..f8e307900f79
--- /dev/null
+++ b/src/AlgebraicGeometry/Surfaces/EllipticSurface/MoveMeToHecke.jl
@@ -0,0 +1,57 @@
+
+function evaluate(f::AbstractAlgebra.Generic.FracFieldElem{<:MPolyRingElem}, a::Vector{T}) where {T<:RingElem}
+ return evaluate(numerator(f), a)//evaluate(denominator(f), a)
+end
+
+function evaluate(f::AbstractAlgebra.Generic.FracFieldElem{<:PolyRingElem}, a::RingElem)
+ return evaluate(numerator(f), a)//evaluate(denominator(f), a)
+end
+
+function extend_domain_to_fraction_field(phi::Map{<:MPolyRing, <:Ring})
+ ext_dom = fraction_field(domain(phi))
+ return MapFromFunc(ext_dom, codomain(phi), x->phi(numerator(x))*inv(phi(denominator(x))))
+end
+
+
+function iszero(P::EllipticCurvePoint)
+ return iszero(P[1]) && isone(P[2]) && iszero(P[3])
+end
+
+@doc raw"""
+ extended_ade(ADE::Symbol, n::Int)
+
+Return the dual intersection matrix of an extended ade Dynkin diagram
+as well as the isotropic vector (with positive coefficients in the roots).
+"""
+function extended_ade(ADE::Symbol, n::Int)
+ R = change_base_ring(ZZ,gram_matrix(root_lattice(ADE,n)))
+ G = block_diagonal_matrix([ZZ[2;],R])
+ if ADE == :E && n == 8
+ G[1,n] = -1
+ G[n,1] = -1
+ end
+ if ADE == :E && n == 7
+ G[1,2] = -1
+ G[2,1] = -1
+ end
+ if ADE == :E && n == 6
+ G[1,n+1] = -1
+ G[n+1,1] = -1
+ end
+ if ADE == :A && n > 0
+ G[1,2] = -1
+ G[2,1] = -1
+ G[1,n+1] = -1
+ G[n+1,1] = -1
+ end
+ if ADE == :A && n ==1 0
+ G[1,2]= -2
+ G[2,1] = -2
+ end
+ if ADE == :D
+ G[1,n] = -1
+ G[n,1] = -1
+ end
+ @assert rank(G) == n
+ return -G, kernel(G; side = :left)
+end
diff --git a/src/AlgebraicGeometry/Surfaces/EllipticSurface/NeighborStep.jl b/src/AlgebraicGeometry/Surfaces/EllipticSurface/NeighborStep.jl
new file mode 100644
index 000000000000..f5706d9b7a1a
--- /dev/null
+++ b/src/AlgebraicGeometry/Surfaces/EllipticSurface/NeighborStep.jl
@@ -0,0 +1,899 @@
+################################################################################
+#
+# Some linear systems on elliptic surfaces
+#
+################################################################################
+
+@doc raw"""
+ _prop217(E::EllipticCurve, P::EllipticCurvePoint, k)
+
+Compute a basis for the linear system
+``|O + P + kF|``
+on the minimal elliptic (K3) surface defined by E.
+Here F is the class of a fiber O the zero section
+and P any non-torsion section.
+
+The return value is a list of pairs ``(a(t),b(t))``
+
+```jldoctest
+julia> kt,t = polynomial_ring(GF(29),:t);
+
+julia> ktfield = fraction_field(kt);
+
+julia> bk = [((17*t^4 + 23*t^3 + 18*t^2 + 2*t + 6, 8*t^5 + 2*t^4 + 6*t^3 + 25*t^2 + 24*t + 5 )),
+ ((17*t^6 + 3*t^5 + 16*t^4 + 4*t^3 + 13*t^2 + 6*t + 5)//(t^2 + 12*t + 7), (4*t^8 + 19*t^7 + 14*t^6 + 18*t^5 + 27*t^4 + 13*t^3 + 9*t^2 + 14*t + 12)//(t^3 + 18*t^2 + 21*t + 13) ),
+ ((17*t^6 + 10*t^5 + 24*t^4 + 15*t^3 + 22*t^2 + 27*t + 5)//(t^2 + 16*t + 6), (20*t^8 + 24*t^7 + 22*t^6 + 12*t^5 + 21*t^4 + 21*t^3 + 9*t^2 + 21*t + 12)//(t^3 + 24*t^2 + 18*t + 19) ),
+ ((17*t^8 + 21*t^7 + 20*t^5 + 24*t^4 + 21*t^3 + 4*t^2 + 9*t + 13)//(t^4 + 17*t^3 + 12*t^2 + 28*t + 28), (23*t^11 + 25*t^10 + 8*t^9 + 7*t^8 + 28*t^7 + 16*t^6 + 7*t^5 + 23*t^4 + 9*t^3 + 27*t^2 + 13*t + 13)//(t^6 + 11*t^5 + 14*t^4 + 13*t^3 + 6*t^2 + 18*t + 12) )];
+
+julia> E = elliptic_curve(ktfield,[3*t^8+24*t^7+22*t^6+15*t^5+28*t^4+20*t^3+16*t^2+26*t+16, 24*t^12+27*t^11+28*t^10+8*t^9+6*t^8+16*t^7+2*t^6+10*t^5+3*t^4+22*t^3+27*t^2+10*t+3]);
+
+julia> bk = [E(collect(i)) for i in bk];
+
+julia> Oscar._prop217(E,bk[2],2)
+5-element Vector{Tuple{FqPolyRingElem, FqPolyRingElem}}:
+ (t^2 + 12*t + 7, 0)
+ (t^3 + 8*t + 3, 0)
+ (t^4 + 23*t + 2, 0)
+ (25*t + 22, 1)
+ (12*t + 28, t)
+
+julia> Oscar._prop217(E,bk[1],1)
+2-element Vector{Tuple{FqPolyRingElem, FqPolyRingElem}}:
+ (1, 0)
+ (t, 0)
+```
+"""
+function _prop217(E::EllipticCurve, P::EllipticCurvePoint, k)
+ @req !iszero(P[3]) "P must not be torsion" # seems like we cannot check this
+ xn = numerator(P[1])
+ xd = denominator(P[1])
+ yn = numerator(P[2])
+ yd = denominator(P[2])
+ OP = divexact(max(degree(xd), degree(xn) - 4), 2)
+ dega = k + 2*OP
+ degb = k + 2*OP - 2 - divexact(degree(xd), 2) #?
+ base = base_field(E)
+ Bt = base_ring(base)
+ B = coefficient_ring(Bt)
+
+ R,ab = polynomial_ring(base,vcat([Symbol(:a,i) for i in 0:dega],[Symbol(:b,i) for i in 0:degb]),cached=false)
+ Rt, t1 = polynomial_ring(R,:t)
+ a = reduce(+,(ab[i+1]*t1^i for i in 0:dega), init=zero(Rt))
+ b = reduce(+,(ab[2+dega+j]*t1^j for j in 0:degb), init=zero(Rt))
+ c = a*xn(t1) - b*yn(t1)
+ r = mod(c, xd(t1))
+ # setup the linear equations for coefficients of r to vanish
+ # and for the degree of c to be bounded above by
+ # k + 2*OP + 4 + degree(xd)
+ eq1 = collect(coefficients(r))
+ eq2 = [coeff(c,i) for i in (k + 2*OP + 4 + degree(xd) + 1):degree(c)]
+ eqns = vcat(eq1, eq2)
+
+ # collect the equations as a matrix
+ cc = [[coeff(j, abi) for abi in ab] for j in eqns]
+ mat = reduce(vcat,cc, init=elem_type(base)[])
+ @assert all(is_one(denominator(x)) for x in mat)
+ @assert all(is_constant(numerator(x)) for x in mat)
+ mat2 = [constant_coefficient(numerator(x)) for x in mat]
+ M = matrix(B, length(eqns), length(ab), mat2)
+ # @assert M == matrix(base, cc) # does not work if length(eqns)==0
+ K = kernel(M; side = :right)
+ kerdim = ncols(K)
+ result = Tuple{elem_type(Bt),elem_type(Bt)}[]
+ t = gen(Bt)
+ for j in 1:kerdim
+ aa = reduce(+, (K[i+1,j]*t^i for i in 0:dega), init=zero(Bt))
+ bb = reduce(+, (K[dega+i+2,j]*t^i for i in 0:degb), init=zero(Bt))
+ push!(result, (aa, bb))
+ end
+ # confirm the computation
+ @assert kerdim == 2*k + OP # prediced by Riemann-Roch
+ for (a,b) in result
+ @assert mod(a*xn - b*yn, xd) == 0
+ @assert degree(a) <= k + 2*OP
+ @assert degree(b) <= k + 2*OP - 2 - 1//2*degree(xd)
+ @assert degree(a*xn - b*yn) <= k + 2*OP + 4 + degree(xd)
+ end
+ return result
+end
+
+@doc raw"""
+ linear_system(X::EllipticSurface, P::EllipticCurvePoint, k::Int) -> LinearSystem
+
+Compute the linear system ``|O + P + k F|`` on the elliptic surface ``X``.
+Here ``F`` is the class of the fiber over ``[0:1]``, ``O`` the zero section
+and ``P`` any section given as a point on the generic fiber.
+
+The linear system is represented in terms of the Weierstrass coordinates.
+"""
+function linear_system(X::EllipticSurface, P::EllipticCurvePoint, k::Int)
+ euler_characteristic(X) == 2 || error("linear system implemented only for elliptic K3s")
+ #FS = function_field(weierstrass_model(X)[1])
+ FS = function_field(X)
+ U = weierstrass_chart_on_minimal_model(X)
+ (x,y,t) = ambient_coordinates(U)
+
+ sections = elem_type(FS)[]
+ if iszero(P[3])
+ append!(sections, [FS(t)^(i-k) for i in 0:k])
+ append!(sections, [FS(t)^(i-k)*FS(x) for i in 0:k-4])
+ else
+ xn = numerator(P[1])
+ xd = denominator(P[1])
+ yn = numerator(P[2])
+ yd = denominator(P[2])
+
+ I = saturated_ideal(defining_ideal(U))
+ IP = ideal([x*xd(t)-xn(t),y*yd(t)-yn(t)])
+ @hassert :EllipticSurface 2 issubset(I, IP) || error("P does not define a point on the Weierstrasschart")
+
+ @assert gcd(xn, xd)==1
+ @assert gcd(yn, yd)==1
+ ab = _prop217(generic_fiber(X), P, k)
+ d = divexact(yd, xd)(t)
+ den = t^k*(x*xd(t) - xn(t))
+ for (a,b) in ab
+ c = divexact(b*yn - a*xn, xd)
+ num = a(t)*x+b(t)*d*y + c(t)
+ push!(sections, FS(num//den))
+ end
+ end
+ return sections
+end
+
+@doc raw"""
+ two_neighbor_step(X::EllipticSurface, F1::Vector{QQFieldElem})
+
+Let ``F`` be the class of a fiber of the elliptic fibration on ``X``.
+Given an isotropic nef divisor ``F_1`` with ``F_1.F = 2``,
+compute the linear system ``|F_1|`` and return the corresponding generic fiber
+as a double cover `C` of the projective line branched over four points.
+
+Input:
+``F_1`` is represented as a vector in the `algebraic_lattice(X)`
+``X`` must be a K3 surface
+
+Output:
+A tuple `(C, (x1, y1, t1))` defined as follows.
+- `C` is given by a polynomial ``y_1^2 - q(x_1)`` in ``k(t_1)[x_1,y_1]`` with ``q`` of degree ``3`` or ``4``.
+- (x1,y1,t1) are expressed as rational functions in terms of the weierstrass coordinates `(x,y,t)`.
+"""
+function two_neighbor_step(X::EllipticSurface, F::Vector{QQFieldElem})
+ E = generic_fiber(X)
+ basisNS, tors, NS = algebraic_lattice(X)
+ V = ambient_space(NS)
+ @req inner_product(V, F, F)==0 "not an isotropic divisor"
+ @req euler_characteristic(X) == 2 "not a K3 surface"
+ F0 = zeros(QQ,degree(NS)); F0[1]=1
+
+ @req inner_product(V, F, F0) == 2 "not a 2-neighbor"
+
+ D1, D, P, l, c = horizontal_decomposition(X, F)
+ u = _elliptic_parameter(X, D1, D, P, l, c)
+ @assert scheme(parent(u)) === X
+ pr = weierstrass_contraction(X)
+ WX, _ = weierstrass_model(X)
+ # The following is a cheating version of the command u = pushforward(pr)(u) (the latter has now been deprecated!)
+ u = function_field(WX)(u[weierstrass_chart_on_minimal_model(X)])
+ @assert scheme(parent(u)) === weierstrass_model(X)[1]
+
+ # Helper function
+ my_const(u::MPolyRingElem) = is_zero(u) ? zero(coefficient_ring(parent(u))) : first(coefficients(u))
+
+ # transform to a quartic y'^2 = q(x)
+ if iszero(P[3]) # P = O
+ eqn1, phi1 = _elliptic_parameter_conversion(X, u, case=:case1)
+ eqn2, phi2 = _normalize_hyperelliptic_curve(eqn1)
+# function phi_func(x)
+# y = phi1(x)
+# n = numerator(y)
+# d = denominator(y)
+# return phi2(n)//phi2(d)
+# end
+# phi = MapFromFunc(domain(phi1), codomain(phi2), phi_func)
+# # TODO: Verify that the construction below also works and replace by that, eventually.
+# phi_alt = compose(phi1, extend_domain_to_fraction_field(phi2))
+# @assert phi.(gens(domain(phi))) == phi_alt.(gens(domain(phi)))
+ phi = compose(phi1, extend_domain_to_fraction_field(phi2))
+ elseif iszero(2*P) # P is a 2-torsion section
+ eqn1, phi1 = _elliptic_parameter_conversion(X, u, case=:case3)
+ #eqn1, phi1 = _conversion_case_3(X, u)
+ (x2, y2) = gens(parent(eqn1))
+
+ # Make sure the coefficient of y² is one (or a square) so that
+ # completing the square works.
+ c = my_const(coeff(eqn1, [x2, y2], [0, 2]))::AbstractAlgebra.Generic.FracFieldElem
+ eqn1 = inv(unit(factor(c)))*eqn1
+
+ eqn2, phi2 = _normalize_hyperelliptic_curve(eqn1)
+ phi = compose(phi1, extend_domain_to_fraction_field(phi2))
+ else # P has infinite order
+ eqn1, phi1 = _elliptic_parameter_conversion(X, u, case=:case2)
+ #eqn1, phi1 = _conversion_case_2(X, u)
+ (x2, y2) = gens(parent(eqn1))
+
+ # Make sure the coefficient of y² is one (or a square) so that
+ # completing the square works.
+ c = my_const(coeff(eqn1, [x2, y2], [0, 2]))::AbstractAlgebra.Generic.FracFieldElem
+ eqn1 = inv(unit(factor(c)))*eqn1
+
+ eqn2, phi2 = _normalize_hyperelliptic_curve(eqn1)
+ phi = compose(phi1, extend_domain_to_fraction_field(phi2))
+ end
+
+ return eqn2, phi
+end
+
+@doc raw"""
+ horizontal_decomposition(X::EllipticSurface, L::Vector{QQFieldElem}) -> AbsWeilDivisor, EllipticCurvePoint
+
+Given a divisor ``L`` as a vector in the `algebraic_lattice(X)`
+find a linearly equivalent divisor ``(n-1) O + P + V = D ~ L`` where
+``O`` is the zero section, ``P`` is any section and ``V`` is vertical.
+
+Returns a tuple `(D1, D, P, l, c)` where `D` and `P` are as above and
+``D <= D1 = (n-1)O + P + n_1F_1 + ... n_k F_k`` with ``l = n_1 + ... n_k`` minimal
+and the `F_i` are some other fibers.
+The rational function `c=c(t)` has divisor of zeros and poles``
+(c) = lF - n_0F_1 + ... n_k F_k``
+"""
+function horizontal_decomposition(X::EllipticSurface, F::Vector{QQFieldElem})
+ E = generic_fiber(X)
+ basisNS, tors, NS = algebraic_lattice(X)
+ V = ambient_space(NS)
+ @req F in algebraic_lattice(X)[3] "not in the algebraic lattice"
+ @req inner_product(V, F, F)==0 "not an isotropic divisor"
+ @req euler_characteristic(X) == 2 "not a K3 surface"
+ # how to give an ample divisor automagically in general?
+ # @req is_nef(X, F) "F is not nef"
+ l = F[1]
+ rk_triv = nrows(trivial_lattice(X)[2])
+ n = rank(NS)
+ @assert degree(NS) == rank(NS)
+ p, P = _vertical_part(X,F)
+ D = section(X, P)
+ F2 = F - p
+ @vprint :EllipticSurface 4 "F2 = $(F2)\n"
+ D = D + ZZ(F2[2])*zero_section(X)
+ D1 = D
+ F2 = ZZ.(F2); F2[2] = 0
+ l = F2[1] # number of fibers that we need
+ # find the fiber components meeting O necessary
+ F3 = F2
+ (_,_,t) = ambient_coordinates(weierstrass_chart_on_minimal_model(X))
+ c = t^0
+ for (pt, rt, fiber, comp, gram) in reducible_fibers(X)
+ Fib0 = comp[1]
+ f0 = zeros(QQFieldElem, length(basisNS))
+ for i in 1:length(basisNS)
+ if !isone(components(Fib0)[1]+components(basisNS[i])[1])
+ if length(comp)==2 && 2=0 for i in 1:length(basisNS))
+ D = D + sum(ZZ(F4[i])*basisNS[i] for i in 1:length(basisNS))
+ @assert D<=D1
+ return D1, D, P, Int(l), c
+end
+
+# internal method used for two neighbor steps
+# in the horizontal_decomposition
+function _vertical_part(X::EllipticSurface, v::QQMatrix)
+ @req nrows(v)==1 "not a row vector"
+ _,tors, NS = algebraic_lattice(X)
+ E = generic_fiber(X)
+ @req ncols(v)==degree(NS) "vector of wrong size $(ncols(v))"
+ @req v in NS "not an element of the lattice"
+ mwl_rank = length(X.MWL)
+ rk_triv = rank(NS)-mwl_rank
+ n = rank(NS)
+ P = sum([ZZ(v[1,i])*X.MWL[i-rk_triv] for i in (rk_triv+1):n], init = E([0,1,0]))
+ p = zero_matrix(QQ, 1, rank(NS)) # the section part
+ p[1,end-mwl_rank+1:end] = v[1,end-mwl_rank+1:end]
+ p[1,2] = 1 - sum(p) # assert p.F = 1 by adding a multiple of the zero section O
+
+ # P meets exactly one fiber component per fiber
+ # and that one must be simple, it can be the one meeting O or not
+ # assert this by adding fiber components under the additional condition that p stays in the algebraic lattice
+ simples = []
+ E = identity_matrix(QQ,rank(NS))
+ z = zero_matrix(QQ,1, rank(NS))
+ r = 2
+ for fiber in _trivial_lattice(X)[3]
+ fiber_type = fiber[2]
+ fiber_rk = fiber_type[2]
+ h = highest_root(fiber_type...)
+ simple_indices = [r+i for i in 1:ncols(h) if isone(h[1,i])]
+ simple_or_zero = [E[i:i,:] for i in simple_indices]
+ push!(simple_or_zero, z)
+ push!(simples,simple_or_zero)
+ r += fiber_rk
+ end
+ G = gram_matrix(ambient_space(NS))
+ pG = (p*G)[1:1,3:r]
+ T = Tuple(simples)
+ GF = G[3:r,3:r]
+ candidates = QQMatrix[]
+ for s in Base.Iterators.ProductIterator(T)
+ g = sum(s)[:,3:r]
+ y = (g - pG)
+ xx = solve(GF,y;side=:left)
+ x = zero_matrix(QQ,1, rank(NS))
+ x[:,3:r] = xx
+ if x in NS
+ push!(candidates,p+x)
+ end
+ end
+ @assert length(candidates)>0
+ # Select the candidate congruent to v modulo Triv
+ mwg = _mordell_weil_group(X)
+ vmwg = mwg(vec(collect(v)))
+ candidates2 = [mwg(vec(collect(x))) for x in candidates]
+ i = findfirst(==(vmwg), candidates2)
+ t = mwg(vec(collect(p - candidates[i])))
+ mwl_tors_gens = [mwg(vec(collect(i[2]))) for i in tors]
+ ag = abelian_group(zeros(ZZ,length(tors)))
+ mwlAb = abelian_group(mwg)
+ phi = hom(ag, mwlAb, mwlAb.(mwl_tors_gens))
+ a = preimage(phi, mwlAb(t))
+ for i in 1:ngens(ag)
+ P += a[i]*rational_point(tors[i][1])
+ end
+
+ p = candidates[i]
+ k = (p*G*transpose(p))[1,1]
+ # assert p^2 = -2
+ p[1,1] = -k/2-1
+ V = ambient_space(NS)
+ @hassert :EllipticSurface 1 inner_product(V, p, p)[1,1]== -2
+ @hassert :EllipticSurface 1 mwg(vec(collect(p))) == mwg(vec(collect(p)))
+ @hassert :EllipticSurface 3 basis_representation(X,section(X,P))==vec(collect(p))
+ return p, P
+end
+
+function _vertical_part(X::EllipticSurface, v::Vector{QQFieldElem})
+ vv = matrix(QQ,1,length(v),v)
+ p, P = _vertical_part(X,vv)
+ pp = vec(collect(p))
+ return pp, P
+end
+
+@doc raw"""
+ elliptic_parameter(X::EllipticSurface, F::Vector{QQFieldElem}) -> LinearSystem
+
+Return the elliptic parameter ``u`` of the divisor class `F`.
+
+The input `F` must be given with respect to the basis of
+`algebraic_lattice(X)` and be an isotropic nef divisor.
+This method assumes that $X$ is a K3 surface.
+"""
+function elliptic_parameter(X::EllipticSurface, F::Vector{QQFieldElem})
+ D1, D, P, l, c = horizontal_decomposition(X, F)
+ return _elliptic_parameter(X, D1, D, P, l, c)
+end
+
+@doc raw"""
+ _elliptic_parameter(X::EllipticSurface, D::AbsWeilDivisor, l, c)
+
+Compute the linear system of ``D = (n-1) O + P + V``.
+where V is vertical and `l` is the coefficient of the fiber class.
+Assumes `D` nef and `D^2=0`.
+Typically ``D`` is the output of `horizontal_decomposition`.
+"""
+function _elliptic_parameter(X::EllipticSurface, D1::AbsWeilDivisor, D::AbsWeilDivisor, P::EllipticCurvePoint, l::Int, c)
+ S, piS = weierstrass_model(X);
+ piX = weierstrass_contraction(X)
+ c = function_field(X)(c)
+ L = [i*c for i in linear_system(X, P, l)];
+ LonX = linear_system(L, D1, check=false);
+
+ LsubF, Tmat = subsystem(LonX, D);
+ LsubFonS = [sum(Tmat[i,j]*L[j] for j in 1:ncols(Tmat)) for i in 1:nrows(Tmat)]
+
+ @assert length(LsubFonS)==2
+ u2 = LsubFonS[2]//LsubFonS[1]
+ return u2
+end
+
+
+########################################################################
+# Internal functionality for Weierstrass transformation
+########################################################################
+
+@doc raw"""
+ _normalize_hyperelliptic_curve(g::MPolyRingElem, parent=nothing)
+
+Transform ``a(x)y^2 + b(x)y - h(x)`` in ``K(t)[x,y]`` to ``y'^2 - h(x')``
+"""
+function _normalize_hyperelliptic_curve(g::MPolyRingElem; parent::Union{MPolyRing, Nothing}=parent(g))
+ R = Oscar.parent(g)
+ @assert ngens(R) == 2 "polynomial must be bivariate"
+ F = fraction_field(R)
+ kt = coefficient_ring(R)
+ (x, y) = gens(R)
+
+ # Prepare the output ring
+ if parent===nothing
+ R1, (x1, y1) = R, gens(R)
+ else
+ R1 = parent
+ @assert coefficient_ring(R1) == coefficient_ring(R) "coefficient ring of output is incompatible with input"
+ (x1, y1) = gens(R1)
+ end
+
+ # Get the coefficients of g as a univariate polynomial in y
+ ktx, X = polynomial_ring(kt, :X, cached=false)
+ ktxy, Y = polynomial_ring(ktx, :y, cached=false)
+
+ # Maps to transform to univariate polynomials in y
+ split_map_R = hom(R, ktxy, [ktxy(X), Y])
+ split_map_R1 = hom(R1, ktxy, [ktxy(X), Y])
+ G = split_map_R(g)
+ @assert degree(G) == 2 "polynomial must be of degree 2 in its second variable"
+
+ #complete the square
+ h, b, a = collect(coefficients(G))
+ h = -h
+ u = unit(factor(a))
+ a = inv(u)*a
+ b = inv(u)*b
+ success, sqa = is_square_with_sqrt(a)
+ @assert success "leading coefficient as univariate polynomial in the second variable must be a square"
+
+ F1 = fraction_field(R1)
+ psi = hom(R1, F, F.([x, (2*evaluate(a, x)*y + evaluate(b, x))//(2*evaluate(sqa, x))]))
+ conv = MapFromFunc(ktx, R1, f->evaluate(f, x1))
+ (a1, b1, sqa1) = conv.([a, b, sqa])
+ phi = hom(R, F1, F1.([x1, (2*sqa1*y1-b1)//(2*a1)]))
+ phiF = MapFromFunc(F, F1, x-> phi(numerator(x))//phi(denominator(x)))
+ # the inverse map if wanted
+ # psiF = MapFromFunc(F1, F, x-> psi(numerator(x))//psi(denominator(x)))
+ # @assert all(phiF(psiF(F1(i)))==i for i in gens(R1))
+
+ # absorb squares into y1
+ g1 = numerator(phi(g))
+ G1 = split_map_R1(g1)
+ ff = factor(first(coefficients(G1)))
+ c = prod([p^div(i, 2) for (p, i) in ff], init=one(ktx))
+ #d = sqrt(my_coeff(g1, y1, 2))
+ d = last(coefficients(split_map_R1(g1)))
+ success, d = is_square_with_sqrt(d)
+ @assert success "leading coefficient must be a square"
+
+ phi1 = hom(R1, F1, [F1(x1), F1(evaluate(c, x1), evaluate(d, x1))*y1])
+ phiF1 = MapFromFunc(F1, F1, x-> phi1(numerator(x))//phi1(denominator(x)))
+ phi2 = compose(phi, phiF1)
+ g2 = numerator(phi1(g1))
+ #c = my_coeff(g2, y1, 2)
+ c = last(coefficients(split_map_R1(g2)))
+ g2 = divexact(g2, evaluate(c, x1))
+ @assert degree(g2, gen(parent, 1)) <= 4 "degree in the first variable is too high"
+ @assert degree(g2, gen(parent, 1)) >= 3 "degree in the first variable is too low"
+ return g2, phi2
+end
+
+@doc raw"""
+ transform_to_weierstrass(g::MPolyRingElem, x::MPolyRingElem, y::MPolyRingElem, P::Vector{<:RingElem})
+
+Transform a bivariate polynomial `g` of the form `y^2 - Q(x)` with `Q(x)` of degree ``≤ 4``
+to Weierstrass form. This returns a pair `(f, trans)` where `trans` is an endomorphism of the
+`fraction_field` of `parent(g)` and `f` is the transform. The input `P` must be a rational point
+on the curve defined by `g`, i.e. `g(P) == 0`.
+"""
+function transform_to_weierstrass(g::MPolyRingElem, x::MPolyRingElem, y::MPolyRingElem, P::Vector{<:RingElem})
+ R = parent(g)
+ F = fraction_field(R)
+ @assert ngens(R) == 2 "input polynomial must be bivariate"
+ @assert x in gens(R) "second argument must be a variable of the parent of the first"
+ @assert y in gens(R) "third argument must be a variable of the parent of the first"
+ # In case of variables in the wrong order, switch and transform the result.
+ if x == R[2] && y == R[1]
+ switch = hom(R, R, reverse(gens(R)))
+ g_trans, trans = transform_to_weierstrass(switch(g), y, x, reverse(P))
+ new_trans = MapFromFunc(F, F, f->begin
+ switch_num = switch(numerator(f))
+ switch_den = switch(denominator(f))
+ interm_res = trans(F(switch_num))//trans(F(switch_den))
+ num = numerator(interm_res)
+ den = denominator(interm_res)
+ switch(num)//switch(den)
+ end
+ )
+ return switch(g_trans), new_trans
+ end
+
+ g = inv(coeff(g,[0,2]))*g # normalise g
+ kk = coefficient_ring(R)
+ kkx, X = polynomial_ring(kk, :x, cached=false)
+ kkxy, Y = polynomial_ring(kkx, :y, cached=false)
+
+ imgs = [kkxy(X), Y]
+ split_map = hom(R, kkxy, imgs)
+
+ G = split_map(g)
+ @assert degree(G) == 2 "input polynomial must be of degree 2 in y"
+ @assert all(h->degree(h)<=4, coefficients(G)) "input polynomial must be of degree <= 4 in x"
+ @assert iszero(coefficients(G)[1]) "coefficient of linear term in y must be zero"
+ @assert isone(coefficients(G)[2]) "leading coefficient in y must be one"
+
+ if length(P) == 3 && isone(P[3])
+ P = P[1:2]
+ end
+
+
+ if length(P) == 2
+ @assert iszero(evaluate(g, P)) "point does not lie on the hypersurface"
+ (px, py) = P
+ else
+ px = P[1]
+ end
+ # assert g.subs({x:px,y:py})==0
+ gx = -evaluate(g, [X + px, zero(X)])
+ coeff_gx = collect(coefficients(gx))
+ A = coeff(gx, 4)
+ B = coeff(gx, 3)
+ C = coeff(gx, 2)
+ D = coeff(gx, 1)
+ E = coeff(gx, 0)
+ #E, D, C, B, A = coeff_gx
+ if length(P)==3
+ @req all(h->degree(h)<=3, coefficients(G)) "infinity (0:1:0) is not a point of this hypersurface"
+ # y^2 = B*x^3+C*x^2+C*x+D
+ x1 = F(inv(B)*x)
+ y1 = F(inv(B)*y)
+ trans = MapFromFunc(F, F, f->evaluate(numerator(f), [x1, y1])//evaluate(denominator(f), [x1, y1]))
+ f_trans = B^2*trans(F(g))
+ result = numerator(B^2*f_trans)
+ return result, trans
+ elseif !iszero(E)
+ b = py
+ a4, a3, a2, a1, a0 = A,B,C,D,E
+ A = b
+ B = a1//(2*b)
+ C = (4*a2*b^2-a1^2)//(8*b^3)
+ D = -2*b
+
+ x1 = x//y
+ y1 = (A*y^2+B*x*y+C*x^2+D*x^3)//y^2
+ x1 = x1+px
+
+ # TODO: The following are needed for the inverse. To be added eventually.
+ # x2 = (y-(A+B*x+C*x^2))//(D*x^2)
+ # y2 = x2//x
+ # x2 = evaluate(x2, [x-px, y])
+ # y2 = evaluate(y2, [x-px, y])
+
+ # @assert x == evaluate(x1, [x2, y2])
+ # @assert y == evaluate(y1, [x2, y2])
+ else
+ # TODO compute the inverse transformation (x2,y2)
+ x1 = 1//x
+ y1 = y//x^2
+ g1 = numerator(evaluate(g, [x1, y1]))
+ c = coeff(g1, [x], [3])
+ x1 = evaluate(x1, [-x//c, y//c])
+ y1 = evaluate(y1, [-x//c, y//c])
+ x1 = x1+px
+ #@assert x == evaluate(x1, [x2, y2])
+ #@assert y == evaluate(y1, [x2, y2])
+ end
+ @assert F === parent(x1) "something is wrong with caching of fraction fields"
+ # TODO: eventually add the inverse.
+ trans = MapFromFunc(F, F, f->evaluate(numerator(f), [x1, y1])//evaluate(denominator(f), [x1, y1]))
+ f_trans = trans(F(g))
+ fac = [a[1] for a in factor(numerator(f_trans)) if isone(a[2]) && _is_in_weierstrass_form(a[1])]
+ isone(length(fac)) || error("transform to weierstrass form did not succeed")
+
+ # normalize the output
+ result = first(fac)
+ result = inv(first(coefficients(coeff(result, gens(parent(result)), [3, 0]))))*result
+
+ return result, trans
+end
+
+function _is_in_weierstrass_form(f::MPolyRingElem)
+ R = parent(f)
+ @req ngens(R) == 2 "polynomial must be bivariate"
+ # Helper function
+ my_const(u::MPolyRingElem) = is_zero(u) ? zero(coefficient_ring(parent(u))) : first(coefficients(u))
+
+ (x, y) = gens(R)
+ f = -inv(my_const(coeff(f, [x, y], [0, 2]))) * f
+ isone(-coeff(f, [x, y], [0, 2])) || return false
+ isone(coeff(f, [x, y], [3, 0])) || return false
+
+ a6 = coeff(f, [x,y], [0,0])
+ a4 = coeff(f, [x,y], [1,0])
+ a2 = coeff(f, [x,y], [2,0])
+ a3 = -coeff(f, [x,y], [0,1])
+ a1 = -coeff(f, [x,y], [1,1])
+ a_invars = [my_const(i) for i in [a1,a2,a3,a4,a6]]
+ (a1,a2,a3,a4,a6) = a_invars
+ return f == (-(y^2 + a1*x*y + a3*y) + (x^3 + a2*x^2 + a4*x + a6))
+end
+
+########################################################################
+# The three conversions from Section 39.1 in
+# A. Kumar: "Elliptic Fibrations on a generic Jacobian Kummer surface"
+# pp. 44--45.
+########################################################################
+
+function _elliptic_parameter_conversion(X::EllipticSurface, u::VarietyFunctionFieldElem;
+ case::Symbol=:case1, names=[:x, :y, :t]
+ )
+ @req variety(parent(u)) === weierstrass_model(X)[1] "function field element must live on the weierstrass model of the first argument"
+ @req length(names) == 3 "need 3 variable names x, y, t"
+ U = weierstrass_chart(X)
+ R = ambient_coordinate_ring(U)
+ x, y, t = gens(R)
+ loc_eqn = first(gens(modulus(OO(U))))
+ E = generic_fiber(X)::EllipticCurve
+ f = equation(E)
+ kk = base_ring(X)
+ kkt_frac_XY = parent(f)::MPolyRing
+ (xx, yy) = gens(kkt_frac_XY)
+ kkt_frac = coefficient_ring(kkt_frac_XY)::AbstractAlgebra.Generic.FracField
+ kkt = base_ring(kkt_frac)::PolyRing
+ T = first(gens(kkt))
+
+# kk = base_ring(U)
+# kkt, T = polynomial_ring(kk, :T, cached=false)
+# kkt_frac = fraction_field(kkt)
+# kkt_frac_XY, (xx, yy) = polynomial_ring(kkt_frac, [:X, :Y], cached=false)
+ R_to_kkt_frac_XY = hom(R, kkt_frac_XY, [xx, yy, kkt_frac_XY(T)])
+
+ f_loc = first(gens(modulus(OO(U))))
+ @assert f == R_to_kkt_frac_XY(f_loc) && _is_in_weierstrass_form(f) "local equation is not in Weierstrass form"
+ a = a_invariants(E)
+
+ u_loc = u[U]::AbstractAlgebra.Generic.FracFieldElem # the representative on the Weierstrass chart
+
+ # Set up the ambient_coordinate_ring of the new Weierstrass-chart
+ kkt2, t2 = polynomial_ring(kk, names[3], cached=false)
+ kkt2_frac = fraction_field(kkt2)
+ S, (x2, y2) = polynomial_ring(kkt2_frac, names[1:2], cached=false)
+ FS = fraction_field(S)
+
+ # Helper function
+ my_const(u::MPolyRingElem) = is_zero(u) ? zero(coefficient_ring(parent(u))) : first(coefficients(u))
+
+ # We verify the assumptions made on p. 44 of
+ # A. Kumar: "Elliptic Fibrations on a generic Jacobian Kummer surface"
+ # for the first case considered there.
+ @assert all(x->isone(denominator(x)), a) "local equation does not have the correct form"
+ a = numerator.(a)
+ @assert iszero(a[1]) "local equation does not have the correct form"
+ @assert degree(a[2]) <= 4 "local equation does not have the correct form"
+ @assert iszero(a[3]) "local equation does not have the correct form"
+ @assert degree(a[4]) <= 8 "local equation does not have the correct form"
+ @assert degree(a[5]) <= 12 "local equation does not have the correct form" # This is really a₆ in the notation of the paper, a₅ does not exist.
+ # reduce fraction
+ u_frac = R_to_kkt_frac_XY(numerator(u_loc))//R_to_kkt_frac_XY(denominator(u_loc))
+ u_num = numerator(u_frac)
+ u_den = denominator(u_frac)
+ if case == :case1
+ # D = 2O
+ u_poly = u_num*inv(u_den) # Will throw if the latter is not a unit
+ # Extract a(t) and b(t) as in the notation of the paper
+ a_t = my_const(coeff(u_poly, [xx, yy], [0, 0]))
+ b_t = my_const(coeff(u_poly, [xx, yy], [1, 0]))
+
+ a_t = evaluate(a_t, x2)
+ b_t = evaluate(b_t, x2)
+ phi = hom(R, FS, FS.([(t2 - a_t)//b_t, y2, x2]))
+ f_trans = phi(f_loc)
+ return numerator(f_trans), phi
+ elseif case == :old
+ # D = O + P
+ @assert degree(u_num, 2) == 1 && degree(u_num, 1) <= 1 "numerator does not have the correct degree"
+ @assert degree(u_den, 1) == 1 && degree(u_den, 2) == 0 "denominator does not have the correct degree"
+
+ # We expect a form as on p. 44, l. -4
+ denom_unit = my_const(coeff(u_den, [xx, yy], [1, 0]))
+ x0 = -inv(denom_unit)*my_const(coeff(u_den, [xx, yy], [0, 0]))
+ b_t = inv(denom_unit)*my_const(coeff(u_num, [xx, yy], [0, 1]))
+ u_num = u_num - denom_unit * b_t * yy
+ a_t = inv(denom_unit)*my_const(coeff(u_num, [xx, yy], [1, 0]))
+ u_num = u_num - denom_unit * a_t * (xx - x0)
+ @assert is_constant(u_num) "numerator is not in the correct form"
+ y0 = my_const(coeff(u_num, [xx, yy], [0, 0])) * inv(denom_unit * b_t)
+
+ @assert a_t + b_t*(yy + y0)//(xx - x0) == u_frac "decomposition failed"
+ # We have
+ #
+ # y ↦ (u - a_t) * (x - x₀) / b_t - y₀ = (t₂ - a_t(x₂)) * (y₂ - x₀(x₂)) / b_t(x₂) - y₀(x₂)
+ # x ↦ y₂
+ # t ↦ x₂
+ phi = hom(R, FS, FS.([y2, (t2 - evaluate(a_t, x2)) * (y2 - evaluate(x0, x2)) // evaluate(b_t, x2) - evaluate(y0, x2), x2]))
+ f_trans = phi(f_loc)
+ eqn1 = numerator(f_trans)
+ # According to
+ # A. Kumar: "Elliptic Fibrations on a generic Jacobian Kummer surface"
+ # p. 45, l. 1 we expect the following cancelation to be possible:
+ divisor_num = evaluate(numerator(x0), x2)
+ divisor_den = evaluate(denominator(x0), x2)
+ divisor = divisor_den * y2 - divisor_num
+ success, eqn1 = divides(eqn1, divisor) # This division must only be possible in the ring K(x2)[y2].
+ # Hence, multiplying by the denominator `divisor_den` is
+ # merely an educated guess.
+ @assert success "division failed"
+ return eqn1, phi
+ elseif case == :case3
+ # D = O + T
+
+ @assert u_den == xx "elliptic parameter was not brought to the correct form"
+ @assert degree(u_num, 1) <= 1 && degree(u_num, 2) <= 1 "numerator does not have the correct degrees"
+ a_t = my_const(coeff(u_num, [xx, yy], [1, 0]))
+ b_t = my_const(coeff(u_num, [xx, yy], [0, 1]))
+
+ # New Weierstrass equation is of the form
+ #
+ # x^2 = h(t, u)
+ #
+ # so y₂ = x, x₂ = t, and t₂ = u.
+ #
+ # We have u = a_t + b_t * y/x ⇒ y = (u - a_t) * x / b_t = (t₂ - a_t(x₂)) * y₂ / b_t(x₂)
+ phi = hom(R, FS, FS.([y2, (t2 - evaluate(a_t, x2)) * y2 // evaluate(b_t, x2), x2]))
+ f_trans = phi(f_loc)
+ eqn1 = numerator(f_trans)
+ # According to
+ # A. Kumar: "Elliptic Fibrations on a generic Jacobian Kummer surface"
+ # p. 45, l. 15 we expect the following cancelation to be possible:
+ success, eqn1 = divides(eqn1, y2)
+ @assert success "equation did not come out in the anticipated form"
+ return eqn1, phi
+ elseif case == :case2
+ # D = O + P
+ @assert degree(u_num, 2) == 1 && degree(u_num, 1) <= 1 "numerator does not have the correct degree"
+ @assert degree(u_den, 1) == 1 && degree(u_den, 2) <= 1 "denominator does not have the correct degree"
+
+ # u = (ax + by + c)/(a'x + b'y + c')
+ an = my_const(coeff(u_num, [xx, yy], [1, 0]))
+ bn = my_const(coeff(u_num, [xx, yy], [0, 1]))
+ cn = my_const(coeff(u_num, [xx, yy], [0, 0]))
+
+ ad = my_const(coeff(u_den, [xx, yy], [1, 0]))
+ bd = my_const(coeff(u_den, [xx, yy], [0, 1]))
+ cd = my_const(coeff(u_den, [xx, yy], [0, 0]))
+
+ @assert (an*xx+bn*yy+cn)//(ad*xx+bd*yy+cd) == u_frac "decomposition failed"
+
+
+ v = solve(matrix(parent(an), 2, 2, [-an, bn,-ad, bd]), matrix(parent(an), 2, 1, [cn, cd]); side=:right)
+ x0 = v[1,1]
+ y0 = v[2,1]
+ @assert evaluate(f_loc,[x0,y0,gen(parent(x0))])==0
+
+ ad = evaluate(ad,x2)
+ an = evaluate(an,x2)
+ bd = evaluate(bd,x2)
+ bn = evaluate(bn,x2)
+ cn = evaluate(cn,x2)
+ cd = evaluate(cd,x2)
+ #x0 = evaluate(x0,x2)
+ #y0 = evaluate(y0,x2)
+
+
+ imgy = -FS(((ad*t2 - an )*y2 + (cd*t2 -cn)) //(bd*t2 -bn))
+
+ # We have
+ #
+ # y ↦ -((ad u - an )x + (cd u -cn)) // (bd*u -bn)
+ # x ↦ y₂
+ # t ↦ x₂
+ phi = hom(R, FS, [y2, imgy, x2])
+ f_trans = phi(f_loc)
+ eqn1 = numerator(f_trans)
+ # According to
+ # A. Kumar: "Elliptic Fibrations on a generic Jacobian Kummer surface"
+ # p. 45, l. 1 we expect the following cancellation to be possible:
+ divisor_num = evaluate(numerator(x0), x2)
+ divisor_den = evaluate(denominator(x0), x2)
+ divisor = divisor_den * y2 - divisor_num
+ success, eqn1 = divides(eqn1, divisor) # This division must only be possible in the ring K(x2)[y2].
+ # Hence, multiplying by the denominator `divisor_den` is
+ # merely an educated guess.
+ @assert success "division failed"
+ return eqn1, phi
+ else
+ error("case not recognized")
+ end
+end
+
+
+# Given a bivariate polynomial over a univariate function field,
+# normalize the associated elliptic curve so that the usual constructor
+# for elliptic surfaces digests it, and then return it, together with the
+# transformation on the algebraic side.
+#
+# The transformation is a morphism from the fraction field of the
+# parent of g to the fraction field of the `ambient_coordinate_ring`
+# of the `weierstrass_chart` of the resulting surface.
+function _elliptic_surface_with_trafo(g::MPolyRingElem{<:AbstractAlgebra.Generic.FracFieldElem}; minimize::Bool=true)
+ x, y = gens(parent(g))
+ E = elliptic_curve(g, x, y)
+ kkt = base_field(E)
+ kk = coefficient_ring(base_ring(kkt))
+
+ FFt, t = rational_function_field(kk, :t)
+
+ # The following three commands won't work unless we convert to a rational_function_field
+ EE = base_change(x->evaluate(x, t), E)
+ if minimize
+ EE = tates_algorithm_global(EE)
+ EE, _ = short_weierstrass_model(EE)
+ EE, _ = integral_model(EE)
+ end
+
+ # ...and back.
+ E2 = base_change(x->evaluate(x, gen(kkt)), EE)
+
+ @assert is_isomorphic(E, E2)
+ a, b, _ = rational_maps(isomorphism(E2, E))
+
+ eq_E = equation(E)
+ eq_E2 = equation(E2)
+
+ h = evaluate(eq_E, [a, b])
+ @assert divides(h, eq_E2)[1]
+
+ cod = parent(a)::MPolyRing
+
+ #phi = hom(R, cod, cod.([a, b]))
+ #Phi = extend_domain_to_fraction_field(phi)
+
+ result = elliptic_surface(E2, 2)
+ W = weierstrass_chart(result)
+ R = ambient_coordinate_ring(W)
+ FR = fraction_field(R)
+
+ help_map = hom(cod, FR, t->evaluate(t, FR(R[3])), FR.([R[1], R[2]]))
+ A = help_map(a)
+ B = help_map(b)
+
+ res_map = hom(parent(g), FR, t->evaluate(t, FR(R[3])), [A, B])
+ return result, extend_domain_to_fraction_field(res_map)
+end
+
+
+
+# TODO: Instead return an abelian group A and two maps.
+# algebraic_lattice -> A
+# A -> MWL= E(k(t))
+function _mordell_weil_group(X)
+ N = algebraic_lattice(X)[3]
+ V = ambient_space(N)
+ t = nrows(trivial_lattice(X)[2])
+ Triv = lattice(V, identity_matrix(QQ,dim(V))[1:t,:])
+ return torsion_quadratic_module(N, Triv;modulus=1, modulus_qf=1, check=false)
+end
+
diff --git a/src/AlgebraicGeometry/Surfaces/EllipticSurface/Types.jl b/src/AlgebraicGeometry/Surfaces/EllipticSurface/Types.jl
new file mode 100644
index 000000000000..07caee1d56b0
--- /dev/null
+++ b/src/AlgebraicGeometry/Surfaces/EllipticSurface/Types.jl
@@ -0,0 +1,97 @@
+@doc raw"""
+ EllipticSurface{BaseField<:Field, BaseCurveFieldType} <: AbsCoveredScheme{BaseField}
+
+A relatively minimal elliptic surface defined as follows.
+
+A genus ``1``-fibration is a proper map
+```math
+\pi \colon X \to C
+```
+from a smooth projective surface ``X`` to a smooth projective curve ``C`` whose generic fiber is a curve of (arithmetic) genus ``1``.
+
+The fibration is relatively minimal if its fibers do not contain any ``(-1)``-curves.
+We call the fibration elliptic if it is relatively minimal and comes equipped with a section ``\sigma_0\colon \mathbb{P}^1 \to X``.
+This turns the generic fiber of ``\pi`` into an elliptic curve ``E/k(C)`` where
+``k(C)`` is the function field of the curve ``C``.
+
+We further require that ``\pi`` has at least one singular fiber and that the base field ``k`` is perfect.
+
+For now functionality is restricted to ``C = \mathbb{P}^1``.
+
+This datatype stores a subgroup of the Mordell-Weil group ``E(k(C))``.
+It is referred to as the Mordell-Weil subgroup of `X`.
+"""
+@attributes mutable struct EllipticSurface{BaseField<:Field, BaseCurveFieldType} <: AbsCoveredSurface{BaseField}
+ Y::CoveredScheme{BaseField} # the underlying_scheme
+ E::EllipticCurve{BaseCurveFieldType}
+ MWL::Vector{EllipticCurvePoint{BaseCurveFieldType}} # basis for the mordell weil group
+ MWLtors::Vector{EllipticCurvePoint{BaseCurveFieldType}} # torsion sections
+ Weierstrasschart::AbsAffineScheme
+ Weierstrassmodel::CoveredScheme
+ inc_Weierstrass::CoveredClosedEmbedding # inclusion of the weierstrass chart in its ambient projective bundle
+ inc_Y::CoveredClosedEmbedding # inclusion of Y in its ambient blown up projective bundle
+ euler_characteristic::Int
+ resolution_strategy::Symbol
+ # the following are temporary until we have a dedicated type for
+ # iterated blow ups
+ blowup::AbsCoveredSchemeMorphism
+ blowups::Vector{<:AbsCoveredSchemeMorphism}
+ # exceptionals not used for now
+ ambient_blowups::Vector{<:BlowupMorphism}
+ ambient_exceptionals::Vector{<:EffectiveCartierDivisor}
+ fibration::AbsCoveredSchemeMorphism # the projection to IP^1
+ fibration_weierstrass_model::AbsCoveredSchemeMorphism # the projection from the Weierstrass model
+
+ function EllipticSurface(
+ generic_fiber::EllipticCurve{F},
+ euler_characteristic::Int,
+ mwl_basis::Vector{<:EllipticCurvePoint};
+ resolution_strategy::Symbol=:iterative
+ ) where F
+ B = typeof(coefficient_ring(base_ring(base_field(generic_fiber))))
+ S = new{B,F}()
+ S.E = generic_fiber
+ S.MWL = mwl_basis
+ S.euler_characteristic = euler_characteristic
+ set_attribute!(S, :is_irreducible=>true)
+ set_attribute!(S, :is_reduced=>true)
+ set_attribute!(S, :is_integral=>true)
+ set_attribute!(S, :is_equidimensional=>true)
+ S.resolution_strategy = resolution_strategy
+ return S
+ end
+end
+
+@doc raw"""
+ EllipticSurfaceSection <: AbsWeilDivisor
+
+A section of an elliptic fibration represented as a Weil divisor.
+"""
+@attributes mutable struct EllipticSurfaceSection{
+ CoveredSchemeType<:AbsCoveredScheme,
+ CoefficientRingType<:AbstractAlgebra.Ring,
+ CoefficientRingElemType<:AbstractAlgebra.RingElem
+ } <: AbsWeilDivisor{CoveredSchemeType, CoefficientRingType}
+ D::WeilDivisor{CoveredSchemeType, CoefficientRingType, CoefficientRingElemType}
+ P::EllipticCurvePoint
+
+ function EllipticSurfaceSection(X::EllipticSurface, P::EllipticCurvePoint; coefficient_ring::Ring=ZZ)
+ @vprint :EllipticSurface 3 "Computing a section from a point on the generic fiber\n"
+ weierstrass_contraction(X) # trigger required computations
+ PX = _section_on_weierstrass_ambient_space(X, P)
+ for f in X.ambient_blowups
+ PX = strict_transform(f , PX)
+ end
+ PY = pullback(X.inc_Y, PX)
+ set_attribute!(PY, :name, string("section: (",P[1]," : ",P[2]," : ",P[3],")"))
+ set_attribute!(PY, :_self_intersection, -euler_characteristic(X))
+ W = WeilDivisor(PY, check=false)
+ set_attribute!(W, :is_prime=>true)
+ I = first(components(W))
+ set_attribute!(I, :is_prime=>true)
+ return new{typeof(X), typeof(coefficient_ring), elem_type(coefficient_ring)}(W, P)
+ end
+end
+
+underlying_divisor(D::EllipticSurfaceSection) = D.D
+rational_point(D::EllipticSurfaceSection) = D.P
diff --git a/src/AlgebraicGeometry/ToricVarieties/AlgebraicCycles/special_attributes.jl b/src/AlgebraicGeometry/ToricVarieties/AlgebraicCycles/special_attributes.jl
index 3f03add700af..c61df9438095 100644
--- a/src/AlgebraicGeometry/ToricVarieties/AlgebraicCycles/special_attributes.jl
+++ b/src/AlgebraicGeometry/ToricVarieties/AlgebraicCycles/special_attributes.jl
@@ -27,7 +27,7 @@ true
julia> ngens(chow_ring(p2))
3
-julia> v = normal_toric_variety(IncidenceMatrix([[1], [2], [3]]), [[1, 0], [0, 1], [-1, -1]])
+julia> v = normal_toric_variety(incidence_matrix([[1], [2], [3]]), [[1, 0], [0, 1], [-1, -1]])
Normal toric variety
julia> is_complete(v)
diff --git a/src/AlgebraicGeometry/ToricVarieties/CohomologyClasses/methods.jl b/src/AlgebraicGeometry/ToricVarieties/CohomologyClasses/methods.jl
index 23eca4350f2f..21478f09306b 100644
--- a/src/AlgebraicGeometry/ToricVarieties/CohomologyClasses/methods.jl
+++ b/src/AlgebraicGeometry/ToricVarieties/CohomologyClasses/methods.jl
@@ -63,7 +63,7 @@ julia> m = 2;
julia> ray_generators = [e1, -e1, e2, e3, - e2 - e3 - m * e1];
-julia> max_cones = IncidenceMatrix([[1,3,4], [1,3,5], [1,4,5], [2,3,4], [2,3,5], [2,4,5]]);
+julia> max_cones = incidence_matrix([[1,3,4], [1,3,5], [1,4,5], [2,3,4], [2,3,5], [2,4,5]]);
julia> X = normal_toric_variety(max_cones, ray_generators; non_redundant = true)
Normal toric variety
diff --git a/src/AlgebraicGeometry/ToricVarieties/CohomologyClasses/special_attributes.jl b/src/AlgebraicGeometry/ToricVarieties/CohomologyClasses/special_attributes.jl
index 605ecfecc967..293c7d49cfd6 100644
--- a/src/AlgebraicGeometry/ToricVarieties/CohomologyClasses/special_attributes.jl
+++ b/src/AlgebraicGeometry/ToricVarieties/CohomologyClasses/special_attributes.jl
@@ -214,3 +214,55 @@ function chern_classes(v::NormalToricVariety; check::Bool = true)
end
return [chern_class(v, k; check = check) for k in 0:dim(v)]
end
+
+
+@doc raw"""
+ basis_of_h4(v::NormalToricVariety; check::Bool = true)
+
+This method computes a monomial basis of the cohomology class $H^4(X, \mathbb{Q})$
+for a toric variety $X$. The algorithm employs Theorem 12.4.1 in [CLS11](@cite),
+i.e. truncates the cohomology ring to degree $2$. By virtue of this theorem,
+this approach is supported only for toric varieties that are both complete and
+simplicial. Since it can be computationally very demanding to verify completeness,
+the optional argument `check` can be set to `false` to skip the tests.
+
+# Examples
+```jldoctest
+julia> Y1 = hirzebruch_surface(NormalToricVariety, 2)
+Normal toric variety
+
+julia> Y2 = hirzebruch_surface(NormalToricVariety, 2)
+Normal toric variety
+
+julia> Y = Y1 * Y2
+Normal toric variety
+
+julia> h4_basis = basis_of_h4(Y)
+6-element Vector{CohomologyClass}:
+ Cohomology class on a normal toric variety given by yx2^2
+ Cohomology class on a normal toric variety given by xx2*yx2
+ Cohomology class on a normal toric variety given by xx2*yt2
+ Cohomology class on a normal toric variety given by xx2^2
+ Cohomology class on a normal toric variety given by xt2*yx2
+ Cohomology class on a normal toric variety given by xt2*yt2
+
+julia> betti_number(Y, 4) == length(h4_basis)
+true
+```
+"""
+function basis_of_h4(v::NormalToricVariety; check::Bool = true)::Vector{CohomologyClass}
+ if check
+ @req is_complete(v) "Computation of basis of H4(X, Q) is currently only supported for complete toric varieties"
+ @req is_simplicial(v) "Computation of basis of H4(X, Q) is currently only supported for simplicial toric varieties"
+ end
+ if dim(v) < 4
+ set_attribute!(v, :basis_of_h4, Vector{CohomologyClass}())
+ end
+ if has_attribute(v, :basis_of_h4)
+ return get_attribute(v, :basis_of_h4)
+ end
+ R = cohomology_ring(v, check = check)
+ basis_of_h4 = [cohomology_class(v, R(g)) for g in monomial_basis(R, [2])]
+ set_attribute!(v, :basis_of_h4, basis_of_h4)
+ return basis_of_h4
+end
diff --git a/src/AlgebraicGeometry/ToricVarieties/NormalToricVarieties/attributes.jl b/src/AlgebraicGeometry/ToricVarieties/NormalToricVarieties/attributes.jl
index 8af312aa7b72..e54115514227 100644
--- a/src/AlgebraicGeometry/ToricVarieties/NormalToricVarieties/attributes.jl
+++ b/src/AlgebraicGeometry/ToricVarieties/NormalToricVarieties/attributes.jl
@@ -210,7 +210,10 @@ julia> coordinate_names(antv)
```
"""
@attr Vector{String} function coordinate_names(v::NormalToricVarietyType)
- return ["x$(i)" for i in 1:torsion_free_rank(torusinvariant_weil_divisor_group(v))]
+ if has_attribute(v, :cox_ring)
+ return string.(symbols(cox_ring(v)))
+ end
+ return ["x$(i)" for i in 1:torsion_free_rank(torusinvariant_weil_divisor_group(v))]
end
diff --git a/src/AlgebraicGeometry/ToricVarieties/NormalToricVarieties/constructors.jl b/src/AlgebraicGeometry/ToricVarieties/NormalToricVarieties/constructors.jl
index ecce8f513743..8ee9acd8f07a 100644
--- a/src/AlgebraicGeometry/ToricVarieties/NormalToricVarieties/constructors.jl
+++ b/src/AlgebraicGeometry/ToricVarieties/NormalToricVarieties/constructors.jl
@@ -82,7 +82,7 @@ julia> ray_generators = [[1,0], [0, 1], [-1, 5], [0, -1]]
[-1, 5]
[0, -1]
-julia> max_cones = IncidenceMatrix([[1, 2], [2, 3], [3, 4], [4, 1]])
+julia> max_cones = incidence_matrix([[1, 2], [2, 3], [3, 4], [4, 1]])
4×4 IncidenceMatrix
[1, 2]
[2, 3]
@@ -187,6 +187,10 @@ function Base.:(==)(tv1::NormalToricVariety, tv2::NormalToricVariety)
error("Equality of normal toric varieties is computationally very demanding. More details in the documentation.")
end
+function Base.hash(tv::NormalToricVariety, h::UInt)
+ return hash(objectid(tv), h)
+end
+
######################
diff --git a/src/Combinatorics/EnumerativeCombinatorics/compositions.jl b/src/Combinatorics/EnumerativeCombinatorics/compositions.jl
index acfb64371452..5cec5e2ac336 100644
--- a/src/Combinatorics/EnumerativeCombinatorics/compositions.jl
+++ b/src/Combinatorics/EnumerativeCombinatorics/compositions.jl
@@ -40,7 +40,12 @@ function composition(parts::Vector{T}; check::Bool = true) where {T <: IntegerUn
end
function Base.show(io::IO, ::MIME"text/plain", C::Composition)
- print(io, data(C))
+ c = data(C)
+ if isempty(c)
+ print(io, "Empty composition")
+ return
+ end
+ print(io, c)
end
################################################################################
diff --git a/src/Combinatorics/EnumerativeCombinatorics/partitions.jl b/src/Combinatorics/EnumerativeCombinatorics/partitions.jl
index a833e0f47d23..167a46a32e99 100644
--- a/src/Combinatorics/EnumerativeCombinatorics/partitions.jl
+++ b/src/Combinatorics/EnumerativeCombinatorics/partitions.jl
@@ -72,7 +72,12 @@ end
data(P::Partition) = P.p
function Base.show(io::IO, ::MIME"text/plain", P::Partition)
- print(io, data(P))
+ p = data(P)
+ if isempty(p)
+ print(io, "Empty partition")
+ return
+ end
+ print(io, p)
end
################################################################################
diff --git a/src/Combinatorics/EnumerativeCombinatorics/tableaux.jl b/src/Combinatorics/EnumerativeCombinatorics/tableaux.jl
index 522c13f0fdbb..61aa41ad3241 100644
--- a/src/Combinatorics/EnumerativeCombinatorics/tableaux.jl
+++ b/src/Combinatorics/EnumerativeCombinatorics/tableaux.jl
@@ -48,7 +48,7 @@ young_tableau
function young_tableau(::Type{T}, v::Vector{Vector{TT}}; check::Bool = true) where {T <: IntegerUnion, TT <: IntegerUnion}
if check
- @req _defines_partition(map(length, v)) "The input does not define a Young tableau"
+ @req _defines_partition(map(length, v)) "The input does not define a Young tableau: lengths of rows must be weakly decreasing"
end
return YoungTableau{T}(v)
end
@@ -222,20 +222,24 @@ Return the shape of the tableau `tab`, i.e. the partition given by the lengths
of the rows of the tableau.
"""
function shape(tab::YoungTableau{T}) where T
- return partition(T[ length(tab[i]) for i = 1:length(tab) ], check = false)
+ # Line below DOES NOT CHECK that the lengths of the rows are weakly decreasing
+ return partition(T[ length(tab[i]) for i = 1:length(tab) ]; check = false)
end
@doc raw"""
weight(tab::YoungTableau)
-Return the weight of the tableau `tab` as an array whose `i`-th element gives
-the number of times the integer `i` appears in the tableau.
+Return the weight sequence of the tableau `tab` as an array whose `i`-th element
+gives the number of times the integer `i` appears in the tableau.
"""
function weight(tab::YoungTableau)
+ @req is_semistandard(tab) "Tableau must be (semi-)standard"
+
if isempty(tab)
return Int[]
end
+ # Computation of max must be changed if we want to permit non-semi-standard YT
max = 0
for i = 1:length(tab)
if max < tab[i][end]
diff --git a/src/Combinatorics/EnumerativeCombinatorics/weak_compositions.jl b/src/Combinatorics/EnumerativeCombinatorics/weak_compositions.jl
index 04b00ee7f72c..dadcd07e977c 100644
--- a/src/Combinatorics/EnumerativeCombinatorics/weak_compositions.jl
+++ b/src/Combinatorics/EnumerativeCombinatorics/weak_compositions.jl
@@ -32,7 +32,12 @@ function weak_composition(parts::Vector{T}; check::Bool = true) where {T <: Inte
end
function Base.show(io::IO, ::MIME"text/plain", C::WeakComposition)
- print(io, data(C))
+ c = data(C)
+ if isempty(c)
+ print(io, "Empty weak composition")
+ return
+ end
+ print(io, c)
end
################################################################################
diff --git a/src/Combinatorics/Matroids/ChowRings.jl b/src/Combinatorics/Matroids/ChowRings.jl
index 6e98d0cec084..dbcefb19380c 100644
--- a/src/Combinatorics/Matroids/ChowRings.jl
+++ b/src/Combinatorics/Matroids/ChowRings.jl
@@ -3,7 +3,7 @@
Return the Chow ring of a matroid, optionally also with the simplicial generators and the polynomial ring.
-See [AHK18](@cite) and [BES19](@cite).
+See [AHK18](@cite) and [BES23](@cite).
# Examples
The following computes the Chow ring of the Fano matroid.
@@ -141,7 +141,7 @@ end
@doc raw"""
augmented_chow_ring(M::Matroid)
-Return an augmented Chow ring of a matroid. As described in [BHMPW20](@cite).
+Return an augmented Chow ring of a matroid. As described in [BHMPW22](@cite).
# Examples
```jldoctest
diff --git a/src/Combinatorics/Matroids/matroids.jl b/src/Combinatorics/Matroids/matroids.jl
index 4e028825fd1f..af2a530d4556 100644
--- a/src/Combinatorics/Matroids/matroids.jl
+++ b/src/Combinatorics/Matroids/matroids.jl
@@ -278,9 +278,9 @@ function matroid_from_hyperplanes(hyperplanes::Union{AbstractVector{T},AbstractS
end
@doc raw"""
- matroid_from_matrix_columns(A::MatrixElem)
+ matroid_from_matrix_columns(A::MatrixElem; check::Bool=true)
-A matroid represented by the column vectors of a matrix `A`.
+A matroid represented by the column vectors of a matrix `A`. The value of `check` is currently ignored.
See Section 1.1 of [Oxl11](@cite).
@@ -310,13 +310,13 @@ function matroid_from_matrix_columns(A::MatrixElem; check::Bool=true)
end
end
- return matroid_from_bases(bases, ncols(A); check=check)
+ return matroid_from_bases(bases, ncols(A); check=false)
end
@doc raw"""
- matroid_from_matrix_columns(A::MatrixElem)
+ matroid_from_matrix_rows(A::MatrixElem, check::Bool=true)
-A matroid represented by the row vectors of a matrix.
+A matroid represented by the row vectors of a matrix. The value of `check` is currently ignored.
See Section 1.1 of [Oxl11](@cite).
diff --git a/src/Combinatorics/Matroids/properties.jl b/src/Combinatorics/Matroids/properties.jl
index 56bf952a350f..addae6cad2e0 100644
--- a/src/Combinatorics/Matroids/properties.jl
+++ b/src/Combinatorics/Matroids/properties.jl
@@ -1059,11 +1059,9 @@ julia> matroid_hex(fano_matroid())
function matroid_hex(M::Matroid)
rvlx = min_revlex_basis_encoding(M)
r,n = rank(M), length(M)
+ v = zeros(Int, 4*ceil(Int, length(rvlx)/4))
+ v[length(v)-length(rvlx)+1:end] = _revlex_basis_to_vector(rvlx)
- v = _revlex_basis_to_vector(rvlx)
- for _ in 1:(4-length(v)%4)
- pushfirst!(v,0)
- end
v = reshape(v,4,:)
v = [string(parse(Int, join(v[:, j]), base=2), base=16) for j in 1:size(v)[2]]
diff --git a/src/GAP/iso_oscar_gap.jl b/src/GAP/iso_oscar_gap.jl
index 6cbf343306db..7d87de40db34 100644
--- a/src/GAP/iso_oscar_gap.jl
+++ b/src/GAP/iso_oscar_gap.jl
@@ -402,7 +402,7 @@ function _iso_oscar_gap(FO::QQAbField)
end
"""
- Oscar.iso_oscar_gap(R) -> Map{T, GapObj}
+ Oscar.iso_oscar_gap(R::T) -> Map{T, GapObj}
Return an isomorphism `f` with domain `R`
and `codomain` a GAP object `S`.
@@ -481,7 +481,7 @@ true
structure is not fully supported in GAP will likely cause overhead
at runtime.
"""
-@attr Map function iso_oscar_gap(F)
+@attr Map{T, GapObj} function iso_oscar_gap(F::T) where T
return _iso_oscar_gap(F)
end
diff --git a/src/GAP/wrappers.jl b/src/GAP/wrappers.jl
index a12f1e309d6b..d3013a214bae 100644
--- a/src/GAP/wrappers.jl
+++ b/src/GAP/wrappers.jl
@@ -270,6 +270,7 @@ GAP.@wrap LargestMovedPoint(x::Any)::Int
GAP.@wrap LeftActingDomain(x::GapObj)::GapObj
GAP.@wrap LetterRepAssocWord(x::GapObj)::GapObj
GAP.@wrap LibInfoCharacterTable(x::GapObj)::GapObj
+GAP.@wrap LieAlgebraByStructureConstants(x::GapObj, y::GapObj)::GapObj
GAP.@wrap LinearCharacters(x::GapObj)::GapObj
GAP.@wrap LinearCombination(x::GapObj, y::GapObj)::GapObj
GAP.@wrap ListPerm(x::GapObj)::GapObj
@@ -345,6 +346,7 @@ GAP.@wrap SizesCentralizers(x::GapObj)::GapObj
GAP.@wrap SizesConjugacyClasses(x::GapObj)::GapObj
GAP.@wrap Source(x::GapObj)::GapObj
GAP.@wrap Sqrt(x::Int64)::GAP.Obj
+GAP.@wrap Stabilizer(x::GapObj, y::Any, z::GapObj)::GapObj
GAP.@wrap Stabilizer(v::GapObj, w::Any, x::GapObj, y::GapObj, z::GapObj)::GapObj
GAP.@wrap StringViewObj(x::Any)::GapObj
GAP.@wrap StructureConstantsTable(x::GapObj)::GapObj
diff --git a/src/Groups/GAPGroups.jl b/src/Groups/GAPGroups.jl
index 89321335532e..cdb45b98b49b 100644
--- a/src/Groups/GAPGroups.jl
+++ b/src/Groups/GAPGroups.jl
@@ -673,25 +673,25 @@ julia> length(small_generating_set(abelian_group(PermGroup, [2,3,4])))
end
"""
- minimal_generating_set(G::GAPGroup)
+ minimal_size_generating_set(G::GAPGroup)
Return a vector of minimal length of elements in `G` that generate `G`.
# Examples
```jldoctest
-julia> length(minimal_generating_set(abelian_group(SubPcGroup, [2,3,4])))
+julia> length(minimal_size_generating_set(abelian_group(SubPcGroup, [2,3,4])))
2
-julia> length(minimal_generating_set(abelian_group(PermGroup, [2,3,4])))
+julia> length(minimal_size_generating_set(abelian_group(PermGroup, [2,3,4])))
2
-julia> minimal_generating_set(symmetric_group(5))
+julia> minimal_size_generating_set(symmetric_group(5))
2-element Vector{PermGroupElem}:
(1,2,3,4,5)
(1,2)
```
"""
-@gapattribute function minimal_generating_set(G::GAPGroup)
+@gapattribute function minimal_size_generating_set(G::GAPGroup)
L = GAP.Globals.MinimalGeneratingSet(GapObj(G))::GapObj
res = Vector{elem_type(G)}(undef, length(L))
for i = 1:length(res)
@@ -1852,7 +1852,7 @@ end
# if is_free(G) || (has_is_finite(G) && is_finite(G) && is_pgroup(G))
# return GAP.Globals.Rank(GapObj(G))::Int
# end
-# has_is_finite(G) && is_finite(G) && return length(minimal_generating_set(G))
+# has_is_finite(G) && is_finite(G) && return length(minimal_size_generating_set(G))
# error("not yet supported")
#end
diff --git a/src/Groups/action.jl b/src/Groups/action.jl
index 8c7624163e9d..776c4469fc7c 100644
--- a/src/Groups/action.jl
+++ b/src/Groups/action.jl
@@ -19,7 +19,8 @@ objects, for example wrapped GAP matrices on GAP vectors:
julia> g = GL(2,3);
julia> m = g[1]
-[ [ Z(3), 0*Z(3) ], [ 0*Z(3), Z(3)^0 ] ]
+[2 0]
+[0 1]
julia> v = GapObj(m)[1]
GAP: [ Z(3), 0*Z(3) ]
@@ -453,6 +454,45 @@ end
on_subgroups(x::T, g::GAPGroupElem) where T <: GAPGroup = T(on_subgroups(GapObj(x), g))
+
+@doc raw"""
+ on_echelon_form_mats(m::MatElem{T}, x::MatrixGroupElem) where T <: FinFieldElem
+
+Return the image of `m` under `x`,
+where the action is given by first computing the product `m * x`
+and then normalizing the result by computing its reduced row echelon form
+with `echelon_form`.
+
+Identifying `m` with the subspace of the natural module for the group of `x`
+that is generated by the rows of `m`,
+`on_echelon_form_mats` describes the action on subspaces of this natural module.
+Note that for computing the orbit and stabilizer of `m` w.r.t.
+`on_echelon_form_mats`, `m` must be in reduced row echelon form.
+
+# Examples
+```jldoctest
+julia> n = 3; q = 2; F = GF(q); V = free_module(F, n);
+
+julia> G = GL(n, F);
+
+julia> W, embW = sub(V, [gen(V,1), gen(V,3)])
+(Subspace over F with 2 generators and no relations, Hom: W -> V)
+
+julia> m = matrix(embW)
+[1 0 0]
+[0 0 1]
+
+julia> S, _ = stabilizer(G, m, on_echelon_form_mats); order(S)
+24
+
+julia> orb = orbit(G, on_echelon_form_mats, m); length(orb)
+7
+```
+"""
+function on_echelon_form_mats(m::MatElem{T}, x::MatrixGroupElem) where T <: FinFieldElem
+ return echelon_form(m * x)
+end
+
@doc raw"""
stabilizer(G::GAPGroup, pnt::Any[, actfun::Function])
@@ -493,11 +533,25 @@ function stabilizer(G::GAPGroup, pnt::Any, actfun::Function)
end
# natural stabilizers in permutation groups
-stabilizer(G::PermGroup, pnt::T) where T <: Oscar.IntegerUnion = stabilizer(G, pnt, ^)
+# Construct the arguments on the GAP side such that GAP's method selection
+# can choose the special method.
+function stabilizer(G::PermGroup, pnt::T) where T <: Oscar.IntegerUnion
+ return Oscar._as_subgroup(G, GAPWrap.Stabilizer(GapObj(G),
+ GapObj(pnt),
+ GAP.Globals.OnPoints)) # Do not use GAPWrap.OnPoints!
+end
-stabilizer(G::PermGroup, pnt::Vector{T}) where T <: Oscar.IntegerUnion = stabilizer(G, pnt, on_tuples)
+function stabilizer(G::PermGroup, pnt::Union{Vector{T}, Tuple{T, Vararg{T}}}) where T <: Oscar.IntegerUnion
+ return Oscar._as_subgroup(G, GAPWrap.Stabilizer(GapObj(G),
+ GapObj(pnt, recursive = true),
+ GAP.Globals.OnTuples)) # Do not use GAPWrap.OnTuples!
+end
-stabilizer(G::PermGroup, pnt::AbstractSet{T}) where T <: Oscar.IntegerUnion = stabilizer(G, pnt, on_sets)
+function stabilizer(G::PermGroup, pnt::AbstractSet{T}) where T <: Oscar.IntegerUnion
+ return Oscar._as_subgroup(G, GAPWrap.Stabilizer(GapObj(G),
+ GapObj(pnt, recursive = true),
+ GAP.Globals.OnSets)) # Do not use GAPWrap.OnSets!
+end
# natural stabilizers in matrix groups
stabilizer(G::MatrixGroup{ET,MT}, pnt::AbstractAlgebra.Generic.FreeModuleElem{ET}) where {ET,MT} = stabilizer(G, pnt, *)
diff --git a/src/Groups/cosets.jl b/src/Groups/cosets.jl
index 9fc72c240dc3..66032af7386b 100644
--- a/src/Groups/cosets.jl
+++ b/src/Groups/cosets.jl
@@ -1,34 +1,68 @@
# T=type of the group, S=type of the element
@doc raw"""
- GroupCoset{T<: Group, S <: GAPGroupElem}
+ GroupCoset{TG <: GAPGroup, TH <: GAPGroup, S <: GAPGroupElem}
-Type of group cosets.
-Two cosets are equal if, and only if, they are both left (resp. right)
+Type of right and left cosets of subgroups in groups.
+
+For an element $g$ in a group $G$, and a subgroup $H$ of $G$,
+the set $Hg = \{ hg; h \in H \}$ is a right coset of $H$ in $G$,
+and the set $gH = \{ gh; h \in H \}$ is a left coset of $H$ in $G$.
+
+- [`group(C::GroupCoset)`](@ref) returns $G$.
+
+- [`acting_group(C::GroupCoset)`](@ref) returns $H$.
+
+- [`representative(C::GroupCoset)`](@ref) returns an element
+ (the same element for each call) of `C`.
+
+- [`is_right(C::GroupCoset)`](@ref) and [`is_left(C::GroupCoset)`](@ref)
+ return whether `C` is a right or left coset, respectively.
+
+Two cosets are equal if and only if they are both left or right, respectively,
and they contain the same elements.
"""
-struct GroupCoset{T<: GAPGroup, S <: GAPGroupElem}
- G::T # big group containing the subgroup and the element
- H::GAPGroup # subgroup (may have a different type)
+struct GroupCoset{TG <: GAPGroup, TH <: GAPGroup, S <: GAPGroupElem}
+ G::TG # big group containing the subgroup and the element
+ H::TH # subgroup (may have a different type)
repr::S # element
side::Symbol # says if the coset is left or right
- X::GapObj # GapObj(H*repr)
-end
-
-GAP.@install GapObj(obj::GroupCoset) = obj.X
+ X::Ref{GapObj} # GapObj(H*repr)
-Base.hash(x::GroupCoset, h::UInt) = h # FIXME
-Base.eltype(::Type{GroupCoset{T,S}}) where {T,S} = S
+ function GroupCoset(G::TG, H::TH, representative::S, side::Symbol) where {TG <: GAPGroup, TH <: GAPGroup, S <:GAPGroupElem}
+ return new{TG, TH, S}(G, H, representative, side, Ref{GapObj}())
+ end
+end
-function _group_coset(G::GAPGroup, H::GAPGroup, repr::GAPGroupElem, side::Symbol, X::GapObj)
- return GroupCoset{typeof(G), typeof(repr)}(G, H, repr, side, X)
+GAP.@install function GapObj(obj::GroupCoset)
+ if !isassigned(obj.X)
+ g = GapObj(representative(obj))
+ if is_right(obj)
+ obj.X[] = GAPWrap.RightCoset(GapObj(obj.H), g)
+ else
+ obj.X[] = GAPWrap.RightCoset(GAPWrap.ConjugateSubgroup(GapObj(obj.H), GAPWrap.Inverse(g)), g)
+ end
+ end
+ return obj.X[]::GapObj
end
-function ==(x::GroupCoset, y::GroupCoset)
- return GapObj(x) == GapObj(y) && x.side == y.side
+Base.hash(x::GroupCoset, h::UInt) = h # FIXME
+Base.eltype(::Type{GroupCoset{TG, TH, S}}) where {TG, TH, S} = S
+
+function ==(C1::GroupCoset, C2::GroupCoset)
+ H = C1.H
+ right = is_right(C1)
+ (right == is_right(C2) && C1.G == C2.G && H == C2.H ) || return false
+ if right
+ # Hx == Hy if x/y in H
+ return representative(C1) / representative(C2) in H
+ else
+ # xH == yH if x\y in H
+ return representative(C1) \ representative(C2) in H
+ end
end
function Base.show(io::IO, ::MIME"text/plain", x::GroupCoset)
- side = x.side === :left ? "Left" : "Right"
+ side = is_left(x) ? "Left" : "Right"
io = pretty(io)
println(io, "$side coset of ", Lowercase(), x.H)
print(io, Indent())
@@ -38,7 +72,7 @@ function Base.show(io::IO, ::MIME"text/plain", x::GroupCoset)
end
function Base.show(io::IO, x::GroupCoset)
- side = x.side === :left ? "Left" : "Right"
+ side = is_left(x) ? "Left" : "Right"
if is_terse(io)
print(io, "$side coset of a group")
else
@@ -73,8 +107,9 @@ Right coset of Sym(3)
```
"""
function right_coset(H::GAPGroup, g::GAPGroupElem)
- @req GAPWrap.IsSubset(GapObj(parent(g)), GapObj(H)) "H is not a subgroup of parent(g)"
- return _group_coset(parent(g), H, g, :right, GAPWrap.RightCoset(GapObj(H), GapObj(g)))
+ G = parent(g)
+ @req GAPWrap.IsSubset(GapObj(G), GapObj(H)) "H is not a subgroup of parent(g)"
+ return GroupCoset(G, H, g, :right)
end
"""
@@ -84,7 +119,7 @@ end
Return the coset `gH`.
!!! note
Since GAP supports right cosets only, the underlying GAP object of
- `left_coset(H,g)` is the right coset `H^(g^-1) * g`.
+ `left_coset(H,g)`, if assigned, is the right coset `H^(g^-1) * g`.
# Examples
```jldoctest
@@ -101,8 +136,9 @@ Left coset of Sym(3)
```
"""
function left_coset(H::GAPGroup, g::GAPGroupElem)
- @req GAPWrap.IsSubset(GapObj(parent(g)), GapObj(H)) "H is not a subgroup of parent(g)"
- return _group_coset(parent(g), H, g, :left, GAPWrap.RightCoset(GAPWrap.ConjugateSubgroup(GapObj(H), GAPWrap.Inverse(GapObj(g))), GapObj(g)))
+ G = parent(g)
+ @req GAPWrap.IsSubset(GapObj(G), GapObj(H)) "H is not a subgroup of parent(g)"
+ return GroupCoset(G, H, g, :left)
end
@@ -125,7 +161,7 @@ Base.:*(g::GAPGroupElem, H::GAPGroup) = left_coset(H,g)
function Base.:*(c::GroupCoset, y::GAPGroupElem)
@assert y in c.G "element not in the group"
- if c.side == :right
+ if is_right(c)
return right_coset(c.H, representative(c)*y)
else
return left_coset(c.H^y, representative(c)*y)
@@ -134,7 +170,7 @@ end
function Base.:*(y::GAPGroupElem, c::GroupCoset)
@assert y in c.G "element not in the group"
- if c.side == :left
+ if is_left(c)
return left_coset(c.H, y*representative(c))
else
return right_coset(c.H^(y^-1), y*representative(c))
@@ -142,41 +178,68 @@ function Base.:*(y::GAPGroupElem, c::GroupCoset)
end
function Base.:*(c::GroupCoset, d::GroupCoset)
- @req (c.side == :right && d.side == :left) "Wrong input"
+ @req (is_right(c) && is_left(d)) "Wrong input"
return double_coset(c.H, representative(c)*representative(d), d.H)
end
+
"""
- acting_domain(C::GroupCoset)
+ group(C::GroupCoset)
-If `C` = `Hx` or `xH`, return `H`.
+Return the group `G` that is the parent of all elements in `C`.
+That is, `C` is a left or right coset of a subgroup of `G` in `G`.
# Examples
```jldoctest
julia> G = symmetric_group(5)
Sym(5)
-julia> g = perm(G,[3,4,1,5,2])
-(1,3)(2,4,5)
+julia> H = sylow_subgroup(G, 2)[1]
+Permutation group of degree 5 and order 8
+
+julia> C = right_coset(H, gen(G, 1))
+Right coset of permutation group of degree 5 and order 8
+ with representative (1,2,3,4,5)
+ in Sym(5)
+
+julia> group(C) == G
+true
+```
+"""
+group(C::GroupCoset) = C.G
+
+
+"""
+ acting_group(C::GroupCoset)
+
+Return the group `H` such that `C` is `Hx` (if `C` is a right coset)
+or `xH` (if `C` is a left coset), for an element `x` in `C`.
+
+# Examples
+```jldoctest
+julia> G = symmetric_group(5)
+Sym(5)
julia> H = symmetric_group(3)
Sym(3)
-julia> gH = left_coset(H,g)
-Left coset of Sym(3)
- with representative (1,3)(2,4,5)
+julia> C = right_coset(H, gen(G, 1))
+Right coset of Sym(3)
+ with representative (1,2,3,4,5)
in Sym(5)
-julia> acting_domain(gH)
-Sym(3)
+julia> acting_group(C) == H
+true
```
"""
-acting_domain(C::GroupCoset) = C.H
+acting_group(C::GroupCoset) = C.H
"""
representative(C::GroupCoset)
-If `C` = `Hx` or `xH`, return `x`.
+Return an element `x` in `group(C)` such that
+`C` = `Hx` (if `C` is a right coset)
+or `xH` (if `C` is a left coset).
# Examples
```jldoctest
@@ -189,12 +252,12 @@ julia> g = perm(G,[3,4,1,5,2])
julia> H = symmetric_group(3)
Sym(3)
-julia> gH = left_coset(H, g)
-Left coset of Sym(3)
+julia> Hg = right_coset(H, g)
+Right coset of Sym(3)
with representative (1,3)(2,4,5)
in Sym(5)
-julia> representative(gH)
+julia> representative(Hg)
(1,3)(2,4,5)
```
"""
@@ -204,8 +267,10 @@ representative(C::GroupCoset) = C.repr
"""
is_bicoset(C::GroupCoset)
-Return whether `C` is simultaneously a right coset and a left coset for the same subgroup `H`. This
-is the case if and only if the coset representative normalizes the acting domain subgroup.
+Return whether `C` is simultaneously a right coset and a left coset
+for the same subgroup `H`.
+This is the case if and only if the coset representative normalizes
+`acting_group(C)`.
# Examples
```jldoctest
@@ -247,6 +312,8 @@ Return the G-set that describes the right cosets of `H` in `G`.
If `check == false`, do not check whether `H` is a subgroup of `G`.
+Use [`right_transversal`](@ref) to compute the vector of coset representatives.
+
# Examples
```jldoctest
julia> G = symmetric_group(4)
@@ -261,7 +328,7 @@ Right cosets of
Sym(4)
julia> collect(rc)
-4-element Vector{GroupCoset{PermGroup, PermGroupElem}}:
+4-element Vector{GroupCoset{PermGroup, PermGroup, PermGroupElem}}:
Right coset of H with representative ()
Right coset of H with representative (1,4)
Right coset of H with representative (1,4,2)
@@ -269,7 +336,6 @@ julia> collect(rc)
```
"""
function right_cosets(G::GAPGroup, H::GAPGroup; check::Bool=true)
-#T _check_compatible(G, H) ?
return GSetBySubgroupTransversal(G, H, :right, check = check)
end
@@ -280,6 +346,8 @@ Return the G-set that describes the left cosets of `H` in `G`.
If `check == false`, do not check whether `H` is a subgroup of `G`.
+Use [`left_transversal`](@ref) to compute the vector of coset representatives.
+
# Examples
```jldoctest
julia> G = symmetric_group(4)
@@ -304,11 +372,14 @@ end
SubgroupTransversal{T<: GAPGroup, S<: GAPGroup, E<: GAPGroupElem}
Type of left/right transversals of subgroups in groups.
-The elements are encoded via a right transversal object in GAP.
-(Note that GAP does not support left transversals.)
Objects of this type are created by [`right_transversal`](@ref) and
[`left_transversal`](@ref).
+
+# Note for developers
+
+The elements are encoded via a right transversal object in GAP.
+(Note that GAP does not support left transversals.)
"""
struct SubgroupTransversal{T<: GAPGroup, S<: GAPGroup, E<: GAPGroupElem} <: AbstractVector{E}
G::T # big group containing the subgroup
@@ -320,7 +391,7 @@ end
GAP.@install GapObj(T::SubgroupTransversal) = T.X
function Base.show(io::IO, ::MIME"text/plain", x::SubgroupTransversal)
- side = x.side === :left ? "Left" : "Right"
+ side = is_left(x) ? "Left" : "Right"
println(io, "$side transversal of length $(length(x)) of")
io = pretty(io)
print(io, Indent())
@@ -330,7 +401,7 @@ function Base.show(io::IO, ::MIME"text/plain", x::SubgroupTransversal)
end
function Base.show(io::IO, x::SubgroupTransversal)
- side = x.side === :left ? "Left" : "Right"
+ side = is_left(x) ? "Left" : "Right"
if is_terse(io)
print(io, "$side transversal of groups")
else
@@ -340,13 +411,17 @@ function Base.show(io::IO, x::SubgroupTransversal)
end
end
+is_left(x::SubgroupTransversal) = x.side == :left
+
+is_right(x::SubgroupTransversal) = x.side == :right
+
Base.hash(x::SubgroupTransversal, h::UInt) = h # FIXME
Base.length(T::SubgroupTransversal) = index(Int, T.G, T.H)
function Base.getindex(T::SubgroupTransversal, i::Int)
res = group_element(T.G, GapObj(T)[i])
- if T.side === :left
+ if is_left(T)
res = inv(res)
end
return res
@@ -372,6 +447,8 @@ they are created anew with each access to the transversal.
If `check == false`, do not check whether `H` is a subgroup of `G`.
+Use [`right_cosets`](@ref) to compute the G-set of right cosets.
+
# Examples
```jldoctest
julia> G = symmetric_group(4)
@@ -412,6 +489,8 @@ they are created anew with each access to the transversal.
If `check == false`, do not check whether `H` is a subgroup of `G`.
+Use [`left_cosets`](@ref) to compute the G-set of left cosets.
+
# Examples
```jldoctest
julia> G = symmetric_group(4)
@@ -442,22 +521,25 @@ function left_transversal(G::T1, H::T2; check::Bool=true) where T1 <: GAPGroup w
GAPWrap.RightTransversal(GapObj(G), GapObj(H)))
end
-Base.IteratorSize(::Type{<:GroupCoset}) = Base.SizeUnknown()
-Base.iterate(G::GroupCoset) = iterate(G, GAPWrap.Iterator(GapObj(G)))
-function Base.iterate(G::GroupCoset, state)
- GAPWrap.IsDoneIterator(state) && return nothing
- i = GAPWrap.NextIterator(state)::GapObj
- return group_element(G.G, i), state
-end
+@doc raw"""
+ GroupDoubleCoset{T<: Group, S <: GAPGroupElem}
+Type of double cosets of subgroups in groups.
+For an element $g$ in a group $G$, and two subgroups $H$, $K$ of $G$,
+the set $HgK = \{ hgk; h \in H, k \in K \}$ is a $H-K$-double coset in $G$.
-@doc raw"""
- GroupDoubleCoset{T<: Group, S <: GAPGroupElem}
+- [`group(C::GroupDoubleCoset)`](@ref) returns $G$.
+
+- [`left_acting_group(C::GroupDoubleCoset)`](@ref) returns $H$.
+
+- [`right_acting_group(C::GroupDoubleCoset)`](@ref) returns $H$.
-Group double coset.
-Two double cosets are equal if, and only if, they contain the same elements.
+- [`representative(C::GroupDoubleCoset)`](@ref) returns an element
+ (the same element for each call) of `C`.
+
+Two double cosets are equal if and only if they contain the same elements.
"""
struct GroupDoubleCoset{T <: GAPGroup, S <: GAPGroupElem}
# T=type of the group, S=type of the element
@@ -467,17 +549,17 @@ struct GroupDoubleCoset{T <: GAPGroup, S <: GAPGroupElem}
repr::S
X::Ref{GapObj}
size::Ref{ZZRingElem}
-
+
function GroupDoubleCoset(G::T, H::GAPGroup, K::GAPGroup, representative::S) where {T<: GAPGroup, S<:GAPGroupElem}
return new{T, S}(G, H, K, representative, Ref{GapObj}(), Ref{ZZRingElem}())
- end
+ end
end
GAP.@install function GapObj(C::GroupDoubleCoset)
if !isassigned(C.X)
C.X[] = GAPWrap.DoubleCoset(GapObj(C.H), GapObj(representative(C)), GapObj(C.K))
end
- return C.X[]
+ return C.X[]::GapObj
end
Base.hash(x::GroupDoubleCoset, h::UInt) = h # FIXME
@@ -585,7 +667,7 @@ function double_cosets(G::T, H::GAPGroup, K::GAPGroup; check::Bool=true) where T
C.size[] = ZZRingElem(n)
res[i] = C
end
- return res
+ return res
end
"""
@@ -604,10 +686,9 @@ function order(::Type{T}, C::GroupDoubleCoset) where T <: IntegerUnion
if !isassigned(C.size)
C.size[] = ZZRingElem(GAPWrap.Size(GapObj(C)))
end
- return T(C.size[])
-end
+ return T(C.size[])::T
+end
-Base.length(C::Union{GroupCoset,GroupDoubleCoset}) = order(C)
"""
rand(rng::Random.AbstractRNG = Random.GLOBAL_RNG, C::Union{GroupCoset,GroupDoubleCoset})
@@ -622,28 +703,145 @@ function Base.rand(rng::Random.AbstractRNG, C::Union{GroupCoset,GroupDoubleCoset
return group_element(C.G, s)
end
+
+"""
+ group(C::GroupDoubleCoset)
+
+Return the group `G` that is the parent of all elements in `C`.
+That is, `C` is a double coset of two subgroups of `G` in `G`.
+
+# Examples
+```jldoctest
+julia> G = symmetric_group(5)
+Sym(5)
+
+julia> H = symmetric_group(3); K = symmetric_group(2);
+
+julia> HgK = double_coset(H, gen(G, 1), K)
+Double coset of Sym(3)
+ and Sym(2)
+ with representative (1,2,3,4,5)
+ in Sym(5)
+
+julia> group(HgK) == G
+true
+```
+"""
+group(C::GroupDoubleCoset) = C.G
+
"""
representative(C::GroupDoubleCoset)
-Return a representative `x` of the double coset `C` = `HxK`.
+Return an element `x` of the double coset `C` = `HxK`.
+
+# Examples
+```jldoctest
+julia> G = symmetric_group(5)
+Sym(5)
+
+julia> H = symmetric_group(3); K = symmetric_group(2);
+
+julia> HgK = double_coset(H, gen(G, 1), K)
+Double coset of Sym(3)
+ and Sym(2)
+ with representative (1,2,3,4,5)
+ in Sym(5)
+
+julia> representative(HgK)
+(1,2,3,4,5)
+```
"""
representative(C::GroupDoubleCoset) = C.repr
"""
left_acting_group(C::GroupDoubleCoset)
-Given a double coset `C` = `HxK`, return `H`.
+Return `H` if `C` = `HxK`.
+
+# Examples
+```jldoctest
+julia> G = symmetric_group(5)
+Sym(5)
+
+julia> H = symmetric_group(3); K = symmetric_group(2);
+
+julia> HgK = double_coset(H, gen(G, 1), K)
+Double coset of Sym(3)
+ and Sym(2)
+ with representative (1,2,3,4,5)
+ in Sym(5)
+
+julia> left_acting_group(HgK) == H
+true
+```
"""
left_acting_group(C::GroupDoubleCoset) = C.H
"""
right_acting_group(C::GroupDoubleCoset)
-Given a double coset `C` = `HxK`, return `K`.
+Return `K` if `C` = `HxK`.
+
+# Examples
+```jldoctest
+julia> G = symmetric_group(5)
+Sym(5)
+
+julia> H = symmetric_group(3); K = symmetric_group(2);
+
+julia> HgK = double_coset(H, gen(G, 1), K)
+Double coset of Sym(3)
+ and Sym(2)
+ with representative (1,2,3,4,5)
+ in Sym(5)
+
+julia> right_acting_group(HgK) == K
+true
+```
"""
right_acting_group(C::GroupDoubleCoset) = C.K
+
+############################################################################
+#
+# iteration over cosets
+#
+function Base.in(g::GAPGroupElem, C::GroupCoset)
+ if is_right(C)
+ return g / representative(C) in acting_group(C)
+ else
+ return g \ representative(C) in acting_group(C)
+ end
+end
+
+function Base.in(g::GAPGroupElem, C::GroupDoubleCoset)
+ return GapObj(g) in GapObj(C)
+#TODO: avoid delegation to GAP?
+# (GAP uses `RepresentativesContainedRightCosets`, `CanonicalRightCosetElement`)
+end
+
+Base.IteratorSize(::Type{<:GroupCoset{TG, TH, S}}) where {TG, TH, S} = Base.IteratorSize(TH)
+
+# need this function just for the iterator
+Base.length(C::Union{GroupCoset,GroupDoubleCoset}) = order(Int, C)
+
+function Base.iterate(C::GroupCoset)
+ return iterate(C, iterate(acting_group(C)))
+end
+
+function Base.iterate(C::GroupCoset, state)
+ state === nothing && return nothing
+ G = group(C)
+ if is_right(C)
+ res = G(state[1]) * representative(C)
+ else
+ res = representative(C) * G(state[1])
+ end
+ return res, iterate(acting_group(C), state[2])
+end
+
Base.IteratorSize(::Type{<:GroupDoubleCoset}) = Base.SizeUnknown()
+Base.IteratorSize(::Type{GroupDoubleCoset{PermGroup, PermGroupElem}}) = Base.HasLength()
Base.iterate(G::GroupDoubleCoset) = iterate(G, GAPWrap.Iterator(GapObj(G)))
@@ -652,26 +850,3 @@ function Base.iterate(G::GroupDoubleCoset, state)
i = GAPWrap.NextIterator(state)::GapObj
return group_element(G.G, i), state
end
-
-"""
- intersect(V::AbstractVector{Union{<: GAPGroup, GroupCoset, GroupDoubleCoset}})
-
-Return a vector containing all elements belonging to all groups and cosets
-in `V`.
-"""
-function Base.intersect(V::AbstractVector{Union{<: GAPGroup, GroupCoset, GroupDoubleCoset}})
- if V[1] isa GAPGroup
- G = V[1]
- else
- G = V[1].G
- end
- l = GAP.Obj(V; recursive = true)
- ints = GAPWrap.Intersection(l)
- L = Vector{eltype(G)}(undef, length(ints))
- for i in 1:length(ints)
- L[i] = group_element(G,ints[i])
- end
-
- return L
-end
-#TODO: Can this method get called at all?
diff --git a/src/Groups/gsets.jl b/src/Groups/gsets.jl
index 77b35f8755a6..0c94b49427fe 100644
--- a/src/Groups/gsets.jl
+++ b/src/Groups/gsets.jl
@@ -41,8 +41,9 @@ The fields are
action_function::Function
seeds
- function GSetByElements(G::T, fun::Function, seeds; closed::Bool = false) where {T<:Union{GAPGroup, FinGenAbGroup}}
- @assert !isempty(seeds)
+ function GSetByElements(G::T, fun::Function, seeds; closed::Bool = false, check::Bool = true) where {T<:Union{GAPGroup, FinGenAbGroup}}
+ @req !isempty(seeds) "seeds for G-set must be nonempty"
+ check && @req hasmethod(fun, (typeof(first(seeds)), elem_type(T))) "action function does not fit to seeds"
Omega = new{T,eltype(seeds)}(G, fun, seeds, Dict{Symbol,Any}())
closed && set_attribute!(Omega, :elements => unique!(collect(seeds)))
return Omega
@@ -117,7 +118,7 @@ end
## general method with explicit action function
"""
- gset(G::Union{GAPGroup, FinGenAbGroup}[, fun::Function], seeds, closed::Bool = false)
+ gset(G::Union{GAPGroup, FinGenAbGroup}[, fun::Function], seeds, closed::Bool = false, check::Bool = true)
Return the G-set `Omega` that consists of the closure of the seeds `seeds`
under the action of `G` defined by `fun`.
@@ -130,6 +131,9 @@ a reasonable default,
for example, if `G` is a `PermGroup` and `seeds` is a `Vector{T}`
where `T` is one of `Int`, `Set{Int}`, `Vector{Int}`.
+If `check` is set to `false` then it is *not* checked whether the entries
+of `seeds` are valid as the first argument of `fun`.
+
If `closed` is set to `true` then `seeds` is assumed to be closed
under the action of `G`.
In this case, `collect(Omega)` is guaranteed to be equal to `collect(seeds)`;
@@ -151,8 +155,8 @@ julia> length(gset(G, on_sets, [[1, 2]])) # action on unordered pairs
6
```
"""
-function gset(G::Union{GAPGroup, FinGenAbGroup}, fun::Function, seeds; closed::Bool = false)
- return GSetByElements(G, fun, seeds; closed = closed)
+function gset(G::Union{GAPGroup, FinGenAbGroup}, fun::Function, seeds; closed::Bool = false, check::Bool = true)
+ return GSetByElements(G, fun, seeds; closed = closed, check = check)
end
@@ -169,47 +173,47 @@ gset(G::T, seeds; closed::Bool = false) where T<:GAPGroup = gset_by_type(G, seed
## natural action of permutations on positive integers
function gset_by_type(G::PermGroup, Omega, ::Type{T}; closed::Bool = false) where T<:IntegerUnion
- return GSetByElements(G, ^, Omega; closed = closed)
+ return GSetByElements(G, ^, Omega; closed = closed, check = false)
end
## action of permutations on sets of positive integers
function gset_by_type(G::PermGroup, Omega, ::Type{T}; closed::Bool = false) where T<:Set{T2} where T2<:IntegerUnion
- return GSetByElements(G, on_sets, Omega; closed = closed)
+ return GSetByElements(G, on_sets, Omega; closed = closed, check = false)
end
## action of permutations on vectors of positive integers
function gset_by_type(G::PermGroup, Omega, ::Type{T}; closed::Bool = false) where T<:Vector{T2} where T2<:IntegerUnion
- return GSetByElements(G, on_tuples, Omega; closed = closed)
+ return GSetByElements(G, on_tuples, Omega; closed = closed, check = false)
end
## action of permutations on tuples of positive integers
function gset_by_type(G::PermGroup, Omega, ::Type{T}; closed::Bool = false) where T<:Tuple{T2,Vararg{T2}} where T2<:IntegerUnion
- return GSetByElements(G, on_tuples, Omega; closed = closed)
+ return GSetByElements(G, on_tuples, Omega; closed = closed, check = false)
end
## action of matrices on vectors via right multiplication
function gset_by_type(G::MatrixGroup{E, M}, Omega, ::Type{AbstractAlgebra.Generic.FreeModuleElem{E}}; closed::Bool = false) where E where M
- return GSetByElements(G, *, Omega; closed = closed)
+ return GSetByElements(G, *, Omega; closed = closed, check = false)
end
## action of matrices on sets of vectors via right multiplication
function gset_by_type(G::MatrixGroup{E, M}, Omega, ::Type{T}; closed::Bool = false) where T <: Set{AbstractAlgebra.Generic.FreeModuleElem{E}} where E where M
- return GSetByElements(G, on_sets, Omega; closed = closed)
+ return GSetByElements(G, on_sets, Omega; closed = closed, check = false)
end
## action of matrices on vectors of vectors via right multiplication
function gset_by_type(G::MatrixGroup{E, M}, Omega, ::Type{T}; closed::Bool = false) where T <: Vector{AbstractAlgebra.Generic.FreeModuleElem{E}} where E where M
- return GSetByElements(G, on_tuples, Omega; closed = closed)
+ return GSetByElements(G, on_tuples, Omega; closed = closed, check = false)
end
## action of matrices on subspaces via right multiplication
function gset_by_type(G::MatrixGroup{E, M}, Omega, ::Type{T}; closed::Bool = false) where T <: AbstractAlgebra.Generic.Submodule{E} where E where M
- return GSetByElements(G, ^, Omega; closed = closed)
+ return GSetByElements(G, ^, Omega; closed = closed, check = false)
end
## action of matrices on polynomials via `on_indeterminates`
function gset_by_type(G::MatrixGroup{E, M}, Omega, ::Type{T}; closed::Bool = false) where T <: MPolyRingElem{E} where E where M
- return GSetByElements(G, on_indeterminates, Omega; closed = closed)
+ return GSetByElements(G, on_indeterminates, Omega; closed = closed, check = false)
end
## (add more such actions: on sets of sets, on sets of tuples, ...)
@@ -446,17 +450,29 @@ julia> map(length, orbs)
"""
stabilizer(Omega::GSet{T,S})
stabilizer(Omega::GSet{T,S}, omega::S = representative(Omega); check::Bool = true) where {T,S}
+ stabilizer(Omega::GSet{T,S}, omega::Set{S}; check::Bool = true) where {T,S}
+ stabilizer(Omega::GSet{T,S}, omega::Vector{S}; check::Bool = true) where {T,S}
+ stabilizer(Omega::GSet{T,S}, omega::Tuple{S,Vararg{S}}; check::Bool = true) where {T,S}
Return the subgroup of `G = acting_group(Omega)` that fixes `omega`,
together with the embedding of this subgroup into `G`.
+
+If `omega` is a `Set` of points in `Omega`
+then `stabilizer` means the setwise stabilizer of the entries in `omega`.
+If `omega` is a `Vector` or a `Tuple` of points in `Omega`
+then `stabilizer` means the pointwise stabilizer of the entries in `omega`.
+
If `check` is `false` then it is not checked whether `omega` is in `Omega`.
# Examples
```jldoctest
-julia> Omega = gset(symmetric_group(3));
+julia> Omega = gset(symmetric_group(4));
julia> stabilizer(Omega)
-(Permutation group of degree 3 and order 2, Hom: permutation group -> Sym(3))
+(Permutation group of degree 4 and order 6, Hom: permutation group -> Sym(4))
+
+julia> stabilizer(Omega, [1, 2])
+(Permutation group of degree 4 and order 2, Hom: permutation group -> Sym(4))
```
"""
@attr Tuple{sub_type(T), Map{sub_type(T), T}} function stabilizer(Omega::GSet{T,S}) where {T,S}
@@ -470,6 +486,50 @@ function stabilizer(Omega::GSet{T,S}, omega::S; check::Bool = true) where {T,S}
return stabilizer(G, omega, gfun)
end
+# Construct the arguments on the GAP side such that GAP's method selection
+# can choose the special method.
+function stabilizer(Omega::GSet{PermGroup,S}, omega::S; check::Bool = true) where S <: Oscar.IntegerUnion
+ check && @req omega in Omega "omega must be an element of Omega"
+ return stabilizer(acting_group(Omega), omega)
+end
+
+# support `stabilizer` under "derived" actions:
+# If the given point is a set of the element type of the G-set
+# then compute the setwise stabilizer.
+# If the given point is a tuple or vector of the element type of the G-set
+# then compute the pointwise stabilizer.
+
+function stabilizer(Omega::GSet{T,S}, omega::Set{S}; check::Bool = true) where {T,S}
+ check && @req all(in(Omega), omega) "omega must be a set of elements of Omega"
+ G = acting_group(Omega)
+ gfun = action_function(Omega)
+ derived_fun = function(x, g) return Set(gfun(y, g) for y in x); end
+ return stabilizer(G, omega, derived_fun)
+end
+
+function stabilizer(Omega::GSet{T,S}, omega::Vector{S}; check::Bool = true) where {T,S}
+ check && @req all(in(Omega), omega) "omega must be a vector of elements of Omega"
+ G = acting_group(Omega)
+ gfun = action_function(Omega)
+ derived_fun = function(x, g) return [gfun(y, g) for y in x]; end
+ return stabilizer(G, omega, derived_fun)
+end
+
+function stabilizer(Omega::GSet{T,S}, omega::Tuple{S,Vararg{S}}; check::Bool = true) where {T,S}
+ check && @req all(in(Omega), omega) "omega must be a tuple of elements of Omega"
+ G = acting_group(Omega)
+ gfun = action_function(Omega)
+ derived_fun = function(x, g) return Tuple([gfun(y, g) for y in x]); end
+ return stabilizer(G, omega, derived_fun)
+end
+
+# Construct the arguments on the GAP side such that GAP's method selection
+# can choose the special method.
+function stabilizer(Omega::GSet{PermGroup,S}, omega::Union{Set{S}, Tuple{S,Vararg{S}}, Vector{S}}; check::Bool = true) where S <: Oscar.IntegerUnion
+ check && @req all(in(Omega), omega) "omega must be a set of elements of Omega"
+ return stabilizer(acting_group(Omega), omega)
+end
+
#############################################################################
##
@@ -538,7 +598,7 @@ The fields are
- the (left or right) transversal, of type `SubgroupTransversal{T, S, E}`,
- the dictionary used to store attributes (orbits, elements, ...).
"""
-@attributes mutable struct GSetBySubgroupTransversal{T, S, E} <: GSet{T,GroupCoset{T, E}}
+@attributes mutable struct GSetBySubgroupTransversal{T, S, E} <: GSet{T,GroupCoset{T, S, E}}
group::T
subgroup::S
side::Symbol
@@ -612,7 +672,7 @@ function Base.iterate(Omega::GSetBySubgroupTransversal, state = 1)
end
end
-Base.eltype(::Type{GSetBySubgroupTransversal{T, S, E}}) where {S, T, E} = GroupCoset{T, E}
+Base.eltype(::Type{GSetBySubgroupTransversal{T, S, E}}) where {S, T, E} = GroupCoset{T, S, E}
function Base.getindex(Omega::GSetBySubgroupTransversal, i::Int)
if Omega.side == :right
@@ -624,7 +684,7 @@ end
is_transitive(Omega::GSetBySubgroupTransversal) = true
-function orbit(G::T, omega::GroupCoset{T, S}) where T <: GAPGroup where S
+function orbit(G::T, omega::GroupCoset{T, TH, S}) where {T <: GAPGroup, TH <: GAPGroup, S}
@req G == omega.G "omega must be a left or right coset in G"
return GSetBySubgroupTransversal(G, omega.H, omega.side, check = false)
end
@@ -632,7 +692,7 @@ end
# One problem would be that `omega` would not be a point in the orbit,
# according to the definition of equality for cosets.
-function orbit(Omega::GSetBySubgroupTransversal{T, S, E}, omega::GroupCoset{T, E}) where T <: GAPGroup where S <: GAPGroup where E
+function orbit(Omega::GSetBySubgroupTransversal{T, S, E}, omega::GroupCoset{T, S, E}) where {T <: GAPGroup, S <: GAPGroup, E}
@req (Omega.group == omega.G && Omega.subgroup == omega.H && Omega.side == omega.side) "omega is not in Omega"
return Omega
end
@@ -738,8 +798,8 @@ function action_homomorphism(G::PermGroup, Omega)
return action_homomorphism(gset_by_type(G, Omega, eltype(Omega); closed = true))
end
-function action_homomorphism(G::PermGroup, fun::Function, Omega)
- return action_homomorphism(GSetByElements(G, fun, Omega, closed = true))
+function action_homomorphism(G::PermGroup, fun::Function, Omega; check = true)
+ return action_homomorphism(GSetByElements(G, fun, Omega, closed = true, check = check))
end
@@ -814,8 +874,6 @@ end
############################################################################
-acting_domain(Omega::GSet) = acting_group(Omega)
-
Base.length(Omega::GSetByElements) = length(elements(Omega))
Base.length(::Type{T}, Omega::GSetByElements) where T <: IntegerUnion = T(length(elements(Omega)))
diff --git a/src/Groups/homomorphisms.jl b/src/Groups/homomorphisms.jl
index e42a1cc7d151..acac1f65be8a 100644
--- a/src/Groups/homomorphisms.jl
+++ b/src/Groups/homomorphisms.jl
@@ -9,7 +9,7 @@ function Base.show(io::IO, x::GAPGroupHomomorphism)
end
-function ==(f::GAPGroupHomomorphism{S,T}, g::GAPGroupHomomorphism{S,T}) where S where T
+function ==(f::GAPGroupHomomorphism, g::GAPGroupHomomorphism)
return GapObj(f) == GapObj(g)
end
@@ -711,7 +711,7 @@ end
isomorphism(::Type{T}, A::FinGenAbGroup) where T <: Union{GAPGroup, FinGenAbGroup}
Return an isomorphism from `A` to a group of type `T`.
-An exception is thrown if no such isomorphism exists or if `A` is not finite.
+An exception is thrown if no such isomorphism exists.
"""
function isomorphism(::Type{T}, A::FinGenAbGroup) where T <: GAPGroup
# Known isomorphisms are cached in the attribute `:isomorphisms`.
@@ -729,15 +729,16 @@ function isomorphism(::Type{T}, A::FinGenAbGroup) where T <: GAPGroup
A_to_A2 = inv(A2_to_A)
# Create an isomorphic GAP group whose `GAPWrap.GeneratorsOfGroup`
# consists of independent elements of the orders in `exponents`.
- # (We cannot guarantee that these generators form a pcgs in the case
- # `T == PcGroup`, hence we cannot call `abelian_group(T, exponents)`.)
if T == PcGroup
+ # We cannot guarantee that these generators form a pcgs in the case
+ # `T == PcGroup`, hence we cannot call `abelian_group(T, exponents)`.
if 0 in exponents
GapG = GAP.Globals.AbelianPcpGroup(length(exponents), GapObj(exponents; recursive = true))
+ G = PcGroup(GapG)
else
GapG = GAP.Globals.AbelianGroup(GAP.Globals.IsPcGroup, GapObj(exponents; recursive = true))
+ G = PcGroup(GAP.Globals.SubgroupNC(GapG, GAP.Globals.FamilyPcgs(GapG)))
end
- G = PcGroup(GAP.Globals.SubgroupNC(GapG, GAP.Globals.FamilyPcgs(GapG)))
else
G = abelian_group(T, exponents)
GapG = GapObj(G)
@@ -771,7 +772,9 @@ function isomorphism(::Type{T}, A::FinGenAbGroup) where T <: GAPGroup
Ggens = newGgens
end
gensindep = GAP.Globals.IndependentGeneratorsOfAbelianGroup(GapG)::GapObj
- Aindep = abelian_group(ZZRingElem[GAPWrap.Order(g) for g in gensindep])
+ orders = [GAPWrap.Order(g) for g in gensindep]
+ exps = map(x -> x == GAP.Globals.infinity ? ZZRingElem(0) : ZZRingElem(x), orders)
+ Aindep = abelian_group(exps)
imgs = [Vector{ZZRingElem}(GAPWrap.IndependentGeneratorExponents(GapG, a)) for a in Ggens]
A2_to_Aindep = hom(A2, Aindep, elem_type(Aindep)[Aindep(e) for e in imgs])
Aindep_to_A = compose(inv(A2_to_Aindep), A2_to_A)
diff --git a/src/Groups/matrices/MatGrp.jl b/src/Groups/matrices/MatGrp.jl
index c74f12f83a54..2c5ab5552258 100644
--- a/src/Groups/matrices/MatGrp.jl
+++ b/src/Groups/matrices/MatGrp.jl
@@ -559,7 +559,7 @@ compute_order(G::GAPGroup) = ZZRingElem(GAPWrap.Size(G.X))
function compute_order(G::MatrixGroup{T}) where {T <: Union{AbsSimpleNumFieldElem, QQFieldElem}}
#=
- - For a matrix group G over the Rationals or over a number field,
+ - For a matrix group G over the rationals or over a number field,
the GAP group G.X does usually not store the flag `IsHandledByNiceMonomorphism`.
- If we know a reasonable ("nice") faithful permutation action of `G` in advance,
we can set this flag in `G.X` to true and store the action homomorphism in `G.X`,
diff --git a/src/Groups/matrices/forms.jl b/src/Groups/matrices/forms.jl
index 887df1bbbb42..ffe05230e273 100644
--- a/src/Groups/matrices/forms.jl
+++ b/src/Groups/matrices/forms.jl
@@ -367,15 +367,16 @@ function (f::SesquilinearForm{T})(v::AbstractAlgebra.Generic.FreeModuleElem{T},w
@req f.descr!=:quadratic "Quadratic forms requires only one argument"
if f.descr==:hermitian
- return v*gram_matrix(f)*map( y->frobenius(y,div(degree(base_ring(w)),2)),w)
+ w = conjugate_transpose(w.v)
else
- return v*gram_matrix(f)*w
+ w = transpose(w.v)
end
+ return v.v*gram_matrix(f)*w
end
function (f::SesquilinearForm{T})(v::AbstractAlgebra.Generic.FreeModuleElem{T}) where T <: RingElem
@req f.descr==:quadratic "Sesquilinear forms requires two arguments"
- return v*gram_matrix(f)*v
+ return v.v*gram_matrix(f)*transpose(v.v)
end
diff --git a/src/Groups/matrices/matrix_manipulation.jl b/src/Groups/matrices/matrix_manipulation.jl
index 39220de07b16..5b62d9450631 100644
--- a/src/Groups/matrices/matrix_manipulation.jl
+++ b/src/Groups/matrices/matrix_manipulation.jl
@@ -170,17 +170,7 @@ end
#
########################################################################
-
-Base.:*(v::AbstractAlgebra.Generic.FreeModuleElem{T},x::MatElem{T}) where T <: RingElem = v.parent(v.v*x)
-Base.:*(x::MatElem{T},u::AbstractAlgebra.Generic.FreeModuleElem{T}) where T <: RingElem = x*transpose(u.v)
-
-# evaluation of the form x into the vectors v and u
-Base.:*(v::AbstractAlgebra.Generic.FreeModuleElem{T},x::MatElem{T},u::AbstractAlgebra.Generic.FreeModuleElem{T}) where T <: RingElem = (v.v*x*transpose(u.v))[1]
-
-
Base.:*(v::AbstractAlgebra.Generic.FreeModuleElem{T},x::MatrixGroupElem{T}) where T <: RingElem = v.parent(v.v*matrix(x))
-Base.:*(x::MatrixGroupElem{T},u::AbstractAlgebra.Generic.FreeModuleElem{T}) where T <: RingElem = matrix(x)*transpose(u.v)
-
Base.:*(v::Vector{T}, x::MatrixGroupElem{T}) where T <: RingElem = v*matrix(x)
Base.:*(x::MatrixGroupElem{T}, u::Vector{T}) where T <: RingElem = matrix(x)*u
@@ -193,8 +183,3 @@ Base.:^(v::AbstractAlgebra.Generic.FreeModuleElem{T},x::MatrixGroupElem{T}) wher
function Base.:^(V::AbstractAlgebra.Generic.Submodule{T}, x::MatrixGroupElem{T}) where T <: RingElem
return sub(V.m, [v^x for v in V.gens])[1]
end
-
-# evaluation of the form x into the vectors v and u
-Base.:*(v::AbstractAlgebra.Generic.FreeModuleElem{T},x::MatrixGroupElem{T},u::AbstractAlgebra.Generic.FreeModuleElem{T}) where T <: RingElem = (v.v*matrix(x)*transpose(u.v))[1]
-
-map(f::Function, v::AbstractAlgebra.Generic.FreeModuleElem{T}) where T <: RingElem = v.parent(map(f,v.v))
diff --git a/src/Groups/pcgroup.jl b/src/Groups/pcgroup.jl
index 923170798e44..db534e1f14e1 100644
--- a/src/Groups/pcgroup.jl
+++ b/src/Groups/pcgroup.jl
@@ -51,7 +51,7 @@ true
collector(n::Int, ::Type{T} = ZZRingElem) where T <: IntegerUnion = GAP_Collector{T}(n)
-# Provide functions for entering data into the collector.
+# Provide functions for entering data into the collector and accessing data.
# utility:
# Convert a vector of pairs to a generator-exponent vector in GAP.
@@ -98,13 +98,36 @@ function set_relative_order!(c::Collector{T}, i::Int, relord::T) where T <: Inte
end
end
+"""
+ get_relative_order(c::Collector{T}, i::Int) where T <: IntegerUnion
+
+Get the relative order of the `i`-th generator of `c`.
+
+# Examples
+```jldoctest
+julia> c = collector(2, Int);
+
+julia> get_relative_order(c, 1)
+0
+
+julia> set_relative_order!(c, 1, 2)
+
+julia> get_relative_order(c, 1)
+2
+```
+"""
+function get_relative_order(c::Collector{T}, i::Int) where T <: IntegerUnion
+ @req (0 < i && i <= c.ngens) "the collector has only $(c.ngens) generators not $i"
+ return c.relorders[i]
+end
+
"""
set_relative_orders!(c::Collector{T}, relords::Vector{T})
Set all relative orders of the generators of `c`,
where the length of `relords` must be equal to the number of generators of
`c`, and `relords[i]` denotes the relative order of the `i`-th generator.
-which must be either `0` (meaning infinite order) or a positive integer..
+which must be either `0` (meaning infinite order) or a positive integer.
# Examples
```jldoctest
@@ -131,6 +154,32 @@ function set_relative_orders!(c::Collector{T}, relords::Vector{T}) where T <: In
end
end
+"""
+ get_relative_orders(c::Collector{T})
+
+Get the `Vector{T}` of all relative orders of the generators of `c`.
+
+# Examples
+```jldoctest
+julia> c = collector(2);
+
+julia> get_relative_orders(c)
+2-element Vector{ZZRingElem}:
+ 0
+ 0
+
+julia> set_relative_orders!(c, ZZRingElem[2, 0])
+
+julia> get_relative_orders(c)
+2-element Vector{ZZRingElem}:
+ 2
+ 0
+```
+"""
+function get_relative_orders(c::Collector{T}) where T <: IntegerUnion
+ return c.relorders
+end
+
"""
set_power!(c::Collector{T}, i::Int, rhs::Vector{Pair{Int, T}}) where T <: IntegerUnion
@@ -165,6 +214,35 @@ function set_power!(c::Collector{T}, i::Int, rhs::Vector{Pair{Int, T}}) where T
end
end
+"""
+ get_power(c::Collector{T}, i::Int) where T <: IntegerUnion
+
+Get the `Vector{Pair{Int, T}}` that describes the `c.relorders[i]`-th power
+of the `i`-th generator of `c`.
+
+# Examples
+```jldoctest
+julia> c = collector(2, Int);
+
+julia> set_relative_order!(c, 1, 2)
+
+julia> set_relative_order!(c, 2, 3)
+
+julia> get_power(c, 1)
+Pair{Int64, Int64}[]
+
+julia> set_power!(c, 1, [2 => 1])
+
+julia> get_power(c, 1)
+1-element Vector{Pair{Int64, Int64}}:
+ 2 => 1
+```
+"""
+function get_power(c::Collector{T}, i::Int) where T <: IntegerUnion
+ @req 0 < i <= c.ngens "the collector has only $(c.ngens) generators not $i"
+ return c.powers[i]
+end
+
"""
set_conjugate!(c::Collector{T}, j::Int, i::Int, rhs::Vector{Pair{Int, T}}) where T <: IntegerUnion
@@ -199,6 +277,36 @@ function set_conjugate!(c::Collector{T}, j::Int, i::Int, rhs::Vector{Pair{Int, T
end
end
+"""
+ get_conjugate(c::Collector{T}, j::Int, i::Int) where T <: IntegerUnion
+
+Get the `Vector{Pair{Int, T}}` that describes the conjugate of the `j`-th
+generator of `c` by the `i`-th generator of `c`, for `i < j`.
+
+# Examples
+```jldoctest
+julia> c = collector(2, Int);
+
+julia> set_relative_orders!(c, [2, 3])
+
+julia> get_conjugate(c, 2, 1)
+1-element Vector{Pair{Int64, Int64}}:
+ 2 => 1
+
+julia> set_conjugate!(c, 2, 1, [2 => 2])
+
+julia> get_conjugate(c, 2, 1)
+1-element Vector{Pair{Int64, Int64}}:
+ 2 => 2
+```
+"""
+function get_conjugate(c::Collector{T}, j::Int, i::Int) where T <: IntegerUnion
+ @req 0 < i <= c.ngens "the collector has only $(c.ngens) generators not $i"
+ @req i < j "only for i < j, but i = $i, j = $j"
+ conj = c.conjugates
+ return isassigned(conj, i, j) ? conj[i, j] : [j => T(1)]
+end
+
"""
set_commutator!(c::Collector{T}, j::Int, i::Int, rhs::Vector{Pair{Int, T}}) where T <: IntegerUnion
@@ -215,7 +323,7 @@ julia> set_commutator!(c, 2, 1, [2 => 1])
```
"""
function set_commutator!(c::Collector{T}, j::Int, i::Int, rhs::Vector{Pair{Int, T}}) where T <: IntegerUnion
- @req 0 < i <= c.ngens "the collector has only $(c.ngens) generators not $i"
+ @req 0 < j <= c.ngens "the collector has only $(c.ngens) generators not $j"
@req i < j "only for i < j, but i = $i, j = $j"
if length(rhs) > 0 && rhs[1].first == j
# freely reduce
@@ -365,3 +473,67 @@ function pc_group(c::GAP_Collector)
end
end
+
+# Create an Oscar collector from a GAP collector.
+
+"""
+ collector([::Type{T} = ZZRingElem, ]G::PcGroup) where T <: IntegerUnion
+
+Return a collector object for `G`.
+
+# Examples
+```jldoctest
+julia> g = small_group(12, 3)
+Pc group of order 12
+
+julia> c = collector(g);
+
+julia> gc = pc_group(c)
+Pc group of order 12
+
+julia> is_isomorphic(g, gc)
+true
+```
+"""
+function collector(::Type{T}, G::PcGroup) where T <: IntegerUnion
+ Fam = GAPWrap.ElementsFamily(GAPWrap.FamilyObj(GapObj(G)))
+ GapC = GAP.getbangproperty(Fam, :rewritingSystem)::GapObj
+
+ n = GAP.getbangindex(GapC, 3)::Int
+ c = collector(n, T)
+
+ c.relorders = Vector{T}(GAP.getbangindex(GapC, 6)::GapObj)
+
+ Gap_powers = GAP.gap_to_julia(GAP.getbangindex(GapC, 7)::GapObj, recursive = false)
+ for i in 1:length(Gap_powers)
+ if Gap_powers[i] !== nothing
+ l = GAPWrap.ExtRepOfObj(Gap_powers[i])
+ c.powers[i] = Pair{Int,T}[l[k-1] => T(l[k]) for k in 2:2:length(l)]
+ end
+ end
+
+ Gap_conj = GAP.gap_to_julia(GAP.getbangindex(GapC, 8)::GapObj, recursive = false)
+ for i in 1:length(Gap_conj)
+ Gap_conj_i = GAP.gap_to_julia(Gap_conj[i]::GapObj, recursive = false)
+ for j in 1:length(Gap_conj_i)
+ if Gap_conj_i[j] !== nothing
+ l = GAPWrap.ExtRepOfObj(Gap_conj_i[j])
+ c.conjugates[j,i] = Pair{Int,T}[l[k-1] => T(l[k]) for k in 2:2:length(l)]
+ end
+ end
+ end
+
+#TODO: deal also with the from-the-left-collector from the Polycyclic package
+
+# c.X = GapC
+# c.F = FPGroup(GAP.getbangproperty(GAP.getbangindex(GapC, 1)::GapObj, :freeGroup)::GapObj)
+#TODO: Set these known data.
+# Currently this does not work because somehow `GroupByRws`
+# requires a *mutable* GAP collector, and `GapC` is immutable.
+# (Change `pc_group` to not call `GroupByRWS` in this case?
+# Forbid `set_power!` etc. in this case?)
+
+ return c
+end
+
+collector(G::PcGroup) = collector(ZZRingElem, G)
diff --git a/src/Groups/sub.jl b/src/Groups/sub.jl
index b107a3062912..95162c68fa3c 100644
--- a/src/Groups/sub.jl
+++ b/src/Groups/sub.jl
@@ -157,15 +157,7 @@ end
# convert a GAP list of subgroups into a vector of Julia groups objects
function _as_subgroups(G::T, subs::GapObj) where T <: GAPGroup
- res = Vector{T}(undef, length(subs))
- for i = 1:length(res)
- res[i] = _as_subgroup_bare(G, subs[i]::GapObj)
- end
- return res
-end
-
-function _as_subgroups(G::PcGroup, subs::GapObj)
- res = Vector{SubPcGroup}(undef, length(subs))
+ res = Vector{sub_type(T)}(undef, length(subs))
for i = 1:length(res)
res[i] = _as_subgroup_bare(G, subs[i]::GapObj)
end
diff --git a/src/Modules/ModuleTypes.jl b/src/Modules/ModuleTypes.jl
index 422e6021a1da..15f803c5bd59 100644
--- a/src/Modules/ModuleTypes.jl
+++ b/src/Modules/ModuleTypes.jl
@@ -294,14 +294,14 @@ julia> B = R[x^2; x*y; y^2; z^4]
[z^4]
julia> M = SubquoModule(A, B)
-Subquotient of Submodule with 2 generators
-1 -> x*e[1]
-2 -> y*e[1]
-by Submodule with 4 generators
-1 -> x^2*e[1]
-2 -> x*y*e[1]
-3 -> y^2*e[1]
-4 -> z^4*e[1]
+Subquotient of submodule with 2 generators
+ 1: x*e[1]
+ 2: y*e[1]
+by submodule with 4 generators
+ 1: x^2*e[1]
+ 2: x*y*e[1]
+ 3: y^2*e[1]
+ 4: z^4*e[1]
julia> f = SubquoModuleElem(sparse_row(R, [(1,z),(2,one(R))]),M)
(x*z + y)*e[1]
diff --git a/src/Modules/ModulesGraded.jl b/src/Modules/ModulesGraded.jl
index 08cf10fda0a7..d7144b1ef6d3 100644
--- a/src/Modules/ModulesGraded.jl
+++ b/src/Modules/ModulesGraded.jl
@@ -758,11 +758,13 @@ julia> V = [y*G[1], x*G[1]+y*G[2], z*G[2]]
z*e[2]
julia> a = hom(F, G, V)
-F -> G
-e[1] -> y*e[1]
-e[2] -> x*e[1] + y*e[2]
-e[3] -> z*e[2]
Graded module homomorphism of degree [1]
+ from F
+ to G
+defined by
+ e[1] -> y*e[1]
+ e[2] -> x*e[1] + y*e[2]
+ e[3] -> z*e[2]
julia> degree(a)
[1]
@@ -832,11 +834,13 @@ julia> V = [y*G[1], x*G[1]+y*G[2], z*G[2]]
z*e[2]
julia> a = hom(F, G, V)
-F -> G
-e[1] -> y*e[1]
-e[2] -> x*e[1] + y*e[2]
-e[3] -> z*e[2]
Graded module homomorphism of degree [1]
+ from F
+ to G
+defined by
+ e[1] -> y*e[1]
+ e[2] -> x*e[1] + y*e[2]
+ e[3] -> z*e[2]
julia> is_graded(a)
true
@@ -893,11 +897,13 @@ julia> V = [y*G[1], x*G[1]+y*G[2], z*G[2]]
z*e[2]
julia> a = hom(F, G, V)
-F -> G
-e[1] -> y*e[1]
-e[2] -> x*e[1] + y*e[2]
-e[3] -> z*e[2]
Graded module homomorphism of degree [1]
+ from F
+ to G
+defined by
+ e[1] -> y*e[1]
+ e[2] -> x*e[1] + y*e[2]
+ e[3] -> z*e[2]
julia> is_graded(a)
true
@@ -935,11 +941,13 @@ julia> V = [y*G[1], x*G[1]+y*G[2], z*G[2]]
z*e[2]
julia> a = hom(F, G, V)
-F -> G
-e[1] -> y*e[1]
-e[2] -> x*e[1] + y*e[2]
-e[3] -> z*e[2]
Graded module homomorphism of degree [1]
+ from F
+ to G
+defined by
+ e[1] -> y*e[1]
+ e[2] -> x*e[1] + y*e[2]
+ e[3] -> z*e[2]
julia> is_homogeneous(a)
false
@@ -1258,10 +1266,12 @@ julia> N = M;
julia> V = [y^2*N[1], x^2*N[2]];
julia> a = hom(M, N, V)
-M -> M
-x*e[1] -> x*y^2*e[1]
-y*e[1] -> x^2*y*e[1]
Graded module homomorphism of degree [2]
+ from M
+ to M
+defined by
+ x*e[1] -> x*y^2*e[1]
+ y*e[1] -> x^2*y*e[1]
julia> degree(a)
[2]
@@ -1337,10 +1347,12 @@ julia> N = M;
julia> V = [y^2*N[1], x^2*N[2]];
julia> a = hom(M, N, V)
-M -> M
-x*e[1] -> x*y^2*e[1]
-y*e[1] -> x^2*y*e[1]
Graded module homomorphism of degree [2]
+ from M
+ to M
+defined by
+ x*e[1] -> x*y^2*e[1]
+ y*e[1] -> x^2*y*e[1]
julia> grading_group(a)
Z
@@ -1375,10 +1387,12 @@ julia> N = M;
julia> V = [y^2*N[1], x^2*N[2]];
julia> a = hom(M, N, V)
-M -> M
-x*e[1] -> x*y^2*e[1]
-y*e[1] -> x^2*y*e[1]
Graded module homomorphism of degree [2]
+ from M
+ to M
+defined by
+ x*e[1] -> x*y^2*e[1]
+ y*e[1] -> x^2*y*e[1]
julia> is_homogeneous(a)
false
@@ -1412,15 +1426,18 @@ of `F` in form of a Betti table.
Alternatively, use `betti`.
# Examples
-```julia
+```jldoctest
julia> R, (w, x, y, z) = graded_polynomial_ring(QQ, [:w, :x, :y, :z]);
julia> I = ideal(R, [x*z, y*z, x*w^2, y*w^2])
-ideal(x*z, y*z, w^2*x, w^2*y)
+Ideal generated by
+ x*z
+ y*z
+ w^2*x
+ w^2*y
julia> A, _= quo(R, I)
-(Quotient of multivariate polynomial ring by ideal with 4 generators, Map from
-R to A defined by a julia-function with inverse)
+(Quotient of multivariate polynomial ring by ideal (x*z, y*z, w^2*x, w^2*y), Map: R -> A)
julia> FA = free_resolution(A)
Free resolution of A
@@ -1428,13 +1445,13 @@ R^1 <---- R^4 <---- R^4 <---- R^1 <---- 0
0 1 2 3 4
julia> betti_table(FA)
- 0 1 2 3
+degree: 0 1 2 3
------------------
-0 : 1 - - -
-1 : - 2 1 -
-2 : - 2 3 1
+ 0: 1 - - -
+ 1: - 2 1 -
+ 2: - 2 3 1
------------------
-total: 1 4 4 1
+ total: 1 4 4 1
julia> R, (x, y) = graded_polynomial_ring(QQ, [:x, :y]);
@@ -1445,12 +1462,11 @@ julia> M = quotient_ring_as_module(I);
julia> FM = free_resolution(M, algorithm = :nres);
julia> betti_table(FM)
- 0 1 2
+degree: 0 1 2
---------------
--1 : - - 1
-0 : 1 3 1
+ 0: 1 2 1
---------------
-total: 1 3 2
+ total: 1 2 1
```
"""
function betti_table(F::FreeResolution; project::Union{FinGenAbGroupElem, Nothing} = nothing, reverse_direction::Bool=false)
@@ -1517,27 +1533,33 @@ function Base.show(io::IO, b::BettiTable)
if b.project === nothing
for i in 1:ngens(parent(x[1][2]))
ngens(parent(x[1][2])) > 1 && println(io, "Betti Table for component ", i)
+
+ # figure out width of first column
L = sort(unique(collect(x[k][2][i] for k in 1:length(x))))
mi = minimum(L)
mx = maximum(L)
- initial_padding = max(ndigits(mi) + mi < 0 ? 0 : 1, 7)-2
- print(io, " "^initial_padding)
- total_space_count = initial_padding
+ # 6 = length(degree); we take length of mi into account in case it is negative
+ first_column_width = max(6, ndigits(mi), ndigits(mx))
+
+ # header row
+ print(io, lpad("degree", first_column_width), ":")
+ total_space_count = first_column_width
for j in min:step:maxv
adjustment = j < 0 ? 1 : 0
+ if j == min
+ adjustment += 1
+ end
space_count = max(0, column_widths[j] - ndigits(j) - adjustment)
print(io, " "^(space_count))
print(io, j)
- total_space_count = total_space_count + space_count + ndigits(j) + adjustment
+ total_space_count += space_count + ndigits(j) + adjustment
end
- total_space_count = total_space_count
- print(io, "\n")
- print(io, "-"^total_space_count)
print(io, "\n")
+ # separator row
+ println(io, "-"^total_space_count)
+ # print bulk of table
for j in mi:mx
- adjustment = j < 0 ? 1 : 0
- print(io, j, " "^(5 - ndigits(j) - adjustment))
- print(io, ":")
+ print(io, lpad(j, first_column_width), ":")
for h in min:step:maxv
sum_current = sum([getindex(T, x[k]) for k in 1:length(x) if x[k][1] == h && x[k][2][i] == j])
@assert column_widths[h] - ndigits(sum_current) >= 2
@@ -1549,8 +1571,10 @@ function Base.show(io::IO, b::BettiTable)
end
print(io,"\n")
end
- print(io, "-" ^ total_space_count)
- print(io, "\n", "total:")
+ # separator row
+ println(io, "-"^total_space_count)
+ # footer row
+ print(io, lpad("total", first_column_width), ":")
for i_total in min:step:maxv
sum_row = sum(getindex(T, x[j]) for j in 1:length(x) if x[j][1] == i_total)
print(io, " ", sum_row)
@@ -2032,7 +2056,7 @@ julia> R, (x,y) = graded_polynomial_ring(QQ, [:x, :y])
(Graded multivariate polynomial ring in 2 variables over QQ, MPolyDecRingElem{QQFieldElem, QQMPolyRingElem}[x, y])
julia> free_module_dec(R,3)
-Decorated free module of rank 3 over RR^3([0])
+Decorated free module of rank 3 over R
```
"""
@@ -2092,23 +2116,10 @@ function show(io::IO, F::FreeMod_dec)
@show_name(io, F)
@show_special(io, F)
+ io = terse(io)
+ io = pretty(io)
print(io, "Decorated free module of rank $(rank(F)) over ")
- print(IOContext(io, :compact =>true), base_ring(F))
-
- i = 1
- while i < dim(F)
- d = F.d[i]
- j = 1
- while i+j <= dim(F) && d == F.d[i+j]
- j += 1
- end
- print(IOContext(io, :compact => true), base_ring(F), "^$j")
- print(IOContext(io, :compact => true), "(", -d, ")")
- if i+j < dim(F)
- print(io, " + ")
- end
- i += j
- end
+ print(IOContext(io, :compact => true), Lowercase(), base_ring(F))
end
# Generic specialized show methods (formerly in Hecke)
@@ -2498,23 +2509,22 @@ multivariate polynomial ring with coefficients in a field, return the Betti Tabl
of the minimal free resolution of `M`. Similarly for `A` and `I`.
# Examples
-```julia
+```jldoctest
julia> R, (w, x, y, z) = graded_polynomial_ring(QQ, [:w, :x, :y, :z]);
julia> I = ideal(R, [w^2-x*z, w*x-y*z, x^2-w*y, x*y-z^2, y^2-w*z]);
julia> A, _ = quo(R, I)
-(Quotient of multivariate polynomial ring by ideal with 5 generators, Map from
-R to A defined by a julia-function with inverse)
+(Quotient of multivariate polynomial ring by ideal (w^2 - x*z, w*x - y*z, -w*y + x^2, x*y - z^2, -w*z + y^2), Map: R -> A)
julia> minimal_betti_table(A)
- 0 1 2 3
+degree: 0 1 2 3
------------------
-0 : 1 - - -
-1 : - 5 5 -
-2 : - - - 1
+ 0: 1 - - -
+ 1: - 5 5 -
+ 2: - - - 1
------------------
-total: 1 5 5 1
+ total: 1 5 5 1
```
"""
function minimal_betti_table(M::ModuleFP{T}; check::Bool=true) where {T<:MPolyDecRingElem}
@@ -2550,14 +2560,13 @@ Betti table of the minimal free resolution arising from `F`.
The algorithm proceeds without actually minimizing the resolution.
# Examples
-```julia
+```jldoctest
julia> R, (w, x, y, z) = graded_polynomial_ring(QQ, [:w, :x, :y, :z]);
julia> I = ideal(R, [w^2-x*z, w*x-y*z, x^2-w*y, x*y-z^2, y^2-w*z]);
julia> A, _ = quo(R, I)
-(Quotient of multivariate polynomial ring by ideal with 5 generators, Map from
-R to A defined by a julia-function with inverse)
+(Quotient of multivariate polynomial ring by ideal (w^2 - x*z, w*x - y*z, -w*y + x^2, x*y - z^2, -w*z + y^2), Map: R -> A)
julia> FA = free_resolution(A)
Free resolution of A
@@ -2565,22 +2574,22 @@ R^1 <---- R^5 <---- R^6 <---- R^2 <---- 0
0 1 2 3 4
julia> betti_table(FA)
- 0 1 2 3
+degree: 0 1 2 3
------------------
-0 : 1 - - -
-1 : - 5 5 1
-2 : - - 1 1
+ 0: 1 - - -
+ 1: - 5 5 1
+ 2: - - 1 1
------------------
-total: 1 5 6 2
+ total: 1 5 6 2
julia> minimal_betti_table(FA)
- 0 1 2 3
+degree: 0 1 2 3
------------------
-0 : 1 - - -
-1 : - 5 5 -
-2 : - - - 1
+ 0: 1 - - -
+ 1: - 5 5 -
+ 2: - - - 1
------------------
-total: 1 5 5 1
+ total: 1 5 5 1
```
"""
function minimal_betti_table(res::FreeResolution{T}; check::Bool=true) where {T<:ModuleFP}
@@ -2718,21 +2727,21 @@ e[1]
julia> MT = truncate(M, 3);
julia> MT[1]
-Graded subquotient of submodule of F generated by
-1 -> z^3*e[1]
-2 -> y*z^2*e[1]
-3 -> y^2*z*e[1]
-4 -> y^3*e[1]
-5 -> x*z^2*e[1]
-6 -> x*y*z*e[1]
-7 -> x*y^2*e[1]
-8 -> x^2*z*e[1]
-9 -> x^2*y*e[1]
-10 -> x^3*e[1]
-by submodule of F generated by
-1 -> x*e[1]
-2 -> y^4*e[1]
-3 -> z^5*e[1]
+Graded subquotient of graded submodule of F with 10 generators
+ 1: z^3*e[1]
+ 2: y*z^2*e[1]
+ 3: y^2*z*e[1]
+ 4: y^3*e[1]
+ 5: x*z^2*e[1]
+ 6: x*y*z*e[1]
+ 7: x*y^2*e[1]
+ 8: x^2*z*e[1]
+ 9: x^2*y*e[1]
+ 10: x^3*e[1]
+by graded submodule of F with 3 generators
+ 1: x*e[1]
+ 2: y^4*e[1]
+ 3: z^5*e[1]
```
"""
function truncate(I::ModuleFP, g::FinGenAbGroupElem, task::Symbol=:with_morphism)
@@ -2805,35 +2814,33 @@ multivariate polynomial ring with coefficients in a field, return the
Castelnuovo-Mumford regularity of `I`.
# Examples
-```julia
+```jldoctest
julia> R, (x, y, z) = graded_polynomial_ring(QQ, [:x, :y, :z]);
julia> F = graded_free_module(R, 1);
julia> M, _ = quo(F, [x^2*F[1], y^2*F[1], z^2*F[1]])
-(Graded subquotient of submodule of F generated by
-1 -> e[1]
-by submodule of F generated by
-1 -> x^2*e[1]
-2 -> y^2*e[1]
-3 -> z^2*e[1], F -> M
-e[1] -> e[1]
-Homogeneous module homomorphism)
+(Graded subquotient of graded submodule of F with 1 generator
+ 1: e[1]
+by graded submodule of F with 3 generators
+ 1: x^2*e[1]
+ 2: y^2*e[1]
+ 3: z^2*e[1], Hom: F -> M)
julia> cm_regularity(M)
3
julia> minimal_betti_table(M)
- 0 1 2 3
---------------
-0 : 1 - - -
-1 : - 3 - -
-2 : - - 3 -
-3 : - - - 1
---------------
-total: 1 3 3 1
+degree: 0 1 2 3
+------------------
+ 0: 1 - - -
+ 1: - 3 - -
+ 2: - - 3 -
+ 3: - - - 1
+------------------
+ total: 1 3 3 1
```
-```julia
+```jldoctest
julia> R, (w, x, y, z) = graded_polynomial_ring(QQ, [:w, :x, :y, :z]);
julia> I = ideal(R, [-x*z+y^2, x*y-w*z, x^2-w*y]);
@@ -2844,12 +2851,12 @@ julia> cm_regularity(I)
julia> A, _ = quo(R, I);
julia> minimal_betti_table(A)
- 0 1 2
-------------
-0 : 1 - -
-1 : - 3 2
-------------
-total: 1 3 2
+degree: 0 1 2
+---------------
+ 0: 1 - -
+ 1: - 3 2
+---------------
+ total: 1 3 2
```
"""
function cm_regularity(M::ModuleFP; check::Bool=true)
@@ -2890,11 +2897,11 @@ julia> R, (x, y) = polynomial_ring(QQ, [:x, :y]);
julia> IR = ideal(R, [x^2, y^3]);
julia> quotient_ring_as_module(IR)
-Subquotient of Submodule with 1 generator
-1 -> e[1]
-by Submodule with 2 generators
-1 -> x^2*e[1]
-2 -> y^3*e[1]
+Subquotient of submodule with 1 generator
+ 1: e[1]
+by submodule with 2 generators
+ 1: x^2*e[1]
+ 2: y^3*e[1]
julia> base_ring(ans)
Multivariate polynomial ring in 2 variables x, y
@@ -2905,11 +2912,11 @@ julia> A, _ = quo(R, ideal(R,[x*y]));
julia> AI = ideal(A, [x^2, y^3]);
julia> quotient_ring_as_module(AI)
-Subquotient of Submodule with 1 generator
-1 -> e[1]
-by Submodule with 2 generators
-1 -> x^2*e[1]
-2 -> y^3*e[1]
+Subquotient of submodule with 1 generator
+ 1: e[1]
+by submodule with 2 generators
+ 1: x^2*e[1]
+ 2: y^3*e[1]
julia> base_ring(ans)
Quotient
@@ -2927,11 +2934,11 @@ Ideal generated by
y^3
julia> quotient_ring_as_module(I)
-Graded subquotient of submodule of S^1 generated by
-1 -> e[1]
-by submodule of S^1 generated by
-1 -> x^2*e[1]
-2 -> y^3*e[1]
+Graded subquotient of graded submodule of S^1 with 1 generator
+ 1: e[1]
+by graded submodule of S^1 with 2 generators
+ 1: x^2*e[1]
+ 2: y^3*e[1]
```
"""
@@ -2964,9 +2971,9 @@ Ideal generated by
julia> ideal_as_module(I)
Submodule with 2 generators
-1 -> x^2*e[1]
-2 -> y^3*e[1]
-represented as subquotient with no relations.
+ 1: x^2*e[1]
+ 2: y^3*e[1]
+represented as subquotient with no relations
```
```jldoctest
julia> S, (x, y) = graded_polynomial_ring(QQ, [:x, :y]);
@@ -2977,9 +2984,9 @@ Ideal generated by
y^3
julia> ideal_as_module(I)
-Graded submodule of S^1
-1 -> x^2*e[1]
-2 -> y^3*e[1]
+Graded submodule of S^1 with 2 generators
+ 1: x^2*e[1]
+ 2: y^3*e[1]
represented as subquotient with no relations
```
"""
@@ -3020,16 +3027,16 @@ Ideal generated by
0
julia> M = quotient_ring_as_module(I)
-Graded submodule of R^1
-1 -> e[1]
+Graded submodule of R^1 with 1 generator
+ 1: e[1]
represented as subquotient with no relations
julia> degree(gen(M, 1))
[0]
julia> N = twist(M, 2)
-Graded submodule of R^1
-1 -> e[1]
+Graded submodule of R^1 with 1 generator
+ 1: e[1]
represented as subquotient with no relations
julia> degree(gen(N, 1))
diff --git a/src/Modules/UngradedModules/FreeMod.jl b/src/Modules/UngradedModules/FreeMod.jl
index 151225e454e2..8aff69ed7568 100644
--- a/src/Modules/UngradedModules/FreeMod.jl
+++ b/src/Modules/UngradedModules/FreeMod.jl
@@ -49,7 +49,7 @@ julia> U = complement_of_prime_ideal(P);
julia> RL, _ = localization(R, U);
julia> FRL = free_module(RL, 2, "f")
-Free module of rank 2 over Localization of R at complement of prime ideal (x, y, z)
+Free module of rank 2 over localization of R at complement of prime ideal (x, y, z)
julia> RL(x)*FRL[1]
x*f[1]
@@ -65,7 +65,7 @@ x*g[1]
julia> RQL, _ = localization(RQ, U);
julia> FRQL = free_module(RQL, 2, "h")
-Free module of rank 2 over Localization of RQ at complement of prime ideal
+Free module of rank 2 over localization of RQ at complement of prime ideal
julia> RQL(x)*FRQL[1]
x*h[1]
@@ -108,8 +108,9 @@ end
function show(io::IO, F::FreeMod)
@show_name(io, F)
@show_special(io, F)
+ io = pretty(io)
compact = get(io, :compact, false)
- io_compact = IOContext(io, :compact => true)
+ io = IOContext(io, :compact => true)
if is_graded(F)
if !compact
print(io, "Graded free module ")
@@ -121,8 +122,8 @@ function show(io::IO, F::FreeMod)
while i+j <= dim(F) && d == F.d[i+j]
j += 1
end
- print(io_compact, base_ring(F), "^$j")
- print(io_compact, "(", -d, ")")
+ print(io, base_ring(F), "^$j")
+ print(io, "(", -d, ")")
if i+j <= dim(F)
print(io, " + ")
end
@@ -130,21 +131,21 @@ function show(io::IO, F::FreeMod)
end
if rank(F)==0
- print(io_compact, base_ring(F), "^0")
+ print(io, base_ring(F), "^0")
end
if !compact
- print(io," of rank $(rank(F)) over ")
- print(io_compact, base_ring(F))
+ print(io," of rank $(rank(F)) over ", Lowercase())
+ print(io, base_ring(F))
end
else
if !compact
#Todo: Use once the printing of rings is fixed
- #print(io_compact, "Free module ", base_ring(F), "^$(F.n) of rank $(F.n) over ")
- print(io_compact, "Free module of rank $(F.n) over ")
- print(io_compact, F.R)
+ #print(io, "Free module ", base_ring(F), "^$(F.n) of rank $(F.n) over ")
+ print(io, "Free module of rank $(rank(F)) over ", Lowercase())
+ print(io, F.R)
else
- print(io_compact, base_ring(F), "^$(F.n)")
+ print(io, base_ring(F), "^$(rank(F))")
end
end
end
diff --git a/src/Modules/UngradedModules/FreeModuleHom.jl b/src/Modules/UngradedModules/FreeModuleHom.jl
index eb90491055c3..9e725f0e9b26 100644
--- a/src/Modules/UngradedModules/FreeModuleHom.jl
+++ b/src/Modules/UngradedModules/FreeModuleHom.jl
@@ -113,13 +113,9 @@ julia> V = [y*G[1], x*G[1]+y*G[2], z*G[2]]
z*e[2]
julia> a = hom(F, G, V)
-Map with following data
-Domain:
-=======
-Free module of rank 3 over R
-Codomain:
-=========
-Free module of rank 2 over R
+Module homomorphism
+ from F
+ to G
julia> a(F[2])
x*e[1] + y*e[2]
@@ -130,13 +126,9 @@ julia> B = R[y 0; x y; 0 z]
[0 z]
julia> b = hom(F, G, B)
-Map with following data
-Domain:
-=======
-Free module of rank 3 over R
-Codomain:
-=========
-Free module of rank 2 over R
+Module homomorphism
+ from F
+ to G
julia> a == b
true
@@ -158,11 +150,13 @@ julia> V1 = [y*G1[1], (x+y)*G1[1]+y*G1[2], z*G1[2]]
z*e[2]
julia> a1 = hom(F1, G1, V1)
-F1 -> G1
-e[1] -> y*e[1]
-e[2] -> (x + y)*e[1] + y*e[2]
-e[3] -> z*e[2]
Graded module homomorphism of degree [1]
+ from F1
+ to G1
+defined by
+ e[1] -> y*e[1]
+ e[2] -> (x + y)*e[1] + y*e[2]
+ e[3] -> z*e[2]
julia> F2 = graded_free_module(Rg, [1,1,1])
Graded free module Rg^3([-1]) of rank 3 over Rg
@@ -177,11 +171,13 @@ julia> V2 = [y*G2[1], (x+y)*G2[1]+y*G2[2], z*G2[2]]
z*e[2]
julia> a2 = hom(F2, G2, V2)
-F2 -> G2
-e[1] -> y*e[1]
-e[2] -> (x + y)*e[1] + y*e[2]
-e[3] -> z*e[2]
Homogeneous module homomorphism
+ from F2
+ to G2
+defined by
+ e[1] -> y*e[1]
+ e[2] -> (x + y)*e[1] + y*e[2]
+ e[3] -> z*e[2]
julia> B = Rg[y 0; x+y y; 0 z]
[ y 0]
@@ -189,11 +185,13 @@ julia> B = Rg[y 0; x+y y; 0 z]
[ 0 z]
julia> b = hom(F2, G2, B)
-F2 -> G2
-e[1] -> y*e[1]
-e[2] -> (x + y)*e[1] + y*e[2]
-e[3] -> z*e[2]
Homogeneous module homomorphism
+ from F2
+ to G2
+defined by
+ e[1] -> y*e[1]
+ e[2] -> (x + y)*e[1] + y*e[2]
+ e[3] -> z*e[2]
julia> a2 == b
true
@@ -277,40 +275,42 @@ function morphism_type(
end
function Base.show(io::IO, ::MIME"text/plain", fmh::FreeModuleHom{T1, T2, RingMapType}) where {T1 <: AbstractFreeMod, T2 <: ModuleFP, RingMapType}
- # HACK
- show(io, fmh)
+ println(terse(io), fmh)
+ io = pretty(io)
+ io_compact = IOContext(io, :compact => true)
+ println(io_compact, Indent(), "from ", Lowercase(), domain(fmh))
+ print(io_compact, "to ", Lowercase(), codomain(fmh), Dedent())
+
+ if is_graded(fmh)
+ println(io)
+ print(io, "defined by", Indent())
+ io = terse(io)
+ domain_gens = gens(domain(fmh))
+ for g in domain_gens
+ println(io)
+ print(io, g, " -> ", fmh(g))
+ end
+ end
end
function Base.show(io::IO, fmh::FreeModuleHom{T1, T2, RingMapType}) where {T1 <: AbstractFreeMod, T2 <: ModuleFP, RingMapType}
- compact = get(io, :compact, false)
- io_compact = IOContext(io, :compact => true)
- if is_graded(fmh)
- print(io_compact, domain(fmh))
- print(io, " -> ")
- print(io_compact, codomain(fmh))
- if !compact
- print(io, "\n")
- for i in 1:ngens(domain(fmh))
- print(io, domain(fmh)[i], " -> ")
- print(io_compact, fmh(domain(fmh)[i]))
- print(io, "\n")
- end
+ if is_terse(io)
+ if is_graded(fmh)
A = grading_group(fmh)
if degree(fmh) == A[0]
print(io, "Homogeneous module homomorphism")
else
- print(io_compact, "Graded module homomorphism of degree ", degree(fmh))
- print(io, "\n")
+ print(io, "Graded module homomorphism of degree ", degree(fmh))
end
+ else
+ print(io, "Module homomorphism")
end
else
- println(io, "Map with following data")
- println(io, "Domain:")
- println(io, "=======")
- println(io, domain(fmh))
- println(io, "Codomain:")
- println(io, "=========")
- print(io, codomain(fmh))
+ io = pretty(io)
+ print(io, "Hom: ")
+ io = terse(io)
+ print(io, Lowercase(), domain(fmh), " -> ")
+ print(io, Lowercase(), codomain(fmh))
end
end
@@ -335,13 +335,9 @@ julia> V, f = hom(F1, F2)
(hom of (F1, F2), Map: V -> set of all homomorphisms from F1 to F2)
julia> f(V[1])
-Map with following data
-Domain:
-=======
-Free module of rank 3 over R
-Codomain:
-=========
-Free module of rank 2 over R
+Module homomorphism
+ from F1
+ to F2
```
@@ -358,11 +354,13 @@ julia> V, f = hom(F1, F2)
(hom of (F1, F2), Map: V -> set of all homomorphisms from F1 to F2)
julia> f(V[1])
-F1 -> F2
-e[1] -> e[1]
-e[2] -> 0
-e[3] -> 0
Graded module homomorphism of degree [2]
+ from F1
+ to F2
+defined by
+ e[1] -> e[1]
+ e[2] -> 0
+ e[3] -> 0
```
"""
@@ -427,16 +425,10 @@ julia> a = hom(F, G, V);
julia> kernel(a)
(Submodule with 1 generator
-1 -> x*z*e[1] - y*z*e[2] + y^2*e[3]
-represented as subquotient with no relations., Map with following data
-Domain:
-=======
-Submodule with 1 generator
-1 -> x*z*e[1] - y*z*e[2] + y^2*e[3]
-represented as subquotient with no relations.
-Codomain:
-=========
-Free module of rank 3 over R)
+ 1: x*z*e[1] - y*z*e[2] + y^2*e[3]
+represented as subquotient with no relations, Hom: submodule with 1 generator
+ 1: x*z*e[1] - y*z*e[2] + y^2*e[3]
+represented as subquotient with no relations -> F)
```
```jldoctest
@@ -451,13 +443,11 @@ julia> V = [y*G[1], x*G[1]+y*G[2], z*G[2]];
julia> a = hom(F, G, V);
julia> kernel(a)
-(Graded submodule of F
-1 -> x*z*e[1] - y*z*e[2] + y^2*e[3]
-represented as subquotient with no relations, Graded submodule of F
-1 -> x*z*e[1] - y*z*e[2] + y^2*e[3]
-represented as subquotient with no relations -> F
-x*z*e[1] - y*z*e[2] + y^2*e[3] -> x*z*e[1] - y*z*e[2] + y^2*e[3]
-Homogeneous module homomorphism)
+(Graded submodule of F with 1 generator
+ 1: x*z*e[1] - y*z*e[2] + y^2*e[3]
+represented as subquotient with no relations, Hom: graded submodule of F with 1 generator
+ 1: x*z*e[1] - y*z*e[2] + y^2*e[3]
+represented as subquotient with no relations -> F)
```
"""
@@ -560,20 +550,14 @@ julia> a = hom(F, G, V);
julia> image(a)
(Submodule with 3 generators
-1 -> y*e[1]
-2 -> x*e[1] + y*e[2]
-3 -> z*e[2]
-represented as subquotient with no relations., Map with following data
-Domain:
-=======
-Submodule with 3 generators
-1 -> y*e[1]
-2 -> x*e[1] + y*e[2]
-3 -> z*e[2]
-represented as subquotient with no relations.
-Codomain:
-=========
-Free module of rank 2 over R)
+ 1: y*e[1]
+ 2: x*e[1] + y*e[2]
+ 3: z*e[2]
+represented as subquotient with no relations, Hom: submodule with 3 generators
+ 1: y*e[1]
+ 2: x*e[1] + y*e[2]
+ 3: z*e[2]
+represented as subquotient with no relations -> G)
```
```jldoctest
@@ -588,19 +572,15 @@ julia> V = [y*G[1], x*G[1]+y*G[2], z*G[2]];
julia> a = hom(F, G, V);
julia> image(a)
-(Graded submodule of G
-1 -> y*e[1]
-2 -> x*e[1] + y*e[2]
-3 -> z*e[2]
-represented as subquotient with no relations, Graded submodule of G
-1 -> y*e[1]
-2 -> x*e[1] + y*e[2]
-3 -> z*e[2]
-represented as subquotient with no relations -> G
-y*e[1] -> y*e[1]
-x*e[1] + y*e[2] -> x*e[1] + y*e[2]
-z*e[2] -> z*e[2]
-Homogeneous module homomorphism)
+(Graded submodule of G with 3 generators
+ 1: y*e[1]
+ 2: x*e[1] + y*e[2]
+ 3: z*e[2]
+represented as subquotient with no relations, Hom: graded submodule of G with 3 generators
+ 1: y*e[1]
+ 2: x*e[1] + y*e[2]
+ 3: z*e[2]
+represented as subquotient with no relations -> G)
```
"""
diff --git a/src/Modules/UngradedModules/FreeResolutions.jl b/src/Modules/UngradedModules/FreeResolutions.jl
index 1e7073a478e7..f9d075c36bf1 100644
--- a/src/Modules/UngradedModules/FreeResolutions.jl
+++ b/src/Modules/UngradedModules/FreeResolutions.jl
@@ -26,6 +26,7 @@ function free_show(io::IO, C::ComplexOfMorphisms)
push!(rank_mod, rank(M))
end
+ io = terse(io)
io = IOContext(io, :compact => true)
N = get_attribute(C, :free_res)
if N !== nothing
@@ -96,14 +97,14 @@ julia> B = R[x^2; x*y; y^2; z^4]
[z^4]
julia> M = SubquoModule(A, B)
-Subquotient of Submodule with 2 generators
-1 -> x*e[1]
-2 -> y*e[1]
-by Submodule with 4 generators
-1 -> x^2*e[1]
-2 -> x*y*e[1]
-3 -> y^2*e[1]
-4 -> z^4*e[1]
+Subquotient of submodule with 2 generators
+ 1: x*e[1]
+ 2: y*e[1]
+by submodule with 4 generators
+ 1: x^2*e[1]
+ 2: x*y*e[1]
+ 3: y^2*e[1]
+ 4: z^4*e[1]
julia> fr = free_resolution(M, length=1)
Free resolution of M
@@ -275,14 +276,14 @@ julia> B = R[x^2; x*y; y^2; z^4]
[z^4]
julia> M = SubquoModule(A, B)
-Subquotient of Submodule with 2 generators
-1 -> x*e[1]
-2 -> y*e[1]
-by Submodule with 4 generators
-1 -> x^2*e[1]
-2 -> x*y*e[1]
-3 -> y^2*e[1]
-4 -> z^4*e[1]
+Subquotient of submodule with 2 generators
+ 1: x*e[1]
+ 2: y*e[1]
+by submodule with 4 generators
+ 1: x^2*e[1]
+ 2: x*y*e[1]
+ 3: y^2*e[1]
+ 4: z^4*e[1]
julia> fr = free_resolution(M, length=1)
Free resolution of M
@@ -304,7 +305,7 @@ julia> is_complete(fr)
true
```
-```
+```jldoctest
julia> R, (w, x, y, z) = graded_polynomial_ring(QQ, [:w, :x, :y, :z]);
julia> Z = R(0)
@@ -318,14 +319,14 @@ julia> B = [Z Z Z O; w*y w*z-x*y x*z-y^2 Z];
julia> A = transpose(matrix(B));
julia> M = graded_cokernel(A)
-Graded subquotient of submodule of R^2 generated by
-1 -> e[1]
-2 -> e[2]
-by submodule of R^2 generated by
-1 -> w*y*e[2]
-2 -> (w*z - x*y)*e[2]
-3 -> (x*z - y^2)*e[2]
-4 -> e[1]
+Graded subquotient of graded submodule of R^2 with 2 generators
+ 1: e[1]
+ 2: e[2]
+by graded submodule of R^2 with 4 generators
+ 1: w*y*e[2]
+ 2: (w*z - x*y)*e[2]
+ 3: (x*z - y^2)*e[2]
+ 4: e[1]
julia> FM1 = free_resolution(M)
Free resolution of M
@@ -333,15 +334,14 @@ R^2 <---- R^7 <---- R^8 <---- R^3 <---- 0
0 1 2 3 4
julia> betti_table(FM1)
- 0 1 2 3
------------------
--1 : - 1 - -
-0 : 2 - - -
-1 : - 3 3 1
-2 : - 3 5 2
------------------
-total: 2 7 8 3
-
+degree: 0 1 2 3
+------------------
+ -1: - 1 - -
+ 0: 2 - - -
+ 1: - 3 3 1
+ 2: - 3 5 2
+------------------
+ total: 2 7 8 3
julia> matrix(map(FM1, 1))
[1 0]
@@ -358,15 +358,14 @@ R^2 <---- R^4 <---- R^4 <---- R^2 <---- 0
0 1 2 3 4
julia> betti_table(FM2)
- 0 1 2 3
------------------
--1 : - 1 - -
-0 : 2 - - -
-1 : - 3 - -
-2 : - - 4 2
------------------
-total: 2 4 4 2
-
+degree: 0 1 2 3
+------------------
+ -1: - 1 - -
+ 0: 2 - - -
+ 1: - 3 - -
+ 2: - - 4 2
+------------------
+ total: 2 4 4 2
julia> matrix(map(FM2, 1))
[1 0]
@@ -380,14 +379,13 @@ R^1 <---- R^3 <---- R^4 <---- R^2 <---- 0
0 1 2 3 4
julia> betti_table(FM3)
- 0 1 2 3
------------------
-0 : 1 - - -
-1 : - 3 - -
-2 : - - 4 2
------------------
-total: 1 3 4 2
-
+degree: 0 1 2 3
+------------------
+ 0: 1 - - -
+ 1: - 3 - -
+ 2: - - 4 2
+------------------
+ total: 1 3 4 2
julia> matrix(map(FM3, 1))
[-x*z + y^2]
diff --git a/src/Modules/UngradedModules/Hom_and_ext.jl b/src/Modules/UngradedModules/Hom_and_ext.jl
index 00cdb25d0ec6..e1a3bd587c80 100644
--- a/src/Modules/UngradedModules/Hom_and_ext.jl
+++ b/src/Modules/UngradedModules/Hom_and_ext.jl
@@ -25,12 +25,12 @@ julia> F = FreeMod(R, 2);
julia> V = [x*F[1], y^2*F[2]];
julia> M = quo_object(F, V)
-Subquotient of Submodule with 2 generators
-1 -> e[1]
-2 -> e[2]
-by Submodule with 2 generators
-1 -> x*e[1]
-2 -> y^2*e[2]
+Subquotient of submodule with 2 generators
+ 1: e[1]
+ 2: e[2]
+by submodule with 2 generators
+ 1: x*e[1]
+ 2: y^2*e[2]
julia> H = hom(M, M)[1]
hom of (M, M)
@@ -374,12 +374,12 @@ julia> F = FreeMod(R, 2);
julia> V = [x*F[1], y^2*F[2]];
julia> M = quo_object(F, V)
-Subquotient of Submodule with 2 generators
-1 -> e[1]
-2 -> e[2]
-by Submodule with 2 generators
-1 -> x*e[1]
-2 -> y^2*e[2]
+Subquotient of submodule with 2 generators
+ 1: e[1]
+ 2: e[2]
+by submodule with 2 generators
+ 1: x*e[1]
+ 2: y^2*e[2]
julia> H = hom(M, M)[1];
@@ -396,23 +396,9 @@ julia> relations(H)
y^2*(e[2] -> e[2])
julia> a = element_to_homomorphism(H[1]+y*H[2])
-Map with following data
-Domain:
-=======
-Subquotient of Submodule with 2 generators
-1 -> e[1]
-2 -> e[2]
-by Submodule with 2 generators
-1 -> x*e[1]
-2 -> y^2*e[2]
-Codomain:
-=========
-Subquotient of Submodule with 2 generators
-1 -> e[1]
-2 -> e[2]
-by Submodule with 2 generators
-1 -> x*e[1]
-2 -> y^2*e[2]
+Module homomorphism
+ from M
+ to M
julia> matrix(a)
[1 0]
@@ -440,12 +426,12 @@ julia> F = FreeMod(R, 2);
julia> V = [x*F[1], y^2*F[2]];
julia> M = quo_object(F, V)
-Subquotient of Submodule with 2 generators
-1 -> e[1]
-2 -> e[2]
-by Submodule with 2 generators
-1 -> x*e[1]
-2 -> y^2*e[2]
+Subquotient of submodule with 2 generators
+ 1: e[1]
+ 2: e[2]
+by submodule with 2 generators
+ 1: x*e[1]
+ 2: y^2*e[2]
julia> H = hom(M, M)[1];
diff --git a/src/Modules/UngradedModules/HomologicalAlgebra.jl b/src/Modules/UngradedModules/HomologicalAlgebra.jl
index b0597da4e97c..21a77b1d3286 100644
--- a/src/Modules/UngradedModules/HomologicalAlgebra.jl
+++ b/src/Modules/UngradedModules/HomologicalAlgebra.jl
@@ -231,27 +231,27 @@ julia> F = free_module(R, 1);
julia> Q, _ = quo(F, [x*F[1]]);
julia> T0 = tor(Q, M, 0)
-Subquotient of Submodule with 2 generators
-1 -> x*e[1] \otimes e[1]
-2 -> y*e[1] \otimes e[1]
-by Submodule with 4 generators
-1 -> x^2*e[1] \otimes e[1]
-2 -> y^3*e[1] \otimes e[1]
-3 -> z^4*e[1] \otimes e[1]
-4 -> x*y*e[1] \otimes e[1]
+Subquotient of submodule with 2 generators
+ 1: x*e[1] \otimes e[1]
+ 2: y*e[1] \otimes e[1]
+by submodule with 4 generators
+ 1: x^2*e[1] \otimes e[1]
+ 2: y^3*e[1] \otimes e[1]
+ 3: z^4*e[1] \otimes e[1]
+ 4: x*y*e[1] \otimes e[1]
julia> T1 = tor(Q, M, 1)
-Subquotient of Submodule with 2 generators
-1 -> x*e[1] \otimes e[1]
-2 -> x*y*e[1] \otimes e[1]
-by Submodule with 3 generators
-1 -> x^2*e[1] \otimes e[1]
-2 -> y^3*e[1] \otimes e[1]
-3 -> z^4*e[1] \otimes e[1]
+Subquotient of submodule with 2 generators
+ 1: x*e[1] \otimes e[1]
+ 2: x*y*e[1] \otimes e[1]
+by submodule with 3 generators
+ 1: x^2*e[1] \otimes e[1]
+ 2: y^3*e[1] \otimes e[1]
+ 3: z^4*e[1] \otimes e[1]
julia> T2 = tor(Q, M, 2)
Submodule with 0 generators
-represented as subquotient with no relations.
+represented as subquotient with no relations
```
"""
function tor(M::ModuleFP, N::ModuleFP, i::Int)
@@ -487,20 +487,20 @@ julia> C = ComplexOfMorphisms(ModuleFP, [a, b]);
julia> H = homology(C)
3-element Vector{SubquoModule{QQMPolyRingElem}}:
- Subquotient of Submodule with 1 generator
-1 -> x*e[1]
-by Submodule with 1 generator
-1 -> x^4*e[1]
- Subquotient of Submodule with 1 generator
-1 -> x*e[1]
-by Submodule with 2 generators
-1 -> x^3*e[1]
-2 -> x^2*e[1]
- Subquotient of Submodule with 1 generator
-1 -> e[1]
-by Submodule with 2 generators
-1 -> x^3*e[1]
-2 -> x^2*e[1]
+ Subquotient of submodule with 1 generator
+ 1: x*e[1]
+by submodule with 1 generator
+ 1: x^4*e[1]
+ Subquotient of submodule with 1 generator
+ 1: x*e[1]
+by submodule with 2 generators
+ 1: x^3*e[1]
+ 2: x^2*e[1]
+ Subquotient of submodule with 1 generator
+ 1: e[1]
+by submodule with 2 generators
+ 1: x^3*e[1]
+ 2: x^2*e[1]
```
"""
function homology(C::Hecke.ComplexOfMorphisms{<:ModuleFP})
@@ -534,11 +534,11 @@ julia> b = hom(B, B, [x^2*B[1]]);
julia> C = ComplexOfMorphisms(ModuleFP, [a, b]);
julia> H = homology(C, 1)
-Subquotient of Submodule with 1 generator
-1 -> x*e[1]
-by Submodule with 2 generators
-1 -> x^3*e[1]
-2 -> x^2*e[1]
+Subquotient of submodule with 1 generator
+ 1: x*e[1]
+by submodule with 2 generators
+ 1: x^3*e[1]
+ 2: x^2*e[1]
```
"""
function homology(C::Hecke.ComplexOfMorphisms{<:ModuleFP}, i::Int)
@@ -578,39 +578,39 @@ julia> F = FreeMod(R, 1);
julia> V = [x*F[1], y*F[1]];
julia> M = quo_object(F, V)
-Subquotient of Submodule with 1 generator
-1 -> e[1]
-by Submodule with 2 generators
-1 -> x*e[1]
-2 -> y*e[1]
+Subquotient of submodule with 1 generator
+ 1: e[1]
+by submodule with 2 generators
+ 1: x*e[1]
+ 2: y*e[1]
julia> ext(M, M, 0)
-Subquotient of Submodule with 1 generator
-1 -> (e[1] -> e[1])
-by Submodule with 2 generators
-1 -> y*(e[1] -> e[1])
-2 -> x*(e[1] -> e[1])
+Subquotient of submodule with 1 generator
+ 1: (e[1] -> e[1])
+by submodule with 2 generators
+ 1: y*(e[1] -> e[1])
+ 2: x*(e[1] -> e[1])
julia> ext(M, M, 1)
-Subquotient of Submodule with 2 generators
-1 -> (e[1] -> e[1])
-2 -> (e[2] -> e[1])
-by Submodule with 4 generators
-1 -> y*(e[1] -> e[1])
-2 -> x*(e[1] -> e[1])
-3 -> y*(e[2] -> e[1])
-4 -> x*(e[2] -> e[1])
+Subquotient of submodule with 2 generators
+ 1: (e[1] -> e[1])
+ 2: (e[2] -> e[1])
+by submodule with 4 generators
+ 1: y*(e[1] -> e[1])
+ 2: x*(e[1] -> e[1])
+ 3: y*(e[2] -> e[1])
+ 4: x*(e[2] -> e[1])
julia> ext(M, M, 2)
-Subquotient of Submodule with 1 generator
-1 -> (e[1] -> e[1])
-by Submodule with 2 generators
-1 -> y*(e[1] -> e[1])
-2 -> x*(e[1] -> e[1])
+Subquotient of submodule with 1 generator
+ 1: (e[1] -> e[1])
+by submodule with 2 generators
+ 1: y*(e[1] -> e[1])
+ 2: x*(e[1] -> e[1])
julia> ext(M, M, 3)
Submodule with 0 generators
-represented as subquotient with no relations.
+represented as subquotient with no relations
```
"""
function ext(M::ModuleFP, N::ModuleFP, i::Int)
diff --git a/src/Modules/UngradedModules/Methods.jl b/src/Modules/UngradedModules/Methods.jl
index fba8152ab01b..822b9036ea85 100644
--- a/src/Modules/UngradedModules/Methods.jl
+++ b/src/Modules/UngradedModules/Methods.jl
@@ -19,10 +19,12 @@ julia> B = Rg[x^2; y^3; z^4];
julia> M = SubquoModule(F, A, B);
julia> is_equal_with_morphism(M, M)
-M -> M
-x*e[1] -> x*e[1]
-y*e[1] -> y*e[1]
Homogeneous module homomorphism
+ from M
+ to M
+defined by
+ x*e[1] -> x*e[1]
+ y*e[1] -> y*e[1]
```
"""
function is_equal_with_morphism(M::SubquoModule{T}, N::SubquoModule{T}, task::Symbol = :none) where {T}
diff --git a/src/Modules/UngradedModules/ModuleGens.jl b/src/Modules/UngradedModules/ModuleGens.jl
index bca35fa7e220..f8853391eadd 100644
--- a/src/Modules/UngradedModules/ModuleGens.jl
+++ b/src/Modules/UngradedModules/ModuleGens.jl
@@ -127,7 +127,7 @@ function show(io::IO, F::ModuleGens)
print(io, "Module generating system of length ", length(F))
for i=1:length(F)
if isassigned(F.O, i)
- print(io, "\n", i, " -> ", F.O[i])
+ print(io, "\n", i, ": ", F.O[i])
end
end
end
diff --git a/src/Modules/UngradedModules/Presentation.jl b/src/Modules/UngradedModules/Presentation.jl
index 569d82936558..dd04827f498c 100644
--- a/src/Modules/UngradedModules/Presentation.jl
+++ b/src/Modules/UngradedModules/Presentation.jl
@@ -208,14 +208,14 @@ julia> A = transpose(matrix(B))
[1 0]
julia> M = graded_cokernel(A)
-Graded subquotient of submodule of R^2 generated by
-1 -> e[1]
-2 -> e[2]
-by submodule of R^2 generated by
-1 -> w*y*e[2]
-2 -> (w*z - x*y)*e[2]
-3 -> (x*z - y^2)*e[2]
-4 -> e[1]
+Graded subquotient of graded submodule of R^2 with 2 generators
+ 1: e[1]
+ 2: e[2]
+by graded submodule of R^2 with 4 generators
+ 1: w*y*e[2]
+ 2: (w*z - x*y)*e[2]
+ 3: (x*z - y^2)*e[2]
+ 4: e[1]
julia> PM1 = presentation(M)
0 <---- M <---- R^2 <---- R^4
@@ -246,22 +246,28 @@ julia> p[1]
Graded free module Rg^0 of rank 0 over Rg
julia> map(p,-1)
-F -> 0
-e[1] -> 0
-e[2] -> 0
-e[3] -> 0
Homogeneous module homomorphism
+ from F
+ to 0
+defined by
+ e[1] -> 0
+ e[2] -> 0
+ e[3] -> 0
julia> map(p,0)
-F -> F
-e[1] -> e[1]
-e[2] -> e[2]
-e[3] -> e[3]
Homogeneous module homomorphism
+ from F
+ to F
+defined by
+ e[1] -> e[1]
+ e[2] -> e[2]
+ e[3] -> e[3]
julia> map(p,1)
-0 -> F
Homogeneous module homomorphism
+ from 0
+ to F
+defined by
julia> F = graded_free_module(Rg, 1);
@@ -278,13 +284,13 @@ julia> P[-2]
Graded free module Rg^0 of rank 0 over Rg
julia> P[-1]
-Graded subquotient of submodule of F generated by
-1 -> x*e[1]
-2 -> y*e[1]
-by submodule of F generated by
-1 -> x^2*e[1]
-2 -> y^3*e[1]
-3 -> z^4*e[1]
+Graded subquotient of graded submodule of F with 2 generators
+ 1: x*e[1]
+ 2: y*e[1]
+by graded submodule of F with 3 generators
+ 1: x^2*e[1]
+ 2: y^3*e[1]
+ 3: z^4*e[1]
julia> P[0]
Graded free module Rg^2([-1]) of rank 2 over Rg
@@ -293,25 +299,31 @@ julia> P[1]
Graded free module Rg^2([-2]) + Rg^1([-3]) + Rg^2([-5]) of rank 5 over Rg
julia> map(P,-1)
-M -> 0
-x*e[1] -> 0
-y*e[1] -> 0
Homogeneous module homomorphism
+ from M
+ to 0
+defined by
+ x*e[1] -> 0
+ y*e[1] -> 0
julia> map(P,0)
-Rg^2 -> M
-e[1] -> x*e[1]
-e[2] -> y*e[1]
Homogeneous module homomorphism
+ from Rg^2
+ to M
+defined by
+ e[1] -> x*e[1]
+ e[2] -> y*e[1]
julia> map(P,1)
-Rg^5 -> Rg^2
-e[1] -> x*e[1]
-e[2] -> -y*e[1] + x*e[2]
-e[3] -> y^2*e[2]
-e[4] -> z^4*e[1]
-e[5] -> z^4*e[2]
Homogeneous module homomorphism
+ from Rg^5
+ to Rg^2
+defined by
+ e[1] -> x*e[1]
+ e[2] -> -y*e[1] + x*e[2]
+ e[3] -> y^2*e[2]
+ e[4] -> z^4*e[1]
+ e[5] -> z^4*e[2]
```
"""
function presentation(M::ModuleFP; minimal=false)
@@ -340,24 +352,24 @@ julia> A = R[x; y];
julia> B = R[x^2; y^3; z^4];
julia> M = SubquoModule(A, B)
-Subquotient of Submodule with 2 generators
-1 -> x*e[1]
-2 -> y*e[1]
-by Submodule with 3 generators
-1 -> x^2*e[1]
-2 -> y^3*e[1]
-3 -> z^4*e[1]
+Subquotient of submodule with 2 generators
+ 1: x*e[1]
+ 2: y*e[1]
+by submodule with 3 generators
+ 1: x^2*e[1]
+ 2: y^3*e[1]
+ 3: z^4*e[1]
julia> C = present_as_cokernel(M)
-Subquotient of Submodule with 2 generators
-1 -> e[1]
-2 -> e[2]
-by Submodule with 5 generators
-1 -> x*e[1]
-2 -> -y*e[1] + x*e[2]
-3 -> y^2*e[2]
-4 -> z^4*e[1]
-5 -> z^4*e[2]
+Subquotient of submodule with 2 generators
+ 1: e[1]
+ 2: e[2]
+by submodule with 5 generators
+ 1: x*e[1]
+ 2: -y*e[1] + x*e[2]
+ 3: y^2*e[2]
+ 4: z^4*e[1]
+ 5: z^4*e[2]
```
```jldoctest
@@ -372,26 +384,23 @@ julia> B = Rg[x^2; y^3; z^4];
julia> M = SubquoModule(F, A, B);
julia> present_as_cokernel(M, :with_morphism)
-(Graded subquotient of submodule of Rg^2 generated by
-1 -> e[1]
-2 -> e[2]
-by submodule of Rg^2 generated by
-1 -> x*e[1]
-2 -> -y*e[1] + x*e[2]
-3 -> y^2*e[2]
-4 -> z^4*e[1]
-5 -> z^4*e[2], Graded subquotient of submodule of Rg^2 generated by
-1 -> e[1]
-2 -> e[2]
-by submodule of Rg^2 generated by
-1 -> x*e[1]
-2 -> -y*e[1] + x*e[2]
-3 -> y^2*e[2]
-4 -> z^4*e[1]
-5 -> z^4*e[2] -> M
-e[1] -> x*e[1]
-e[2] -> y*e[1]
-Homogeneous module homomorphism)
+(Graded subquotient of graded submodule of Rg^2 with 2 generators
+ 1: e[1]
+ 2: e[2]
+by graded submodule of Rg^2 with 5 generators
+ 1: x*e[1]
+ 2: -y*e[1] + x*e[2]
+ 3: y^2*e[2]
+ 4: z^4*e[1]
+ 5: z^4*e[2], Hom: graded subquotient of graded submodule of Rg^2 with 2 generators
+ 1: e[1]
+ 2: e[2]
+by graded submodule of Rg^2 with 5 generators
+ 1: x*e[1]
+ 2: -y*e[1] + x*e[2]
+ 3: y^2*e[2]
+ 4: z^4*e[1]
+ 5: z^4*e[2] -> M)
```
"""
function present_as_cokernel(SQ::SubquoModule, task::Symbol = :none)
@@ -441,21 +450,17 @@ Free module of rank 2 over R
julia> present_as_cokernel(F)
Submodule with 2 generators
-1 -> e[1]
-2 -> e[2]
-represented as subquotient with no relations.
+ 1: e[1]
+ 2: e[2]
+represented as subquotient with no relations
julia> present_as_cokernel(F, :only_morphism)
-Map with following data
-Domain:
-=======
-Free module of rank 2 over R
-Codomain:
-=========
-Submodule with 2 generators
-1 -> e[1]
-2 -> e[2]
-represented as subquotient with no relations.
+Module homomorphism
+ from F
+ to submodule with 2 generators
+ 1: e[1]
+ 2: e[2]
+ represented as subquotient with no relations
```
"""
function present_as_cokernel(F::FreeMod, task::Symbol = :none)
@@ -502,24 +507,24 @@ julia> A = transpose(matrix(B))
[1 0]
julia> M = graded_cokernel(A)
-Graded subquotient of submodule of R^2 generated by
-1 -> e[1]
-2 -> e[2]
-by submodule of R^2 generated by
-1 -> w*y*e[2]
-2 -> (w*z - x*y)*e[2]
-3 -> (x*z - y^2)*e[2]
-4 -> e[1]
+Graded subquotient of graded submodule of R^2 with 2 generators
+ 1: e[1]
+ 2: e[2]
+by graded submodule of R^2 with 4 generators
+ 1: w*y*e[2]
+ 2: (w*z - x*y)*e[2]
+ 3: (x*z - y^2)*e[2]
+ 4: e[1]
julia> N, phi = prune_with_map(M);
julia> N
-Graded subquotient of submodule of R^1 generated by
-1 -> e[1]
-by submodule of R^1 generated by
-1 -> (-x*z + y^2)*e[1]
-2 -> (-w*z + x*y)*e[1]
-3 -> w*y*e[1]
+Graded subquotient of graded submodule of R^1 with 1 generator
+ 1: e[1]
+by graded submodule of R^1 with 3 generators
+ 1: (-x*z + y^2)*e[1]
+ 2: (-w*z + x*y)*e[1]
+ 3: w*y*e[1]
julia> phi(first(gens(N)))
e[2]
diff --git a/src/Modules/UngradedModules/SubModuleOfFreeModule.jl b/src/Modules/UngradedModules/SubModuleOfFreeModule.jl
index 840c761ad18a..ecf3de21aa25 100644
--- a/src/Modules/UngradedModules/SubModuleOfFreeModule.jl
+++ b/src/Modules/UngradedModules/SubModuleOfFreeModule.jl
@@ -306,27 +306,29 @@ end
function show(io::IO, M::SubModuleOfFreeModule)
@show_name(io, M)
@show_special(io, M)
- io_compact = IOContext(io, :compact => true)
- compact = get(io, :compact, false)
- if !compact
+# if !is_terse(io)
if is_graded(M)
- print(io_compact, "Graded submodule of ", M.F)
+ io_compact = IOContext(io, :compact => true)
+ print(terse(io_compact), "Graded submodule of ", M.F)
else
#Todo: Use again once the printing of rings is fixed
#print(io_compact, "Submodule of ", M.F)
- print(io_compact, "Submodule")
+ print(io, "Submodule")
end
if ngens(M) == 1
print(io, " with ", ngens(M), " generator")
else
print(io, " with ", ngens(M), " generators")
end
- end
+# end
+ io = pretty(io)
+ print(io, Indent())
for i=1:ngens(M)
if isassigned(M.gens.O, i)
- print(io, "\n", i, " -> ", M[i])
+ print(io, "\n", i, ": ", M[i])
end
end
+ print(io, Dedent())
end
function length(M::SubModuleOfFreeModule)
diff --git a/src/Modules/UngradedModules/SubQuoHom.jl b/src/Modules/UngradedModules/SubQuoHom.jl
index 4dc3e6a10443..4fc4ea9ffbbe 100644
--- a/src/Modules/UngradedModules/SubQuoHom.jl
+++ b/src/Modules/UngradedModules/SubQuoHom.jl
@@ -42,41 +42,42 @@ function SubQuoHom(D::SubquoModule, C::ModuleFP{T}, mat::MatElem{T}, h::RingMapT
end
function Base.show(io::IO, ::MIME"text/plain", fmh::SubQuoHom{T1, T2, RingMapType}) where {T1 <: AbstractSubQuo, T2 <: ModuleFP, RingMapType}
- # HACK
- show(io, fmh)
+ println(terse(io), fmh)
+ io = pretty(io)
+ io_compact = IOContext(io, :compact => true)
+ println(io_compact, Indent(), "from ", Lowercase(), domain(fmh))
+ print(io_compact, "to ", Lowercase(), codomain(fmh), Dedent())
+
+ if is_graded(fmh)
+ println(io)
+ print(io, "defined by", Indent())
+ io = terse(io)
+ domain_gens = gens(domain(fmh))
+ for g in domain_gens
+ println(io)
+ print(io, g, " -> ", fmh(g))
+ end
+ end
end
function Base.show(io::IO, fmh::SubQuoHom{T1, T2, RingMapType}) where {T1 <: AbstractSubQuo, T2 <: ModuleFP, RingMapType}
- compact = get(io, :compact, false)
- io_compact = IOContext(io, :compact => true)
- domain_gens = gens(domain(fmh))
- if is_graded(fmh)
- print(io_compact, domain(fmh))
- print(io, " -> ")
- print(io_compact, codomain(fmh))
- if !compact
- print(io, "\n")
- for i in 1:length(domain_gens)
- print(io, domain_gens[i], " -> ")
- print(io_compact, fmh(domain_gens[i]))
- print(io, "\n")
- end
+ if is_terse(io)
+ if is_graded(fmh)
A = grading_group(fmh)
if degree(fmh) == A[0]
print(io, "Homogeneous module homomorphism")
else
- print(io_compact, "Graded module homomorphism of degree ", degree(fmh))
- print(io, "\n")
+ print(io, "Graded module homomorphism of degree ", degree(fmh))
end
+ else
+ print(io, "Module homomorphism")
end
else
- println(io, "Map with following data")
- println(io, "Domain:")
- println(io, "=======")
- println(io, domain(fmh))
- println(io, "Codomain:")
- println(io, "=========")
- print(io, codomain(fmh))
+ io = pretty(io)
+ print(io, "Hom: ")
+ io = terse(io)
+ print(io, Lowercase(), domain(fmh), " -> ")
+ print(io, Lowercase(), codomain(fmh))
end
end
@@ -133,13 +134,13 @@ julia> B = R[x^2; y^3; z^4]
[z^4]
julia> M = SubquoModule(F, A, B)
-Subquotient of Submodule with 2 generators
-1 -> x*e[1]
-2 -> y*e[1]
-by Submodule with 3 generators
-1 -> x^2*e[1]
-2 -> y^3*e[1]
-3 -> z^4*e[1]
+Subquotient of submodule with 2 generators
+ 1: x*e[1]
+ 2: y*e[1]
+by submodule with 3 generators
+ 1: x^2*e[1]
+ 2: y^3*e[1]
+ 3: z^4*e[1]
julia> N = M;
@@ -149,25 +150,9 @@ julia> V = [y^2*N[1], x*N[2]]
x*y*e[1]
julia> a = hom(M, N, V)
-Map with following data
-Domain:
-=======
-Subquotient of Submodule with 2 generators
-1 -> x*e[1]
-2 -> y*e[1]
-by Submodule with 3 generators
-1 -> x^2*e[1]
-2 -> y^3*e[1]
-3 -> z^4*e[1]
-Codomain:
-=========
-Subquotient of Submodule with 2 generators
-1 -> x*e[1]
-2 -> y*e[1]
-by Submodule with 3 generators
-1 -> x^2*e[1]
-2 -> y^3*e[1]
-3 -> z^4*e[1]
+Module homomorphism
+ from M
+ to M
julia> is_welldefined(a)
true
@@ -218,23 +203,25 @@ julia> A = Rg[x; y];
julia> B = Rg[x^2; y^3; z^4];
julia> M = SubquoModule(F, A, B)
-Graded subquotient of submodule of F generated by
-1 -> x*e[1]
-2 -> y*e[1]
-by submodule of F generated by
-1 -> x^2*e[1]
-2 -> y^3*e[1]
-3 -> z^4*e[1]
+Graded subquotient of graded submodule of F with 2 generators
+ 1: x*e[1]
+ 2: y*e[1]
+by graded submodule of F with 3 generators
+ 1: x^2*e[1]
+ 2: y^3*e[1]
+ 3: z^4*e[1]
julia> N = M;
julia> V = [y^2*N[1], x^2*N[2]];
julia> a = hom(M, N, V)
-M -> M
-x*e[1] -> x*y^2*e[1]
-y*e[1] -> x^2*y*e[1]
Graded module homomorphism of degree [2]
+ from M
+ to M
+defined by
+ x*e[1] -> x*y^2*e[1]
+ y*e[1] -> x^2*y*e[1]
julia> is_welldefined(a)
true
@@ -244,10 +231,12 @@ julia> W = Rg[y^2 0; 0 x^2]
[ 0 x^2]
julia> b = hom(M, N, W)
-M -> M
-x*e[1] -> x*y^2*e[1]
-y*e[1] -> x^2*y*e[1]
Graded module homomorphism of degree [2]
+ from M
+ to M
+defined by
+ x*e[1] -> x*y^2*e[1]
+ y*e[1] -> x^2*y*e[1]
julia> a == b
true
@@ -258,10 +247,12 @@ julia> W = [y*N[1], x*N[2]]
x*y*e[1]
julia> c = hom(M, N, W)
-M -> M
-x*e[1] -> x*y*e[1]
-y*e[1] -> x*y*e[1]
Graded module homomorphism of degree [1]
+ from M
+ to M
+defined by
+ x*e[1] -> x*y*e[1]
+ y*e[1] -> x*y*e[1]
julia> is_welldefined(c)
false
@@ -395,13 +386,13 @@ julia> B = R[x^2; y^3; z^4]
[z^4]
julia> M = SubquoModule(F, A, B)
-Subquotient of Submodule with 2 generators
-1 -> x*e[1]
-2 -> y*e[1]
-by Submodule with 3 generators
-1 -> x^2*e[1]
-2 -> y^3*e[1]
-3 -> z^4*e[1]
+Subquotient of submodule with 2 generators
+ 1: x*e[1]
+ 2: y*e[1]
+by submodule with 3 generators
+ 1: x^2*e[1]
+ 2: y^3*e[1]
+ 3: z^4*e[1]
julia> N = M;
@@ -427,23 +418,25 @@ julia> A = Rg[x; y];
julia> B = Rg[x^2; y^3; z^4];
julia> M = SubquoModule(F, A, B)
-Graded subquotient of submodule of F generated by
-1 -> x*e[1]
-2 -> y*e[1]
-by submodule of F generated by
-1 -> x^2*e[1]
-2 -> y^3*e[1]
-3 -> z^4*e[1]
+Graded subquotient of graded submodule of F with 2 generators
+ 1: x*e[1]
+ 2: y*e[1]
+by graded submodule of F with 3 generators
+ 1: x^2*e[1]
+ 2: y^3*e[1]
+ 3: z^4*e[1]
julia> N = M;
julia> V = [y^2*N[1], x^2*N[2]];
julia> a = hom(M, N, V)
-M -> M
-x*e[1] -> x*y^2*e[1]
-y*e[1] -> x^2*y*e[1]
Graded module homomorphism of degree [2]
+ from M
+ to M
+defined by
+ x*e[1] -> x*y^2*e[1]
+ y*e[1] -> x^2*y*e[1]
julia> matrix(a)
[y^2 0]
@@ -586,23 +579,15 @@ julia> I, incl = image(a);
julia> I
Submodule with 3 generators
-1 -> y*e[1]
-2 -> x*e[1] + y*e[2]
-3 -> z*e[2]
-represented as subquotient with no relations.
+ 1: y*e[1]
+ 2: x*e[1] + y*e[2]
+ 3: z*e[2]
+represented as subquotient with no relations
julia> incl
-Map with following data
-Domain:
-=======
-Submodule with 3 generators
-1 -> y*e[1]
-2 -> x*e[1] + y*e[2]
-3 -> z*e[2]
-represented as subquotient with no relations.
-Codomain:
-=========
-Free module of rank 2 over R
+Module homomorphism
+ from I
+ to G
```
```jldoctest
@@ -620,13 +605,13 @@ julia> B = R[x^2; y^3; z^4]
[z^4]
julia> M = SubquoModule(F, A, B)
-Subquotient of Submodule with 2 generators
-1 -> x*e[1]
-2 -> y*e[1]
-by Submodule with 3 generators
-1 -> x^2*e[1]
-2 -> y^3*e[1]
-3 -> z^4*e[1]
+Subquotient of submodule with 2 generators
+ 1: x*e[1]
+ 2: y*e[1]
+by submodule with 3 generators
+ 1: x^2*e[1]
+ 2: y^3*e[1]
+ 3: z^4*e[1]
julia> N = M;
@@ -640,34 +625,18 @@ julia> a = hom(M, N, V);
julia> I, incl = image(a);
julia> I
-Subquotient of Submodule with 2 generators
-1 -> x*y^2*e[1]
-2 -> x*y*e[1]
-by Submodule with 3 generators
-1 -> x^2*e[1]
-2 -> y^3*e[1]
-3 -> z^4*e[1]
+Subquotient of submodule with 2 generators
+ 1: x*y^2*e[1]
+ 2: x*y*e[1]
+by submodule with 3 generators
+ 1: x^2*e[1]
+ 2: y^3*e[1]
+ 3: z^4*e[1]
julia> incl
-Map with following data
-Domain:
-=======
-Subquotient of Submodule with 2 generators
-1 -> x*y^2*e[1]
-2 -> x*y*e[1]
-by Submodule with 3 generators
-1 -> x^2*e[1]
-2 -> y^3*e[1]
-3 -> z^4*e[1]
-Codomain:
-=========
-Subquotient of Submodule with 2 generators
-1 -> x*e[1]
-2 -> y*e[1]
-by Submodule with 3 generators
-1 -> x^2*e[1]
-2 -> y^3*e[1]
-3 -> z^4*e[1]
+Module homomorphism
+ from I
+ to M
```
```jldoctest
@@ -680,41 +649,40 @@ julia> A = Rg[x; y];
julia> B = Rg[x^2; y^3; z^4];
julia> M = SubquoModule(F, A, B)
-Graded subquotient of submodule of F generated by
-1 -> x*e[1]
-2 -> y*e[1]
-by submodule of F generated by
-1 -> x^2*e[1]
-2 -> y^3*e[1]
-3 -> z^4*e[1]
+Graded subquotient of graded submodule of F with 2 generators
+ 1: x*e[1]
+ 2: y*e[1]
+by graded submodule of F with 3 generators
+ 1: x^2*e[1]
+ 2: y^3*e[1]
+ 3: z^4*e[1]
julia> N = M;
julia> V = [y^2*N[1], x^2*N[2]];
julia> a = hom(M, N, V)
-M -> M
-x*e[1] -> x*y^2*e[1]
-y*e[1] -> x^2*y*e[1]
Graded module homomorphism of degree [2]
+ from M
+ to M
+defined by
+ x*e[1] -> x*y^2*e[1]
+ y*e[1] -> x^2*y*e[1]
julia> image(a)
-(Graded subquotient of submodule of F generated by
-1 -> x*y^2*e[1]
-2 -> x^2*y*e[1]
-by submodule of F generated by
-1 -> x^2*e[1]
-2 -> y^3*e[1]
-3 -> z^4*e[1], Graded subquotient of submodule of F generated by
-1 -> x*y^2*e[1]
-2 -> x^2*y*e[1]
-by submodule of F generated by
-1 -> x^2*e[1]
-2 -> y^3*e[1]
-3 -> z^4*e[1] -> M
-x*y^2*e[1] -> x*y^2*e[1]
-x^2*y*e[1] -> x^2*y*e[1]
-Homogeneous module homomorphism)
+(Graded subquotient of graded submodule of F with 2 generators
+ 1: x*y^2*e[1]
+ 2: x^2*y*e[1]
+by graded submodule of F with 3 generators
+ 1: x^2*e[1]
+ 2: y^3*e[1]
+ 3: z^4*e[1], Hom: graded subquotient of graded submodule of F with 2 generators
+ 1: x*y^2*e[1]
+ 2: x^2*y*e[1]
+by graded submodule of F with 3 generators
+ 1: x^2*e[1]
+ 2: y^3*e[1]
+ 3: z^4*e[1] -> M)
```
"""
function image(a::ModuleFPHom)
@@ -768,19 +736,13 @@ julia> K, incl = kernel(a);
julia> K
Submodule with 1 generator
-1 -> x*z*e[1] - y*z*e[2] + y^2*e[3]
-represented as subquotient with no relations.
+ 1: x*z*e[1] - y*z*e[2] + y^2*e[3]
+represented as subquotient with no relations
julia> incl
-Map with following data
-Domain:
-=======
-Submodule with 1 generator
-1 -> x*z*e[1] - y*z*e[2] + y^2*e[3]
-represented as subquotient with no relations.
-Codomain:
-=========
-Free module of rank 3 over R
+Module homomorphism
+ from K
+ to F
```
```jldoctest
@@ -798,13 +760,13 @@ julia> B = R[x^2; y^3; z^4]
[z^4]
julia> M = SubquoModule(F, A, B)
-Subquotient of Submodule with 2 generators
-1 -> x*e[1]
-2 -> y*e[1]
-by Submodule with 3 generators
-1 -> x^2*e[1]
-2 -> y^3*e[1]
-3 -> z^4*e[1]
+Subquotient of submodule with 2 generators
+ 1: x*e[1]
+ 2: y*e[1]
+by submodule with 3 generators
+ 1: x^2*e[1]
+ 2: y^3*e[1]
+ 3: z^4*e[1]
julia> N = M;
@@ -818,36 +780,19 @@ julia> a = hom(M, N, V);
julia> K, incl = kernel(a);
julia> K
-Subquotient of Submodule with 3 generators
-1 -> (-x + y^2)*e[1]
-2 -> x*y*e[1]
-3 -> -x*y*e[1]
-by Submodule with 3 generators
-1 -> x^2*e[1]
-2 -> y^3*e[1]
-3 -> z^4*e[1]
+Subquotient of submodule with 3 generators
+ 1: (-x + y^2)*e[1]
+ 2: x*y*e[1]
+ 3: -x*y*e[1]
+by submodule with 3 generators
+ 1: x^2*e[1]
+ 2: y^3*e[1]
+ 3: z^4*e[1]
julia> incl
-Map with following data
-Domain:
-=======
-Subquotient of Submodule with 3 generators
-1 -> (-x + y^2)*e[1]
-2 -> x*y*e[1]
-3 -> -x*y*e[1]
-by Submodule with 3 generators
-1 -> x^2*e[1]
-2 -> y^3*e[1]
-3 -> z^4*e[1]
-Codomain:
-=========
-Subquotient of Submodule with 2 generators
-1 -> x*e[1]
-2 -> y*e[1]
-by Submodule with 3 generators
-1 -> x^2*e[1]
-2 -> y^3*e[1]
-3 -> z^4*e[1]
+Module homomorphism
+ from K
+ to M
```
```jldoctest
@@ -860,41 +805,40 @@ julia> A = Rg[x; y];
julia> B = Rg[x^2; y^3; z^4];
julia> M = SubquoModule(F, A, B)
-Graded subquotient of submodule of F generated by
-1 -> x*e[1]
-2 -> y*e[1]
-by submodule of F generated by
-1 -> x^2*e[1]
-2 -> y^3*e[1]
-3 -> z^4*e[1]
+Graded subquotient of graded submodule of F with 2 generators
+ 1: x*e[1]
+ 2: y*e[1]
+by graded submodule of F with 3 generators
+ 1: x^2*e[1]
+ 2: y^3*e[1]
+ 3: z^4*e[1]
julia> N = M;
julia> V = [y^2*N[1], x^2*N[2]];
julia> a = hom(M, N, V)
-M -> M
-x*e[1] -> x*y^2*e[1]
-y*e[1] -> x^2*y*e[1]
Graded module homomorphism of degree [2]
+ from M
+ to M
+defined by
+ x*e[1] -> x*y^2*e[1]
+ y*e[1] -> x^2*y*e[1]
julia> kernel(a)
-(Graded subquotient of submodule of F generated by
-1 -> y*e[1]
-2 -> -x*y*e[1]
-by submodule of F generated by
-1 -> x^2*e[1]
-2 -> y^3*e[1]
-3 -> z^4*e[1], Graded subquotient of submodule of F generated by
-1 -> y*e[1]
-2 -> -x*y*e[1]
-by submodule of F generated by
-1 -> x^2*e[1]
-2 -> y^3*e[1]
-3 -> z^4*e[1] -> M
-y*e[1] -> y*e[1]
--x*y*e[1] -> -x*y*e[1]
-Homogeneous module homomorphism)
+(Graded subquotient of graded submodule of F with 2 generators
+ 1: y*e[1]
+ 2: -x*y*e[1]
+by graded submodule of F with 3 generators
+ 1: x^2*e[1]
+ 2: y^3*e[1]
+ 3: z^4*e[1], Hom: graded subquotient of graded submodule of F with 2 generators
+ 1: y*e[1]
+ 2: -x*y*e[1]
+by graded submodule of F with 3 generators
+ 1: x^2*e[1]
+ 2: y^3*e[1]
+ 3: z^4*e[1] -> M)
```
"""
diff --git a/src/Modules/UngradedModules/SubquoModule.jl b/src/Modules/UngradedModules/SubquoModule.jl
index f644aeabe8bc..f0162b03c11d 100644
--- a/src/Modules/UngradedModules/SubquoModule.jl
+++ b/src/Modules/UngradedModules/SubquoModule.jl
@@ -51,9 +51,9 @@ julia> O = [x*F[1]+F[2],y*F[2]]
julia> M = SubquoModule(F, O)
Submodule with 2 generators
-1 -> x*e[1] + e[2]
-2 -> y*e[2]
-represented as subquotient with no relations.
+ 1: x*e[1] + e[2]
+ 2: y*e[2]
+represented as subquotient with no relations
```
"""
@@ -134,14 +134,14 @@ julia> B = R[x^2; x*y; y^2; z^4]
[z^4]
julia> M = SubquoModule(A, B)
-Subquotient of Submodule with 2 generators
-1 -> x*e[1]
-2 -> y*e[1]
-by Submodule with 4 generators
-1 -> x^2*e[1]
-2 -> x*y*e[1]
-3 -> y^2*e[1]
-4 -> z^4*e[1]
+Subquotient of submodule with 2 generators
+ 1: x*e[1]
+ 2: y*e[1]
+by submodule with 4 generators
+ 1: x^2*e[1]
+ 2: x*y*e[1]
+ 3: y^2*e[1]
+ 4: z^4*e[1]
```
"""
function SubquoModule(A::MatElem{R}, B::MatElem{R}) where {R}
@@ -199,13 +199,13 @@ julia> BR = R[x^2; y^3; z^4]
[z^4]
julia> MR = SubquoModule(FR, AR, BR)
-Subquotient of Submodule with 2 generators
-1 -> x*e[1]
-2 -> y*e[1]
-by Submodule with 3 generators
-1 -> x^2*e[1]
-2 -> y^3*e[1]
-3 -> z^4*e[1]
+Subquotient of submodule with 2 generators
+ 1: x*e[1]
+ 2: y*e[1]
+by submodule with 3 generators
+ 1: x^2*e[1]
+ 2: y^3*e[1]
+ 3: z^4*e[1]
julia> P = ideal(R, [x, y, z]);
@@ -214,7 +214,7 @@ julia> U = complement_of_prime_ideal(P);
julia> RL, _ = localization(R, U);
julia> FRL = free_module(RL, 1)
-Free module of rank 1 over Localization of R at complement of prime ideal (x, y, z)
+Free module of rank 1 over localization of R at complement of prime ideal (x, y, z)
julia> ARL = RL[x; y]
[x]
@@ -226,13 +226,13 @@ julia> BRL = RL[x^2; y^3; z^4]
[z^4]
julia> MRL = SubquoModule(FRL, ARL, BRL)
-Subquotient of Submodule with 2 generators
-1 -> x*e[1]
-2 -> y*e[1]
-by Submodule with 3 generators
-1 -> x^2*e[1]
-2 -> y^3*e[1]
-3 -> z^4*e[1]
+Subquotient of submodule with 2 generators
+ 1: x*e[1]
+ 2: y*e[1]
+by submodule with 3 generators
+ 1: x^2*e[1]
+ 2: y^3*e[1]
+ 3: z^4*e[1]
julia> RQ, _ = quo(R, ideal(R, [2*x^2-y^3, 2*x^2-y^5]));
@@ -249,18 +249,18 @@ julia> BRQ = RQ[x^2; y^3; z^4]
[z^4]
julia> MRQ = SubquoModule(FRQ, ARQ, BRQ)
-Subquotient of Submodule with 2 generators
-1 -> x*e[1]
-2 -> y*e[1]
-by Submodule with 3 generators
-1 -> x^2*e[1]
-2 -> 2*x^2*e[1]
-3 -> z^4*e[1]
+Subquotient of submodule with 2 generators
+ 1: x*e[1]
+ 2: y*e[1]
+by submodule with 3 generators
+ 1: x^2*e[1]
+ 2: 2*x^2*e[1]
+ 3: z^4*e[1]
julia> RQL, _ = localization(RQ, U);
julia> FRQL = free_module(RQL, 1)
-Free module of rank 1 over Localization of RQ at complement of prime ideal
+Free module of rank 1 over localization of RQ at complement of prime ideal
julia> ARQL = RQL[x; y]
[x]
@@ -272,13 +272,13 @@ julia> BRQL = RQL[x^2; y^3; z^4]
[z^4]
julia> MRQL = SubquoModule(FRQL, ARQL, BRQL)
-Subquotient of Submodule with 2 generators
-1 -> x*e[1]
-2 -> y*e[1]
-by Submodule with 3 generators
-1 -> 0
-2 -> 0
-3 -> z^4*e[1]
+Subquotient of submodule with 2 generators
+ 1: x*e[1]
+ 2: y*e[1]
+by submodule with 3 generators
+ 1: 0
+ 2: 0
+ 3: z^4*e[1]
```
```jldoctest
@@ -301,24 +301,28 @@ julia> V2 = [z*G[2]+y*G[1]]
y*e[1] + z*e[2]
julia> a1 = hom(F1, G, V1)
-F1 -> G
-e[1] -> y*e[1]
-e[2] -> (x + y)*e[1] + y*e[2]
-e[3] -> z*e[2]
Homogeneous module homomorphism
+ from F1
+ to G
+defined by
+ e[1] -> y*e[1]
+ e[2] -> (x + y)*e[1] + y*e[2]
+ e[3] -> z*e[2]
julia> a2 = hom(F2, G, V2)
-F2 -> G
-e[1] -> y*e[1] + z*e[2]
Homogeneous module homomorphism
+ from F2
+ to G
+defined by
+ e[1] -> y*e[1] + z*e[2]
julia> V = subquotient(a1,a2)
-Graded subquotient of submodule of G generated by
-1 -> y*e[1]
-2 -> (x + y)*e[1] + y*e[2]
-3 -> z*e[2]
-by submodule of G generated by
-1 -> y*e[1] + z*e[2]
+Graded subquotient of graded submodule of G with 3 generators
+ 1: y*e[1]
+ 2: (x + y)*e[1] + y*e[2]
+ 3: z*e[2]
+by graded submodule of G with 1 generator
+ 1: y*e[1] + z*e[2]
julia> A1 = Rg[x y; 2*x^2 3*y^2]
[ x y]
@@ -335,11 +339,11 @@ julia> F2 = graded_free_module(Rg,[0,0])
Graded free module Rg^2([0]) of rank 2 over Rg
julia> M1 = SubquoModule(F2, A1, B)
-Graded subquotient of submodule of F2 generated by
-1 -> x*e[1] + y*e[2]
-2 -> 2*x^2*e[1] + 3*y^2*e[2]
-by submodule of F2 generated by
-1 -> 4*x*y^3*e[1] + (16*x^4 + 32*x^3*y + 24*x^2*y^2 + 8*x*y^3 + y^4)*e[2]
+Graded subquotient of graded submodule of F2 with 2 generators
+ 1: x*e[1] + y*e[2]
+ 2: 2*x^2*e[1] + 3*y^2*e[2]
+by graded submodule of F2 with 1 generator
+ 1: 4*x*y^3*e[1] + (16*x^4 + 32*x^3*y + 24*x^2*y^2 + 8*x*y^3 + y^4)*e[2]
```
"""
function subquotient(a::FreeModuleHom, b::FreeModuleHom)
@@ -356,32 +360,34 @@ subquotient(A::MatElem{T}, B::MatElem{T}) where {T} = SubquoModule(A, B)
function show(io::IO, SQ::SubquoModule)
@show_name(io, SQ)
@show_special(io, SQ)
- io_compact = IOContext(io, :compact => true)
+ io = pretty(io)
if is_graded(SQ)
+ io_compact = IOContext(io, :compact => true)
if isdefined(SQ, :quo) && !iszero(SQ.quo)
print(io, "Graded subquotient")
- print(io_compact, " of submodule of ", SQ.F, " generated by", SQ.sub, "\nby submodule of ", SQ.F, " generated by", SQ.quo)
+ println(io_compact, " of ", Lowercase(), SQ.sub)
+ print(io_compact, "by ", Lowercase(), SQ.quo)
else
- print(io_compact, "Graded submodule of ", SQ.F)
- print(io_compact, SQ.sub, "\n")
+ println(io_compact, SQ.sub)
print(io, "represented as subquotient with no relations")
end
else
# Todo: Use again once the printing of rings is fixed
# if isdefined(SQ, :quo) && !iszero(SQ.quo)
# print(io, "Subquotient")
- # print(io_compact, " of submodule of ", SQ.F, " generated by", SQ.sub, "\nby submodule of ", SQ.F, " generated by", SQ.quo)
+ # print(io_compact, " of submodule of ", SQ.F, " generated by ", SQ.sub, "\nby submodule of ", SQ.F, " generated by", SQ.quo)
# else
# print(io_compact, "Submodule of ", SQ.F)
# print(io_compact, SQ.sub, "\n")
# print(io, "represented as subquotient with no relations")
# end
if isdefined(SQ, :quo) && !iszero(SQ.quo)
- print(io, "Subquotient of ", SQ.sub, "\nby ", SQ.quo)
+ println(io, "Subquotient of ", Lowercase(), SQ.sub)
+ print(io, "by ", Lowercase(), SQ.quo)
else
- print(io, SQ.sub, "\n")
- print(io, "represented as subquotient with no relations.")
+ println(io, SQ.sub)
+ print(io, "represented as subquotient with no relations")
end
end
end
@@ -394,7 +400,6 @@ Show `SQ` as a subquotient of *matrices* `A` and `B`.
function show_subquo(SQ::SubquoModule)
#@show_name(io, SQ)
#@show_special(io, SQ)
- io_compact = IOContext(stdout, :compact => true)
if isdefined(SQ, :quo)
if is_generated_by_standard_unit_vectors(SQ.sub)
if is_graded(SQ)
@@ -421,11 +426,11 @@ function show_subquo(SQ::SubquoModule)
end
show(stdout, "text/plain", generator_matrix(SQ.sub))
end
- print(io_compact, "\nwith ambient free module ", SQ.F)
+ print(terse(io), "\nwith ambient free module ", SQ.F)
end
function show_morphism_as_map(f::ModuleFPHom, print_non_zero_only = false)
- io_compact = IOContext(stdout, :compact => true)
+ io_compact = terse(stdout)
print(io_compact, domain(f), " -> ", codomain(f))
print("\n")
D = domain(f)
@@ -445,7 +450,7 @@ function show_morphism_as_map(f::ModuleFPHom, print_non_zero_only = false)
if degree(f)==A[0]
print("Homogeneous homomorphism")
else
- print(io_compact,"Graded homomorphism of degree ", degree(f))
+ print(io_compact, "Graded homomorphism of degree ", degree(f))
end
else
print("Homomorphism")
@@ -474,13 +479,13 @@ julia> W = R[y 0; x y; 0 z]
julia> a = hom(F, G, W);
julia> cokernel(a)
-Subquotient of Submodule with 2 generators
-1 -> e[1]
-2 -> e[2]
-by Submodule with 3 generators
-1 -> y*e[1]
-2 -> x*e[1] + y*e[2]
-3 -> z*e[2]
+Subquotient of submodule with 2 generators
+ 1: e[1]
+ 2: e[2]
+by submodule with 3 generators
+ 1: y*e[1]
+ 2: x*e[1] + y*e[2]
+ 3: z*e[2]
```
```jldoctest
@@ -498,13 +503,13 @@ julia> B = R[x^2; y^3; z^4]
[z^4]
julia> M = SubquoModule(F, A, B)
-Subquotient of Submodule with 2 generators
-1 -> x*e[1]
-2 -> y*e[1]
-by Submodule with 3 generators
-1 -> x^2*e[1]
-2 -> y^3*e[1]
-3 -> z^4*e[1]
+Subquotient of submodule with 2 generators
+ 1: x*e[1]
+ 2: y*e[1]
+by submodule with 3 generators
+ 1: x^2*e[1]
+ 2: y^3*e[1]
+ 3: z^4*e[1]
julia> N = M;
@@ -516,15 +521,15 @@ julia> V = [y^2*N[1], x*N[2]]
julia> a = hom(M, N, V);
julia> cokernel(a)
-Subquotient of Submodule with 2 generators
-1 -> x*e[1]
-2 -> y*e[1]
-by Submodule with 5 generators
-1 -> x^2*e[1]
-2 -> y^3*e[1]
-3 -> z^4*e[1]
-4 -> x*y^2*e[1]
-5 -> x*y*e[1]
+Subquotient of submodule with 2 generators
+ 1: x*e[1]
+ 2: y*e[1]
+by submodule with 5 generators
+ 1: x^2*e[1]
+ 2: y^3*e[1]
+ 3: z^4*e[1]
+ 4: x*y^2*e[1]
+ 5: x*y*e[1]
```
```jldoctest
@@ -540,20 +545,22 @@ julia> W = Rg[y 0; x y; 0 z]
[0 z]
julia> a = hom(F, G, W)
-F -> G
-e[1] -> y*e[1]
-e[2] -> x*e[1] + y*e[2]
-e[3] -> z*e[2]
Graded module homomorphism of degree [1]
+ from F
+ to G
+defined by
+ e[1] -> y*e[1]
+ e[2] -> x*e[1] + y*e[2]
+ e[3] -> z*e[2]
julia> M = cokernel(a)
-Graded subquotient of submodule of G generated by
-1 -> e[1]
-2 -> e[2]
-by submodule of G generated by
-1 -> y*e[1]
-2 -> x*e[1] + y*e[2]
-3 -> z*e[2]
+Graded subquotient of graded submodule of G with 2 generators
+ 1: e[1]
+ 2: e[2]
+by graded submodule of G with 3 generators
+ 1: y*e[1]
+ 2: x*e[1] + y*e[2]
+ 3: z*e[2]
```
"""
@@ -578,12 +585,12 @@ julia> A = R[x y; 2*x^2 3*y^2]
[2*x^2 3*y^2]
julia> M = cokernel(F, A)
-Subquotient of Submodule with 2 generators
-1 -> e[1]
-2 -> e[2]
-by Submodule with 2 generators
-1 -> x*e[1] + y*e[2]
-2 -> 2*x^2*e[1] + 3*y^2*e[2]
+Subquotient of submodule with 2 generators
+ 1: e[1]
+ 2: e[2]
+by submodule with 2 generators
+ 1: x*e[1] + y*e[2]
+ 2: 2*x^2*e[1] + 3*y^2*e[2]
julia> ambient_free_module(M) === F
true
@@ -601,12 +608,12 @@ julia> A = Rg[x y; 2*x^2 3*y^2]
[2*x^2 3*y^2]
julia> M = cokernel(F, A)
-Graded subquotient of submodule of F generated by
-1 -> e[1]
-2 -> e[2]
-by submodule of F generated by
-1 -> x*e[1] + y*e[2]
-2 -> 2*x^2*e[1] + 3*y^2*e[2]
+Graded subquotient of graded submodule of F with 2 generators
+ 1: e[1]
+ 2: e[2]
+by graded submodule of F with 2 generators
+ 1: x*e[1] + y*e[2]
+ 2: 2*x^2*e[1] + 3*y^2*e[2]
julia> ambient_free_module(M) === F
true
@@ -635,12 +642,12 @@ julia> A = R[x y; 2*x^2 3*y^2]
[2*x^2 3*y^2]
julia> M = cokernel(A)
-Subquotient of Submodule with 2 generators
-1 -> e[1]
-2 -> e[2]
-by Submodule with 2 generators
-1 -> x*e[1] + y*e[2]
-2 -> 2*x^2*e[1] + 3*y^2*e[2]
+Subquotient of submodule with 2 generators
+ 1: e[1]
+ 2: e[2]
+by submodule with 2 generators
+ 1: x*e[1] + y*e[2]
+ 2: 2*x^2*e[1] + 3*y^2*e[2]
```
"""
@@ -666,9 +673,9 @@ julia> A = R[x y; 2*x^2 3*y^2]
julia> M = image(F, A)
Submodule with 2 generators
-1 -> x*e[1] + y*e[2]
-2 -> 2*x^2*e[1] + 3*y^2*e[2]
-represented as subquotient with no relations.
+ 1: x*e[1] + y*e[2]
+ 2: 2*x^2*e[1] + 3*y^2*e[2]
+represented as subquotient with no relations
julia> ambient_free_module(M) === F
true
@@ -685,9 +692,9 @@ julia> A = Rg[x y; 2*x^2 3*y^2]
[2*x^2 3*y^2]
julia> M = image(F, A)
-Graded submodule of F
-1 -> x*e[1] + y*e[2]
-2 -> 2*x^2*e[1] + 3*y^2*e[2]
+Graded submodule of F with 2 generators
+ 1: x*e[1] + y*e[2]
+ 2: 2*x^2*e[1] + 3*y^2*e[2]
represented as subquotient with no relations
julia> ambient_free_module(M) === F
@@ -718,9 +725,9 @@ julia> A = R[x y; 2*x^2 3*y^2]
julia> M = image(A)
Submodule with 2 generators
-1 -> x*e[1] + y*e[2]
-2 -> 2*x^2*e[1] + 3*y^2*e[2]
-represented as subquotient with no relations.
+ 1: x*e[1] + y*e[2]
+ 2: 2*x^2*e[1] + 3*y^2*e[2]
+represented as subquotient with no relations
```
"""
function image(A::MatElem)
@@ -853,12 +860,12 @@ julia> BM = R[x^2; y^3; z^4]
[z^4]
julia> M = SubquoModule(F, AM, BM)
-Subquotient of Submodule with 1 generator
-1 -> x*e[1]
-by Submodule with 3 generators
-1 -> x^2*e[1]
-2 -> y^3*e[1]
-3 -> z^4*e[1]
+Subquotient of submodule with 1 generator
+ 1: x*e[1]
+by submodule with 3 generators
+ 1: x^2*e[1]
+ 2: y^3*e[1]
+ 3: z^4*e[1]
julia> AN = R[x; y]
[x]
@@ -870,13 +877,13 @@ julia> BN = R[x^2+y^4; y^3; z^4]
[ z^4]
julia> N = SubquoModule(F, AN, BN)
-Subquotient of Submodule with 2 generators
-1 -> x*e[1]
-2 -> y*e[1]
-by Submodule with 3 generators
-1 -> (x^2 + y^4)*e[1]
-2 -> y^3*e[1]
-3 -> z^4*e[1]
+Subquotient of submodule with 2 generators
+ 1: x*e[1]
+ 2: y*e[1]
+by submodule with 3 generators
+ 1: (x^2 + y^4)*e[1]
+ 2: y^3*e[1]
+ 3: z^4*e[1]
julia> is_subset(M, N)
true
@@ -894,20 +901,20 @@ julia> O1a = [x*F[1],y*F[2]];
julia> O2 = [x^2*F[1]+y^2*F[2],y^2*F[2]];
julia> M1 = SubquoModule(F, O1, O2)
-Graded subquotient of submodule of F generated by
-1 -> x*e[1] + y*e[2]
-2 -> y*e[2]
-by submodule of F generated by
-1 -> x^2*e[1] + y^2*e[2]
-2 -> y^2*e[2]
+Graded subquotient of graded submodule of F with 2 generators
+ 1: x*e[1] + y*e[2]
+ 2: y*e[2]
+by graded submodule of F with 2 generators
+ 1: x^2*e[1] + y^2*e[2]
+ 2: y^2*e[2]
julia> M2 = SubquoModule(F, O1a, O2)
-Graded subquotient of submodule of F generated by
-1 -> x*e[1]
-2 -> y*e[2]
-by submodule of F generated by
-1 -> x^2*e[1] + y^2*e[2]
-2 -> y^2*e[2]
+Graded subquotient of graded submodule of F with 2 generators
+ 1: x*e[1]
+ 2: y*e[2]
+by graded submodule of F with 2 generators
+ 1: x^2*e[1] + y^2*e[2]
+ 2: y^2*e[2]
julia> is_subset(M1,M2)
true
@@ -981,12 +988,12 @@ julia> BM = R[x^2; y^3; z^4]
[z^4]
julia> M = SubquoModule(F, AM, BM)
-Subquotient of Submodule with 1 generator
-1 -> x*e[1]
-by Submodule with 3 generators
-1 -> x^2*e[1]
-2 -> y^3*e[1]
-3 -> z^4*e[1]
+Subquotient of submodule with 1 generator
+ 1: x*e[1]
+by submodule with 3 generators
+ 1: x^2*e[1]
+ 2: y^3*e[1]
+ 3: z^4*e[1]
julia> AN = R[x; y]
[x]
@@ -998,13 +1005,13 @@ julia> BN = R[x^2+y^4; y^3; z^4]
[ z^4]
julia> N = SubquoModule(F, AN, BN)
-Subquotient of Submodule with 2 generators
-1 -> x*e[1]
-2 -> y*e[1]
-by Submodule with 3 generators
-1 -> (x^2 + y^4)*e[1]
-2 -> y^3*e[1]
-3 -> z^4*e[1]
+Subquotient of submodule with 2 generators
+ 1: x*e[1]
+ 2: y*e[1]
+by submodule with 3 generators
+ 1: (x^2 + y^4)*e[1]
+ 2: y^3*e[1]
+ 3: z^4*e[1]
julia> M == N
false
@@ -1022,20 +1029,20 @@ julia> O1a = [x*F[1],y*F[2]];
julia> O2 = [x^2*F[1]+y^2*F[2],y^2*F[2]];
julia> M1 = SubquoModule(F, O1, O2)
-Graded subquotient of submodule of F generated by
-1 -> x*e[1] + y*e[2]
-2 -> y*e[2]
-by submodule of F generated by
-1 -> x^2*e[1] + y^2*e[2]
-2 -> y^2*e[2]
+Graded subquotient of graded submodule of F with 2 generators
+ 1: x*e[1] + y*e[2]
+ 2: y*e[2]
+by graded submodule of F with 2 generators
+ 1: x^2*e[1] + y^2*e[2]
+ 2: y^2*e[2]
julia> M2 = SubquoModule(F, O1a, O2)
-Graded subquotient of submodule of F generated by
-1 -> x*e[1]
-2 -> y*e[2]
-by submodule of F generated by
-1 -> x^2*e[1] + y^2*e[2]
-2 -> y^2*e[2]
+Graded subquotient of graded submodule of F with 2 generators
+ 1: x*e[1]
+ 2: y*e[2]
+by graded submodule of F with 2 generators
+ 1: x^2*e[1] + y^2*e[2]
+ 2: y^2*e[2]
julia> M1 == M2
true
@@ -1063,9 +1070,9 @@ julia> A1 = Rg[x^3 x^2 x; (2*x^2+x*y)*x^2 (2*y^2+x^2)*x x^2]
[2*x^4 + x^3*y x^3 + 2*x*y^2 x^2]
julia> M1 = image(F1, A1)
-Graded submodule of F1
-1 -> x^3*e[1] + x^2*e[2] + x*e[3]
-2 -> (2*x^4 + x^3*y)*e[1] + (x^3 + 2*x*y^2)*e[2] + x^2*e[3]
+Graded submodule of F1 with 2 generators
+ 1: x^3*e[1] + x^2*e[2] + x*e[3]
+ 2: (2*x^4 + x^3*y)*e[1] + (x^3 + 2*x*y^2)*e[2] + x^2*e[3]
represented as subquotient with no relations
julia> F2 = graded_free_module(Rg,[2,4, 3])
@@ -1076,9 +1083,9 @@ julia> A2 = Rg[x^3 x x^2; (2*x^2+x*y)*x^2 x^2 (2*y^2+x^2)*x]
[2*x^4 + x^3*y x^2 x^3 + 2*x*y^2]
julia> M2 = image(F2, A2)
-Graded submodule of F2
-1 -> x^3*e[1] + x*e[2] + x^2*e[3]
-2 -> (2*x^4 + x^3*y)*e[1] + x^2*e[2] + (x^3 + 2*x*y^2)*e[3]
+Graded submodule of F2 with 2 generators
+ 1: x^3*e[1] + x*e[2] + x^2*e[3]
+ 2: (2*x^4 + x^3*y)*e[1] + x^2*e[2] + (x^3 + 2*x*y^2)*e[3]
represented as subquotient with no relations
julia> is_canonically_isomorphic(M1, M2)
@@ -1114,9 +1121,9 @@ julia> A1 = Rg[x^3 x^2 x; (2*x^2+x*y)*x^2 (2*y^2+x^2)*x x^2]
[2*x^4 + x^3*y x^3 + 2*x*y^2 x^2]
julia> M1 = image(F1, A1)
-Graded submodule of F1
-1 -> x^3*e[1] + x^2*e[2] + x*e[3]
-2 -> (2*x^4 + x^3*y)*e[1] + (x^3 + 2*x*y^2)*e[2] + x^2*e[3]
+Graded submodule of F1 with 2 generators
+ 1: x^3*e[1] + x^2*e[2] + x*e[3]
+ 2: (2*x^4 + x^3*y)*e[1] + (x^3 + 2*x*y^2)*e[2] + x^2*e[3]
represented as subquotient with no relations
julia> F2 = graded_free_module(Rg,[2,4, 3])
@@ -1127,16 +1134,13 @@ julia> A2 = Rg[x^3 x x^2; (2*x^2+x*y)*x^2 x^2 (2*y^2+x^2)*x]
[2*x^4 + x^3*y x^2 x^3 + 2*x*y^2]
julia> M2 = image(F2, A2)
-Graded submodule of F2
-1 -> x^3*e[1] + x*e[2] + x^2*e[3]
-2 -> (2*x^4 + x^3*y)*e[1] + x^2*e[2] + (x^3 + 2*x*y^2)*e[3]
+Graded submodule of F2 with 2 generators
+ 1: x^3*e[1] + x*e[2] + x^2*e[3]
+ 2: (2*x^4 + x^3*y)*e[1] + x^2*e[2] + (x^3 + 2*x*y^2)*e[3]
represented as subquotient with no relations
julia> is_canonically_isomorphic_with_map(M1, M2)
-(true, M1 -> M2
-x^3*e[1] + x^2*e[2] + x*e[3] -> x^3*e[1] + x*e[2] + x^2*e[3]
-(2*x^4 + x^3*y)*e[1] + (x^3 + 2*x*y^2)*e[2] + x^2*e[3] -> (2*x^4 + x^3*y)*e[1] + x^2*e[2] + (x^3 + 2*x*y^2)*e[3]
-Homogeneous module homomorphism)
+(true, Hom: M1 -> M2)
```
"""
@@ -1180,12 +1184,12 @@ julia> BM = R[x^2; y^3; z^4]
[z^4]
julia> M = SubquoModule(F, AM, BM)
-Subquotient of Submodule with 1 generator
-1 -> x*e[1]
-by Submodule with 3 generators
-1 -> x^2*e[1]
-2 -> y^3*e[1]
-3 -> z^4*e[1]
+Subquotient of submodule with 1 generator
+ 1: x*e[1]
+by submodule with 3 generators
+ 1: x^2*e[1]
+ 2: y^3*e[1]
+ 3: z^4*e[1]
julia> AN = R[y;]
[y]
@@ -1196,63 +1200,45 @@ julia> BN = R[x^2; y^3; z^4]
[z^4]
julia> N = SubquoModule(F, AN, BN)
-Subquotient of Submodule with 1 generator
-1 -> y*e[1]
-by Submodule with 3 generators
-1 -> x^2*e[1]
-2 -> y^3*e[1]
-3 -> z^4*e[1]
+Subquotient of submodule with 1 generator
+ 1: y*e[1]
+by submodule with 3 generators
+ 1: x^2*e[1]
+ 2: y^3*e[1]
+ 3: z^4*e[1]
julia> O = sum(M, N);
julia> O[1]
-Subquotient of Submodule with 2 generators
-1 -> x*e[1]
-2 -> y*e[1]
-by Submodule with 3 generators
-1 -> x^2*e[1]
-2 -> y^3*e[1]
-3 -> z^4*e[1]
+Subquotient of submodule with 2 generators
+ 1: x*e[1]
+ 2: y*e[1]
+by submodule with 3 generators
+ 1: x^2*e[1]
+ 2: y^3*e[1]
+ 3: z^4*e[1]
julia> O[2]
-Map with following data
-Domain:
-=======
-Subquotient of Submodule with 1 generator
-1 -> x*e[1]
-by Submodule with 3 generators
-1 -> x^2*e[1]
-2 -> y^3*e[1]
-3 -> z^4*e[1]
-Codomain:
-=========
-Subquotient of Submodule with 2 generators
-1 -> x*e[1]
-2 -> y*e[1]
-by Submodule with 3 generators
-1 -> x^2*e[1]
-2 -> y^3*e[1]
-3 -> z^4*e[1]
+Module homomorphism
+ from M
+ to subquotient of submodule with 2 generators
+ 1: x*e[1]
+ 2: y*e[1]
+ by submodule with 3 generators
+ 1: x^2*e[1]
+ 2: y^3*e[1]
+ 3: z^4*e[1]
julia> O[3]
-Map with following data
-Domain:
-=======
-Subquotient of Submodule with 1 generator
-1 -> y*e[1]
-by Submodule with 3 generators
-1 -> x^2*e[1]
-2 -> y^3*e[1]
-3 -> z^4*e[1]
-Codomain:
-=========
-Subquotient of Submodule with 2 generators
-1 -> x*e[1]
-2 -> y*e[1]
-by Submodule with 3 generators
-1 -> x^2*e[1]
-2 -> y^3*e[1]
-3 -> z^4*e[1]
+Module homomorphism
+ from N
+ to subquotient of submodule with 2 generators
+ 1: x*e[1]
+ 2: y*e[1]
+ by submodule with 3 generators
+ 1: x^2*e[1]
+ 2: y^3*e[1]
+ 3: z^4*e[1]
```
```jldoctest
@@ -1265,49 +1251,45 @@ julia> AM = Rg[x;];
julia> BM = Rg[x^2; y^3; z^4];
julia> M = SubquoModule(F, AM, BM)
-Graded subquotient of submodule of F generated by
-1 -> x*e[1]
-by submodule of F generated by
-1 -> x^2*e[1]
-2 -> y^3*e[1]
-3 -> z^4*e[1]
+Graded subquotient of graded submodule of F with 1 generator
+ 1: x*e[1]
+by graded submodule of F with 3 generators
+ 1: x^2*e[1]
+ 2: y^3*e[1]
+ 3: z^4*e[1]
julia> AN = Rg[y;];
julia> BN = Rg[x^2; y^3; z^4];
julia> N = SubquoModule(F, AN, BN)
-Graded subquotient of submodule of F generated by
-1 -> y*e[1]
-by submodule of F generated by
-1 -> x^2*e[1]
-2 -> y^3*e[1]
-3 -> z^4*e[1]
+Graded subquotient of graded submodule of F with 1 generator
+ 1: y*e[1]
+by graded submodule of F with 3 generators
+ 1: x^2*e[1]
+ 2: y^3*e[1]
+ 3: z^4*e[1]
julia> sum(M, N)
-(Graded subquotient of submodule of F generated by
-1 -> x*e[1]
-2 -> y*e[1]
-by submodule of F generated by
-1 -> x^2*e[1]
-2 -> y^3*e[1]
-3 -> z^4*e[1], M -> Graded subquotient of submodule of F generated by
-1 -> x*e[1]
-2 -> y*e[1]
-by submodule of F generated by
-1 -> x^2*e[1]
-2 -> y^3*e[1]
-3 -> z^4*e[1]
-x*e[1] -> x*e[1]
-Homogeneous module homomorphism, N -> Graded subquotient of submodule of F generated by
-1 -> x*e[1]
-2 -> y*e[1]
-by submodule of F generated by
-1 -> x^2*e[1]
-2 -> y^3*e[1]
-3 -> z^4*e[1]
-y*e[1] -> y*e[1]
-Homogeneous module homomorphism)
+(Graded subquotient of graded submodule of F with 2 generators
+ 1: x*e[1]
+ 2: y*e[1]
+by graded submodule of F with 3 generators
+ 1: x^2*e[1]
+ 2: y^3*e[1]
+ 3: z^4*e[1], Hom: M -> graded subquotient of graded submodule of F with 2 generators
+ 1: x*e[1]
+ 2: y*e[1]
+by graded submodule of F with 3 generators
+ 1: x^2*e[1]
+ 2: y^3*e[1]
+ 3: z^4*e[1], Hom: N -> graded subquotient of graded submodule of F with 2 generators
+ 1: x*e[1]
+ 2: y*e[1]
+by graded submodule of F with 3 generators
+ 1: x^2*e[1]
+ 2: y^3*e[1]
+ 3: z^4*e[1])
```
"""
@@ -1362,12 +1344,12 @@ julia> BM = R[x^2; y^3; z^4]
[z^4]
julia> M = SubquoModule(F, AM, BM)
-Subquotient of Submodule with 1 generator
-1 -> x*e[1]
-by Submodule with 3 generators
-1 -> x^2*e[1]
-2 -> y^3*e[1]
-3 -> z^4*e[1]
+Subquotient of submodule with 1 generator
+ 1: x*e[1]
+by submodule with 3 generators
+ 1: x^2*e[1]
+ 2: y^3*e[1]
+ 3: z^4*e[1]
julia> AN = R[y;]
[y]
@@ -1378,21 +1360,21 @@ julia> BN = R[x^2; y^3; z^4]
[z^4]
julia> N = SubquoModule(F, AN, BN)
-Subquotient of Submodule with 1 generator
-1 -> y*e[1]
-by Submodule with 3 generators
-1 -> x^2*e[1]
-2 -> y^3*e[1]
-3 -> z^4*e[1]
+Subquotient of submodule with 1 generator
+ 1: y*e[1]
+by submodule with 3 generators
+ 1: x^2*e[1]
+ 2: y^3*e[1]
+ 3: z^4*e[1]
julia> O = M + N
-Subquotient of Submodule with 2 generators
-1 -> x*e[1]
-2 -> y*e[1]
-by Submodule with 3 generators
-1 -> x^2*e[1]
-2 -> y^3*e[1]
-3 -> z^4*e[1]
+Subquotient of submodule with 2 generators
+ 1: x*e[1]
+ 2: y*e[1]
+by submodule with 3 generators
+ 1: x^2*e[1]
+ 2: y^3*e[1]
+ 3: z^4*e[1]
```
```jldoctest
@@ -1405,33 +1387,33 @@ julia> AM = Rg[x;];
julia> BM = Rg[x^2; y^3; z^4];
julia> M = SubquoModule(F, AM, BM)
-Graded subquotient of submodule of F generated by
-1 -> x*e[1]
-by submodule of F generated by
-1 -> x^2*e[1]
-2 -> y^3*e[1]
-3 -> z^4*e[1]
+Graded subquotient of graded submodule of F with 1 generator
+ 1: x*e[1]
+by graded submodule of F with 3 generators
+ 1: x^2*e[1]
+ 2: y^3*e[1]
+ 3: z^4*e[1]
julia> AN = Rg[y;];
julia> BN = Rg[x^2; y^3; z^4];
julia> N = SubquoModule(F, AN, BN)
-Graded subquotient of submodule of F generated by
-1 -> y*e[1]
-by submodule of F generated by
-1 -> x^2*e[1]
-2 -> y^3*e[1]
-3 -> z^4*e[1]
+Graded subquotient of graded submodule of F with 1 generator
+ 1: y*e[1]
+by graded submodule of F with 3 generators
+ 1: x^2*e[1]
+ 2: y^3*e[1]
+ 3: z^4*e[1]
julia> M + N
-Graded subquotient of submodule of F generated by
-1 -> x*e[1]
-2 -> y*e[1]
-by submodule of F generated by
-1 -> x^2*e[1]
-2 -> y^3*e[1]
-3 -> z^4*e[1]
+Graded subquotient of graded submodule of F with 2 generators
+ 1: x*e[1]
+ 2: y*e[1]
+by graded submodule of F with 3 generators
+ 1: x^2*e[1]
+ 2: y^3*e[1]
+ 3: z^4*e[1]
```
"""
@@ -1465,12 +1447,12 @@ julia> BM = R[x^2; y^3; z^4]
[z^4]
julia> M = SubquoModule(F, AM, BM)
-Subquotient of Submodule with 1 generator
-1 -> x*e[1]
-by Submodule with 3 generators
-1 -> x^2*e[1]
-2 -> y^3*e[1]
-3 -> z^4*e[1]
+Subquotient of submodule with 1 generator
+ 1: x*e[1]
+by submodule with 3 generators
+ 1: x^2*e[1]
+ 2: y^3*e[1]
+ 3: z^4*e[1]
julia> AN = R[y;]
[y]
@@ -1481,55 +1463,33 @@ julia> BN = R[x^2; y^3; z^4]
[z^4]
julia> N = SubquoModule(F, AN, BN)
-Subquotient of Submodule with 1 generator
-1 -> y*e[1]
-by Submodule with 3 generators
-1 -> x^2*e[1]
-2 -> y^3*e[1]
-3 -> z^4*e[1]
+Subquotient of submodule with 1 generator
+ 1: y*e[1]
+by submodule with 3 generators
+ 1: x^2*e[1]
+ 2: y^3*e[1]
+ 3: z^4*e[1]
julia> intersect(M, N)
-(Subquotient of Submodule with 2 generators
-1 -> -x*y*e[1]
-2 -> x*z^4*e[1]
-by Submodule with 3 generators
-1 -> x^2*e[1]
-2 -> y^3*e[1]
-3 -> z^4*e[1], Map with following data
-Domain:
-=======
-Subquotient of Submodule with 2 generators
-1 -> -x*y*e[1]
-2 -> x*z^4*e[1]
-by Submodule with 3 generators
-1 -> x^2*e[1]
-2 -> y^3*e[1]
-3 -> z^4*e[1]
-Codomain:
-=========
-Subquotient of Submodule with 1 generator
-1 -> x*e[1]
-by Submodule with 3 generators
-1 -> x^2*e[1]
-2 -> y^3*e[1]
-3 -> z^4*e[1], Map with following data
-Domain:
-=======
-Subquotient of Submodule with 2 generators
-1 -> -x*y*e[1]
-2 -> x*z^4*e[1]
-by Submodule with 3 generators
-1 -> x^2*e[1]
-2 -> y^3*e[1]
-3 -> z^4*e[1]
-Codomain:
-=========
-Subquotient of Submodule with 1 generator
-1 -> y*e[1]
-by Submodule with 3 generators
-1 -> x^2*e[1]
-2 -> y^3*e[1]
-3 -> z^4*e[1])
+(Subquotient of submodule with 2 generators
+ 1: -x*y*e[1]
+ 2: x*z^4*e[1]
+by submodule with 3 generators
+ 1: x^2*e[1]
+ 2: y^3*e[1]
+ 3: z^4*e[1], Hom: subquotient of submodule with 2 generators
+ 1: -x*y*e[1]
+ 2: x*z^4*e[1]
+by submodule with 3 generators
+ 1: x^2*e[1]
+ 2: y^3*e[1]
+ 3: z^4*e[1] -> M, Hom: subquotient of submodule with 2 generators
+ 1: -x*y*e[1]
+ 2: x*z^4*e[1]
+by submodule with 3 generators
+ 1: x^2*e[1]
+ 2: y^3*e[1]
+ 3: z^4*e[1] -> N)
```
```jldoctest
@@ -1542,51 +1502,45 @@ julia> AM = Rg[x;];
julia> BM = Rg[x^2; y^3; z^4];
julia> M = SubquoModule(F, AM, BM)
-Graded subquotient of submodule of F generated by
-1 -> x*e[1]
-by submodule of F generated by
-1 -> x^2*e[1]
-2 -> y^3*e[1]
-3 -> z^4*e[1]
+Graded subquotient of graded submodule of F with 1 generator
+ 1: x*e[1]
+by graded submodule of F with 3 generators
+ 1: x^2*e[1]
+ 2: y^3*e[1]
+ 3: z^4*e[1]
julia> AN = Rg[y;];
julia> BN = Rg[x^2; y^3; z^4];
julia> N = SubquoModule(F, AN, BN)
-Graded subquotient of submodule of F generated by
-1 -> y*e[1]
-by submodule of F generated by
-1 -> x^2*e[1]
-2 -> y^3*e[1]
-3 -> z^4*e[1]
+Graded subquotient of graded submodule of F with 1 generator
+ 1: y*e[1]
+by graded submodule of F with 3 generators
+ 1: x^2*e[1]
+ 2: y^3*e[1]
+ 3: z^4*e[1]
julia> intersect(M, N)
-(Graded subquotient of submodule of F generated by
-1 -> -x*y*e[1]
-2 -> x*z^4*e[1]
-by submodule of F generated by
-1 -> x^2*e[1]
-2 -> y^3*e[1]
-3 -> z^4*e[1], Graded subquotient of submodule of F generated by
-1 -> -x*y*e[1]
-2 -> x*z^4*e[1]
-by submodule of F generated by
-1 -> x^2*e[1]
-2 -> y^3*e[1]
-3 -> z^4*e[1] -> M
--x*y*e[1] -> -x*y*e[1]
-x*z^4*e[1] -> x*z^4*e[1]
-Homogeneous module homomorphism, Graded subquotient of submodule of F generated by
-1 -> -x*y*e[1]
-2 -> x*z^4*e[1]
-by submodule of F generated by
-1 -> x^2*e[1]
-2 -> y^3*e[1]
-3 -> z^4*e[1] -> N
--x*y*e[1] -> x*y*e[1]
-x*z^4*e[1] -> 0
-Homogeneous module homomorphism)
+(Graded subquotient of graded submodule of F with 2 generators
+ 1: -x*y*e[1]
+ 2: x*z^4*e[1]
+by graded submodule of F with 3 generators
+ 1: x^2*e[1]
+ 2: y^3*e[1]
+ 3: z^4*e[1], Hom: graded subquotient of graded submodule of F with 2 generators
+ 1: -x*y*e[1]
+ 2: x*z^4*e[1]
+by graded submodule of F with 3 generators
+ 1: x^2*e[1]
+ 2: y^3*e[1]
+ 3: z^4*e[1] -> M, Hom: graded subquotient of graded submodule of F with 2 generators
+ 1: -x*y*e[1]
+ 2: x*z^4*e[1]
+by graded submodule of F with 3 generators
+ 1: x^2*e[1]
+ 2: y^3*e[1]
+ 3: z^4*e[1] -> N)
```
"""
@@ -1648,12 +1602,12 @@ julia> AN = R[y;];
julia> BN = R[x^2; y^3; z^4];
julia> N = SubquoModule(F, AN, BN)
-Subquotient of Submodule with 1 generator
-1 -> y*e[1]
-by Submodule with 3 generators
-1 -> x^2*e[1]
-2 -> y^3*e[1]
-3 -> z^4*e[1]
+Subquotient of submodule with 1 generator
+ 1: y*e[1]
+by submodule with 3 generators
+ 1: x^2*e[1]
+ 2: y^3*e[1]
+ 3: z^4*e[1]
julia> J = annihilator(N)
Ideal generated by
@@ -1663,7 +1617,7 @@ Ideal generated by
```
-```
+```jldoctest
julia> S, (x, y, z) = polynomial_ring(QQ, [:x, :y, :z]);
julia> I = ideal(S, [x*y*z])
@@ -1680,12 +1634,12 @@ julia> AN = R[y;];
julia> BN = R[x^2; y^3; z^4];
julia> N = SubquoModule(F, AN, BN)
-Subquotient of Submodule with 1 generator
-1 -> y*e[1]
-by Submodule with 3 generators
-1 -> x^2*e[1]
-2 -> y^3*e[1]
-3 -> z^4*e[1]
+Subquotient of submodule with 1 generator
+ 1: y*e[1]
+by submodule with 3 generators
+ 1: x^2*e[1]
+ 2: y^3*e[1]
+ 3: z^4*e[1]
julia> J = annihilator(N)
Ideal generated by
@@ -1693,7 +1647,6 @@ Ideal generated by
y^2
x^2
z^4
-
```
"""
function annihilator(M::SubquoModule{T}) where T
@@ -1743,22 +1696,22 @@ julia> B = R[x^2; y^3; z^4];
julia> AM = R[x;];
julia> M = SubquoModule(F, AM, B)
-Graded subquotient of submodule of F generated by
-1 -> x*e[1]
-by submodule of F generated by
-1 -> x^2*e[1]
-2 -> y^3*e[1]
-3 -> z^4*e[1]
+Graded subquotient of graded submodule of F with 1 generator
+ 1: x*e[1]
+by graded submodule of F with 3 generators
+ 1: x^2*e[1]
+ 2: y^3*e[1]
+ 3: z^4*e[1]
julia> AN = R[y;];
julia> N = SubquoModule(F, AN, B)
-Graded subquotient of submodule of F generated by
-1 -> y*e[1]
-by submodule of F generated by
-1 -> x^2*e[1]
-2 -> y^3*e[1]
-3 -> z^4*e[1]
+Graded subquotient of graded submodule of F with 1 generator
+ 1: y*e[1]
+by graded submodule of F with 3 generators
+ 1: x^2*e[1]
+ 2: y^3*e[1]
+ 3: z^4*e[1]
julia> L = quotient(M, N)
Ideal generated by
@@ -1778,8 +1731,338 @@ end
(::Colon)(M::SubquoModule{T}, N::SubquoModule{T}) where T = quotient(M, N)
+@doc raw"""
+ quotient(M::SubquoModule, J::Ideal)
+
+Return the quotient of `M` by `J`.
+
+Alternatively, use `M:J`.
+
+!!! note
+ By definition, $M:J = \{a \in A \mid Ja \subset M\}$. Here, $A$ is the
+ ambient module of $M$.
+
+# Examples
+
+```jldoctest
+julia> R, (x, y, z) = polynomial_ring(QQ, [:x, :y, :z]);
+
+julia> F = free_module(R, 1);
+
+julia> AM = R[x;];
+
+julia> BM = R[x^2; y^3; z^4];
+
+julia> M = SubquoModule(F, AM, BM)
+Subquotient of submodule with 1 generator
+ 1: x*e[1]
+by submodule with 3 generators
+ 1: x^2*e[1]
+ 2: y^3*e[1]
+ 3: z^4*e[1]
+
+julia> J = ideal(R, [x, y, z])^2
+Ideal generated by
+ x^2
+ x*y
+ x*z
+ y^2
+ y*z
+ z^2
+
+julia> L = quotient(M, J)
+Subquotient of submodule with 3 generators
+ 1: x*e[1]
+ 2: y*z^3*e[1]
+ 3: y^2*z^2*e[1]
+by submodule with 3 generators
+ 1: x^2*e[1]
+ 2: y^3*e[1]
+ 3: z^4*e[1]
+
+julia> ambient_free_module(L) == ambient_free_module(M)
+true
+
+```
+
+```jldoctest
+julia> S, (x, y, z) = polynomial_ring(QQ, [:x, :y, :z]);
+
+julia> R, _ = quo(S, ideal(S, [x+y+z]));
+
+julia> F = free_module(R, 1);
+
+julia> AM = R[x;];
+
+julia> BM = R[x^2; y^3; z^4];
+
+julia> M = SubquoModule(F, AM, BM)
+Subquotient of submodule with 1 generator
+ 1: (-y - z)*e[1]
+by submodule with 3 generators
+ 1: (y^2 + 2*y*z + z^2)*e[1]
+ 2: y^3*e[1]
+ 3: z^4*e[1]
+
+julia> J = ideal(R, [x, y, z])^2
+Ideal generated by
+ x^2
+ x*y
+ x*z
+ y^2
+ y*z
+ z^2
+
+julia> quotient(M, J)
+Subquotient of submodule with 2 generators
+ 1: z*e[1]
+ 2: y*e[1]
+by submodule with 3 generators
+ 1: (y^2 + 2*y*z + z^2)*e[1]
+ 2: y^3*e[1]
+ 3: z^4*e[1]
+
+```
+"""
+function quotient(M::SubquoModule, J::Ideal)
+ @assert base_ring(M) == base_ring(J)
+ M_quo = isdefined(M, :quo) ? M.quo : SubModuleOfFreeModule(ambient_free_module(M), Vector{elem_type(ambient_free_module(M))}())
+ U = M.sub+M.quo
+ UF = _quotient(U, J)
+ res = SubquoModule(UF)
+ res.quo = M.quo
+ return simplify_light(res)[1]
+end
+
+(::Colon)(M::SubquoModule, J::Ideal) = quotient(M, N)
+
+function _quotient(U::SubModuleOfFreeModule, J::Ideal) ### TODO Replace by generic method
+ error("not implemented for the given types of modules.")
+end
+
+function _quotient(U::SubModuleOfFreeModule, J::Ideal{T}) where T <: Union{MPolyRingElem, MPolyQuoRingElem}
+ F = ambient_free_module(U)
+ SgU = singular_generators(U.gens)
+ SgJ = singular_generators(J.gens)
+ SQ = Singular.quotient(SgU, SgJ)
+ MG = ModuleGens(F, SQ)
+ return SubModuleOfFreeModule(F, MG)
+end
+
+########################################
+### saturation for modules
+########################################
+
+@doc raw"""
+ saturation(M::SubquoModule,
+ J::Ideal = ideal(base_ring(M), gens(base_ring(M)));
+ iteration::Bool = false)
+
+Return the saturation $M:J^{\infty}$ of `M` with respect to `J`.
+
+If the ideal `J` is not given, the ideal generated by the generators (variables) of `base_ring(M)` is used.
+
+Setting `iteration` to `true` only has an effect over rings of type `MPolyRing` or `MPolyQuoRing`. Over such rings,
+if `iteration` is set to `true`, the saturation is done by carrying out successive ideal quotient computations as
+suggested by the definition of saturation. Otherwise, a more sophisticated Gröbner basis approach is used which is typically
+faster. Applying the two approaches may lead to different generating sets of the saturation.
+
+!!! note
+ By definition,
+ $M:J^{\infty} = \{ a \in A \mid J^ka \subset M \text{ for some } k\geq 1 \} = \bigcup\limits_{k=1}^{\infty} (M:J^k).$
+ Here, $A$ is the ambient module of $M$.
+
+# Examples
+```jldoctest
+julia> R, (x, y, z) = polynomial_ring(QQ, [:x, :y, :z]);
+
+julia> F = free_module(R, 1);
+
+julia> AM = R[x;];
+
+julia> BM = R[x^2; y^3; z^4];
+
+julia> M = SubquoModule(F, AM, BM)
+Subquotient of submodule with 1 generator
+ 1: x*e[1]
+by submodule with 3 generators
+ 1: x^2*e[1]
+ 2: y^3*e[1]
+ 3: z^4*e[1]
+
+julia> J = ideal(R, [x, y, z])^2
+Ideal generated by
+ x^2
+ x*y
+ x*z
+ y^2
+ y*z
+ z^2
+
+julia> saturation(M, J)
+Subquotient of submodule with 1 generator
+ 1: e[1]
+by submodule with 3 generators
+ 1: x^2*e[1]
+ 2: y^3*e[1]
+ 3: z^4*e[1]
+
+```
+"""
+function saturation(M::SubquoModule, J::Ideal = ideal(base_ring(M), gens(base_ring(M))); iteration::Bool = false)
+ @assert base_ring(M) == base_ring(J)
+ M_quo = isdefined(M, :quo) ? M.quo : SubModuleOfFreeModule(ambient_free_module(M), Vector{elem_type(ambient_free_module(M))}())
+ U = M.sub+M.quo
+ UF = _saturation(U, J; iteration = iteration)
+ res = SubquoModule(UF)
+ res.quo = M.quo
+ return simplify_light(res)[1]
+end
+
+function _saturation(U::SubModuleOfFreeModule, J::Ideal) ### TODO Replace by generic method
+ error("not implemented for the given types of modules.")
+end
+
+function _saturation(U::SubModuleOfFreeModule, J::Ideal{T}; iteration::Bool = false) where T <: Union{MPolyRingElem, MPolyQuoRingElem}
+ F = ambient_free_module(U)
+ SgU = singular_generators(U.gens)
+ SgJ = singular_generators(J.gens)
+ SQ, _ = Singular.saturation(SgU, SgJ)
+ MG = ModuleGens(F, SQ)
+ return SubModuleOfFreeModule(F, MG)
+end
+
+@doc raw"""
+ saturation_with_index(M::SubquoModule,
+ J::MPolyIdeal = ideal(base_ring(M), gens(base_ring(M)));
+ iteration::Bool = false)
+
+
+Return the saturation $M:J^{\infty}$ of $M$ with respect to $J$ and the smallest integer $k$ such that $I:J^k = I:J^{\infty}$ (saturation index).
+
+If the ideal `J` is not given, the ideal generated by the generators (variables) of `base_ring(M)` is used.
+
+Setting `iteration` to `true` only has an effect over rings of type `MPolyRing` or `MPolyQuoRing`. Over such rings,
+if `iteration` is set to `true`, the saturation is done by carrying out successive module quotient computations as
+suggested by the definition of saturation. Otherwise, a more sophisticated Gröbner basis approach is used which is typically
+faster. Applying the two approaches may lead to different generating sets of the saturation.
+
+!!! note
+ By definition,
+ $M:J^{\infty} = \{ a \in A \mid J^ka \subset M \text{ for some } k\geq 1 \} = \bigcup\limits_{k=1}^{\infty} (M:J^k).$
+ Here, $A$ is the ambient module of $M$.
+
+# Examples
+```jldoctest
+julia> R, (x, y, z) = polynomial_ring(QQ, [:x, :y, :z]);
+
+julia> F = free_module(R, 1);
+
+julia> AM = R[x;];
+
+julia> BM = R[x^2; y^3; z^4];
+
+julia> M = SubquoModule(F, AM, BM)
+Subquotient of submodule with 1 generator
+ 1: x*e[1]
+by submodule with 3 generators
+ 1: x^2*e[1]
+ 2: y^3*e[1]
+ 3: z^4*e[1]
+
+julia> J = ideal(R, [x, y, z])^2
+Ideal generated by
+ x^2
+ x*y
+ x*z
+ y^2
+ y*z
+ z^2
+
+julia> L = saturation_with_index(M, J);
+
+julia> L[1]
+Subquotient of submodule with 1 generator
+ 1: e[1]
+by submodule with 3 generators
+ 1: x^2*e[1]
+ 2: y^3*e[1]
+ 3: z^4*e[1]
+
+julia> L[2]
+3
+
+```
+
+```jldoctest
+julia> S, (x, y, z) = polynomial_ring(QQ, [:x, :y, :z]);
+
+julia> R, _ = quo(S, ideal(S, [x+y+z]));
+
+julia> F = free_module(R, 1);
+
+julia> AM = R[x;];
+
+julia> BM = R[x^2; y^3; z^4];
+
+julia> M = SubquoModule(F, AM, BM)
+Subquotient of submodule with 1 generator
+ 1: (-y - z)*e[1]
+by submodule with 3 generators
+ 1: (y^2 + 2*y*z + z^2)*e[1]
+ 2: y^3*e[1]
+ 3: z^4*e[1]
+
+julia> J = ideal(R, [x, y, z])^2
+Ideal generated by
+ x^2
+ x*y
+ x*z
+ y^2
+ y*z
+ z^2
+
+julia> L = saturation_with_index(M, J);
+
+julia> L[1]
+Subquotient of submodule with 1 generator
+ 1: e[1]
+by submodule with 3 generators
+ 1: (y^2 + 2*y*z + z^2)*e[1]
+ 2: y^3*e[1]
+ 3: z^4*e[1]
+
+julia> L[2]
+2
+
+```
+"""
+function saturation_with_index(M::SubquoModule, J::Ideal = ideal(base_ring(M), gens(base_ring(M))); iteration::Bool = false)
+@assert base_ring(M) == base_ring(J)
+ M_quo = isdefined(M, :quo) ? M.quo : SubModuleOfFreeModule(ambient_free_module(M), Vector{elem_type(ambient_free_module(M))}())
+ U = M.sub+M.quo
+ UF, k = _saturation_with_index(U, J; iteration = iteration)
+ res = SubquoModule(UF)
+ res.quo = M.quo
+ return simplify_light(res)[1], k
+end
+
+function _saturation_with_index(U::SubModuleOfFreeModule, J::Ideal) ### TODO Replace by generic method
+ error("not implemented for the given types of modules.")
+end
+
+function _saturation_with_index(U::SubModuleOfFreeModule, J::Ideal{T}; iteration::Bool = false) where T <: Union{MPolyRingElem, MPolyQuoRingElem}
+ F = ambient_free_module(U)
+ SgU = singular_generators(U.gens)
+ SgJ = singular_generators(J.gens)
+ SQ, k = Singular.saturation(SgU, SgJ)
+ MG = ModuleGens(F, SQ)
+ return SubModuleOfFreeModule(F, MG), k
+end
+
########################################
+
@doc raw"""
represents_element(a::FreeModElem, SQ::SubquoModule)
@@ -1826,11 +2109,11 @@ julia> mat = matrix(QQ, [0 -1; 0 0]);
julia> U = image(mat)
Submodule with 1 generator
-1 -> -e[2]
-represented as subquotient with no relations.
+ 1: -e[2]
+represented as subquotient with no relations
julia> ambient_module(U)
-Free module of rank 2 over Rational field
+Free module of rank 2 over rational field
```
"""
function ambient_module(M::SubquoModule, task = :none)
diff --git a/src/Modules/UngradedModules/SubquoModuleElem.jl b/src/Modules/UngradedModules/SubquoModuleElem.jl
index d0256cf415a7..93dcd238f8a1 100644
--- a/src/Modules/UngradedModules/SubquoModuleElem.jl
+++ b/src/Modules/UngradedModules/SubquoModuleElem.jl
@@ -607,23 +607,15 @@ julia> N, incl = sub(F, V);
julia> N
Submodule with 3 generators
-1 -> x^2*e[1]
-2 -> y^3*e[1]
-3 -> z^4*e[1]
-represented as subquotient with no relations.
+ 1: x^2*e[1]
+ 2: y^3*e[1]
+ 3: z^4*e[1]
+represented as subquotient with no relations
julia> incl
-Map with following data
-Domain:
-=======
-Submodule with 3 generators
-1 -> x^2*e[1]
-2 -> y^3*e[1]
-3 -> z^4*e[1]
-represented as subquotient with no relations.
-Codomain:
-=========
-Free module of rank 1 over R
+Module homomorphism
+ from N
+ to F
```
"""
function sub(M::ModuleFP{T}, V::Vector{<:ModuleFPElem{T}}; cache_morphism::Bool=false) where T
@@ -810,26 +802,17 @@ julia> V = [x^2*F[1]; y^3*F[1]; z^4*F[1]];
julia> N, proj = quo(F, V);
julia> N
-Subquotient of Submodule with 1 generator
-1 -> e[1]
-by Submodule with 3 generators
-1 -> x^2*e[1]
-2 -> y^3*e[1]
-3 -> z^4*e[1]
+Subquotient of submodule with 1 generator
+ 1: e[1]
+by submodule with 3 generators
+ 1: x^2*e[1]
+ 2: y^3*e[1]
+ 3: z^4*e[1]
julia> proj
-Map with following data
-Domain:
-=======
-Free module of rank 1 over R
-Codomain:
-=========
-Subquotient of Submodule with 1 generator
-1 -> e[1]
-by Submodule with 3 generators
-1 -> x^2*e[1]
-2 -> y^3*e[1]
-3 -> z^4*e[1]
+Module homomorphism
+ from F
+ to N
```
"""
function quo(M::ModuleFP{T}, V::Vector{<:ModuleFPElem{T}}; cache_morphism::Bool=false) where T
@@ -994,12 +977,12 @@ julia> B = R[x^2; y^3; z^4]
[z^4]
julia> M = SubquoModule(F, A, B)
-Subquotient of Submodule with 1 generator
-1 -> (x^2 + y^2)*e[1]
-by Submodule with 3 generators
-1 -> x^2*e[1]
-2 -> y^3*e[1]
-3 -> z^4*e[1]
+Subquotient of submodule with 1 generator
+ 1: (x^2 + y^2)*e[1]
+by submodule with 3 generators
+ 1: x^2*e[1]
+ 2: y^3*e[1]
+ 3: z^4*e[1]
julia> is_zero(M)
false
@@ -1051,13 +1034,13 @@ julia> B = R[x^2; y^3; z^4]
[z^4]
julia> M = SubquoModule(F, A, B)
-Subquotient of Submodule with 2 generators
-1 -> x*e[1]
-2 -> y*e[1]
-by Submodule with 3 generators
-1 -> x^2*e[1]
-2 -> y^3*e[1]
-3 -> z^4*e[1]
+Subquotient of submodule with 2 generators
+ 1: x*e[1]
+ 2: y*e[1]
+by submodule with 3 generators
+ 1: x^2*e[1]
+ 2: y^3*e[1]
+ 3: z^4*e[1]
julia> is_zero(M[1])
false
@@ -1082,13 +1065,13 @@ julia> B = Rg[x^2; y^3; z^4]
[z^4]
julia> M = SubquoModule(F, A, B)
-Graded subquotient of submodule of F generated by
-1 -> x*e[1]
-2 -> y*e[1]
-by submodule of F generated by
-1 -> x^2*e[1]
-2 -> y^3*e[1]
-3 -> z^4*e[1]
+Graded subquotient of graded submodule of F with 2 generators
+ 1: x*e[1]
+ 2: y*e[1]
+by graded submodule of F with 3 generators
+ 1: x^2*e[1]
+ 2: y^3*e[1]
+ 3: z^4*e[1]
julia> is_zero(M[1])
false
diff --git a/src/Modules/homological-algebra.jl b/src/Modules/homological-algebra.jl
index 0610f5e49c22..e748b96c7add 100644
--- a/src/Modules/homological-algebra.jl
+++ b/src/Modules/homological-algebra.jl
@@ -31,14 +31,14 @@ julia> U = matrix([x^3-y^2 o; o x^3-y^2; -x^2 y; -y x])
[ -y x]
julia> M = quo_object(F,U)
-Subquotient of Submodule with 2 generators
-1 -> e[1]
-2 -> e[2]
-by Submodule with 4 generators
-1 -> (x^3 - y^2)*e[1]
-2 -> (x^3 - y^2)*e[2]
-3 -> -x^2*e[1] + y*e[2]
-4 -> -y*e[1] + x*e[2]
+Subquotient of submodule with 2 generators
+ 1: e[1]
+ 2: e[2]
+by submodule with 4 generators
+ 1: (x^3 - y^2)*e[1]
+ 2: (x^3 - y^2)*e[2]
+ 3: -x^2*e[1] + y*e[2]
+ 4: -y*e[1] + x*e[2]
julia> fitting_ideal(M, -1)
Ideal generated by
@@ -106,14 +106,14 @@ julia> U = matrix([x^3-y^2 o; o x^3-y^2; -x^2 y; -y x])
[ -y x]
julia> M = quo_object(F,U)
-Subquotient of Submodule with 2 generators
-1 -> e[1]
-2 -> e[2]
-by Submodule with 4 generators
-1 -> (x^3 - y^2)*e[1]
-2 -> (x^3 - y^2)*e[2]
-3 -> -x^2*e[1] + y*e[2]
-4 -> -y*e[1] + x*e[2]
+Subquotient of submodule with 2 generators
+ 1: e[1]
+ 2: e[2]
+by submodule with 4 generators
+ 1: (x^3 - y^2)*e[1]
+ 2: (x^3 - y^2)*e[2]
+ 3: -x^2*e[1] + y*e[2]
+ 4: -y*e[1] + x*e[2]
julia> is_flat(M)
false
@@ -163,14 +163,14 @@ julia> U = matrix([x^3-y^2 o; o x^3-y^2; -x^2 y; -y x])
[ -y x]
julia> M = quo_object(F,U)
-Subquotient of Submodule with 2 generators
-1 -> e[1]
-2 -> e[2]
-by Submodule with 4 generators
-1 -> (x^3 - y^2)*e[1]
-2 -> (x^3 - y^2)*e[2]
-3 -> -x^2*e[1] + y*e[2]
-4 -> -y*e[1] + x*e[2]
+Subquotient of submodule with 2 generators
+ 1: e[1]
+ 2: e[2]
+by submodule with 4 generators
+ 1: (x^3 - y^2)*e[1]
+ 2: (x^3 - y^2)*e[2]
+ 3: -x^2*e[1] + y*e[2]
+ 4: -y*e[1] + x*e[2]
julia> non_flat_locus(M)
Ideal generated by
@@ -295,27 +295,27 @@ julia> V = [x*y, x*z, y*z]
y*z
julia> koszul_homology(V, F, 0)
-Subquotient of Submodule with 1 generator
-1 -> e[1]^e[2]^e[3]
-by Submodule with 3 generators
-1 -> y*z*e[1]^e[2]^e[3]
-2 -> -x*z*e[1]^e[2]^e[3]
-3 -> x*y*e[1]^e[2]^e[3]
+Subquotient of submodule with 1 generator
+ 1: e[1]^e[2]^e[3]
+by submodule with 3 generators
+ 1: y*z*e[1]^e[2]^e[3]
+ 2: -x*z*e[1]^e[2]^e[3]
+ 3: x*y*e[1]^e[2]^e[3]
julia> koszul_homology(V, F, 1)
-Subquotient of Submodule with 2 generators
-1 -> y*e[1]^e[3] \otimes e[1] + z*e[2]^e[3] \otimes e[1]
-2 -> x*e[1]^e[2] \otimes e[1] - z*e[2]^e[3] \otimes e[1]
-by Submodule with 3 generators
-1 -> -x*z*e[1]^e[2] \otimes e[1] - y*z*e[1]^e[3] \otimes e[1]
-2 -> x*y*e[1]^e[2] \otimes e[1] - y*z*e[2]^e[3] \otimes e[1]
-3 -> x*y*e[1]^e[3] \otimes e[1] + x*z*e[2]^e[3] \otimes e[1]
+Subquotient of submodule with 2 generators
+ 1: y*e[1]^e[3] \otimes e[1] + z*e[2]^e[3] \otimes e[1]
+ 2: x*e[1]^e[2] \otimes e[1] - z*e[2]^e[3] \otimes e[1]
+by submodule with 3 generators
+ 1: -x*z*e[1]^e[2] \otimes e[1] - y*z*e[1]^e[3] \otimes e[1]
+ 2: x*y*e[1]^e[2] \otimes e[1] - y*z*e[2]^e[3] \otimes e[1]
+ 3: x*y*e[1]^e[3] \otimes e[1] + x*z*e[2]^e[3] \otimes e[1]
julia> koszul_homology(V, F, 2)
-Subquotient of Submodule with 1 generator
-1 -> x*y*e[1] \otimes e[1] + x*z*e[2] \otimes e[1] + y*z*e[3] \otimes e[1]
-by Submodule with 1 generator
-1 -> x*y*e[1] \otimes e[1] + x*z*e[2] \otimes e[1] + y*z*e[3] \otimes e[1]
+Subquotient of submodule with 1 generator
+ 1: x*y*e[1] \otimes e[1] + x*z*e[2] \otimes e[1] + y*z*e[3] \otimes e[1]
+by submodule with 1 generator
+ 1: x*y*e[1] \otimes e[1] + x*z*e[2] \otimes e[1] + y*z*e[3] \otimes e[1]
```
```jldoctest
@@ -326,27 +326,27 @@ julia> TC = ideal(R, [x*z-y^2, w*z-x*y, w*y-x^2]);
julia> F = free_module(R, 1);
julia> koszul_homology(gens(TC), F, 0)
-Subquotient of Submodule with 1 generator
-1 -> e[1]^e[2]^e[3]
-by Submodule with 3 generators
-1 -> (w*y - x^2)*e[1]^e[2]^e[3]
-2 -> (-w*z + x*y)*e[1]^e[2]^e[3]
-3 -> (x*z - y^2)*e[1]^e[2]^e[3]
+Subquotient of submodule with 1 generator
+ 1: e[1]^e[2]^e[3]
+by submodule with 3 generators
+ 1: (w*y - x^2)*e[1]^e[2]^e[3]
+ 2: (-w*z + x*y)*e[1]^e[2]^e[3]
+ 3: (x*z - y^2)*e[1]^e[2]^e[3]
julia> koszul_homology(gens(TC), F, 1)
-Subquotient of Submodule with 2 generators
-1 -> z*e[1]^e[2] \otimes e[1] + y*e[1]^e[3] \otimes e[1] + x*e[2]^e[3] \otimes e[1]
-2 -> y*e[1]^e[2] \otimes e[1] + x*e[1]^e[3] \otimes e[1] + w*e[2]^e[3] \otimes e[1]
-by Submodule with 3 generators
-1 -> (-w*z + x*y)*e[1]^e[2] \otimes e[1] + (-w*y + x^2)*e[1]^e[3] \otimes e[1]
-2 -> (x*z - y^2)*e[1]^e[2] \otimes e[1] + (-w*y + x^2)*e[2]^e[3] \otimes e[1]
-3 -> (x*z - y^2)*e[1]^e[3] \otimes e[1] + (w*z - x*y)*e[2]^e[3] \otimes e[1]
+Subquotient of submodule with 2 generators
+ 1: z*e[1]^e[2] \otimes e[1] + y*e[1]^e[3] \otimes e[1] + x*e[2]^e[3] \otimes e[1]
+ 2: y*e[1]^e[2] \otimes e[1] + x*e[1]^e[3] \otimes e[1] + w*e[2]^e[3] \otimes e[1]
+by submodule with 3 generators
+ 1: (-w*z + x*y)*e[1]^e[2] \otimes e[1] + (-w*y + x^2)*e[1]^e[3] \otimes e[1]
+ 2: (x*z - y^2)*e[1]^e[2] \otimes e[1] + (-w*y + x^2)*e[2]^e[3] \otimes e[1]
+ 3: (x*z - y^2)*e[1]^e[3] \otimes e[1] + (w*z - x*y)*e[2]^e[3] \otimes e[1]
julia> koszul_homology(gens(TC), F, 2)
-Subquotient of Submodule with 1 generator
-1 -> (-x*z + y^2)*e[1] \otimes e[1] + (-w*z + x*y)*e[2] \otimes e[1] + (-w*y + x^2)*e[3] \otimes e[1]
-by Submodule with 1 generator
-1 -> (x*z - y^2)*e[1] \otimes e[1] + (w*z - x*y)*e[2] \otimes e[1] + (w*y - x^2)*e[3] \otimes e[1]
+Subquotient of submodule with 1 generator
+ 1: (-x*z + y^2)*e[1] \otimes e[1] + (-w*z + x*y)*e[2] \otimes e[1] + (-w*y + x^2)*e[3] \otimes e[1]
+by submodule with 1 generator
+ 1: (x*z - y^2)*e[1] \otimes e[1] + (w*z - x*y)*e[2] \otimes e[1] + (w*y - x^2)*e[3] \otimes e[1]
```
"""
function koszul_homology(V::Vector{T}, F::ModuleFP{T}, i::Int) where T <: MPolyRingElem
diff --git a/src/NumberTheory/GaloisGrp/GaloisGrp.jl b/src/NumberTheory/GaloisGrp/GaloisGrp.jl
index 8e3ef37c81ac..7b5246099f7e 100644
--- a/src/NumberTheory/GaloisGrp/GaloisGrp.jl
+++ b/src/NumberTheory/GaloisGrp/GaloisGrp.jl
@@ -579,7 +579,7 @@ end
function Nemo.roots_upper_bound(f::ZZMPolyRingElem, t::Int = 0)
@assert nvars(parent(f)) == 2
- Qs, s = rational_function_field(FlintQQ, "t", cached = false)
+ Qs, s = rational_function_field(QQ, "t", cached = false)
Qsx, x = polynomial_ring(Qs, cached = false)
F = evaluate(f, [x, Qsx(s)])
dis = numerator(discriminant(F))
diff --git a/src/NumberTheory/GaloisGrp/Qt.jl b/src/NumberTheory/GaloisGrp/Qt.jl
index 2b69cc4c8ef9..ad9791b87fba 100644
--- a/src/NumberTheory/GaloisGrp/Qt.jl
+++ b/src/NumberTheory/GaloisGrp/Qt.jl
@@ -88,7 +88,7 @@ for analysis of the denominator and the infinite valuations
function _galois_init(F::Generic.FunctionField{QQFieldElem}; tStart::Int = -1)
f = defining_polynomial(F)
@assert is_monic(f)
- Zxy, (x, y) = polynomial_ring(FlintZZ, 2, cached = false)
+ Zxy, (x, y) = polynomial_ring(ZZ, 2, cached = false)
ff = Zxy()
d = lcm(map(denominator, coefficients(f)))
df = f*d
@@ -101,7 +101,7 @@ function _galois_init(F::Generic.FunctionField{QQFieldElem}; tStart::Int = -1)
for i=0:degree(f)
c = coeff(df, i)
if !iszero(c)
- ff += map_coefficients(FlintZZ, numerator(c))(y)*x^i
+ ff += map_coefficients(ZZ, numerator(c))(y)*x^i
end
end
_subfields(F, ff, tStart = tStart)
diff --git a/src/NumberTheory/NmbThy.jl b/src/NumberTheory/NmbThy.jl
index 7f8921b85823..140c6597161b 100644
--- a/src/NumberTheory/NmbThy.jl
+++ b/src/NumberTheory/NmbThy.jl
@@ -89,7 +89,7 @@ function norm_equation_fac_elem(R::AbsNumFieldOrder, k::ZZRingElem; abs::Bool =
S = Tuple{Vector{Tuple{Hecke.ideal_type(R), Int}}, Vector{ZZMatrix}}[]
for (p, k) = lp.fac
P = prime_decomposition(R, p)
- s = solve_non_negative(matrix(FlintZZ, 1, length(P), [degree(x[1]) for x = P]), matrix(FlintZZ, 1, 1, [k]))
+ s = solve_non_negative(matrix(ZZ, 1, length(P), [degree(x[1]) for x = P]), matrix(ZZ, 1, 1, [k]))
push!(S, (P, ZZMatrix[view(s, i:i, 1:ncols(s)) for i=1:nrows(s)]))
end
sol = FacElem{AbsSimpleNumFieldElem, AbsSimpleNumField}[]
@@ -126,10 +126,10 @@ end
norm_equation(R::AbsNumFieldOrder, k::Base.Integer; abs::Bool = false) = norm_equation(R, ZZRingElem(k), abs = abs)
-function norm_equation_fac_elem(R::Hecke.RelNumFieldOrder{AbsSimpleNumFieldElem,Hecke.AbsSimpleNumFieldOrderFractionalIdeal}, a::AbsNumFieldOrderElem{AbsSimpleNumField,AbsSimpleNumFieldElem})
+function norm_equation_fac_elem(R::Hecke.RelNumFieldOrder{AbsSimpleNumFieldElem,Hecke.AbsSimpleNumFieldOrderFractionalIdeal}, a::AbsSimpleNumFieldOrderElem)
@assert Hecke.is_maximal(R)
- Ka, mKa, mkK = absolute_field(Hecke.nf(R))
+ Ka, mKa, mkK = collapse_top_layer(Hecke.nf(R))
Ra = maximal_order(Ka)
class_group(Ra)
k = Hecke.nf(parent(a))
@@ -144,10 +144,10 @@ function norm_equation_fac_elem(R::Hecke.RelNumFieldOrder{AbsSimpleNumFieldElem,
q, mms = snf(q)
mq = mq*inv(mms)
- C = vcat([matrix(FlintZZ, 1, ngens(q), [valuation(mS(preimage(mq, q[i])), p) for i=1:ngens(q)]) for p = keys(lp)])
+ C = reduce(vcat, (matrix(ZZ, 1, ngens(q), [valuation(mS(preimage(mq, q[i])), p) for i=1:ngens(q)]) for p = keys(lp)))
- A = vcat([matrix(FlintZZ, 1, ngens(q), [valuation(norm(mkK, mS(preimage(mq, g))), p) for g in gens(q)]) for p = keys(la)])
- b = matrix(FlintZZ, length(la), 1, [valuation(a, p) for p = keys(la)])
+ A = reduce(vcat, (matrix(ZZ, 1, ngens(q), [valuation(norm(mkK, mS(preimage(mq, g))), p) for g in gens(q)]) for p = keys(la)))
+ b = matrix(ZZ, length(la), 1, [valuation(a, p) for p = keys(la)])
so = solve_mixed(A, b, C)
u, mu = Hecke.unit_group_fac_elem(parent(a))
@@ -168,9 +168,9 @@ function norm_equation_fac_elem(R::Hecke.RelNumFieldOrder{AbsSimpleNumFieldElem,
return sol
end
-norm_equation(R::Hecke.RelNumFieldOrder{AbsSimpleNumFieldElem,Hecke.AbsSimpleNumFieldOrderFractionalIdeal}, a::AbsNumFieldOrderElem{AbsSimpleNumField,AbsSimpleNumFieldElem}) = map(x -> R(evaluate(x)), norm_equation_fac_elem(R, a))
+norm_equation(R::Hecke.RelNumFieldOrder{AbsSimpleNumFieldElem,Hecke.AbsSimpleNumFieldOrderFractionalIdeal}, a::AbsSimpleNumFieldOrderElem) = map(x -> R(evaluate(x)), norm_equation_fac_elem(R, a))
-function is_irreducible(a::AbsNumFieldOrderElem{AbsSimpleNumField,AbsSimpleNumFieldElem})
+function is_irreducible(a::AbsSimpleNumFieldOrderElem)
if iszero(a)
return false
end
@@ -189,16 +189,16 @@ function is_irreducible(a::AbsNumFieldOrderElem{AbsSimpleNumField,AbsSimpleNumFi
# if this is possible, then a is not irreducible as a
# is then ms(Ax) * ms(Ay) and neither is trivial.
- I = identity_matrix(FlintZZ, length(S))
+ I = identity_matrix(ZZ, length(S))
A = hcat(I, I)
#so A*(x|y) = x+y = sol is the 1. condition
C = cat(V, V, dims=(1,2))
# C(x|y) >=0 iff Cx >=0 and Cy >=0
#Cx <> 0 iff (1,..1)*Cx >= 1
- one = matrix(FlintZZ, 1, length(S), [1 for p = S])
- zer = matrix(FlintZZ, 1, length(S), [0 for p = S])
+ one = matrix(ZZ, 1, length(S), [1 for p = S])
+ zer = matrix(ZZ, 1, length(S), [0 for p = S])
C = vcat(C, hcat(one, zer), hcat(zer, one))
- d = matrix(FlintZZ, 2*length(S)+2, 1, [0 for i = 1:2*length(S) + 2])
+ d = matrix(ZZ, 2*length(S)+2, 1, [0 for i = 1:2*length(S) + 2])
d[end-1, 1] = 1
d[end, 1] = 1
pt = solve_mixed(A, sol, C, d)
@@ -206,11 +206,11 @@ function is_irreducible(a::AbsNumFieldOrderElem{AbsSimpleNumField,AbsSimpleNumFi
end
@doc raw"""
- irreducibles(S::Vector{AbsNumFieldOrderIdeal{AbsSimpleNumField,AbsSimpleNumFieldElem}}) -> Vector{AbsNumFieldOrderElem}
+ irreducibles(S::Vector{AbsSimpleNumFieldOrderIdeal}) -> Vector{AbsNumFieldOrderElem}
Return all irreducibles whose support is contained in $S$.
"""
-function irreducibles(S::Vector{AbsNumFieldOrderIdeal{AbsSimpleNumField,AbsSimpleNumFieldElem}})
+function irreducibles(S::Vector{AbsSimpleNumFieldOrderIdeal})
if length(S) == 0
return []
end
@@ -268,11 +268,11 @@ end
=#
@doc raw"""
- factorizations(a::AbsNumFieldOrderElem{AbsSimpleNumField,AbsSimpleNumFieldElem}) -> Vector{Fac{OrdElem}}
+ factorizations(a::AbsSimpleNumFieldOrderElem) -> Vector{Fac{OrdElem}}
Return all factorizations of $a$ into irreducibles.
"""
-function factorizations(a::AbsNumFieldOrderElem{AbsSimpleNumField,AbsSimpleNumFieldElem})
+function factorizations(a::AbsSimpleNumFieldOrderElem)
O = parent(a)
S = collect(keys(factor(a*O)))
if length(S) == 0
@@ -302,7 +302,7 @@ function factorizations(a::AbsNumFieldOrderElem{AbsSimpleNumField,AbsSimpleNumFi
end
end
sol = solve_non_negative(A, b)
- res = Fac{AbsNumFieldOrderElem{AbsSimpleNumField,AbsSimpleNumFieldElem}}[]
+ res = Fac{AbsSimpleNumFieldOrderElem}[]
for j=1:nrows(sol)
x = Dict{typeof(a), Int}()
y = a
diff --git a/src/PolyhedralGeometry/Cone/properties.jl b/src/PolyhedralGeometry/Cone/properties.jl
index 7a4d3f964f0f..6e56e125921c 100644
--- a/src/PolyhedralGeometry/Cone/properties.jl
+++ b/src/PolyhedralGeometry/Cone/properties.jl
@@ -534,7 +534,7 @@ is_fulldimensional(C::Cone) = pm_object(C).FULL_DIM::Bool
Return the facets of `C` in the format defined by `as`.
The allowed values for `as` are
-* `Halfspace`,
+* `Halfspace` (or its subtype `LinearHalfspace`),
* `Cone`.
# Examples
@@ -543,7 +543,7 @@ julia> c = positive_hull([1 0 0; 0 1 0; 1 1 1])
Polyhedral cone in ambient dimension 3
julia> f = facets(Halfspace, c)
-3-element SubObjectIterator{LinearHalfspace{QQFieldElem}} over the Halfspaces of R^3 described by:
+3-element SubObjectIterator{LinearHalfspace{QQFieldElem}} over the halfspaces of R^3 described by:
-x_3 <= 0
-x_1 + x_3 <= 0
-x_2 + x_3 <= 0
@@ -616,7 +616,7 @@ $H = \{ (x_1, x_2, x_3) | x_3 = 0 \}$.
julia> c = positive_hull([1 0 0; 0 1 0]);
julia> linear_span(c)
-1-element SubObjectIterator{LinearHyperplane{QQFieldElem}} over the Hyperplanes of R^3 described by:
+1-element SubObjectIterator{LinearHyperplane{QQFieldElem}} over the hyperplanes of R^3 described by:
x_3 = 0
```
"""
diff --git a/src/PolyhedralGeometry/PolyhedralComplex/constructors.jl b/src/PolyhedralGeometry/PolyhedralComplex/constructors.jl
index 6b5217e01143..db9e9c56125d 100644
--- a/src/PolyhedralGeometry/PolyhedralComplex/constructors.jl
+++ b/src/PolyhedralGeometry/PolyhedralComplex/constructors.jl
@@ -40,7 +40,7 @@ points and the rows represent the polyhedra.
# Examples
```jldoctest
-julia> IM = IncidenceMatrix([[1,2,3],[1,3,4]])
+julia> IM = incidence_matrix([[1,2,3],[1,3,4]])
2×4 IncidenceMatrix
[1, 2, 3]
[1, 3, 4]
@@ -61,7 +61,7 @@ Polyhedral complex with rays and lineality:
```jldoctest
julia> VR = [0 0 0; 1 0 0; 0 1 0; -1 0 0];
-julia> IM = IncidenceMatrix([[1,2,3],[1,3,4]]);
+julia> IM = incidence_matrix([[1,2,3],[1,3,4]]);
julia> far_vertices = [2,3,4];
diff --git a/src/PolyhedralGeometry/PolyhedralComplex/properties.jl b/src/PolyhedralGeometry/PolyhedralComplex/properties.jl
index f769ef684cdb..670ae81cc9e6 100644
--- a/src/PolyhedralGeometry/PolyhedralComplex/properties.jl
+++ b/src/PolyhedralGeometry/PolyhedralComplex/properties.jl
@@ -5,7 +5,7 @@ Return the ambient dimension of `PC`.
# Examples
```jldoctest
-julia> IM = IncidenceMatrix([[1,2,3],[1,3,4]])
+julia> IM = incidence_matrix([[1,2,3],[1,3,4]])
2×4 IncidenceMatrix
[1, 2, 3]
[1, 3, 4]
@@ -41,7 +41,7 @@ Optional arguments for `as` include
# Examples
```jldoctest
-julia> IM = IncidenceMatrix([[1,2,3],[1,3,4]]);
+julia> IM = incidence_matrix([[1,2,3],[1,3,4]]);
julia> V = [0 0; 1 0; 1 1; 0 1];
@@ -63,7 +63,7 @@ julia> matrix(QQ, vertices(PointVector, PC))
```
The following complex has no vertices:
```
-julia> IM = IncidenceMatrix([[1,2,3],[1,3,4]]);
+julia> IM = incidence_matrix([[1,2,3],[1,3,4]]);
julia> VR = [0 0 0; 1 0 0; 0 1 0; -1 0 0];
@@ -139,7 +139,7 @@ function is mainly a helper function for [`maximal_polyhedra`](@ref maximal_poly
# Examples
```jldoctest
-julia> IM = IncidenceMatrix([[1,2,3],[1,3,4]]);
+julia> IM = incidence_matrix([[1,2,3],[1,3,4]]);
julia> VR = [0 0 0; 1 0 0; 0 1 0; -1 0 0];
@@ -193,7 +193,7 @@ See also [`rays`](@ref rays(PC::PolyhedralComplex{T}) where {T<:scalar_types}) a
```jldoctest
julia> VR = [0 0 0; 1 0 0; 0 1 0; -1 0 0];
-julia> IM = IncidenceMatrix([[1,2,3],[1,3,4]]);
+julia> IM = incidence_matrix([[1,2,3],[1,3,4]]);
julia> far_vertices = [2,3,4];
@@ -259,7 +259,7 @@ See also [`vertices`](@ref vertices(as::Type{PointVector{T}}, PC::PolyhedralComp
```jldoctest
julia> VR = [0 0 0; 1 0 0; 0 1 0; -1 0 0];
-julia> IM = IncidenceMatrix([[1,2,3],[1,3,4]]);
+julia> IM = incidence_matrix([[1,2,3],[1,3,4]]);
julia> far_vertices = [2,3,4];
@@ -317,7 +317,7 @@ Optional arguments for `as` include
# Examples
```jldoctest
-julia> IM = IncidenceMatrix([[1,2,3],[1,3,4]]);
+julia> IM = incidence_matrix([[1,2,3],[1,3,4]]);
julia> VR = [0 0; 1 0; 1 1; 0 1];
@@ -333,7 +333,7 @@ julia> matrix(QQ, rays(RayVector, PC))
```
The following complex has no vertices:
```
-julia> IM = IncidenceMatrix([[1,2,3],[1,3,4]]);
+julia> IM = incidence_matrix([[1,2,3],[1,3,4]]);
julia> VR = [0 0 0; 1 0 0; 0 1 0; -1 0 0];
@@ -398,7 +398,7 @@ refer to the output of [`vertices_and_rays`](@ref vertices_and_rays(PC::Polyhedr
# Examples
```jldoctest
-julia> IM = IncidenceMatrix([[1,2,3],[1,3,4]])
+julia> IM = incidence_matrix([[1,2,3],[1,3,4]])
2×4 IncidenceMatrix
[1, 2, 3]
[1, 3, 4]
@@ -435,7 +435,7 @@ Return the number of maximal polyhedra of `PC`
# Examples
```jldoctest
-julia> IM = IncidenceMatrix([[1,2,3],[1,3,4]])
+julia> IM = incidence_matrix([[1,2,3],[1,3,4]])
2×4 IncidenceMatrix
[1, 2, 3]
[1, 3, 4]
@@ -464,7 +464,7 @@ Determine whether the polyhedral complex is simplicial.
# Examples
```jldoctest
-julia> IM = IncidenceMatrix([[1,2,3],[1,3,4]]);
+julia> IM = incidence_matrix([[1,2,3],[1,3,4]]);
julia> VR = [0 0; 1 0; 1 1; 0 1];
@@ -484,7 +484,7 @@ Determine whether the polyhedral complex is pure.
# Examples
```jldoctest
-julia> IM = IncidenceMatrix([[1,2,3],[1,3,4]]);
+julia> IM = incidence_matrix([[1,2,3],[1,3,4]]);
julia> VR = [0 0; 1 0; 1 1; 0 1];
@@ -504,7 +504,7 @@ Compute the dimension of the polyhedral complex.
# Examples
```jldoctest
-julia> IM = IncidenceMatrix([[1,2,3],[1,3,4]]);
+julia> IM = incidence_matrix([[1,2,3],[1,3,4]]);
julia> VR = [0 0; 1 0; 1 1; 0 1];
@@ -524,7 +524,7 @@ Return the polyhedra of a given dimension in the polyhedral complex `PC`.
# Examples
```jldoctest
-julia> IM = IncidenceMatrix([[1,2,3],[1,3,4]]);
+julia> IM = incidence_matrix([[1,2,3],[1,3,4]]);
julia> VR = [0 0; 1 0; 1 1; 0 1];
@@ -596,7 +596,7 @@ Return the lineality space of `PC`.
```jldoctest
julia> VR = [0 0 0; 1 0 0; 0 1 0; -1 0 0];
-julia> IM = IncidenceMatrix([[1,2,3],[1,3,4]]);
+julia> IM = incidence_matrix([[1,2,3],[1,3,4]]);
julia> far_vertices = [2,3,4];
@@ -636,7 +636,7 @@ Return the lineality dimension of `PC`.
```jldoctest
julia> VR = [0 0 0; 1 0 0; 0 1 0; -1 0 0];
-julia> IM = IncidenceMatrix([[1,2,3],[1,3,4]]);
+julia> IM = incidence_matrix([[1,2,3],[1,3,4]]);
julia> far_vertices = [2,3,4];
@@ -661,7 +661,7 @@ faces of $PC$ of dimension $i$.
```jldoctest
julia> VR = [0 0; 1 0; -1 0; 0 1];
-julia> IM = IncidenceMatrix([[1,2,4],[1,3,4]]);
+julia> IM = incidence_matrix([[1,2,4],[1,3,4]]);
julia> far_vertices = [2,3,4];
@@ -689,7 +689,7 @@ Return the number of rays of `PC`.
```jldoctest
julia> VR = [0 0; 1 0; -1 0; 0 1];
-julia> IM = IncidenceMatrix([[1,2,4],[1,3,4]]);
+julia> IM = incidence_matrix([[1,2,4],[1,3,4]]);
julia> far_vertices = [2,3,4];
@@ -711,7 +711,7 @@ Return the number of vertices of `PC`.
```jldoctest
julia> VR = [0 0; 1 0; -1 0; 0 1];
-julia> IM = IncidenceMatrix([[1,2,4],[1,3,4]]);
+julia> IM = incidence_matrix([[1,2,4],[1,3,4]]);
julia> far_vertices = [2,3,4];
@@ -733,7 +733,7 @@ Return the total number of polyhedra in the polyhedral complex `PC`.
```jldoctest
julia> VR = [0 0; 1 0; -1 0; 0 1];
-julia> IM = IncidenceMatrix([[1,2,4],[1,3,4]]);
+julia> IM = incidence_matrix([[1,2,4],[1,3,4]]);
julia> far_vertices = [2,3,4];
@@ -754,7 +754,7 @@ Compute the codimension of a polyhedral complex.
```
julia> VR = [0 0; 1 0; -1 0; 0 1];
-julia> IM = IncidenceMatrix([[1,2],[1,3],[1,4]]);
+julia> IM = incidence_matrix([[1,2],[1,3],[1,4]]);
julia> far_vertices = [2,3,4];
@@ -777,7 +777,7 @@ subset of some $\mathbb{R}^n$.
```jldoctest
julia> VR = [0 0; 1 0; -1 0; 0 1];
-julia> IM = IncidenceMatrix([[1,2],[1,3],[1,4]]);
+julia> IM = incidence_matrix([[1,2],[1,3],[1,4]]);
julia> PC = polyhedral_complex(IM, VR)
Polyhedral complex in ambient dimension 2
diff --git a/src/PolyhedralGeometry/PolyhedralComplex/standard_constructions.jl b/src/PolyhedralGeometry/PolyhedralComplex/standard_constructions.jl
index 1eb7cf43e588..711c3a6d87c4 100644
--- a/src/PolyhedralGeometry/PolyhedralComplex/standard_constructions.jl
+++ b/src/PolyhedralGeometry/PolyhedralComplex/standard_constructions.jl
@@ -5,7 +5,7 @@ Return the common refinement of two polyhedral complexes.
# Examples
```jldoctest
-julia> IM = IncidenceMatrix([[1,2,3]])
+julia> IM = incidence_matrix([[1,2,3]])
1×3 IncidenceMatrix
[1, 2, 3]
@@ -51,7 +51,7 @@ Return the k-skeleton of a polyhedral complex.
# Examples
```jldoctest
-julia> IM = IncidenceMatrix([[1,2,3]])
+julia> IM = incidence_matrix([[1,2,3]])
1×3 IncidenceMatrix
[1, 2, 3]
diff --git a/src/PolyhedralGeometry/PolyhedralFan/constructors.jl b/src/PolyhedralGeometry/PolyhedralFan/constructors.jl
index f54219634937..9005ace2a38d 100644
--- a/src/PolyhedralGeometry/PolyhedralFan/constructors.jl
+++ b/src/PolyhedralGeometry/PolyhedralFan/constructors.jl
@@ -43,7 +43,7 @@ To obtain the upper half-space of the plane:
```jldoctest
julia> R = [1 0; 1 1; 0 1; -1 0; 0 -1];
-julia> IM=IncidenceMatrix([[1,2],[2,3],[3,4],[4,5],[1,5]]);
+julia> IM = incidence_matrix([[1,2],[2,3],[3,4],[4,5],[1,5]]);
julia> PF=polyhedral_fan(IM, R)
Polyhedral fan in ambient dimension 2
@@ -55,7 +55,7 @@ julia> R = [1 0 0; 0 0 1];
julia> L = [0 1 0];
-julia> IM = IncidenceMatrix([[1],[2]]);
+julia> IM = incidence_matrix([[1],[2]]);
julia> PF=polyhedral_fan(IM, R, L)
Polyhedral fan in ambient dimension 3
diff --git a/src/PolyhedralGeometry/PolyhedralFan/properties.jl b/src/PolyhedralGeometry/PolyhedralFan/properties.jl
index 13d9a3fbeec3..9a319a4b2f27 100644
--- a/src/PolyhedralGeometry/PolyhedralFan/properties.jl
+++ b/src/PolyhedralGeometry/PolyhedralFan/properties.jl
@@ -50,7 +50,7 @@ julia> matrix(QQ, rays(NF))
```
The following fan has no rays:
```
-julia> IM = IncidenceMatrix([[1,2],[2,3]]);
+julia> IM = incidence_matrix([[1,2],[2,3]]);
julia> R = [1 0 0; 0 1 0; -1 0 0];
@@ -212,8 +212,21 @@ julia> cones(PF, 2)
"""
function cones(PF::_FanLikeType, cone_dim::Int)
l = cone_dim - length(lineality_space(PF))
- l < 1 && return nothing
- return SubObjectIterator{Cone{_get_scalar_type(PF)}}(
+ t = Cone{_get_scalar_type(PF)}
+ (l < 0 || dim(PF) == -1) && return _empty_subobjectiterator(t, PF)
+
+ if l == 0
+ return SubObjectIterator{t}(
+ PF,
+ (_, _, _) -> positive_hull(
+ coefficient_field(PF), zeros(Int, ambient_dim(PF)), lineality_space(PF)
+ ),
+ 1,
+ NamedTuple(),
+ )
+ end
+
+ return SubObjectIterator{t}(
PF, _cone_of_dim, size(Polymake.fan.cones_of_dim(pm_object(PF), l), 1), (c_dim=l,)
)
end
@@ -287,7 +300,7 @@ Return the dimension of `PF`.
This fan in the plane contains a 2-dimensional cone and is thus 2-dimensional
itself.
```jldoctest
-julia> PF = polyhedral_fan(IncidenceMatrix([[1, 2], [3]]), [1 0; 0 1; -1 -1]);
+julia> PF = polyhedral_fan(incidence_matrix([[1, 2], [3]]), [1 0; 0 1; -1 -1]);
julia> dim(PF)
2
@@ -304,7 +317,7 @@ Return the number of maximal cones of `PF`.
The cones given in this construction are non-redundant. Thus there are two
maximal cones.
```jldoctest
-julia> PF = polyhedral_fan(IncidenceMatrix([[1, 2], [3]]), [1 0; 0 1; -1 -1]);
+julia> PF = polyhedral_fan(incidence_matrix([[1, 2], [3]]), [1 0; 0 1; -1 -1]);
julia> n_maximal_cones(PF)
2
@@ -321,7 +334,7 @@ Return the number of cones of `PF`.
The cones given in this construction are non-redundant. There are six
cones in this fan.
```jldoctest
-julia> PF = polyhedral_fan(IncidenceMatrix([[1, 2], [3]]), [1 0; 0 1; -1 -1])
+julia> PF = polyhedral_fan(incidence_matrix([[1, 2], [3]]), [1 0; 0 1; -1 -1])
Polyhedral fan in ambient dimension 2
julia> n_cones(PF)
@@ -441,7 +454,7 @@ This fan consists of two cones, one containing all the points with $y ≤ 0$ and
one containing all the points with $y ≥ 0$. The fan's lineality is the common
lineality of these two cones, i.e. in $x$-direction.
```jldoctest
-julia> PF = polyhedral_fan(IncidenceMatrix([[1, 2, 3], [3, 4, 1]]), [1 0; 0 1; -1 0; 0 -1])
+julia> PF = polyhedral_fan(incidence_matrix([[1, 2, 3], [3, 4, 1]]), [1 0; 0 1; -1 0; 0 -1])
Polyhedral fan in ambient dimension 2
julia> lineality_space(PF)
@@ -500,7 +513,7 @@ Determine whether `PF` is smooth.
Even though the cones of this fan cover the positive orthant together, one of
these und thus the whole fan is not smooth.
```jldoctest
-julia> PF = polyhedral_fan(IncidenceMatrix([[1, 2], [2, 3]]), [0 1; 2 1; 1 0]);
+julia> PF = polyhedral_fan(incidence_matrix([[1, 2], [2, 3]]), [0 1; 2 1; 1 0]);
julia> is_smooth(PF)
false
@@ -516,7 +529,7 @@ Determine whether `PF` is regular, i.e. the normal fan of a polytope.
# Examples
This fan is not complete and thus not regular.
```jldoctest
-julia> PF = polyhedral_fan(IncidenceMatrix([[1, 2], [3]]), [1 0; 0 1; -1 -1]);
+julia> PF = polyhedral_fan(incidence_matrix([[1, 2], [3]]), [1 0; 0 1; -1 -1]);
julia> is_regular(PF)
false
@@ -531,7 +544,7 @@ Determine whether `PF` is pure, i.e. all maximal cones have the same dimension.
# Examples
```jldoctest
-julia> PF = polyhedral_fan(IncidenceMatrix([[1, 2], [3]]), [1 0; 0 1; -1 -1]);
+julia> PF = polyhedral_fan(incidence_matrix([[1, 2], [3]]), [1 0; 0 1; -1 -1]);
julia> is_pure(PF)
false
@@ -547,7 +560,7 @@ dimension.
# Examples
```jldoctest
-julia> PF = polyhedral_fan(IncidenceMatrix([[1, 2], [3]]), [1 0; 0 1; -1 -1]);
+julia> PF = polyhedral_fan(incidence_matrix([[1, 2], [3]]), [1 0; 0 1; -1 -1]);
julia> is_fulldimensional(PF)
true
diff --git a/src/PolyhedralGeometry/Polyhedron/properties.jl b/src/PolyhedralGeometry/Polyhedron/properties.jl
index 63ecdbbf44cb..c400ea1bce88 100644
--- a/src/PolyhedralGeometry/Polyhedron/properties.jl
+++ b/src/PolyhedralGeometry/Polyhedron/properties.jl
@@ -491,7 +491,7 @@ end
Return the facets of `P` in the format defined by `as`.
The allowed values for `as` are
-* `Halfspace`,
+* `Halfspace` (or its subtype `AffineHalfspace`),
* `Polyhedron`,
* `Pair`.
@@ -510,7 +510,7 @@ julia> facets(Polyhedron, C)
Polytope in ambient dimension 3
julia> facets(Halfspace, C)
-6-element SubObjectIterator{AffineHalfspace{QQFieldElem}} over the Halfspaces of R^3 described by:
+6-element SubObjectIterator{AffineHalfspace{QQFieldElem}} over the halfspaces of R^3 described by:
-x_1 <= 1
x_1 <= 1
-x_2 <= 1
@@ -593,7 +593,7 @@ We can retrieve the six facets of the 3-dimensional cube this way:
julia> C = cube(3);
julia> facets(C)
-6-element SubObjectIterator{AffineHalfspace{QQFieldElem}} over the Halfspaces of R^3 described by:
+6-element SubObjectIterator{AffineHalfspace{QQFieldElem}} over the halfspaces of R^3 described by:
-x_1 <= 1
x_1 <= 1
-x_2 <= 1
@@ -998,7 +998,7 @@ $P = \{ (x_1, x_2, x_3, x_4) | x_3 = 2 ∧ x_4 = 5 \}$.
julia> t = convex_hull([0 0 2 5; 1 0 2 5; 0 1 2 5]);
julia> affine_hull(t)
-2-element SubObjectIterator{AffineHyperplane{QQFieldElem}} over the Hyperplanes of R^4 described by:
+2-element SubObjectIterator{AffineHyperplane{QQFieldElem}} over the hyperplanes of R^4 described by:
x_3 = 2
x_4 = 5
```
@@ -1831,7 +1831,7 @@ function Base.show(io::IO, H::SubObjectIterator{<:Halfspace})
print(io, "$s-element $t")
if !isempty(H)
n = length(normal_vector(H[1]))
- print(io, " over the Halfspaces of R^$n described by:\n")
+ print(io, " over the halfspaces of R^$n described by:\n")
if s < d
print_constraints(io, H)
else
@@ -1854,7 +1854,7 @@ function Base.show(io::IO, H::SubObjectIterator{<:Hyperplane})
print(io, "$s-element $t")
if !isempty(H)
n = length(normal_vector(H[1]))
- print(io, " over the Hyperplanes of R^$n described by:\n")
+ print(io, " over the hyperplanes of R^$n described by:\n")
if s < d
print_constraints(io, H)
else
diff --git a/src/PolyhedralGeometry/Polyhedron/standard_constructions.jl b/src/PolyhedralGeometry/Polyhedron/standard_constructions.jl
index 9e18a71d8113..29e51665b074 100644
--- a/src/PolyhedralGeometry/Polyhedron/standard_constructions.jl
+++ b/src/PolyhedralGeometry/Polyhedron/standard_constructions.jl
@@ -618,7 +618,7 @@ julia> s = simplex(7)
Polytope in ambient dimension 7
julia> facets(s)
-8-element SubObjectIterator{AffineHalfspace{QQFieldElem}} over the Halfspaces of R^7 described by:
+8-element SubObjectIterator{AffineHalfspace{QQFieldElem}} over the halfspaces of R^7 described by:
-x_1 <= 0
-x_2 <= 0
-x_3 <= 0
@@ -632,7 +632,7 @@ julia> t = simplex(7, 5)
Polytope in ambient dimension 7
julia> facets(t)
-8-element SubObjectIterator{AffineHalfspace{QQFieldElem}} over the Halfspaces of R^7 described by:
+8-element SubObjectIterator{AffineHalfspace{QQFieldElem}} over the halfspaces of R^7 described by:
-x_1 <= 0
-x_2 <= 0
-x_3 <= 0
@@ -674,7 +674,7 @@ julia> C = cross_polytope(3)
Polytope in ambient dimension 3
julia> facets(C)
-8-element SubObjectIterator{AffineHalfspace{QQFieldElem}} over the Halfspaces of R^3 described by:
+8-element SubObjectIterator{AffineHalfspace{QQFieldElem}} over the halfspaces of R^3 described by:
x_1 + x_2 + x_3 <= 1
-x_1 + x_2 + x_3 <= 1
x_1 - x_2 + x_3 <= 1
@@ -688,7 +688,7 @@ julia> D = cross_polytope(3, 2)
Polytope in ambient dimension 3
julia> facets(D)
-8-element SubObjectIterator{AffineHalfspace{QQFieldElem}} over the Halfspaces of R^3 described by:
+8-element SubObjectIterator{AffineHalfspace{QQFieldElem}} over the halfspaces of R^3 described by:
x_1 + x_2 + x_3 <= 2
-x_1 + x_2 + x_3 <= 2
x_1 - x_2 + x_3 <= 2
@@ -1408,7 +1408,7 @@ julia> vertices(A)
[4, 1, 10, 6]
julia> facets(A)
-5-element SubObjectIterator{AffineHalfspace{QQFieldElem}} over the Halfspaces of R^4 described by:
+5-element SubObjectIterator{AffineHalfspace{QQFieldElem}} over the halfspaces of R^4 described by:
-x_1 <= -1
-2*x_1 - 2*x_2 <= -10
-x_2 <= -1
@@ -1637,14 +1637,14 @@ julia> G = hypersimplex(3,4,no_facets=true)
Polytope in ambient dimension 4
julia> facets(G)
-4-element SubObjectIterator{AffineHalfspace{QQFieldElem}} over the Halfspaces of R^4 described by:
+4-element SubObjectIterator{AffineHalfspace{QQFieldElem}} over the halfspaces of R^4 described by:
x_4 <= 1
x_3 <= 1
-x_1 - x_3 - x_4 <= -2
x_1 <= 1
julia> facets(H)
-4-element SubObjectIterator{AffineHalfspace{QQFieldElem}} over the Halfspaces of R^4 described by:
+4-element SubObjectIterator{AffineHalfspace{QQFieldElem}} over the halfspaces of R^4 described by:
x_4 <= 1
x_3 <= 1
-x_1 - x_3 - x_4 <= -2
@@ -2253,7 +2253,7 @@ julia> vertices(a)
[0, 3, 4, 15, 16]
julia> facets(a)
-9-element SubObjectIterator{AffineHalfspace{QQFieldElem}} over the Halfspaces of R^5 described by:
+9-element SubObjectIterator{AffineHalfspace{QQFieldElem}} over the halfspaces of R^5 described by:
x_1 - x_2 <= -1
x_1 - x_3 <= -4
x_1 - x_4 <= -9
diff --git a/src/PolyhedralGeometry/SubdivisionOfPoints/constructors.jl b/src/PolyhedralGeometry/SubdivisionOfPoints/constructors.jl
index 7411b26fee52..5373f5dd966c 100644
--- a/src/PolyhedralGeometry/SubdivisionOfPoints/constructors.jl
+++ b/src/PolyhedralGeometry/SubdivisionOfPoints/constructors.jl
@@ -52,7 +52,7 @@ triangulation.
```jldoctest
julia> moaepts = [4 0 0; 0 4 0; 0 0 4; 2 1 1; 1 2 1; 1 1 2];
-julia> moaeimnonreg0 = IncidenceMatrix([[4,5,6],[1,4,2],[2,4,5],[2,3,5],[3,5,6],[1,3,6],[1,4,6]]);
+julia> moaeimnonreg0 = incidence_matrix([[4,5,6],[1,4,2],[2,4,5],[2,3,5],[3,5,6],[1,3,6],[1,4,6]]);
julia> MOAE = subdivision_of_points(moaepts, moaeimnonreg0)
Subdivision of points in ambient dimension 3
diff --git a/src/PolyhedralGeometry/SubdivisionOfPoints/functions.jl b/src/PolyhedralGeometry/SubdivisionOfPoints/functions.jl
index 50775eeb099f..72b5b251074f 100644
--- a/src/PolyhedralGeometry/SubdivisionOfPoints/functions.jl
+++ b/src/PolyhedralGeometry/SubdivisionOfPoints/functions.jl
@@ -16,7 +16,7 @@ weights, but it will not be full-dimensional.
```jldoctest
julia> moaepts = [4 0 0; 0 4 0; 0 0 4; 2 1 1; 1 2 1; 1 1 2];
-julia> moaeimnonreg0 = IncidenceMatrix([[4,5,6],[1,4,2],[2,4,5],[2,3,5],[3,5,6],[1,3,6],[1,4,6]]);
+julia> moaeimnonreg0 = incidence_matrix([[4,5,6],[1,4,2],[2,4,5],[2,3,5],[3,5,6],[1,3,6],[1,4,6]]);
julia> MOAE = subdivision_of_points(moaepts, moaeimnonreg0)
Subdivision of points in ambient dimension 3
diff --git a/src/PolyhedralGeometry/SubdivisionOfPoints/properties.jl b/src/PolyhedralGeometry/SubdivisionOfPoints/properties.jl
index 761ce6ac8811..f7e03198f29c 100644
--- a/src/PolyhedralGeometry/SubdivisionOfPoints/properties.jl
+++ b/src/PolyhedralGeometry/SubdivisionOfPoints/properties.jl
@@ -14,7 +14,7 @@ Display the points of the "mother of all examples" non-regular triangulation.
```jldoctest
julia> moaepts = [4 0 0; 0 4 0; 0 0 4; 2 1 1; 1 2 1; 1 1 2];
-julia> moaeimnonreg0 = IncidenceMatrix([[4,5,6],[1,4,2],[2,4,5],[2,3,5],[3,5,6],[1,3,6],[1,4,6]]);
+julia> moaeimnonreg0 = incidence_matrix([[4,5,6],[1,4,2],[2,4,5],[2,3,5],[3,5,6],[1,3,6],[1,4,6]]);
julia> MOAE = subdivision_of_points(moaepts, moaeimnonreg0);
@@ -62,7 +62,7 @@ julia> moaepts = [4 0 0; 0 4 0; 0 0 4; 2 1 1; 1 2 1; 1 1 2]
1 2 1
1 1 2
-julia> moaeimnonreg0 = IncidenceMatrix([[4,5,6],[1,4,2],[2,4,5],[2,3,5],[3,5,6],[1,3,6],[1,4,6]])
+julia> moaeimnonreg0 = incidence_matrix([[4,5,6],[1,4,2],[2,4,5],[2,3,5],[3,5,6],[1,3,6],[1,4,6]])
7×6 IncidenceMatrix
[4, 5, 6]
[1, 2, 4]
@@ -245,7 +245,7 @@ triangulation of six points.
```jldoctest
julia> moaepts = [4 0 0; 0 4 0; 0 0 4; 2 1 1; 1 2 1; 1 1 2];
-julia> moaeimnonreg0 = IncidenceMatrix([[4,5,6],[1,4,2],[2,4,5],[2,3,5],[3,5,6],[1,3,6],[1,4,6]]);
+julia> moaeimnonreg0 = incidence_matrix([[4,5,6],[1,4,2],[2,4,5],[2,3,5],[3,5,6],[1,3,6],[1,4,6]]);
julia> MOAE = subdivision_of_points(moaepts, moaeimnonreg0);
diff --git a/src/PolyhedralGeometry/helpers.jl b/src/PolyhedralGeometry/helpers.jl
index 8c4c1ff3ee38..45d876183d92 100644
--- a/src/PolyhedralGeometry/helpers.jl
+++ b/src/PolyhedralGeometry/helpers.jl
@@ -6,9 +6,9 @@ import Polymake: IncidenceMatrix
A matrix with boolean entries. Each row corresponds to a fixed element of a collection of mathematical objects and the same holds for the columns and a second (possibly equal) collection. A `1` at entry `(i, j)` is interpreted as an incidence between object `i` of the first collection and object `j` of the second one.
# Examples
-Note that the input and print of an `IncidenceMatrix` lists the non-zero indices for each row.
+Note that the input of this example and the print of an `IncidenceMatrix` list the non-zero indices for each row.
```jldoctest
-julia> IM = IncidenceMatrix([[1,2,3],[4,5,6]])
+julia> IM = incidence_matrix([[1,2,3],[4,5,6]])
2×6 IncidenceMatrix
[1, 2, 3]
[4, 5, 6]
@@ -27,6 +27,109 @@ julia> IM[:, 4]
"""
IncidenceMatrix
+@doc raw"""
+ incidence_matrix(r::Base.Integer, c::Base.Integer)
+
+Return an `IncidenceMatrix` of size r x c whose entries are all `false`.
+
+# Examples
+```jldoctest
+julia> IM = incidence_matrix(8, 5)
+8×5 IncidenceMatrix
+[]
+[]
+[]
+[]
+[]
+[]
+[]
+[]
+
+```
+"""
+incidence_matrix(r::Base.Integer, c::Base.Integer) = IncidenceMatrix(undef, r, c)
+
+@doc raw"""
+ incidence_matrix(mat::Union{AbstractMatrix{Bool}, IncidenceMatrix})
+
+Convert `mat` to an `IncidenceMatrix`.
+
+# Examples
+```jldoctest
+julia> IM = incidence_matrix([true false true false true false; false true false true false true])
+2×6 IncidenceMatrix
+[1, 3, 5]
+[2, 4, 6]
+
+```
+"""
+incidence_matrix(mat::Union{AbstractMatrix{Bool},IncidenceMatrix}) = IncidenceMatrix(mat)
+
+@doc raw"""
+ incidence_matrix(mat::AbstractMatrix)
+
+Convert the `0`/`1` matrix `mat` to an `IncidenceMatrix`. Entries become `true` if the initial entry is `1` and `false` if the initial entry is `0`.
+
+# Examples
+```jldoctest
+julia> IM = incidence_matrix([1 0 1 0 1 0; 0 1 0 1 0 1])
+2×6 IncidenceMatrix
+[1, 3, 5]
+[2, 4, 6]
+
+```
+"""
+function incidence_matrix(mat::AbstractMatrix)
+ m, n = size(mat)
+ for i in 1:m
+ for j in 1:n
+ iszero(mat[i, j]) || isone(mat[i, j]) ||
+ throw(
+ ArgumentError("incidence_matrix requires matrices with 0/1 or boolean entries.")
+ )
+ end
+ end
+ return IncidenceMatrix(mat)
+end
+
+@doc raw"""
+ incidence_matrix(r::Base.Integer, c::Base.Integer, incidenceRows::AbstractVector{<:AbstractVector{<:Base.Integer}})
+
+Return an `IncidenceMatrix` of size r x c. The i-th element of `incidenceRows` lists the indices of the `true` entries of the i-th row.
+
+# Examples
+```jldoctest
+julia> IM = incidence_matrix(3, 4, [[2, 3], [1]])
+3×4 IncidenceMatrix
+[2, 3]
+[1]
+[]
+
+```
+"""
+incidence_matrix(
+ r::Base.Integer,
+ c::Base.Integer,
+ incidenceRows::AbstractVector{<:AbstractVector{<:Base.Integer}},
+) = IncidenceMatrix(r, c, incidenceRows)
+
+@doc raw"""
+ incidence_matrix(incidenceRows::AbstractVector{<:AbstractVector{<:Base.Integer}})
+
+Return an `IncidenceMatrix` where the i-th element of `incidenceRows` lists the indices of the `true` entries of the i-th row. The dimensions of the result are the smallest possible row and column count that can be deduced from the input.
+
+# Examples
+```jldoctest
+julia> IM = incidence_matrix([[2, 3], [1]])
+2×3 IncidenceMatrix
+[2, 3]
+[1]
+
+```
+"""
+incidence_matrix(incidenceRows::AbstractVector{<:AbstractVector{<:Base.Integer}}) =
+ IncidenceMatrix(incidenceRows)
+
number_of_rows(i::IncidenceMatrix) = Polymake.nrows(i)
number_of_columns(i::IncidenceMatrix) = Polymake.ncols(i)
@@ -40,7 +143,7 @@ Return the indices where the `n`-th row of `i` is `true`, as a `Set{Int}`.
# Examples
```jldoctest
-julia> IM = IncidenceMatrix([[1,2,3],[4,5,6]])
+julia> IM = incidence_matrix([[1,2,3],[4,5,6]])
2×6 IncidenceMatrix
[1, 2, 3]
[4, 5, 6]
@@ -62,7 +165,7 @@ Return the indices where the `n`-th column of `i` is `true`, as a `Set{Int}`.
# Examples
```jldoctest
-julia> IM = IncidenceMatrix([[1,2,3],[4,5,6]])
+julia> IM = incidence_matrix([[1,2,3],[4,5,6]])
2×6 IncidenceMatrix
[1, 2, 3]
[4, 5, 6]
@@ -508,6 +611,10 @@ function _parent_or_coefficient_field(::Type{T}, x, y...) where {T<:scalar_types
missing
end
+function _parent_or_coefficient_field(::Type{T}, c::Tuple) where {T<:FieldElem}
+ return _parent_or_coefficient_field(T, c...)
+end
+
function _determine_parent_and_scalar(f::Union{Field,ZZRing}, x...)
_check_field_polyhedral(elem_type(f))
return (f, elem_type(f))
diff --git a/src/PolyhedralGeometry/iterators.jl b/src/PolyhedralGeometry/iterators.jl
index 93f972e27575..d7b56e325448 100644
--- a/src/PolyhedralGeometry/iterators.jl
+++ b/src/PolyhedralGeometry/iterators.jl
@@ -85,6 +85,27 @@ Return a `RayVector` resembling a ray from the origin through the point whose co
"""
ray_vector
+function Base.:(==)(x::RayVector, y::RayVector)
+ ix = findfirst(!is_zero, x)
+ iy = findfirst(!is_zero, y)
+ ix == iy || return false
+ isnothing(ix) && return true
+ sign(x[ix]) == sign(y[iy]) || return false
+ return y[iy] * x.p == x[ix] * y.p
+end
+
+function Base.:(==)(x::RayVector, y::AbstractVector)
+ ry = ray_vector(coefficient_field(x), y)
+ return x == ry
+end
+
+Base.:(==)(x::AbstractVector, y::RayVector) = y == x
+
+Base.:(==)(::PointVector, ::RayVector) =
+ throw(ArgumentError("Cannot compare PointVector to RayVector"))
+Base.:(==)(::RayVector, ::PointVector) =
+ throw(ArgumentError("Cannot compare PointVector to RayVector"))
+
################################################################################
######## Halfspaces and Hyperplanes
################################################################################
@@ -303,6 +324,8 @@ function IncidenceMatrix(iter::SubObjectIterator)
end
end
+incidence_matrix(iter::SubObjectIterator) = IncidenceMatrix(iter)
+
# primitive generators only for ray based iterators
matrix(R::ZZRing, iter::SubObjectIterator{RayVector{QQFieldElem}}) =
matrix(R, Polymake.common.primitive(matrix_for_polymake(iter)))
diff --git a/src/PolyhedralGeometry/solving_integrally.jl b/src/PolyhedralGeometry/solving_integrally.jl
index 7818e280a53e..4659cf58a221 100644
--- a/src/PolyhedralGeometry/solving_integrally.jl
+++ b/src/PolyhedralGeometry/solving_integrally.jl
@@ -49,11 +49,11 @@ Note that the output can be permuted, hence we sort it.
```jldoctest
julia> A = ZZMatrix([1 1]);
-julia> b = zero_matrix(FlintZZ, 1,1); b[1,1]=7;
+julia> b = zero_matrix(ZZ, 1,1); b[1,1]=7;
julia> C = ZZMatrix([1 0; 0 1]);
-julia> d = zero_matrix(FlintZZ,2,1); d[1,1]=2; d[2,1]=3;
+julia> d = zero_matrix(ZZ,2,1); d[1,1]=2; d[2,1]=3;
julia> sortslices(Matrix{BigInt}(solve_mixed(A, b, C, d)), dims=1)
3×2 Matrix{BigInt}:
@@ -101,7 +101,7 @@ Note that the output can be permuted, hence we sort it.
```jldoctest
julia> A = ZZMatrix([1 1]);
-julia> b = zero_matrix(FlintZZ, 1,1); b[1,1]=3;
+julia> b = zero_matrix(ZZ, 1,1); b[1,1]=3;
julia> C = ZZMatrix([1 0; 0 1]);
@@ -131,9 +131,9 @@ julia> for x in it
"""
solve_mixed(
as::Type{T}, A::ZZMatrix, b::ZZMatrix, C::ZZMatrix; permit_unbounded=false
-) where {T} = solve_mixed(T, A, b, C, zero_matrix(FlintZZ, nrows(C), 1); permit_unbounded)
+) where {T} = solve_mixed(T, A, b, C, zero_matrix(ZZ, nrows(C), 1); permit_unbounded)
solve_mixed(A::ZZMatrix, b::ZZMatrix, C::ZZMatrix; permit_unbounded=false) =
- solve_mixed(ZZMatrix, A, b, C, zero_matrix(FlintZZ, nrows(C), 1); permit_unbounded)
+ solve_mixed(ZZMatrix, A, b, C, zero_matrix(ZZ, nrows(C), 1); permit_unbounded)
@doc raw"""
solve_ineq(as::Type{T}, A::ZZMatrix, b::ZZMatrix) where {T}
@@ -151,7 +151,7 @@ Note that the output can be permuted, hence we sort it.
```jldoctest
julia> A = ZZMatrix([1 0; 0 1; -1 0; 0 -1]);
-julia> b = zero_matrix(FlintZZ, 4,1); b[1,1]=1; b[2,1]=1; b[3,1]=0; b[4,1]=0;
+julia> b = zero_matrix(ZZ, 4,1); b[1,1]=1; b[2,1]=1; b[3,1]=0; b[4,1]=0;
julia> sortslices(Matrix{BigInt}(solve_ineq(A, b)), dims=1)
4×2 Matrix{BigInt}:
@@ -173,8 +173,8 @@ SubObjectIterator{PointVector{ZZRingElem}}
solve_ineq(as::Type{T}, A::ZZMatrix, b::ZZMatrix; permit_unbounded=false) where {T} =
solve_mixed(
T,
- zero_matrix(FlintZZ, 0, ncols(A)),
- zero_matrix(FlintZZ, 0, 1),
+ zero_matrix(ZZ, 0, ncols(A)),
+ zero_matrix(ZZ, 0, 1),
-A,
-b;
permit_unbounded,
@@ -198,7 +198,7 @@ Note that the output can be permuted, hence we sort it.
```jldoctest
julia> A = ZZMatrix([1 1]);
-julia> b = zero_matrix(FlintZZ, 1,1); b[1,1]=3;
+julia> b = zero_matrix(ZZ, 1,1); b[1,1]=3;
julia> sortslices(Matrix{BigInt}(solve_non_negative(A, b)), dims=1)
4×2 Matrix{BigInt}:
@@ -219,6 +219,6 @@ SubObjectIterator{PointVector{ZZRingElem}}
"""
solve_non_negative(
as::Type{T}, A::ZZMatrix, b::ZZMatrix; permit_unbounded=false
-) where {T} = solve_mixed(T, A, b, identity_matrix(FlintZZ, ncols(A)); permit_unbounded)
+) where {T} = solve_mixed(T, A, b, identity_matrix(ZZ, ncols(A)); permit_unbounded)
solve_non_negative(A::ZZMatrix, b::ZZMatrix; permit_unbounded=false) =
solve_non_negative(ZZMatrix, A, b; permit_unbounded)
diff --git a/src/PolyhedralGeometry/triangulations.jl b/src/PolyhedralGeometry/triangulations.jl
index 774f29a27e00..084cf77e19af 100644
--- a/src/PolyhedralGeometry/triangulations.jl
+++ b/src/PolyhedralGeometry/triangulations.jl
@@ -471,7 +471,7 @@ Compute a triangulation of the square
```jldoctest
julia> C = cube(2);
-julia> cells = IncidenceMatrix([[1,2,3],[2,3,4]]);
+julia> cells = incidence_matrix([[1,2,3],[2,3,4]]);
julia> S = subdivision_of_points(C, cells)
Subdivision of points in ambient dimension 2
diff --git a/src/Rings/AbelianClosure.jl b/src/Rings/AbelianClosure.jl
index dd60211a93b8..76d38f6b6e4d 100644
--- a/src/Rings/AbelianClosure.jl
+++ b/src/Rings/AbelianClosure.jl
@@ -933,25 +933,22 @@ end
# Construct the map from `F` to an abelian closure `K` such that `gen(F)`
# is mapped to `x`.
-# If `F` is a cyclotomic field with conductor `N` then assume that `gen(F)`
-# is mapped to `QQAbFieldElem(gen(F), N)`.
+# If `F` has conductor `N` then assume that `x.c == N` holds.
+# If `F` is a cyclotomic field with conductor `N` then assume that
+# `x == QQAbFieldElem(gen(F), N)`.
# (Use that the powers of this element form a basis of the field.)
function _embedding(F::QQField, K::QQAbField{AbsSimpleNumField},
x::QQAbFieldElem{AbsSimpleNumFieldElem})
- C1, z = cyclotomic_field(1)
+ C1, _ = cyclotomic_field(1)
f = function(x::QQFieldElem)
return QQAbFieldElem(C1(x), 1)
end
- finv = function(x::QQAbFieldElem; check::Bool = false)
- if conductor(x) == 1
- return Hecke.force_coerce_cyclo(C1, data(x))
- elseif check
- return
- else
- error("element has no preimage")
- end
+ finv = function(x::QQAbFieldElem; throw_error::Bool = true)
+ res = Hecke.force_coerce_cyclo(C1, data(x), Val(false))
+ throw_error && res === nothing && error("element has no preimage")
+ return res
end
return MapFromFunc(F, K, f, finv)
@@ -966,18 +963,14 @@ function _embedding(F::AbsSimpleNumField, K::QQAbField{AbsSimpleNumField},
return QQAbFieldElem(x, n)
end
- finv = function(x::QQAbFieldElem; check::Bool = false)
- if n % conductor(x) == 0
- return Hecke.force_coerce_cyclo(F, data(x))
- elseif check
- return
- else
- error("element has no preimage")
- end
+ finv = function(x::QQAbFieldElem; throw_error::Bool = true)
+ res = Hecke.force_coerce_cyclo(F, data(x), Val(false))
+ throw_error && res === nothing && error("element has no preimage")
+ return res
end
else
# `F` is expected to be a proper subfield of a cyclotomic field.
- n = conductor(x)
+ n = x.c
x = data(x)
Kn, = AbelianClosure.cyclotomic_field(K, n)
powers = [Hecke.coefficients(Hecke.force_coerce_cyclo(Kn, x^i))
@@ -989,25 +982,26 @@ function _embedding(F::AbsSimpleNumField, K::QQAbField{AbsSimpleNumField},
return QQAbFieldElem(evaluate(R(z), x), n)
end
- finv = function(x::QQAbFieldElem; check::Bool = false)
- n % conductor(x) == 0 || return false, zero(F)
+ finv = function(x::QQAbFieldElem; throw_error::Bool = true)
# Write `x` w.r.t. the n-th cyclotomic field ...
g = gcd(x.c, n)
Kg, = AbelianClosure.cyclotomic_field(K, g)
- x = Hecke.force_coerce_cyclo(Kg, data(x))
+ x = Hecke.force_coerce_cyclo(Kg, data(x), Val(false))
+ if x === nothing
+ throw_error && error("element has no preimage")
+ return
+ end
x = Hecke.force_coerce_cyclo(Kn, x)
# ... and then w.r.t. `F`
a = Hecke.coefficients(x)
fl, sol = can_solve_with_solution(c, matrix(QQ, length(a), 1, a); side = :right)
- if fl
- b = transpose(sol)
- b = [b[i] for i in 1:length(b)]
- return F(b)
- elseif check
+ if !fl
+ throw_error && error("element has no preimage")
return
- else
- error("element has no preimage")
end
+ b = transpose(sol)
+ b = [b[i] for i in 1:length(b)]
+ return F(b)
end
end
return MapFromFunc(F, K, f, finv)
@@ -1016,7 +1010,7 @@ end
# The following works only if `mp.g` admits a second argument,
# which is the case if `mp` has been constructed by `_embedding` above.
function has_preimage_with_preimage(mp::MapFromFunc{AbsSimpleNumField, QQAbField{AbsSimpleNumField}}, x::QQAbFieldElem{AbsSimpleNumFieldElem})
- pre = mp.g(x, check = true)
+ pre = mp.g(x, throw_error = false)
if isnothing(pre)
return false, zero(domain(mp))
else
diff --git a/src/Rings/FreeAssociativeAlgebraIdeal.jl b/src/Rings/FreeAssociativeAlgebraIdeal.jl
index 3547db25a148..60d41b63e628 100644
--- a/src/Rings/FreeAssociativeAlgebraIdeal.jl
+++ b/src/Rings/FreeAssociativeAlgebraIdeal.jl
@@ -173,10 +173,10 @@ julia> I = ideal([f1, f2]);
julia> gb = groebner_basis(I, 3; protocol=false)
Ideal generating system with elements
- 1 -> x*y + y*z
- 2 -> x^2 + y^2
- 3 -> y^3 + y*z^2
- 4 -> y^2*x + y*z*y
+ 1: x*y + y*z
+ 2: x^2 + y^2
+ 3: y^3 + y*z^2
+ 4: y^2*x + y*z*y
```
"""
function groebner_basis(I::FreeAssociativeAlgebraIdeal,
diff --git a/src/Rings/MPolyMap/MPolyRing.jl b/src/Rings/MPolyMap/MPolyRing.jl
index 0b3b9b6044ea..e8cd05b41b89 100644
--- a/src/Rings/MPolyMap/MPolyRing.jl
+++ b/src/Rings/MPolyMap/MPolyRing.jl
@@ -152,6 +152,11 @@ function _allunique(lst::Vector{T}) where {T<:RingElem}
return all(!(x in lst[i+1:end]) for (i, x) in enumerate(lst))
end
+function _allunique(lst::Vector{T}) where {T<:MPolyQuoRingElem}
+ rep_list = lift.(lst)
+ return _allunique(rep_list)
+end
+
function _build_poly(u::MPolyRingElem, indices::Vector{Int}, S::MPolyRing)
kk = coefficient_ring(S)
r = ngens(S)
@@ -263,6 +268,7 @@ function _evaluate_help(F::MPolyAnyMap{<: MPolyRing}, g)
end
function (F::MPolyAnyMap{<: MPolyRing})(g)
+ parent(g) === domain(F) || return F(domain(F)(g))
if g isa elem_type(domain(F))
if coefficient_map(F) === nothing
return _evaluate_plain(F, g)
diff --git a/src/Rings/MPolyQuo.jl b/src/Rings/MPolyQuo.jl
index 79f407830116..fe521d51dba1 100644
--- a/src/Rings/MPolyQuo.jl
+++ b/src/Rings/MPolyQuo.jl
@@ -79,6 +79,14 @@ oscar_origin_ring(Q::MPolyQuoRing) = base_ring(Q)
default_ordering(Q::MPolyQuoRing) = default_ordering(base_ring(Q))
+# Only for fields for now because of things like char(ZZ[x, y]/<2>) = 2
+function characteristic(Q::MPolyQuoRing{<:MPolyRingElem{T}}) where {T <: FieldElement}
+ if is_zero(one(Q))
+ return 1
+ end
+ return characteristic(coefficient_ring(Q))
+end
+
##############################################################################
#
# Quotient ring elements
@@ -1100,6 +1108,33 @@ end
one(Q::MPolyQuoRing) = Q(1)
+@doc raw"""
+ is_invertible_with_inverse(f::MPolyQuoRingElem)
+
+If `f` is invertible with inverse `g`, say, return `(true, g)`. Otherwise, return `(false, f)`.
+
+# Examples
+
+```jldoctest
+julia> R, c = polynomial_ring(QQ, :c => (1:3));
+
+julia> R, c = grade(R, [1, 2, 3]);
+
+julia> I = ideal(R, [ -c[1]^3 + 2*c[1]*c[2] - c[3], c[1]^4 - 3*c[1]^2*c[2] + 2*c[1]*c[3] + c[2]^2,-c[1]^5 + 4*c[1]^3*c[2] - 3*c[1]^2*c[3] - 3*c[1]*c[2]^2 + 2*c[2]*c[3]]);
+
+julia> A, _ = quo(R, I);
+
+julia> f = A(c[1]^2 - c[1] - c[2] + 1)
+c[1]^2 - c[1] - c[2] + 1
+
+julia> tt, g = is_invertible_with_inverse(f)
+(true, c[1] + c[2] + c[3] + 1)
+
+julia> f*g
+1
+
+```
+"""
function is_invertible_with_inverse(a::MPolyQuoRingElem)
# TODO:
# Eventually, the code below should be replaced
@@ -1111,6 +1146,11 @@ function is_invertible_with_inverse(a::MPolyQuoRingElem)
Q = parent(a)
J = oscar_groebner_basis(Q)
J = vcat(J, [a.f])
+
+ if Q isa MPolyQuoRing{<:MPolyDecRingElem}
+ J = [x.f for x in J]
+ end
+
j, T = standard_basis_with_transformation_matrix(ideal(J))
if is_constant(j[1]) && is_unit(first(coefficients(j[1])))
@assert ncols(T) == 1
@@ -1121,6 +1161,28 @@ end
is_unit(a::MPolyQuoRingElem) = is_invertible_with_inverse(a)[1]
+@doc raw"""
+ inv(f::MPolyQuoRingElem)
+
+If `f` is invertible, return its inverse. Otherwise, throw an error.
+
+# Examples
+
+```jldoctest
+julia> R, c = polynomial_ring(QQ, :c => (1:3));
+
+julia> I = ideal(R, [ -c[1]^3 + 2*c[1]*c[2] - c[3], c[1]^4 - 3*c[1]^2*c[2] + 2*c[1]*c[3] + c[2]^2,-c[1]^5 + 4*c[1]^3*c[2] - 3*c[1]^2*c[3] - 3*c[1]*c[2]^2 + 2*c[2]*c[3]]);
+
+julia> A, _ = quo(R, I);
+
+julia> f = A(c[1]^2 - c[1] - c[2] + 1)
+c[1]^2 - c[1] - c[2] + 1
+
+julia> inv(f)
+c[1] + c[2] + c[3] + 1
+
+```
+"""
function inv(a::MPolyQuoRingElem)
fl, b = is_invertible_with_inverse(a)
fl || error("Element not invertible")
diff --git a/src/Rings/NumberField.jl b/src/Rings/NumberField.jl
index 4f3e651d85ef..85a3e0c8549f 100644
--- a/src/Rings/NumberField.jl
+++ b/src/Rings/NumberField.jl
@@ -138,7 +138,7 @@ parent(a::NfNSGenElem) = a.parent
Hecke.data(a::NfNSGenElem) = a.f
-base_field(K::NfNSGen{QQFieldElem, QQMPolyRingElem}) = FlintQQ
+base_field(K::NfNSGen{QQFieldElem, QQMPolyRingElem}) = QQ
base_field(K::NfNSGen) = base_ring(polynomial_ring(K))
@@ -616,7 +616,7 @@ end
function basis_matrix(v::Vector{NfNSGenElem{QQFieldElem, QQMPolyRingElem}},
::Type{Hecke.FakeFmpqMat})
d = degree(parent(v[1]))
- z = zero_matrix(FlintQQ, length(v), d)
+ z = zero_matrix(QQ, length(v), d)
for i in 1:length(v)
elem_to_mat_row!(z, i, v[i])
end
diff --git a/src/Rings/PBWAlgebra.jl b/src/Rings/PBWAlgebra.jl
index 515989d88413..b692649288a9 100644
--- a/src/Rings/PBWAlgebra.jl
+++ b/src/Rings/PBWAlgebra.jl
@@ -1,4 +1,3 @@
-# Use attribute :is_weyl_algebra to permit better printing (see expressify, below)
@attributes mutable struct PBWAlgRing{T, S} <: NCRing
sring::Singular.PluralRing{S}
relations::Singular.smatrix{Singular.spoly{S}}
@@ -85,28 +84,31 @@ end
@enable_all_show_via_expressify PBWAlgElem
-function expressify(a::PBWAlgRing; context = nothing)
+function show(io::IO, a::PBWAlgRing)
+ @show_name(io, a)
+ @show_special(io, a)
x = symbols(a)
n = length(x)
- # Next if stmt handles special printing for Weyl algebras
- if get_attribute(a, :is_weyl_algebra) === :true
- return Expr(:sequence, Expr(:text, "Weyl-algebra over "),
- expressify(coefficient_ring(a); context=context),
- Expr(:text, " in variables ("),
- Expr(:series, first(x,div(n,2))...),
- Expr(:text, ")"))
- end
- rel = [Expr(:call, :(==), Expr(:call, :*, x[j], x[i]), expressify(a.relations[i,j]))
+ io = pretty(io)
+ rel = [AbstractAlgebra.PrettyPrinting.canonicalize(Expr(:call, :(==), Expr(:call, :*, x[j], x[i]), expressify(a.relations[i,j])))
for i in 1:n-1 for j in i+1:n]
- return Expr(:sequence, Expr(:text, "PBW-algebra over "),
- expressify(coefficient_ring(a); context=context),
- Expr(:text, " in "),
- Expr(:series, x...),
- Expr(:text, " with relations "),
- Expr(:series, rel...))
+ print(io, LowercaseOff(), "PBW-algebra over ", Lowercase(), coefficient_ring(a))
+ print(io, " in ")
+ join(io, x, ", ")
+ print(io, " with relations ")
+ AbstractAlgebra.show_obj(io, MIME("text/plain"), Expr(:series, rel...))
end
-@enable_all_show_via_expressify PBWAlgRing
+# handles special printing for Weyl algebras
+function show_weyl_algebra(io::IO, a::PBWAlgRing)
+ x = symbols(a)
+ n = length(x)
+ io = pretty(io)
+ print(io, LowercaseOff(), "Weyl-algebra over ", Lowercase(), coefficient_ring(a))
+ print(io, " in variables (")
+ join(io, first(x, div(n, 2)), ", ")
+ print(io, ")")
+end
#### AA prefix here because these all use the ordering in the parent
@@ -266,14 +268,17 @@ function one(R::PBWAlgRing)
end
function Base.:(==)(a::PBWAlgElem, b::PBWAlgElem)
+ check_parent(a, b)
return a.sdata == b.sdata
end
function Base.:+(a::PBWAlgElem, b::PBWAlgElem)
+ check_parent(a, b)
return PBWAlgElem(parent(a), a.sdata + b.sdata)
end
function Base.:-(a::PBWAlgElem, b::PBWAlgElem)
+ check_parent(a, b)
return PBWAlgElem(parent(a), a.sdata - b.sdata)
end
@@ -282,7 +287,8 @@ function Base.:-(a::PBWAlgElem)
end
function Base.:*(a::PBWAlgElem, b::PBWAlgElem)
- return PBWAlgElem(parent(a), a.sdata*b.sdata)
+ check_parent(a, b)
+ return PBWAlgElem(parent(a), a.sdata * b.sdata)
end
function Base.:^(a::PBWAlgElem, b::Int)
@@ -424,7 +430,7 @@ julia> L = [x*y, x*z, y*z + 1];
julia> REL = strictly_upper_triangular_matrix(L);
julia> A, (x, y, z) = pbw_algebra(R, REL, deglex(gens(R)))
-(PBW-algebra over Rational field in x, y, z with relations y*x = x*y, z*x = x*z, z*y = y*z + 1, PBWAlgElem{QQFieldElem, Singular.n_Q}[x, y, z])
+(PBW-algebra over rational field in x, y, z with relations y*x = x*y, z*x = x*z, z*y = y*z + 1, PBWAlgElem{QQFieldElem, Singular.n_Q}[x, y, z])
```
"""
function pbw_algebra(r::MPolyRing{T}, rel, ord::MonomialOrdering; check::Bool = true) where T
@@ -478,7 +484,8 @@ function weyl_algebra(K::Ring, xs::Vector{Symbol}, dxs::Vector{Symbol})
r, v = polynomial_ring(K, vcat(xs, dxs); cached = false)
rel = elem_type(r)[v[i]*v[j] + (j == i + n) for i in 1:2*n-1 for j in i+1:2*n]
R,vars = pbw_algebra(r, strictly_upper_triangular_matrix(rel), default_ordering(r); check = false)
- set_attribute!(R, :is_weyl_algebra, :true) # to activate special printing for Weyl algebras
+ set_attribute!(R, :is_weyl_algebra, :true)
+ set_attribute!(R, :show, show_weyl_algebra) # to activate special printing for Weyl algebras
return (R,vars)
end
@@ -500,7 +507,7 @@ The generators of the returned algebra print according to the entries of `xs`. S
# Examples
```jldoctest
julia> D, (x, y, dx, dy) = weyl_algebra(QQ, [:x, :y])
-(Weyl-algebra over Rational field in variables (x, y), PBWAlgElem{QQFieldElem, Singular.n_Q}[x, y, dx, dy])
+(Weyl-algebra over rational field in variables (x, y), PBWAlgElem{QQFieldElem, Singular.n_Q}[x, y, dx, dy])
julia> dx*x
x*dx + 1
@@ -515,13 +522,11 @@ end
####
-function expressify(a::PBWAlgOppositeMap; context = nothing)
- return Expr(:sequence, Expr(:text, "Map to opposite of "),
- expressify(a.source; context=context))
+function Base.show(io::IO, a::PBWAlgOppositeMap)
+ io = pretty(io)
+ print(io, "Map to opposite of ", Lowercase(), a.source)
end
-@enable_all_show_via_expressify PBWAlgOppositeMap
-
function _opposite(a::PBWAlgRing{T, S}) where {T, S}
if !isdefined(a, :opposite)
ptr = Singular.libSingular.rOpposite(a.sring.ptr)
@@ -549,15 +554,15 @@ Return the opposite algebra of `A`.
# Examples
```jldoctest
julia> D, (x, y, dx, dy) = weyl_algebra(QQ, [:x, :y])
-(Weyl-algebra over Rational field in variables (x, y), PBWAlgElem{QQFieldElem, Singular.n_Q}[x, y, dx, dy])
+(Weyl-algebra over rational field in variables (x, y), PBWAlgElem{QQFieldElem, Singular.n_Q}[x, y, dx, dy])
julia> Dop, opp = opposite_algebra(D);
julia> Dop
-PBW-algebra over Rational field in dy, dx, y, x with relations dx*dy = dy*dx, y*dy = dy*y + 1, x*dy = dy*x, y*dx = dx*y, x*dx = dx*x + 1, x*y = y*x
+PBW-algebra over rational field in dy, dx, y, x with relations dx*dy = dy*dx, y*dy = dy*y + 1, x*dy = dy*x, y*dx = dx*y, x*dx = dx*x + 1, x*y = y*x
julia> opp
-Map to opposite of Weyl-algebra over Rational field in variables (x, y)
+Map to opposite of Weyl-algebra over rational field in variables (x, y)
julia> opp(dx*x)
dx*x + 1
@@ -640,7 +645,7 @@ julia> L = [x*y, x*z, y*z + 1];
julia> REL = strictly_upper_triangular_matrix(L);
julia> A, (x, y, z) = pbw_algebra(R, REL, deglex(gens(R)))
-(PBW-algebra over Rational field in x, y, z with relations y*x = x*y, z*x = x*z, z*y = y*z + 1, PBWAlgElem{QQFieldElem, Singular.n_Q}[x, y, z])
+(PBW-algebra over rational field in x, y, z with relations y*x = x*y, z*x = x*z, z*y = y*z + 1, PBWAlgElem{QQFieldElem, Singular.n_Q}[x, y, z])
julia> I = left_ideal(A, [x^2*y^2, x*z+y*z])
left_ideal(x^2*y^2, x*z + y*z)
@@ -744,7 +749,7 @@ Return `true` if `I` is the zero ideal, `false` otherwise.
# Examples
```jldoctest
julia> D, (x, y, dx, dy) = weyl_algebra(QQ, [:x, :y])
-(Weyl-algebra over Rational field in variables (x, y), PBWAlgElem{QQFieldElem, Singular.n_Q}[x, y, dx, dy])
+(Weyl-algebra over rational field in variables (x, y), PBWAlgElem{QQFieldElem, Singular.n_Q}[x, y, dx, dy])
julia> I = left_ideal(D, [x, dx])
left_ideal(x, dx)
@@ -774,7 +779,7 @@ Return `true` if `I` is generated by `1`, `false` otherwise.
# Examples
```jldoctest
julia> D, (x, y, dx, dy) = weyl_algebra(QQ, [:x, :y])
-(Weyl-algebra over Rational field in variables (x, y), PBWAlgElem{QQFieldElem, Singular.n_Q}[x, y, dx, dy])
+(Weyl-algebra over rational field in variables (x, y), PBWAlgElem{QQFieldElem, Singular.n_Q}[x, y, dx, dy])
julia> I = left_ideal(D, [x, dx])
left_ideal(x, dx)
@@ -1271,7 +1276,7 @@ julia> L = [x*y-z, x*z+2*x, x*a, y*z-2*y, y*a, z*a];
julia> REL = strictly_upper_triangular_matrix(L);
julia> A, (x, y, z, a) = pbw_algebra(R, REL, deglex(gens(R)))
-(PBW-algebra over Rational field in x, y, z, a with relations y*x = x*y - z, z*x = x*z + 2*x, a*x = x*a, z*y = y*z - 2*y, a*y = y*a, a*z = z*a, PBWAlgElem{QQFieldElem, Singular.n_Q}[x, y, z, a])
+(PBW-algebra over rational field in x, y, z, a with relations y*x = x*y - z, z*x = x*z + 2*x, a*x = x*a, z*y = y*z - 2*y, a*y = y*a, a*z = z*a, PBWAlgElem{QQFieldElem, Singular.n_Q}[x, y, z, a])
julia> f = 4*x*y+z^2-2*z-a;
@@ -1296,7 +1301,7 @@ julia> L = [p*q+q^2];
julia> REL = strictly_upper_triangular_matrix(L);
julia> A, (p, q) = pbw_algebra(R, REL, lex(gens(R)))
-(PBW-algebra over Rational field in p, q with relations q*p = p*q + q^2, PBWAlgElem{QQFieldElem, Singular.n_Q}[p, q])
+(PBW-algebra over rational field in p, q with relations q*p = p*q + q^2, PBWAlgElem{QQFieldElem, Singular.n_Q}[p, q])
julia> I = left_ideal(A, [p, q])
left_ideal(p, q)
diff --git a/src/Rings/PBWAlgebraQuo.jl b/src/Rings/PBWAlgebraQuo.jl
index a717e729c19d..8f2635c4b851 100644
--- a/src/Rings/PBWAlgebraQuo.jl
+++ b/src/Rings/PBWAlgebraQuo.jl
@@ -33,16 +33,20 @@ export PBWAlgQuo, PBWAlgQuoElem
###### @attributes ### DID NOT WORK -- alternative solution found (via has_special_impl, see ExteriorAlgebra.jl)
-mutable struct PBWAlgQuo{T, S} <: NCRing
+@attributes mutable struct PBWAlgQuo{T, S} <: NCRing
I::PBWAlgIdeal{0, T, S}
sring::Singular.PluralRing{S} # For ExtAlg this is the Singular impl; o/w same as I.basering.sring
+
+ function PBWAlgQuo(I::PBWAlgIdeal{0, T, S}, sring::Singular.PluralRing{S}) where {T, S}
+ return new{T, S}(I, sring)
+ end
end
# For backward compatibility: ctor with 1 arg:
# uses "default" arith impl -- namely that from basering!
function PBWAlgQuo(I::PBWAlgIdeal{0, T, S}) where {T, S}
- return PBWAlgQuo{T, S}(I, I.basering.sring)
+ return PBWAlgQuo(I, I.basering.sring)
end
@@ -93,27 +97,12 @@ end
@enable_all_show_via_expressify PBWAlgQuoElem
-function expressify(Q::PBWAlgQuo; context = nothing) # what about new sring data-field ???
- ## special printing if Q is an exterior algebra
-###### if get_attribute(Q, :is_exterior_algebra) === :true
- if has_special_impl(Q)
- a = Q.I.basering
- x = symbols(a)
- n = length(x)
- return Expr(:sequence, Expr(:text, "Exterior algebra over "),
- expressify(coefficient_ring(a); context=context),
- Expr(:text, " in ("),
- Expr(:series, x...),
- Expr(:text, ")"))
-
- end
- # General case (not exterior algebra)
- return Expr(:call, :/, expressify(Q.I.basering; context = nothing),
- expressify(Q.I; context = nothing))
+function Base.show(io::IO, Q::PBWAlgQuo)
+ @show_name(io, Q)
+ @show_special(io, Q)
+ print(io, "(", base_ring(Q), ")/", modulus(Q))
end
-@enable_all_show_via_expressify PBWAlgQuo
-
####
function number_of_generators(Q::PBWAlgQuo)
@@ -169,12 +158,12 @@ function Base.:(==)(a::PBWAlgQuoElem, b::PBWAlgQuoElem)
end
function Base.:+(a::PBWAlgQuoElem, b::PBWAlgQuoElem)
- @assert parent(a) == parent(b)
+ check_parent(a, b)
return PBWAlgQuoElem(parent(a), a.data + b.data)
end
function Base.:-(a::PBWAlgQuoElem, b::PBWAlgQuoElem)
- @assert parent(a) == parent(b)
+ check_parent(a, b)
return PBWAlgQuoElem(parent(a), a.data - b.data)
end
@@ -183,7 +172,8 @@ function Base.:-(a::PBWAlgQuoElem)
end
function Base.:*(a::PBWAlgQuoElem, b::PBWAlgQuoElem)
- return PBWAlgQuoElem(parent(a), a.data*b.data)
+ check_parent(a, b)
+ return PBWAlgQuoElem(parent(a), a.data * b.data)
end
function Base.:^(a::PBWAlgQuoElem, b::Int)
@@ -215,7 +205,7 @@ julia> L = [-x*y, -x*z, -y*z];
julia> REL = strictly_upper_triangular_matrix(L);
julia> A, (x, y, z) = pbw_algebra(R, REL, deglex(gens(R)))
-(PBW-algebra over Rational field in x, y, z with relations y*x = -x*y, z*x = -x*z, z*y = -y*z, PBWAlgElem{QQFieldElem, Singular.n_Q}[x, y, z])
+(PBW-algebra over rational field in x, y, z with relations y*x = -x*y, z*x = -x*z, z*y = -y*z, PBWAlgElem{QQFieldElem, Singular.n_Q}[x, y, z])
julia> I = two_sided_ideal(A, [x^2, y^2, z^2])
two_sided_ideal(x^2, y^2, z^2)
@@ -223,12 +213,12 @@ two_sided_ideal(x^2, y^2, z^2)
julia> Q, q = quo(A, I);
julia> Q
-(PBW-algebra over Rational field in x, y, z with relations y*x = -x*y, z*x = -x*z, z*y = -y*z)/two_sided_ideal(x^2, y^2, z^2)
+(PBW-algebra over rational field in x, y, z with relations y*x = -x*y, z*x = -x*z, z*y = -y*z)/two_sided_ideal(x^2, y^2, z^2)
julia> q
Map defined by a julia-function with inverse
- from pBW-algebra over Rational field in x, y, z with relations y*x = -x*y, z*x = -x*z, z*y = -y*z
- to (PBW-algebra over Rational field in x, y, z with relations y*x = -x*y, z*x = -x*z, z*y = -y*z)/two_sided_ideal(x^2, y^2, z^2)
+ from PBW-algebra over rational field in x, y, z with relations y*x = -x*y, z*x = -x*z, z*y = -y*z
+ to (PBW-algebra over rational field in x, y, z with relations y*x = -x*y, z*x = -x*z, z*y = -y*z)/two_sided_ideal(x^2, y^2, z^2)
```
!!! note
diff --git a/src/Rings/Rings.jl b/src/Rings/Rings.jl
index 2a0d9ad474f8..4c25c36d612b 100644
--- a/src/Rings/Rings.jl
+++ b/src/Rings/Rings.jl
@@ -5,7 +5,7 @@ include("mpoly_types.jl")
include("mpoly-graded.jl")
include("hilbert_zach.jl")
include("mpoly-ideals.jl")
-include("groebner.jl")
+include("groebner/groebner.jl")
include("solving.jl")
include("MPolyQuo.jl")
include("FractionalIdeal.jl")
diff --git a/src/Rings/binomial_ideals.jl b/src/Rings/binomial_ideals.jl
index c9dd600ef8eb..1cfa6e0d0bfb 100644
--- a/src/Rings/binomial_ideals.jl
+++ b/src/Rings/binomial_ideals.jl
@@ -393,7 +393,7 @@ function (Chi::PartialCharacter)(b::ZZMatrix)
end
function (Chi::PartialCharacter)(b::Vector{ZZRingElem})
- return Chi(matrix(FlintZZ, 1, length(b), b))
+ return Chi(matrix(ZZ, 1, length(b), b))
end
function have_same_domain(P::PartialCharacter, Q::PartialCharacter)
@@ -482,7 +482,7 @@ function ideal_from_character(P::PartialCharacter, R::MPolyRing)
@assert ncols(P.A) == nvars(R)
#test if the domain of the partial character is the zero lattice
- if isone(nrows(P.A)) && have_same_span(P.A, zero_matrix(FlintZZ, 1, ncols(P.A)))
+ if isone(nrows(P.A)) && have_same_span(P.A, zero_matrix(ZZ, 1, ncols(P.A)))
return ideal(R, zero(R))
end
@@ -582,7 +582,7 @@ function partial_character_from_ideal(I::MPolyIdeal, R::MPolyRing)
Delta = cell[2] #cell variables
if isempty(Delta)
- return partial_character(zero_matrix(FlintZZ, 1, nvars(R)), [one(QQAb)], Set{Int64}())
+ return partial_character(zero_matrix(ZZ, 1, nvars(R)), [one(QQAb)], Set{Int64}())
end
#now consider the case where Delta is not empty
@@ -598,12 +598,12 @@ function partial_character_from_ideal(I::MPolyIdeal, R::MPolyRing)
end
QQAbcl, = abelian_closure(QQ)
if iszero(J)
- return partial_character(zero_matrix(FlintZZ, 1, nvars(R)), [one(QQAbcl)], Set{Int64}())
+ return partial_character(zero_matrix(ZZ, 1, nvars(R)), [one(QQAbcl)], Set{Int64}())
end
#now case if J \neq 0
#let ts be a list of minimal binomial generators for J
gb = groebner_basis(J, complete_reduction = true)
- vs = zero_matrix(FlintZZ, 0, nvars(R))
+ vs = zero_matrix(ZZ, 0, nvars(R))
images = QQAbFieldElem{AbsSimpleNumFieldElem}[]
for t in gb
#TODO: Once tail will be available, use it.
@@ -612,7 +612,7 @@ function partial_character_from_ideal(I::MPolyIdeal, R::MPolyRing)
u = exponent_vector(lm, 1)
v = exponent_vector(tl, 1)
#now test if we need the vector uv
- uv = matrix(FlintZZ, 1, nvars(R), Int[u[j]-v[j] for j =1:length(u)]) #this is the vector of u-v
+ uv = matrix(ZZ, 1, nvars(R), Int[u[j]-v[j] for j =1:length(u)]) #this is the vector of u-v
#TODO: It can be done better by saving the hnf...
if !can_solve(vs, uv, side = :left)[1]
push!(images, -QQAbcl(AbstractAlgebra.leading_coefficient(tl)))
@@ -1162,7 +1162,7 @@ function birth_death_ideal(m::Int, n::Int)
R = Matrix{QQMPolyRingElem}(undef, m, n+1)
D = Matrix{QQMPolyRingElem}(undef, m+1, m)
L = Matrix{QQMPolyRingElem}(undef, m+1, n+1)
- Qxy, gQxy = polynomial_ring(FlintQQ, length(U)+length(R)+length(D)+length(L); cached = false)
+ Qxy, gQxy = polynomial_ring(QQ, length(U)+length(R)+length(D)+length(L); cached = false)
pols = Vector{elem_type(Qxy)}(undef, 4*n*m)
ind = 1
for i = 1:m+1
diff --git a/src/Rings/groebner.jl b/src/Rings/groebner.jl
deleted file mode 100644
index 1a0feb6626d6..000000000000
--- a/src/Rings/groebner.jl
+++ /dev/null
@@ -1,1780 +0,0 @@
-# groebner stuff #######################################################
-@doc raw"""
- groebner_assure(I::MPolyIdeal, complete_reduction::Bool = false, need_global::Bool = false)
- groebner_assure(I::MPolyIdeal, ordering::MonomialOrdering, complete_reduction::Bool = false)
-
-**Note**: Internal function, subject to change, do not use.
-
-Given an ideal `I` in a multivariate polynomial ring this function assures that a
-Gröbner basis w.r.t. the given monomial ordering is attached to `I` in `I.gb`.
-It *currently* also ensures that the basis is defined on the Singular side in
-`I.gb.S`, but this should not be relied upon: use `singular_assure(I.gb)` before
-accessing `I.gb.S`.
-
-# Examples
-```jldoctest
-julia> R,(x,y) = polynomial_ring(QQ, [:x,:y])
-(Multivariate polynomial ring in 2 variables over QQ, QQMPolyRingElem[x, y])
-
-julia> I = ideal([x*y-3*x,y^3-2*x^2*y])
-Ideal generated by
- x*y - 3*x
- -2*x^2*y + y^3
-
-julia> Oscar.groebner_assure(I, degrevlex(R));
-
-julia> I.gb[degrevlex(R)]
-Gröbner basis with elements
- 1 -> x*y - 3*x
- 2 -> y^3 - 6*x^2
- 3 -> 2*x^3 - 9*x
-with respect to the ordering
- degrevlex([x, y])
-```
-"""
-function groebner_assure(I::MPolyIdeal, complete_reduction::Bool = false, need_global::Bool = false)
- if !isempty(I.gb)
- for G in values(I.gb)
- need_global || return G
- is_global(G.ord) || continue
- complete_reduction || return G
- if !G.isReduced
- I.gb[G.ord] = _compute_standard_basis(G, G.ord, true)
- end
- return I.gb[G.ord]
- end
- end
- ord = default_ordering(base_ring(I))
- (need_global <= is_global(ord)) || error("Monomial ordering must be global.")
- I.gb[ord] = groebner_assure(I, ord, complete_reduction)
- return I.gb[ord]
-end
-
-function groebner_assure(I::MPolyIdeal, ordering::MonomialOrdering, complete_reduction::Bool = false)
- return get!(I.gb, ordering) do
- _compute_standard_basis(I.gens, ordering, complete_reduction)
- end
-end
-
-function oscar_groebner_generators(I::MPolyIdeal, ordering::MonomialOrdering = default_ordering(base_ring(I)), complete_reduction::Bool = false)
- standard_basis(I, ordering=ordering, complete_reduction = complete_reduction)
- oscar_assure(I.gb[ordering])
- return I.gb[ordering].gens.O
-end
-
-function singular_groebner_generators(I::MPolyIdeal, ordering::MonomialOrdering = default_ordering(base_ring(I)), complete_reduction::Bool = false)
- standard_basis(I, ordering=ordering, complete_reduction = complete_reduction)
- return singular_generators(I.gb[ordering], ordering)
-end
-
-function singular_groebner_generators(I::MPolyIdeal, complete_reduction::Bool, need_global::Bool)
- G = groebner_assure(I, complete_reduction, need_global)
- return singular_generators(G, G.ord)
-end
-
-@doc raw"""
- _compute_standard_basis(B::IdealGens; ordering::MonomialOrdering,
- complete_reduction::Bool = false)
-
-**Note**: Internal function, subject to change, do not use.
-
-Given an `IdealGens` `B` and optional parameters `ordering` for a monomial ordering and `complete_reduction`
-this function computes a Gröbner basis (if `complete_reduction = true` the reduced Gröbner basis) of the
-ideal spanned by the elements in `B` w.r.t. the given monomial ordering `ordering`. The Gröbner basis is then
-returned in `B.S`.
-
-# Examples
-```jldoctest
-julia> R,(x,y) = polynomial_ring(QQ, [:x,:y])
-(Multivariate polynomial ring in 2 variables over QQ, QQMPolyRingElem[x, y])
-
-julia> A = Oscar.IdealGens([x*y-3*x,y^3-2*x^2*y])
-Ideal generating system with elements
- 1 -> x*y - 3*x
- 2 -> -2*x^2*y + y^3
-
-julia> B = Oscar._compute_standard_basis(A, degrevlex(R))
-Gröbner basis with elements
- 1 -> x*y - 3*x
- 2 -> y^3 - 6*x^2
- 3 -> 2*x^3 - 9*x
-with respect to the ordering
- degrevlex([x, y])
-```
-"""
-function _compute_standard_basis(B::IdealGens, ordering::MonomialOrdering, complete_reduction::Bool = false)
- gensSord = singular_generators(B, ordering)
- i = Singular.std(gensSord, complete_reduction = complete_reduction)
- BA = IdealGens(B.Ox, i, complete_reduction)
- BA.isGB = true
- BA.ord = ordering
- if isdefined(BA, :S)
- BA.S.isGB = true
- end
- return BA
-end
-
-# standard basis for non-global orderings #############################
-@doc raw"""
- standard_basis(I::MPolyIdeal; ordering::MonomialOrdering = default_ordering(base_ring(I)),
- complete_reduction::Bool = false, algorithm::Symbol = :buchberger)
-
-Return a standard basis of `I` with respect to `ordering`.
-
-The keyword `algorithm` can be set to
-- `:buchberger` (implementation of Buchberger's algorithm in *Singular*),
-- `:f4` (implementation of Faugère's F4 algorithm in the *msolve* package),
-- `:fglm` (implementation of the FGLM algorithm in *Singular*),
-- `:hc` (implementation of Buchberger's algorithm in *Singular* trying to first compute the highest corner modulo some prime), and
-- `:hilbert` (implementation of a Hilbert driven Gröbner basis computation in *Singular*).
-
-!!! note
- See the description of the functions `groebner_basis_hilbert_driven`, `fglm`,
- and `f4` in the OSCAR documentation for some more details and for restrictions
- on the input data when using these versions of the standard basis algorithm.
-
-!!! note
- The returned standard basis is reduced if `ordering` is `global` and `complete_reduction = true`.
-
-# Examples
-```jldoctest
-julia> R,(x,y) = polynomial_ring(QQ, [:x,:y]);
-
-julia> I = ideal([x*(x+1), x^2-y^2+(x-2)*y]);
-
-julia> standard_basis(I, ordering = negdegrevlex(R))
-Standard basis with elements
- 1 -> x
- 2 -> y
-with respect to the ordering
- negdegrevlex([x, y])
-```
-"""
-function standard_basis(I::MPolyIdeal; ordering::MonomialOrdering = default_ordering(base_ring(I)),
- complete_reduction::Bool = false, algorithm::Symbol = :buchberger)
- complete_reduction && @assert is_global(ordering)
- @req is_exact_type(elem_type(base_ring(I))) "This functionality is only supported over exact fields."
- if haskey(I.gb, ordering) && (complete_reduction == false || I.gb[ordering].isReduced == true)
- return I.gb[ordering]
- end
- if algorithm == :buchberger
- if !haskey(I.gb, ordering)
- I.gb[ordering] = _compute_standard_basis(I.gens, ordering, complete_reduction)
- elseif complete_reduction == true
- I.gb[ordering] = _compute_standard_basis(I.gb[ordering], ordering, complete_reduction)
- end
- elseif algorithm == :fglm
- _compute_groebner_basis_using_fglm(I, ordering)
- elseif algorithm == :hc
- standard_basis_highest_corner(I, ordering=ordering)
- elseif algorithm == :hilbert
- weights = _find_weights(gens(I))
- if !any(iszero, weights)
- J, target_ordering, hn = I, ordering, nothing
- else
- R = base_ring(I)
- K = iszero(characteristic(R)) && !haskey(I.gb, degrevlex(R)) ? _mod_rand_prime(I) : I
- S = base_ring(K)
- gb = groebner_assure(K, degrevlex(S))
- # 2024-02-09 Next lines "blindly" updated to use new homogenization UI
- H = homogenizer(S, "w")
- K_hom = H(K)
- gb_hom = IdealGens(H.(gens(gb)))
- gb_hom.isGB = true
- K_hom.gb[degrevlex(S)] = gb_hom
- singular_assure(K_hom.gb[degrevlex(S)])
- hn = hilbert_series(quo(base_ring(K_hom), K_hom)[1])[1]
- H2 = homogenizer(R, "w")
- J = H2(I)
- weights = ones(Int, ngens(base_ring(J)))
- target_ordering = _extend_mon_order(ordering, base_ring(J))
- end
- GB = groebner_basis_hilbert_driven(J, destination_ordering=target_ordering,
- complete_reduction=complete_reduction,
- weights=weights,
- hilbert_numerator=hn)
- if base_ring(I) == base_ring(J)
- I.gb[ordering] = GB
- else
- DH2 = dehomogenizer(H2)
- GB_dehom_gens = DH2.(gens(GB))
- I.gb[ordering] = IdealGens(GB_dehom_gens, ordering, isGB = true)
- end
- elseif algorithm == :f4
- # since msolve v0.7.0 is most of the time more efficient
- # to compute a reduced GB by default
- groebner_basis_f4(I, complete_reduction=true)
- end
- return I.gb[ordering]
-end
-
-@doc raw"""
- groebner_basis(I::MPolyIdeal;
- ordering::MonomialOrdering = default_ordering(base_ring(I)),
- complete_reduction::Bool = false, algorithm::Symbol = :buchberger)
-
-If `ordering` is global, return a Gröbner basis of `I` with respect to `ordering`.
-
-The keyword `algorithm` can be set to
-- `:buchberger` (implementation of Buchberger's algorithm in *Singular*),
-- `:hilbert` (implementation of a Hilbert driven Gröbner basis computation in *Singular*),
-- `:fglm` (implementation of the FGLM algorithm in *Singular*), and
-- `:f4` (implementation of Faugère's F4 algorithm in the *msolve* package).
-
-!!! note
- See the description of the functions `groebner_basis_hilbert_driven`, `fglm`,
- and `f4` in the OSCAR documentation for some more details and for restrictions
- on the input data when using these versions of the standard basis algorithm.
-
-!!! note
- The returned Gröbner basis is reduced if `complete_reduction = true`.
-
-# Examples
-```jldoctest
-julia> R, (x, y, z) = polynomial_ring(QQ, [:x, :y, :z]);
-
-julia> I = ideal(R, [y-x^2, z-x^3]);
-
-julia> G = groebner_basis(I)
-Gröbner basis with elements
- 1 -> y^2 - x*z
- 2 -> x*y - z
- 3 -> x^2 - y
-with respect to the ordering
- degrevlex([x, y, z])
-
-julia> elements(G)
-3-element Vector{QQMPolyRingElem}:
- -x*z + y^2
- x*y - z
- x^2 - y
-
-julia> elements(G) == gens(G)
-true
-
-julia> groebner_basis(I, ordering = lex(R))
-Gröbner basis with elements
- 1 -> y^3 - z^2
- 2 -> x*z - y^2
- 3 -> x*y - z
- 4 -> x^2 - y
-with respect to the ordering
- lex([x, y, z])
-```
-```jldoctest
-julia> R, (x, y) = graded_polynomial_ring(QQ, [:x, :y], [1, 3]);
-
-julia> I = ideal(R, [x*y-3*x^4,y^3-2*x^6*y]);
-
-julia> groebner_basis(I)
-Gröbner basis with elements
- 1 -> 3*x^4 - x*y
- 2 -> 2*x^3*y^2 - 3*y^3
- 3 -> x*y^3
- 4 -> y^4
-with respect to the ordering
- wdegrevlex([x, y], [1, 3])
-```
-
-```jldoctest
-julia> R, (x, y, z) = polynomial_ring(QQ, [:x, :y, :z]);
-
-julia> V = [3*x^3*y+x^3+x*y^3+y^2*z^2, 2*x^3*z-x*y-x*z^3-y^4-z^2,
- 2*x^2*y*z-2*x*y^2+x*z^2-y^4];
-
-julia> I = ideal(R, V);
-
-julia> G = groebner_basis(I, ordering = lex(R), algorithm = :fglm);
-
-julia> length(G)
-8
-
-julia> total_degree(G[8])
-34
-
-julia> leading_coefficient(G[8])
--91230304237130414552564280286681870842473427917231798336639893796481988733936505735341479640589040146625319419037353645834346047404145021391726185993823650399589880820226804328750
-```
-"""
-function groebner_basis(I::MPolyIdeal; ordering::MonomialOrdering = default_ordering(base_ring(I)), complete_reduction::Bool=false,
- algorithm::Symbol = :buchberger)
- is_global(ordering) || error("Ordering must be global")
- return standard_basis(I, ordering=ordering, complete_reduction=complete_reduction, algorithm=algorithm)
-end
-
-@doc raw"""
- standard_basis_highest_corner(I::MPolyIdeal; ordering::MonomialOrdering = default_ordering(base_ring(I)))
-
-Return a standard basis of `I` with respect to `ordering`. `ordering` needs to be local, the coefficient ring needs to be `QQ`.
-The algorithm first computes a standard basis over a finite field in order to get an upper bound for the highest corner fast.
-Then this bound is used to speed up the standard basis computation over `QQ´.
-"""
-function standard_basis_highest_corner(I::MPolyIdeal; ordering::MonomialOrdering = default_ordering(base_ring(I)))
- @req is_local(ordering) "Monomial ordering must be local for this variant."
- @req coefficient_ring(I) == QQ "Base ring must be QQ."
-
- #= apply highest corner standard basis variant in Singular =#
- ssb = Singular.LibStandard.groebner(singular_groebner_generators(I, ordering), "HC")
-
- sb = IdealGens(I.gens.Ox, ssb, false)
- sb.isGB = true
- sb.ord = ordering
- if isdefined(sb, :S)
- sb.S.isGB = true
- end
- I.gb[ordering] = sb
- return sb
-end
-
-function is_f4_applicable(I::MPolyIdeal, ordering::MonomialOrdering)
- return (ordering == degrevlex(base_ring(I)) && !is_graded(base_ring(I))
- && ((coefficient_ring(I) isa FqField
- && absolute_degree(coefficient_ring(I)) == 1
- && characteristic(coefficient_ring(I)) < 2^31)
- || coefficient_ring(I) == QQ))
-end
-
-@doc raw"""
- groebner_basis_f4(I::MPolyIdeal, )
-
-Compute a Gröbner basis of `I` with respect to `degrevlex` using Faugère's F4 algorithm.
-See [Fau99](@cite) for more information.
-
-!!! note
- At current state only prime fields of characteristic `0 < p < 2^{31}` and the rationals are supported.
-
-# Possible keyword arguments
-- `initial_hts::Int=17`: initial hash table size `log_2`.
-- `nr_thrds::Int=1`: number of threads for parallel linear algebra.
-- `max_nr_pairs::Int=0`: maximal number of pairs per matrix, only bounded by minimal degree if `0`.
-- `la_option::Int=2`: linear algebra option: exact sparse-dense (`1`), exact sparse (`2`, default), probabilistic sparse-dense (`42`), probabilistic sparse(`44`).
-- `eliminate::Int=0`: size of first block of variables to be eliminated.
-- `complete_reduction::Bool=true`: compute a reduced Gröbner basis for `I`
-- `normalize::Bool=true`: normalizes elements in computed Gröbner basis for `I`
-- `truncate_lifting::Int=0`: degree up to which the elements of the Gröbner basis are lifted to `QQ`, `0` for complete lifting
-- `info_level::Int=0`: info level printout: off (`0`, default), summary (`1`), detailed (`2`).
-
-# Examples
-```jldoctest
-julia> R,(x,y,z) = polynomial_ring(GF(101), [:x,:y,:z])
-(Multivariate polynomial ring in 3 variables over GF(101), FqMPolyRingElem[x, y, z])
-
-julia> I = ideal(R, [x+2*y+2*z-1, x^2+2*y^2+2*z^2-x, 2*x*y+2*y*z-y])
-Ideal generated by
- x + 2*y + 2*z + 100
- x^2 + 100*x + 2*y^2 + 2*z^2
- 2*x*y + 2*y*z + 100*y
-
-julia> groebner_basis_f4(I)
-Gröbner basis with elements
- 1 -> x + 2*y + 2*z + 100
- 2 -> y*z + 82*z^2 + 10*y + 40*z
- 3 -> y^2 + 60*z^2 + 20*y + 81*z
- 4 -> z^3 + 28*z^2 + 64*y + 13*z
-with respect to the ordering
- degrevlex([x, y, z])
-```
-"""
-function groebner_basis_f4(
- I::MPolyIdeal;
- initial_hts::Int=17,
- nr_thrds::Int=1,
- max_nr_pairs::Int=0,
- la_option::Int=2,
- eliminate::Int=0,
- complete_reduction::Bool=true,
- normalize::Bool=true,
- truncate_lifting::Int=0,
- info_level::Int=0
- )
-
- AI = AlgebraicSolving.Ideal(I.gens.O)
- vars = gens(base_ring(I))[eliminate+1:end]
- ord = degrevlex(vars)
- if length(AI.gens) == 0
- I.gb[ord] = IdealGens(I.gens.Ox, singular_generators(I), complete_reduction)
- I.gb[ord].ord = ord
- I.gb[ord].isGB = true
- I.gb[ord].S.isGB = true
- else
- AlgebraicSolving.groebner_basis(AI,
- initial_hts = initial_hts,
- nr_thrds = nr_thrds,
- max_nr_pairs = max_nr_pairs,
- la_option = la_option,
- eliminate = eliminate,
- complete_reduction = complete_reduction,
- normalize = normalize,
- truncate_lifting = truncate_lifting,
- info_level = info_level)
-
- I.gb[ord] =
- IdealGens(AI.gb[eliminate], ord, keep_ordering = false, isGB = true)
- I.gb[ord].isReduced = complete_reduction
- end
- return I.gb[ord]
-end
-
-@doc raw"""
- _compute_standard_basis_with_transform(B::IdealGens, ordering::MonomialOrdering, complete_reduction::Bool = false)
-
-**Note**: Internal function, subject to change, do not use.
-
-Given an `IdealGens` `B` and optional parameters `ordering` for a monomial ordering and `complete_reduction`
-this function computes a standard basis (if `ordering` is a global monomial ordering and `complete_reduction = true`
-the reduced Gröbner basis) of the ideal spanned by the elements in `B` w.r.t. the given monomial ordering `ordering`
-and the transformation matrix from the ideal to the standard basis. Return value is a IdealGens together with a map.
-
-# Examples
-```jldoctest
-julia> R, (x, y) = polynomial_ring(QQ, [:x, :y])
-(Multivariate polynomial ring in 2 variables over QQ, QQMPolyRingElem[x, y])
-
-julia> A = Oscar.IdealGens([x*y-3*x,y^3-2*x^2*y])
-Ideal generating system with elements
- 1 -> x*y - 3*x
- 2 -> -2*x^2*y + y^3
-
-julia> B,m = Oscar._compute_standard_basis_with_transform(A, degrevlex(R))
-(Ideal generating system with 3 elements with associated ordering degrevlex([x, y]), [1 2*x -2*x^2+y^2+3*y+9; 0 1 -x])
-```
-"""
-function _compute_standard_basis_with_transform(B::IdealGens, ordering::MonomialOrdering, complete_reduction::Bool = false)
- istd, m = Singular.lift_std(singular_generators(B, ordering), complete_reduction = complete_reduction)
- return IdealGens(B.Ox, istd), map_entries(B.Ox, m)
-end
-
-@doc raw"""
- standard_basis_with_transformation_matrix(I::MPolyIdeal;
- ordering::MonomialOrdering = default_ordering(base_ring(I)),
- complete_reduction::Bool=false)
-
-Return a pair `G`, `T`, say, where `G` is a standard basis of `I` with respect to `ordering`, and `T`
-is a transformation matrix from `gens(I)` to `G`. That is, `gens(I)*T == G`.
-
-!!! note
- The returned Gröbner basis is reduced if `ordering` is a global monomial odering and `complete_reduction = true`.
-
-# Examples
-```jldoctest
-julia> R,(x,y) = polynomial_ring(QQ,[:x,:y]);
-
-julia> I = ideal([x*y^2-1,x^3+y^2+x*y]);
-
-julia> G, T = standard_basis_with_transformation_matrix(I, ordering=neglex(R))
-(Standard basis with 1 element w.r.t. neglex([x, y]), [-1; 0])
-
-julia> gens(I)*T == gens(G)
-true
-```
-"""
-function standard_basis_with_transformation_matrix(I::MPolyIdeal; ordering::MonomialOrdering = default_ordering(base_ring(I)), complete_reduction::Bool = false)
- complete_reduction && @assert is_global(ordering)
- G, m = _compute_standard_basis_with_transform(I.gens, ordering, complete_reduction)
- G.isGB = true
- I.gb[ordering] = G
- return G, m
-end
-
-@doc raw"""
- groebner_basis_with_transformation_matrix(I::MPolyIdeal;
- ordering::MonomialOrdering = default_ordering(base_ring(I)),
- complete_reduction::Bool=false)
-
-Return a pair `G`, `T`, say, where `G` is a Gröbner basis of `I` with respect to `ordering`, and `T`
-is a transformation matrix from `gens(I)` to `G`. That is, `gens(I)*T == G`.
-
-!!! note
- The returned Gröbner basis is reduced if `complete_reduction = true`.
-
-# Examples
-```jldoctest
-julia> R,(x,y) = polynomial_ring(QQ,[:x,:y]);
-
-julia> I = ideal([x*y^2-1,x^3+y^2+x*y]);
-
-julia> G, T = groebner_basis_with_transformation_matrix(I)
-(Gröbner basis with 3 elements w.r.t. degrevlex([x, y]), [1 0 -x^2-y; 0 1 y^2])
-
-julia> gens(I)*T == gens(G)
-true
-```
-"""
-function groebner_basis_with_transformation_matrix(I::MPolyIdeal; ordering::MonomialOrdering = default_ordering(base_ring(I)), complete_reduction::Bool = false)
- is_global(ordering) || error("Ordering must be global")
- return standard_basis_with_transformation_matrix(I, ordering=ordering, complete_reduction=complete_reduction)
-end
-
-# syzygies #######################################################
-# See src/Modules/UngradedModules/FreeMod.jl for the implementation.
-
-# leading ideal #######################################################
-@doc raw"""
- leading_ideal(G::Vector{T}; ordering::MonomialOrdering = default_ordering(parent(G[1])))
- where T <: MPolyRingElem
-
-Return the leading ideal of `G` with respect to `ordering`.
-
-# Examples
-```jldoctest
-julia> R, (x, y) = polynomial_ring(QQ, [:x, :y])
-(Multivariate polynomial ring in 2 variables over QQ, QQMPolyRingElem[x, y])
-
-julia> L = leading_ideal([x*y^2-3*x, x^3-14*y^5], ordering=degrevlex(R))
-Ideal generated by
- x*y^2
- y^5
-
-julia> L = leading_ideal([x*y^2-3*x, x^3-14*y^5], ordering=lex(R))
-Ideal generated by
- x*y^2
- x^3
-```
-"""
-function leading_ideal(G::Vector{T}; ordering::MonomialOrdering = default_ordering(parent(G[1]))) where { T <: MPolyRingElem }
- return ideal(parent(G[1]), [leading_monomial(f; ordering = ordering) for f in G])
-end
-
-function leading_ideal(I::IdealGens{T}) where { T <: MPolyRingElem }
- return ideal(base_ring(I), [leading_monomial(f; ordering = I.ord) for f in I])
-end
-
-function leading_ideal(I::IdealGens{T}, ordering::MonomialOrdering) where T <: MPolyRingElem
- return ideal(base_ring(I), [leading_monomial(f; ordering = ordering) for f in I])
-end
-
-
-@doc raw"""
- leading_ideal(I::MPolyIdeal; ordering::MonomialOrdering = default_ordering(base_ring(I)))
-
-Return the leading ideal of `I` with respect to `ordering`.
-
-# Examples
-```jldoctest
-julia> R, (x, y) = polynomial_ring(QQ, [:x, :y])
-(Multivariate polynomial ring in 2 variables over QQ, QQMPolyRingElem[x, y])
-
-julia> I = ideal(R,[x*y^2-3*x, x^3-14*y^5])
-Ideal generated by
- x*y^2 - 3*x
- x^3 - 14*y^5
-
-julia> L = leading_ideal(I, ordering=degrevlex(R))
-Ideal generated by
- x*y^2
- x^4
- y^5
-
-julia> L = leading_ideal(I, ordering=lex(R))
-Ideal generated by
- y^7
- x*y^2
- x^3
-```
-"""
-function leading_ideal(I::MPolyIdeal; ordering::MonomialOrdering = default_ordering(base_ring(I)))
- G = standard_basis(I, ordering=ordering)
- return ideal(base_ring(I), [leading_monomial(g; ordering = ordering) for g in G])
-end
-
-@doc raw"""
- reduce(I::IdealGens, J::IdealGens;
- ordering::MonomialOrdering = default_ordering(base_ring(J)), complete_reduction::Bool = false)
-
-Return a `Vector` whose elements are the underlying elements of `I`
-reduced by the underlying generators of `J` w.r.t. the monomial
-ordering `ordering`. `J` need not be a Gröbner basis. The returned
-`Vector` will have the same number of elements as `I`, even if they
-are zero.
-
-# Examples
-```jldoctest
-julia> R, (x, y, z) = polynomial_ring(GF(11), [:x, :y, :z]);
-
-julia> I = ideal(R, [x^2, x*y - y^2]);
-
-julia> J = ideal(R, [y^3])
-Ideal generated by
- y^3
-
-julia> reduce(J.gens, I.gens)
-1-element Vector{FqMPolyRingElem}:
- y^3
-
-julia> reduce(J.gens, groebner_basis(I))
-1-element Vector{FqMPolyRingElem}:
- 0
-
-julia> reduce(y^3, [x^2, x*y-y^3])
-x*y
-
-julia> reduce(y^3, [x^2, x*y-y^3], ordering=lex(R))
-y^3
-
-julia> reduce([y^3], [x^2, x*y-y^3], ordering=lex(R))
-1-element Vector{FqMPolyRingElem}:
- y^3
-```
-"""
-function reduce(I::IdealGens, J::IdealGens; ordering::MonomialOrdering = default_ordering(base_ring(J)), complete_reduction::Bool = false)
- @assert base_ring(J) == base_ring(I)
- Is = singular_generators(I, ordering)
- Js = singular_generators(J, ordering)
- res = reduce(Is, Js, complete_reduction=complete_reduction)
- return [J.gens.Ox(x) for x = gens(res)]
-end
-
-@doc raw"""
- reduce(g::T, F::Union{Vector{T}, IdealGens{T}};
- ordering::MonomialOrdering = default_ordering(g)), complete_reduction::Bool = false) where T <: MPolyRingElem
-
-If `ordering` is global, return the remainder in a standard representation for `g` on division by the polynomials in `F` with respect to `ordering`.
-Otherwise, return the remainder in a *weak* standard representation for `g` on division by the polynomials in `F` with respect to `ordering`.
-
- reduce(G::Vector{T}, F::Union{Vector{T}, IdealGens{T}};
- ordering::MonomialOrdering = default_ordering(parent(G[1])), complete_reduction::Bool = false) where T <: MPolyRingElem
-
-Return a `Vector` which contains, for each element `g` of `G`, a remainder as above.
-
-!!! note
- The returned remainders are fully reduced if `complete_reduction` is set to `true` and `ordering` is global.
-
-!!! note
- The reduction strategy behind the `reduce` function and the reduction strategy behind the functions
- `reduce_with_quotients` and `reduce_with_quotients_and_unit` differ. As a consequence, the computed
- remainders may differ.
-
-# Examples
-```jldoctest
-julia> R, (z, y, x) = polynomial_ring(QQ, [:z, :y, :x]);
-
-julia> f1 = y-x^2; f2 = z-x^3;
-
-julia> g = x^3*y-3*y^2*z^2+x*y*z;
-
-julia> reduce(g, [f1, f2], ordering = lex(R))
--3*x^10 + x^6 + x^5
-```
-
-```jldoctest
-julia> R, (x, y, z) = polynomial_ring(QQ, [:x, :y, :z]);
-
-julia> f1 = x^2+x^2*y; f2 = y^3+x*y*z; f3 = x^3*y^2+z^4;
-
-julia> g = x^3*y+x^5+x^2*y^2*z^2+z^6;
-
-julia> reduce(g, [f1, f2, f3], ordering = lex(R))
-x^5 + x^3*y + x^2*y^2*z^2 + z^6
-
-julia> reduce(g, [f1,f2, f3], ordering = lex(R), complete_reduction = true)
-x^5 - x^3 + y^6 + z^6
-```
-
-"""
-function reduce(f::T, F::Vector{T}; ordering::MonomialOrdering = default_ordering(parent(f)), complete_reduction::Bool = false) where {T <: MPolyRingElem}
- isempty(F) && return f
- J = IdealGens(parent(F[1]), F, ordering)
- return reduce(f, J; ordering=ordering, complete_reduction=complete_reduction)
-end
-
-function reduce(F::Vector{T}, G::Vector{T}; ordering::MonomialOrdering = default_ordering(parent(F[1])), complete_reduction::Bool = false) where {T <: MPolyRingElem}
- isempty(G) && return F
- J = IdealGens(parent(G[1]), G, ordering)
- return reduce(F, J; ordering=ordering, complete_reduction=complete_reduction)
-end
-
-function reduce(f::T, F::IdealGens{T}; ordering::MonomialOrdering = default_ordering(parent(f)), complete_reduction::Bool = false) where {T <: MPolyRingElem}
- isempty(F) && return f
- @assert parent(f) == base_ring(F)
- R = parent(f)
- I = IdealGens(R, [f], ordering)
- redv = reduce(I, F, ordering=ordering, complete_reduction=complete_reduction)
- return redv[1]
-end
-
-function reduce(F::Vector{T}, G::IdealGens{T}; ordering::MonomialOrdering = default_ordering(parent(F[1])), complete_reduction::Bool = false) where {T <: MPolyRingElem}
- (isempty(F) || isempty(G)) && return F
- @assert parent(F[1]) == base_ring(G)
- R = parent(F[1])
- I = IdealGens(R, F, ordering)
- return reduce(I, G, ordering=ordering, complete_reduction=complete_reduction)
-end
-
-@doc raw"""
- reduce_with_quotients_and_unit(g::T, F::Union{Vector{T}, IdealGens{T}};
- ordering::MonomialOrdering = default_ordering(parent(g)), complete_reduction::Bool = false) where T <: MPolyRingElem
-
-Return the unit, the quotients and the remainder in a weak standard representation for `g` on division by the polynomials in `F` with respect to `ordering`.
-
- reduce_with_quotients_and_unit(G::Vector{T}, F::Union{Vector{T}, IdealGens{T}};
- ordering::MonomialOrdering = default_ordering(parent(G[1])), complete_reduction::Bool = false) where T <: MPolyRingElem
-
-Return a `Vector` which contains, for each element `g` of `G`, a unit, quotients, and a remainder as above.
-
-!!! note
- The returned remainders are fully reduced if `complete_reduction` is set to `true` and `ordering` is global.
-
-!!! note
- The reduction strategy behind the `reduce` function and the reduction strategy behind the functions
- `reduce_with_quotients` and `reduce_with_quotients_and_unit` differ. As a consequence, the computed
- remainders may differ.
-
-# Examples
-```jldoctest
-julia> R, (x, y, z) = polynomial_ring(QQ, [:x, :y, :z]);
-
-julia> f1 = x^2+x^2*y; f2 = y^3+x*y*z; f3 = x^3*y^2+z^4;
-
-julia> g = x^3*y+x^5+x^2*y^2*z^2+z^6;
-
-julia> u, Q, h =reduce_with_quotients_and_unit(g, [f1,f2, f3], ordering = lex(R));
-
-julia> u
-[1]
-
-julia> G = [g, x*y^3-3*x^2*y^2*z^2];
-
-julia> U, Q, H = reduce_with_quotients_and_unit(G, [f1, f2, f3], ordering = negdegrevlex(R));
-
-julia> U
-[y + 1 0]
-[ 0 y + 1]
-
-julia> Q
-[ x^3 - x*y^2*z^2 + x*y + y^2*z^2 0 y*z^2 + z^2]
-[x*y*z^2 + y^3*z - 3*y^2*z^2 - y*z -x^2*y*z - x^2*z + x*y + x 0]
-
-julia> H
-2-element Vector{QQMPolyRingElem}:
- 0
- 0
-
-julia> U*G == Q*[f1, f2, f3]+H
-true
-```
-"""
-function reduce_with_quotients_and_unit(f::T, F::Vector{T}; ordering::MonomialOrdering = default_ordering(parent(f)), complete_reduction::Bool = false) where {T <: MPolyRingElem}
- if isempty(F)
- return identity_matrix(parent(f), 1), zero_matrix(parent(f), 1, 0), f
- end
- J = IdealGens(parent(F[1]), F, ordering)
- return reduce_with_quotients_and_unit(f, J; ordering=ordering, complete_reduction=complete_reduction)
-end
-
-function reduce_with_quotients_and_unit(F::Vector{T}, G::Vector{T}; ordering::MonomialOrdering = default_ordering(parent(F[1])), complete_reduction::Bool = false) where {T <: MPolyRingElem}
- @assert !isempty(F)
- if isempty(G)
- return identity_matrix(parent(F[1]), length(F)), zero_matrix(parent(F[1]), length(F), 0), F
- end
- J = IdealGens(parent(G[1]), G, ordering)
- return reduce_with_quotients_and_unit(F, J; ordering=ordering, complete_reduction=complete_reduction)
-end
-
-function reduce_with_quotients_and_unit(f::T, F::IdealGens{T}; ordering::MonomialOrdering = default_ordering(parent(f)), complete_reduction::Bool = false) where {T <: MPolyRingElem}
- if isempty(F)
- return identity_matrix(parent(f), 1), zero_matrix(parent(f), 1, 0), f
- end
- @assert parent(f) == base_ring(F)
- R = parent(f)
- I = IdealGens(R, [f], ordering)
- u, q, r = _reduce_with_quotients_and_unit(I, F, ordering, complete_reduction)
- return u, q, r[1]
-end
-
-function reduce_with_quotients_and_unit(F::Vector{T}, G::IdealGens{T}; ordering::MonomialOrdering = default_ordering(parent(F[1])), complete_reduction::Bool = false) where {T <: MPolyRingElem}
- @assert !isempty(F)
- if isempty(G)
- return identity_matrix(parent(F[1]), length(F)), zero_matrix(parent(F[1]), length(F), 0), F
- end
- @assert parent(F[1]) == base_ring(G)
- R = parent(F[1])
- I = IdealGens(R, F, ordering)
- return _reduce_with_quotients_and_unit(I, G, ordering, complete_reduction)
-end
-
-@doc raw"""
- reduce_with_quotients_and_unit(I::IdealGens, J::IdealGens;
- ordering::MonomialOrdering = default_ordering(base_ring(J)), complete_reduction::Bool = false)
-
-Return a `Tuple` consisting of a `Generic.MatSpaceElem` `M`, a
-`Vector` `res` whose elements are the underlying elements of `I`
-reduced by the underlying generators of `J` w.r.t. the monomial
-ordering `ordering` and a diagonal matrix `units` such that `M *
-gens(J) + res == units * gens(I)`. If `ordering` is global then
-`units` will always be the identity matrix, see also
-`reduce_with_quotients`. `J` need not be a Gröbner basis. `res` will
-have the same number of elements as `I`, even if they are zero.
-
-# Examples
-```jldoctest
-julia> R, (x, y) = polynomial_ring(GF(11), [:x, :y]);
-
-julia> I = ideal(R, [x]);
-
-julia> R, (x, y) = polynomial_ring(GF(11), [:x, :y]);
-
-julia> I = ideal(R, [x]);
-
-julia> J = ideal(R, [x+1]);
-
-julia> unit, M, res = reduce_with_quotients_and_unit(I.gens, J.gens, ordering = neglex(R))
-([x+1], [x], FqMPolyRingElem[0])
-
-julia> M * gens(J) + res == unit * gens(I)
-true
-
-julia> f = x^3*y^2-y^4-10
-x^3*y^2 + 10*y^4 + 1
-
-julia> F = [x^2*y-y^3, x^3-y^4]
-2-element Vector{FqMPolyRingElem}:
- x^2*y + 10*y^3
- x^3 + 10*y^4
-
-julia> reduce_with_quotients_and_unit(f, F)
-([1], [x*y 10*x+1], x^4 + 10*x^3 + 1)
-
-julia> unit, M, res = reduce_with_quotients_and_unit(f, F, ordering=lex(R))
-([1], [x*y 0], x*y^4 + 10*y^4 + 1)
-
-julia> M * F + [res] == unit * [f]
-true
-```
-"""
-function reduce_with_quotients_and_unit(I::IdealGens, J::IdealGens; ordering::MonomialOrdering = default_ordering(base_ring(J)), complete_reduction::Bool = false)
- return _reduce_with_quotients_and_unit(I, J, ordering, complete_reduction)
-end
-
-
-@doc raw"""
- reduce_with_quotients(I::IdealGens, J::IdealGens; ordering::MonomialOrdering = default_ordering(base_ring(J)), complete_reduction::Bool = false)
-
-Return a `Tuple` consisting of a `Generic.MatSpaceElem` `M` and a
-`Vector` `res` whose elements are the underlying elements of `I`
-reduced by the underlying generators of `J` w.r.t. the monomial
-ordering `ordering` such that `M * gens(J) + res == gens(I)` if `ordering` is global.
-If `ordering` is local then this equality holds after `gens(I)` has been multiplied
-with an unknown diagonal matrix of units, see `reduce_with_quotients_and_unit` to
-obtain this matrix. `J` need not be a Gröbner basis. `res` will have the same number
-of elements as `I`, even if they are zero.
-
-# Examples
-```jldoctest
-julia> R, (x, y, z) = polynomial_ring(GF(11), [:x, :y, :z]);
-
-julia> J = ideal(R, [x^2, x*y - y^2]);
-
-julia> I = ideal(R, [x*y, y^3]);
-
-julia> gb = groebner_basis(J)
-Gröbner basis with elements
- 1 -> x*y + 10*y^2
- 2 -> x^2
- 3 -> y^3
-with respect to the ordering
- degrevlex([x, y, z])
-
-julia> M, res = reduce_with_quotients(I.gens, gb)
-([1 0 0; 0 0 1], FqMPolyRingElem[y^2, 0])
-
-julia> M * gens(gb) + res == gens(I)
-true
-
-julia> f = x^3*y^2-y^4-10
-x^3*y^2 + 10*y^4 + 1
-
-julia> F = [x^2*y-y^3, x^3-y^4]
-2-element Vector{FqMPolyRingElem}:
- x^2*y + 10*y^3
- x^3 + 10*y^4
-
-julia> reduce_with_quotients_and_unit(f, F)
-([1], [x*y 10*x+1], x^4 + 10*x^3 + 1)
-
-julia> unit, M, res = reduce_with_quotients_and_unit(f, F, ordering=lex(R))
-([1], [x*y 0], x*y^4 + 10*y^4 + 1)
-
-julia> M * F + [res] == unit * [f]
-true
-```
-"""
-function reduce_with_quotients(I::IdealGens, J::IdealGens; ordering::MonomialOrdering = default_ordering(base_ring(J)), complete_reduction::Bool = false)
- _, q, r = _reduce_with_quotients_and_unit(I, J, ordering, complete_reduction)
- return q, r
-end
-
-@doc raw"""
- reduce_with_quotients(g::T, F::Union{Vector{T}, IdealGens{T}};
- ordering::MonomialOrdering = default_ordering(parent(g)), complete_reduction::Bool = false) where T <: MPolyRingElem
-
-If `ordering` is global, return the quotients and the remainder in a standard representation for `g` on division by the polynomials in `F` with respect to `ordering`.
-Otherwise, return the quotients and the remainder in a *weak* standard representation for `g` on division by the polynomials in `F` with respect to `ordering`.
-
- reduce_with_quotients(G::Vector{T}, F::Union{Vector{T}, IdealGens{T}};
- ordering::MonomialOrdering = default_ordering(parent(G[1])), complete_reduction::Bool = false) where T <: MPolyRingElem
-
-Return a `Vector` which contains, for each element `g` of `G`, quotients and a remainder as above.
-
-!!! note
- The returned remainders are fully reduced if `complete_reduction` is set to `true` and `ordering` is global.
-
-# Examples
-
-```jldoctest
-julia> R, (x, y, z) = polynomial_ring(QQ, [:x, :y, :z]);
-
-julia> f1 = x^2+x^2*y; f2 = y^3+x*y*z; f3 = x^3*y^2+z^4;
-
-julia> g = x^3*y+x^5+x^2*y^2*z^2+z^6;
-
-julia> Q, h = reduce_with_quotients(g, [f1,f2, f3], ordering = lex(R));
-
-julia> h
-x^5 - x^3 + y^6 + z^6
-
-julia> g == Q[1]*f1+Q[2]*f2+Q[3]*f3+h
-true
-```
-"""
-function reduce_with_quotients(f::T, F::Vector{T}; ordering::MonomialOrdering = default_ordering(parent(f)), complete_reduction::Bool = false) where {T <: MPolyRingElem}
- isempty(F) && return zero_matrix(parent(f), 1, 0), f
- J = IdealGens(parent(F[1]), F, ordering)
- return reduce_with_quotients(f, J; ordering=ordering, complete_reduction=complete_reduction)
-end
-
-function reduce_with_quotients(F::Vector{T}, G::Vector{T}; ordering::MonomialOrdering = default_ordering(parent(F[1])), complete_reduction::Bool = false) where {T <: MPolyRingElem}
- @assert !isempty(F)
- isempty(G) && return zero_matrix(parent(F[1]), length(F), 0), F
- J = IdealGens(parent(G[1]), G, ordering)
- return reduce_with_quotients(F, J; ordering=ordering, complete_reduction=complete_reduction)
-end
-
-function reduce_with_quotients(f::T, F::IdealGens{T}; ordering::MonomialOrdering = default_ordering(parent(f)), complete_reduction::Bool = false) where {T <: MPolyRingElem}
- isempty(F) && return zero_matrix(parent(f), 1, 0), f
- @assert parent(f) == parent(F[1])
- R = parent(f)
- I = IdealGens(R, [f], ordering)
- _, q, r = _reduce_with_quotients_and_unit(I, F, ordering, complete_reduction)
- return q, r[1]
-end
-
-function reduce_with_quotients(F::Vector{T}, G::IdealGens{T}; ordering::MonomialOrdering = default_ordering(parent(F[1])), complete_reduction::Bool = false) where {T <: MPolyRingElem}
- @assert !isempty(F)
- isempty(G) && return zero_matrix(parent(F[1]), length(F), 0), F
- @assert parent(F[1]) == parent(G[1])
- R = parent(F[1])
- I = IdealGens(R, F, ordering)
- _, q, r = _reduce_with_quotients_and_unit(I, G, ordering, complete_reduction)
- return q, r
-end
-
-function _reduce_with_quotients_and_unit(I::IdealGens, J::IdealGens, ordering::MonomialOrdering = default_ordering(base_ring(J)), complete_reduction::Bool = complete_reduction)
- @assert base_ring(J) == base_ring(I)
- sI = singular_generators(I, ordering)
- sJ = singular_generators(J, ordering)
- res = Singular.divrem2(sI, sJ, complete_reduction=complete_reduction)
- return matrix(base_ring(I), res[3]), matrix(base_ring(I), res[1]), [J.gens.Ox(x) for x = gens(res[2])]
-end
-
-@doc raw"""
- normal_form(g::T, I::MPolyIdeal;
- ordering::MonomialOrdering = default_ordering(base_ring(I))) where T <: MPolyRingElem
-
-Compute the normal form of `g` mod `I` with respect to `ordering`.
-
- normal_form(G::Vector{T}, I::MPolyIdeal;
- ordering::MonomialOrdering = default_ordering(base_ring(I))) where T <: MPolyRingElem
-
-Return a `Vector` which contains for each element `g` of `G` a normal form as above.
-
-# Examples
-```jldoctest
-julia> R,(a,b,c) = polynomial_ring(QQ,[:a,:b,:c])
-(Multivariate polynomial ring in 3 variables over QQ, QQMPolyRingElem[a, b, c])
-
-julia> J = ideal(R,[-1+c+b,-1+b+c*a+2*a*b])
-Ideal generated by
- b + c - 1
- 2*a*b + a*c + b - 1
-
-julia> gens(groebner_basis(J))
-2-element Vector{QQMPolyRingElem}:
- b + c - 1
- a*c - 2*a + c
-
-julia> normal_form(-1+c+b+a^3, J)
-a^3
-
-julia> R,(a,b,c) = polynomial_ring(QQ,[:a,:b,:c])
-(Multivariate polynomial ring in 3 variables over QQ, QQMPolyRingElem[a, b, c])
-
-julia> A = [-1+c+b+a^3,-1+b+c*a+2*a^3,5+c*b+c^2*a]
-3-element Vector{QQMPolyRingElem}:
- a^3 + b + c - 1
- 2*a^3 + a*c + b - 1
- a*c^2 + b*c + 5
-
-julia> J = ideal(R,[-1+c+b,-1+b+c*a+2*a*b])
-Ideal generated by
- b + c - 1
- 2*a*b + a*c + b - 1
-
-julia> gens(groebner_basis(J))
-2-element Vector{QQMPolyRingElem}:
- b + c - 1
- a*c - 2*a + c
-
-julia> normal_form(A, J)
-3-element Vector{QQMPolyRingElem}:
- a^3
- 2*a^3 + 2*a - 2*c
- 4*a - 2*c^2 - c + 5
-```
-"""
-function normal_form(f::T, J::MPolyIdeal; ordering::MonomialOrdering = default_ordering(base_ring(J))) where { T <: MPolyRingElem }
- res = normal_form([f], J, ordering = ordering)
-
- return res[1]
-end
-
-function normal_form(A::Vector{T}, J::MPolyIdeal; ordering::MonomialOrdering=default_ordering(base_ring(J))) where { T <: MPolyRingElem }
- @req is_exact_type(elem_type(base_ring(J))) "This functionality is only supported over exact fields."
- if is_normal_form_f4_applicable(J, ordering)
- res = _normal_form_f4(A, J)
- else
- res = _normal_form_singular(A, J, ordering)
- end
-
- return res
-end
-
-function is_normal_form_f4_applicable(I::MPolyIdeal, ordering::MonomialOrdering)
- return (ordering == degrevlex(base_ring(I)) && !is_graded(base_ring(I))
- && ((coefficient_ring(I) isa FqField
- && absolute_degree(coefficient_ring(I)) == 1
- && characteristic(coefficient_ring(I)) < 2^31)))
-end
-
-@doc raw"""
- _normal_form_f4(A::Vector{T}, J::MPolyIdeal) where { T <: MPolyRingElem }
-
-**Note**: Internal function, subject to change, do not use.
-
-Compute the normal form of the elements of `A` w.r.t. a
-Gröbner basis of `J` and the monomial ordering `degrevlex` using the F4 Algorithm from AlgebraicSolving.
-
-CAVEAT: This computation needs a Gröbner basis of `J` and the monomial ordering
-`ordering. If this Gröbner basis is not available, one is computed automatically.
-This may take some time. This function only works in polynomial rings over prime fields
-with the degree reverse lexicographical ordering.
-
-# Examples
-```jldoctest
-julia> R,(a,b,c) = polynomial_ring(GF(65521),[:a,:b,:c])
-(Multivariate polynomial ring in 3 variables over GF(65521), FqMPolyRingElem[a, b, c])
-
-julia> J = ideal(R,[-1+c+b,-1+b+c*a+2*a*b])
-Ideal generated by
- b + c + 65520
- 2*a*b + a*c + b + 65520
-
-julia> A = [-1+c+b+a^3, -1+b+c*a+2*a^3, 5+c*b+c^2*a]
-3-element Vector{FqMPolyRingElem}:
- a^3 + b + c + 65520
- 2*a^3 + a*c + b + 65520
- a*c^2 + b*c + 5
-
-julia> Oscar._normal_form_f4(A, J)
-3-element Vector{FqMPolyRingElem}:
- a^3
- 2*a^3 + 2*a + 65519*c
- 4*a + 65519*c^2 + 65520*c + 5
-```
-"""
-function _normal_form_f4(A::Vector{T}, J::MPolyIdeal) where { T <: MPolyRingElem }
- if !haskey(J.gb, degrevlex(base_ring(J)))
- groebner_basis_f4(J, complete_reduction = true)
- end
-
- AJ = AlgebraicSolving.Ideal(J.gens.O)
- AJ.gb[0] = oscar_groebner_generators(J, degrevlex(base_ring(J)), true)
-
- return AlgebraicSolving.normal_form(A, AJ)
-end
-
-@doc raw"""
- _normal_form_singular(A::Vector{T}, J::MPolyIdeal, ordering::MonomialOrdering) where { T <: MPolyRingElem }
-
-**Note**: Internal function, subject to change, do not use.
-
-Compute the normal form of the elements of `A` w.r.t. a
-Gröbner basis of `J` and the monomial ordering `ordering` using Singular.
-
-CAVEAT: This computation needs a Gröbner basis of `J` and the monomial ordering
-`ordering. If this Gröbner basis is not available, one is computed automatically.
-This may take some time.
-
-# Examples
-```jldoctest
-julia> R,(a,b,c) = polynomial_ring(QQ,[:a,:b,:c])
-(Multivariate polynomial ring in 3 variables over QQ, QQMPolyRingElem[a, b, c])
-
-julia> J = ideal(R,[-1+c+b,-1+b+c*a+2*a*b])
-Ideal generated by
- b + c - 1
- 2*a*b + a*c + b - 1
-
-julia> gens(groebner_basis(J))
-2-element Vector{QQMPolyRingElem}:
- b + c - 1
- a*c - 2*a + c
-
-julia> A = [-1+c+b+a^3, -1+b+c*a+2*a^3, 5+c*b+c^2*a]
-3-element Vector{QQMPolyRingElem}:
- a^3 + b + c - 1
- 2*a^3 + a*c + b - 1
- a*c^2 + b*c + 5
-
-julia> Oscar._normal_form_singular(A, J, default_ordering(base_ring(J)))
-3-element Vector{QQMPolyRingElem}:
- a^3
- 2*a^3 + 2*a - 2*c
- 4*a - 2*c^2 - c + 5
-```
-"""
-function _normal_form_singular(A::Vector{T}, J::MPolyIdeal, ordering::MonomialOrdering) where { T <: MPolyRingElem }
- GS = singular_groebner_generators(J, ordering)
- SR = base_ring(GS)
- tmp = map(SR, A)
- IS = Singular.Ideal(SR, tmp)
- K = reduce(IS, GS)
- OR = base_ring(J)
- return map(OR, gens(K))
-end
-
-@doc raw"""
- is_standard_basis(F::IdealGens; ordering::MonomialOrdering=default_ordering(base_ring(F)))
-
-Tests if a given IdealGens `F` is a standard basis w.r.t. the given monomial ordering `ordering`.
-
-# Examples
-```jldoctest
-julia> R, (x, y) = polynomial_ring(QQ, [:x, :y])
-(Multivariate polynomial ring in 2 variables over QQ, QQMPolyRingElem[x, y])
-
-julia> I = ideal(R,[x^2+y,x*y-y])
-Ideal generated by
- x^2 + y
- x*y - y
-
-julia> is_standard_basis(I.gens, ordering=neglex(R))
-false
-
-julia> standard_basis(I, ordering=neglex(R))
-Standard basis with elements
- 1 -> y
- 2 -> x^2
-with respect to the ordering
- neglex([x, y])
-
-julia> is_standard_basis(I.gb[neglex(R)], ordering=neglex(R))
-true
-```
-"""
-function is_standard_basis(F::IdealGens; ordering::MonomialOrdering=default_ordering(base_ring(F)))
- @req is_exact_type(elem_type(base_ring(F))) "This functionality is only supported over exact fields."
- if F.isGB && F.ord == ordering
- return true
- else
- # Try to reduce all possible s-polynomials, i.e. Buchberger's criterion
- R = base_ring(F)
- for i in 1:length(F)
- lt_i = leading_term(F[i], ordering=ordering)
- for j in i+1:length(F)
- lt_j = leading_term(F[j], ordering=ordering)
- lcm_ij = lcm(lt_i, lt_j)
- sp_ij = div(lcm_ij, lt_i) * F[i] - div(lcm_ij, lt_j) * F[j]
- if reduce(IdealGens([sp_ij], ordering), F, ordering=ordering) != [R(0)]
- return false
- end
- end
- end
- F.isGB = true
- F.ord = ordering
- return true
- end
-end
-
-@doc raw"""
- is_groebner_basis(F::IdealGens; ordering::MonomialOrdering=default_ordering(base_ring(F)))
-
-Tests if a given IdealGens `F` is a Gröbner basis w.r.t. the given monomial ordering `ordering`.
-
-# Examples
-```jldoctest
-julia> R, (x, y) = polynomial_ring(QQ, [:x, :y])
-(Multivariate polynomial ring in 2 variables over QQ, QQMPolyRingElem[x, y])
-
-julia> I = ideal(R,[x^2+y,x*y-y])
-Ideal generated by
- x^2 + y
- x*y - y
-
-julia> is_groebner_basis(I.gens, ordering=lex(R))
-false
-
-julia> groebner_basis(I, ordering=lex(R))
-Gröbner basis with elements
- 1 -> y^2 + y
- 2 -> x*y - y
- 3 -> x^2 + y
-with respect to the ordering
- lex([x, y])
-
-julia> is_groebner_basis(I.gb[lex(R)], ordering=lex(R))
-true
-```
-"""
-function is_groebner_basis(F::IdealGens; ordering::MonomialOrdering = default_ordering(base_ring(F)))
- is_global(ordering) || error("Ordering must be global")
- return is_standard_basis(F, ordering=ordering)
-end
-
-@doc raw"""
- _fglm(G::IdealGens; ordering::MonomialOrdering)
-
-Converts a Gröbner basis `G` w.r.t. a given global monomial ordering for ``
-to a Gröbner basis `H` w.r.t. another monomial ordering `ordering` for ``.
-
-**NOTE**: `_fglm` assumes that `G` is a reduced Gröbner basis (i.e. w.r.t. a global monomial ordering) and that `ordering` is a global monomial ordering.
-
-# Examples
-```jldoctest
-julia> R, (x1, x2, x3, x4) = polynomial_ring(GF(101), [:x1, :x2, :x3, :x4])
-(Multivariate polynomial ring in 4 variables over GF(101), FqMPolyRingElem[x1, x2, x3, x4])
-
-julia> J = ideal(R, [x1+2*x2+2*x3+2*x4-1,
- x1^2+2*x2^2+2*x3^2+2*x4^2-x1,
- 2*x1*x2+2*x2*x3+2*x3*x4-x2,
- x2^2+2*x1*x3+2*x2*x4-x3
- ])
-Ideal generated by
- x1 + 2*x2 + 2*x3 + 2*x4 + 100
- x1^2 + 100*x1 + 2*x2^2 + 2*x3^2 + 2*x4^2
- 2*x1*x2 + 2*x2*x3 + 100*x2 + 2*x3*x4
- 2*x1*x3 + x2^2 + 2*x2*x4 + 100*x3
-
-julia> groebner_basis(J, ordering=degrevlex(R), complete_reduction=true)
-Gröbner basis with elements
- 1 -> x1 + 2*x2 + 2*x3 + 2*x4 + 100
- 2 -> x3^2 + 2*x2*x4 + 19*x3*x4 + 76*x4^2 + 72*x2 + 86*x3 + 42*x4
- 3 -> x2*x3 + 99*x2*x4 + 40*x3*x4 + 11*x4^2 + 65*x2 + 58*x3 + 30*x4
- 4 -> x2^2 + 2*x2*x4 + 30*x3*x4 + 45*x4^2 + 43*x2 + 72*x3 + 86*x4
- 5 -> x3*x4^2 + 46*x4^3 + 28*x2*x4 + 16*x3*x4 + 7*x4^2 + 58*x2 + 63*x3 + 15*x4
- 6 -> x2*x4^2 + 67*x4^3 + 56*x2*x4 + 58*x3*x4 + 45*x4^2 + 14*x2 + 86*x3
- 7 -> x4^4 + 65*x4^3 + 26*x2*x4 + 47*x3*x4 + 71*x4^2 + 37*x2 + 79*x3 + 100*x4
-with respect to the ordering
- degrevlex([x1, x2, x3, x4])
-
-julia> Oscar._fglm(J.gb[degrevlex(R)], lex(R))
-Gröbner basis with elements
- 1 -> x4^8 + 36*x4^7 + 95*x4^6 + 39*x4^5 + 74*x4^4 + 7*x4^3 + 45*x4^2 + 98*x4
- 2 -> x3 + 53*x4^7 + 93*x4^6 + 74*x4^5 + 26*x4^4 + 56*x4^3 + 15*x4^2 + 88*x4
- 3 -> x2 + 25*x4^7 + 57*x4^6 + 13*x4^5 + 16*x4^4 + 78*x4^3 + 31*x4^2 + 16*x4
- 4 -> x1 + 46*x4^7 + 3*x4^6 + 28*x4^5 + 17*x4^4 + 35*x4^3 + 9*x4^2 + 97*x4 + 100
-with respect to the ordering
- lex([x1, x2, x3, x4])
-```
-"""
-function _fglm(G::IdealGens, ordering::MonomialOrdering)
- (G.isGB == true && G.isReduced == true) || error("Input must be a reduced Gröbner basis.")
- Singular.dimension(singular_generators(G)) == 0 || error("Dimension of corresponding ideal must be zero.")
- SR_destination, = Singular.polynomial_ring(base_ring(G.Sx), symbols(G.Sx); ordering = singular(ordering))
-
- ptr = Singular.libSingular.fglmzero(G.S.ptr, G.Sx.ptr, SR_destination.ptr)
- return IdealGens(base_ring(G), Singular.sideal{Singular.spoly}(SR_destination, ptr, true))
-end
-
-@doc raw"""
- fglm(I::MPolyIdeal; start_ordering::MonomialOrdering = default_ordering(base_ring(I)),
- destination_ordering::MonomialOrdering)
-
-Given a **zero-dimensional** ideal `I`, return the reduced Gröbner basis of `I` with respect to `destination_ordering`.
-
-!!! note
- Both `start_ordering` and `destination_ordering` must be global and the base ring of `I` must be a polynomial ring over a field.
-
-!!! note
- The function implements the Gröbner basis conversion algorithm by **F**augère, **G**ianni, **L**azard, and **M**ora. See [FGLM93](@cite) for more information.
-
-# Examples
-```jldoctest
-julia> R, (a, b, c, d, e) = polynomial_ring(QQ, [:a, :b, :c, :d, :e]);
-
-julia> f1 = a+b+c+d+e;
-
-julia> f2 = a*b+b*c+c*d+a*e+d*e;
-
-julia> f3 = a*b*c+b*c*d+a*b*e+a*d*e+c*d*e;
-
-julia> f4 = b*c*d+a*b*c*e+a*b*d*e+a*c*d*e+b*c*d*e;
-
-julia> f5 = a*b*c*d*e-1;
-
-julia> I = ideal(R, [f1, f2, f3, f4, f5]);
-
-julia> G = fglm(I, destination_ordering = lex(R));
-
-julia> length(G)
-8
-
-julia> total_degree(G[8])
-60
-
-julia> leading_coefficient(G[8])
-83369589588385815165248207597941242098312973356252482872580035860533111990678631297423089011608753348453253671406641805924218003925165995322989635503951507226650115539638517111445927746874479234
-```
-"""
-function fglm(I::MPolyIdeal; start_ordering::MonomialOrdering = default_ordering(base_ring(I)), destination_ordering::MonomialOrdering)
- isa(coefficient_ring(I), AbstractAlgebra.Field) || error("The FGLM algorithm requires a coefficient ring that is a field.")
- (is_global(start_ordering) && is_global(destination_ordering)) || error("Start and destination orderings must be global.")
- haskey(I.gb, destination_ordering) && return I.gb[destination_ordering]
- if !haskey(I.gb, start_ordering)
- standard_basis(I, ordering=start_ordering, complete_reduction=true)
- elseif I.gb[start_ordering].isReduced == false
- I.gb[start_ordering] = _compute_standard_basis(I.gb[start_ordering], start_ordering, true)
- end
-
- I.gb[destination_ordering] = _fglm(I.gb[start_ordering], destination_ordering)
-
- return I.gb[destination_ordering]
-end
-
-@doc raw"""
- _compute_groebner_basis_using_fglm(I::MPolyIdeal, destination_ordering::MonomialOrdering)
-
-Computes a reduced Gröbner basis for `I` w.r.t. `destination_ordering` using the FGLM algorithm.
-
-**Note**: Internal function, subject to change, do not use.
-
-# Examples
-```jldoctest
-julia> R, (x, y) = polynomial_ring(QQ, [:x, :y])
-(Multivariate polynomial ring in 2 variables over QQ, QQMPolyRingElem[x, y])
-
-julia> I = ideal(R,[x^2+y,x*y-y])
-Ideal generated by
- x^2 + y
- x*y - y
-
-julia> Oscar._compute_groebner_basis_using_fglm(I, lex(R))
-Gröbner basis with elements
- 1 -> y^2 + y
- 2 -> x*y - y
- 3 -> x^2 + y
-with respect to the ordering
- lex([x, y])
-
-julia> I.gb[lex(R)]
-Gröbner basis with elements
- 1 -> y^2 + y
- 2 -> x*y - y
- 3 -> x^2 + y
-with respect to the ordering
- lex([x, y])
-
-julia> I.gb[degrevlex(R)]
-Gröbner basis with elements
- 1 -> y^2 + y
- 2 -> x*y - y
- 3 -> x^2 + y
-with respect to the ordering
- degrevlex([x, y])
-```
-"""
-function _compute_groebner_basis_using_fglm(I::MPolyIdeal,
- destination_ordering::MonomialOrdering)
- isa(coefficient_ring(I), AbstractAlgebra.Field) || error("The FGLM algorithm requires a coefficient ring that is a field.")
- haskey(I.gb, destination_ordering) && return I.gb[destination_ordering]
- is_global(destination_ordering) || error("Destination ordering must be global.")
- G = groebner_assure(I, true, true)
- start_ordering = G.ord
- dim(I) == 0 || error("Dimension of ideal must be zero.")
- I.gb[destination_ordering] = _fglm(G, destination_ordering)
-end
-
-@doc raw"""
- groebner_basis_hilbert_driven(I::MPolyIdeal{P}; destination_ordering::MonomialOrdering,
- complete_reduction::Bool = false,
- weights::Vector{Int} = ones(Int, ngens(base_ring(I))),
- hilbert_numerator::Union{Nothing, ZZPolyRingElem} = nothing)
- where {P <: MPolyRingElem}
-
-Return a Gröbner basis of `I` with respect to `destination_ordering`.
-
-!!! note
- The function implements a version of the Hilbert driven Gröbner basis algorithm.
- See the corresponding section of the OSCAR documentation for some details.
-
-!!! note
- All weights must be positive. If no weight vector is entered by the user, all weights
- are set to 1. An error is thrown if the generators of `I` are not homogeneous with
- respect to the corresponding (weighted) degree.
-
-!!! note
- If $R$ denotes the parent ring of $I$, and $p, q\in\mathbb Z[t]$ are polynomials
- such that $p/q$ represents the Hilbert series of $R/I$ as a rational function with
- denominator $q = (1-t^{w_1})\cdots (1-t^{w_n}),$ where $n$ is the number of variables
- of $R$, and $w_1, \dots, w_n$ are the assigned weights, then `hilbert_numerator` is
- meant to be $p$. If this numerator is not entered by the user, it will be computed
- internally.
-
-# Examples
-```jldoctest
-julia> R, (a, b, c, d, e, f, g) = polynomial_ring(QQ, [:a, :b, :c, :d, :e, :f, :g]);
-
-julia> V = [-3*a^2+2*f*b+3*f*d, (3*g*b+3*g*e)*a-3*f*c*b,
- -3*g^2*a^2-c*b^2*a-g^2*f*e-g^4, e*a-f*b-d*c];
-
-julia> I = ideal(R, V);
-
-julia> o = degrevlex([a, b, c])*degrevlex([d, e, f, g]);
-
-julia> G = groebner_basis_hilbert_driven(I, destination_ordering = o);
-
-julia> length(G)
-296
-
-julia> total_degree(G[49])
-30
-```
-
-```jldoctest
-julia> R, (x, y, z) = polynomial_ring(GF(32003), [:x, :y, :z]);
-
-julia> f1 = x^2*y+169*y^21+151*x*y*z^10;
-
-julia> f2 = 6*x^2*y^4+x*z^14+3*z^24;
-
-julia> f3 = 11*x^3+5*x*y^10*z^10+2*y^20*z^10+y^10*z^20;
-
-julia> I = ideal(R, [f1, f2,f3]);
-
-julia> W = [10, 1, 1];
-
-julia> GB = groebner_basis_hilbert_driven(I, destination_ordering = lex(R), weights = W);
-
-julia> length(GB)
-40
-```
-
-```jldoctest
-julia> R, (x, y, z) = polynomial_ring(GF(32003), [:x, :y, :z]);
-
-julia> f1 = x^2*y+169*y^21+151*x*y*z^10;
-
-julia> f2 = 6*x^2*y^4+x*z^14+3*z^24;
-
-julia> f3 = 11*x^3+5*x*y^10*z^10+2*y^20*z^10+y^10*z^20;
-
-julia> I = ideal(R, [f1, f2,f3]);
-
-julia> W = [10, 1, 1];
-
-julia> S, t = polynomial_ring(ZZ, :t)
-(Univariate polynomial ring in t over ZZ, t)
-
-julia> hn = -t^75 + t^54 + t^51 + t^45 - t^30 - t^24 - t^21 + 1
--t^75 + t^54 + t^51 + t^45 - t^30 - t^24 - t^21 + 1
-
-julia> GB = groebner_basis_hilbert_driven(I, destination_ordering = lex(R), weights = W, hilbert_numerator = hn);
-
-julia> length(GB)
-40
-```
-"""
-function groebner_basis_hilbert_driven(I::MPolyIdeal{P};
- destination_ordering::MonomialOrdering,
- complete_reduction::Bool = false,
- weights::Vector{Int} = ones(Int, ngens(base_ring(I))),
- hilbert_numerator::Union{Nothing, ZZPolyRingElem} = nothing) where {P <: MPolyRingElem}
-
- all(f -> _is_homogeneous(f, weights), gens(I)) || error("I must be given by generators homogeneous with respect to the given weights.")
- isa(coefficient_ring(I), AbstractAlgebra.Field) || error("The underlying coefficient ring of I must be a field.")
- ordering = destination_ordering
- is_global(ordering) || error("Destination ordering must be global.")
- haskey(I.gb, ordering) && return I.gb[ordering]
- if isnothing(hilbert_numerator)
- if isempty(I.gb)
- J = iszero(characteristic(base_ring(I))) ? _mod_rand_prime(I) : I
- G = groebner_assure(J, wdegrevlex(base_ring(J), weights))
- else
- G = groebner_assure(I)
- end
-
- if characteristic(base_ring(I)) > 0 && ordering == wdegrevlex(base_ring(I), weights)
- return G
- end
- singular_assure(G)
- h = Singular.hilbert_series(G.S, weights)
-
- else
- # Quoting from the documentation of Singular.hilbert_series:
- # The coefficient vector is returned as a `Vector{Int32}`, and the last element is not actually part of the coefficients of Q(t).
- # what?
- h = (Int32).([coeff(hilbert_numerator, i) for i in 0:degree(hilbert_numerator)+1])
- end
-
- singular_I_gens = singular_generators(I.gens, ordering)
- singular_ring = base_ring(singular_I_gens)
- J = Singular.Ideal(singular_ring, gens(singular_I_gens)...)
- i = Singular.std_hilbert(J, h, (Int32).(weights),
- complete_reduction = complete_reduction)
- GB = IdealGens(I.gens.Ox, i, complete_reduction)
- GB.isGB = true
- GB.ord = ordering
- if isdefined(GB, :S)
- GB.S.isGB = true
- end
- I.gb[destination_ordering] = GB
- return GB
-end
-
-# Helper functions for groebner_basis_with_hilbert
-
-function _extract_weights(T::MPolyDecRing)
- if !is_z_graded(T)
- error("Ring must be graded by the Integers.")
- end
- return [Int(first(gr_elem.coeff)) for gr_elem in T.d]
-end
-
-function _extend_mon_order(ordering::MonomialOrdering,
- homogenized_ring::MPolyDecRing)
-
- nvars = ngens(ordering.R)
- m = canonical_matrix(ordering)
- m_hom = similar(m, nvars + 1, nvars + 1)
- m_hom[1, :] = ones(Int, nvars + 1)
- m_hom[2:end, 2:end] = m
- return matrix_ordering(homogenized_ring, m_hom)
-end
-
-function _mod_rand_prime(I::MPolyIdeal)
- p = 32771
- while true
- p = Hecke.next_prime(p)
-
- base_field = GF(p)
- ModP, _ = polynomial_ring(base_field, ngens(base_ring(I)); cached = false)
- I_mod_p_gens =
- try
- [map_coefficients(base_field, f; parent=ModP) for f in gens(I)]
- catch e
- # this precise error is thrown if the chosen prime p divides one
- # of the denominators of the coefficients of the generators of I.
- # In this case we simply choose the next prime and try again.
- if e == ErrorException("Unable to coerce")
- continue
- else
- rethrow(e)
- end
- end
- return ideal(ModP, I_mod_p_gens)
- end
-end
-
-# check homogeneity w.r.t. some weights
-
-function _is_homogeneous(f::MPolyRingElem, weights::Vector{Int})
- w = sum(weights .* first(exponents(f)))
- all(sum(weights .* e) == w for e in exponents(f))
-end
-
-
-# check homogeneity w.r.t. total degree
-function _is_homogeneous(f::MPolyRingElem)
- leadexpv,tailexpvs = Iterators.peel(AbstractAlgebra.exponent_vectors(f))
- d = sum(leadexpv)
- for tailexpv in tailexpvs
- if d!=sum(tailexpv)
- return false
- end
- end
- return true
-end
-
-# compute weights such that F is a homogeneous system w.r.t. these weights
-function _find_weights(F::Vector{P}) where {P <: MPolyRingElem}
-
- if all(_is_homogeneous, F)
- return ones(Int, ngens(parent(F[1])))
- end
-
- nrows = sum((length).(F)) - length(F)
- ncols = ngens(parent(first(F)))
-
- exp_diffs = permutedims(reduce(hcat, [e[i] - e[1] for e in
- (collect).((exponents).(F))
- for i in 2:length(e)]))
- K = kernel(matrix(QQ, nrows, ncols, exp_diffs); side = :right)
- isempty(K) && return zeros(Int, ncols)
- # Here we try to find a vector with strictly positive entries in K
- # this method to find such a vector is taken from
- # https://mathoverflow.net/questions/363181/intersection-of-a-vector-subspace-with-a-cone
- Pol = polyhedron(-K, zeros(Int, ncols))
- !is_feasible(Pol) && return zeros(Int, ncols)
- pos_vec = zeros(Int, ncols)
- for i in 1:ncols
- ei = [j == i ? one(QQ) : zero(QQ) for j in 1:ncols]
- obj_func = ei * K
- L = linear_program(Pol, obj_func)
- m, v = solve_lp(L)
- if isnothing(v)
- Pol_new = intersect(Pol, polyhedron(ei*K, [1]))
- L = linear_program(Pol_new, obj_func)
- v = optimal_vertex(L)
- end
- pos_vec += K*(v.p)
- end
- ret = (Int).(lcm((denominator).(pos_vec)) .* pos_vec)
- ret = (x -> div(x, gcd(ret))).(ret)
- # assure that the weights fit in Int32 for singular
- return all(ret .< 2^32) ? ret : zeros(Int,ncols)
-end
-
-# modular gröbner basis techniques using Singular
-@doc raw"""
- groebner_basis_modular(I::MPolyIdeal{QQMPolyRingElem}; ordering::MonomialOrdering = default_ordering(base_ring(I)), certify::Bool = false)
-
-Compute the reduced Gröbner basis of `I` w.r.t. `ordering` using a
-multi-modular strategy.
-
-!!! note
- This function is probabilistic and returns a correct result
- only with high probability.
-```jldoctest
-julia> R, (x, y, z) = polynomial_ring(QQ, [:x,:y,:z]);
-
-julia> I = ideal(R, [x^2+1209, x*y + 3279*y^2])
-Ideal generated by
- x^2 + 1209
- x*y + 3279*y^2
-
-julia> groebner_basis_modular(I)
-Gröbner basis with elements
- 1 -> y^3 + 403//3583947*y
- 2 -> x^2 + 1209
- 3 -> x*y + 3279*y^2
-with respect to the ordering
- degrevlex([x, y, z])
-```
-"""
-function groebner_basis_modular(I::MPolyIdeal{QQMPolyRingElem}; ordering::MonomialOrdering = default_ordering(base_ring(I)),
- certify::Bool = false)
-
- # small function to get a canonically sorted reduced gb
- sorted_gb = idl -> begin
- R = base_ring(idl)
- gb = gens(groebner_basis(idl, ordering = ordering,
- complete_reduction = true))
- sort!(gb; by = leading_monomial,
- lt = (m1, m2) -> cmp(MonomialOrdering(R, ordering.o), m1, m2) > 0)
- end
-
- if haskey(I.gb, ordering)
- return I.gb[ordering]
- end
-
- primes = Hecke.PrimesSet(rand(2^15:2^16), -1)
-
- p = iterate(primes)[1]
- Qt = base_ring(I)
- Zt = polynomial_ring(ZZ, [string(s) for s = symbols(Qt)]; cached = false)[1]
-
- Rt, t = polynomial_ring(GF(p), [string(s) for s = symbols(Qt)]; cached = false)
- std_basis_mod_p_lifted = map(sorted_gb(ideal(Rt, gens(I)))) do x
- map_coefficients(z -> lift(ZZ, z), x, parent = Zt)
- end
- std_basis_crt_previous = std_basis_mod_p_lifted
-
- n_stable_primes = 0
- d = ZZRingElem(p)
- unlucky_primes_in_a_row = 0
- done = false
- while !done
- while n_stable_primes < 2
- p = iterate(primes, p)[1]
- Rt, t = polynomial_ring(GF(p), [string(s) for s = symbols(Qt)]; cached = false)
- std_basis_mod_p_lifted = map(sorted_gb(ideal(Rt, gens(I)))) do x
- map_coefficients(z -> lift(ZZ, z), x, parent = Zt)
- end
-
- # test for unlucky prime
- if any(((i, p), ) -> leading_monomial(p) != leading_monomial(std_basis_crt_previous[i]),
- enumerate(std_basis_mod_p_lifted))
- unlucky_primes_in_a_row += 1
- # if we get unlucky twice in a row we assume that
- # we started with an unlucky prime
- if unlucky_primes_in_a_row == 2
- std_basis_crt_previous = std_basis_mod_p_lifted
- end
- continue
- end
- unlucky_primes_in_a_row = 0
-
- is_stable = true
- for (i, f) in enumerate(std_basis_mod_p_lifted)
- if !iszero(f - std_basis_crt_previous[i])
- std_basis_crt_previous[i], _ = induce_crt(std_basis_crt_previous[i], d, f, ZZRingElem(p), true)
- stable = false
- end
- end
- if is_stable
- n_stable_primes += 1
- end
- d *= ZZRingElem(p)
- end
- final_gb = QQMPolyRingElem[induce_rational_reconstruction(f, d, parent = base_ring(I)) for f in std_basis_crt_previous]
-
- I.gb[ordering] = IdealGens(final_gb, ordering)
- if certify
- done = _certify_modular_groebner_basis(I, ordering)
- else
- done = true
- end
- end
- I.gb[ordering].isGB = true
- return I.gb[ordering]
-end
-
-function induce_rational_reconstruction(f::ZZMPolyRingElem, d::ZZRingElem; parent = 1)
- g = MPolyBuildCtx(parent)
- for (c, v) in zip(AbstractAlgebra.coefficients(f), AbstractAlgebra.exponent_vectors(f))
- fl, r, s = Hecke.rational_reconstruction(c, d)
- fl ? push_term!(g, r//s, v) : push_term!(g, c, v)
- end
- return finish(g)
-end
-
-function _certify_modular_groebner_basis(I::MPolyIdeal, ordering::MonomialOrdering)
- @req haskey(I.gb, ordering) "There exists no standard basis w.r.t. the given ordering."
- ctr = 0
- singular_generators(I.gb[ordering])
- SR = I.gb[ordering].gens.Sx
- SG = I.gb[ordering].gens.S
-
- #= test if I is included in =#
- for f in I.gens
- if Singular.reduce(SR(f), SG) != 0
- break
- end
- ctr += 1
- end
- if ctr != ngens(I)
- return false
- end
-
- #= test if G is a standard basis of w.r.t. ordering =#
- return is_standard_basis(I.gb[ordering], ordering=ordering)
-end
diff --git a/src/Rings/groebner/f4.jl b/src/Rings/groebner/f4.jl
new file mode 100644
index 000000000000..5ed611bbf64a
--- /dev/null
+++ b/src/Rings/groebner/f4.jl
@@ -0,0 +1,88 @@
+function is_f4_applicable(I::MPolyIdeal, ordering::MonomialOrdering)
+ return (ordering == degrevlex(base_ring(I)) && !is_graded(base_ring(I))
+ && ((coefficient_ring(I) isa FqField
+ && absolute_degree(coefficient_ring(I)) == 1
+ && characteristic(coefficient_ring(I)) < 2^31)
+ || base_ring(I) isa QQMPolyRing))
+end
+
+@doc raw"""
+ groebner_basis_f4(I::MPolyIdeal, )
+
+Compute a Gröbner basis of `I` with respect to `degrevlex` using Faugère's F4 algorithm.
+See [Fau99](@cite) for more information.
+
+!!! note
+ At current state only prime fields of characteristic `0 < p < 2^{31}` and the rationals are supported.
+
+# Possible keyword arguments
+- `initial_hts::Int=17`: initial hash table size `log_2`.
+- `nr_thrds::Int=1`: number of threads for parallel linear algebra.
+- `max_nr_pairs::Int=0`: maximal number of pairs per matrix, only bounded by minimal degree if `0`.
+- `la_option::Int=2`: linear algebra option: exact sparse-dense (`1`), exact sparse (`2`, default), probabilistic sparse-dense (`42`), probabilistic sparse(`44`).
+- `eliminate::Int=0`: size of first block of variables to be eliminated.
+- `complete_reduction::Bool=true`: compute a reduced Gröbner basis for `I`
+- `normalize::Bool=true`: normalizes elements in computed Gröbner basis for `I`
+- `truncate_lifting::Int=0`: degree up to which the elements of the Gröbner basis are lifted to `QQ`, `0` for complete lifting
+- `info_level::Int=0`: info level printout: off (`0`, default), summary (`1`), detailed (`2`).
+
+# Examples
+```jldoctest
+julia> R,(x,y,z) = polynomial_ring(GF(101), [:x,:y,:z])
+(Multivariate polynomial ring in 3 variables over GF(101), FqMPolyRingElem[x, y, z])
+
+julia> I = ideal(R, [x+2*y+2*z-1, x^2+2*y^2+2*z^2-x, 2*x*y+2*y*z-y])
+Ideal generated by
+ x + 2*y + 2*z + 100
+ x^2 + 100*x + 2*y^2 + 2*z^2
+ 2*x*y + 2*y*z + 100*y
+
+julia> groebner_basis_f4(I)
+Gröbner basis with elements
+ 1: x + 2*y + 2*z + 100
+ 2: y*z + 82*z^2 + 10*y + 40*z
+ 3: y^2 + 60*z^2 + 20*y + 81*z
+ 4: z^3 + 28*z^2 + 64*y + 13*z
+with respect to the ordering
+ degrevlex([x, y, z])
+```
+"""
+function groebner_basis_f4(
+ I::MPolyIdeal;
+ initial_hts::Int=17,
+ nr_thrds::Int=1,
+ max_nr_pairs::Int=0,
+ la_option::Int=2,
+ eliminate::Int=0,
+ complete_reduction::Bool=true,
+ normalize::Bool=true,
+ truncate_lifting::Int=0,
+ info_level::Int=0
+ )
+
+ AI = AlgebraicSolving.Ideal(I.gens.O)
+ vars = gens(base_ring(I))[eliminate+1:end]
+ ord = degrevlex(vars)
+ if length(AI.gens) == 0
+ I.gb[ord] = IdealGens(I.gens.Ox, singular_generators(I), complete_reduction)
+ I.gb[ord].ord = ord
+ I.gb[ord].isGB = true
+ I.gb[ord].S.isGB = true
+ else
+ AlgebraicSolving.groebner_basis(AI,
+ initial_hts = initial_hts,
+ nr_thrds = nr_thrds,
+ max_nr_pairs = max_nr_pairs,
+ la_option = la_option,
+ eliminate = eliminate,
+ complete_reduction = complete_reduction,
+ normalize = normalize,
+ truncate_lifting = truncate_lifting,
+ info_level = info_level)
+
+ I.gb[ord] =
+ IdealGens(AI.gb[eliminate], ord, keep_ordering = false, isGB = true)
+ I.gb[ord].isReduced = complete_reduction
+ end
+ return I.gb[ord]
+end
diff --git a/src/Rings/groebner/fglm.jl b/src/Rings/groebner/fglm.jl
new file mode 100644
index 000000000000..b8ded21f0efd
--- /dev/null
+++ b/src/Rings/groebner/fglm.jl
@@ -0,0 +1,162 @@
+@doc raw"""
+ _fglm(G::IdealGens; ordering::MonomialOrdering)
+
+Converts a Gröbner basis `G` w.r.t. a given global monomial ordering for ``
+to a Gröbner basis `H` w.r.t. another monomial ordering `ordering` for ``.
+
+**NOTE**: `_fglm` assumes that `G` is a reduced Gröbner basis (i.e. w.r.t. a global monomial ordering) and that `ordering` is a global monomial ordering.
+
+# Examples
+```jldoctest
+julia> R, (x1, x2, x3, x4) = polynomial_ring(GF(101), [:x1, :x2, :x3, :x4])
+(Multivariate polynomial ring in 4 variables over GF(101), FqMPolyRingElem[x1, x2, x3, x4])
+
+julia> J = ideal(R, [x1+2*x2+2*x3+2*x4-1,
+ x1^2+2*x2^2+2*x3^2+2*x4^2-x1,
+ 2*x1*x2+2*x2*x3+2*x3*x4-x2,
+ x2^2+2*x1*x3+2*x2*x4-x3
+ ])
+Ideal generated by
+ x1 + 2*x2 + 2*x3 + 2*x4 + 100
+ x1^2 + 100*x1 + 2*x2^2 + 2*x3^2 + 2*x4^2
+ 2*x1*x2 + 2*x2*x3 + 100*x2 + 2*x3*x4
+ 2*x1*x3 + x2^2 + 2*x2*x4 + 100*x3
+
+julia> groebner_basis(J, ordering=degrevlex(R), complete_reduction=true)
+Gröbner basis with elements
+ 1: x1 + 2*x2 + 2*x3 + 2*x4 + 100
+ 2: x3^2 + 2*x2*x4 + 19*x3*x4 + 76*x4^2 + 72*x2 + 86*x3 + 42*x4
+ 3: x2*x3 + 99*x2*x4 + 40*x3*x4 + 11*x4^2 + 65*x2 + 58*x3 + 30*x4
+ 4: x2^2 + 2*x2*x4 + 30*x3*x4 + 45*x4^2 + 43*x2 + 72*x3 + 86*x4
+ 5: x3*x4^2 + 46*x4^3 + 28*x2*x4 + 16*x3*x4 + 7*x4^2 + 58*x2 + 63*x3 + 15*x4
+ 6: x2*x4^2 + 67*x4^3 + 56*x2*x4 + 58*x3*x4 + 45*x4^2 + 14*x2 + 86*x3
+ 7: x4^4 + 65*x4^3 + 26*x2*x4 + 47*x3*x4 + 71*x4^2 + 37*x2 + 79*x3 + 100*x4
+with respect to the ordering
+ degrevlex([x1, x2, x3, x4])
+
+julia> Oscar._fglm(J.gb[degrevlex(R)], lex(R))
+Gröbner basis with elements
+ 1: x4^8 + 36*x4^7 + 95*x4^6 + 39*x4^5 + 74*x4^4 + 7*x4^3 + 45*x4^2 + 98*x4
+ 2: x3 + 53*x4^7 + 93*x4^6 + 74*x4^5 + 26*x4^4 + 56*x4^3 + 15*x4^2 + 88*x4
+ 3: x2 + 25*x4^7 + 57*x4^6 + 13*x4^5 + 16*x4^4 + 78*x4^3 + 31*x4^2 + 16*x4
+ 4: x1 + 46*x4^7 + 3*x4^6 + 28*x4^5 + 17*x4^4 + 35*x4^3 + 9*x4^2 + 97*x4 + 100
+with respect to the ordering
+ lex([x1, x2, x3, x4])
+```
+"""
+function _fglm(G::IdealGens, ordering::MonomialOrdering)
+ (G.isGB == true && G.isReduced == true) || error("Input must be a reduced Gröbner basis.")
+ Singular.dimension(singular_generators(G)) == 0 || error("Dimension of corresponding ideal must be zero.")
+ SR_destination, = Singular.polynomial_ring(base_ring(G.Sx), symbols(G.Sx); ordering = singular(ordering))
+
+ ptr = Singular.libSingular.fglmzero(G.S.ptr, G.Sx.ptr, SR_destination.ptr)
+ return IdealGens(base_ring(G), Singular.sideal{Singular.spoly}(SR_destination, ptr, true))
+end
+
+@doc raw"""
+ fglm(I::MPolyIdeal; start_ordering::MonomialOrdering = default_ordering(base_ring(I)),
+ destination_ordering::MonomialOrdering)
+
+Given a **zero-dimensional** ideal `I`, return the reduced Gröbner basis of `I` with respect to `destination_ordering`.
+
+!!! note
+ Both `start_ordering` and `destination_ordering` must be global and the base ring of `I` must be a polynomial ring over a field.
+
+!!! note
+ The function implements the Gröbner basis conversion algorithm by **F**augère, **G**ianni, **L**azard, and **M**ora. See [FGLM93](@cite) for more information.
+
+# Examples
+```jldoctest
+julia> R, (a, b, c, d, e) = polynomial_ring(QQ, [:a, :b, :c, :d, :e]);
+
+julia> f1 = a+b+c+d+e;
+
+julia> f2 = a*b+b*c+c*d+a*e+d*e;
+
+julia> f3 = a*b*c+b*c*d+a*b*e+a*d*e+c*d*e;
+
+julia> f4 = b*c*d+a*b*c*e+a*b*d*e+a*c*d*e+b*c*d*e;
+
+julia> f5 = a*b*c*d*e-1;
+
+julia> I = ideal(R, [f1, f2, f3, f4, f5]);
+
+julia> G = fglm(I, destination_ordering = lex(R));
+
+julia> length(G)
+8
+
+julia> total_degree(G[8])
+60
+
+julia> leading_coefficient(G[8])
+83369589588385815165248207597941242098312973356252482872580035860533111990678631297423089011608753348453253671406641805924218003925165995322989635503951507226650115539638517111445927746874479234
+```
+"""
+function fglm(I::MPolyIdeal; start_ordering::MonomialOrdering = default_ordering(base_ring(I)), destination_ordering::MonomialOrdering)
+ isa(coefficient_ring(I), AbstractAlgebra.Field) || error("The FGLM algorithm requires a coefficient ring that is a field.")
+ (is_global(start_ordering) && is_global(destination_ordering)) || error("Start and destination orderings must be global.")
+ haskey(I.gb, destination_ordering) && return I.gb[destination_ordering]
+ if !haskey(I.gb, start_ordering)
+ standard_basis(I, ordering=start_ordering, complete_reduction=true)
+ elseif I.gb[start_ordering].isReduced == false
+ I.gb[start_ordering] = _compute_standard_basis(I.gb[start_ordering], start_ordering, true)
+ end
+
+ I.gb[destination_ordering] = _fglm(I.gb[start_ordering], destination_ordering)
+
+ return I.gb[destination_ordering]
+end
+
+@doc raw"""
+ _compute_groebner_basis_using_fglm(I::MPolyIdeal, destination_ordering::MonomialOrdering)
+
+Computes a reduced Gröbner basis for `I` w.r.t. `destination_ordering` using the FGLM algorithm.
+
+**Note**: Internal function, subject to change, do not use.
+
+# Examples
+```jldoctest
+julia> R, (x, y) = polynomial_ring(QQ, [:x, :y])
+(Multivariate polynomial ring in 2 variables over QQ, QQMPolyRingElem[x, y])
+
+julia> I = ideal(R,[x^2+y,x*y-y])
+Ideal generated by
+ x^2 + y
+ x*y - y
+
+julia> Oscar._compute_groebner_basis_using_fglm(I, lex(R))
+Gröbner basis with elements
+ 1: y^2 + y
+ 2: x*y - y
+ 3: x^2 + y
+with respect to the ordering
+ lex([x, y])
+
+julia> I.gb[lex(R)]
+Gröbner basis with elements
+ 1: y^2 + y
+ 2: x*y - y
+ 3: x^2 + y
+with respect to the ordering
+ lex([x, y])
+
+julia> I.gb[degrevlex(R)]
+Gröbner basis with elements
+ 1: y^2 + y
+ 2: x*y - y
+ 3: x^2 + y
+with respect to the ordering
+ degrevlex([x, y])
+```
+"""
+function _compute_groebner_basis_using_fglm(I::MPolyIdeal,
+ destination_ordering::MonomialOrdering)
+ isa(coefficient_ring(I), AbstractAlgebra.Field) || error("The FGLM algorithm requires a coefficient ring that is a field.")
+ haskey(I.gb, destination_ordering) && return I.gb[destination_ordering]
+ is_global(destination_ordering) || error("Destination ordering must be global.")
+ G = groebner_assure(I, true, true)
+ start_ordering = G.ord
+ dim(I) == 0 || error("Dimension of ideal must be zero.")
+ I.gb[destination_ordering] = _fglm(G, destination_ordering)
+end
diff --git a/src/Rings/groebner/general.jl b/src/Rings/groebner/general.jl
new file mode 100644
index 000000000000..d033831fd63f
--- /dev/null
+++ b/src/Rings/groebner/general.jl
@@ -0,0 +1,242 @@
+# groebner stuff #######################################################
+@doc raw"""
+ _compute_standard_basis(B::IdealGens; ordering::MonomialOrdering,
+ complete_reduction::Bool = false)
+
+**Note**: Internal function, subject to change, do not use.
+
+Given an `IdealGens` `B` and optional parameters `ordering` for a monomial ordering and `complete_reduction`
+this function computes a Gröbner basis (if `complete_reduction = true` the reduced Gröbner basis) of the
+ideal spanned by the elements in `B` w.r.t. the given monomial ordering `ordering`. The Gröbner basis is then
+returned in `B.S`.
+
+# Examples
+```jldoctest
+julia> R,(x,y) = polynomial_ring(QQ, [:x,:y])
+(Multivariate polynomial ring in 2 variables over QQ, QQMPolyRingElem[x, y])
+
+julia> A = Oscar.IdealGens([x*y-3*x,y^3-2*x^2*y])
+Ideal generating system with elements
+ 1: x*y - 3*x
+ 2: -2*x^2*y + y^3
+
+julia> B = Oscar._compute_standard_basis(A, degrevlex(R))
+Gröbner basis with elements
+ 1: x*y - 3*x
+ 2: y^3 - 6*x^2
+ 3: 2*x^3 - 9*x
+with respect to the ordering
+ degrevlex([x, y])
+```
+"""
+function _compute_standard_basis(B::IdealGens, ordering::MonomialOrdering, complete_reduction::Bool = false)
+ gensSord = singular_generators(B, ordering)
+ i = Singular.std(gensSord, complete_reduction = complete_reduction)
+ BA = IdealGens(B.Ox, i, complete_reduction)
+ BA.isGB = true
+ BA.ord = ordering
+ if isdefined(BA, :S)
+ BA.S.isGB = true
+ end
+ return BA
+end
+
+# standard basis for non-global orderings #############################
+@doc raw"""
+ standard_basis(I::MPolyIdeal; ordering::MonomialOrdering = default_ordering(base_ring(I)),
+ complete_reduction::Bool = false, algorithm::Symbol = :buchberger)
+
+Return a standard basis of `I` with respect to `ordering`.
+
+The keyword `algorithm` can be set to
+- `:buchberger` (implementation of Buchberger's algorithm in *Singular*),
+- `:modular` (implementation of multi-modular approach, if applicable),
+- `:f4` (implementation of Faugère's F4 algorithm in the *msolve* package),
+- `:fglm` (implementation of the FGLM algorithm in *Singular*),
+- `:hc` (implementation of Buchberger's algorithm in *Singular* trying to first compute the highest corner modulo some prime), and
+- `:hilbert` (implementation of a Hilbert driven Gröbner basis computation in *Singular*).
+
+!!! note
+ See the description of the functions `groebner_basis_hilbert_driven`, `fglm`,
+ and `f4` in the OSCAR documentation for some more details and for restrictions
+ on the input data when using these versions of the standard basis algorithm.
+
+!!! note
+ The returned standard basis is reduced if `ordering` is `global` and `complete_reduction = true`.
+
+# Examples
+```jldoctest
+julia> R,(x,y) = polynomial_ring(QQ, [:x,:y]);
+
+julia> I = ideal([x*(x+1), x^2-y^2+(x-2)*y]);
+
+julia> standard_basis(I, ordering = negdegrevlex(R))
+Standard basis with elements
+ 1: x
+ 2: y
+with respect to the ordering
+ negdegrevlex([x, y])
+```
+"""
+function standard_basis(I::MPolyIdeal; ordering::MonomialOrdering = default_ordering(base_ring(I)),
+ complete_reduction::Bool = false, algorithm::Symbol = :buchberger)
+ complete_reduction && @assert is_global(ordering)
+ @req is_exact_type(elem_type(base_ring(I))) "This functionality is only supported over exact fields."
+ if haskey(I.gb, ordering) && (complete_reduction == false || I.gb[ordering].isReduced == true)
+ return I.gb[ordering]
+ end
+ if algorithm == :buchberger
+ if !haskey(I.gb, ordering)
+ I.gb[ordering] = _compute_standard_basis(I.gens, ordering, complete_reduction)
+ elseif complete_reduction == true
+ I.gb[ordering] = _compute_standard_basis(I.gb[ordering], ordering, complete_reduction)
+ end
+ elseif algorithm == :modular
+ if is_f4_applicable(I, ordering)
+ # since msolve v0.7.0 is most of the time more efficient
+ # to compute a reduced GB by default
+ groebner_basis_f4(I, complete_reduction=true)
+ elseif base_ring(I) isa QQMPolyRing
+ groebner_basis_modular(I, ordering=ordering)
+ else
+ error("Modular option not applicable in this setting.")
+ end
+ elseif algorithm == :fglm
+ _compute_groebner_basis_using_fglm(I, ordering)
+ elseif algorithm == :hc
+ standard_basis_highest_corner(I, ordering=ordering)
+ elseif algorithm == :hilbert
+ weights = _find_weights(gens(I))
+ if !any(iszero, weights)
+ J, target_ordering, hn = I, ordering, nothing
+ else
+ R = base_ring(I)
+ K = iszero(characteristic(R)) && !haskey(I.gb, degrevlex(R)) ? _mod_rand_prime(I) : I
+ S = base_ring(K)
+ gb = groebner_assure(K, degrevlex(S))
+ # 2024-02-09 Next lines "blindly" updated to use new homogenization UI
+ H = homogenizer(S, "w")
+ K_hom = H(K)
+ gb_hom = IdealGens(H.(gens(gb)))
+ gb_hom.isGB = true
+ K_hom.gb[degrevlex(S)] = gb_hom
+ singular_assure(K_hom.gb[degrevlex(S)])
+ hn = hilbert_series(quo(base_ring(K_hom), K_hom)[1])[1]
+ H2 = homogenizer(R, "w")
+ J = H2(I)
+ weights = ones(Int, ngens(base_ring(J)))
+ target_ordering = _extend_mon_order(ordering, base_ring(J))
+ end
+ GB = groebner_basis_hilbert_driven(J, destination_ordering=target_ordering,
+ complete_reduction=complete_reduction,
+ weights=weights,
+ hilbert_numerator=hn)
+ if base_ring(I) == base_ring(J)
+ I.gb[ordering] = GB
+ else
+ DH2 = dehomogenizer(H2)
+ GB_dehom_gens = DH2.(gens(GB))
+ I.gb[ordering] = IdealGens(GB_dehom_gens, ordering, isGB = true)
+ end
+ elseif algorithm == :f4
+ # since msolve v0.7.0 is most of the time more efficient
+ # to compute a reduced GB by default
+ groebner_basis_f4(I, complete_reduction=true)
+ end
+ return I.gb[ordering]
+end
+
+@doc raw"""
+ groebner_basis(I::MPolyIdeal;
+ ordering::MonomialOrdering = default_ordering(base_ring(I)),
+ complete_reduction::Bool = false, algorithm::Symbol = :buchberger)
+
+If `ordering` is global, return a Gröbner basis of `I` with respect to `ordering`.
+
+The keyword `algorithm` can be set to
+- `:buchberger` (implementation of Buchberger's algorithm in *Singular*),
+- `:modular` (implementation of multi-modular approach, if applicable),
+- `:hilbert` (implementation of a Hilbert driven Gröbner basis computation in *Singular*),
+- `:fglm` (implementation of the FGLM algorithm in *Singular*), and
+- `:f4` (implementation of Faugère's F4 algorithm in the *msolve* package).
+
+!!! note
+ See the description of the functions `groebner_basis_hilbert_driven`, `fglm`,
+ and `f4` in the OSCAR documentation for some more details and for restrictions
+ on the input data when using these versions of the standard basis algorithm.
+
+!!! note
+ The returned Gröbner basis is reduced if `complete_reduction = true`.
+
+# Examples
+```jldoctest
+julia> R, (x, y, z) = polynomial_ring(QQ, [:x, :y, :z]);
+
+julia> I = ideal(R, [y-x^2, z-x^3]);
+
+julia> G = groebner_basis(I)
+Gröbner basis with elements
+ 1: y^2 - x*z
+ 2: x*y - z
+ 3: x^2 - y
+with respect to the ordering
+ degrevlex([x, y, z])
+
+julia> elements(G)
+3-element Vector{QQMPolyRingElem}:
+ -x*z + y^2
+ x*y - z
+ x^2 - y
+
+julia> elements(G) == gens(G)
+true
+
+julia> groebner_basis(I, ordering = lex(R))
+Gröbner basis with elements
+ 1: y^3 - z^2
+ 2: x*z - y^2
+ 3: x*y - z
+ 4: x^2 - y
+with respect to the ordering
+ lex([x, y, z])
+```
+```jldoctest
+julia> R, (x, y) = graded_polynomial_ring(QQ, [:x, :y], [1, 3]);
+
+julia> I = ideal(R, [x*y-3*x^4,y^3-2*x^6*y]);
+
+julia> groebner_basis(I)
+Gröbner basis with elements
+ 1: 3*x^4 - x*y
+ 2: 2*x^3*y^2 - 3*y^3
+ 3: x*y^3
+ 4: y^4
+with respect to the ordering
+ wdegrevlex([x, y], [1, 3])
+```
+
+```jldoctest
+julia> R, (x, y, z) = polynomial_ring(QQ, [:x, :y, :z]);
+
+julia> V = [3*x^3*y+x^3+x*y^3+y^2*z^2, 2*x^3*z-x*y-x*z^3-y^4-z^2,
+ 2*x^2*y*z-2*x*y^2+x*z^2-y^4];
+
+julia> I = ideal(R, V);
+
+julia> G = groebner_basis(I, ordering = lex(R), algorithm = :fglm);
+
+julia> length(G)
+8
+
+julia> total_degree(G[8])
+34
+
+julia> leading_coefficient(G[8])
+-91230304237130414552564280286681870842473427917231798336639893796481988733936505735341479640589040146625319419037353645834346047404145021391726185993823650399589880820226804328750
+```
+"""
+function groebner_basis(I::MPolyIdeal; ordering::MonomialOrdering = default_ordering(base_ring(I)), complete_reduction::Bool=false,
+ algorithm::Symbol = :buchberger)
+ is_global(ordering) || error("Ordering must be global")
+ return standard_basis(I, ordering=ordering, complete_reduction=complete_reduction, algorithm=algorithm)
+end
diff --git a/src/Rings/groebner/generators.jl b/src/Rings/groebner/generators.jl
new file mode 100644
index 000000000000..80b61cc0d19d
--- /dev/null
+++ b/src/Rings/groebner/generators.jl
@@ -0,0 +1,72 @@
+@doc raw"""
+ groebner_assure(I::MPolyIdeal, complete_reduction::Bool = false, need_global::Bool = false)
+ groebner_assure(I::MPolyIdeal, ordering::MonomialOrdering, complete_reduction::Bool = false)
+
+**Note**: Internal function, subject to change, do not use.
+
+Given an ideal `I` in a multivariate polynomial ring this function assures that a
+Gröbner basis w.r.t. the given monomial ordering is attached to `I` in `I.gb`.
+It *currently* also ensures that the basis is defined on the Singular side in
+`I.gb.S`, but this should not be relied upon: use `singular_assure(I.gb)` before
+accessing `I.gb.S`.
+
+# Examples
+```jldoctest
+julia> R,(x,y) = polynomial_ring(QQ, [:x,:y])
+(Multivariate polynomial ring in 2 variables over QQ, QQMPolyRingElem[x, y])
+
+julia> I = ideal([x*y-3*x,y^3-2*x^2*y])
+Ideal generated by
+ x*y - 3*x
+ -2*x^2*y + y^3
+
+julia> Oscar.groebner_assure(I, degrevlex(R));
+
+julia> I.gb[degrevlex(R)]
+Gröbner basis with elements
+ 1: x*y - 3*x
+ 2: y^3 - 6*x^2
+ 3: 2*x^3 - 9*x
+with respect to the ordering
+ degrevlex([x, y])
+```
+"""
+function groebner_assure(I::MPolyIdeal, complete_reduction::Bool = false, need_global::Bool = false)
+ if !isempty(I.gb)
+ for G in values(I.gb)
+ need_global || return G
+ is_global(G.ord) || continue
+ complete_reduction || return G
+ if !G.isReduced
+ I.gb[G.ord] = _compute_standard_basis(G, G.ord, true)
+ end
+ return I.gb[G.ord]
+ end
+ end
+ ord = default_ordering(base_ring(I))
+ (need_global <= is_global(ord)) || error("Monomial ordering must be global.")
+ I.gb[ord] = groebner_assure(I, ord, complete_reduction)
+ return I.gb[ord]
+end
+
+function groebner_assure(I::MPolyIdeal, ordering::MonomialOrdering, complete_reduction::Bool = false)
+ return get!(I.gb, ordering) do
+ _compute_standard_basis(I.gens, ordering, complete_reduction)
+ end
+end
+
+function oscar_groebner_generators(I::MPolyIdeal, ordering::MonomialOrdering = default_ordering(base_ring(I)), complete_reduction::Bool = false)
+ standard_basis(I, ordering=ordering, complete_reduction = complete_reduction)
+ oscar_assure(I.gb[ordering])
+ return I.gb[ordering].gens.O
+end
+
+function singular_groebner_generators(I::MPolyIdeal, ordering::MonomialOrdering = default_ordering(base_ring(I)), complete_reduction::Bool = false)
+ standard_basis(I, ordering=ordering, complete_reduction = complete_reduction)
+ return singular_generators(I.gb[ordering], ordering)
+end
+
+function singular_groebner_generators(I::MPolyIdeal, complete_reduction::Bool, need_global::Bool)
+ G = groebner_assure(I, complete_reduction, need_global)
+ return singular_generators(G, G.ord)
+end
diff --git a/src/Rings/groebner/groebner.jl b/src/Rings/groebner/groebner.jl
new file mode 100644
index 000000000000..232e4eace58d
--- /dev/null
+++ b/src/Rings/groebner/groebner.jl
@@ -0,0 +1,10 @@
+include("f4.jl")
+include("fglm.jl")
+include("general.jl")
+include("generators.jl")
+include("highest-corner.jl")
+include("hilbert-driven.jl")
+include("leading-ideal.jl")
+include("modular.jl")
+include("reduce.jl")
+include("transformation-matrix.jl")
diff --git a/src/Rings/groebner/highest-corner.jl b/src/Rings/groebner/highest-corner.jl
new file mode 100644
index 000000000000..e721e71e58ba
--- /dev/null
+++ b/src/Rings/groebner/highest-corner.jl
@@ -0,0 +1,23 @@
+@doc raw"""
+ standard_basis_highest_corner(I::MPolyIdeal; ordering::MonomialOrdering = default_ordering(base_ring(I)))
+
+Return a standard basis of `I` with respect to `ordering`. `ordering` needs to be local, the coefficient ring needs to be `QQ`.
+The algorithm first computes a standard basis over a finite field in order to get an upper bound for the highest corner fast.
+Then this bound is used to speed up the standard basis computation over `QQ´.
+"""
+function standard_basis_highest_corner(I::MPolyIdeal; ordering::MonomialOrdering = default_ordering(base_ring(I)))
+ @req is_local(ordering) "Monomial ordering must be local for this variant."
+ @req coefficient_ring(I) == QQ "Base ring must be QQ."
+
+ #= apply highest corner standard basis variant in Singular =#
+ ssb = Singular.LibStandard.groebner(singular_groebner_generators(I, ordering), "HC")
+
+ sb = IdealGens(I.gens.Ox, ssb, false)
+ sb.isGB = true
+ sb.ord = ordering
+ if isdefined(sb, :S)
+ sb.S.isGB = true
+ end
+ I.gb[ordering] = sb
+ return sb
+end
diff --git a/src/Rings/groebner/hilbert-driven.jl b/src/Rings/groebner/hilbert-driven.jl
new file mode 100644
index 000000000000..1bc52994cb0a
--- /dev/null
+++ b/src/Rings/groebner/hilbert-driven.jl
@@ -0,0 +1,239 @@
+@doc raw"""
+ groebner_basis_hilbert_driven(I::MPolyIdeal{P}; destination_ordering::MonomialOrdering,
+ complete_reduction::Bool = false,
+ weights::Vector{Int} = ones(Int, ngens(base_ring(I))),
+ hilbert_numerator::Union{Nothing, ZZPolyRingElem} = nothing)
+ where {P <: MPolyRingElem}
+
+Return a Gröbner basis of `I` with respect to `destination_ordering`.
+
+!!! note
+ The function implements a version of the Hilbert driven Gröbner basis algorithm.
+ See the corresponding section of the OSCAR documentation for some details.
+
+!!! note
+ All weights must be positive. If no weight vector is entered by the user, all weights
+ are set to 1. An error is thrown if the generators of `I` are not homogeneous with
+ respect to the corresponding (weighted) degree.
+
+!!! note
+ If $R$ denotes the parent ring of $I$, and $p, q\in\mathbb Z[t]$ are polynomials
+ such that $p/q$ represents the Hilbert series of $R/I$ as a rational function with
+ denominator $q = (1-t^{w_1})\cdots (1-t^{w_n}),$ where $n$ is the number of variables
+ of $R$, and $w_1, \dots, w_n$ are the assigned weights, then `hilbert_numerator` is
+ meant to be $p$. If this numerator is not entered by the user, it will be computed
+ internally.
+
+# Examples
+```jldoctest
+julia> R, (a, b, c, d, e, f, g) = polynomial_ring(QQ, [:a, :b, :c, :d, :e, :f, :g]);
+
+julia> V = [-3*a^2+2*f*b+3*f*d, (3*g*b+3*g*e)*a-3*f*c*b,
+ -3*g^2*a^2-c*b^2*a-g^2*f*e-g^4, e*a-f*b-d*c];
+
+julia> I = ideal(R, V);
+
+julia> o = degrevlex([a, b, c])*degrevlex([d, e, f, g]);
+
+julia> G = groebner_basis_hilbert_driven(I, destination_ordering = o);
+
+julia> length(G)
+296
+
+julia> total_degree(G[49])
+30
+```
+
+```jldoctest
+julia> R, (x, y, z) = polynomial_ring(GF(32003), [:x, :y, :z]);
+
+julia> f1 = x^2*y+169*y^21+151*x*y*z^10;
+
+julia> f2 = 6*x^2*y^4+x*z^14+3*z^24;
+
+julia> f3 = 11*x^3+5*x*y^10*z^10+2*y^20*z^10+y^10*z^20;
+
+julia> I = ideal(R, [f1, f2,f3]);
+
+julia> W = [10, 1, 1];
+
+julia> GB = groebner_basis_hilbert_driven(I, destination_ordering = lex(R), weights = W);
+
+julia> length(GB)
+40
+```
+
+```jldoctest
+julia> R, (x, y, z) = polynomial_ring(GF(32003), [:x, :y, :z]);
+
+julia> f1 = x^2*y+169*y^21+151*x*y*z^10;
+
+julia> f2 = 6*x^2*y^4+x*z^14+3*z^24;
+
+julia> f3 = 11*x^3+5*x*y^10*z^10+2*y^20*z^10+y^10*z^20;
+
+julia> I = ideal(R, [f1, f2,f3]);
+
+julia> W = [10, 1, 1];
+
+julia> S, t = polynomial_ring(ZZ, :t)
+(Univariate polynomial ring in t over ZZ, t)
+
+julia> hn = -t^75 + t^54 + t^51 + t^45 - t^30 - t^24 - t^21 + 1
+-t^75 + t^54 + t^51 + t^45 - t^30 - t^24 - t^21 + 1
+
+julia> GB = groebner_basis_hilbert_driven(I, destination_ordering = lex(R), weights = W, hilbert_numerator = hn);
+
+julia> length(GB)
+40
+```
+"""
+function groebner_basis_hilbert_driven(I::MPolyIdeal{P};
+ destination_ordering::MonomialOrdering,
+ complete_reduction::Bool = false,
+ weights::Vector{Int} = ones(Int, ngens(base_ring(I))),
+ hilbert_numerator::Union{Nothing, ZZPolyRingElem} = nothing) where {P <: MPolyRingElem}
+
+ all(f -> _is_homogeneous(f, weights), gens(I)) || error("I must be given by generators homogeneous with respect to the given weights.")
+ isa(coefficient_ring(I), AbstractAlgebra.Field) || error("The underlying coefficient ring of I must be a field.")
+ ordering = destination_ordering
+ is_global(ordering) || error("Destination ordering must be global.")
+ haskey(I.gb, ordering) && return I.gb[ordering]
+ if isnothing(hilbert_numerator)
+ if isempty(I.gb)
+ J = iszero(characteristic(base_ring(I))) ? _mod_rand_prime(I) : I
+ G = groebner_assure(J, wdegrevlex(base_ring(J), weights))
+ else
+ G = groebner_assure(I)
+ end
+
+ if characteristic(base_ring(I)) > 0 && ordering == wdegrevlex(base_ring(I), weights)
+ return G
+ end
+ singular_assure(G)
+ h = Singular.hilbert_series(G.S, weights)
+
+ else
+ # Quoting from the documentation of Singular.hilbert_series:
+ # The coefficient vector is returned as a `Vector{Int32}`, and the last element is not actually part of the coefficients of Q(t).
+ # what?
+ h = (Int32).([coeff(hilbert_numerator, i) for i in 0:degree(hilbert_numerator)+1])
+ end
+
+ singular_I_gens = singular_generators(I.gens, ordering)
+ singular_ring = base_ring(singular_I_gens)
+ J = Singular.Ideal(singular_ring, gens(singular_I_gens)...)
+ i = Singular.std_hilbert(J, h, (Int32).(weights),
+ complete_reduction = complete_reduction)
+ GB = IdealGens(I.gens.Ox, i, complete_reduction)
+ GB.isGB = true
+ GB.ord = ordering
+ if isdefined(GB, :S)
+ GB.S.isGB = true
+ end
+ I.gb[destination_ordering] = GB
+ return GB
+end
+
+# Helper functions for groebner_basis_with_hilbert
+
+function _extract_weights(T::MPolyDecRing)
+ if !is_z_graded(T)
+ error("Ring must be graded by the Integers.")
+ end
+ return [Int(first(gr_elem.coeff)) for gr_elem in T.d]
+end
+
+function _extend_mon_order(ordering::MonomialOrdering,
+ homogenized_ring::MPolyDecRing)
+
+ nvars = ngens(ordering.R)
+ m = canonical_matrix(ordering)
+ m_hom = similar(m, nvars + 1, nvars + 1)
+ m_hom[1, :] = ones(Int, nvars + 1)
+ m_hom[2:end, 2:end] = m
+ return matrix_ordering(homogenized_ring, m_hom)
+end
+
+function _mod_rand_prime(I::MPolyIdeal)
+ p = 32771
+ while true
+ p = Hecke.next_prime(p)
+
+ base_field = GF(p)
+ ModP, _ = polynomial_ring(base_field, ngens(base_ring(I)); cached = false)
+ I_mod_p_gens =
+ try
+ [map_coefficients(base_field, f; parent=ModP) for f in gens(I)]
+ catch e
+ # this precise error is thrown if the chosen prime p divides one
+ # of the denominators of the coefficients of the generators of I.
+ # In this case we simply choose the next prime and try again.
+ if e == ErrorException("Unable to coerce")
+ continue
+ else
+ rethrow(e)
+ end
+ end
+ return ideal(ModP, I_mod_p_gens)
+ end
+end
+
+# check homogeneity w.r.t. some weights
+
+function _is_homogeneous(f::MPolyRingElem, weights::Vector{Int})
+ w = sum(weights .* first(exponents(f)))
+ all(sum(weights .* e) == w for e in exponents(f))
+end
+
+
+# check homogeneity w.r.t. total degree
+function _is_homogeneous(f::MPolyRingElem)
+ leadexpv,tailexpvs = Iterators.peel(AbstractAlgebra.exponent_vectors(f))
+ d = sum(leadexpv)
+ for tailexpv in tailexpvs
+ if d!=sum(tailexpv)
+ return false
+ end
+ end
+ return true
+end
+
+# compute weights such that F is a homogeneous system w.r.t. these weights
+function _find_weights(F::Vector{P}) where {P <: MPolyRingElem}
+
+ if all(_is_homogeneous, F)
+ return ones(Int, ngens(parent(F[1])))
+ end
+
+ nrows = sum((length).(F)) - length(F)
+ ncols = ngens(parent(first(F)))
+
+ exp_diffs = permutedims(reduce(hcat, [e[i] - e[1] for e in
+ (collect).((exponents).(F))
+ for i in 2:length(e)]))
+ K = kernel(matrix(QQ, nrows, ncols, exp_diffs); side = :right)
+ isempty(K) && return zeros(Int, ncols)
+ # Here we try to find a vector with strictly positive entries in K
+ # this method to find such a vector is taken from
+ # https://mathoverflow.net/questions/363181/intersection-of-a-vector-subspace-with-a-cone
+ Pol = polyhedron(-K, zeros(Int, ncols))
+ !is_feasible(Pol) && return zeros(Int, ncols)
+ pos_vec = zeros(Int, ncols)
+ for i in 1:ncols
+ ei = [j == i ? one(QQ) : zero(QQ) for j in 1:ncols]
+ obj_func = ei * K
+ L = linear_program(Pol, obj_func)
+ m, v = solve_lp(L)
+ if isnothing(v)
+ Pol_new = intersect(Pol, polyhedron(ei*K, [1]))
+ L = linear_program(Pol_new, obj_func)
+ v = optimal_vertex(L)
+ end
+ pos_vec += K*(v.p)
+ end
+ ret = (Int).(lcm((denominator).(pos_vec)) .* pos_vec)
+ ret = (x -> div(x, gcd(ret))).(ret)
+ # assure that the weights fit in Int32 for singular
+ return all(ret .< 2^32) ? ret : zeros(Int,ncols)
+end
diff --git a/src/Rings/groebner/leading-ideal.jl b/src/Rings/groebner/leading-ideal.jl
new file mode 100644
index 000000000000..c0e8b1f8dbd7
--- /dev/null
+++ b/src/Rings/groebner/leading-ideal.jl
@@ -0,0 +1,67 @@
+@doc raw"""
+ leading_ideal(G::Vector{T}; ordering::MonomialOrdering = default_ordering(parent(G[1])))
+ where T <: MPolyRingElem
+
+Return the leading ideal of `G` with respect to `ordering`.
+
+# Examples
+```jldoctest
+julia> R, (x, y) = polynomial_ring(QQ, [:x, :y])
+(Multivariate polynomial ring in 2 variables over QQ, QQMPolyRingElem[x, y])
+
+julia> L = leading_ideal([x*y^2-3*x, x^3-14*y^5], ordering=degrevlex(R))
+Ideal generated by
+ x*y^2
+ y^5
+
+julia> L = leading_ideal([x*y^2-3*x, x^3-14*y^5], ordering=lex(R))
+Ideal generated by
+ x*y^2
+ x^3
+```
+"""
+function leading_ideal(G::Vector{T}; ordering::MonomialOrdering = default_ordering(parent(G[1]))) where { T <: MPolyRingElem }
+ return ideal(parent(G[1]), [leading_monomial(f; ordering = ordering) for f in G])
+end
+
+function leading_ideal(I::IdealGens{T}) where { T <: MPolyRingElem }
+ return ideal(base_ring(I), [leading_monomial(f; ordering = I.ord) for f in I])
+end
+
+function leading_ideal(I::IdealGens{T}, ordering::MonomialOrdering) where T <: MPolyRingElem
+ return ideal(base_ring(I), [leading_monomial(f; ordering = ordering) for f in I])
+end
+
+
+@doc raw"""
+ leading_ideal(I::MPolyIdeal; ordering::MonomialOrdering = default_ordering(base_ring(I)))
+
+Return the leading ideal of `I` with respect to `ordering`.
+
+# Examples
+```jldoctest
+julia> R, (x, y) = polynomial_ring(QQ, [:x, :y])
+(Multivariate polynomial ring in 2 variables over QQ, QQMPolyRingElem[x, y])
+
+julia> I = ideal(R,[x*y^2-3*x, x^3-14*y^5])
+Ideal generated by
+ x*y^2 - 3*x
+ x^3 - 14*y^5
+
+julia> L = leading_ideal(I, ordering=degrevlex(R))
+Ideal generated by
+ x*y^2
+ x^4
+ y^5
+
+julia> L = leading_ideal(I, ordering=lex(R))
+Ideal generated by
+ y^7
+ x*y^2
+ x^3
+```
+"""
+function leading_ideal(I::MPolyIdeal; ordering::MonomialOrdering = default_ordering(base_ring(I)))
+ G = standard_basis(I, ordering=ordering)
+ return ideal(base_ring(I), [leading_monomial(g; ordering = ordering) for g in G])
+end
diff --git a/src/Rings/groebner/modular.jl b/src/Rings/groebner/modular.jl
new file mode 100644
index 000000000000..73f3c01ab610
--- /dev/null
+++ b/src/Rings/groebner/modular.jl
@@ -0,0 +1,135 @@
+# modular gröbner basis techniques using Singular
+@doc raw"""
+ groebner_basis_modular(I::MPolyIdeal{QQMPolyRingElem}; ordering::MonomialOrdering = default_ordering(base_ring(I)), certify::Bool = false)
+
+Compute the reduced Gröbner basis of `I` w.r.t. `ordering` using a
+multi-modular strategy.
+
+!!! note
+ This function is probabilistic and returns a correct result
+ only with high probability.
+```jldoctest
+julia> R, (x, y, z) = polynomial_ring(QQ, [:x,:y,:z]);
+
+julia> I = ideal(R, [x^2+1209, x*y + 3279*y^2])
+Ideal generated by
+ x^2 + 1209
+ x*y + 3279*y^2
+
+julia> groebner_basis_modular(I)
+Gröbner basis with elements
+ 1: y^3 + 403//3583947*y
+ 2: x^2 + 1209
+ 3: x*y + 3279*y^2
+with respect to the ordering
+ degrevlex([x, y, z])
+```
+"""
+function groebner_basis_modular(I::MPolyIdeal{QQMPolyRingElem}; ordering::MonomialOrdering = default_ordering(base_ring(I)),
+ certify::Bool = false)
+
+ # small function to get a canonically sorted reduced gb
+ sorted_gb = idl -> begin
+ R = base_ring(idl)
+ gb = gens(groebner_basis(idl, ordering = ordering,
+ complete_reduction = true))
+ sort!(gb; by = leading_monomial,
+ lt = (m1, m2) -> cmp(MonomialOrdering(R, ordering.o), m1, m2) > 0)
+ end
+
+ if haskey(I.gb, ordering)
+ return I.gb[ordering]
+ end
+
+ primes = Hecke.PrimesSet(rand(2^15:2^16), -1)
+
+ p = iterate(primes)[1]
+ Qt = base_ring(I)
+ Zt = polynomial_ring(ZZ, [string(s) for s = symbols(Qt)]; cached = false)[1]
+
+ Rt, t = polynomial_ring(GF(p), [string(s) for s = symbols(Qt)]; cached = false)
+ std_basis_mod_p_lifted = map(sorted_gb(ideal(Rt, gens(I)))) do x
+ map_coefficients(z -> lift(ZZ, z), x, parent = Zt)
+ end
+ std_basis_crt_previous = std_basis_mod_p_lifted
+
+ n_stable_primes = 0
+ d = ZZRingElem(p)
+ unlucky_primes_in_a_row = 0
+ done = false
+ while !done
+ while n_stable_primes < 2
+ p = iterate(primes, p)[1]
+ Rt, t = polynomial_ring(GF(p), [string(s) for s = symbols(Qt)]; cached = false)
+ std_basis_mod_p_lifted = map(sorted_gb(ideal(Rt, gens(I)))) do x
+ map_coefficients(z -> lift(ZZ, z), x, parent = Zt)
+ end
+
+ # test for unlucky prime
+ if any(((i, p), ) -> leading_monomial(p) != leading_monomial(std_basis_crt_previous[i]),
+ enumerate(std_basis_mod_p_lifted))
+ unlucky_primes_in_a_row += 1
+ # if we get unlucky twice in a row we assume that
+ # we started with an unlucky prime
+ if unlucky_primes_in_a_row == 2
+ std_basis_crt_previous = std_basis_mod_p_lifted
+ end
+ continue
+ end
+ unlucky_primes_in_a_row = 0
+
+ is_stable = true
+ for (i, f) in enumerate(std_basis_mod_p_lifted)
+ if !iszero(f - std_basis_crt_previous[i])
+ std_basis_crt_previous[i], _ = induce_crt(std_basis_crt_previous[i], d, f, ZZRingElem(p), true)
+ stable = false
+ end
+ end
+ if is_stable
+ n_stable_primes += 1
+ end
+ d *= ZZRingElem(p)
+ end
+ final_gb = QQMPolyRingElem[induce_rational_reconstruction(f, d, parent = base_ring(I)) for f in std_basis_crt_previous]
+
+ I.gb[ordering] = IdealGens(final_gb, ordering)
+ if certify
+ done = _certify_modular_groebner_basis(I, ordering)
+ else
+ done = true
+ end
+ end
+ I.gb[ordering].isGB = true
+ return I.gb[ordering]
+end
+
+function induce_rational_reconstruction(f::ZZMPolyRingElem, d::ZZRingElem; parent = 1)
+ g = MPolyBuildCtx(parent)
+ for (c, v) in zip(AbstractAlgebra.coefficients(f), AbstractAlgebra.exponent_vectors(f))
+ fl, r, s = Hecke.rational_reconstruction(c, d)
+ fl ? push_term!(g, r//s, v) : push_term!(g, c, v)
+ end
+ return finish(g)
+end
+
+function _certify_modular_groebner_basis(I::MPolyIdeal, ordering::MonomialOrdering)
+ @req haskey(I.gb, ordering) "There exists no standard basis w.r.t. the given ordering."
+ ctr = 0
+ singular_generators(I.gb[ordering])
+ SR = I.gb[ordering].gens.Sx
+ SG = I.gb[ordering].gens.S
+
+ #= test if I is included in =#
+ for f in I.gens
+ if Singular.reduce(SR(f), SG) != 0
+ break
+ end
+ ctr += 1
+ end
+ if ctr != ngens(I)
+ return false
+ end
+
+ #= test if G is a standard basis of w.r.t. ordering =#
+ return is_standard_basis(I.gb[ordering], ordering=ordering)
+end
diff --git a/src/Rings/groebner/reduce.jl b/src/Rings/groebner/reduce.jl
new file mode 100644
index 000000000000..2cdbfadef5fe
--- /dev/null
+++ b/src/Rings/groebner/reduce.jl
@@ -0,0 +1,662 @@
+@doc raw"""
+ reduce(I::IdealGens, J::IdealGens;
+ ordering::MonomialOrdering = default_ordering(base_ring(J)), complete_reduction::Bool = false)
+
+Return a `Vector` whose elements are the underlying elements of `I`
+reduced by the underlying generators of `J` w.r.t. the monomial
+ordering `ordering`. `J` need not be a Gröbner basis. The returned
+`Vector` will have the same number of elements as `I`, even if they
+are zero.
+
+# Examples
+```jldoctest
+julia> R, (x, y, z) = polynomial_ring(GF(11), [:x, :y, :z]);
+
+julia> I = ideal(R, [x^2, x*y - y^2]);
+
+julia> J = ideal(R, [y^3])
+Ideal generated by
+ y^3
+
+julia> reduce(J.gens, I.gens)
+1-element Vector{FqMPolyRingElem}:
+ y^3
+
+julia> reduce(J.gens, groebner_basis(I))
+1-element Vector{FqMPolyRingElem}:
+ 0
+
+julia> reduce(y^3, [x^2, x*y-y^3])
+x*y
+
+julia> reduce(y^3, [x^2, x*y-y^3], ordering=lex(R))
+y^3
+
+julia> reduce([y^3], [x^2, x*y-y^3], ordering=lex(R))
+1-element Vector{FqMPolyRingElem}:
+ y^3
+```
+"""
+function reduce(I::IdealGens, J::IdealGens; ordering::MonomialOrdering = default_ordering(base_ring(J)), complete_reduction::Bool = false)
+ @assert base_ring(J) == base_ring(I)
+ Is = singular_generators(I, ordering)
+ Js = singular_generators(J, ordering)
+ res = reduce(Is, Js, complete_reduction=complete_reduction)
+ return [J.gens.Ox(x) for x = gens(res)]
+end
+
+@doc raw"""
+ reduce(g::T, F::Union{Vector{T}, IdealGens{T}};
+ ordering::MonomialOrdering = default_ordering(g)), complete_reduction::Bool = false) where T <: MPolyRingElem
+
+If `ordering` is global, return the remainder in a standard representation for `g` on division by the polynomials in `F` with respect to `ordering`.
+Otherwise, return the remainder in a *weak* standard representation for `g` on division by the polynomials in `F` with respect to `ordering`.
+
+ reduce(G::Vector{T}, F::Union{Vector{T}, IdealGens{T}};
+ ordering::MonomialOrdering = default_ordering(parent(G[1])), complete_reduction::Bool = false) where T <: MPolyRingElem
+
+Return a `Vector` which contains, for each element `g` of `G`, a remainder as above.
+
+!!! note
+ The returned remainders are fully reduced if `complete_reduction` is set to `true` and `ordering` is global.
+
+!!! note
+ The reduction strategy behind the `reduce` function and the reduction strategy behind the functions
+ `reduce_with_quotients` and `reduce_with_quotients_and_unit` differ. As a consequence, the computed
+ remainders may differ.
+
+# Examples
+```jldoctest
+julia> R, (z, y, x) = polynomial_ring(QQ, [:z, :y, :x]);
+
+julia> f1 = y-x^2; f2 = z-x^3;
+
+julia> g = x^3*y-3*y^2*z^2+x*y*z;
+
+julia> reduce(g, [f1, f2], ordering = lex(R))
+-3*x^10 + x^6 + x^5
+```
+
+```jldoctest
+julia> R, (x, y, z) = polynomial_ring(QQ, [:x, :y, :z]);
+
+julia> f1 = x^2+x^2*y; f2 = y^3+x*y*z; f3 = x^3*y^2+z^4;
+
+julia> g = x^3*y+x^5+x^2*y^2*z^2+z^6;
+
+julia> reduce(g, [f1, f2, f3], ordering = lex(R))
+x^5 + x^3*y + x^2*y^2*z^2 + z^6
+
+julia> reduce(g, [f1,f2, f3], ordering = lex(R), complete_reduction = true)
+x^5 - x^3 + y^6 + z^6
+```
+
+"""
+function reduce(f::T, F::Vector{T}; ordering::MonomialOrdering = default_ordering(parent(f)), complete_reduction::Bool = false) where {T <: MPolyRingElem}
+ isempty(F) && return f
+ J = IdealGens(parent(F[1]), F, ordering)
+ return reduce(f, J; ordering=ordering, complete_reduction=complete_reduction)
+end
+
+function reduce(F::Vector{T}, G::Vector{T}; ordering::MonomialOrdering = default_ordering(parent(F[1])), complete_reduction::Bool = false) where {T <: MPolyRingElem}
+ isempty(G) && return F
+ J = IdealGens(parent(G[1]), G, ordering)
+ return reduce(F, J; ordering=ordering, complete_reduction=complete_reduction)
+end
+
+function reduce(f::T, F::IdealGens{T}; ordering::MonomialOrdering = default_ordering(parent(f)), complete_reduction::Bool = false) where {T <: MPolyRingElem}
+ isempty(F) && return f
+ @assert parent(f) == base_ring(F)
+ R = parent(f)
+ I = IdealGens(R, [f], ordering)
+ redv = reduce(I, F, ordering=ordering, complete_reduction=complete_reduction)
+ return redv[1]
+end
+
+function reduce(F::Vector{T}, G::IdealGens{T}; ordering::MonomialOrdering = default_ordering(parent(F[1])), complete_reduction::Bool = false) where {T <: MPolyRingElem}
+ (isempty(F) || isempty(G)) && return F
+ @assert parent(F[1]) == base_ring(G)
+ R = parent(F[1])
+ I = IdealGens(R, F, ordering)
+ return reduce(I, G, ordering=ordering, complete_reduction=complete_reduction)
+end
+
+@doc raw"""
+ reduce_with_quotients_and_unit(g::T, F::Union{Vector{T}, IdealGens{T}};
+ ordering::MonomialOrdering = default_ordering(parent(g)), complete_reduction::Bool = false) where T <: MPolyRingElem
+
+Return the unit, the quotients and the remainder in a weak standard representation for `g` on division by the polynomials in `F` with respect to `ordering`.
+
+ reduce_with_quotients_and_unit(G::Vector{T}, F::Union{Vector{T}, IdealGens{T}};
+ ordering::MonomialOrdering = default_ordering(parent(G[1])), complete_reduction::Bool = false) where T <: MPolyRingElem
+
+Return a `Vector` which contains, for each element `g` of `G`, a unit, quotients, and a remainder as above.
+
+!!! note
+ The returned remainders are fully reduced if `complete_reduction` is set to `true` and `ordering` is global.
+
+!!! note
+ The reduction strategy behind the `reduce` function and the reduction strategy behind the functions
+ `reduce_with_quotients` and `reduce_with_quotients_and_unit` differ. As a consequence, the computed
+ remainders may differ.
+
+# Examples
+```jldoctest
+julia> R, (x, y, z) = polynomial_ring(QQ, [:x, :y, :z]);
+
+julia> f1 = x^2+x^2*y; f2 = y^3+x*y*z; f3 = x^3*y^2+z^4;
+
+julia> g = x^3*y+x^5+x^2*y^2*z^2+z^6;
+
+julia> u, Q, h =reduce_with_quotients_and_unit(g, [f1,f2, f3], ordering = lex(R));
+
+julia> u
+[1]
+
+julia> G = [g, x*y^3-3*x^2*y^2*z^2];
+
+julia> U, Q, H = reduce_with_quotients_and_unit(G, [f1, f2, f3], ordering = negdegrevlex(R));
+
+julia> U
+[y + 1 0]
+[ 0 y + 1]
+
+julia> Q
+[ x^3 - x*y^2*z^2 + x*y + y^2*z^2 0 y*z^2 + z^2]
+[x*y*z^2 + y^3*z - 3*y^2*z^2 - y*z -x^2*y*z - x^2*z + x*y + x 0]
+
+julia> H
+2-element Vector{QQMPolyRingElem}:
+ 0
+ 0
+
+julia> U*G == Q*[f1, f2, f3]+H
+true
+```
+"""
+function reduce_with_quotients_and_unit(f::T, F::Vector{T}; ordering::MonomialOrdering = default_ordering(parent(f)), complete_reduction::Bool = false) where {T <: MPolyRingElem}
+ if isempty(F)
+ return identity_matrix(parent(f), 1), zero_matrix(parent(f), 1, 0), f
+ end
+ J = IdealGens(parent(F[1]), F, ordering)
+ return reduce_with_quotients_and_unit(f, J; ordering=ordering, complete_reduction=complete_reduction)
+end
+
+function reduce_with_quotients_and_unit(F::Vector{T}, G::Vector{T}; ordering::MonomialOrdering = default_ordering(parent(F[1])), complete_reduction::Bool = false) where {T <: MPolyRingElem}
+ @assert !isempty(F)
+ if isempty(G)
+ return identity_matrix(parent(F[1]), length(F)), zero_matrix(parent(F[1]), length(F), 0), F
+ end
+ J = IdealGens(parent(G[1]), G, ordering)
+ return reduce_with_quotients_and_unit(F, J; ordering=ordering, complete_reduction=complete_reduction)
+end
+
+function reduce_with_quotients_and_unit(f::T, F::IdealGens{T}; ordering::MonomialOrdering = default_ordering(parent(f)), complete_reduction::Bool = false) where {T <: MPolyRingElem}
+ if isempty(F)
+ return identity_matrix(parent(f), 1), zero_matrix(parent(f), 1, 0), f
+ end
+ @assert parent(f) == base_ring(F)
+ R = parent(f)
+ I = IdealGens(R, [f], ordering)
+ u, q, r = _reduce_with_quotients_and_unit(I, F, ordering, complete_reduction)
+ return u, q, r[1]
+end
+
+function reduce_with_quotients_and_unit(F::Vector{T}, G::IdealGens{T}; ordering::MonomialOrdering = default_ordering(parent(F[1])), complete_reduction::Bool = false) where {T <: MPolyRingElem}
+ @assert !isempty(F)
+ if isempty(G)
+ return identity_matrix(parent(F[1]), length(F)), zero_matrix(parent(F[1]), length(F), 0), F
+ end
+ @assert parent(F[1]) == base_ring(G)
+ R = parent(F[1])
+ I = IdealGens(R, F, ordering)
+ return _reduce_with_quotients_and_unit(I, G, ordering, complete_reduction)
+end
+
+@doc raw"""
+ reduce_with_quotients_and_unit(I::IdealGens, J::IdealGens;
+ ordering::MonomialOrdering = default_ordering(base_ring(J)), complete_reduction::Bool = false)
+
+Return a `Tuple` consisting of a `Generic.MatSpaceElem` `M`, a
+`Vector` `res` whose elements are the underlying elements of `I`
+reduced by the underlying generators of `J` w.r.t. the monomial
+ordering `ordering` and a diagonal matrix `units` such that `M *
+gens(J) + res == units * gens(I)`. If `ordering` is global then
+`units` will always be the identity matrix, see also
+`reduce_with_quotients`. `J` need not be a Gröbner basis. `res` will
+have the same number of elements as `I`, even if they are zero.
+
+# Examples
+```jldoctest
+julia> R, (x, y) = polynomial_ring(GF(11), [:x, :y]);
+
+julia> I = ideal(R, [x]);
+
+julia> R, (x, y) = polynomial_ring(GF(11), [:x, :y]);
+
+julia> I = ideal(R, [x]);
+
+julia> J = ideal(R, [x+1]);
+
+julia> unit, M, res = reduce_with_quotients_and_unit(I.gens, J.gens, ordering = neglex(R))
+([x+1], [x], FqMPolyRingElem[0])
+
+julia> M * gens(J) + res == unit * gens(I)
+true
+
+julia> f = x^3*y^2-y^4-10
+x^3*y^2 + 10*y^4 + 1
+
+julia> F = [x^2*y-y^3, x^3-y^4]
+2-element Vector{FqMPolyRingElem}:
+ x^2*y + 10*y^3
+ x^3 + 10*y^4
+
+julia> reduce_with_quotients_and_unit(f, F)
+([1], [x*y 10*x+1], x^4 + 10*x^3 + 1)
+
+julia> unit, M, res = reduce_with_quotients_and_unit(f, F, ordering=lex(R))
+([1], [x*y 0], x*y^4 + 10*y^4 + 1)
+
+julia> M * F + [res] == unit * [f]
+true
+```
+"""
+function reduce_with_quotients_and_unit(I::IdealGens, J::IdealGens; ordering::MonomialOrdering = default_ordering(base_ring(J)), complete_reduction::Bool = false)
+ return _reduce_with_quotients_and_unit(I, J, ordering, complete_reduction)
+end
+
+
+@doc raw"""
+ reduce_with_quotients(I::IdealGens, J::IdealGens; ordering::MonomialOrdering = default_ordering(base_ring(J)), complete_reduction::Bool = false)
+
+Return a `Tuple` consisting of a `Generic.MatSpaceElem` `M` and a
+`Vector` `res` whose elements are the underlying elements of `I`
+reduced by the underlying generators of `J` w.r.t. the monomial
+ordering `ordering` such that `M * gens(J) + res == gens(I)` if `ordering` is global.
+If `ordering` is local then this equality holds after `gens(I)` has been multiplied
+with an unknown diagonal matrix of units, see `reduce_with_quotients_and_unit` to
+obtain this matrix. `J` need not be a Gröbner basis. `res` will have the same number
+of elements as `I`, even if they are zero.
+
+# Examples
+```jldoctest
+julia> R, (x, y, z) = polynomial_ring(GF(11), [:x, :y, :z]);
+
+julia> J = ideal(R, [x^2, x*y - y^2]);
+
+julia> I = ideal(R, [x*y, y^3]);
+
+julia> gb = groebner_basis(J)
+Gröbner basis with elements
+ 1: x*y + 10*y^2
+ 2: x^2
+ 3: y^3
+with respect to the ordering
+ degrevlex([x, y, z])
+
+julia> M, res = reduce_with_quotients(I.gens, gb)
+([1 0 0; 0 0 1], FqMPolyRingElem[y^2, 0])
+
+julia> M * gens(gb) + res == gens(I)
+true
+
+julia> f = x^3*y^2-y^4-10
+x^3*y^2 + 10*y^4 + 1
+
+julia> F = [x^2*y-y^3, x^3-y^4]
+2-element Vector{FqMPolyRingElem}:
+ x^2*y + 10*y^3
+ x^3 + 10*y^4
+
+julia> reduce_with_quotients_and_unit(f, F)
+([1], [x*y 10*x+1], x^4 + 10*x^3 + 1)
+
+julia> unit, M, res = reduce_with_quotients_and_unit(f, F, ordering=lex(R))
+([1], [x*y 0], x*y^4 + 10*y^4 + 1)
+
+julia> M * F + [res] == unit * [f]
+true
+```
+"""
+function reduce_with_quotients(I::IdealGens, J::IdealGens; ordering::MonomialOrdering = default_ordering(base_ring(J)), complete_reduction::Bool = false)
+ _, q, r = _reduce_with_quotients_and_unit(I, J, ordering, complete_reduction)
+ return q, r
+end
+
+@doc raw"""
+ reduce_with_quotients(g::T, F::Union{Vector{T}, IdealGens{T}};
+ ordering::MonomialOrdering = default_ordering(parent(g)), complete_reduction::Bool = false) where T <: MPolyRingElem
+
+If `ordering` is global, return the quotients and the remainder in a standard representation for `g` on division by the polynomials in `F` with respect to `ordering`.
+Otherwise, return the quotients and the remainder in a *weak* standard representation for `g` on division by the polynomials in `F` with respect to `ordering`.
+
+ reduce_with_quotients(G::Vector{T}, F::Union{Vector{T}, IdealGens{T}};
+ ordering::MonomialOrdering = default_ordering(parent(G[1])), complete_reduction::Bool = false) where T <: MPolyRingElem
+
+Return a `Vector` which contains, for each element `g` of `G`, quotients and a remainder as above.
+
+!!! note
+ The returned remainders are fully reduced if `complete_reduction` is set to `true` and `ordering` is global.
+
+# Examples
+
+```jldoctest
+julia> R, (x, y, z) = polynomial_ring(QQ, [:x, :y, :z]);
+
+julia> f1 = x^2+x^2*y; f2 = y^3+x*y*z; f3 = x^3*y^2+z^4;
+
+julia> g = x^3*y+x^5+x^2*y^2*z^2+z^6;
+
+julia> Q, h = reduce_with_quotients(g, [f1,f2, f3], ordering = lex(R));
+
+julia> h
+x^5 - x^3 + y^6 + z^6
+
+julia> g == Q[1]*f1+Q[2]*f2+Q[3]*f3+h
+true
+```
+"""
+function reduce_with_quotients(f::T, F::Vector{T}; ordering::MonomialOrdering = default_ordering(parent(f)), complete_reduction::Bool = false) where {T <: MPolyRingElem}
+ isempty(F) && return zero_matrix(parent(f), 1, 0), f
+ J = IdealGens(parent(F[1]), F, ordering)
+ return reduce_with_quotients(f, J; ordering=ordering, complete_reduction=complete_reduction)
+end
+
+function reduce_with_quotients(F::Vector{T}, G::Vector{T}; ordering::MonomialOrdering = default_ordering(parent(F[1])), complete_reduction::Bool = false) where {T <: MPolyRingElem}
+ @assert !isempty(F)
+ isempty(G) && return zero_matrix(parent(F[1]), length(F), 0), F
+ J = IdealGens(parent(G[1]), G, ordering)
+ return reduce_with_quotients(F, J; ordering=ordering, complete_reduction=complete_reduction)
+end
+
+function reduce_with_quotients(f::T, F::IdealGens{T}; ordering::MonomialOrdering = default_ordering(parent(f)), complete_reduction::Bool = false) where {T <: MPolyRingElem}
+ isempty(F) && return zero_matrix(parent(f), 1, 0), f
+ @assert parent(f) == parent(F[1])
+ R = parent(f)
+ I = IdealGens(R, [f], ordering)
+ _, q, r = _reduce_with_quotients_and_unit(I, F, ordering, complete_reduction)
+ return q, r[1]
+end
+
+function reduce_with_quotients(F::Vector{T}, G::IdealGens{T}; ordering::MonomialOrdering = default_ordering(parent(F[1])), complete_reduction::Bool = false) where {T <: MPolyRingElem}
+ @assert !isempty(F)
+ isempty(G) && return zero_matrix(parent(F[1]), length(F), 0), F
+ @assert parent(F[1]) == parent(G[1])
+ R = parent(F[1])
+ I = IdealGens(R, F, ordering)
+ _, q, r = _reduce_with_quotients_and_unit(I, G, ordering, complete_reduction)
+ return q, r
+end
+
+function _reduce_with_quotients_and_unit(I::IdealGens, J::IdealGens, ordering::MonomialOrdering = default_ordering(base_ring(J)), complete_reduction::Bool = complete_reduction)
+ @assert base_ring(J) == base_ring(I)
+ sI = singular_generators(I, ordering)
+ sJ = singular_generators(J, ordering)
+ res = Singular.divrem2(sI, sJ, complete_reduction=complete_reduction)
+ return matrix(base_ring(I), res[3]), matrix(base_ring(I), res[1]), [J.gens.Ox(x) for x = gens(res[2])]
+end
+
+@doc raw"""
+ normal_form(g::T, I::MPolyIdeal;
+ ordering::MonomialOrdering = default_ordering(base_ring(I))) where T <: MPolyRingElem
+
+Compute the normal form of `g` mod `I` with respect to `ordering`.
+
+ normal_form(G::Vector{T}, I::MPolyIdeal;
+ ordering::MonomialOrdering = default_ordering(base_ring(I))) where T <: MPolyRingElem
+
+Return a `Vector` which contains for each element `g` of `G` a normal form as above.
+
+# Examples
+```jldoctest
+julia> R,(a,b,c) = polynomial_ring(QQ,[:a,:b,:c])
+(Multivariate polynomial ring in 3 variables over QQ, QQMPolyRingElem[a, b, c])
+
+julia> J = ideal(R,[-1+c+b,-1+b+c*a+2*a*b])
+Ideal generated by
+ b + c - 1
+ 2*a*b + a*c + b - 1
+
+julia> gens(groebner_basis(J))
+2-element Vector{QQMPolyRingElem}:
+ b + c - 1
+ a*c - 2*a + c
+
+julia> normal_form(-1+c+b+a^3, J)
+a^3
+
+julia> R,(a,b,c) = polynomial_ring(QQ,[:a,:b,:c])
+(Multivariate polynomial ring in 3 variables over QQ, QQMPolyRingElem[a, b, c])
+
+julia> A = [-1+c+b+a^3,-1+b+c*a+2*a^3,5+c*b+c^2*a]
+3-element Vector{QQMPolyRingElem}:
+ a^3 + b + c - 1
+ 2*a^3 + a*c + b - 1
+ a*c^2 + b*c + 5
+
+julia> J = ideal(R,[-1+c+b,-1+b+c*a+2*a*b])
+Ideal generated by
+ b + c - 1
+ 2*a*b + a*c + b - 1
+
+julia> gens(groebner_basis(J))
+2-element Vector{QQMPolyRingElem}:
+ b + c - 1
+ a*c - 2*a + c
+
+julia> normal_form(A, J)
+3-element Vector{QQMPolyRingElem}:
+ a^3
+ 2*a^3 + 2*a - 2*c
+ 4*a - 2*c^2 - c + 5
+```
+"""
+function normal_form(f::T, J::MPolyIdeal; ordering::MonomialOrdering = default_ordering(base_ring(J))) where { T <: MPolyRingElem }
+ res = normal_form([f], J, ordering = ordering)
+
+ return res[1]
+end
+
+function normal_form(A::Vector{T}, J::MPolyIdeal; ordering::MonomialOrdering=default_ordering(base_ring(J))) where { T <: MPolyRingElem }
+ @req is_exact_type(elem_type(base_ring(J))) "This functionality is only supported over exact fields."
+ if is_normal_form_f4_applicable(J, ordering)
+ res = _normal_form_f4(A, J)
+ else
+ res = _normal_form_singular(A, J, ordering)
+ end
+
+ return res
+end
+
+function is_normal_form_f4_applicable(I::MPolyIdeal, ordering::MonomialOrdering)
+ return (ordering == degrevlex(base_ring(I)) && !is_graded(base_ring(I))
+ && ((coefficient_ring(I) isa FqField
+ && absolute_degree(coefficient_ring(I)) == 1
+ && characteristic(coefficient_ring(I)) < 2^31)))
+end
+
+@doc raw"""
+ _normal_form_f4(A::Vector{T}, J::MPolyIdeal) where { T <: MPolyRingElem }
+
+**Note**: Internal function, subject to change, do not use.
+
+Compute the normal form of the elements of `A` w.r.t. a
+Gröbner basis of `J` and the monomial ordering `degrevlex` using the F4 Algorithm from AlgebraicSolving.
+
+CAVEAT: This computation needs a Gröbner basis of `J` and the monomial ordering
+`ordering. If this Gröbner basis is not available, one is computed automatically.
+This may take some time. This function only works in polynomial rings over prime fields
+with the degree reverse lexicographical ordering.
+
+# Examples
+```jldoctest
+julia> R,(a,b,c) = polynomial_ring(GF(65521),[:a,:b,:c])
+(Multivariate polynomial ring in 3 variables over GF(65521), FqMPolyRingElem[a, b, c])
+
+julia> J = ideal(R,[-1+c+b,-1+b+c*a+2*a*b])
+Ideal generated by
+ b + c + 65520
+ 2*a*b + a*c + b + 65520
+
+julia> A = [-1+c+b+a^3, -1+b+c*a+2*a^3, 5+c*b+c^2*a]
+3-element Vector{FqMPolyRingElem}:
+ a^3 + b + c + 65520
+ 2*a^3 + a*c + b + 65520
+ a*c^2 + b*c + 5
+
+julia> Oscar._normal_form_f4(A, J)
+3-element Vector{FqMPolyRingElem}:
+ a^3
+ 2*a^3 + 2*a + 65519*c
+ 4*a + 65519*c^2 + 65520*c + 5
+```
+"""
+function _normal_form_f4(A::Vector{T}, J::MPolyIdeal) where { T <: MPolyRingElem }
+ if !haskey(J.gb, degrevlex(base_ring(J)))
+ groebner_basis_f4(J, complete_reduction = true)
+ end
+
+ AJ = AlgebraicSolving.Ideal(J.gens.O)
+ AJ.gb[0] = oscar_groebner_generators(J, degrevlex(base_ring(J)), true)
+
+ return AlgebraicSolving.normal_form(A, AJ)
+end
+
+@doc raw"""
+ _normal_form_singular(A::Vector{T}, J::MPolyIdeal, ordering::MonomialOrdering) where { T <: MPolyRingElem }
+
+**Note**: Internal function, subject to change, do not use.
+
+Compute the normal form of the elements of `A` w.r.t. a
+Gröbner basis of `J` and the monomial ordering `ordering` using Singular.
+
+CAVEAT: This computation needs a Gröbner basis of `J` and the monomial ordering
+`ordering. If this Gröbner basis is not available, one is computed automatically.
+This may take some time.
+
+# Examples
+```jldoctest
+julia> R,(a,b,c) = polynomial_ring(QQ,[:a,:b,:c])
+(Multivariate polynomial ring in 3 variables over QQ, QQMPolyRingElem[a, b, c])
+
+julia> J = ideal(R,[-1+c+b,-1+b+c*a+2*a*b])
+Ideal generated by
+ b + c - 1
+ 2*a*b + a*c + b - 1
+
+julia> gens(groebner_basis(J))
+2-element Vector{QQMPolyRingElem}:
+ b + c - 1
+ a*c - 2*a + c
+
+julia> A = [-1+c+b+a^3, -1+b+c*a+2*a^3, 5+c*b+c^2*a]
+3-element Vector{QQMPolyRingElem}:
+ a^3 + b + c - 1
+ 2*a^3 + a*c + b - 1
+ a*c^2 + b*c + 5
+
+julia> Oscar._normal_form_singular(A, J, default_ordering(base_ring(J)))
+3-element Vector{QQMPolyRingElem}:
+ a^3
+ 2*a^3 + 2*a - 2*c
+ 4*a - 2*c^2 - c + 5
+```
+"""
+function _normal_form_singular(A::Vector{T}, J::MPolyIdeal, ordering::MonomialOrdering) where { T <: MPolyRingElem }
+ GS = singular_groebner_generators(J, ordering)
+ SR = base_ring(GS)
+ tmp = map(SR, A)
+ IS = Singular.Ideal(SR, tmp)
+ K = reduce(IS, GS)
+ OR = base_ring(J)
+ return map(OR, gens(K))
+end
+
+@doc raw"""
+ is_standard_basis(F::IdealGens; ordering::MonomialOrdering=default_ordering(base_ring(F)))
+
+Tests if a given IdealGens `F` is a standard basis w.r.t. the given monomial ordering `ordering`.
+
+# Examples
+```jldoctest
+julia> R, (x, y) = polynomial_ring(QQ, [:x, :y])
+(Multivariate polynomial ring in 2 variables over QQ, QQMPolyRingElem[x, y])
+
+julia> I = ideal(R,[x^2+y,x*y-y])
+Ideal generated by
+ x^2 + y
+ x*y - y
+
+julia> is_standard_basis(I.gens, ordering=neglex(R))
+false
+
+julia> standard_basis(I, ordering=neglex(R))
+Standard basis with elements
+ 1: y
+ 2: x^2
+with respect to the ordering
+ neglex([x, y])
+
+julia> is_standard_basis(I.gb[neglex(R)], ordering=neglex(R))
+true
+```
+"""
+function is_standard_basis(F::IdealGens; ordering::MonomialOrdering=default_ordering(base_ring(F)))
+ @req is_exact_type(elem_type(base_ring(F))) "This functionality is only supported over exact fields."
+ if F.isGB && F.ord == ordering
+ return true
+ else
+ # Try to reduce all possible s-polynomials, i.e. Buchberger's criterion
+ R = base_ring(F)
+ for i in 1:length(F)
+ lt_i = leading_term(F[i], ordering=ordering)
+ for j in i+1:length(F)
+ lt_j = leading_term(F[j], ordering=ordering)
+ lcm_ij = lcm(lt_i, lt_j)
+ sp_ij = div(lcm_ij, lt_i) * F[i] - div(lcm_ij, lt_j) * F[j]
+ if reduce(IdealGens([sp_ij], ordering), F, ordering=ordering) != [R(0)]
+ return false
+ end
+ end
+ end
+ F.isGB = true
+ F.ord = ordering
+ return true
+ end
+end
+
+@doc raw"""
+ is_groebner_basis(F::IdealGens; ordering::MonomialOrdering=default_ordering(base_ring(F)))
+
+Tests if a given IdealGens `F` is a Gröbner basis w.r.t. the given monomial ordering `ordering`.
+
+# Examples
+```jldoctest
+julia> R, (x, y) = polynomial_ring(QQ, [:x, :y])
+(Multivariate polynomial ring in 2 variables over QQ, QQMPolyRingElem[x, y])
+
+julia> I = ideal(R,[x^2+y,x*y-y])
+Ideal generated by
+ x^2 + y
+ x*y - y
+
+julia> is_groebner_basis(I.gens, ordering=lex(R))
+false
+
+julia> groebner_basis(I, ordering=lex(R))
+Gröbner basis with elements
+ 1: y^2 + y
+ 2: x*y - y
+ 3: x^2 + y
+with respect to the ordering
+ lex([x, y])
+
+julia> is_groebner_basis(I.gb[lex(R)], ordering=lex(R))
+true
+```
+"""
+function is_groebner_basis(F::IdealGens; ordering::MonomialOrdering = default_ordering(base_ring(F)))
+ is_global(ordering) || error("Ordering must be global")
+ return is_standard_basis(F, ordering=ordering)
+end
diff --git a/src/Rings/groebner/transformation-matrix.jl b/src/Rings/groebner/transformation-matrix.jl
new file mode 100644
index 000000000000..301a6be0c6ac
--- /dev/null
+++ b/src/Rings/groebner/transformation-matrix.jl
@@ -0,0 +1,89 @@
+@doc raw"""
+ _compute_standard_basis_with_transform(B::IdealGens, ordering::MonomialOrdering, complete_reduction::Bool = false)
+
+**Note**: Internal function, subject to change, do not use.
+
+Given an `IdealGens` `B` and optional parameters `ordering` for a monomial ordering and `complete_reduction`
+this function computes a standard basis (if `ordering` is a global monomial ordering and `complete_reduction = true`
+the reduced Gröbner basis) of the ideal spanned by the elements in `B` w.r.t. the given monomial ordering `ordering`
+and the transformation matrix from the ideal to the standard basis. Return value is a IdealGens together with a map.
+
+# Examples
+```jldoctest
+julia> R, (x, y) = polynomial_ring(QQ, [:x, :y])
+(Multivariate polynomial ring in 2 variables over QQ, QQMPolyRingElem[x, y])
+
+julia> A = Oscar.IdealGens([x*y-3*x,y^3-2*x^2*y])
+Ideal generating system with elements
+ 1: x*y - 3*x
+ 2: -2*x^2*y + y^3
+
+julia> B,m = Oscar._compute_standard_basis_with_transform(A, degrevlex(R))
+(Ideal generating system with 3 elements with associated ordering degrevlex([x, y]), [1 2*x -2*x^2+y^2+3*y+9; 0 1 -x])
+```
+"""
+function _compute_standard_basis_with_transform(B::IdealGens, ordering::MonomialOrdering, complete_reduction::Bool = false)
+ istd, m = Singular.lift_std(singular_generators(B, ordering), complete_reduction = complete_reduction)
+ return IdealGens(B.Ox, istd), map_entries(B.Ox, m)
+end
+
+@doc raw"""
+ standard_basis_with_transformation_matrix(I::MPolyIdeal;
+ ordering::MonomialOrdering = default_ordering(base_ring(I)),
+ complete_reduction::Bool=false)
+
+Return a pair `G`, `T`, say, where `G` is a standard basis of `I` with respect to `ordering`, and `T`
+is a transformation matrix from `gens(I)` to `G`. That is, `gens(I)*T == G`.
+
+!!! note
+ The returned Gröbner basis is reduced if `ordering` is a global monomial odering and `complete_reduction = true`.
+
+# Examples
+```jldoctest
+julia> R,(x,y) = polynomial_ring(QQ,[:x,:y]);
+
+julia> I = ideal([x*y^2-1,x^3+y^2+x*y]);
+
+julia> G, T = standard_basis_with_transformation_matrix(I, ordering=neglex(R))
+(Standard basis with 1 element w.r.t. neglex([x, y]), [-1; 0])
+
+julia> gens(I)*T == gens(G)
+true
+```
+"""
+function standard_basis_with_transformation_matrix(I::MPolyIdeal; ordering::MonomialOrdering = default_ordering(base_ring(I)), complete_reduction::Bool = false)
+ complete_reduction && @assert is_global(ordering)
+ G, m = _compute_standard_basis_with_transform(I.gens, ordering, complete_reduction)
+ G.isGB = true
+ I.gb[ordering] = G
+ return G, m
+end
+
+@doc raw"""
+ groebner_basis_with_transformation_matrix(I::MPolyIdeal;
+ ordering::MonomialOrdering = default_ordering(base_ring(I)),
+ complete_reduction::Bool=false)
+
+Return a pair `G`, `T`, say, where `G` is a Gröbner basis of `I` with respect to `ordering`, and `T`
+is a transformation matrix from `gens(I)` to `G`. That is, `gens(I)*T == G`.
+
+!!! note
+ The returned Gröbner basis is reduced if `complete_reduction = true`.
+
+# Examples
+```jldoctest
+julia> R,(x,y) = polynomial_ring(QQ,[:x,:y]);
+
+julia> I = ideal([x*y^2-1,x^3+y^2+x*y]);
+
+julia> G, T = groebner_basis_with_transformation_matrix(I)
+(Gröbner basis with 3 elements w.r.t. degrevlex([x, y]), [1 0 -x^2-y; 0 1 y^2])
+
+julia> gens(I)*T == gens(G)
+true
+```
+"""
+function groebner_basis_with_transformation_matrix(I::MPolyIdeal; ordering::MonomialOrdering = default_ordering(base_ring(I)), complete_reduction::Bool = false)
+ is_global(ordering) || error("Ordering must be global")
+ return standard_basis_with_transformation_matrix(I, ordering=ordering, complete_reduction=complete_reduction)
+end
diff --git a/src/Rings/hilbert.jl b/src/Rings/hilbert.jl
index 26acdd148b69..cce1b152d364 100644
--- a/src/Rings/hilbert.jl
+++ b/src/Rings/hilbert.jl
@@ -934,9 +934,9 @@ end
# # Transpose while converting:
# ncols = length(W);
# nrows = length(W[1]);
-# A = zero_matrix(FlintZZ, nrows,ncols);
+# A = zero_matrix(ZZ, nrows,ncols);
# for i in 1:nrows for j in 1:ncols A[i,j] = W[j][i]; end; end;
-# b = zero_matrix(FlintZZ, nrows,1);
+# b = zero_matrix(ZZ, nrows,1);
# try
# solve_non_negative(A, b); # any non-zero soln gives rise to infinitely many, which triggers an exception
# catch e
diff --git a/src/Rings/mpoly-affine-algebras.jl b/src/Rings/mpoly-affine-algebras.jl
index ea73898c699c..c96f3d247dc6 100644
--- a/src/Rings/mpoly-affine-algebras.jl
+++ b/src/Rings/mpoly-affine-algebras.jl
@@ -20,8 +20,17 @@ julia> dim(A)
```
"""
function dim(A::MPolyQuoRing)
- I = A.I
- return dim(I)
+ return dim(modulus(A))
+end
+
+function dim(A::zzModRing)
+ modulus(A) == 1 && error("Function `dim` gives wrong answers if the base ring is the zero ring.")
+ return 0
+end
+
+function dim(A::ZZModRing)
+ modulus(A) == 1 && error("Function `dim` gives wrong answers if the base ring is the zero ring.")
+ return 0
end
@doc raw"""
@@ -89,9 +98,9 @@ Ideal generated by
julia> groebner_basis(I, ordering = lex(base_ring(I)))
Gröbner basis with elements
- 1 -> z^3 - z^2
- 2 -> y^2 + y*z - y + z^2 - z
- 3 -> x + y + z - 1
+ 1: z^3 - z^2
+ 2: y^2 + y*z - y + z^2 - z
+ 3: x + y + z - 1
with respect to the ordering
lex([x, y, z])
```
diff --git a/src/Rings/mpoly-graded.jl b/src/Rings/mpoly-graded.jl
index a6a2ffcd5cad..40394f5d9b62 100644
--- a/src/Rings/mpoly-graded.jl
+++ b/src/Rings/mpoly-graded.jl
@@ -1239,7 +1239,7 @@ function monomial_basis(W::MPolyDecRing, d::FinGenAbGroupElem)
k, im = kernel(h)
#need the positive elements in there...
#Ax = b, Cx >= 0
- C = identity_matrix(FlintZZ, ngens(W))
+ C = identity_matrix(ZZ, ngens(W))
A = reduce(vcat, [x.coeff for x = W.d])
k = solve_mixed(transpose(A), transpose(d.coeff), C)
for ee = 1:nrows(k)
@@ -2383,7 +2383,15 @@ julia> I = ideal(R, [y^2*z − x^2*w, z^4 − x*w^3]);
julia> cm_regularity(I)
6
-julia> minimal_betti_table(I);
+julia> minimal_betti_table(I)
+degree: 0 1
+------------
+ 3: 1 -
+ 4: 1 -
+ 5: - -
+ 6: - 1
+------------
+ total: 2 1
```
"""
function cm_regularity(I::MPolyIdeal)
diff --git a/src/Rings/mpoly-ideals.jl b/src/Rings/mpoly-ideals.jl
index 27b717b3d013..6f69dd8d0068 100644
--- a/src/Rings/mpoly-ideals.jl
+++ b/src/Rings/mpoly-ideals.jl
@@ -302,11 +302,16 @@ end
# saturation #######################################################
@doc raw"""
- saturation(I::MPolyIdeal{T}, J::MPolyIdeal{T} = ideal(base_ring(I), gens(base_ring(I)))) where T
+ saturation(I::MPolyIdeal{T},
+ J::MPolyIdeal{T} = ideal(base_ring(I), gens(base_ring(I)));
+ iteration::Bool=false) where T
Return the saturation of `I` with respect to `J`.
+
If the second ideal `J` is not given, the ideal generated by the generators (variables) of `base_ring(I)` is used.
+If `iteration` is set to `true`, the saturation is done by carrying out successive ideal quotient computations as in the definition of saturation. Otherwise, a more sophisticated Gröbner basis approach is used which is typically faster. Applying the two approaches may lead to different generating sets of the saturation.
+
# Examples
```jldoctest
julia> R, (x, y, z) = polynomial_ring(QQ, [:x, :y, :z])
@@ -338,27 +343,33 @@ julia> K = saturation(I)
Ideal generated by
z
x*y
+
```
"""
-function saturation(I::MPolyIdeal{T}, J::MPolyIdeal{T} = ideal(base_ring(I), gens(base_ring(I)))) where T
- K, _ = Singular.saturation(singular_generators(I), singular_generators(J))
+function saturation(I::MPolyIdeal{T}, J::MPolyIdeal{T} = ideal(base_ring(I), gens(base_ring(I))); iteration::Bool=false) where T
+ if iteration
+ K, _ = Singular.saturation(singular_generators(I), singular_generators(J))
+ else
+ K, _ = Singular.saturation2(singular_generators(I), singular_generators(J))
+ end
return MPolyIdeal(base_ring(I), K)
end
-# the following is corresponding to saturation2 from Singular
-# TODO: think about how to use use this properly/automatically
-function _saturation2(I::MPolyIdeal{T}, J::MPolyIdeal{T} = ideal(base_ring(I), gens(base_ring(I)))) where T
- K, _ = Singular.saturation2(singular_generators(I), singular_generators(J))
- return MPolyIdeal(base_ring(I), K)
-end
+_saturation2(I::MPolyIdeal{T}, J::MPolyIdeal{T} = ideal(base_ring(I), gens(base_ring(I)))) where T = saturation(I, J)
+# kept for backwards compatibility
#######################################################
@doc raw"""
- saturation_with_index(I::MPolyIdeal{T}, J::MPolyIdeal{T} = ideal(base_ring(I), gens(base_ring(I)))) where T
+ saturation_with_index(I::MPolyIdeal{T},
+ J::MPolyIdeal{T} = ideal(base_ring(I), gens(base_ring(I)))) where T
+
+Return $I:J^{\infty}$ together with the smallest integer $m$ such that $I:J^m = I:J^{\infty}$ (saturation index).
-Return $I:J^{\infty}$ together with the smallest integer $m$ such that $I:J^m = I:J^{\infty}$.
If the second ideal `J` is not given, the ideal generated by the generators (variables) of `base_ring(I)` is used.
+!!! note
+ If the saturation index is not needed, we recommend to use `saturation(I, J)` which is typically faster.
+
# Examples
```jldoctest
julia> R, (x, y, z) = polynomial_ring(QQ, [:x, :y, :z])
@@ -386,6 +397,7 @@ julia> K, m = saturation_with_index(I, J)
julia> K, m = saturation_with_index(I)
(Ideal (z, x*y), 2)
+
```
"""
function saturation_with_index(I::MPolyIdeal{T}, J::MPolyIdeal{T} = ideal(base_ring(I), gens(base_ring(I)))) where T
@@ -1191,17 +1203,27 @@ function minimal_primes(
# This will in many cases lead to an easy simplification of the problem
if factor_generators
- J = typeof(I)[ideal(R, elem_type(R)[])]
+ J = [ideal(R, gens(I))] # A copy of I as initialization
for g in gens(I)
K = typeof(I)[]
is_zero(g) && continue
for (b, k) in factor(g)
+ # Split the already collected components with b
for j in J
push!(K, j + ideal(R, b))
end
end
J = K
end
+
+ unique_comp = typeof(I)[]
+ for q in J
+ is_one(q) && continue
+ q in unique_comp && continue
+ push!(unique_comp, q)
+ end
+ J = unique_comp
+
# unique! seems to fail here. We have to do it manually.
pre_result = filter!(!is_one, vcat([minimal_primes(j; algorithm, factor_generators=false) for j in J]...))
result = typeof(I)[]
@@ -2098,7 +2120,8 @@ function small_generating_set(
computed_gb = IdealGens(ring, sing_gb, true)
if !haskey(I.gb,computed_gb.ord)
# if not yet present, store gb for later use
- I.gb[computed_gb.ord] = computed_gb
+ I.gb[computed_gb.ord] = computed_gb
+ I.gb[computed_gb.ord].isGB = true
end
# we do not have a notion of minimal generating set in this context!
@@ -2316,4 +2339,3 @@ end
function hash(I::Ideal, c::UInt)
return hash(base_ring(I), c)
end
-
diff --git a/src/Rings/mpoly-localization_types.jl b/src/Rings/mpoly-localization_types.jl
index 473358e93961..5db57ddceb2d 100644
--- a/src/Rings/mpoly-localization_types.jl
+++ b/src/Rings/mpoly-localization_types.jl
@@ -143,6 +143,9 @@ end
Complement of a maximal ideal ``𝔪 = ⟨x₁-a₁,…,xₙ-aₙ⟩⊂ 𝕜[x₁,…xₙ]`` with ``aᵢ∈ 𝕜``.
+!!! note
+The coefficient ring is required to be a field.
+
```jldoctest
julia> R, (x, y) = polynomial_ring(QQ, [:x, :y]);
@@ -178,6 +181,7 @@ mutable struct MPolyComplementOfKPointIdeal{
length(a) == ngens(R) || error("the number of variables in the ring does not coincide with the number of coordinates")
n = length(a)
kk = coefficient_ring(R)
+ @req kk isa Field "This localization is only available over fields"
b = kk.(a) # fails if the input is not compatible
S = new{typeof(kk), elem_type(kk), RingType, elem_type(R)}(R, b)
return S
diff --git a/src/Rings/mpoly.jl b/src/Rings/mpoly.jl
index 5bb259b88b82..ce2543562705 100644
--- a/src/Rings/mpoly.jl
+++ b/src/Rings/mpoly.jl
@@ -253,7 +253,7 @@ function show(io::IO, ::MIME"text/plain", I::IdealGens)
end
print(io, " with elements", Indent())
for (i, g) in enumerate(gens(I))
- print(io, "\n", i, " -> ", OscarPair(g, I.ord))
+ print(io, "\n", i, ": ", OscarPair(g, I.ord))
end
print(io, Dedent())
print(io, "\nwith respect to the ordering")
@@ -262,7 +262,7 @@ function show(io::IO, ::MIME"text/plain", I::IdealGens)
print(io, "Ideal generating system with elements")
print(io, Indent())
for (i,g) in enumerate(gens(I))
- print(io, "\n", i, " -> ", g)
+ print(io, "\n", i, ": ", g)
end
print(io, Dedent())
if isdefined(I, :ord)
@@ -405,8 +405,8 @@ julia> g = generating_system(I);
julia> set_ordering(g, degrevlex(gens(R)))
Ideal generating system with elements
- 1 -> x0*x1
- 2 -> x2
+ 1: x0*x1
+ 2: x2
with associated ordering
degrevlex([x0, x1, x2])
```
@@ -821,8 +821,8 @@ julia> I = ideal([x*(x+1), x^2-y^2+(x-2)*y]);
julia> generating_system(I)
Ideal generating system with elements
- 1 -> x^2 + x
- 2 -> x^2 + x*y - y^2 - 2*y
+ 1: x^2 + x
+ 2: x^2 + x*y - y^2 - 2*y
```
"""
function generating_system(I::MPolyIdeal)
diff --git a/src/Rings/mpolyquo-localizations.jl b/src/Rings/mpolyquo-localizations.jl
index e0e3ecf557d3..f2019b9acea2 100644
--- a/src/Rings/mpolyquo-localizations.jl
+++ b/src/Rings/mpolyquo-localizations.jl
@@ -1850,6 +1850,83 @@ function vector_space_dimension(R::MPolyQuoLocRing{<:Field, <:Any,<:Any, <:Any,
return vector_space_dimension(quo(base_ring(R),ideal(base_ring(R),gens(LI)))[1])
end
+@doc raw"""
+ _monomial_basis(L::MPolyLocRing{<:Field, <:Any, <:Any, <:Any, <:MPolyComplementOfKPointIdeal}, I::MPolyLocalizedIdeal)
+
+If, say, `A = L/I`, where `L` is a localization of multivariate polynomial ring over a field
+`K` at a point `p`, and `I` is an ideal of `L`, return a vector of monomials of `L`
+such that the residue classes of these monomials form a basis of `A` as a `K`-vector
+space.
+!!! note
+ This is an internal method for computing a monomial basis without creating the quotient.
+"""
+function _monomial_basis(L::MPolyLocRing{<:Field, <:Any, <:Any, <:Any, <:MPolyComplementOfKPointIdeal}, I::MPolyLocalizedIdeal)
+ base_ring(I) == L || error("ideal does not belong to the correct ring")
+ G = numerator.(gens(I))
+ shift,_ = base_ring_shifts(L)
+ G_0 = shift.(G)
+ R = base_ring(L)
+ LI = leading_ideal(ideal(R, G_0), ordering = negdeglex(R))
+ return L.(monomial_basis(quo(R, LI)[1]))
+end
+
+@doc raw"""
+ monomial_basis(A::MPolyQuoLocRing{<:Field, <:Any, <:Any, <:Any, <:MPolyComplementOfKPointIdeal})
+
+If, say, `A = L/I`, where `L` is a localization of multivariate polynomial ring over a field
+`K` at a point `p`, and `I` is an ideal of `L`, return a vector of monomials of `L`
+such that the residue classes of these monomials form a basis of `A` as a `K`-vector
+space.
+!!! note
+ The monomials are for readabilty in the varibles of the underlying polynomial ring of `L` and not in the variables of power series ring $K[[x_1-p_1,...,x_n-p_n]]$ in which `L` is embedded.
+!!! note
+ If `A` is not finite-dimensional as a `K`-vector space, an error is thrown.
+# Examples
+```jldoctest
+julia> R, (x,y) = QQ["x","y"];
+
+julia> f = (x^2-y^3)*(y-1); # 3 singularities, a cusp singularity and two node singularities
+
+julia> A = tjurina_algebra(f)
+Quotient
+ of multivariate polynomial ring in 2 variables x, y
+ over rational field
+ by ideal (x^2*y - x^2 - y^4 + y^3, 2*x*y - 2*x, x^2 - 4*y^3 + 3*y^2)
+
+julia> monomial_basis(A)
+4-element Vector{QQMPolyRingElem}:
+ y^2
+ y
+ x
+ 1
+
+julia> Aloc0,_ = localization(A, complement_of_point_ideal(R, [0,0]));
+
+julia> monomial_basis(Aloc0)
+2-element Vector{Oscar.MPolyLocRingElem{QQField, QQFieldElem, QQMPolyRing, QQMPolyRingElem, Oscar.MPolyComplementOfKPointIdeal{QQField, QQFieldElem, QQMPolyRing, QQMPolyRingElem}}}:
+ y
+ 1
+
+julia> Aloc1,_ = localization(A, complement_of_point_ideal(R, [1,1]));
+
+julia> monomial_basis(Aloc1)
+1-element Vector{Oscar.MPolyLocRingElem{QQField, QQFieldElem, QQMPolyRing, QQMPolyRingElem, Oscar.MPolyComplementOfKPointIdeal{QQField, QQFieldElem, QQMPolyRing, QQMPolyRingElem}}}:
+ 1
+
+julia> Aloc2,_ = localization(A, complement_of_point_ideal(R, [-1,1]));
+
+julia> monomial_basis(Aloc2)
+1-element Vector{Oscar.MPolyLocRingElem{QQField, QQFieldElem, QQMPolyRing, QQMPolyRingElem, Oscar.MPolyComplementOfKPointIdeal{QQField, QQFieldElem, QQMPolyRing, QQMPolyRingElem}}}:
+ 1
+
+julia> vector_space_dimension(A) == vector_space_dimension(Aloc0) + vector_space_dimension(Aloc1) + vector_space_dimension(Aloc2)
+true
+```
+"""
+function monomial_basis(A::MPolyQuoLocRing{<:Field, <:Any, <:Any, <:Any, <:MPolyComplementOfKPointIdeal})
+ return _monomial_basis(localized_ring(A), modulus(A))
+end
+
function is_finite_dimensional_vector_space(R::MPolyQuoLocRing)
throw(NotImplementedError(:is_finite_dimensional_vector_space, R))
end
@@ -2488,7 +2565,36 @@ function small_generating_set(
end::Vector{elem_type(base_ring(I))}
end
-dim(R::MPolyQuoLocRing{<:Field, <:FieldElem, <:MPolyRing, <:MPolyRingElem, <:MPolyComplementOfPrimeIdeal}) = dim(saturated_ideal(modulus(R))) - dim(prime_ideal(inverted_set(R)))
+@attr Int function dim(R::MPolyLocRing)
+ error("Not implemented")
+end
+
+@attr Int function dim(R::MPolyQuoLocRing{<:Any, <:Any, <:MPolyRing, <:MPolyRingElem, <:Union{MPolyComplementOfPrimeIdeal, MPolyComplementOfKPointIdeal}})
+ P = prime_ideal(inverted_set(R))
+ I = saturated_ideal(modulus(R))
+ return dim(I) - dim(P)
+end
+
+@attr Int function dim(R::MPolyQuoLocRing{<:Any, <:Any, <:MPolyRing, <:MPolyRingElem, <:MPolyPowersOfElement})
+ return dim(saturated_ideal(modulus(R)))
+end
+
+@attr Int function dim(R::MPolyLocRing{<:Any,<:Any,<:MPolyRing,<:MPolyRingElem, <:MPolyPowersOfElement})
+ # zariski open subset of A^n
+ return dim(base_ring(R))
+end
+
+@attr Int function dim(R::MPolyLocRing{<:Any,<:Any,<:MPolyRing,<:MPolyRingElem, <:MPolyComplementOfPrimeIdeal})
+ P = prime_ideal(inverted_set(R))
+ return codim(P)
+end
+
+
+@attr Int function dim(R::MPolyLocRing{<:Field,<:Any,<:MPolyRing,<:MPolyRingElem, <:MPolyComplementOfKPointIdeal})
+ # localization of a polynomial ring over a field at a maximal ideal does not change the dimension
+ # because all maximal ideals have the same dimension in this case.
+ return dim(base_ring(R))
+end
########################################################################
# Localizations of graded rings #
@@ -2807,4 +2913,5 @@ _exponents(x::MPolyQuoLocRingElem) = AbstractAlgebra.exponent_vectors(lifted_num
# overwriting the comparison method to avoid computing saturations and groebner bases.
_cmp_reps(a::MPolyLocRingElem) = y->(fraction(y) == fraction(a))
_cmp_reps(a::MPolyQuoLocRingElem) = y->(fraction(y) == fraction(a))
+_cmp_reps(a::MPolyQuoRingElem) = y->(y.f == a.f)
diff --git a/src/Serialization/Fields.jl b/src/Serialization/Fields.jl
index 4176250d0e58..043ff7c23184 100644
--- a/src/Serialization/Fields.jl
+++ b/src/Serialization/Fields.jl
@@ -191,7 +191,7 @@ function save_object(s::SerializerState, K::FqField)
save_object(s, order(K))
else
save_data_dict(s) do
- save_typed_object(s, defining_polynomial(K))
+ save_typed_object(s, defining_polynomial(K), :def_pol)
end
end
end
@@ -202,7 +202,7 @@ function load_object(s::DeserializerState, ::Type{<: FqField})
order = ZZRingElem(node)
return finite_field(order)[1]
else
- def_pol = load_typed_object(s)
+ def_pol = load_typed_object(s, :def_pol)
return finite_field(def_pol, cached=false)[1]
end
end
diff --git a/src/Serialization/ToricGeometry.jl b/src/Serialization/ToricGeometry.jl
index c7434869be26..7c8fad660f2e 100644
--- a/src/Serialization/ToricGeometry.jl
+++ b/src/Serialization/ToricGeometry.jl
@@ -2,7 +2,7 @@
# Toric varieties
@register_serialization_type AffineNormalToricVariety uses_id
-@register_serialization_type NormalToricVariety uses_id [:cox_ring, :class_group]
+@register_serialization_type NormalToricVariety uses_id [:cox_ring, :class_group, :cohomology_ring]
function save_object(s::SerializerState, ntv::T) where T <: NormalToricVarietyType
@@ -93,3 +93,29 @@ function load_object(s::DeserializerState, ::Type{ToricDivisorClass}, tv::Normal
pmdiv = Polymake._lookup_multi(pm_object(tv), "DIVISOR", index-1)
return toric_divisor_class(ToricDivisor(pmdiv, tv, coeffs))
end
+
+################################################################################
+# Cohomology classes on toric varieties
+@register_serialization_type CohomologyClass uses_params
+
+function save_type_params(s::SerializerState, obj::CohomologyClass)
+ save_data_dict(s) do
+ save_object(s, encode_type(CohomologyClass), :name)
+ save_typed_object(s, obj.v, :params)
+ end
+end
+
+function load_type_params(s::DeserializerState, ::Type{<:CohomologyClass})
+ return load_typed_object(s)
+end
+
+function save_object(s::SerializerState, cc::CohomologyClass)
+ save_data_dict(s) do
+ save_object(s, lift(polynomial(cc)), :polynomial)
+ end
+end
+
+function load_object(s::DeserializerState, ::Type{CohomologyClass}, tv::NormalToricVarietyType)
+ poly = load_object(s, MPolyDecRingElem, base_ring(cohomology_ring(tv)), :polynomial)
+ return cohomology_class(tv, MPolyQuoRingElem(poly, cohomology_ring(tv)))
+end
diff --git a/src/Serialization/Upgrades/1.3.0.jl b/src/Serialization/Upgrades/1.3.0.jl
new file mode 100644
index 000000000000..1c721bf8f489
--- /dev/null
+++ b/src/Serialization/Upgrades/1.3.0.jl
@@ -0,0 +1,24 @@
+push!(upgrade_scripts_set, UpgradeScript(
+ v"1.3.0",
+ function upgrade_1_3_0(s::UpgradeState, dict::Dict)
+ upgraded_dict = dict
+ if haskey(dict, :_type) && dict[:_type] == "FqField"
+ if dict[:data] isa Dict
+ if !(haskey(dict[:data], :def_pol))
+ upgraded_dict[:data][:def_pol] = copy(dict[:data])
+ end
+ end
+ elseif haskey(dict, :data) && dict[:data] isa Dict
+ upgraded_dict[:data] = upgrade_1_3_0(s, dict[:data])
+ end
+ if haskey(dict, :_refs)
+ upgraded_refs = Dict()
+ for (k, v) in dict[:_refs]
+ upgraded_refs[k] = upgrade_1_3_0(s, v)
+ end
+ upgraded_dict[:_refs] = upgraded_refs
+ end
+
+ return upgraded_dict
+ end
+))
diff --git a/src/Serialization/Upgrades/main.jl b/src/Serialization/Upgrades/main.jl
index fa297ff5e03f..f6c35f46589f 100644
--- a/src/Serialization/Upgrades/main.jl
+++ b/src/Serialization/Upgrades/main.jl
@@ -141,6 +141,7 @@ include("0.13.0.jl")
include("0.15.0.jl")
include("1.1.0.jl")
include("1.2.0.jl")
+include("1.3.0.jl")
const upgrade_scripts = collect(upgrade_scripts_set)
sort!(upgrade_scripts; by=version)
diff --git a/src/TropicalGeometry/curve.jl b/src/TropicalGeometry/curve.jl
index e6f70218c390..32ef9762d5eb 100644
--- a/src/TropicalGeometry/curve.jl
+++ b/src/TropicalGeometry/curve.jl
@@ -59,7 +59,7 @@ Return the embedded tropical curve consisting of the polyhedral complex `Sigma`
```jldoctest
julia> verticesAndRays = [0 0; 1 0; 0 1; -1 -1];
-julia> incidenceMatrix = IncidenceMatrix([[1,2],[1,3],[1,4]]);
+julia> incidenceMatrix = incidence_matrix([[1,2],[1,3],[1,4]]);
julia> rayIndices = [2,3,4];
@@ -222,7 +222,7 @@ end
# # Examples
# ```jldoctest
-# julia> IM = IncidenceMatrix([[1,2],[1,3],[1,4],[2,3],[2,4],[3,4]]);
+# julia> IM = incidence_matrix([[1,2],[1,3],[1,4],[2,3],[2,4],[3,4]]);
# julia> tc = TropicalCurve(IM)
# ERROR: MethodError: no method matching TropicalCurve(::Polymake.LibPolymake.IncidenceMatrixAllocated{Polymake.LibPolymake.NonSymmetric})
@@ -291,7 +291,7 @@ end
# # Examples
# ```jldoctest
-# julia> IM = IncidenceMatrix([[1,2],[1,3],[1,4],[2,3],[2,4],[3,4]]);
+# julia> IM = incidence_matrix([[1,2],[1,3],[1,4],[2,3],[2,4],[3,4]]);
# julia> tc = TropicalCurve(IM)
# ERROR: MethodError: no method matching TropicalCurve(::Polymake.LibPolymake.IncidenceMatrixAllocated{Polymake.LibPolymake.NonSymmetric})
@@ -352,7 +352,7 @@ end
# # Examples
# ```jldoctest
-# julia> IM = IncidenceMatrix([[1,2],[1,3],[1,4],[2,3],[2,4],[3,4]]);
+# julia> IM = incidence_matrix([[1,2],[1,3],[1,4],[2,3],[2,4],[3,4]]);
# julia> tc = TropicalCurve(IM)
# ERROR: MethodError: no method matching TropicalCurve(::Polymake.LibPolymake.IncidenceMatrixAllocated{Polymake.LibPolymake.NonSymmetric})
@@ -411,7 +411,7 @@ end
# ```jldoctest
# julia> cg = complete_graph(5);
-# julia> IM1=IncidenceMatrix([[src(e), dst(e)] for e in edges(cg)])
+# julia> IM1 = incidence_matrix([[src(e), dst(e)] for e in edges(cg)])
# 10×5 IncidenceMatrix
# [1, 2]
# [1, 3]
@@ -438,7 +438,7 @@ end
# julia> cg2 = complete_graph(3);
-# julia> IM2=IncidenceMatrix([[src(e), dst(e)] for e in edges(cg2)])
+# julia> IM2 = incidence_matrix([[src(e), dst(e)] for e in edges(cg2)])
# 3×3 IncidenceMatrix
# [1, 2]
# [1, 3]
@@ -456,7 +456,7 @@ end
# [1] top-level scope
# @ none:1
-# julia> IM3 = IncidenceMatrix([[1,2],[2,3],[3,4],[4,5],[1,5]])
+# julia> IM3 = incidence_matrix([[1,2],[2,3],[3,4],[4,5],[1,5]])
# 5×5 IncidenceMatrix
# [1, 2]
# [2, 3]
@@ -500,7 +500,7 @@ end
# # ```julia
# # julia> using Revise, Plots, Oscar, Test;
-# # julia> IM = IncidenceMatrix([[1,2],[1,3],[1,4]]);
+# # julia> IM = incidence_matrix([[1,2],[1,3],[1,4]]);
# # julia> VR = [0 0; 1 0; -1 0; 0 1];
diff --git a/src/TropicalGeometry/groebner_fan.jl b/src/TropicalGeometry/groebner_fan.jl
index df58dd72723a..0ba7939fb4f7 100644
--- a/src/TropicalGeometry/groebner_fan.jl
+++ b/src/TropicalGeometry/groebner_fan.jl
@@ -172,8 +172,8 @@ Ideal generated by
julia> G = groebner_basis(I,ordering=lex(Qx))
Gröbner basis with elements
- 1 -> x2 + x3
- 2 -> x1
+ 1: x2 + x3
+ 2: x1
with respect to the ordering
lex([x1, x2, x3])
diff --git a/src/TropicalGeometry/variety.jl b/src/TropicalGeometry/variety.jl
index 7c2822564274..66f481378f70 100644
--- a/src/TropicalGeometry/variety.jl
+++ b/src/TropicalGeometry/variety.jl
@@ -46,7 +46,7 @@ Return the `TropicalVariety` whose polyhedral complex is `Sigma` with multiplici
# Examples
```jldoctest
-julia> Sigma = polyhedral_complex(IncidenceMatrix([[1],[2]]), [[0],[1]])
+julia> Sigma = polyhedral_complex(incidence_matrix([[1],[2]]), [[0],[1]])
Polyhedral complex in ambient dimension 1
julia> tropical_variety(Sigma)
diff --git a/src/deprecations.jl b/src/deprecations.jl
index e48a6cc42ecd..fee339161138 100644
--- a/src/deprecations.jl
+++ b/src/deprecations.jl
@@ -143,3 +143,12 @@ Base.@deprecate_binding in_linear_system is_in_linear_system
@deprecate scheme(W::AbsAlgebraicCycle) ambient_scheme(W)
@deprecate scheme(W::CartierDivisor) ambient_scheme(W)
@deprecate scheme(W::EffectiveCartierDivisor) ambient_scheme(W)
+
+@deprecate mordell_weil_lattice(X::EllipticSurface) mordell_weil_sublattice(X)
+@deprecate minimal_generating_set(G::GAPGroup) minimal_size_generating_set(G)
+@deprecate has_minimal_generating_set(G::GAPGroup) has_minimal_size_generating_set(G)
+@deprecate set_minimal_generating_set(G::GAPGroup, v) set_minimal_size_generating_set(G, v)
+
+# deprecated for 1.3
+@deprecate acting_domain(C::GroupCoset) acting_group(C)
+@deprecate acting_domain(Omega::GSet) acting_group(Omega)
diff --git a/src/exports.jl b/src/exports.jl
index cce9ee01c6e0..88d5d00374e9 100644
--- a/src/exports.jl
+++ b/src/exports.jl
@@ -49,6 +49,7 @@ export AlgebraicCycle
export AutomorphismGroup
export AutomorphismGroupElem
export BettiTable
+export BlowupMorphism
export BorcherdsCtx
export CartierDivisor
export ClosedEmbedding
@@ -66,6 +67,7 @@ export DirectSumSheaf
export Directed
export Edge
export EffectiveCartierDivisor
+export EllipticSurface
export EmptyScheme
export FPGroup
export FPGroupElem
@@ -199,7 +201,6 @@ export abelian_group
export abelian_invariants
export abelian_invariants_schur_multiplier
export absolute_primary_decomposition
-export acting_domain
export acting_group
export acting_subgroup
export action
@@ -233,6 +234,7 @@ export affine_space
export alexander_dual
export algebraic_cycle
export algebraic_ideal
+export algebraic_lattice
export algebraic_matrix
export algebraic_matroid
export algebraic_pluecker_vector
@@ -277,8 +279,8 @@ export as_dictionary
export as_gset
export ascending_compositions
export associahedron
-export associated_primes
export associated_points
+export associated_primes
export atlas_description
export atlas_group
export atlas_irrationality
@@ -293,6 +295,7 @@ export bases
export basis_of_global_sections
export basis_of_global_sections_via_homogeneous_component
export basis_of_global_sections_via_rational_functions
+export basis_of_h4
export bell
export betti
export betti_number
@@ -528,6 +531,8 @@ export elementary_abelian_group
export elementary_symmetric
export elements
export eliminate
+export elliptic_parameter
+export elliptic_surface
export embedding
export embedding_orthogonal_group
export epimorphism_from_free_group
@@ -537,6 +542,7 @@ export equidimensional_hull
export equidimensional_hull_radical
export euler_characteristic
export euler_phi
+export exceptional_divisor
export expand
export explicit_zonotope
export exponent, has_exponent, set_exponent
@@ -562,8 +568,10 @@ export fat_ideal
export fat_scheme
export feasible_region
export fglm
+export fiber_components
export fiber_product
export fibonacci
+export fibration_type
export filtrate
export find_morphism
export find_morphisms
@@ -610,6 +618,7 @@ export generalized_jordan_block
export generalized_jordan_form
export generating_system
export generator_matrix
+export generic_fiber
export generic_fraction
export generic_fractions
export generic_section
@@ -617,6 +626,10 @@ export gens, has_gens
export gens_of_rational_equivalence_classes
export geometric_genus
export geometric_irreducible_components
+export get_conjugate
+export get_power
+export get_relative_order
+export get_relative_orders
export getindex_safe
export girth
export gkz_vector
@@ -714,7 +727,6 @@ export image_in_Oq
export images
export img_gens
export immaculate_line_bundles
-export is_in_linear_system
export incidence_matrix
export inclusion_morphism
export independent_sets
@@ -832,6 +844,7 @@ export is_groebner_basis
export is_homogeneous
export is_identity_map
export is_immaculate
+export is_in_linear_system
export is_injective
export is_inner_automorphism
export is_integral
@@ -1053,7 +1066,8 @@ export min_weights
export minimal_betti_table
export minimal_block_reps
export minimal_faces
-export minimal_generating_set, has_minimal_generating_set, set_minimal_generating_set
+export minimal_generating_set
+export minimal_size_generating_set, has_minimal_size_generating_set, set_minimal_size_generating_set
export minimal_nonfaces
export minimal_normal_subgroups, has_minimal_normal_subgroups, set_minimal_normal_subgroups
export minimal_primes
@@ -1069,6 +1083,7 @@ export monomial_basis
export monomial_ordering
export monomials
export monomials_of_degree
+export mordell_weil_sublattice
export mori_cone
export morphism
export morphism_from_cox_variety
@@ -1166,6 +1181,7 @@ export objective_function
export omega_group
export on_indeterminates
export on_lines
+export on_echelon_form_mats
export on_sets
export on_sets_sets
export on_simplicial_complex
@@ -1329,6 +1345,7 @@ export reduce_with_quotients_and_unit
export reduced_characteristic_polynomial
export reduced_groebner_basis
export reduced_scheme
+export reducible_fibers
export register_morphism!
export regular_120_cell
export regular_24_cell
@@ -1397,6 +1414,7 @@ export schur_polynomial
export secondary_cone
export secondary_invariants
export secondary_polytope
+export section
export sectional_genus
export semi_invariants
export semidirect_product
@@ -1409,6 +1427,7 @@ export set_conjugate!
export set_coordinate_names
export set_coordinate_names_of_torus
export set_grading
+export set_mordell_weil_basis!
export set_name!
export set_ordering
export set_power!
@@ -1525,6 +1544,7 @@ export torusinvariant_weil_divisor_group
export total_degree
export total_space
export transform
+export transform_to_weierstrass
export transitive_group
export transitive_group_identification, has_transitive_group_identification
export transitivity
@@ -1533,6 +1553,7 @@ export transportation_polytope
export trivial_character
export trivial_divisor
export trivial_divisor_class
+export trivial_lattice
export trivial_line_bundle
export trivial_morphism
export trivial_subgroup, has_trivial_subgroup, set_trivial_subgroup
@@ -1596,6 +1617,10 @@ export wedge
export wedge_generator_decompose_function
export wedge_multiplication_map
export wedge_pure_function
+export weierstrass_chart
+export weierstrass_chart_on_minimal_model
+export weierstrass_contraction
+export weierstrass_model
export weight
export weight_cone
export weight_ordering
@@ -1608,5 +1633,6 @@ export witt_index
export wreath_product
export write_as_full
export young_tableau
+export zero_section
export zonotope
export zonotope_vertices_fukuda_matrix
diff --git a/test/AlgebraicGeometry/Schemes/AffineSchemes.jl b/test/AlgebraicGeometry/Schemes/AffineSchemes.jl
index 0e1cde438b3a..7e245998c202 100644
--- a/test/AlgebraicGeometry/Schemes/AffineSchemes.jl
+++ b/test/AlgebraicGeometry/Schemes/AffineSchemes.jl
@@ -138,7 +138,7 @@ end
Z = spec(R, S)
@test dim(Z) == 4
- S = complement_of_point_ideal(R, [1, 1, 1])
+ S = complement_of_prime_ideal(ideal(R, [x-1, y-1, z-1]))
I = ideal(R, [x-1, y-1])*ideal(R, z)
L, _ = localization(R, S)
W, _ = quo(L, L(I))
diff --git a/test/AlgebraicGeometry/Schemes/elliptic_surface.jl b/test/AlgebraicGeometry/Schemes/EllipticSurface.jl
similarity index 99%
rename from test/AlgebraicGeometry/Schemes/elliptic_surface.jl
rename to test/AlgebraicGeometry/Schemes/EllipticSurface.jl
index 1d38d185653f..2860d531759e 100644
--- a/test/AlgebraicGeometry/Schemes/elliptic_surface.jl
+++ b/test/AlgebraicGeometry/Schemes/EllipticSurface.jl
@@ -50,7 +50,7 @@
@test length(Oscar.mordell_weil_torsion(X)) == 1
alg = algebraic_lattice(X)
@test det(alg[3]) == -192
- @test det(mordell_weil_lattice(X)) == 3
+ @test det(mordell_weil_sublattice(X)) == 3
X1 = elliptic_surface(short_weierstrass_model(E)[1],2)
Oscar.isomorphism_from_generic_fibers(X,X1)
diff --git a/test/AlgebraicGeometry/Schemes/Tjurina.jl b/test/AlgebraicGeometry/Schemes/Tjurina.jl
index af5b33ac2495..a9014b53b246 100644
--- a/test/AlgebraicGeometry/Schemes/Tjurina.jl
+++ b/test/AlgebraicGeometry/Schemes/Tjurina.jl
@@ -252,3 +252,17 @@ end
@test !is_contact_equivalent(L(x^9+y^2+z^2), L(x^3+y^5))
end
+
+
+@testset "Tjurina number complete intersection germ" begin
+ A = affine_space(QQ, 3)
+ R = coordinate_ring(A);
+ (x,y,z) = gens(R);
+ X = CompleteIntersectionGerm(spec(quo(R,ideal(R,[x^2+y^2+z^2, x^2+2*y^2+3*z^2]))[1]), [0,0,0])
+ @test tjurina_number(X) == 5
+ S = spec(quo(R,ideal(R,[x^5+y^6+z^7+x*y*z]))[1])
+ @test tjurina_number(HypersurfaceGerm(S, [0,0,0])) == tjurina_number(CompleteIntersectionGerm(S, [0,0,0]))
+ Y = CompleteIntersectionGerm(spec(quo(R,ideal(R,[x^2+y^2, x^2+2*y^2]))[1]), [0,0,0])
+ @test tjurina_number(Y) == PosInf()
+end
+
diff --git a/test/AlgebraicGeometry/Surfaces/K3Auto.jl b/test/AlgebraicGeometry/Surfaces/K3Auto.jl
index 0e637c52ff02..035c3f2ecee2 100644
--- a/test/AlgebraicGeometry/Surfaces/K3Auto.jl
+++ b/test/AlgebraicGeometry/Surfaces/K3Auto.jl
@@ -1,6 +1,6 @@
@testset "elliptic fibrations" begin
- B = matrix(FlintQQ, 16, 16 ,[2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3//2, 1//2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1//2, 3//2, 3//2, 1//2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1//2, 3//2, 0, 1//2, 1//2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1//2, 1//2, 1//2, 0, 1//2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1//2, 1, 1//2, 0, 1//2, 0, 0, 1//2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1//2, 0, 1//2, 0, 3//5, 1//10]);
- G = matrix(FlintQQ, 16, 16 ,[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -170]);
+ B = matrix(QQ, 16, 16 ,[2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3//2, 1//2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1//2, 3//2, 3//2, 1//2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1//2, 3//2, 0, 1//2, 1//2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1//2, 1//2, 1//2, 0, 1//2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1//2, 1, 1//2, 0, 1//2, 0, 0, 1//2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1//2, 0, 1//2, 0, 3//5, 1//10]);
+ G = matrix(QQ, 16, 16 ,[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -170]);
NS = integer_lattice(B, gram = G);
V = ambient_space(NS)
f = QQFieldElem[2, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
@@ -23,12 +23,12 @@ end
@testset "walls of chamber" begin
S = integer_lattice(gram=QQ[-2 1 0 0; 1 -2 1 1; 0 1 -2 1; 0 1 1 -2])
# fix an embedding
- B = matrix(FlintQQ, 10, 10 ,[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1//3, 2//3, 1//3, 2//3, 2//3, 2//3, 1//3, 1//3, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]);
- G = matrix(FlintQQ, 10, 10 ,[-2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, -2, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, -2, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -2, -1, 1, -1, -1, -1, 0, 0, 0, 0, -1, -2, 1, -1, 0, -1, 0, 0, 0, 0, 1, 1, -2, 0, 0, 1, 0, 0, 0, 0, -1, -1, 0, -2, -1, -1, 0, 0, 0, 0, -1, 0, 0, -1, -2, -1, 0, 0, 0, 0, -1, -1, 1, -1, -1, -2]);
+ B = matrix(QQ, 10, 10 ,[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1//3, 2//3, 1//3, 2//3, 2//3, 2//3, 1//3, 1//3, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]);
+ G = matrix(QQ, 10, 10 ,[-2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, -2, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, -2, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -2, -1, 1, -1, -1, -1, 0, 0, 0, 0, -1, -2, 1, -1, 0, -1, 0, 0, 0, 0, 1, 1, -2, 0, 0, 1, 0, 0, 0, 0, -1, -1, 0, -2, -1, -1, 0, 0, 0, 0, -1, 0, 0, -1, -2, -1, 0, 0, 0, 0, -1, -1, 1, -1, -1, -2]);
L = integer_lattice(B, gram = G);
- B = matrix(FlintQQ, 4, 10 ,[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0]);
- G = matrix(FlintQQ, 10, 10 ,[-2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, -2, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, -2, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -2, -1, 1, -1, -1, -1, 0, 0, 0, 0, -1, -2, 1, -1, 0, -1, 0, 0, 0, 0, 1, 1, -2, 0, 0, 1, 0, 0, 0, 0, -1, -1, 0, -2, -1, -1, 0, 0, 0, 0, -1, 0, 0, -1, -2, -1, 0, 0, 0, 0, -1, -1, 1, -1, -1, -2]);
+ B = matrix(QQ, 4, 10 ,[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0]);
+ G = matrix(QQ, 10, 10 ,[-2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, -2, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, -2, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -2, -1, 1, -1, -1, -1, 0, 0, 0, 0, -1, -2, 1, -1, 0, -1, 0, 0, 0, 0, 1, 1, -2, 0, 0, 1, 0, 0, 0, 0, -1, -1, 0, -2, -1, -1, 0, 0, 0, 0, -1, 0, 0, -1, -2, -1, 0, 0, 0, 0, -1, -1, 1, -1, -1, -2]);
S = integer_lattice(B, gram = G);
weyl = QQ[31 61 52 71 5 -6 5 -2 -7 8]
@@ -171,11 +171,11 @@ end
end
@testset "weyl_vector_non_degenerate" begin
- B = matrix(FlintQQ, 10, 10 ,[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1//3, 2//3, 1//3, 2//3, 2//3, 2//3, 1//3, 1//3]);
- G = matrix(FlintQQ, 10, 10 ,[-2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, -2, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, -2, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -2, -1, 1, -1, -1, -1, 0, 0, 0, 0, -1, -2, 1, -1, 0, -1, 0, 0, 0, 0, 1, 1, -2, 0, 0, 1, 0, 0, 0, 0, -1, -1, 0, -2, -1, -1, 0, 0, 0, 0, -1, 0, 0, -1, -2, -1, 0, 0, 0, 0, -1, -1, 1, -1, -1, -2]);
+ B = matrix(QQ, 10, 10 ,[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1//3, 2//3, 1//3, 2//3, 2//3, 2//3, 1//3, 1//3]);
+ G = matrix(QQ, 10, 10 ,[-2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, -2, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, -2, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -2, -1, 1, -1, -1, -1, 0, 0, 0, 0, -1, -2, 1, -1, 0, -1, 0, 0, 0, 0, 1, 1, -2, 0, 0, 1, 0, 0, 0, 0, -1, -1, 0, -2, -1, -1, 0, 0, 0, 0, -1, 0, 0, -1, -2, -1, 0, 0, 0, 0, -1, -1, 1, -1, -1, -2]);
L = integer_lattice(B, gram = G);
- B = matrix(FlintQQ, 4, 10 ,[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0]);
- G = matrix(FlintQQ, 10, 10 ,[-2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, -2, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, -2, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -2, -1, 1, -1, -1, -1, 0, 0, 0, 0, -1, -2, 1, -1, 0, -1, 0, 0, 0, 0, 1, 1, -2, 0, 0, 1, 0, 0, 0, 0, -1, -1, 0, -2, -1, -1, 0, 0, 0, 0, -1, 0, 0, -1, -2, -1, 0, 0, 0, 0, -1, -1, 1, -1, -1, -2]);
+ B = matrix(QQ, 4, 10 ,[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0]);
+ G = matrix(QQ, 10, 10 ,[-2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, -2, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, -2, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -2, -1, 1, -1, -1, -1, 0, 0, 0, 0, -1, -2, 1, -1, 0, -1, 0, 0, 0, 0, 1, 1, -2, 0, 0, 1, 0, 0, 0, 0, -1, -1, 0, -2, -1, -1, 0, 0, 0, 0, -1, 0, 0, -1, -2, -1, 0, 0, 0, 0, -1, -1, 1, -1, -1, -2]);
S = integer_lattice(B, gram = G);
u = QQ[90 157 218//3 346//3 -7//3 13//3 16//3 -11//3 -1//3 32//3]
weyl = QQ[90 157 218//3 346//3 -7//3 13//3 16//3 -11//3 -1//3 32//3]
diff --git a/test/AlgebraicGeometry/ToricVarieties/affine_normal_varieties.jl b/test/AlgebraicGeometry/ToricVarieties/affine_normal_varieties.jl
index b412a3037c33..a21649946a33 100644
--- a/test/AlgebraicGeometry/ToricVarieties/affine_normal_varieties.jl
+++ b/test/AlgebraicGeometry/ToricVarieties/affine_normal_varieties.jl
@@ -5,7 +5,7 @@
antv3 = affine_normal_toric_variety(antv2)
antv4 = affine_normal_toric_variety(Oscar.positive_hull([1 0]))
antv5 = affine_space(NormalToricVariety, 2)
- antv6 = normal_toric_variety(IncidenceMatrix([[1,2,3,4]]), [[1, 0, 0], [1, 0, 1], [1, 1, 1], [1, 1, 0]])
+ antv6 = normal_toric_variety(incidence_matrix([[1,2,3,4]]), [[1, 0, 0], [1, 0, 1], [1, 1, 1], [1, 1, 0]])
@testset "Basic properties" begin
@test is_smooth(antv) == false
diff --git a/test/AlgebraicGeometry/ToricVarieties/direct_products.jl b/test/AlgebraicGeometry/ToricVarieties/direct_products.jl
index a617af339b27..05ced475ffe1 100644
--- a/test/AlgebraicGeometry/ToricVarieties/direct_products.jl
+++ b/test/AlgebraicGeometry/ToricVarieties/direct_products.jl
@@ -1,6 +1,6 @@
@testset "Direct products" begin
- F5 = normal_toric_variety(IncidenceMatrix([[1, 2], [2, 3], [3, 4], [4, 1]]), [[1, 0], [0, 1], [-1, 5], [0, -1]])
+ F5 = normal_toric_variety(incidence_matrix([[1, 2], [2, 3], [3, 4], [4, 1]]), [[1, 0], [0, 1], [-1, 5], [0, -1]])
P2 = normal_toric_variety(normal_fan(Oscar.simplex(2)))
variety = F5 * P2
diff --git a/test/AlgebraicGeometry/ToricVarieties/intersection_numbers.jl b/test/AlgebraicGeometry/ToricVarieties/intersection_numbers.jl
index e83d5a469cf9..384dfd4c369a 100644
--- a/test/AlgebraicGeometry/ToricVarieties/intersection_numbers.jl
+++ b/test/AlgebraicGeometry/ToricVarieties/intersection_numbers.jl
@@ -2,9 +2,9 @@
antv = affine_normal_toric_variety(Oscar.positive_hull([1 1; -1 1]))
- antv2 = normal_toric_variety(IncidenceMatrix([[1,2,3,4]]), [[1, 0, 0], [1, 0, 1], [1, 1, 1], [1, 1, 0]])
+ antv2 = normal_toric_variety(incidence_matrix([[1,2,3,4]]), [[1, 0, 0], [1, 0, 1], [1, 1, 1], [1, 1, 0]])
- v = normal_toric_variety(IncidenceMatrix([[1], [2], [3]]), [[1, 0], [0, 1], [-1, -1]])
+ v = normal_toric_variety(incidence_matrix([[1], [2], [3]]), [[1, 0], [0, 1], [-1, -1]])
dP1 = del_pezzo_surface(NormalToricVariety, 1)
c0 = cohomology_class(dP1, gens(cohomology_ring(dP1))[1])
diff --git a/test/AlgebraicGeometry/ToricVarieties/line_bundle_cohomologies.jl b/test/AlgebraicGeometry/ToricVarieties/line_bundle_cohomologies.jl
index ec7bc5eed471..ba7074feeb1c 100644
--- a/test/AlgebraicGeometry/ToricVarieties/line_bundle_cohomologies.jl
+++ b/test/AlgebraicGeometry/ToricVarieties/line_bundle_cohomologies.jl
@@ -5,7 +5,7 @@
F5 = hirzebruch_surface(NormalToricVariety, 5)
ray_generators = [[1, 0, 0,-2,-3], [0, 1, 0,-2,-3], [0, 0, 1,-2,-3], [-1,-1,-1,-2,-3], [0, 0, 0, 1, 0], [0, 0, 0, 0, 1], [0, 0, 0,-2,-3]]
- max_cones = IncidenceMatrix([[1, 2, 3, 5, 6], [1, 2, 3, 5, 7], [1, 2, 3, 6, 7], [2, 3, 4, 5, 6], [2, 3, 4, 5, 7], [2, 3, 4, 6, 7], [1, 3, 4, 5, 6], [1, 3, 4, 5, 7], [1, 3, 4, 6, 7], [1, 2, 4, 5, 6], [1, 2, 4, 5, 7], [1, 2, 4, 6, 7]])
+ max_cones = incidence_matrix([[1, 2, 3, 5, 6], [1, 2, 3, 5, 7], [1, 2, 3, 6, 7], [2, 3, 4, 5, 6], [2, 3, 4, 5, 7], [2, 3, 4, 6, 7], [1, 3, 4, 5, 6], [1, 3, 4, 5, 7], [1, 3, 4, 6, 7], [1, 2, 4, 5, 6], [1, 2, 4, 5, 7], [1, 2, 4, 6, 7]])
weierstrass_over_p3 = normal_toric_variety(max_cones, ray_generators; non_redundant = true)
l = toric_line_bundle(dP3, [1, 2, 3, 4])
diff --git a/test/AlgebraicGeometry/ToricVarieties/subvarieties.jl b/test/AlgebraicGeometry/ToricVarieties/subvarieties.jl
index d54d38dc197d..f50c9a3305a1 100644
--- a/test/AlgebraicGeometry/ToricVarieties/subvarieties.jl
+++ b/test/AlgebraicGeometry/ToricVarieties/subvarieties.jl
@@ -1,6 +1,6 @@
@testset "Closed subvarieties" begin
- antv = normal_toric_variety(IncidenceMatrix([[1,2,3,4]]), [[1, 0, 0], [1, 0, 1], [1, 1, 1], [1, 1, 0]])
+ antv = normal_toric_variety(incidence_matrix([[1,2,3,4]]), [[1, 0, 0], [1, 0, 1], [1, 1, 1], [1, 1, 0]])
ntv = normal_toric_variety(cube(2))
(x1, x2, y1, y2) = gens(cox_ring(ntv));
diff --git a/test/AlgebraicGeometry/ToricVarieties/toric_divisor_classes.jl b/test/AlgebraicGeometry/ToricVarieties/toric_divisor_classes.jl
index 775e514cd954..724830921061 100644
--- a/test/AlgebraicGeometry/ToricVarieties/toric_divisor_classes.jl
+++ b/test/AlgebraicGeometry/ToricVarieties/toric_divisor_classes.jl
@@ -5,7 +5,7 @@
P2 = projective_space(NormalToricVariety, 2)
rs = [[0, 1, 0], [-1, 1, 1], [-1, 0, 0], [-1, -2, -2], [0, -1, -1], [0, 0, 1], [-1, -1, -1], [1, 0, 0]]
- cs = IncidenceMatrix([[1, 2, 3], [1, 4, 5], [3, 6, 7], [4, 5, 6], [1, 4, 7], [5, 6, 8], [1, 6, 8], [2, 3, 6], [1, 5, 8], [1, 3, 7], [1, 2, 6], [4, 6, 7]])
+ cs = incidence_matrix([[1, 2, 3], [1, 4, 5], [3, 6, 7], [4, 5, 6], [1, 4, 7], [5, 6, 8], [1, 6, 8], [2, 3, 6], [1, 5, 8], [1, 3, 7], [1, 2, 6], [4, 6, 7]])
test_space = normal_toric_variety(cs, rs)
DC = toric_divisor_class(F5, [ZZRingElem(0), ZZRingElem(0)])
diff --git a/test/AlgebraicGeometry/ToricVarieties/toric_schemes.jl b/test/AlgebraicGeometry/ToricVarieties/toric_schemes.jl
index b723ea89f198..8eb6b42cbd9f 100644
--- a/test/AlgebraicGeometry/ToricVarieties/toric_schemes.jl
+++ b/test/AlgebraicGeometry/ToricVarieties/toric_schemes.jl
@@ -97,7 +97,7 @@
end
@testset "Lazy gluings" begin
- f = polyhedral_fan(IncidenceMatrix([[1, 2, 3],[1, 4, 5, 6]]), [0 0 1; 1 0 1; 0 1 0; -1 0 1; -1 -1 1; 0 -1 1])
+ f = polyhedral_fan(incidence_matrix([[1, 2, 3],[1, 4, 5, 6]]), [0 0 1; 1 0 1; 0 1 0; -1 0 1; -1 -1 1; 0 -1 1])
number_of_maximal_cones(f)
ntv = normal_toric_variety(f)
X = Oscar.underlying_scheme(ntv)
diff --git a/test/Combinatorics/EnumerativeCombinatorics/tableaux.jl b/test/Combinatorics/EnumerativeCombinatorics/tableaux.jl
index c3f539917395..16d1f844c703 100644
--- a/test/Combinatorics/EnumerativeCombinatorics/tableaux.jl
+++ b/test/Combinatorics/EnumerativeCombinatorics/tableaux.jl
@@ -6,9 +6,9 @@
@test reading_word(young_tableau(Array{Int,1}[])) == Int[]
# weight
- @test weight(young_tableau([[1,2,3],[1,2],[1]])) == [3,2,1]
+ @test weight(young_tableau([[1,2,3],[2,3],[3]])) == [1,2,3]
@test weight(young_tableau([[1,2,3,4,5]])) == [1,1,1,1,1]
- @test weight(young_tableau([[1],[1],[1]])) == [3]
+ @test_throws ArgumentError weight(young_tableau([[1],[1],[1]]))
@test weight(young_tableau(Array{Int,1}[])) == Int[]
# is_standard
diff --git a/test/Combinatorics/Graph.jl b/test/Combinatorics/Graph.jl
index 0e6ef72156b8..d742171d7b67 100644
--- a/test/Combinatorics/Graph.jl
+++ b/test/Combinatorics/Graph.jl
@@ -67,7 +67,7 @@
@test n_vertices(egplc) == 2
@test n_edges(egplc) == 1
- @test incidence_matrix(egtriangle) == IncidenceMatrix([[1,2],[1,3],[2,3]])
+ @test incidence_matrix(egtriangle) == incidence_matrix([[1,2],[1,3],[2,3]])
@test is_isomorphic(dual_graph(convex_hull([0 0 0; 1 0 0], nothing, [0 1 0])), Graph{Undirected}(2))
@test is_isomorphic(dual_graph(convex_hull([0 0 0], [0 0 1; 0 1 0; 1 0 0])), complete_graph(3))
diff --git a/test/Combinatorics/Matroids/Matroids.jl b/test/Combinatorics/Matroids/Matroids.jl
index 94474e845106..5cd0f76521dc 100644
--- a/test/Combinatorics/Matroids/Matroids.jl
+++ b/test/Combinatorics/Matroids/Matroids.jl
@@ -422,10 +422,17 @@
@testset "matroid_hex" begin
M = fano_matroid()
N = uniform_matroid(2, 4)
+ NN = uniform_matroid(1, 4)
M1 = matroid_from_matroid_hex(matroid_hex(M))
N1 = matroid_from_matroid_hex(matroid_hex(N))
+ NN1 = matroid_from_matroid_hex(matroid_hex(NN))
+
@test is_isomorphic(M, M1)
@test is_isomorphic(N, N1)
+
+ @test matroid_hex(NN) == "r1n4_f"
+ @test is_isomorphic(NN, NN1)
+
end
end
diff --git a/test/Combinatorics/SimplicialComplexes.jl b/test/Combinatorics/SimplicialComplexes.jl
index c89c3baa1856..3ba32a31e8b6 100644
--- a/test/Combinatorics/SimplicialComplexes.jl
+++ b/test/Combinatorics/SimplicialComplexes.jl
@@ -4,7 +4,7 @@
sphere = simplicial_complex([[1, 2, 3], [1, 2, 4], [1, 3, 4], [2, 3, 4]])
- sphere2 = simplicial_complex(IncidenceMatrix([[1, 2, 3], [1, 2, 4], [1, 3, 4], [2, 3, 4]]))
+ sphere2 = simplicial_complex(incidence_matrix([[1, 2, 3], [1, 2, 4], [1, 3, 4], [2, 3, 4]]))
not_known_to_be_a_ball = SimplicialComplex(Polymake.topaz.SimplicialComplex(FACETS=[[0,1]], BALL=nothing))
diff --git a/test/Groups/action.jl b/test/Groups/action.jl
index 2dd697fb61f3..a9e595f63a74 100644
--- a/test/Groups/action.jl
+++ b/test/Groups/action.jl
@@ -29,13 +29,21 @@
@test order(H) == 645120
@test K == stabilizer(H, 1)[1]
+ # larger examples
+ G = symmetric_group(100)
+ S1, _ = stabilizer(G, [1, 2, 3, 4, 5])
+ @test order(S1) == factorial(big(95))
+ S2, _ = stabilizer(G, (1, 2, 3, 4, 5))
+ @test S2 == S1
+ S3, _ = stabilizer(G, Set([1, 2, 3, 4, 5]))
+ @test order(S3) == order(S1) * factorial(5)
end
@testset "natural stabilizers in matrix groups" begin
n = 3
F = GF(2)
G = general_linear_group(n, F)
- V = AbstractAlgebra.Generic.FreeModule(F, n)
+ V = free_module(F, n)
v = gen(V, 1)
S = stabilizer(G, v)
@test order(S[1]) == 24
@@ -124,7 +132,7 @@ end
n = 3
F = GF(5)
G = general_linear_group(n, F)
- V = AbstractAlgebra.Generic.FreeModule(F, n)
+ V = free_module(F, n)
v = gen(V, 1)
v = on_lines(v, one(G)) # make sure that `v` is normalized
@test on_lines(2*v, one(G)) == v
diff --git a/test/Groups/conformance.jl b/test/Groups/conformance.jl
index dbbc4ceed9f9..a37f33d86955 100644
--- a/test/Groups/conformance.jl
+++ b/test/Groups/conformance.jl
@@ -5,7 +5,7 @@ import Oscar.AbstractAlgebra: Group
include(joinpath(dirname(pathof(AbstractAlgebra)), "..", "test", "Groups-conformance-tests.jl"))
-@testset "GAPGroups_interface_conformance for $(G)" for G in L
+@testset "GAPGroups_interface_conformance $G of type $(typeof(G))" for G in L
test_Group_interface(G)
test_GroupElem_interface(rand(G, 2)...)
diff --git a/test/Groups/gsets.jl b/test/Groups/gsets.jl
index c69eabcb8e45..86377eef8bdd 100644
--- a/test/Groups/gsets.jl
+++ b/test/Groups/gsets.jl
@@ -12,20 +12,34 @@
@test ! is_semiregular(Omega)
@test collect(Omega) == 1:6 # ordering is kept
@test order(stabilizer(Omega)[1]) * length(Omega) == order(G)
+ @test order(stabilizer(Omega, 1)[1]) == 120
+ @test order(stabilizer(Omega, Set([1, 2]))[1]) == 48
+ @test order(stabilizer(Omega, [1, 2])[1]) == 24
+ @test order(stabilizer(Omega, (1, 2))[1]) == 24
Omega = gset(G, [Set([1, 2])]) # action on unordered pairs
@test isa(Omega, GSet)
@test length(Omega) == 15
- @test order(stabilizer(Omega)[1]) * length(Omega) == order(G)
@test length(orbits(Omega)) == 1
@test is_transitive(Omega)
@test ! is_regular(Omega)
@test ! is_semiregular(Omega)
+ @test order(stabilizer(Omega)[1]) * length(Omega) == order(G)
+ @test order(stabilizer(Omega, Set([1, 3]))[1]) == 48
+ @test order(stabilizer(Omega, Set([Set([1, 2]), Set([1, 3])]))[1]) == 12
+ @test order(stabilizer(Omega, [Set([1, 2]), Set([1, 3])])[1]) == 6
+ @test order(stabilizer(Omega, (Set([1, 2]), Set([1, 3])))[1]) == 6
+ @test_throws MethodError stabilizer(Omega, [1, 2])
Omega = gset(G, [[1, 2]]) # action on ordered pairs
@test isa(Omega, GSet)
@test length(Omega) == 30
@test order(stabilizer(Omega)[1]) * length(Omega) == order(G)
+ @test order(stabilizer(Omega, [1, 3])[1]) == 24
+ @test order(stabilizer(Omega, Set([[1, 2], [1, 3]]))[1]) == 12
+ @test order(stabilizer(Omega, [[1, 2], [1, 3]])[1]) == 6
+ @test order(stabilizer(Omega, ([1, 2], [1, 3]))[1]) == 6
+ @test_throws MethodError stabilizer(Omega, Set([1, 2]))
@test length(orbits(Omega)) == 1
@test is_transitive(Omega)
@test ! is_regular(Omega)
@@ -40,16 +54,32 @@
@test ! is_regular(Omega)
@test ! is_semiregular(Omega)
+ # larger examples
+ G = symmetric_group(100)
+ Omega = gset(G)
+ S1, _ = stabilizer(Omega, [1, 2, 3, 4, 5])
+ @test order(S1) == factorial(big(95))
+ S2, _ = stabilizer(Omega, (1, 2, 3, 4, 5))
+ @test S2 == S1
+ S3, _ = stabilizer(Omega, Set([1, 2, 3, 4, 5]))
+ @test order(S3) == order(S1) * factorial(big(5))
+
# constructions by explicit action functions
+ G = symmetric_group(6)
omega = [0,1,0,1,0,1]
Omega = gset(G, permuted, [omega, [1,2,3,4,5,6]])
@test isa(Omega, GSet)
@test length(Omega) == 740
@test order(stabilizer(Omega, omega)[1]) * length(orbit(Omega, omega)) == order(G)
+ @test order(stabilizer(Omega, Set([omega, [1,0,0,1,0,1]]))[1]) == 8
+ @test order(stabilizer(Omega, [omega, [1,0,0,1,0,1]])[1]) == 4
+ @test order(stabilizer(Omega, (omega, [1,0,0,1,0,1]))[1]) == 4
+ @test_throws MethodError stabilizer(Omega, Set(omega))
@test length(orbits(Omega)) == 2
@test ! is_transitive(Omega)
@test ! is_regular(Omega)
@test ! is_semiregular(Omega)
+ @test_throws ArgumentError gset(G, permuted, omega)
R, x = polynomial_ring(QQ, [:x1, :x2, :x3]);
f = x[1]*x[2] + x[2]*x[3]
@@ -73,7 +103,7 @@
G = symmetric_group(6)
Omega = gset(G, [Set([1, 2])])
@test representative(Omega) in Omega
- @test acting_domain(Omega) == G
+ @test acting_group(Omega) == G
# wrapped elements of G-sets
G = symmetric_group(4)
diff --git a/test/Groups/homomorphisms.jl b/test/Groups/homomorphisms.jl
index 1889233e1202..1b5e891d8694 100644
--- a/test/Groups/homomorphisms.jl
+++ b/test/Groups/homomorphisms.jl
@@ -265,14 +265,10 @@ end
end
@testset "Finite FinGenAbGroup to GAPGroup" begin
-# @testset for Agens in [Int[], [2, 4, 8], [2, 3, 4], [2, 12],
-#T problem with GAP's `AbelianGroup`;
-#T see https://github.com/gap-system/gap/issues/5430
- @testset for Agens in [[2, 4, 8], [2, 3, 4], [2, 12],
+ @testset for Agens in [Int[], [2, 4, 8], [2, 3, 4], [2, 12],
[1, 6], matrix(ZZ, 2, 2, [2, 3, 2, 6])]
A = abelian_group(Agens)
-# for T in [FPGroup, PcGroup, PermGroup]
- for T in [FPGroup, SubPcGroup, PermGroup]
+ for T in [FPGroup, PcGroup, SubPcGroup, PermGroup]
iso = @inferred isomorphism(T, A)
for x in gens(A), y in gens(A)
z = x+y
@@ -284,14 +280,15 @@ end
end
@testset "Infinite FinGenAbGroup to GAPGroup" begin
- Agens = matrix(ZZ, 2, 2, [2, 3, 0, 0])
- A = abelian_group(Agens)
- for T in [FPGroup]
- iso = @inferred isomorphism(T, A)
- for x in gens(A), y in gens(A)
- z = x+y
- @test iso(x) * iso(y) == iso(z)
- @test all(a -> preimage(iso, iso(a)) == a, [x, y, z])
+ @testset for Agens in [matrix(ZZ, 2, 2, [2, 3, 0, 0]), [6, 0]]
+ A = abelian_group(Agens)
+ for T in [FPGroup, PcGroup]
+ iso = @inferred isomorphism(T, A)
+ for x in gens(A), y in gens(A)
+ z = x+y
+ @test iso(x) * iso(y) == iso(z)
+ @test all(a -> preimage(iso, iso(a)) == a, [x, y, z])
+ end
end
end
end
diff --git a/test/Groups/matrixgroups.jl b/test/Groups/matrixgroups.jl
index 5cc046652da0..bbc14add47e5 100644
--- a/test/Groups/matrixgroups.jl
+++ b/test/Groups/matrixgroups.jl
@@ -622,7 +622,7 @@ end
lc = x*H
@test order(lc)==order(H)
@test representative(lc)==x
- @test acting_domain(lc)==H
+ @test acting_group(lc)==H
@test x in lc
C = centralizer(G,x)[1]
@test order(C)==64
@@ -752,7 +752,7 @@ end
# L = lattice(q, QQ[0 0; 0 0], isbasis=false)
# @test order(isometry_group(L)) == 1
- Qx, x = polynomial_ring(FlintQQ, :x, cached = false)
+ Qx, x = polynomial_ring(QQ, :x, cached = false)
f = x^2-2;
K, a = number_field(f)
D = matrix(K, 3, 3, [2, 0, 0, 0, 1, 0, 0, 0, 7436]);
diff --git a/test/Groups/operations.jl b/test/Groups/operations.jl
index f9b0b23adf0f..63b9666b31de 100644
--- a/test/Groups/operations.jl
+++ b/test/Groups/operations.jl
@@ -50,49 +50,50 @@
end
end
-@testset "Matrix manipulation" begin
- F = GF(5, 1)
-
- I = identity_matrix(F,6)
- x = matrix(F,2,2,[2,3,4,0])
- I1 = deepcopy(I)
- I1[3:4,3:4] = x
- @test I==identity_matrix(F,6)
- I[3:4,3:4] = x
- @test I==I1
- @test I[3:4,3:4]==x
+@testset "Matrix manipulation" for F in (GF(5), GF(5,1))
+
V = vector_space(F,6)
- @test matrix([V[i] for i in 1:6])==identity_matrix(F,6)
+ I = identity_matrix(F,6)
+
+ # test converting a list of vector space elements into a matrix
+ @test matrix([V[i] for i in 1:6]) == I
+
+ # permutation matrix tests
L = [1,4,6,2,3,5]
- P = permutation_matrix(F,L)
- @testset for i in 1:6
- @test V[i]*P == V[L[i]]
- end
p = symmetric_group(6)(L)
- @test permutation_matrix(F,p)==permutation_matrix(F,L)
- @test upper_triangular_matrix(F.([2,3,1,1,0,1]))==matrix(F,3,3,[2,3,1,0,1,0,0,0,1])
- @test lower_triangular_matrix(F.([2,3,1,1,0,1]))==matrix(F,3,3,[2,0,0,3,1,0,1,0,1])
+ @test permutation_matrix(F,p) == permutation_matrix(F,L)
+
+ # upper + lower triangular matrix constructor
+ @test upper_triangular_matrix(F.([1,2,3,4,5,6])) == matrix(F, [1 2 3; 0 4 5; 0 0 6])
+ @test lower_triangular_matrix(F.([2,3,1,1,0,1])) == matrix(F, [2 0 0; 3 1 0; 1 0 1])
@test_throws ArgumentError lower_triangular_matrix(F.([2,3,1,1]))
R,t=polynomial_ring(F,:t)
f = t^4+2*t^3+4*t+1
- @test f(identity_matrix(F,6))==f(1)*identity_matrix(F,6)
- @test_throws ArgumentError conjugate_transpose(x)
+ @test f(I)==f(1)*I
+
+ @test_throws ArgumentError conjugate_transpose(I)
+
+ P = permutation_matrix(F,L)
@test is_symmetric(P+transpose(P))
@test is_skew_symmetric(P-transpose(P))
@test is_alternating(P-transpose(P))
F,z = finite_field(2,2)
- x=matrix(F,4,4,[1,z,0,0,0,1,z^2,z,z,0,0,1,0,0,z+1,0])
+ x=matrix(F,[1 z 0 0; 0 1 z^2 z; z 0 0 1; 0 0 z+1 0])
y=x+transpose(x)
@test is_symmetric(y)
@test is_hermitian(x+conjugate_transpose(x))
@test is_skew_symmetric(y)
@test is_alternating(y)
+ @test conjugate_transpose(conjugate_transpose(x)) == x
+
y[1,1]=1
+ @test is_symmetric(y)
+ @test is_hermitian(x+conjugate_transpose(x))
@test is_skew_symmetric(y)
@test !is_alternating(y)
- @test conjugate_transpose(x)==transpose(matrix(F,4,4,[1,z+1,0,0,0,1,z,z+1,z+1,0,0,1,0,0,z,0]))
+ @test conjugate_transpose(x)==transpose(matrix(F,[1 z+1 0 0; 0 1 z z+1; z+1 0 0 1; 0 0 z 0]))
end
@@ -109,19 +110,10 @@ end
@test complement(V,W0)[1]==V
@test complement(V,sub(V,gens(V))[1])[1]==W0
- v1=V([1,2,3,4,5])
- v2=V([1,6,0,5,2])
G = GL(5,F)
- B=matrix(F,5,5,[1,2,3,1,0,4,5,2,0,1,3,2,5,4,0,1,6,4,3,5,2,0,4,1,1])
+ B = rand(G)
+ v1 = rand(V)
@test v1*B == V([ sum([v1[i]*B[i,j] for i in 1:5]) for j in 1:5 ])
- @test V(transpose(B*v2))==V([ sum([v2[i]*B[j,i] for i in 1:5]) for j in 1:5 ])
- B = G(B)
- @test v1*B == V([ sum([v1[i]*B[i,j] for i in 1:5]) for j in 1:5 ])
- @test V(transpose(B*v2))==V([ sum([v2[i]*B[j,i] for i in 1:5]) for j in 1:5 ])
- @test map(x->x+1,v1)==V([2,3,4,5,6])
-
- # see the discussion of pull/1368 and issues/872
- @test_throws MethodError v1*v2
end
# from file matrices/stuff_field_gen.jl
diff --git a/test/Groups/pcgroup.jl b/test/Groups/pcgroup.jl
index 8ec1f2c3cd3c..983446ed8011 100644
--- a/test/Groups/pcgroup.jl
+++ b/test/Groups/pcgroup.jl
@@ -82,3 +82,13 @@ end
@test GAP.Globals.IsMutable(cgg)
@test cgg !== c.X
end
+
+@testset "create collectors from polycyclic groups" begin
+ for i in rand(1:number_of_small_groups(96), 10)
+ g = small_group(96, i)
+ c = collector(Int64, g)
+ gc = pc_group(c)
+ f = hom(g, gc, gens(gc))
+ @test is_bijective(f)
+ end
+end
diff --git a/test/Groups/subgroups_and_cosets.jl b/test/Groups/subgroups_and_cosets.jl
index abf2fcea09b9..fb51e3a1f881 100644
--- a/test/Groups/subgroups_and_cosets.jl
+++ b/test/Groups/subgroups_and_cosets.jl
@@ -1,29 +1,41 @@
@testset "Subgroups" begin
- G = symmetric_group(7)
- x = cperm(G,[1,2,3,4,5,6,7])
- y = cperm(G,[1,2,3])
- z = cperm(G,[1,2])
-
- H,f=sub(G,[x,y])
- K,g=sub(x,y)
- @test H isa PermGroup
- @test H==alternating_group(7)
- @test domain(f)==H
- @test codomain(f)==G
- @test [f(x) for x in gens(H)]==gens(H)
- @test (H,f)==(K,g)
- @test is_subset(K, G)
- flag, emb = is_subgroup(K, G)
- @test flag
- @test g == emb
- @test g == embedding(K, G)
- @test K === domain(emb)
- @test G === codomain(emb)
- @test is_normal_subgroup(H, G)
- H,f=sub(G,[x,z])
- @test H==G
- @test f==id_hom(G)
+ S = symmetric_group(7)
+ Sx = cperm(S, [1, 2, 3, 4, 5, 6, 7])
+ Sy = cperm(S, [1, 2, 3])
+ Sz = cperm(S, [1, 2])
+
+ for T in [PermGroup, FPGroup]
+ iso = isomorphism(T, S)
+ G = codomain(iso)
+ x = iso(Sx)
+ y = iso(Sy)
+ z = iso(Sz)
+
+ H, f = sub(G, [x, y])
+ K, g = sub(x, y)
+ @test H isa Oscar.sub_type(T)
+ @test domain(f) == H
+ @test codomain(f) == G
+ @test [f(x) for x in gens(H)] == gens(H)
+ @test (H, f) == (K, g)
+ @test is_subset(K, G)
+ flag, emb = is_subgroup(K, G)
+ @test flag
+ @test g == emb
+ @test g == embedding(K, G)
+ @test K === domain(emb)
+ @test G === codomain(emb)
+ @test is_normal_subgroup(H, G)
+ H, f = sub(G, [x, z])
+ @test H == G
+ @test f == id_hom(G)
+ end
+ G = symmetric_group(7)
+ x = cperm(G, [1, 2, 3, 4, 5, 6, 7])
+ y = cperm(G, [1, 2, 3])
+ H, f = sub(G, [x, y])
+ @test H == alternating_group(7)
@test !is_subset(symmetric_group(8), G)
@test_throws ArgumentError embedding(symmetric_group(8), G)
@@ -155,6 +167,10 @@ end
@test index(G, H) == 4
C = right_coset(H, G[1])
+ @test group(C) == G
+ @test acting_group(C) == H
+ @test representative(C) in C
+ @test all(x -> x/G[1] in H, C)
@test is_right(C)
@test order(C) == length(collect(C))
@test order(C) isa ZZRingElem
@@ -185,8 +201,8 @@ end
@test rc==H*x
@test lc==x*H
@test dc==H*x*K
- @test acting_domain(rc) == H
- @test acting_domain(lc) == H
+ @test acting_group(rc) == H
+ @test acting_group(lc) == H
@test left_acting_group(dc) == H
@test right_acting_group(dc) == K
@test representative(rc) == x
@@ -207,6 +223,10 @@ end
@test issubset(left_coset(K,x),dc)
@test !is_bicoset(rc)
+ @inferred GapObj(rc)
+ @inferred GapObj(lc)
+ @inferred GapObj(dc)
+
@test rc == H*x
@test lc == x*H
@test dc == H*x*K
@@ -259,6 +279,7 @@ end
x = G([2,3,4,5,1])
dc = double_coset(H,x,K)
dc1 = double_coset(H, H[1]*x, K)
+ @test group(dc) == G
@test representative(dc) != representative(dc1)
@test dc == dc1
L = double_cosets(G,H,K)
diff --git a/test/Modules/ExteriorPowers.jl b/test/Modules/ExteriorPowers.jl
index 32cf891f4436..25a81d8ee1ce 100644
--- a/test/Modules/ExteriorPowers.jl
+++ b/test/Modules/ExteriorPowers.jl
@@ -130,8 +130,8 @@ end
u = (F[1], F[4], F[3])
@test "$(mm(v))" == "e[1]^e[3]^e[4]"
- #@test "$(F3)" == "⋀^3(Free module of rank 5 over Multivariate polynomial ring in 5 variables over QQ)"
- @test "$(F3)" == "3rd exterior power of Free module of rank 5 over Multivariate polynomial ring in 5 variables over QQ"
+ #@test "$(F3)" == "⋀^3(Free module of rank 5 over multivariate polynomial ring in 5 variables over QQ)"
+ @test "$(F3)" == "3rd exterior power of Free module of rank 5 over multivariate polynomial ring in 5 variables over QQ"
eu = sum(f*e for (f, e) in zip(gens(R), gens(F)))
K = koszul_complex(eu)
diff --git a/test/Modules/ModulesGraded.jl b/test/Modules/ModulesGraded.jl
index 577da99baee1..b352bf66472d 100644
--- a/test/Modules/ModulesGraded.jl
+++ b/test/Modules/ModulesGraded.jl
@@ -1046,37 +1046,94 @@ end
@test degree(phi) == degree(element_to_homomorphism(phi)(v)) - degree(v)
end
-@testset "minimal Betti tables" begin
- # The Veronese surface in IP^4 due to Wolfram
- F = GF(31991)
- R, (x,y,z,u,v) = graded_polynomial_ring(F, [:x, :y, :z, :u, :v])
- I = ideal([F(45)/16*x^3-8565*x^2*y-7937*x*y^2+14060*x^2*z+F(53)/113*x*y*z-F(125)/17*x*z^2-15712*x^2*u-5990*x*y*u-F(71)/88*x*z*u-6141*x*u^2+F(49)/104*x^2*v-194*x*y*v+F(63)/103*y^2*v+F(74)/103*x*z*v+11618*y*z*v+F(41)/111*z^2*v+14387*x*u*v-F(64)/9*y*u*v+13097*z*u*v+F(84)/101*u^2*v+12211*x*v^2+F(85)/63*y*v^2-F(119)/100*z*v^2-6247*u*v^2-F(74)/51*v^3,-F(45)/16*x^2*y+8565*x*y^2+7937*y^3-14060*x*y*z-F(53)/113*y^2*z+F(125)/17*y*z^2+15712*x*y*u+5990*y^2*u+F(71)/88*y*z*u+6141*y*u^2-x^2*v+3340*x*y*v+F(111)/40*y^2*v+F(22)/37*x*z*v-F(110)/29*y*z*v-F(71)/25*z^2*v-F(71)/87*x*u*v+F(112)/55*y*u*v+F(103)/80*z*u*v-F(100)/7*u^2*v-5013*x*v^2+15010*y*v^2+F(52)/51*z*v^2+F(126)/5*u*v^2-6580*v^3,-F(45)/16*x^2*z+8565*x*y*z+7937*y^2*z-14060*x*z^2-F(53)/113*y*z^2+F(125)/17*z^3+15712*x*z*u+5990*y*z*u+F(71)/88*z^2*u+6141*z*u^2+F(41)/79*x^2*v+F(121)/48*x*y*v+9621*y^2*v+F(105)/83*x*z*v+F(27)/26*y*z*v-649*z^2*v-12278*x*u*v+14655*y*u*v+10594*z*u*v+10462*u^2*v+F(76)/13*x*v^2+F(97)/50*y*v^2-7761*z*v^2+F(52)/31*u*v^2-6636*v^3,-F(45)/16*x^2*u+8565*x*y*u+7937*y^2*u-14060*x*z*u-F(53)/113*y*z*u+F(125)/17*z^2*u+15712*x*u^2+5990*y*u^2+F(71)/88*z*u^2+6141*u^3-F(40)/31*x^2*v+13297*x*y*v+F(126)/113*y^2*v-F(51)/100*x*z*v-F(97)/38*y*z*v+10372*z^2*v-F(4)/31*x*u*v+F(32)/9*y*u*v-F(1)/7*z*u*v+15473*u^2*v+F(101)/36*x*v^2+F(97)/109*y*v^2-14100*z*v^2+F(109)/32*u*v^2-F(5)/111*v^3,-F(40)/31*x^3+13297*x^2*y+F(126)/113*x*y^2-F(51)/100*x^2*z-F(97)/38*x*y*z+10372*x*z^2+F(26)/105*x^2*u-3745*x*y*u+F(63)/103*y^2*u-F(98)/61*x*z*u+11618*y*z*u+F(41)/111*z^2*u+F(26)/15*x*u^2-F(64)/9*y*u^2+13097*z*u^2+F(84)/101*u^3+F(101)/36*x^2*v+F(97)/109*x*y*v-14100*x*z*v-14778*x*u*v+F(85)/63*y*u*v-F(119)/100*z*u*v-6247*u^2*v-F(5)/111*x*v^2-F(74)/51*u*v^2,F(40)/31*x^2*y-13297*x*y^2-F(126)/113*y^3+F(51)/100*x*y*z+F(97)/38*y^2*z-10372*y*z^2-x^2*u+F(103)/30*x*y*u+2754*y^2*u+F(22)/37*x*z*u+F(126)/95*y*z*u-F(71)/25*z^2*u-F(71)/87*x*u^2-F(109)/7*y*u^2+F(103)/80*z*u^2-F(100)/7*u^3-F(101)/36*x*y*v-F(97)/109*y^2*v+14100*y*z*v-5013*x*u*v+10008*y*u*v+F(52)/51*z*u*v+F(126)/5*u^2*v+F(5)/111*y*v^2-6580*u*v^2,F(40)/31*x^2*z-13297*x*y*z-F(126)/113*y^2*z+F(51)/100*x*z^2+F(97)/38*y*z^2-10372*z^3+F(41)/79*x^2*u+F(121)/48*x*y*u+9621*y^2*u+5671*x*z*u-F(42)/71*y*z*u-5219*z^2*u-12278*x*u^2+14655*y*u^2+F(58)/59*z*u^2+10462*u^3-F(101)/36*x*z*v-F(97)/109*y*z*v+14100*z^2*v+F(76)/13*x*u*v+F(97)/50*y*u*v-12763*z*u*v+F(52)/31*u^2*v+F(5)/111*z*v^2-6636*u*v^2,F(41)/79*x^3+F(121)/48*x^2*y+9621*x*y^2-F(22)/109*x^2*z+F(25)/19*x*y*z+F(63)/103*y^2*z+F(23)/45*x*z^2+11618*y*z^2+F(41)/111*z^3-12278*x^2*u+14655*x*y*u+F(126)/73*x*z*u-F(64)/9*y*z*u+13097*z^2*u+10462*x*u^2+F(84)/101*z*u^2+F(76)/13*x^2*v+F(97)/50*x*y*v-F(106)/115*x*z*v+F(85)/63*y*z*v-F(119)/100*z^2*v+F(52)/31*x*u*v-6247*z*u*v-6636*x*v^2-F(74)/51*z*v^2,-F(41)/79*x^2*y-F(121)/48*x*y^2-9621*y^3-x^2*z-F(22)/89*x*y*z-F(32)/17*y^2*z+F(22)/37*x*z^2-F(86)/111*y*z^2-F(71)/25*z^3+12278*x*y*u-14655*y^2*u-F(71)/87*x*z*u+F(74)/47*y*z*u+F(103)/80*z^2*u-10462*y*u^2-F(100)/7*z*u^2-F(76)/13*x*y*v-F(97)/50*y^2*v-5013*x*z*v-9220*y*z*v+F(52)/51*z^2*v-F(52)/31*y*u*v+F(126)/5*z*u*v+6636*y*v^2-6580*z*v^2,x^3+11117*x^2*y+991*x*y^2-F(63)/103*y^3-F(22)/37*x^2*z-F(35)/13*x*y*z-11618*y^2*z+F(71)/25*x*z^2-F(41)/111*y*z^2+F(71)/87*x^2*u+F(68)/115*x*y*u+F(64)/9*y^2*u-F(103)/80*x*z*u-13097*y*z*u+F(100)/7*x*u^2-F(84)/101*y*u^2+5013*x^2*v-F(67)/114*x*y*v-F(85)/63*y^2*v-F(52)/51*x*z*v+F(119)/100*y*z*v-F(126)/5*x*u*v+6247*y*u*v+6580*x*v^2+F(74)/51*y*v^2])
- I = ideal(R, minimal_generating_set(I))
- F = graded_free_module(R, 1)
- sub_F, inc = sub(F, [g*F[1] for g in gens(I)])
- M = cokernel(inc)
- A, _ = quo(R, I)
- # To reproduce the string on the right hand side, evaluate
- # `"$(Oscar.minimal_betti_table(M))"`
- # and insert the result here; after verification of the result!
- @test "$(Oscar.minimal_betti_table(A))" == " 0 1 2 3 4\n---------------------\n0 : 1 - - - -\n1 : - - - - -\n2 : - 7 10 5 1\n---------------------\ntotal: 1 7 10 5 1"
-
- @test "$(Oscar.minimal_betti_table(M))" == " 0 1 2 3 4\n---------------------\n0 : 1 - - - -\n1 : - - - - -\n2 : - 7 10 5 1\n---------------------\ntotal: 1 7 10 5 1"
-
- @test "$(Oscar.minimal_betti_table(I))" == "$(Oscar.minimal_betti_table(sub_F))"
-
- # small example due to Janko
- R, x = graded_polynomial_ring(QQ, :x => 1:7)
- I = ideal(R, [x[1]*x[2]*x[5], x[1]*x[2]*x[6], x[3]*x[4]*x[6], x[3]*x[4]*x[7], x[5]*x[7]])
- A, _ = quo(R, I)
- @test "$(Oscar.minimal_betti_table(A))" == " 0 1 2 3\n-----------------\n0 : 1 - - -\n1 : - 1 - -\n2 : - 4 4 -\n3 : - - 1 -\n4 : - - - 1\n-----------------\ntotal: 1 5 5 1"
-
- # another example due to Wolfram
- R, (x, y, z, w) = graded_polynomial_ring(QQ, [:x, :y, :z, :w])
- I = ideal(R, [w^2 - x*z, w*x - y*z, x^2 - w*y, x*y - z^2, y^2 - w*z])
- A, _ = quo(R, I)
- @test "$(Oscar.minimal_betti_table(free_resolution(A)))" == " 0 1 2 3\n-----------------\n0 : 1 - - -\n1 : - 5 5 -\n2 : - - - 1\n-----------------\ntotal: 1 5 5 1"
-end
+Oscar.@_AuxDocTest "minimal Betti tables", (fix = false),
+raw"""
+# The Veronese surface in IP^4 due to Wolfram
+
+```jldoctest; setup = :(using Oscar)
+julia> F = GF(31991)
+Prime field of characteristic 31991
+
+julia> R, (x,y,z,u,v) = graded_polynomial_ring(F, [:x, :y, :z, :u, :v]);
+
+julia> I = ideal([F(45)/16*x^3-8565*x^2*y-7937*x*y^2+14060*x^2*z+F(53)/113*x*y*z-F(125)/17*x*z^2-15712*x^2*u-5990*x*y*u-F(71)/88*x*z*u-6141*x*u^2+F(49)/104*x^2*v-194*x*y*v+F(63)/103*y^2*v+F(74)/103*x*z*v+11618*y*z*v+F(41)/111*z^2*v+14387*x*u*v-F(64)/9*y*u*v+13097*z*u*v+F(84)/101*u^2*v+12211*x*v^2+F(85)/63*y*v^2-F(119)/100*z*v^2-6247*u*v^2-F(74)/51*v^3,-F(45)/16*x^2*y+8565*x*y^2+7937*y^3-14060*x*y*z-F(53)/113*y^2*z+F(125)/17*y*z^2+15712*x*y*u+5990*y^2*u+F(71)/88*y*z*u+6141*y*u^2-x^2*v+3340*x*y*v+F(111)/40*y^2*v+F(22)/37*x*z*v-F(110)/29*y*z*v-F(71)/25*z^2*v-F(71)/87*x*u*v+F(112)/55*y*u*v+F(103)/80*z*u*v-F(100)/7*u^2*v-5013*x*v^2+15010*y*v^2+F(52)/51*z*v^2+F(126)/5*u*v^2-6580*v^3,-F(45)/16*x^2*z+8565*x*y*z+7937*y^2*z-14060*x*z^2-F(53)/113*y*z^2+F(125)/17*z^3+15712*x*z*u+5990*y*z*u+F(71)/88*z^2*u+6141*z*u^2+F(41)/79*x^2*v+F(121)/48*x*y*v+9621*y^2*v+F(105)/83*x*z*v+F(27)/26*y*z*v-649*z^2*v-12278*x*u*v+14655*y*u*v+10594*z*u*v+10462*u^2*v+F(76)/13*x*v^2+F(97)/50*y*v^2-7761*z*v^2+F(52)/31*u*v^2-6636*v^3,-F(45)/16*x^2*u+8565*x*y*u+7937*y^2*u-14060*x*z*u-F(53)/113*y*z*u+F(125)/17*z^2*u+15712*x*u^2+5990*y*u^2+F(71)/88*z*u^2+6141*u^3-F(40)/31*x^2*v+13297*x*y*v+F(126)/113*y^2*v-F(51)/100*x*z*v-F(97)/38*y*z*v+10372*z^2*v-F(4)/31*x*u*v+F(32)/9*y*u*v-F(1)/7*z*u*v+15473*u^2*v+F(101)/36*x*v^2+F(97)/109*y*v^2-14100*z*v^2+F(109)/32*u*v^2-F(5)/111*v^3,-F(40)/31*x^3+13297*x^2*y+F(126)/113*x*y^2-F(51)/100*x^2*z-F(97)/38*x*y*z+10372*x*z^2+F(26)/105*x^2*u-3745*x*y*u+F(63)/103*y^2*u-F(98)/61*x*z*u+11618*y*z*u+F(41)/111*z^2*u+F(26)/15*x*u^2-F(64)/9*y*u^2+13097*z*u^2+F(84)/101*u^3+F(101)/36*x^2*v+F(97)/109*x*y*v-14100*x*z*v-14778*x*u*v+F(85)/63*y*u*v-F(119)/100*z*u*v-6247*u^2*v-F(5)/111*x*v^2-F(74)/51*u*v^2,F(40)/31*x^2*y-13297*x*y^2-F(126)/113*y^3+F(51)/100*x*y*z+F(97)/38*y^2*z-10372*y*z^2-x^2*u+F(103)/30*x*y*u+2754*y^2*u+F(22)/37*x*z*u+F(126)/95*y*z*u-F(71)/25*z^2*u-F(71)/87*x*u^2-F(109)/7*y*u^2+F(103)/80*z*u^2-F(100)/7*u^3-F(101)/36*x*y*v-F(97)/109*y^2*v+14100*y*z*v-5013*x*u*v+10008*y*u*v+F(52)/51*z*u*v+F(126)/5*u^2*v+F(5)/111*y*v^2-6580*u*v^2,F(40)/31*x^2*z-13297*x*y*z-F(126)/113*y^2*z+F(51)/100*x*z^2+F(97)/38*y*z^2-10372*z^3+F(41)/79*x^2*u+F(121)/48*x*y*u+9621*y^2*u+5671*x*z*u-F(42)/71*y*z*u-5219*z^2*u-12278*x*u^2+14655*y*u^2+F(58)/59*z*u^2+10462*u^3-F(101)/36*x*z*v-F(97)/109*y*z*v+14100*z^2*v+F(76)/13*x*u*v+F(97)/50*y*u*v-12763*z*u*v+F(52)/31*u^2*v+F(5)/111*z*v^2-6636*u*v^2,F(41)/79*x^3+F(121)/48*x^2*y+9621*x*y^2-F(22)/109*x^2*z+F(25)/19*x*y*z+F(63)/103*y^2*z+F(23)/45*x*z^2+11618*y*z^2+F(41)/111*z^3-12278*x^2*u+14655*x*y*u+F(126)/73*x*z*u-F(64)/9*y*z*u+13097*z^2*u+10462*x*u^2+F(84)/101*z*u^2+F(76)/13*x^2*v+F(97)/50*x*y*v-F(106)/115*x*z*v+F(85)/63*y*z*v-F(119)/100*z^2*v+F(52)/31*x*u*v-6247*z*u*v-6636*x*v^2-F(74)/51*z*v^2,-F(41)/79*x^2*y-F(121)/48*x*y^2-9621*y^3-x^2*z-F(22)/89*x*y*z-F(32)/17*y^2*z+F(22)/37*x*z^2-F(86)/111*y*z^2-F(71)/25*z^3+12278*x*y*u-14655*y^2*u-F(71)/87*x*z*u+F(74)/47*y*z*u+F(103)/80*z^2*u-10462*y*u^2-F(100)/7*z*u^2-F(76)/13*x*y*v-F(97)/50*y^2*v-5013*x*z*v-9220*y*z*v+F(52)/51*z^2*v-F(52)/31*y*u*v+F(126)/5*z*u*v+6636*y*v^2-6580*z*v^2,x^3+11117*x^2*y+991*x*y^2-F(63)/103*y^3-F(22)/37*x^2*z-F(35)/13*x*y*z-11618*y^2*z+F(71)/25*x*z^2-F(41)/111*y*z^2+F(71)/87*x^2*u+F(68)/115*x*y*u+F(64)/9*y^2*u-F(103)/80*x*z*u-13097*y*z*u+F(100)/7*x*u^2-F(84)/101*y*u^2+5013*x^2*v-F(67)/114*x*y*v-F(85)/63*y^2*v-F(52)/51*x*z*v+F(119)/100*y*z*v-F(126)/5*x*u*v+6247*y*u*v+6580*x*v^2+F(74)/51*y*v^2]);
+
+julia> I = ideal(R, minimal_generating_set(I));
+
+julia> F = graded_free_module(R, 1);
+
+julia> sub_F, inc = sub(F, [g*F[1] for g in gens(I)]);
+
+julia> M = cokernel(inc);
+
+julia> A, _ = quo(R, I);
+
+julia> minimal_betti_table(A)
+degree: 0 1 2 3 4
+----------------------
+ 0: 1 - - - -
+ 1: - - - - -
+ 2: - 7 10 5 1
+----------------------
+ total: 1 7 10 5 1
+
+julia> minimal_betti_table(M)
+degree: 0 1 2 3 4
+----------------------
+ 0: 1 - - - -
+ 1: - - - - -
+ 2: - 7 10 5 1
+----------------------
+ total: 1 7 10 5 1
+
+julia> minimal_betti_table(I)
+degree: 0 1 2 3
+-------------------
+ 3: 7 10 5 1
+-------------------
+ total: 7 10 5 1
+```
+
+# small example due to Janko
+
+```jldoctest; setup = :(using Oscar)
+julia> R, x = graded_polynomial_ring(QQ, :x => 1:7);
+
+julia> I = ideal(R, [x[1]*x[2]*x[5], x[1]*x[2]*x[6], x[3]*x[4]*x[6], x[3]*x[4]*x[7], x[5]*x[7]]);
+
+julia> A, _ = quo(R, I);
+
+julia> minimal_betti_table(A)
+degree: 0 1 2 3
+------------------
+ 0: 1 - - -
+ 1: - 1 - -
+ 2: - 4 4 -
+ 3: - - 1 -
+ 4: - - - 1
+------------------
+ total: 1 5 5 1
+```
+
+# another example due to Wolfram
+
+```jldoctest; setup = :(using Oscar)
+julia> R, (x, y, z, w) = graded_polynomial_ring(QQ, [:x, :y, :z, :w]);
+
+julia> I = ideal(R, [w^2 - x*z, w*x - y*z, x^2 - w*y, x*y - z^2, y^2 - w*z]);
+
+julia> A, _ = quo(R, I);
+
+julia> minimal_betti_table(free_resolution(A))
+degree: 0 1 2 3
+------------------
+ 0: 1 - - -
+ 1: - 5 5 -
+ 2: - - - 1
+------------------
+ total: 1 5 5 1
+```
+"""
@testset "sheaf cohomology" begin
S, _ = graded_polynomial_ring(QQ, :x => 1:4)
@@ -1264,9 +1321,3 @@ end
ideal_as_module(J)
quotient_ring_as_module(J)
end
-
-
-
-
-
-
diff --git a/test/NumberTheory/nmbthy.jl b/test/NumberTheory/nmbthy.jl
index f4e628df5ccc..bc6790ac17a3 100644
--- a/test/NumberTheory/nmbthy.jl
+++ b/test/NumberTheory/nmbthy.jl
@@ -4,7 +4,8 @@ using Test
function evalu(x::Fac)
return x.unit * prod(p*k for (p,k) = x.fac)
end
-@testset "Polymake.factorizations" begin
+
+@testset "factorizations" begin
k, a = quadratic_field(-5)
zk = maximal_order(k)
f = factorizations(zk(6))
@@ -12,7 +13,7 @@ end
@test all(x -> evalu(x) == 6, f)
end
-@testset "Polymake.norm_equation" begin
+@testset "norm_equation.absolute" begin
k, a = wildanger_field(3, 13)
zk = maximal_order(k)
na = norm(rand(zk, 1:10))
@@ -20,6 +21,18 @@ end
@test all(x->norm(x) == na, s)
end
+@testset "norm_equation.relative" begin
+ L, _ = quadratic_field(-1)
+ _, x = L[:x]
+ f = x^3 - 2;
+ k, _ = number_field(f)
+
+ zk = maximal_order(k)
+ na = norm(rand(zk, 10))
+ s = norm_equation(zk, na)
+ @test all(x->norm(x) == na, s)
+end
+
@testset "DiscreteLog" begin
F = GF(3,4);
diff --git a/test/PolyhedralGeometry/cone.jl b/test/PolyhedralGeometry/cone.jl
index 780870c10d2a..8adcfc125b94 100644
--- a/test/PolyhedralGeometry/cone.jl
+++ b/test/PolyhedralGeometry/cone.jl
@@ -28,43 +28,38 @@
if T == QQFieldElem
@test hilbert_basis(Cone1) isa SubObjectIterator{PointVector{ZZRingElem}}
@test length(hilbert_basis(Cone1)) == 2
- @test hilbert_basis(Cone1) == [[1, 0], [0, 1]]
- @test generator_matrix(hilbert_basis(Cone1)) == matrix(QQ, [1 0; 0 1])
+ @test issetequal(hilbert_basis(Cone1), ray_vector.(Ref(ZZ), [[1, 0], [0, 1]]))
+ @test generator_matrix(hilbert_basis(Cone1)) == _oscar_matrix_from_property(ZZ, hilbert_basis(Cone1))
end
@test n_rays(Cone1) == 2
@test rays(RayVector{T}, Cone1) isa SubObjectIterator{RayVector{T}}
@test rays(Cone1) isa SubObjectIterator{RayVector{T}}
@test rays(RayVector, Cone1) isa SubObjectIterator{RayVector{T}}
- @test vector_matrix(rays(Cone1)) == matrix(f, [1 0; 0 1])
+ @test issetequal(rays(Cone1), ray_vector.(Ref(f), [[1, 0], [0, 1]]))
+ @test vector_matrix(rays(Cone1)) == _oscar_matrix_from_property(f, rays(Cone1))
if T == QQFieldElem
- @test matrix(QQ, rays(Cone1)) == matrix(QQ, [1 0; 0 1])
- @test matrix(ZZ, rays(Cone6)) == matrix(ZZ, [2 3; 2 5])
+ @test matrix(QQ, rays(Cone1)) == _oscar_matrix_from_property(f, rays(Cone1))
+ let r = rays(Cone6)
+ m = matrix(ZZ, r[1] == [1//3, 1//2] ? [2 3; 2 5] : [2 5; 2 3])
+ @test matrix(ZZ, rays(Cone6)) == m
+ end
end
@test length(rays(Cone1)) == 2
- @test rays(Cone1) == [[1, 0], [0, 1]]
- for S in [LinearHalfspace{T}, Cone{T}]
+ for S in [LinearHalfspace{T},
+ Cone{T}]
@test facets(S, Cone1) isa SubObjectIterator{S}
@test length(facets(S, Cone1)) == 2
- if T == QQFieldElem
- @test linear_inequality_matrix(facets(S, Cone1)) == matrix(QQ, [-1 0; 0 -1])
- @test Oscar.linear_matrix_for_polymake(facets(S, Cone1)) == [-1 0; 0 -1]
- @test ray_indices(facets(S, Cone1)) == IncidenceMatrix([[2], [1]])
- @test IncidenceMatrix(facets(S, Cone1)) == IncidenceMatrix([[2], [1]])
- if S == LinearHalfspace{T}
- @test facets(S, Cone1) == linear_halfspace.([f], [[-1, 0], [0, -1]])
- end
+ if S == LinearHalfspace{T}
+ @test issetequal(facets(S, Cone1), linear_halfspace.(Ref(f), [[-1, 0], [0, -1]]))
else
- @test linear_inequality_matrix(facets(S, Cone1)) == matrix(f, [0 -1; -1 0])
- @test Oscar.linear_matrix_for_polymake(facets(S, Cone1)) == [0 -1; -1 0]
- @test ray_indices(facets(S, Cone1)) == IncidenceMatrix([[1], [2]])
- @test IncidenceMatrix(facets(S, Cone1)) == IncidenceMatrix([[1], [2]])
- if S == LinearHalfspace{T}
- @test facets(S, Cone1) == linear_halfspace.([f], [[0, -1], [-1, 0]])
- end
+ @test issetequal(facets(S, Cone1), positive_hull.(Ref(f), [[1 0], [0 1]]))
end
+ @test linear_inequality_matrix(facets(S, Cone1)) == _oscar_matrix_from_property(f, facets(S, Cone1))
+ @test Oscar.linear_matrix_for_polymake(facets(S, Cone1)) == _polymake_matrix_from_property(facets(S, Cone1))
+ @test _check_im_perm_rows(ray_indices(facets(S, Cone1)), [[1], [2]])
+ @test _check_im_perm_rows(incidence_matrix(facets(S, Cone1)), [[1], [2]])
end
- @test facets(IncidenceMatrix, Cone1) ==
- IncidenceMatrix(T == QQFieldElem ? [[2], [1]] : [[1], [2]])
+ @test _check_im_perm_rows(facets(IncidenceMatrix, Cone1), [[1], [2]])
@test facets(Halfspace, Cone1) isa SubObjectIterator{LinearHalfspace{T}}
@test facets(Cone1) isa SubObjectIterator{LinearHalfspace{T}}
@test linear_span(Cone4) isa SubObjectIterator{LinearHyperplane{T}}
@@ -92,43 +87,32 @@
end
@test length(lineality_space(Cone2)) == 1
@test lineality_space(Cone2) == [L[1, :]]
- @test vector_matrix(rays(Cone4)) == matrix(f, R)
+ @test vector_matrix(rays(Cone4)) == _oscar_matrix_from_property(f, rays(Cone4))
@test codim(Cone4) == 1
@test codim(Cone3) == 0
@test faces(Cone2, 2) isa SubObjectIterator{Cone{T}}
@test length(faces(Cone2, 2)) == 2
@test faces(Cone4, 1) isa SubObjectIterator{Cone{T}}
@test length(faces(Cone4, 1)) == 2
- if T == QQFieldElem
- @test faces(Cone2, 2) == positive_hull.(T, [[0 0 1], [1 0 0]], [[0 1 0]])
- @test ray_indices(faces(Cone2, 2)) == IncidenceMatrix([[2], [1]])
- @test IncidenceMatrix(faces(Cone2, 2)) == IncidenceMatrix([[2], [1]])
- @test faces(IncidenceMatrix, Cone2, 2) == IncidenceMatrix([[2], [1]])
- @test faces(Cone4, 1) == positive_hull.(T, [[0 0 1], [1 0 0]])
- @test ray_indices(faces(Cone4, 1)) == IncidenceMatrix([[2], [1]])
- @test IncidenceMatrix(faces(Cone4, 1)) == IncidenceMatrix([[2], [1]])
- @test faces(IncidenceMatrix, Cone4, 1) == IncidenceMatrix([[2], [1]])
- else
- @test faces(Cone2, 2) == positive_hull.([f], [[1 0 0], [0 0 1]], [[0 1 0]])
- @test ray_indices(faces(Cone2, 2)) == IncidenceMatrix([[1], [2]])
- @test IncidenceMatrix(faces(Cone2, 2)) == IncidenceMatrix([[1], [2]])
- @test faces(IncidenceMatrix, Cone2, 2) == IncidenceMatrix([[1], [2]])
- @test faces(Cone4, 1) == positive_hull.([f], [[1 0 0], [0 0 1]])
- @test ray_indices(faces(Cone4, 1)) == IncidenceMatrix([[1], [2]])
- @test IncidenceMatrix(faces(Cone4, 1)) == IncidenceMatrix([[1], [2]])
- @test faces(IncidenceMatrix, Cone4, 1) == IncidenceMatrix([[1], [2]])
- end
- @test IncidenceMatrix(faces(Cone5, 1)) == IncidenceMatrix([[1], [2], [3], [4]])
+ @test issetequal(faces(Cone2, 2), positive_hull.(Ref(f), [[1 0 0], [0 0 1]], [[0 1 0]]))
+ @test _check_im_perm_rows(ray_indices(faces(Cone2, 2)), [[1], [2]])
+ @test _check_im_perm_rows(incidence_matrix(faces(Cone2, 2)), [[1], [2]])
+ @test _check_im_perm_rows(faces(IncidenceMatrix, Cone2, 2), [[1], [2]])
+ @test issetequal(faces(Cone4, 1), positive_hull.(Ref(f), [[0 0 1], [1 0 0]]))
+ @test _check_im_perm_rows(ray_indices(faces(Cone4, 1)), [[1], [2]])
+ @test _check_im_perm_rows(incidence_matrix(faces(Cone4, 1)), [[1], [2]])
+ @test _check_im_perm_rows(faces(IncidenceMatrix, Cone4, 1), [[1], [2]])
+ @test _check_im_perm_rows(incidence_matrix(faces(Cone5, 1)), [[1], [2], [3], [4]])
@test isnothing(faces(Cone2, 1))
@test f_vector(Cone5) == [4, 4]
@test f_vector(Cone2) == [0, 2]
@test lineality_dim(Cone5) == 0
@test lineality_dim(Cone2) == 1
- @test facet_degrees(Cone5)[1] == 2
- @test facet_degrees(Cone6)[1] == 1
- @test ray_degrees(Cone5)[1] == 2
- @test ray_degrees(Cone6)[1] == 1
+ @test facet_degrees(Cone5) == fill(2, 4)
+ @test facet_degrees(Cone6) == fill(1, 2)
+ @test ray_degrees(Cone5) == fill(2, 4)
+ @test ray_degrees(Cone6) == fill(1, 2)
@test n_facets(Cone5) == 4
@test relative_interior_point(Cone1) == f.([1//2, 1//2])
diff --git a/test/PolyhedralGeometry/extended.jl b/test/PolyhedralGeometry/extended.jl
index 2fcea73e3aca..c7fc6ee058a6 100644
--- a/test/PolyhedralGeometry/extended.jl
+++ b/test/PolyhedralGeometry/extended.jl
@@ -83,29 +83,25 @@
f = sum([x; 1])^2 + x[1]^4 * x[2] * 3
newt = newton_polytope(f)
@test dim(newt) == 2
- @test point_matrix(vertices(newt)) == matrix(QQ, [4 1; 2 0; 0 2; 0 0])
+ @test issetequal(vertices(newt), point_vector.(Ref(QQ), [[4, 1], [2, 0], [0, 2], [0, 0]]))
end
@testset "Construct from QQFieldElem" begin
A = zeros(Oscar.QQ, 3, 2)
A[1, 1] = 1
A[3, 2] = 4
- @test point_matrix(vertices(convex_hull(A))) == matrix(QQ, [1 0; 0 0; 0 4])
+ @test issetequal(vertices(convex_hull(A)), point_vector.(Ref(QQ), [[1, 0], [0, 0], [0, 4]]))
- lhs, rhs = halfspace_matrix_pair(facets(polyhedron(A, [1, 2, -3])))
- @test lhs == matrix(QQ, [1 0; 0 4])
- @test rhs == [1, -3]
+ @test issetequal(facets(polyhedron(A, [1, 2, -3])), [affine_halfspace(QQ, [1, 0], 1), affine_halfspace(QQ, [0, 4], -3)])
end
@testset "Construct from ZZRingElem" begin
A = zeros(Oscar.ZZ, 3, 2)
A[1, 1] = 1
A[3, 2] = 4
- @test point_matrix(vertices(convex_hull(A))) == matrix(QQ, [1 0; 0 0; 0 4])
+ @test issetequal(vertices(convex_hull(A)), point_vector.(Ref(QQ), [[1, 0], [0, 0], [0, 4]]))
- lhs, rhs = halfspace_matrix_pair(facets(polyhedron(A, [1, 2, -3])))
- @test lhs == matrix(QQ, [1 0; 0 4])
- @test rhs == [1, -3]
+ @test issetequal(facets(polyhedron(A, [1, 2, -3])), [affine_halfspace(QQ, [1, 0], 1), affine_halfspace(QQ, [0, 4], -3)])
end
@testset "SubObjectIterator/Matrix compatibility" begin
@@ -199,8 +195,8 @@
@test_throws ArgumentError convex_hull(vertices(Pos_poly), collect(vertices(Pos_poly)))
@test_throws ArgumentError positive_hull(collect(vertices(Pos_poly)))
- @test_throws ArgumentError IncidenceMatrix(lineality_space(Pos_poly))
- IM = IncidenceMatrix([[1]])
+ @test_throws ArgumentError incidence_matrix(lineality_space(Pos_poly))
+ IM = incidence_matrix([[1]])
lincone = positive_hull([1 0 0], [0 1 0])
@test positive_hull(rays_modulo_lineality(lincone)...) == lincone
diff --git a/test/PolyhedralGeometry/group.jl b/test/PolyhedralGeometry/group.jl
index a0945be71ea9..e749e1c87b1b 100644
--- a/test/PolyhedralGeometry/group.jl
+++ b/test/PolyhedralGeometry/group.jl
@@ -45,7 +45,7 @@
M = matroid_from_nonbases([[1, 2, 3, 4], [1, 2, 5, 6], [1, 3, 5, 7], [3, 4, 6, 8]], 8)
GM = automorphism_group(M)
@test is_trivial(GM)
- IM = IncidenceMatrix(bases(M))
+ IM = incidence_matrix(bases(M))
GIM = automorphism_group(IM)
@test length(GIM) == 2
@test haskey(GIM, :on_cols)
diff --git a/test/PolyhedralGeometry/lineality.jl b/test/PolyhedralGeometry/lineality.jl
index 4b76e87430ec..abdf1280b44c 100644
--- a/test/PolyhedralGeometry/lineality.jl
+++ b/test/PolyhedralGeometry/lineality.jl
@@ -82,7 +82,7 @@
@testset "PolyhedralComplex" begin
VR = [0 0 0; 1 0 0; 0 1 0; -1 0 0]
- IM = IncidenceMatrix([[1, 2, 3], [1, 3, 4]])
+ IM = incidence_matrix([[1, 2, 3], [1, 3, 4]])
far_vertices = [2, 3, 4]
L = [0 0 1]
PC = polyhedral_complex(IM, VR, far_vertices, L)
diff --git a/test/PolyhedralGeometry/polyhedral_complex.jl b/test/PolyhedralGeometry/polyhedral_complex.jl
index 821eb959d87c..605ca05a1da6 100644
--- a/test/PolyhedralGeometry/polyhedral_complex.jl
+++ b/test/PolyhedralGeometry/polyhedral_complex.jl
@@ -1,5 +1,5 @@
@testset "PolyhedralComplex{$T}" for (f, T) in _prepare_scalar_types()
- I = IncidenceMatrix([[1, 2, 3], [2, 4]])
+ I = incidence_matrix([[1, 2, 3], [2, 4]])
P = f.([0 0; 1 0; 0 1; 1 1])
P2 = f.([0 0 0; 1 0 0; 0 1 0; 1 1 0])
F = [4]
@@ -34,44 +34,36 @@
# test constructor with re-arranged arguments
let PCF2 = polyhedral_complex(f, -P[1:3, :], I[:, 1:3], -P[4:4, :], I[:, 4:4])
- @test vertices(PCF) == vertices(PCF2)
- @test rays(PCF) == rays(PCF2)
- @test IncidenceMatrix(maximal_polyhedra(PCF)) ==
- IncidenceMatrix(maximal_polyhedra(PCF2))
+ @test issetequal(vertices(PCF), vertices(PCF2))
+ @test issetequal(rays(PCF), rays(PCF2))
+ @test issetequal(maximal_polyhedra(PCF), maximal_polyhedra(PCF2))
end
@testset "core functionality" begin
@test ambient_dim(PC) == 2
@test vertices(PC) isa SubObjectIterator{PointVector{T}}
@test length(vertices(PC)) == 4
- @test point_matrix(vertices(PC)) == matrix(f, P)
- @test vertices(PC) == [[0, 0], [1, 0], [0, 1], [1, 1]]
+ @test issetequal(vertices(PC), point_vector.(Ref(f), [[0, 0], [1, 0], [0, 1], [1, 1]]))
+ @test point_matrix(vertices(PC)) == _oscar_matrix_from_property(f, vertices(PC))
@test rays(PCF) isa SubObjectIterator{RayVector{T}}
@test length(rays(PCF)) == 1
@test rays(PCF) == [[-1, -1]]
@test vector_matrix(rays(PCF)) == matrix(f, [-1 -1])
@test vertices_and_rays(PCFL) isa SubObjectIterator{Union{RayVector{T},PointVector{T}}}
@test length(vertices_and_rays(PCFL)) == 4
- @test vertices_and_rays(PCFL) == [[0, 0, 0], [1, 0, 0], [0, 1, 0], [1, 1, 0]]
- @test typeof.(vertices_and_rays(PCFL)) ==
- [PointVector{T}, PointVector{T}, PointVector{T}, RayVector{T}]
- @test vector_matrix(vertices_and_rays(PCFL)) == matrix(f, P2)
+ @test issetequal(vertices_and_rays(PCFL), [point_vector(f, [0, 0, 0]), point_vector(f, [1, 0, 0]), point_vector(f, [0, 1, 0]), ray_vector(f, [1, 1, 0])])
+ @test vector_matrix(vertices_and_rays(PCFL)) == _oscar_matrix_from_property(f, vertices_and_rays(PCFL))
@test maximal_polyhedra(PC) isa SubObjectIterator{Polyhedron{T}}
@test length(maximal_polyhedra(PC)) == 2
- @test maximal_polyhedra(PC) == convex_hull.([f], [P[1:3, :], P[[2, 4], :]])
+ @test issetequal(maximal_polyhedra(PC), convex_hull.([f], [P[1:3, :], P[[2, 4], :]]))
@test number_of_maximal_polyhedra(PC) == 2
@test is_simplicial(PC)
@test !is_pure(PCL)
@test dim(PCL) == 3
@test polyhedra_of_dim(PC, 1) isa SubObjectIterator{Polyhedron{T}}
@test length(polyhedra_of_dim(PC, 1)) == 4
- if T == QQFieldElem
- @test polyhedra_of_dim(PC, 1) ==
- convex_hull.(T, [P[[2, 4], :], P[[1, 3], :], P[[1, 2], :], P[[2, 3], :]])
- else
- @test polyhedra_of_dim(PC, 1) ==
- convex_hull.([f], [P[[2, 4], :], P[[1, 3], :], P[[2, 3], :], P[[1, 2], :]])
- end
+ @test issetequal(polyhedra_of_dim(PC, 1),
+ convex_hull.(Ref(f), [P[[2, 4], :], P[[1, 3], :], P[[2, 3], :], P[[1, 2], :]]))
@test lineality_space(PCL) isa SubObjectIterator{RayVector{T}}
@test length(lineality_space(PCL)) == 1
@test lineality_space(PCL) == [L[:]]
@@ -94,7 +86,7 @@
@test vertex_indices(maximal_polyhedra(PCFLN)) == I[:, 1:3]
@test ray_indices(maximal_polyhedra(PCFLN)) == I[:, 4:4]
@test vertex_and_ray_indices(maximal_polyhedra(PCFLN)) == I
- @test IncidenceMatrix(maximal_polyhedra(PCFLN)) == I
+ @test incidence_matrix(maximal_polyhedra(PCFLN)) == I
@test maximal_polyhedra(IncidenceMatrix, PCFLN) == I
@test polyhedral_complex(maximal_polyhedra(PCF)) isa PolyhedralComplex
@@ -117,7 +109,7 @@
@testset "Fan conversion" begin
F1 = normal_fan(cube(f, 2))
F2 = normal_fan(convex_hull(f, [0 0; 1 0]))
- IM = IncidenceMatrix([[1, 2], [2, 3], [4]])
+ IM = incidence_matrix([[1, 2], [2, 3], [4]])
R = [0 1 0; 0 0 1; 0 -1 0; 0 -1 -1]
F3 = polyhedral_fan(f, IM, R, [1 0 0])
for F in [F1, F2, F3]
@@ -125,7 +117,7 @@
@test dim(F) == dim(PC)
@test ambient_dim(F) == ambient_dim(PC)
@test lineality_dim(F) == lineality_dim(PC)
- @test matrix(f, rays(F)) == matrix(f, rays(PC))
+ @test issetequal(rays(F), rays(PC))
@test n_maximal_cones(F) == n_maximal_polyhedra(PC)
vrep = PolyhedralComplex{T}(
Polymake.fan.PolyhedralComplex(;
diff --git a/test/PolyhedralGeometry/polyhedral_fan.jl b/test/PolyhedralGeometry/polyhedral_fan.jl
index 8e1c02e3f081..30aa437e5bb6 100644
--- a/test/PolyhedralGeometry/polyhedral_fan.jl
+++ b/test/PolyhedralGeometry/polyhedral_fan.jl
@@ -10,8 +10,8 @@
@test polyhedral_fan([Cone4, Cone5]) isa PolyhedralFan{T}
F0 = polyhedral_fan([Cone4, Cone5])
I3 = [1 0 0; 0 1 0; 0 0 1]
- incidence1 = IncidenceMatrix([[1, 2], [2, 3]])
- incidence2 = IncidenceMatrix([[1, 2]])
+ incidence1 = incidence_matrix([[1, 2], [2, 3]])
+ incidence2 = incidence_matrix([[1, 2]])
@test polyhedral_fan(f, incidence1, I3) isa PolyhedralFan{T}
F1 = polyhedral_fan(f, incidence1, I3)
F1NR = polyhedral_fan(f, incidence1, I3; non_redundant=true)
@@ -28,10 +28,10 @@
if T == QQFieldElem
@test is_smooth(NFsquare)
end
- @test vector_matrix(rays(NFsquare)) == matrix(f, [1 0; -1 0; 0 1; 0 -1])
@test rays(NFsquare) isa SubObjectIterator{RayVector{T}}
@test length(rays(NFsquare)) == 4
- @test rays(NFsquare) == [[1, 0], [-1, 0], [0, 1], [0, -1]]
+ @test issetequal(rays(NFsquare), ray_vector.(Ref(f), [[1, 0], [-1, 0], [0, 1], [0, -1]]))
+ @test vector_matrix(rays(NFsquare)) == _oscar_matrix_from_property(f, rays(NFsquare))
@test is_regular(NFsquare)
@test is_complete(NFsquare)
@test !is_complete(F0)
@@ -45,25 +45,30 @@
@test length(RMLF2[:rays_modulo_lineality]) == 2
@test maximal_cones(F1) isa SubObjectIterator{Cone{T}}
@test dim.(maximal_cones(F1)) == [2, 2]
- @test ray_indices(maximal_cones(F1)) == incidence1
- @test IncidenceMatrix(maximal_cones(F1)) == incidence1
- @test maximal_cones(IncidenceMatrix, F1) == incidence1
+ @test _check_im_perm_rows(ray_indices(maximal_cones(F1)), incidence1)
+ @test _check_im_perm_rows(incidence_matrix(maximal_cones(F1)), incidence1)
+ @test _check_im_perm_rows(maximal_cones(IncidenceMatrix, F1), incidence1)
@test number_of_maximal_cones(F1) == 2
@test lineality_space(F2) isa SubObjectIterator{RayVector{T}}
- @test generator_matrix(lineality_space(F2)) == matrix(f, L)
- if T == QQFieldElem
- @test matrix(QQ, lineality_space(F2)) == matrix(QQ, L)
- end
@test length(lineality_space(F2)) == 1
@test lineality_space(F2) == [L[:]]
+ @test generator_matrix(lineality_space(F2)) == matrix(f, L)
+ @test matrix(f, lineality_space(F2)) == matrix(f, L)
@test cones(F2, 2) isa SubObjectIterator{Cone{T}}
@test size(cones(F2, 2)) == (2,)
@test lineality_space(cones(F2, 2)[1]) == [[0, 1, 0]]
@test rays.(cones(F2, 2)) == [[], []]
- @test isnothing(cones(F2, 1))
- @test ray_indices(cones(F1, 2)) == incidence1
- @test IncidenceMatrix(cones(F1, 2)) == incidence1
- @test cones(IncidenceMatrix, F1, 2) == incidence1
+ @test _check_im_perm_rows(ray_indices(cones(F1, 2)), incidence1)
+ @test _check_im_perm_rows(incidence_matrix(cones(F1, 2)), incidence1)
+ @test _check_im_perm_rows(cones(IncidenceMatrix, F1, 2), incidence1)
+
+ A3 = affine_space(NormalToricVariety, 3)
+ @test length(cones(A3, 1)) == 3
+ @test length(cones(A3, 0)) == 1
+ @test length(cones(A3, -1)) == 0
+ @test cones(A3, 1) isa SubObjectIterator{Cone{QQFieldElem}}
+ @test cones(A3, 0) isa SubObjectIterator{Cone{QQFieldElem}}
+ @test cones(A3, -1) isa SubObjectIterator{Cone{QQFieldElem}}
II = ray_indices(maximal_cones(NFsquare))
NF0 = polyhedral_fan(II, rays(NFsquare))
@@ -75,16 +80,16 @@
end
@test f_vector(NFsquare) == [4, 4]
@test rays(F1NR) == collect(eachrow(I3))
- @test ray_indices(maximal_cones(F1NR)) == incidence1
- @test IncidenceMatrix(maximal_cones(F1NR)) == incidence1
+ @test _check_im_perm_rows(ray_indices(maximal_cones(F1NR)), incidence1)
+ @test _check_im_perm_rows(incidence_matrix(maximal_cones(F1NR)), incidence1)
@test n_rays(F2NR) == 0
@test lineality_dim(F2NR) == 1
RMLF2NR = rays_modulo_lineality(F2NR)
@test length(RMLF2NR[:rays_modulo_lineality]) == 2
@test RMLF2NR[:rays_modulo_lineality] == collect(eachrow(R))
@test lineality_space(F2NR) == collect(eachrow(L))
- @test ray_indices(maximal_cones(F2NR)) == incidence2
- @test IncidenceMatrix(maximal_cones(F2NR)) == incidence2
+ @test _check_im_perm_rows(ray_indices(maximal_cones(F2NR)), incidence2)
+ @test _check_im_perm_rows(incidence_matrix(maximal_cones(F2NR)), incidence2)
C = positive_hull(f, identity_matrix(ZZ, 0))
pf = polyhedral_fan(C)
@@ -140,7 +145,7 @@ end
end
@testset "Star Subdivision" begin
- f = polyhedral_fan(IncidenceMatrix([[1, 2, 3, 4]]), [1 0 0; 1 1 0; 1 1 1; 1 0 1])
+ f = polyhedral_fan(incidence_matrix([[1, 2, 3, 4]]), [1 0 0; 1 1 0; 1 1 1; 1 0 1])
@test is_pure(f)
@test is_fulldimensional(f)
v0 = [1; 0; 0]
@@ -153,7 +158,7 @@ end
@test number_of_maximal_cones(sf1) == 3
@test number_of_maximal_cones(sf2) == 4
- ff = polyhedral_fan(IncidenceMatrix([[1], [2, 3]]), [1 0 0; -1 0 0; 0 1 0])
+ ff = polyhedral_fan(incidence_matrix([[1], [2, 3]]), [1 0 0; -1 0 0; 0 1 0])
@test !is_pure(ff)
@test !is_fulldimensional(ff)
w0 = [1; 0; 0]
diff --git a/test/PolyhedralGeometry/polyhedron.jl b/test/PolyhedralGeometry/polyhedron.jl
index 1445276d7405..3556449f31dd 100644
--- a/test/PolyhedralGeometry/polyhedron.jl
+++ b/test/PolyhedralGeometry/polyhedron.jl
@@ -37,14 +37,6 @@
@test nrows(Oscar.pm_object(pf3).INEQUALITIES) == 4
@test n_vertices(pf3) == 1
- function _check_im_perm_rows(inc::IncidenceMatrix, o)
- oinc = IncidenceMatrix(o)
- nr = nrows(inc)
- nr == nrows(oinc) &&
- issetequal(Polymake.row.(Ref(inc), 1:nr),
- Polymake.row.(Ref(oinc), 1:nr))
- end
-
@testset "core functionality" begin
@test matrix(f, rays(Q1)) * v == T[f(2)]
@test issetequal(matrix(f, vertices(Q1)) * v, T[f(1), f(0), f(1)])
@@ -55,20 +47,20 @@
@test n_vertices(Q0) == 3
@test n_vertices.(faces(Q0, 1)) == [2, 2, 2]
@test lattice_points(Q0) isa SubObjectIterator{PointVector{ZZRingElem}}
- @test point_matrix(lattice_points(Q0)) isa MatElem{ZZRingElem}
- @test matrix(ZZ, lattice_points(Q0)) isa MatElem{ZZRingElem}
@test length(lattice_points(Q0)) == 3
@test issetequal(lattice_points(Q0), point_vector.(Ref(ZZ), [[0, 0], [0, 1], [1, 0]]))
+ @test point_matrix(lattice_points(Q0)) == _oscar_matrix_from_property(ZZ, lattice_points(Q0))
+ @test matrix(ZZ, lattice_points(Q0)) == _oscar_matrix_from_property(ZZ, lattice_points(Q0))
@test interior_lattice_points(square) isa SubObjectIterator{PointVector{ZZRingElem}}
@test point_matrix(interior_lattice_points(square)) == matrix(ZZ, [0 0])
@test matrix(ZZ, interior_lattice_points(square)) == matrix(ZZ, [0 0])
@test length(interior_lattice_points(square)) == 1
@test interior_lattice_points(square) == [[0, 0]]
@test boundary_lattice_points(square) isa SubObjectIterator{PointVector{ZZRingElem}}
- @test point_matrix(boundary_lattice_points(square)) isa MatElem{ZZRingElem}
@test length(boundary_lattice_points(square)) == 8
@test issetequal(boundary_lattice_points(square),
point_vector.(Ref(ZZ), [[-1, -1], [-1, 0], [-1, 1], [0, -1], [0, 1], [1, -1], [1, 0], [1, 1]]))
+ @test point_matrix(boundary_lattice_points(square)) == _oscar_matrix_from_property(ZZ, boundary_lattice_points(square))
if T == QQFieldElem
@test is_smooth(Q0)
@test is_normal(Q0)
@@ -111,8 +103,8 @@
@test rays(RayVector, Pos) isa SubObjectIterator{RayVector{T}}
@test rays(Pos) isa SubObjectIterator{RayVector{T}}
@test length(rays(Pos)) == 3
- @test vector_matrix(rays(Pos)) isa MatElem{T}
@test issetequal(rays(Pos), ray_vector.(Ref(f), [[1, 0, 0], [0, 1, 0], [0, 0, 1]]))
+ @test vector_matrix(rays(Pos)) == _oscar_matrix_from_property(f, rays(Pos))
@test lineality_space(L) isa SubObjectIterator{RayVector{T}}
@test generator_matrix(lineality_space(L)) == matrix(f, [0 0 1])
if T == QQFieldElem
@@ -126,16 +118,16 @@
convex_hull.(Ref(f), [[-1 -1; -1 1], [1 -1; 1 1], [-1 -1; 1 -1], [-1 1; 1 1]]))
@test _check_im_perm_rows(vertex_indices(faces(square, 1)),
[[1, 3], [2, 4], [1, 2], [3, 4]])
- @test ray_indices(faces(square, 1)) == IncidenceMatrix(4, 0)
+ @test ray_indices(faces(square, 1)) == incidence_matrix(4, 0)
@test _check_im_perm_rows(vertex_and_ray_indices(faces(square, 1)),
[[2, 4], [1, 3], [1, 2], [3, 4]])
- @test _check_im_perm_rows(IncidenceMatrix(faces(square, 1)),
+ @test _check_im_perm_rows(incidence_matrix(faces(square, 1)),
[[1, 3], [2, 4], [1, 2], [3, 4]])
@test _check_im_perm_rows(faces(IncidenceMatrix, square, 1),
[[1, 3], [2, 4], [1, 2], [3, 4]])
@test _check_im_perm_rows(facet_indices(vertices(square)),
[[1, 3], [2, 3], [1, 4], [2, 4]])
- @test _check_im_perm_rows(IncidenceMatrix(vertices(square)),
+ @test _check_im_perm_rows(incidence_matrix(vertices(square)),
[[1, 3], [2, 3], [1, 4], [2, 4]])
@test _check_im_perm_rows(vertices(IncidenceMatrix, square),
[[1, 3], [2, 3], [1, 4], [2, 4]])
@@ -145,13 +137,13 @@
@test _check_im_perm_rows(vertex_indices(faces(Pos, 1)), [[1], [1], [1]])
@test _check_im_perm_rows(ray_indices(faces(Pos, 1)), [[1], [2], [3]])
@test _check_im_perm_rows(vertex_and_ray_indices(faces(Pos, 1)), [[1, 4], [2, 4], [3, 4]])
- @test _check_im_perm_rows(IncidenceMatrix(faces(Pos, 1)), [[1, 4], [2, 4], [3, 4]])
+ @test _check_im_perm_rows(incidence_matrix(faces(Pos, 1)), [[1, 4], [2, 4], [3, 4]])
@test _check_im_perm_rows(faces(IncidenceMatrix, Pos, 1), [[1, 4], [2, 4], [3, 4]])
@test isnothing(faces(Q2, 0))
v = vertices(minkowski_sum(Q0, square))
@test length(v) == 5
@test issetequal(v, point_vector.(Ref(f), [[2, -1], [2, 1], [-1, -1], [-1, 2], [1, 2]]))
- @test point_matrix(v) isa MatElem{T}
+ @test point_matrix(v) == _oscar_matrix_from_property(f, v)
let S = Pair{Matrix{T},T}
@test issetequal(facets(S, Pos), S.([f.([-1 0 0]), f.([0 -1 0]), f.([0 0 -1])], [f(0)]))
end
@@ -174,29 +166,27 @@
end
@test _check_im_perm_rows(ray_indices(facets(S, Pos)), [[2, 3], [1, 3], [1, 2]])
@test _check_im_perm_rows(vertex_and_ray_indices(facets(S, Pos)), [[2, 3, 4], [1, 3, 4], [1, 2, 4]])
- @test _check_im_perm_rows(IncidenceMatrix(facets(S, Pos)), [[2, 3, 4], [1, 3, 4], [1, 2, 4]])
+ @test _check_im_perm_rows(incidence_matrix(facets(S, Pos)), [[2, 3, 4], [1, 3, 4], [1, 2, 4]])
@test _check_im_perm_rows(vertex_indices(facets(S, Pos)), [[1], [1], [1]])
end
@test _check_im_perm_rows(facets(IncidenceMatrix, Pos),
[[2, 3, 4], [1, 3, 4], [1, 2, 4]]
)
@test _check_im_perm_rows(facet_indices(vertices(Pos)), [[1, 2, 3]])
- @test _check_im_perm_rows(IncidenceMatrix(vertices(Pos)), [[1, 2, 3]])
+ @test _check_im_perm_rows(incidence_matrix(vertices(Pos)), [[1, 2, 3]])
@test _check_im_perm_rows(vertices(IncidenceMatrix, Pos), [[1, 2, 3]])
@test _check_im_perm_rows(facet_indices(rays(Pos)), [[1, 3], [2, 3], [1, 2]])
- @test _check_im_perm_rows(IncidenceMatrix(rays(Pos)), [[2, 3], [1, 3], [1, 2]])
+ @test _check_im_perm_rows(incidence_matrix(rays(Pos)), [[2, 3], [1, 3], [1, 2]])
@test _check_im_perm_rows(rays(IncidenceMatrix, Pos), [[1, 3], [2, 3], [1, 2]])
@test facets(Pair, Pos) isa SubObjectIterator{Pair{Matrix{T},T}}
@test facets(Pos) isa SubObjectIterator{AffineHalfspace{T}}
@test facets(Halfspace, Pos) isa SubObjectIterator{AffineHalfspace{T}}
@test affine_hull(point) isa SubObjectIterator{AffineHyperplane{T}}
- @test affine_equation_matrix(affine_hull(point)) isa MatElem{T}
- @test size(affine_equation_matrix(affine_hull(point))) == (3, 4)
- @test Oscar.affine_matrix_for_polymake(affine_hull(point)) isa Polymake.Matrix{Oscar._scalar_type_to_polymake(T)}
- @test size(Oscar.affine_matrix_for_polymake(affine_hull(point))) == (3, 4)
@test length(affine_hull(point)) == 3
@test issetequal(affine_hull(point),
[hyperplane(f, [1 0 0], 0), hyperplane(f, [0 1 0], 1), hyperplane(f, [0 0 1], 0)])
+ @test affine_equation_matrix(affine_hull(point)) == _oscar_matrix_from_property(f, affine_hull(point))
+ @test Oscar.affine_matrix_for_polymake(affine_hull(point)) == _polymake_matrix_from_property(affine_hull(point))
@test n_facets(square) == 4
@test lineality_dim(Q0) == 0
@test n_rays(Q1) == 1
@@ -616,7 +606,7 @@
@test affine_inequality_matrix(facets(S, D)) == matrix(R, hcat(-b, vcat(A...)))
@test halfspace_matrix_pair(facets(S, D)) == (A=matrix(R, vcat(A...)), b=b)
- @test ray_indices(facets(S, D)) == IncidenceMatrix(12, 0)
+ @test ray_indices(facets(S, D)) == incidence_matrix(12, 0)
@test _check_im_perm_rows(vertex_indices(facets(S, D)), [
[1, 3, 5, 9, 10],
[1, 2, 3, 4, 6],
@@ -645,7 +635,7 @@
[9, 10, 14, 17, 19],
[15, 17, 18, 19, 20],
])
- @test _check_im_perm_rows(IncidenceMatrix(facets(S, D)), [
+ @test _check_im_perm_rows(incidence_matrix(facets(S, D)), [
[1, 3, 5, 9, 10],
[1, 2, 3, 4, 6],
[1, 2, 5, 7, 8],
@@ -676,9 +666,9 @@
[9, 10, 14, 17, 19],
[15, 17, 18, 19, 20],
])
- @test facet_indices(rays(D)) == IncidenceMatrix(0, 12)
- @test IncidenceMatrix(rays(D)) == IncidenceMatrix(0, 12)
- @test rays(IncidenceMatrix, D) == IncidenceMatrix(0, 12)
+ @test facet_indices(rays(D)) == incidence_matrix(0, 12)
+ @test incidence_matrix(rays(D)) == incidence_matrix(0, 12)
+ @test rays(IncidenceMatrix, D) == incidence_matrix(0, 12)
@test _check_im_perm_rows(facet_indices(vertices(D)), [
[1, 2, 3],
[2, 3, 6],
@@ -701,7 +691,7 @@
[9, 11, 12],
[4, 9, 12],
])
- @test _check_im_perm_rows(IncidenceMatrix(vertices(D)), [
+ @test _check_im_perm_rows(incidence_matrix(vertices(D)), [
[1, 2, 3],
[2, 3, 6],
[1, 2, 7],
diff --git a/test/PolyhedralGeometry/scalar_types.jl b/test/PolyhedralGeometry/scalar_types.jl
index 8e67d92d98e6..676e2645a7ad 100644
--- a/test/PolyhedralGeometry/scalar_types.jl
+++ b/test/PolyhedralGeometry/scalar_types.jl
@@ -47,9 +47,9 @@
@test length(lattice_points(sd)) == 11
let pc = polyhedral_complex(
- E, IncidenceMatrix(facets(sd)), vertices(sd); non_redundant=true
+ E, incidence_matrix(facets(sd)), vertices(sd); non_redundant=true
)
- @test maximal_polyhedra(pc) == faces(sd, 2)
+ @test issetequal(maximal_polyhedra(pc), faces(sd, 2))
end
let c = convex_hull(E, permutedims([0]), permutedims([r]))
ms = product(sd, c)
@@ -96,6 +96,11 @@
)
@test number_field(coefficient_field(j)) == number_field(coefficient_field(jj))
end
+ let ng = n_gon(5)
+ (A,b) = halfspace_matrix_pair(facets(ng))
+ @test typeof(polyhedron(A,b)) == typeof(ng)
+ @test coefficient_field(polyhedron(A,b)) == coefficient_field((ng))
+ end
end
@testset "Cross scalar operations" begin
diff --git a/test/PolyhedralGeometry/setup_tests.jl b/test/PolyhedralGeometry/setup_tests.jl
index d7087e22adaa..af8e73b5f2e3 100644
--- a/test/PolyhedralGeometry/setup_tests.jl
+++ b/test/PolyhedralGeometry/setup_tests.jl
@@ -6,4 +6,28 @@ if !isdefined(Main, :_prepare_scalar_types)
KK, (a1, a2) = embedded_number_field([x^2 - 2, x^3 - 5], [(0, 2), (0, 2)])
return [(f, elem_type(f)) for f in (QQ, K, KK)]
end
+
+ function _check_im_perm_rows(inc::IncidenceMatrix, o)
+ oinc = incidence_matrix(o)
+ nr, nc = size(inc)
+ (nr, nc) == size(oinc) &&
+ issetequal(Polymake.row.(Ref(inc), 1:nr),
+ Polymake.row.(Ref(oinc), 1:nr))
+ end
+
+ _matrix_from_property(b::SubObjectIterator{<:Union{LinearHalfspace, LinearHyperplane}}) = permutedims(hcat([normal_vector(be) for be in b]...))
+
+ _matrix_from_property(b::SubObjectIterator{<:Union{AffineHalfspace, AffineHyperplane}}) = permutedims(hcat([vcat(-negbias(be), normal_vector(be)) for be in b]...))
+
+ # only used for cones that are linear halfspaces
+ _matrix_from_property(b::SubObjectIterator{Cone{T}}) where T = _matrix_from_property(SubObjectIterator{LinearHalfspace{T}}(b.Obj, b.Acc, b.n))
+
+ _matrix_from_property(b::SubObjectIterator) = permutedims(hcat(b...))
+
+ _oscar_matrix_from_property(a, b::SubObjectIterator) = matrix(a, _matrix_from_property(b))
+
+ function _polymake_matrix_from_property(b::SubObjectIterator)
+ m = _matrix_from_property(b)
+ return Polymake.Matrix{Oscar._scalar_type_to_polymake(eltype(m))}(m)
+ end
end
diff --git a/test/PolyhedralGeometry/solve_integrally.jl b/test/PolyhedralGeometry/solve_integrally.jl
index b4acc42344e2..a592f39ae6e4 100644
--- a/test/PolyhedralGeometry/solve_integrally.jl
+++ b/test/PolyhedralGeometry/solve_integrally.jl
@@ -1,10 +1,10 @@
@testset "solve_integrally" begin
@testset "solve_mixed" begin
A = ZZMatrix([1 1])
- b = zero_matrix(FlintZZ, 1, 1)
+ b = zero_matrix(ZZ, 1, 1)
b[1, 1] = 7
C = ZZMatrix([1 0; 0 1])
- d = zero_matrix(FlintZZ, 2, 1)
+ d = zero_matrix(ZZ, 2, 1)
d[1, 1] = 2
d[2, 1] = 3
S0 = solve_mixed(A, b, C, d)
@@ -30,7 +30,7 @@
@testset "solve_ineq" begin
A = ZZMatrix([1 0; 0 1; -1 0; 0 -1])
- b = zero_matrix(FlintZZ, 4, 1)
+ b = zero_matrix(ZZ, 4, 1)
b[1, 1] = 1
b[2, 1] = 1
b[3, 1] = 0
@@ -48,7 +48,7 @@
@testset "solve_non_negative" begin
A = ZZMatrix([1 1])
- b = zero_matrix(FlintZZ, 1, 1)
+ b = zero_matrix(ZZ, 1, 1)
b[1, 1] = 3
S0 = solve_non_negative(A, b)
S1 = solve_non_negative(ZZMatrix, A, b)
diff --git a/test/PolyhedralGeometry/subdivision_of_points.jl b/test/PolyhedralGeometry/subdivision_of_points.jl
index 6d4c241386ef..eebf7eae44b8 100644
--- a/test/PolyhedralGeometry/subdivision_of_points.jl
+++ b/test/PolyhedralGeometry/subdivision_of_points.jl
@@ -2,7 +2,7 @@
C = cube(2)
square_weights = [0, 0, 1, 2]
square_max_cells = [[1, 2, 3], [2, 3, 4]]
- square_incidence = IncidenceMatrix(square_max_cells)
+ square_incidence = incidence_matrix(square_max_cells)
square_by_weights = subdivision_of_points(C, square_weights)
square_by_cells = subdivision_of_points(C, square_max_cells)
@@ -14,16 +14,16 @@
SubdivisionOfPoints
@testset "alternative inputs" begin
- @test issetequal(collect(maximal_cells(square_by_incidence)),
- collect(maximal_cells(square_by_weights)))
- @test min_weights(square_by_cells) == min_weights(square_by_weights)
+ @test issetequal(maximal_cells(square_by_incidence),
+ maximal_cells(square_by_weights))
+ @test issetequal(square_max_cells, maximal_cells(subdivision_of_points(C,min_weights(square_by_cells))))
end
moaepts = [4 0 0; 0 4 0; 0 0 4; 2 1 1; 1 2 1; 1 1 2]
fulldim_moaepts = moaepts[:, 2:3]
- moaeimreg0 = IncidenceMatrix(1, 6)
+ moaeimreg0 = incidence_matrix(1, 6)
moaeimreg0[1, :] = [1, 1, 1, 0, 0, 0]
- moaeimnonreg0 = IncidenceMatrix([
+ moaeimnonreg0 = incidence_matrix([
[4, 5, 6], [1, 4, 2], [2, 4, 5], [2, 3, 5], [3, 5, 6], [1, 3, 6], [1, 4, 6]
])
@@ -45,10 +45,10 @@
@test min_weights(SOP1) == [0, 0, 0, 1, 1, 1]
@test dim(C1) == 6
@test dim(CMOAE) == 4
- @test moaeimnonreg0 == maximal_cells(IncidenceMatrix, MOAE)
+ @test _check_im_perm_rows(moaeimnonreg0, maximal_cells(IncidenceMatrix, MOAE))
@test number_of_points(MOAE) == 6
@test length(points(MOAE)) == 6
- @test collect(points(MOAE))[3] == [0, 0, 4]
+ @test [0, 0, 4] in points(MOAE)
@test gkz_vector(fulldim_MOAE) == [9, 9, 9, 7, 7, 7]
end
end
diff --git a/test/PolyhedralGeometry/types.jl b/test/PolyhedralGeometry/types.jl
index af613877f754..d079c17df422 100644
--- a/test/PolyhedralGeometry/types.jl
+++ b/test/PolyhedralGeometry/types.jl
@@ -1,12 +1,21 @@
@testset "types" begin
@testset "IncidenceMatrix" begin
- im = IncidenceMatrix([[1, 2, 3], [4, 5, 6]])
+ im = incidence_matrix([[1, 2, 3], [4, 5, 6]])
@test nrows(im) == 2
@test ncols(im) == 6
@test row(im, 1) isa Set{Int}
@test row(im, 1) == Set{Int}([1, 2, 3])
@test column(im, 2) isa Set{Int}
@test column(im, 2) == Set{Int}([1])
+
+ @testset "IncidenceMatrix constructions" begin
+ @test incidence_matrix([true true true false false false; false false false true true true]) == im
+ @test incidence_matrix([1 1 1 0 0 0; 0 0 0 1 1 1]) == im
+ @test incidence_matrix(4, 2) == incidence_matrix([0 0; 0 0; 0 0; 0 0])
+ @test incidence_matrix(im) == im
+ @test incidence_matrix(3, 8, [[1, 2, 3], [4, 5, 6]]) == incidence_matrix([1 1 1 0 0 0 0 0; 0 0 0 1 1 1 0 0; 0 0 0 0 0 0 0 0])
+ @test_throws ArgumentError incidence_matrix([1 1 1 0 0 0; 0 0 0 1 2 1])
+ end
end
a = [1, 2, 3]
@@ -14,7 +23,7 @@
(ENF, _) = _prepare_scalar_types()[2]
- @testset "$T" for (T, fun) in ((PointVector, point_vector), (RayVector, ray_vector))
+ @testset "$T" for (T, fun, other) in ((PointVector, point_vector, ray_vector), (RayVector, ray_vector, point_vector))
@test fun(a) isa T{QQFieldElem}
for f in (ZZ, QQ, ENF)
@@ -57,6 +66,10 @@
@test *(g(3), A) isa T
@test *(g(3), A) == 3 * a
+
+ let Ao = other(g, a)
+ @test_throws ArgumentError A == Ao
+ end
end
for op in [+, -]
@@ -69,6 +82,19 @@
@test 3 * A isa T{U}
@test 3 * A == 3 * a
+ if T == RayVector
+ @test 5 * A == A
+ @test fun(f, 5 * a) == A
+ @test A == fun(f, 5 * a)
+ @test 5 * a == A
+ @test vcat(a, a) != A
+ @test -5 * A != A
+ @test fun(f, -5 * a) != A
+ @test A != fun(f, -5 * a)
+ @test A == 5 * a
+ @test A != vcat(a, a)
+ end
+
if f != ENF
let h = Int
Ah = h.(A)
diff --git a/test/Rings/MPolyQuo.jl b/test/Rings/MPolyQuo.jl
index 2d38f5ecfd29..31c18c00ecd3 100644
--- a/test/Rings/MPolyQuo.jl
+++ b/test/Rings/MPolyQuo.jl
@@ -36,6 +36,12 @@
B,q = quo(R, x^3+y,y^2; ordering=lex(R))
@test A.I == B.I
+
+ @test characteristic(quo(R, ideal(x))[1]) == 0
+ @test characteristic(quo(R, ideal(R, 1))[1]) == 1
+
+ S, (s, t) = GF(5)[:s, :t]
+ @test characteristic(quo(S, ideal([s, t]))[1]) == 5
end
@testset "MpolyQuo.manipulation" begin
diff --git a/test/Rings/NumberField.jl b/test/Rings/NumberField.jl
index 6776c019aa79..9beb6682e3c2 100644
--- a/test/Rings/NumberField.jl
+++ b/test/Rings/NumberField.jl
@@ -1,14 +1,14 @@
@testset "Number field" begin
- Qx, x = FlintQQ[:x]
+ Qx, x = QQ[:x]
k, _ = number_field(x^2 + 1)
ku, u = k[:u1, :u2]
Ik = ideal(ku, [u[1]^3 + u[2]^3 - 3, u[1]^5 + u[2]^5 - 5])
- Qy, y = FlintQQ[:y1, :y2]
+ Qy, y = QQ[:y1, :y2]
IQ = ideal(Qy, [y[1]^3 + y[2]^3 - 3, y[1]^5 + y[2]^5 - 5])
- for (Bk, Pk, I) in [(k, ku, Ik), (FlintQQ, Qy, IQ)]
+ for (Bk, Pk, I) in [(k, ku, Ik), (QQ, Qy, IQ)]
gg = gens(Pk)
@test_throws ErrorException number_field(ideal([gg[1]]))
K, = @inferred number_field(I, [:a1, :a2])
@@ -180,7 +180,7 @@
end
# denominator
- if Bk === FlintQQ
+ if Bk === QQ
b = rand(K, -2:2)
d = @inferred denominator(b)
@test d isa ZZRingElem
@@ -203,7 +203,7 @@
end
# basis matrix
- if Bk == FlintQQ
+ if Bk == QQ
for i in 1:10
BB = [rand(K, -2:2) for j in 1:rand(1:10)]
M = @inferred basis_matrix(BB, Hecke.FakeFmpqMat)
@@ -226,7 +226,7 @@
@test b * B[n] == sum(M[n, m] * B[m] for m in 1:length(B))
end
- if Bk == FlintQQ
+ if Bk == QQ
M, d = @inferred representation_matrix_q(b)
@test nrows(M) == degree(K)
@test ncols(M) == degree(K)
@@ -243,7 +243,7 @@
c = rand(-10:10)
end
b = b//c
- MM = zero_matrix(FlintZZ, nrows(M), ncols(M))
+ MM = zero_matrix(ZZ, nrows(M), ncols(M))
dd = ZZRingElem()
j = rand(1:nrows(MM))
Oscar.Hecke.elem_to_mat_row!(MM, j, dd, b)
@@ -318,7 +318,7 @@
end
# simple extension
- if Bk == FlintQQ
+ if Bk == QQ
Ks, KstoK = simple_extension(K, simplify = true)
else
Ks, KstoK = simple_extension(K)
@@ -332,7 +332,7 @@
@test KstoK(b + c) == KstoK(b) + KstoK(c)
@test KstoK(b * c) == KstoK(b) * KstoK(c)
- if Bk == FlintQQ
+ if Bk == QQ
@test KstoK\(KstoK(b)) == b
b = rand(K, -10:10)
c = rand(K, -10:10)
diff --git a/test/Rings/binomial-ideals.jl b/test/Rings/binomial-ideals.jl
index 12390df54231..15aeca65fc6f 100644
--- a/test/Rings/binomial-ideals.jl
+++ b/test/Rings/binomial-ideals.jl
@@ -6,7 +6,7 @@
@test is_binomial(f)
J = ideal(R, [x^2-y^3, z^2])
@test is_binomial(J)
- Qxy, (x, y, z, t) = polynomial_ring(FlintQQ, 4)
+ Qxy, (x, y, z, t) = polynomial_ring(QQ, 4)
I = ideal(elem_type(Qxy)[x*y, z*t^2-t^3, z^2-y^2])
@test Oscar.is_binomial(I)
@test Oscar.is_unital(I)
@@ -24,7 +24,7 @@
@test is_cellular(I)[1]
I = ideal(R, [x[1]*x[4]^2-x[2]*x[5]^2, x[1]^3*x[3]^3-x[2]^4*x[4]^2, x[2]*x[4]^8-x[3]^3*x[5]^6])
@test !is_cellular(I)[1]
- Qxy, (x, y, z, t) = polynomial_ring(FlintQQ, 4)
+ Qxy, (x, y, z, t) = polynomial_ring(QQ, 4)
I = ideal(elem_type(Qxy)[x*y, z*t^2-t^3, z^2-y^2])
@test !Oscar.is_cellular(I)[1]
lI = Oscar.cellular_decomposition(I)
@@ -44,7 +44,7 @@
end
@testset "Binomial primary decomposition" begin
- Qxy, (x, y, z, t) = polynomial_ring(FlintQQ, 4)
+ Qxy, (x, y, z, t) = polynomial_ring(QQ, 4)
I = ideal(elem_type(Qxy)[x*y, z*t^2-t^3, z^2-y^2])
lP = Oscar.binomial_primary_decomposition(I)
diff --git a/test/Rings/groebner.jl b/test/Rings/groebner.jl
index fee6c2dc9f05..53d7b4d96c18 100644
--- a/test/Rings/groebner.jl
+++ b/test/Rings/groebner.jl
@@ -11,6 +11,22 @@
@test leading_ideal(I, ordering=degrevlex(gens(R))) == ideal(R,[x*y^2, x^4, y^5])
@test leading_ideal(I) == ideal(R,[x*y^2, x^4, y^5])
@test leading_ideal(I, ordering=lex(gens(R))) == ideal(R,[y^7, x*y^2, x^3])
+
+ # algorithm = :modular option
+ R = @polynomial_ring(QQ, [:x, :y])
+ I = ideal(R, [x^2+y,y*x-1])
+ # uses f4 in msolve/AlgebraicSolving
+ groebner_basis(I, ordering=degrevlex(R), algorithm=:modular)
+ @test gens(I.gb[degrevlex(R)]) == QQMPolyRingElem[x + y^2, x*y - 1, x^2 + y]
+ # uses multi-modular implementation in Oscar applying Singular finite field
+ # computations
+ groebner_basis(I, ordering=lex(R), algorithm=:modular)
+ @test gens(I.gb[lex(R)]) == QQMPolyRingElem[y^3 + 1, x + y^2]
+ T = @polynomial_ring(QQ, :t)
+ R = @polynomial_ring(T, [:x, :y])
+ I = ideal(R, [x^2+y,y*x-1])
+ @test_throws ErrorException groebner_basis(I, ordering=lex(R), algorithm=:modular)
+
# issue 3665
kt,t = polynomial_ring(GF(2),:t)
Ft = fraction_field(kt)
diff --git a/test/Rings/mpoly-localizations.jl b/test/Rings/mpoly-localizations.jl
index d95a7763458f..902c9b026ca9 100644
--- a/test/Rings/mpoly-localizations.jl
+++ b/test/Rings/mpoly-localizations.jl
@@ -9,8 +9,6 @@ const rng = Oscar.get_seeded_rng()
I = ideal(R, f)
S = Oscar.MPolyComplementOfPrimeIdeal(I)
V, _ = localization(S)
- T = Oscar.MPolyComplementOfKPointIdeal(R, [ZZ(1), ZZ(0)])
- W, _ = localization(T)
k = QQ
R, variab = k[:x, :y]
@@ -72,8 +70,8 @@ const rng = Oscar.get_seeded_rng()
x = v[1]
y = v[2]
f = (x^2 + y^2)^2
- S = Oscar.MPolyComplementOfKPointIdeal(R, [ZZ(0), ZZ(0)])
T = Oscar.MPolyPowersOfElement(R, [f])
+ S = Oscar.MPolyComplementOfPrimeIdeal(ideal(R, [x, y]))
U = Oscar.MPolyProductOfMultSets(R, [S, T])
@test f in U
@test (f*(x-1) in U)
@@ -241,7 +239,6 @@ end
# d = Vector{elem_type(R)}()
# d = [rand(R, 1:3, 0:4, 1:10)::elem_type(R) for i in 0:(abs(rand(Int))%3+1)]
# S = Oscar.MPolyPowersOfElement(R, d)
-# T = Oscar.MPolyComplementOfKPointIdeal(R, [kk(125), kk(-45)])
# U = Oscar.MPolyComplementOfPrimeIdeal(I)
#
# test_Ring_interface_recursive(localization(S)[1])
diff --git a/test/Rings/mpoly.jl b/test/Rings/mpoly.jl
index 8c81bdd1d30b..1f9c33a9dcae 100644
--- a/test/Rings/mpoly.jl
+++ b/test/Rings/mpoly.jl
@@ -159,7 +159,6 @@ end
l = minimal_primes(i, algorithm=:charSets)
@test length(l) == 2
@test l[1] == i1 && l[2] == i2 || l[1] == i2 && l[2] == i1
-
R, (a, b, c, d) = polynomial_ring(ZZ, [:a, :b, :c, :d])
i = ideal(R, [R(9), (a+3)*(b+3)])
i1 = ideal(R, [R(3), a])
@@ -232,6 +231,19 @@ end
R, (x, y) = polynomial_ring(QQ, [:x, :y])
I = ideal(R, [one(R)])
@test is_prime(I) == false
+
+ J = ideal(R, [x*(x-1), y*(y-1), x*y])
+ l = minimal_primes(J)
+ @test length(l) == 3
+
+ QQt, t = QQ[:t]
+ kk, a = extension_field(t^2 + 1)
+
+ R, (x, y) = kk[:x, :y]
+ J = ideal(R, [x^2 + 1, y^2 + 1, (x - a)*(y - a)])
+ l = minimal_primes(J)
+ @test length(l) == 3
+
end
@testset "Groebner" begin
@@ -601,4 +613,3 @@ end
I = ideal(P, elem_type(P)[])
@test !radical_membership(x, I)
end
-
diff --git a/test/Rings/mpolyquo-localizations.jl b/test/Rings/mpolyquo-localizations.jl
index d3c910c10662..ce7a37d225de 100644
--- a/test/Rings/mpolyquo-localizations.jl
+++ b/test/Rings/mpolyquo-localizations.jl
@@ -510,3 +510,20 @@ end
@test Oscar._get_generators_string_one_line(ideal(R, x)) == "with 100 generators"
@test Oscar._get_generators_string_one_line(ideal(R, [sum(x)])) == "with 1 generator"
end
+
+@testset "monomial_basis MPolyQuoLocRing" begin
+ R, (x,y) = QQ["x", "y"]
+ L, _ = localization(R, complement_of_point_ideal(R, [0,0]))
+ Q1, _ = quo(L, ideal(L, L(x+1)))
+ @test isempty(monomial_basis(Q1))
+ Q2, _ = quo(L, ideal(L, L(x^2)))
+ @test_throws InfiniteDimensionError() monomial_basis(Q2)
+ Q3, _ = quo(L, ideal(L, L.([x^2, y^3])))
+ @test monomial_basis(Q3) == L.([x*y^2, y^2, x*y, y, x, 1])
+ Q4,_ = quo(L, ideal(L, [x^2-x, y^2-2*y]))
+ @test monomial_basis(Q4) == [L(1)] #test for difference in localized and non-localized case
+ @test Oscar._monomial_basis(L, ideal(L, [x^3*(x-1), y*(y-1)*(y-2)])) == L.([x^2, x, 1])
+ L1, _ = localization(R, complement_of_point_ideal(R, [1,2]))
+ @test Oscar._monomial_basis(L1, ideal(L1, [(x-1)^2, (y-2)^2])) == L1.([x*y, y, x, 1])
+ @test isempty(Oscar._monomial_basis(L1, ideal(L1, L1.([x, y]))))
+end
diff --git a/test/Serialization/PolyhedralGeometry.jl b/test/Serialization/PolyhedralGeometry.jl
index 0d8b8e1f4c03..9d04515719d3 100644
--- a/test/Serialization/PolyhedralGeometry.jl
+++ b/test/Serialization/PolyhedralGeometry.jl
@@ -87,7 +87,7 @@ using Oscar: _integer_variables
end
@testset "PolyhedralComplex" begin
- IM = IncidenceMatrix([[1,2,3],[1,3,4]])
+ IM = incidence_matrix([[1,2,3],[1,3,4]])
vr = [0 0; 1 0; 1 1; 0 1]
PC = polyhedral_complex(IM, vr)
test_save_load_roundtrip(path, PC) do loaded
@@ -156,7 +156,7 @@ using Oscar: _integer_variables
@testset "SubdivisionOfPoints" begin
moaepts = [4 0 0; 0 4 0; 0 0 4; 2 1 1; 1 2 1; 1 1 2]
- moaeimnonreg0 = IncidenceMatrix([[4,5,6],[1,4,2],[2,4,5],[2,3,5],[3,5,6],[1,3,6],[1,4,6]])
+ moaeimnonreg0 = incidence_matrix([[4,5,6],[1,4,2],[2,4,5],[2,3,5],[3,5,6],[1,3,6],[1,4,6]])
MOAE = subdivision_of_points(moaepts, moaeimnonreg0)
test_save_load_roundtrip(path, MOAE) do loaded
@test number_of_maximal_cells(MOAE) == number_of_maximal_cells(loaded)
diff --git a/test/Serialization/ToricGeometry.jl b/test/Serialization/ToricGeometry.jl
index 05c965bb572e..b8c8d9187638 100644
--- a/test/Serialization/ToricGeometry.jl
+++ b/test/Serialization/ToricGeometry.jl
@@ -8,16 +8,19 @@
test_save_load_roundtrip(path, pp; with_attrs=false, check_func=!check) do loaded
@test rays(pp) == rays(loaded)
@test ray_indices(maximal_cones(pp)) == ray_indices(maximal_cones(loaded))
+ @test coordinate_names(pp) == coordinate_names(loaded)
end
test_save_load_roundtrip(path, pp; with_attrs=true, check_func=check) do loaded
@test rays(pp) == rays(loaded)
@test ray_indices(maximal_cones(pp)) == ray_indices(maximal_cones(loaded))
+ @test coordinate_names(pp) == coordinate_names(loaded)
end
test_save_load_roundtrip(path, pp; check_func=check) do loaded
@test rays(pp) == rays(loaded)
@test ray_indices(maximal_cones(pp)) == ray_indices(maximal_cones(loaded))
+ @test coordinate_names(pp) == coordinate_names(loaded)
end
end
@@ -45,5 +48,15 @@
end
end
+ @testset "ToricDivisorClass" begin
+ pp = projective_space(NormalToricVariety, 2)
+ cc = volume_form(pp)
+ cc_list = [cc]
+ test_save_load_roundtrip(path, cc_list) do loaded
+ @test cc == loaded[1]
+ @test toric_variety(cc) === toric_variety(loaded[1])
+ end
+ end
+
end
end
diff --git a/test/Serialization/TropicalGeometry.jl b/test/Serialization/TropicalGeometry.jl
index 17f01e907466..7d80d1c430cf 100644
--- a/test/Serialization/TropicalGeometry.jl
+++ b/test/Serialization/TropicalGeometry.jl
@@ -10,7 +10,7 @@
end
@testset "Embedded" begin
- IM = IncidenceMatrix([[1,2],[1,3],[1,4]])
+ IM = incidence_matrix([[1,2],[1,3],[1,4]])
VR = [0 0; 1 0; -1 0; 0 1]
PC = polyhedral_complex(QQFieldElem, IM, VR)
TC = tropical_curve(PC)
diff --git a/test/Serialization/loading.jl b/test/Serialization/loading.jl
index 299688d5f1b3..346bcd4b4245 100644
--- a/test/Serialization/loading.jl
+++ b/test/Serialization/loading.jl
@@ -1,17 +1,25 @@
@testset "loading" begin
-
- @testset "loading Vector{LinearProgram}" begin
- c = cube(3)
- LP0 = linear_program(c, [2,2,-3])
- LP1 = linear_program(c, [2,2,4])
- v = [LP0, LP1]
- loaded = load(joinpath(@__DIR__,"vlp.json"))
- @test length(v) == length(loaded)
- @test feasible_region(loaded[1]) == feasible_region(loaded[2])
- @test feasible_region(loaded[1]) == feasible_region(LP0)
- @test objective_function(loaded[1]) == objective_function(v[1])
- @test objective_function(loaded[2]) == objective_function(v[2])
- @test optimal_value(loaded[1]) == optimal_value(v[1])
- @test optimal_value(loaded[2]) == optimal_value(v[2])
- end
+ @testset "loading file format paper example" begin
+ F = GF(7, 2)
+ o = gen(F)
+ Fyz, (y, z) = F[:x, :y]
+ load(joinpath(@__DIR__,"polynomial-example.mrdi");)
+ loaded = load(joinpath(@__DIR__,"polynomial-example.mrdi"); params=Fyz)
+ @test loaded == 2*y^3*z^4 + 5*o*y + (o + 3)*z^2 + 1
+ end
+
+ @testset "loading Vector{LinearProgram}" begin
+ c = cube(3)
+ LP0 = linear_program(c, [2,2,-3])
+ LP1 = linear_program(c, [2,2,4])
+ v = [LP0, LP1]
+ loaded = load(joinpath(@__DIR__,"vlp.json"))
+ @test length(v) == length(loaded)
+ @test feasible_region(loaded[1]) == feasible_region(loaded[2])
+ @test feasible_region(loaded[1]) == feasible_region(LP0)
+ @test objective_function(loaded[1]) == objective_function(v[1])
+ @test objective_function(loaded[2]) == objective_function(v[2])
+ @test optimal_value(loaded[1]) == optimal_value(v[1])
+ @test optimal_value(loaded[2]) == optimal_value(v[2])
+ end
end
diff --git a/test/Serialization/polynomial-example.mrdi b/test/Serialization/polynomial-example.mrdi
new file mode 100644
index 000000000000..0ad82300e7b4
--- /dev/null
+++ b/test/Serialization/polynomial-example.mrdi
@@ -0,0 +1,36 @@
+{
+ "_ns": { "Oscar": [ "https://github.com/oscar-system/Oscar.jl", "1.0.0" ] },
+ "_type": {
+ "name": "MPolyRingElem",
+ "params": "869a359a-43d3-43f4-9821-0af9346be019"
+ },
+ "data": [[["3", "4"], [["0", "2"]]],
+ [["0", "2"], [["0", "3"], ["1", "1"]]],
+ [["1", "0"], [["1", "5"]]],
+ [["0", "0"], [["0", "1"]]]],
+ "_refs": {
+ "152ac7bd-e85a-4b36-acc2-743ade2cad4f": {
+ "data": { "base_ring": { "data": "7", "_type": "FqField"},
+ "symbols": ["x"] },
+ "_type": "PolyRing"
+ },
+ "869a359a-43d3-43f4-9821-0af9346be019": {
+ "data": {
+ "base_ring": "a8309b96-caec-443c-bedb-e23bb0634c14",
+ "symbols": [ "y", "z" ]
+ },
+ "_type": "MPolyRing" },
+ "a8309b96-caec-443c-bedb-e23bb0634c14": {
+ "data": {
+ "def_pol": {
+ "data": [["0", "1"], ["2", "1"]],
+ "_type": {
+ "name": "PolyRingElem",
+ "params": "152ac7bd-e85a-4b36-acc2-743ade2cad4f"
+ }
+ }
+ },
+ "_type": "FqField"
+ }
+ }
+}
diff --git a/test/Serialization/upgrades/GF_2.json b/test/Serialization/upgrades/GF_2.json
new file mode 100644
index 000000000000..812d8d1a467c
--- /dev/null
+++ b/test/Serialization/upgrades/GF_2.json
@@ -0,0 +1,11 @@
+{
+ "_ns": {
+ "Oscar": [
+ "https://github.com/oscar-system/Oscar.jl",
+ "1.2.0"
+ ]
+ },
+ "_type": "FqField",
+ "data": "2",
+ "id": "4e298c21-11cb-45f1-bac0-62e2df5e6454"
+}
diff --git a/test/Serialization/upgrades/GF_2_2.json b/test/Serialization/upgrades/GF_2_2.json
new file mode 100644
index 000000000000..51d9a4e6b4da
--- /dev/null
+++ b/test/Serialization/upgrades/GF_2_2.json
@@ -0,0 +1,45 @@
+{
+ "_ns": {
+ "Oscar": [
+ "https://github.com/oscar-system/Oscar.jl",
+ "1.2.0"
+ ]
+ },
+ "_refs": {
+ "15ec4d5e-409d-4e80-a7a2-aa1b22b0db9d": {
+ "_type": "PolyRing",
+ "data": {
+ "base_ring": "4e298c21-11cb-45f1-bac0-62e2df5e6454",
+ "symbols": [
+ "x"
+ ]
+ }
+ },
+ "4e298c21-11cb-45f1-bac0-62e2df5e6454": {
+ "_type": "FqField",
+ "data": "2"
+ }
+ },
+ "_type": "FqField",
+ "data": {
+ "_type": {
+ "name": "PolyRingElem",
+ "params": "15ec4d5e-409d-4e80-a7a2-aa1b22b0db9d"
+ },
+ "data": [
+ [
+ "0",
+ "1"
+ ],
+ [
+ "1",
+ "1"
+ ],
+ [
+ "2",
+ "1"
+ ]
+ ]
+ },
+ "id": "b2e7bf06-d89a-4fea-8bf4-215a61c16ca2"
+}
diff --git a/test/Serialization/upgrades/poly1.0.5.json b/test/Serialization/upgrades/poly1.0.5.json
new file mode 100644
index 000000000000..b26acd897b02
--- /dev/null
+++ b/test/Serialization/upgrades/poly1.0.5.json
@@ -0,0 +1,110 @@
+{
+ "_ns": {
+ "Oscar": [
+ "https://github.com/oscar-system/Oscar.jl",
+ "1.0.5"
+ ]
+ },
+ "_type": {
+ "name": "MPolyRingElem",
+ "params": "f0885e3e-71ff-4813-88fd-7ee05eeb3657"
+ },
+ "data": [
+ [
+ [
+ "3",
+ "4"
+ ],
+ [
+ [
+ "0",
+ "2"
+ ]
+ ]
+ ],
+ [
+ [
+ "1",
+ "0"
+ ],
+ [
+ [
+ "1",
+ "5"
+ ]
+ ]
+ ],
+ [
+ [
+ "0",
+ "2"
+ ],
+ [
+ [
+ "0",
+ "3"
+ ],
+ [
+ "1",
+ "1"
+ ]
+ ]
+ ],
+ [
+ [
+ "0",
+ "0"
+ ],
+ [
+ [
+ "0",
+ "1"
+ ]
+ ]
+ ]
+ ],
+ "_refs": {
+ "f0885e3e-71ff-4813-88fd-7ee05eeb3657": {
+ "_type": "MPolyRing",
+ "data": {
+ "base_ring": "e06a6ac9-954b-4fb7-89c6-f2a25489440e",
+ "symbols": [
+ "y",
+ "z"
+ ]
+ }
+ },
+ "e06a6ac9-954b-4fb7-89c6-f2a25489440e": {
+ "_type": "FqField",
+ "data": {
+ "_type": {
+ "name": "PolyRingElem",
+ "params": "3a66dcbd-bd73-4bb7-8b99-42d9f5177893"
+ },
+ "data": [
+ [
+ "0",
+ "1"
+ ],
+ [
+ "2",
+ "1"
+ ]
+ ]
+ }
+ },
+ "3a66dcbd-bd73-4bb7-8b99-42d9f5177893": {
+ "_type": "PolyRing",
+ "data": {
+ "base_ring": "221dfa92-69df-4b5a-8f30-166aafddfaa9",
+ "symbols": [
+ "x"
+ ]
+ }
+ },
+ "221dfa92-69df-4b5a-8f30-166aafddfaa9": {
+ "_type": "FqField",
+ "data": "7"
+ }
+ }
+}
diff --git a/test/Serialization/upgrades/runtests.jl b/test/Serialization/upgrades/runtests.jl
index 222da8093629..851a121babe8 100644
--- a/test/Serialization/upgrades/runtests.jl
+++ b/test/Serialization/upgrades/runtests.jl
@@ -27,4 +27,11 @@
loaded = load(joinpath(@__DIR__, "file_version_less_than_1.2.0.json"));
@test loaded isa Dict
end
+
+ @testset "< 1.3.0 Upgrade" begin
+ load(joinpath(@__DIR__, "GF_2_2.json"));
+ load(joinpath(@__DIR__, "GF_2.json"));
+ Oscar.reset_global_serializer_state()
+ load(joinpath(@__DIR__, "poly1.0.5.json"));
+ end
end
diff --git a/test/book/cornerstones/algebraic-geometry/alexander-surface.jlcon b/test/book/cornerstones/algebraic-geometry/alexander-surface.jlcon
index e11ef69384e1..c770d059e81a 100644
--- a/test/book/cornerstones/algebraic-geometry/alexander-surface.jlcon
+++ b/test/book/cornerstones/algebraic-geometry/alexander-surface.jlcon
@@ -31,16 +31,16 @@ julia> A = homogeneous_coordinate_ring(X);
julia> FA = free_resolution(A);
julia> minimal_betti_table(FA)
- 0 1 2 3 4
------------------------
-0 : 1 - - - -
-1 : - - - - -
-2 : - - - - -
-3 : - - - - -
-4 : - 15 26 15 3
-5 : - 1 3 3 1
------------------------
-total: 1 16 29 18 4
+degree: 0 1 2 3 4
+------------------------
+ 0: 1 - - - -
+ 1: - - - - -
+ 2: - - - - -
+ 3: - - - - -
+ 4: - 15 26 15 3
+ 5: - 1 3 3 1
+------------------------
+ total: 1 16 29 18 4
julia> I = defining_ideal(X);
diff --git a/test/book/cornerstones/algebraic-geometry/canonicalimage.jlcon b/test/book/cornerstones/algebraic-geometry/canonicalimage.jlcon
index 535e21eb70cd..14f72936235a 100644
--- a/test/book/cornerstones/algebraic-geometry/canonicalimage.jlcon
+++ b/test/book/cornerstones/algebraic-geometry/canonicalimage.jlcon
@@ -48,14 +48,14 @@ julia> Q , _ = quo(P5, JJ);
julia> re = free_resolution(Q);
julia> minimal_betti_table(re)
- 0 1 2 3 4
----------------------
-0 : 1 - - - -
-1 : - 6 8 3 -
-2 : - 3 8 6 -
-3 : - - - - 1
----------------------
-total: 1 9 16 9 1
+degree: 0 1 2 3 4
+----------------------
+ 0: 1 - - - -
+ 1: - 6 8 3 -
+ 2: - 3 8 6 -
+ 3: - - - - 1
+----------------------
+ total: 1 9 16 9 1
julia> phi1 = hom(Rt,R,[x,y,R(1//10)]);
@@ -94,11 +94,11 @@ julia> Q , _ = quo(P5, JJ);
julia> re = free_resolution(Q);
julia> minimal_betti_table(re)
- 0 1 2 3 4
----------------------
-0 : 1 - - - -
-1 : - 6 5 - -
-2 : - - 5 6 -
-3 : - - - - 1
----------------------
-total: 1 6 10 6 1
+degree: 0 1 2 3 4
+----------------------
+ 0: 1 - - - -
+ 1: - 6 5 - -
+ 2: - - 5 6 -
+ 3: - - - - 1
+----------------------
+ total: 1 6 10 6 1
diff --git a/test/book/cornerstones/algebraic-geometry/char3-surface-1.jlcon b/test/book/cornerstones/algebraic-geometry/char3-surface-1.jlcon
index fdb0d668a212..3cb51c9331f4 100644
--- a/test/book/cornerstones/algebraic-geometry/char3-surface-1.jlcon
+++ b/test/book/cornerstones/algebraic-geometry/char3-surface-1.jlcon
@@ -7,10 +7,10 @@ julia> Qm, _ = quo(S, m);
julia> FQm = free_resolution(Qm, algorithm = :mres);
julia> betti_table(FQm)
- 0 1 2 3 4 5
----------------------------
-0 : 1 - - - - -
-1 : - 10 15 2 - -
-2 : - - 7 26 20 5
----------------------------
-total: 1 10 22 28 20 5
+degree: 0 1 2 3 4 5
+----------------------------
+ 0: 1 - - - - -
+ 1: - 10 15 2 - -
+ 2: - - 7 26 20 5
+----------------------------
+ total: 1 10 22 28 20 5
diff --git a/test/book/cornerstones/algebraic-geometry/char3-surface-2.jlcon b/test/book/cornerstones/algebraic-geometry/char3-surface-2.jlcon
index 171ccbc7a550..3acfb66800b9 100644
--- a/test/book/cornerstones/algebraic-geometry/char3-surface-2.jlcon
+++ b/test/book/cornerstones/algebraic-geometry/char3-surface-2.jlcon
@@ -19,14 +19,14 @@ julia> D = graded_cokernel(transpose(MM*NN));
julia> FD = free_resolution(D, algorithm = :mres);
julia> betti_table(FD)
- 0 1 2
-----------------
-0 : 10 10 -
-1 : - - 1
-2 : - - -
-3 : - - 1
-----------------
-total: 10 10 2
+degree: 0 1 2
+-----------------
+ 0: 10 10 -
+ 1: - - 1
+ 2: - - -
+ 3: - - 1
+-----------------
+ total: 10 10 2
julia> P = cokernel(transpose(matrix(map(FD, 2))));
@@ -37,16 +37,16 @@ julia> QI, _ = quo(S, I);
julia> FQI = free_resolution(QI, algorithm = :mres);
julia> betti_table(FQI)
- 0 1 2 3 4
------------------------
-0 : 1 - - - -
-1 : - - - - -
-2 : - - - - -
-3 : - - - - -
-4 : - 5 - - -
-5 : - 7 26 20 5
------------------------
-total: 1 12 26 20 5
+degree: 0 1 2 3 4
+------------------------
+ 0: 1 - - - -
+ 1: - - - - -
+ 2: - - - - -
+ 3: - - - - -
+ 4: - 5 - - -
+ 5: - 7 26 20 5
+------------------------
+ total: 1 12 26 20 5
julia> dim(I)
3
diff --git a/test/book/cornerstones/algebraic-geometry/circlepar.jlcon b/test/book/cornerstones/algebraic-geometry/circlepar.jlcon
index 3e92366f3372..de91b649e54c 100644
--- a/test/book/cornerstones/algebraic-geometry/circlepar.jlcon
+++ b/test/book/cornerstones/algebraic-geometry/circlepar.jlcon
@@ -4,8 +4,8 @@ julia> I = ideal(R, [x^2 + y^2 - 1, y - t*x - 1]);
julia> Gy = groebner_basis(I, ordering = lex([y, x, t]), complete_reduction=true)
Gröbner basis with elements
- 1 -> x^2*t^2 + x^2 + 2*x*t
- 2 -> y - x*t - 1
+ 1: x^2*t^2 + x^2 + 2*x*t
+ 2: y - x*t - 1
with respect to the ordering
lex([y, x, t])
@@ -14,10 +14,10 @@ julia> factor(Gy[1])
julia> Gx = groebner_basis(I, ordering = lex([x, y, t]), complete_reduction=true)
Gröbner basis with elements
- 1 -> y^2*t^2 + y^2 - 2*y - t^2 + 1
- 2 -> x*t - y + 1
- 3 -> x*y - x + y^2*t - t
- 4 -> x^2 + y^2 - 1
+ 1: y^2*t^2 + y^2 - 2*y - t^2 + 1
+ 2: x*t - y + 1
+ 3: x*y - x + y^2*t - t
+ 4: x^2 + y^2 - 1
with respect to the ordering
lex([x, y, t])
diff --git a/test/book/cornerstones/algebraic-geometry/ex11.jlcon b/test/book/cornerstones/algebraic-geometry/ex11.jlcon
index 3f903771e98b..ff56bef0b7de 100644
--- a/test/book/cornerstones/algebraic-geometry/ex11.jlcon
+++ b/test/book/cornerstones/algebraic-geometry/ex11.jlcon
@@ -4,8 +4,8 @@ julia> I = ideal(R, [x^2+y^2+2*z^2-8, x^2-y^2-z^2+1, x-y+z]);
julia> groebner_basis(I, ordering = lex(R), complete_reduction = true)
Gröbner basis with elements
- 1 -> 6*z^4 - 18*z^2 + 1
- 2 -> y + 3*z^3 - 9*z
- 3 -> x + 3*z^3 - 8*z
+ 1: 6*z^4 - 18*z^2 + 1
+ 2: y + 3*z^3 - 9*z
+ 3: x + 3*z^3 - 8*z
with respect to the ordering
lex([x, y, z])
diff --git a/test/book/cornerstones/algebraic-geometry/ex314.jlcon b/test/book/cornerstones/algebraic-geometry/ex314.jlcon
index 3a15caec9592..dc5c7b375da0 100644
--- a/test/book/cornerstones/algebraic-geometry/ex314.jlcon
+++ b/test/book/cornerstones/algebraic-geometry/ex314.jlcon
@@ -25,21 +25,21 @@ julia> p1 == ideal(minors(m3x3[1:3, 1:2],2))
true
julia> mp1 = ideal_as_module(p1)
-Graded submodule of S^1
-1 -> (-x_1*x_3 + x_2^2)*e[1]
-2 -> (-x_0*x_3 + x_1*x_2)*e[1]
-3 -> (-x_0*x_2 + x_1^2)*e[1]
+Graded submodule of S^1 with 3 generators
+ 1: (-x_1*x_3 + x_2^2)*e[1]
+ 2: (-x_0*x_3 + x_1*x_2)*e[1]
+ 3: (-x_0*x_2 + x_1^2)*e[1]
represented as subquotient with no relations
julia> M1, _ = quo(ambient_free_module(mp1), mp1);
julia> M1
-Graded subquotient of submodule of S^1 generated by
-1 -> e[1]
-by submodule of S^1 generated by
-1 -> (-x_1*x_3 + x_2^2)*e[1]
-2 -> (-x_0*x_3 + x_1*x_2)*e[1]
-3 -> (-x_0*x_2 + x_1^2)*e[1]
+Graded subquotient of graded submodule of S^1 with 1 generator
+ 1: e[1]
+by graded submodule of S^1 with 3 generators
+ 1: (-x_1*x_3 + x_2^2)*e[1]
+ 2: (-x_0*x_3 + x_1*x_2)*e[1]
+ 3: (-x_0*x_2 + x_1^2)*e[1]
julia> mJ = ideal_as_module(J);
@@ -50,13 +50,13 @@ julia> homM1M, psi = hom(M1, M);
julia> hom1, tohomM1M = prune_with_map(homM1M);
julia> hom1
-Graded subquotient of submodule of S^2 generated by
-1 -> e[1]
-2 -> e[2]
-by submodule of S^2 generated by
-1 -> -x_2*e[1] + x_3*e[2]
-2 -> x_0*e[1] - x_1*e[2]
-3 -> -x_1*e[1] + x_2*e[2]
+Graded subquotient of graded submodule of S^2 with 2 generators
+ 1: e[1]
+ 2: e[2]
+by graded submodule of S^2 with 3 generators
+ 1: -x_2*e[1] + x_3*e[2]
+ 2: x_0*e[1] - x_1*e[2]
+ 3: -x_1*e[1] + x_2*e[2]
julia> degrees_of_generators(hom1)
2-element Vector{FinGenAbGroupElem}:
@@ -64,16 +64,18 @@ julia> degrees_of_generators(hom1)
[2]
julia> phi1 = psi(tohomM1M(hom1[1]))
-M1 -> M
-e[1] -> (-x_0*x_3 + x_1*x_2)*e[1]
Graded module homomorphism of degree [2]
-
+ from M1
+ to M
+defined by
+ e[1] -> (-x_0*x_3 + x_1*x_2)*e[1]
julia> phi2 = psi(tohomM1M(hom1[2]))
-M1 -> M
-e[1] -> (-x_0*x_2 + x_1^2)*e[1]
Graded module homomorphism of degree [2]
-
+ from M1
+ to M
+defined by
+ e[1] -> (-x_0*x_2 + x_1^2)*e[1]
julia> kerphi2, _ = kernel(phi2);
@@ -81,12 +83,12 @@ julia> iszero(kerphi2)
true
julia> MmodM1 = cokernel(phi2)
-Graded subquotient of submodule of S^1 generated by
-1 -> e[1]
-by submodule of S^1 generated by
-1 -> (x_1*x_3 - x_2^2)*e[1]
-2 -> (-x_0^2*x_3 + 2*x_0*x_1*x_2 - x_1^3)*e[1]
-3 -> (-x_0*x_2 + x_1^2)*e[1]
+Graded subquotient of graded submodule of S^1 with 1 generator
+ 1: e[1]
+by graded submodule of S^1 with 3 generators
+ 1: (x_1*x_3 - x_2^2)*e[1]
+ 2: (-x_0^2*x_3 + 2*x_0*x_1*x_2 - x_1^3)*e[1]
+ 3: (-x_0*x_2 + x_1^2)*e[1]
julia> p2 = ideal([x[1],x[2],x[3]])
Ideal generated by
diff --git a/test/book/cornerstones/algebraic-geometry/exres.jlcon b/test/book/cornerstones/algebraic-geometry/exres.jlcon
index 087305294474..8e046ee48250 100644
--- a/test/book/cornerstones/algebraic-geometry/exres.jlcon
+++ b/test/book/cornerstones/algebraic-geometry/exres.jlcon
@@ -1,44 +1,50 @@
-julia> R, (w, x, y, z) = graded_polynomial_ring(QQ, ["w", "x", "y", "z"]);
+julia> S, (w, x, y, z) = graded_polynomial_ring(QQ, ["w", "x", "y", "z"]);
-julia> I = ideal([w^2-x*z,w*x-y*z,x^2-w*y,x*y-z^2,y^2-w*z]);
+julia> J = ideal([w^2-x*z,w*x-y*z,x^2-w*y,x*y-z^2,y^2-w*z]);
-julia> A, _ = quo(R, I);
+julia> A, _ = quo(S, J);
julia> FA = free_resolution(A)
Free resolution of A
-R^1 <---- R^5 <---- R^6 <---- R^2 <---- 0
+S^1 <---- S^5 <---- S^6 <---- S^2 <---- 0
0 1 2 3 4
julia> FA[1]
-Graded free module R^5([-2]) of rank 5 over R
+Graded free module S^5([-2]) of rank 5 over S
julia> FA[2]
-Graded free module R^5([-3]) + R^1([-4]) of rank 6 over R
+Graded free module S^5([-3]) + S^1([-4]) of rank 6 over S
julia> FA[3]
-Graded free module R^1([-4]) + R^1([-5]) of rank 2 over R
+Graded free module S^1([-4]) + S^1([-5]) of rank 2 over S
julia> map(FA,1)
-R^5 -> R^1
-e[1] -> (-w*z + y^2)*e[1]
-e[2] -> (x*y - z^2)*e[1]
-e[3] -> (-w*y + x^2)*e[1]
-e[4] -> (w*x - y*z)*e[1]
-e[5] -> (w^2 - x*z)*e[1]
Homogeneous module homomorphism
+ from S^5
+ to S^1
+defined by
+ e[1] -> (-w*z + y^2)*e[1]
+ e[2] -> (x*y - z^2)*e[1]
+ e[3] -> (-w*y + x^2)*e[1]
+ e[4] -> (w*x - y*z)*e[1]
+ e[5] -> (w^2 - x*z)*e[1]
julia> map(FA,2)
-R^6 -> R^5
-e[1] -> -x*e[1] + y*e[2] - z*e[4]
-e[2] -> w*e[1] - x*e[2] + y*e[3] + z*e[5]
-e[3] -> -w*e[3] + x*e[4] - y*e[5]
-e[4] -> z*e[1] - w*e[2] + y*e[4]
-e[5] -> z*e[3] - w*e[4] + x*e[5]
-e[6] -> (-w^2 + x*z)*e[1] + (-w*z + y^2)*e[5]
Homogeneous module homomorphism
+ from S^6
+ to S^5
+defined by
+ e[1] -> -x*e[1] + y*e[2] - z*e[4]
+ e[2] -> w*e[1] - x*e[2] + y*e[3] + z*e[5]
+ e[3] -> -w*e[3] + x*e[4] - y*e[5]
+ e[4] -> z*e[1] - w*e[2] + y*e[4]
+ e[5] -> z*e[3] - w*e[4] + x*e[5]
+ e[6] -> (-w^2 + x*z)*e[1] + (-w*z + y^2)*e[5]
julia> map(FA,3)
-R^2 -> R^6
-e[1] -> -w*e[2] - y*e[3] + x*e[4] - e[6]
-e[2] -> (-w^2 + x*z)*e[1] + y*z*e[2] + z^2*e[3] - w*y*e[4] + (w*z - y^2)*e[5] + x*e[6]
Homogeneous module homomorphism
+ from S^2
+ to S^6
+defined by
+ e[1] -> -w*e[2] - y*e[3] + x*e[4] - e[6]
+ e[2] -> (-w^2 + x*z)*e[1] + y*z*e[2] + z^2*e[3] - w*y*e[4] + (w*z - y^2)*e[5] + x*e[6]
diff --git a/test/book/cornerstones/algebraic-geometry/exres2.jlcon b/test/book/cornerstones/algebraic-geometry/exres2.jlcon
index 3181f5c529ed..a1fc8c1d7e17 100644
--- a/test/book/cornerstones/algebraic-geometry/exres2.jlcon
+++ b/test/book/cornerstones/algebraic-geometry/exres2.jlcon
@@ -1,17 +1,17 @@
julia> betti_table(FA)
- 0 1 2 3
------------------
-0 : 1 - - -
-1 : - 5 5 1
-2 : - - 1 1
------------------
-total: 1 5 6 2
+degree: 0 1 2 3
+------------------
+ 0: 1 - - -
+ 1: - 5 5 1
+ 2: - - 1 1
+------------------
+ total: 1 5 6 2
julia> minimal_betti_table(FA)
- 0 1 2 3
------------------
-0 : 1 - - -
-1 : - 5 5 -
-2 : - - - 1
------------------
-total: 1 5 5 1
+degree: 0 1 2 3
+------------------
+ 0: 1 - - -
+ 1: - 5 5 -
+ 2: - - - 1
+------------------
+ total: 1 5 5 1
diff --git a/test/book/cornerstones/algebraic-geometry/hilbert-polynomial.jlcon b/test/book/cornerstones/algebraic-geometry/hilbert-polynomial.jlcon
index f35655f922e3..3bba333557af 100644
--- a/test/book/cornerstones/algebraic-geometry/hilbert-polynomial.jlcon
+++ b/test/book/cornerstones/algebraic-geometry/hilbert-polynomial.jlcon
@@ -1,6 +1,6 @@
-julia> R, (w,x,y,z) = graded_polynomial_ring(QQ, ["w", "x", "y", "z"]);
+julia> S, (w,x,y,z) = graded_polynomial_ring(QQ, ["w", "x", "y", "z"]);
-julia> I = ideal(R, [x*w-y*z, y*w-(x-z)*(x-2*z)]);
+julia> I = ideal(S, [x*w-y*z, y*w-(x-z)*(x-2*z)]);
julia> Q = projective_scheme(I);
diff --git a/test/book/cornerstones/algebraic-geometry/param.jlcon b/test/book/cornerstones/algebraic-geometry/param.jlcon
index b8e9dbe6e490..13a57fc54342 100644
--- a/test/book/cornerstones/algebraic-geometry/param.jlcon
+++ b/test/book/cornerstones/algebraic-geometry/param.jlcon
@@ -33,11 +33,11 @@ Projective curve
defined by ideal with 3 generators
julia> betti(free_resolution(defining_ideal(D)))
- 0 1
------------
-2 : 3 2
------------
-total: 3 2
+degree: 0 1
+------------
+ 2: 3 2
+------------
+ total: 3 2
julia> Oscar.rat_normal_curve_anticanonical_map(D)
2-element Vector{MPolyDecRingElem{QQFieldElem, QQMPolyRingElem}}:
diff --git a/test/book/cornerstones/groups/actions.jlcon b/test/book/cornerstones/groups/actions.jlcon
index af50427d42b8..8afa776b146e 100644
--- a/test/book/cornerstones/groups/actions.jlcon
+++ b/test/book/cornerstones/groups/actions.jlcon
@@ -3,8 +3,7 @@ G-set of
Alt(4)
with seeds 1:4
-julia> G = dihedral_group(6)
-Pc group of order 6
+julia> G = dihedral_group(6);
julia> U = sub(G, [g for g in gens(G) if order(g) == 2])[1]
Sub-pc group of order 2
@@ -18,7 +17,7 @@ julia> acting_group(r)
Pc group of order 6
julia> collect(r)
-3-element Vector{GroupCoset{PcGroup, PcGroupElem}}:
+3-element Vector{GroupCoset{PcGroup, SubPcGroup, PcGroupElem}}:
Right coset of U with representative of ...
Right coset of U with representative f2
Right coset of U with representative f2^2
@@ -37,7 +36,7 @@ Group homomorphism
julia> phi(G[1]), phi(G[2])
((2,3), (1,2,3))
-julia> function optimal_perm_rep(G)
+julia> function optimal_transitive_perm_rep(G)
is_natural_symmetric_group(G) && return hom(G,G,gens(G))
is_natural_alternating_group(G) && return hom(G,G,gens(G))
cand = [] # pairs (U,h) with U ≤ G and h a map G -> Sym(G/U)
@@ -52,7 +51,7 @@ julia> function optimal_perm_rep(G)
julia> U = dihedral_group(8)
Pc group of order 8
-julia> optimal_perm_rep(U)
+julia> optimal_transitive_perm_rep(U)
Group homomorphism
from pc group of order 8
to permutation group of degree 4 and order 8
@@ -65,8 +64,8 @@ Group homomorphism
julia> permutation_group(U)
Permutation group of degree 4 and order 8
-julia> for g in all_transitive_groups(degree => 3:9, !is_primitive)
- h = image(optimal_perm_rep(g))[1]
+julia> for g in all_transitive_groups(degree => 3:8, !is_primitive)
+ h = image(optimal_transitive_perm_rep(g))[1]
if degree(h) < degree(g)
id = transitive_group_identification(g)
id_new = transitive_group_identification(h)
@@ -81,5 +80,3 @@ julia> for g in all_transitive_groups(degree => 3:9, !is_primitive)
(8, 13) => (6, 6)
(8, 14) => (4, 5)
(8, 24) => (6, 11)
-(9, 4) => (6, 5)
-(9, 8) => (6, 9)
diff --git a/test/book/cornerstones/groups/intro.jlcon b/test/book/cornerstones/groups/intro.jlcon
index 20e0e4f98c9a..4ae590df2d08 100644
--- a/test/book/cornerstones/groups/intro.jlcon
+++ b/test/book/cornerstones/groups/intro.jlcon
@@ -62,13 +62,7 @@ julia> pts = collect(orb)
julia> visualize(convex_hull(pts))
-julia> R2 = free_module(K, 2) # the "euclidean" plane over K
-Vector space of dimension 2 over QQBar
-
-julia> A = R2([0,1])
-(Root 0 of x, Root 1.00000 of x - 1)
-
-julia> pts = [A*mat_rot^i for i in 0:4];
+julia> R2 = vector_space(K, 2); # the "euclidean" plane over K
julia> sigma_1 = hom(R2, R2, [-R2[1], R2[2]])
Module homomorphism
diff --git a/test/book/cornerstones/number-theory/galoismod.jlcon b/test/book/cornerstones/number-theory/galoismod.jlcon
index 64c37466576c..6a1b22c4ba50 100644
--- a/test/book/cornerstones/number-theory/galoismod.jlcon
+++ b/test/book/cornerstones/number-theory/galoismod.jlcon
@@ -52,9 +52,9 @@ true
julia> V, f = galois_module(K); OK = ring_of_integers(K); M = f(OK);
-julia> fl, c = is_free_with_basis(M); # the elements of c are a basis
+julia> fl, c = is_free_with_basis(M); # the elements of c form a basis
-julia> b = preimage(f, c[1]) # the element might different per session
+julia> b = preimage(f, c[1]) # the element may be different per session
a^3
julia> A, mA = automorphism_group(K);
diff --git a/test/book/cornerstones/number-theory/galoismod_1.jl b/test/book/cornerstones/number-theory/galoismod_1.jlcon
similarity index 100%
rename from test/book/cornerstones/number-theory/galoismod_1.jl
rename to test/book/cornerstones/number-theory/galoismod_1.jlcon
diff --git a/test/book/cornerstones/number-theory/galoismod_2.jl b/test/book/cornerstones/number-theory/galoismod_2.jlcon
similarity index 100%
rename from test/book/cornerstones/number-theory/galoismod_2.jl
rename to test/book/cornerstones/number-theory/galoismod_2.jlcon
diff --git a/test/book/cornerstones/number-theory/intro.jlcon b/test/book/cornerstones/number-theory/intro.jlcon
index 55237aeef016..b1a77a32dd84 100644
--- a/test/book/cornerstones/number-theory/intro.jlcon
+++ b/test/book/cornerstones/number-theory/intro.jlcon
@@ -94,4 +94,4 @@ julia> preimage(mU, -214841715*a - 3293461126)
Abelian group element [1, 5]
julia> -214841715*a - 3293461126 == (-1)^1 * (3a + 46)^5
-true
\ No newline at end of file
+true
diff --git a/test/book/cornerstones/number-theory/sym_1.jl b/test/book/cornerstones/number-theory/sym_1.jlcon
similarity index 100%
rename from test/book/cornerstones/number-theory/sym_1.jl
rename to test/book/cornerstones/number-theory/sym_1.jlcon
diff --git a/test/book/cornerstones/number-theory/unit_log_plot.jl b/test/book/cornerstones/number-theory/unit_log_plot.jlcon
similarity index 100%
rename from test/book/cornerstones/number-theory/unit_log_plot.jl
rename to test/book/cornerstones/number-theory/unit_log_plot.jlcon
diff --git a/test/book/cornerstones/polyhedral-geometry/GKZ_orbits.jlcon b/test/book/cornerstones/polyhedral-geometry/GKZ_orbits.jlcon
index 1524f987593e..6d47634cc605 100644
--- a/test/book/cornerstones/polyhedral-geometry/GKZ_orbits.jlcon
+++ b/test/book/cornerstones/polyhedral-geometry/GKZ_orbits.jlcon
@@ -15,8 +15,7 @@ julia> OrbitRepresentatives=
julia> OrbitSizes =
[length(
filter(x->minimum(gset(G,permuted,[x]))==u,
- GKZ_Vectors)
- ) for u in OrbitRepresentatives];
+ GKZ_Vectors)) for u in OrbitRepresentatives];
julia> show(OrbitSizes)
[12, 24, 24, 8, 2, 4]
diff --git a/test/book/cornerstones/polyhedral-geometry/pentagon.jlcon b/test/book/cornerstones/polyhedral-geometry/pentagon.jlcon
index cf96a5f18ba5..e15935e9bb47 100644
--- a/test/book/cornerstones/polyhedral-geometry/pentagon.jlcon
+++ b/test/book/cornerstones/polyhedral-geometry/pentagon.jlcon
@@ -4,7 +4,7 @@ julia> P = convex_hull(points)
Polyhedron in ambient dimension 2
julia> facets(P)
-5-element SubObjectIterator{AffineHalfspace{QQFieldElem}} over the Halfspaces of R^2 described by:
+5-element SubObjectIterator{AffineHalfspace{QQFieldElem}} over the halfspaces of R^2 described by:
-x_1 <= 1
-x_1 + x_2 <= 1
x_1 - 2*x_2 <= 1
diff --git a/test/book/cornerstones/polyhedral-geometry/platonic.jlcon b/test/book/cornerstones/polyhedral-geometry/platonic.jlcon
index 5be3803224d1..f216bce0e5cd 100644
--- a/test/book/cornerstones/polyhedral-geometry/platonic.jlcon
+++ b/test/book/cornerstones/polyhedral-geometry/platonic.jlcon
@@ -1,4 +1,5 @@
-julia> [ f_vector(P) for P in [T, cube(3), cross_polytope(3), dodecahedron(), icosahedron()] ]
+julia> [ f_vector(P) for P in [T, cube(3), cross_polytope(3),
+ dodecahedron(), icosahedron()] ]
5-element Vector{Vector{ZZRingElem}}:
[4, 6, 4]
[8, 12, 6]
diff --git a/test/book/ordered_examples.json b/test/book/ordered_examples.json
index 9100288ceb77..37c1e387f0a9 100644
--- a/test/book/ordered_examples.json
+++ b/test/book/ordered_examples.json
@@ -2,58 +2,58 @@
"_ns": {
"Oscar": [
"https://github.com/oscar-system/Oscar.jl",
- "1.0.0"
+ "1.0.4"
]
},
"_type": {
"name": "Dict",
"params": {
"key_type": "String",
- "specialized/boehm-breuer-git-fans": {
+ "cornerstones/groups": {
"name": "Vector",
"params": "String"
},
- "specialized/markwig-ristau-schleis-faithful-tropicalization": {
+ "specialized/boehm-breuer-git-fans": {
"name": "Vector",
"params": "String"
},
- "specialized/holt-ren-tropical-geometry": {
+ "specialized/markwig-ristau-schleis-faithful-tropicalization": {
"name": "Vector",
"params": "String"
},
- "specialized/bies-turner-string-theory-applications": {
+ "introduction/introduction": {
"name": "Vector",
"params": "String"
},
- "specialized/aga-boehm-hoffmann-markwig-traore": {
+ "specialized/holt-ren-tropical-geometry": {
"name": "Vector",
"params": "String"
},
- "specialized/joswig-kastner-lorenz-confirmable-workflows": {
+ "specialized/eder-mohr-ideal-theoretic": {
"name": "Vector",
"params": "String"
},
- "cornerstones/number-theory": {
+ "specialized/bies-turner-string-theory-applications": {
"name": "Vector",
"params": "String"
},
- "cornerstones/groups": {
+ "specialized/kuehne-schroeter-matroids": {
"name": "Vector",
"params": "String"
},
- "introduction/introduction": {
+ "specialized/aga-boehm-hoffmann-markwig-traore": {
"name": "Vector",
"params": "String"
},
- "specialized/eder-mohr-ideal-theoretic": {
+ "cornerstones/polyhedral-geometry": {
"name": "Vector",
"params": "String"
},
- "specialized/kuehne-schroeter-matroids": {
+ "specialized/fang-fourier-monomial-bases": {
"name": "Vector",
"params": "String"
},
- "cornerstones/polyhedral-geometry": {
+ "specialized/joswig-kastner-lorenz-confirmable-workflows": {
"name": "Vector",
"params": "String"
},
@@ -61,15 +61,15 @@
"name": "Vector",
"params": "String"
},
- "specialized/fang-fourier-monomial-bases": {
+ "specialized/brandhorst-zach-fibration-hopping": {
"name": "Vector",
"params": "String"
},
- "specialized/brandhorst-zach-fibration-hopping": {
+ "specialized/breuer-nebe-parker-orthogonal-discriminants": {
"name": "Vector",
"params": "String"
},
- "specialized/breuer-nebe-parker-orthogonal-discriminants": {
+ "cornerstones/number-theory": {
"name": "Vector",
"params": "String"
},
@@ -88,6 +88,16 @@
}
},
"data": {
+ "cornerstones/groups": [
+ "intro.jlcon",
+ "actions.jlcon",
+ "explSL25.jlcon",
+ "chars.jlcon",
+ "extensions.jlcon",
+ "cohomology.jlcon",
+ "reps.jlcon",
+ "genchar.jlcon"
+ ],
"specialized/boehm-breuer-git-fans": [
"explG25_1.jlcon",
"explG25_2.jlcon",
@@ -107,6 +117,12 @@
"eliminate_xz.jlcon",
"eliminate_yz.jlcon"
],
+ "introduction/introduction": [
+ "julia.jlcon",
+ "julia-jit.jlcon",
+ "julia2.jlcon",
+ "julia3.jlcon"
+ ],
"specialized/holt-ren-tropical-geometry": [
"semiring.jlcon",
"matrixAndPoly.jlcon",
@@ -127,50 +143,6 @@
"intersection.jlcon",
"grc.jlcon"
],
- "specialized/bies-turner-string-theory-applications": [
- "SU5.jlcon",
- "SU5-2.jlcon"
- ],
- "specialized/aga-boehm-hoffmann-markwig-traore": [
- "graphname.jlcon",
- "Caterpillar3.jlcon"
- ],
- "specialized/joswig-kastner-lorenz-confirmable-workflows": [
- "versioninfo.jlcon",
- "polynomial-load.jlcon",
- "snf.jlcon"
- ],
- "cornerstones/number-theory": [
- "intro.jlcon",
- "intro_plot_lattice.jlcon",
- "unit_plot.jlcon",
- "unit_log_plot.jl",
- "general.jlcon",
- "embeddings.jlcon",
- "intro4.jlcon",
- "sym.jlcon",
- "sym_1.jl",
- "cohenlenstra.jlcon",
- "galoismod.jlcon",
- "galoismod_1.jl",
- "galoismod_2.jl"
- ],
- "cornerstones/groups": [
- "intro.jlcon",
- "actions.jlcon",
- "explSL25.jlcon",
- "chars.jlcon",
- "extensions.jlcon",
- "cohomology.jlcon",
- "reps.jlcon",
- "genchar.jlcon"
- ],
- "introduction/introduction": [
- "julia.jlcon",
- "julia-jit.jlcon",
- "julia2.jlcon",
- "julia3.jlcon"
- ],
"specialized/eder-mohr-ideal-theoretic": [
"hilbert.jlcon",
"gbeliminate.jlcon",
@@ -181,11 +153,19 @@
"combinatorics.jlcon",
"lcis.jlcon"
],
+ "specialized/bies-turner-string-theory-applications": [
+ "SU5.jlcon",
+ "SU5-2.jlcon"
+ ],
"specialized/kuehne-schroeter-matroids": [
"basics.jlcon",
"realization_space.jlcon",
"ChowRings.jlcon"
],
+ "specialized/aga-boehm-hoffmann-markwig-traore": [
+ "graphname.jlcon",
+ "Caterpillar3.jlcon"
+ ],
"cornerstones/polyhedral-geometry": [
"pentagon.jlcon",
"lp.jlcon",
@@ -210,6 +190,22 @@
"GKZ_orbits.jlcon",
"ch-benchmark.jlcon"
],
+ "specialized/fang-fourier-monomial-bases": [
+ "get-operators.jlcon",
+ "basis.jlcon",
+ "fflv.jlcon",
+ "string.jlcon",
+ "lusztig.jlcon",
+ "nz.jlcon",
+ "sl7-cases.jlcon",
+ "oscar-vs-gap.jlcon",
+ "gap.jlcon"
+ ],
+ "specialized/joswig-kastner-lorenz-confirmable-workflows": [
+ "versioninfo.jlcon",
+ "polynomial-load.jlcon",
+ "snf.jlcon"
+ ],
"specialized/rose-sturmfels-telen-tropical-implicitization": [
"gen_impl.jlcon",
"hyperdet.jlcon",
@@ -220,14 +216,6 @@
"chow_fan.jlcon",
"chow_transl.jlcon"
],
- "specialized/fang-fourier-monomial-bases": [
- "get-operators.jlcon",
- "basis.jlcon",
- "fflv.jlcon",
- "string.jlcon",
- "lusztig.jlcon",
- "nz.jlcon"
- ],
"specialized/brandhorst-zach-fibration-hopping": [
"vinberg_1.jlcon",
"vinberg_2.jlcon"
@@ -244,6 +232,21 @@
"expl_od_odd.jlcon",
"expl_plusminus.jlcon"
],
+ "cornerstones/number-theory": [
+ "intro.jlcon",
+ "intro_plot_lattice.jlcon",
+ "unit_plot.jlcon",
+ "unit_log_plot.jlcon",
+ "general.jlcon",
+ "embeddings.jlcon",
+ "intro4.jlcon",
+ "sym.jlcon",
+ "sym_1.jlcon",
+ "cohenlenstra.jlcon",
+ "galoismod.jlcon",
+ "galoismod_1.jlcon",
+ "galoismod_2.jlcon"
+ ],
"cornerstones/algebraic-geometry": [
"ex11.jlcon",
"ex11dist.jlcon",
diff --git a/test/book/specialized/bies-kastner-toric-geometry/p1xp1_cohomologies.jlcon b/test/book/specialized/bies-kastner-toric-geometry/p1xp1_cohomologies.jlcon
index 2971bee5b265..c6da260e5df0 100644
--- a/test/book/specialized/bies-kastner-toric-geometry/p1xp1_cohomologies.jlcon
+++ b/test/book/specialized/bies-kastner-toric-geometry/p1xp1_cohomologies.jlcon
@@ -1,4 +1,4 @@
-julia> P1 = projective_space(NormalToricVariety,1)
+julia> P1 = projective_space(NormalToricVariety, 1)
Normal toric variety
julia> l = toric_line_bundle(P1*P1, [-3,1])
diff --git a/test/book/specialized/bies-kastner-toric-geometry/p1xp1_vanishing_sets.jlcon b/test/book/specialized/bies-kastner-toric-geometry/p1xp1_vanishing_sets.jlcon
index 4d412ab3c970..2cad9f47490e 100644
--- a/test/book/specialized/bies-kastner-toric-geometry/p1xp1_vanishing_sets.jlcon
+++ b/test/book/specialized/bies-kastner-toric-geometry/p1xp1_vanishing_sets.jlcon
@@ -1,4 +1,4 @@
-julia> P1 = projective_space(NormalToricVariety,1)
+julia> P1 = projective_space(NormalToricVariety, 1)
Normal toric variety
julia> v0, v1, v2 = vanishing_sets(P1*P1)
diff --git a/test/book/specialized/bies-turner-string-theory-applications/SU5-2.jlcon b/test/book/specialized/bies-turner-string-theory-applications/SU5-2.jlcon
index 98cb9c604347..616ab616fe01 100644
--- a/test/book/specialized/bies-turner-string-theory-applications/SU5-2.jlcon
+++ b/test/book/specialized/bies-turner-string-theory-applications/SU5-2.jlcon
@@ -11,18 +11,3 @@ Global Tate model over a concrete base -- SU(5)xU(1) restricted Tate model based
julia> t5 = resolve(t, 1)
Partially resolved global Tate model over a concrete base -- SU(5)xU(1) restricted Tate model based on arXiv paper 1109.3454 Eq. (3.1)
-
-julia> cox_ring(ambient_space(t5))
-Multivariate polynomial ring in 12 variables over QQ graded by
- x1 -> [1 0 0 0 0 0 0]
- x2 -> [0 1 0 0 0 0 0]
- x3 -> [0 1 0 0 0 0 0]
- x4 -> [0 1 0 0 0 0 0]
- x -> [0 0 1 0 0 0 0]
- y -> [0 0 0 1 0 0 0]
- z -> [0 0 0 0 1 0 0]
- e1 -> [0 0 0 0 0 1 0]
- e4 -> [0 0 0 0 0 0 1]
- e2 -> [-1 -3 -1 1 -1 -1 0]
- e3 -> [0 4 1 -1 1 0 -1]
- s -> [2 6 -1 0 2 1 1]
diff --git a/test/book/specialized/breuer-nebe-parker-orthogonal-discriminants/expl_G23_tbl.jlcon b/test/book/specialized/breuer-nebe-parker-orthogonal-discriminants/expl_G23_tbl.jlcon
index 79c5af782859..8245714a6134 100644
--- a/test/book/specialized/breuer-nebe-parker-orthogonal-discriminants/expl_G23_tbl.jlcon
+++ b/test/book/specialized/breuer-nebe-parker-orthogonal-discriminants/expl_G23_tbl.jlcon
@@ -1,17 +1,17 @@
julia> Oscar.OrthogonalDiscriminants.show_with_ODs(
-character_table("G2(3)", 2))
+ character_table("G2(3)", 2))
G2(3)mod2
- 2 6 3 3 . 1 1 . . . . . .
- 3 6 6 6 6 4 4 . 3 3 3 . .
- 7 1 . . . . . 1 . . . . .
- 13 1 . . . . . . . . . 1 1
-
- 1a 3a 3b 3c 3d 3e 7a 9a 9b 9c 13a 13b
- 2P 1a 3a 3b 3c 3d 3e 7a 9a 9c 9b 13b 13a
- 3P 1a 1a 1a 1a 1a 1a 7a 3c 3c 3c 13a 13b
- 7P 1a 3a 3b 3c 3d 3e 1a 9a 9b 9c 13b 13a
- 13P 1a 3a 3b 3c 3d 3e 7a 9a 9b 9c 1a 1a
+ 2 6 3 3 . 1 1 . . . . . .
+ 3 6 6 6 6 4 4 . 3 3 3 . .
+ 7 1 . . . . . 1 . . . . .
+ 13 1 . . . . . . . . . 1 1
+
+ 1a 3a 3b 3c 3d 3e 7a 9a 9b 9c 13a 13b
+ 2P 1a 3a 3b 3c 3d 3e 7a 9a 9c 9b 13b 13a
+ 3P 1a 1a 1a 1a 1a 1a 7a 3c 3c 3c 13a 13b
+ 7P 1a 3a 3b 3c 3d 3e 1a 9a 9b 9c 13b 13a
+ 13P 1a 3a 3b 3c 3d 3e 7a 9a 9b 9c 1a 1a
d OD 2
X_1 1 + 1 1 1 1 1 1 1 1 1 1 1 1
X_2 1 O- + 14 5 5 -4 2 -1 . 2 -1 -1 1 1
@@ -29,4 +29,4 @@ X_12 1 O+ + 832 -32 -32 -5 4 4 -1 1 1 1 . .
A = 3z_3 + 1
/A = -3z_3 - 2
B = -z_13^11 - z_13^8 - z_13^7 - z_13^6 - z_13^5 - z_13^2 - 1
-B* = z_13^11 + z_13^8 + z_13^7 + z_13^6 + z_13^5 + z_13^2
\ No newline at end of file
+B* = z_13^11 + z_13^8 + z_13^7 + z_13^6 + z_13^5 + z_13^2
diff --git a/test/book/specialized/decker-schmitt-invariant-theory/H3.jlcon b/test/book/specialized/decker-schmitt-invariant-theory/H3.jlcon
index 3c7ed37b97b5..8aa239d34316 100644
--- a/test/book/specialized/decker-schmitt-invariant-theory/H3.jlcon
+++ b/test/book/specialized/decker-schmitt-invariant-theory/H3.jlcon
@@ -47,22 +47,22 @@ julia> [[ kernel(reduce(hcat, [ K[coeff(p, x); coeff(p, y); coeff(p, z)] for p i
1-element Vector{Vector{AbstractAlgebra.Generic.MatSpaceElem{AbsSimpleNumFieldElem}}}:
[[a+1 0 1], [-a 0 1], [-1 0 1], [0 a+1 1], [0 -a 1], [0 -1 1], [-a 1 0], [a+1 1 0], [-1 1 0]]
-julia> T, t = polynomial_ring(QQ, "t")
-(Univariate polynomial ring in t over QQ, t)
+julia> S, s = QQ["t"]; T = fraction_field(S); t = T(s);
julia> RR, (X, Y, Z) = graded_polynomial_ring(T, [ "X", "Y", "Z"]);
julia> F = X^3+Y^3+Z^3;
-julia> G = t*F+hessian(F);
+julia> G = t*F+hessian(F)
+t*X^3 + 216*X*Y*Z + t*Y^3 + t*Z^3
julia> L = syzygy_generators([hessian(G), F, hessian(F)]);
julia> collect(coefficients(L[1]))
-3-element Vector{QQPolyRingElem}:
- 1
- 279936*t
- -t^3 - 93312
+3-element Vector{AbstractAlgebra.Generic.FracFieldElem{QQPolyRingElem}}:
+ -1
+ -279936*t
+ t^3 + 93312
julia> C, iC = center(H3);
diff --git a/test/book/specialized/decker-schmitt-invariant-theory/bertin.jlcon b/test/book/specialized/decker-schmitt-invariant-theory/bertin.jlcon
index 0403110b4fcd..2d3e88c4b5b6 100644
--- a/test/book/specialized/decker-schmitt-invariant-theory/bertin.jlcon
+++ b/test/book/specialized/decker-schmitt-invariant-theory/bertin.jlcon
@@ -20,11 +20,11 @@ julia> secondary_invariants(RG)
julia> M, MtoR, StoR = module_syzygies(RG);
julia> M
-Subquotient of Submodule with 5 generators
-1 -> e[1]
-2 -> e[2]
-3 -> e[3]
-4 -> e[4]
-5 -> e[5]
-by Submodule with 1 generator
-1 -> t2*e[2] + (t2 + t3)*e[3] + t1*e[4]
+Subquotient of submodule with 5 generators
+ 1: e[1]
+ 2: e[2]
+ 3: e[3]
+ 4: e[4]
+ 5: e[5]
+by submodule with 1 generator
+ 1: t2*e[2] + (t2 + t3)*e[3] + t1*e[4]
diff --git a/test/book/specialized/eder-mohr-ideal-theoretic/gbeliminate.jlcon b/test/book/specialized/eder-mohr-ideal-theoretic/gbeliminate.jlcon
index 285858f608cd..fc01033f2b82 100644
--- a/test/book/specialized/eder-mohr-ideal-theoretic/gbeliminate.jlcon
+++ b/test/book/specialized/eder-mohr-ideal-theoretic/gbeliminate.jlcon
@@ -6,10 +6,10 @@ julia> I = ideal(R, [x^2 + y + z - 1, x + y^2 + z - 1, x + y + z^2 - 1]);
julia> groebner_basis(I, ordering = o)
Gröbner basis with elements
- 1 -> z^6 - 4*z^4 + 4*z^3 - z^2
- 2 -> 2*y*z^2 + z^4 - z^2
- 3 -> x + y + z^2 - 1
- 4 -> y^2 + x + z - 1
+ 1: z^6 - 4*z^4 + 4*z^3 - z^2
+ 2: 2*y*z^2 + z^4 - z^2
+ 3: x + y + z^2 - 1
+ 4: y^2 + x + z - 1
with respect to the ordering
degrevlex([x, y])*degrevlex([z])
@@ -19,8 +19,8 @@ Ideal generated by
julia> groebner_basis(I)
Gröbner basis with elements
- 1 -> z^2 + x + y - 1
- 2 -> y^2 + x + z - 1
- 3 -> x^2 + y + z - 1
+ 1: z^2 + x + y - 1
+ 2: y^2 + x + z - 1
+ 3: x^2 + y + z - 1
with respect to the ordering
degrevlex([x, y, z])
diff --git a/test/book/specialized/eder-mohr-ideal-theoretic/lcis.jlcon b/test/book/specialized/eder-mohr-ideal-theoretic/lcis.jlcon
index af11cab95091..e661fe2bdbeb 100644
--- a/test/book/specialized/eder-mohr-ideal-theoretic/lcis.jlcon
+++ b/test/book/specialized/eder-mohr-ideal-theoretic/lcis.jlcon
@@ -3,17 +3,17 @@ julia> R, (x, y, z) = polynomial_ring(QQ, ["x", "y", "z"]);
julia> I = ideal(R, [x*y, x*z, y*z]);
julia> conorm = subquotient(matrix(gens(I)), matrix(gens(I^2)))
-Subquotient of Submodule with 3 generators
-1 -> x*y*e[1]
-2 -> x*z*e[1]
-3 -> y*z*e[1]
-by Submodule with 6 generators
-1 -> x^2*y^2*e[1]
-2 -> x^2*y*z*e[1]
-3 -> x*y^2*z*e[1]
-4 -> x^2*z^2*e[1]
-5 -> x*y*z^2*e[1]
-6 -> y^2*z^2*e[1]
+Subquotient of submodule with 3 generators
+ 1: x*y*e[1]
+ 2: x*z*e[1]
+ 3: y*z*e[1]
+by submodule with 6 generators
+ 1: x^2*y^2*e[1]
+ 2: x^2*y*z*e[1]
+ 3: x*y^2*z*e[1]
+ 4: x^2*z^2*e[1]
+ 5: x*y*z^2*e[1]
+ 6: y^2*z^2*e[1]
julia> fitting_ideal(conorm, 1)
Ideal generated by
diff --git a/test/book/specialized/fang-fourier-monomial-bases/gap.jlcon b/test/book/specialized/fang-fourier-monomial-bases/gap.jlcon
new file mode 100644
index 000000000000..d47d03cf8252
--- /dev/null
+++ b/test/book/specialized/fang-fourier-monomial-bases/gap.jlcon
@@ -0,0 +1,2 @@
+L:= SimpleLieAlgebra("A", 4, Rationals);;
+V:= HighestWeightModule(L, [1,3,2,1]);;
diff --git a/test/book/specialized/fang-fourier-monomial-bases/oscar-vs-gap.jlcon b/test/book/specialized/fang-fourier-monomial-bases/oscar-vs-gap.jlcon
new file mode 100644
index 000000000000..cdf89abac0c2
--- /dev/null
+++ b/test/book/specialized/fang-fourier-monomial-bases/oscar-vs-gap.jlcon
@@ -0,0 +1 @@
+basis_lie_highest_weight(:A, 4, [1,3,2,1]);
diff --git a/test/book/specialized/fang-fourier-monomial-bases/sl7-cases.jlcon b/test/book/specialized/fang-fourier-monomial-bases/sl7-cases.jlcon
new file mode 100644
index 000000000000..d4c290bf899f
--- /dev/null
+++ b/test/book/specialized/fang-fourier-monomial-bases/sl7-cases.jlcon
@@ -0,0 +1,17 @@
+[fundamentals] => 320
+[fundamentals, [1, 0, 1, 0, 0]] => 70
+[fundamentals, [0, 0, 1, 0, 1]] => 70
+[fundamentals, [0, 1, 0, 1, 0]] => 54
+[fundamentals, [1, 0, 0, 1, 0]] => 28
+[fundamentals, [0, 1, 0, 0, 1]] => 28
+[fundamentals, [1, 0, 0, 1, 0], [0, 1, 0, 1, 0]] => 46
+[fundamentals, [0, 1, 0, 1, 0], [0, 1, 0, 0, 1]] => 46
+[fundamentals, [1, 0, 1, 0, 0], [1, 0, 0, 1, 0]] => 30
+[fundamentals, [0, 1, 0, 0, 1], [0, 0, 1, 0, 1]] => 30
+[fundamentals, [1, 0, 1, 0, 0], [0, 1, 0, 0, 1]] => 8
+[fundamentals, [1, 0, 0, 1, 0], [0, 0, 1, 0, 1]] => 8
+[fundamentals, [1, 0, 1, 0, 0], [1, 0, 0, 1, 0], [0, 1, 0, 1, 0]] => 70
+[fundamentals, [0, 1, 0, 1, 0], [0, 1, 0, 0, 1], [0, 0, 1, 0, 1]] => 70
+[fundamentals, [1, 0, 0, 1, 0], [0, 1, 0, 1, 0], [0, 1, 0, 0, 1]] => 10
+[fundamentals, [1, 0, 1, 0, 0], [1, 0, 0, 1, 0], [0, 1, 0, 1, 0], [0, 1, 0, 0, 1]] => 10
+[fundamentals, [1, 0, 0, 1, 0], [0, 1, 0, 1, 0], [0, 1, 0, 0, 1], [0, 0, 1, 0, 1]] => 10
diff --git a/test/book/specialized/kuehne-schroeter-matroids/ChowRings.jlcon b/test/book/specialized/kuehne-schroeter-matroids/ChowRings.jlcon
index 048441a4fb83..c2e3fe5d25c3 100644
--- a/test/book/specialized/kuehne-schroeter-matroids/ChowRings.jlcon
+++ b/test/book/specialized/kuehne-schroeter-matroids/ChowRings.jlcon
@@ -63,26 +63,26 @@ julia> RR, _ = graded_polynomial_ring(QQ,"y_#" => 1:length(basis_PD1));
julia> map = hom(RR,AA,basis_PD1);
-julia> K = kernel(hom(RR,AA,[b^(rank(M)-2k)*b for b in basis_PD1]));
+julia> K = kernel(hom(RR,AA,[b^(rank(M)-2k)*b3 for b3 in basis_PD1]));
julia> basis_HR = [map(h) for h in gens(K) if degree(h).coeff==k*g.coeff]
7-element Vector{MPolyQuoRingElem{MPolyDecRingElem{QQFieldElem, QQMPolyRingElem}}}:
- -x_{Edge(4, 3)} + 2*x_{Edge(2, 1),Edge(3, 1),Edge(3, 2)}
- -x_{Edge(4, 3)} + 2*x_{Edge(2, 1),Edge(4, 1),Edge(4, 2)}
- -x_{Edge(4, 3)} + 2*x_{Edge(2, 1),Edge(4, 3)}
- -x_{Edge(4, 3)} + 2*x_{Edge(3, 1),Edge(4, 2)}
- -x_{Edge(4, 3)} + 2*x_{Edge(3, 1),Edge(4, 1),Edge(4, 3)}
- -x_{Edge(4, 3)} + 2*x_{Edge(3, 2),Edge(4, 1)}
- -x_{Edge(4, 3)} + 2*x_{Edge(3, 2),Edge(4, 2),Edge(4, 3)}
+ x_{Edge(4, 3)}
+ -x_{Edge(2, 1),Edge(3, 1),Edge(3, 2)} + x_{Edge(2, 1),Edge(4, 1),Edge(4, 2)}
+ -x_{Edge(2, 1),Edge(3, 1),Edge(3, 2)} + 2*x_{Edge(2, 1),Edge(4, 3)}
+ -x_{Edge(2, 1),Edge(3, 1),Edge(3, 2)} + 2*x_{Edge(3, 1),Edge(4, 2)}
+ -x_{Edge(2, 1),Edge(3, 1),Edge(3, 2)} + x_{Edge(3, 1),Edge(4, 1),Edge(4, 3)}
+ -x_{Edge(2, 1),Edge(3, 1),Edge(3, 2)} + 2*x_{Edge(3, 2),Edge(4, 1)}
+ -x_{Edge(2, 1),Edge(3, 1),Edge(3, 2)} + x_{Edge(3, 2),Edge(4, 2),Edge(4, 3)}
julia> Mat3 = matrix(QQ,[[(-1)^k*vol_map(b1*b^(rank(M)-2k-1)*b2) for b1 in basis_HR] for b2 in basis_HR])
-[6 2 4 2 4 2 4]
-[2 6 4 2 4 2 4]
-[4 4 10 4 6 4 6]
-[2 2 4 6 4 2 4]
-[4 4 6 4 10 4 6]
-[2 2 4 2 4 6 4]
-[4 4 6 4 6 4 10]
+[ 2 0 -2 0 -1 0 -1]
+[ 0 2 1 1 1 1 1]
+[-2 1 5 1 1 1 1]
+[ 0 1 1 5 1 1 1]
+[-1 1 1 1 2 1 1]
+[ 0 1 1 1 1 5 1]
+[-1 1 1 1 1 1 2]
julia> is_positive_definite(matrix(ZZ,[ZZ(i) for i in Mat3]))
true
diff --git a/test/book/test.jl b/test/book/test.jl
index 656d72b8b4d9..912b995283db 100644
--- a/test/book/test.jl
+++ b/test/book/test.jl
@@ -32,7 +32,10 @@ isdefined(Main, :FakeTerminals) || include(joinpath(pkgdir(REPL),"test","FakeTer
# somewhat slow (~300s)
"cornerstones/polyhedral-geometry/ch-benchmark.jlcon",
- #"specialized/brandhorst-zach-fibration-hopping/vinberg_3.jlcon",
+
+ # not a proper julia input file
+ "specialized/fang-fourier-monomial-bases/sl7-cases.jlcon",
+ "specialized/fang-fourier-monomial-bases/gap.jlcon",
]
dispsize = (40, 130)
diff --git a/test/runtests.jl b/test/runtests.jl
index 6cfd97ea74c1..8e3fc850a0ae 100644
--- a/test/runtests.jl
+++ b/test/runtests.jl
@@ -113,7 +113,7 @@ test_large = [
"experimental/GModule/test/runtests.jl",
"experimental/LieAlgebras/test/LieAlgebraModule-test.jl",
"test/Modules/ModulesGraded.jl",
- "test/AlgebraicGeometry/Schemes/elliptic_surface.jl",
+ "test/AlgebraicGeometry/Schemes/EllipticSurface.jl",
]
test_book = [
"test/book/test.jl",