diff --git a/.github/oscardb_dump/oscar/TransitiveSimplicialComplexes.bson b/.github/oscardb_dump/oscar/TransitiveSimplicialComplexes.bson new file mode 100644 index 000000000000..62f4a0a4dc8a Binary files /dev/null and b/.github/oscardb_dump/oscar/TransitiveSimplicialComplexes.bson differ diff --git a/.github/oscardb_dump/oscar/TransitiveSimplicialComplexes.metadata.json b/.github/oscardb_dump/oscar/TransitiveSimplicialComplexes.metadata.json new file mode 100644 index 000000000000..948aa2eba864 --- /dev/null +++ b/.github/oscardb_dump/oscar/TransitiveSimplicialComplexes.metadata.json @@ -0,0 +1 @@ +{"indexes":[{"v":{"$numberInt":"2"},"key":{"_id":{"$numberInt":"1"}},"name":"_id_"}],"uuid":"65282c16f2af431aaf80186178a83b40","collectionName":"TransitiveSimplicialComplexes","type":"collection"} \ No newline at end of file diff --git a/.github/oscardb_dump/oscar/prelude.json b/.github/oscardb_dump/oscar/prelude.json new file mode 100644 index 000000000000..ebe3085a9d7f --- /dev/null +++ b/.github/oscardb_dump/oscar/prelude.json @@ -0,0 +1 @@ +{"ServerVersion":"8.0.11","ToolVersion":"100.12.2"} \ No newline at end of file diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 86fc09dedf41..5f1ad3813ef0 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -290,6 +290,63 @@ jobs: ${{ steps.julia-cache.outputs.cache-paths }} key: ${{ steps.julia-cache.outputs.cache-key }} + test-mongodb: + runs-on: ${{ matrix.os }} + continue-on-error: ${{ matrix.julia-version == '1.12-nightly' || matrix.julia-version == 'nightly' }} + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + julia-version: + - '1.10' + - '1.11' + - '1.12-nightly' + - 'nightly' + os: ['ubuntu-latest'] + + # Service containers to run + services: + # Label used to access the service container + mongodb: + # Docker Hub image + image: mongo:6.0 + # Provide the login data + env: + MONGO_INITDB_ROOT_USERNAME: admin + MONGO_INITDB_ROOT_PASSWORD: admin + ports: + # Maps tcp port 27017 on service container to the host + - 27017:27017 + env: + JULIA_PKG_SERVER: "" + OSCARDB_TEST_URI: "mongodb://admin:admin@localhost:27017/?authSource=admin" + OSCAR_TEST_SUBSET: "oscar_db" + steps: + - uses: actions/checkout@v4 + - name: "Set up Julia" + uses: julia-actions/setup-julia@v2 + with: + version: ${{ matrix.julia-version }} + - uses: julia-actions/cache@v2 + with: + cache-name: julia-cache;workflow=${{ github.workflow }};julia=${{ matrix.julia-version }};arch=${{ runner.arch }} + include-matrix: false + cache-scratchspaces: false + - name: "Fill OscarDB container" + run: | + wget -qO - https://www.mongodb.org/static/pgp/server-6.0.asc | sudo apt-key add - + echo "deb [ arch=amd64 ] https://repo.mongodb.org/apt/ubuntu jammy/mongodb-org/6.0 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-6.0.list + sudo apt-get update + sudo apt-get install -y mongodb-database-tools + mongorestore --host localhost -u admin -p admin --port 27017 .github/oscardb_dump + - uses: julia-actions/julia-runtest@v1 + - uses: julia-actions/julia-processcoverage@v1 + - uses: codecov/codecov-action@v5 + with: + fail_ci_if_error: false + token: ${{ secrets.CODECOV_TOKEN }} + + # adapted from gap-system/gap slack-notification: name: Send Slack notification on status change diff --git a/Project.toml b/Project.toml index 33365ca2b6aa..ace779ff9bdf 100644 --- a/Project.toml +++ b/Project.toml @@ -14,7 +14,9 @@ JSON = "682c06a0-de6a-54ab-a142-c8b1cf79cde6" JSON3 = "0f8b85d8-7281-11e9-16c2-39a750bddbf1" LazyArtifacts = "4af54fe1-eca0-43a8-85a7-787d91b784e3" Markdown = "d6f4376e-aef5-505a-96c1-9c027394607a" +Mongoc = "4fe8b98c-fc19-5c23-8ec2-168ff83495f2" Nemo = "2edaba10-b0f1-5616-af89-8c11ac63239a" +NetworkOptions = "ca575930-c2e3-43a9-ace4-1e988b2c1908" Pkg = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f" Polymake = "d720cf60-89b5-51f5-aff5-213f193123e7" ProgressMeter = "92933f4c-e287-5a05-a399-4b506db050ca" @@ -39,7 +41,9 @@ JSON = "^0.20, ^0.21" JSON3 = "1.13.2" LazyArtifacts = "1.6" Markdown = "1.6" +Mongoc = "0.9.2" Nemo = "0.52.1" +NetworkOptions = "1.2.0" Pkg = "1.6" Polymake = "0.13.1" ProgressMeter = "1.10.2" diff --git a/docs/oscar_references.bib b/docs/oscar_references.bib index 882f4d96dd6c..6aa5a2a636c3 100644 --- a/docs/oscar_references.bib +++ b/docs/oscar_references.bib @@ -843,6 +843,19 @@ @Misc{D-VJL24 primaryclass = {math.CO} } +@InProceedings{D-VJL24*1, + author = {Della Vecchia, Antony and Joswig, Michael and Lorenz, Benjamin}, + title = {A {FAIR} file format for mathematical software}, + editor = {Buzzard, Kevin and Dickenstein, Alicia and Eick, Bettina and Leykin, Anton and Ren, Yue}, + booktitle = {Mathematical software -- ICMS 2024}, + series = {Lecture Notes in Computer Science}, + volume = {14749}, + publisher = {Springer}, + pages = {234--244}, + year = {2024}, + doi = {10.1007/978-3-031-64529-7_25} +} + @InCollection{DE02, author = {Decker, Wolfram and Eisenbud, David}, title = {Sheaf algorithms using the exterior algebra}, @@ -1581,6 +1594,16 @@ @Article{HM05 doi = {10.1016/j.jsc.2004.11.009} } +@Article{HM16, + author = {Höhn, Gerald and Mason, Geoffrey}, + title = {The 290 fixed-point sublattices of the Leech lattice}, + journal = {J. Algebra}, + volume = {448}, + pages = {618--637}, + year = {2016}, + doi = {10.1016/j.algebra.2015.08.028} +} + @Article{HM73, author = {Horrocks, G. and Mumford, D.}, title = {A rank 2 vector bundle on $\text{P}^4$ with 15,000 symmetries}, @@ -2294,6 +2317,17 @@ @InCollection{Los18 doi = {10.1007/978-3-030-01588-6\_1} } +@Article{Lut08, + author = {Lutz, Frank H.}, + title = {Combinatorial 3-manifolds with 10 vertices}, + mrnumber = {2410566}, + journal = {Beiträge Algebra Geom.}, + volume = {49}, + number = {1}, + pages = {97--106}, + year = {2008} +} + @Misc{MNP24, author = {Merkwitz, Thomas and Naughton, Liam and Pfeiffer, Götz}, title = {TomLib, The GAP Library of Tables of Marks, Version 1.2.11}, diff --git a/docs/src/DeveloperDocumentation/serialization.md b/docs/src/DeveloperDocumentation/serialization.md index 48aa7420bbf8..b58fad78718f 100644 --- a/docs/src/DeveloperDocumentation/serialization.md +++ b/docs/src/DeveloperDocumentation/serialization.md @@ -11,8 +11,8 @@ is the process of reading and writing data. There are many reasons for this feature in OSCAR, but the main reason is communication on mathematics by mathematicians. -We implement our serialization in accordance with the [MaRDI](https://www.mardi4nfdi.de/about/mission) file format specification described [here](https://arxiv.org/abs/2309.00465). -Which means we use a JSON extension to serialize data. +We implement our serialization in accordance with the [MaRDI](https://www.mardi4nfdi.de/about/mission) file format specification developed by Della Vecchia, Joswig and Lorenz [D-VJL24*1](@cite). +In particular, we use a JSON extension to serialize data. ## How it works @@ -25,7 +25,7 @@ julia> load("/tmp/fourtitwo.mrdi") 42 ``` -The filename hints to the [MaRDI file format](https://arxiv.org/abs/2309.00465), which employs JSON. The file looks as follows: +The filename hints to the MaRDI file format [D-VJL24*1](@cite), which employs JSON. The file looks as follows: ```json { "_ns": { diff --git a/experimental/OscarDB/docs/doc.main b/experimental/OscarDB/docs/doc.main new file mode 100644 index 000000000000..b00c2c7605e9 --- /dev/null +++ b/experimental/OscarDB/docs/doc.main @@ -0,0 +1,5 @@ +[ + "OscarDB" => [ + "introduction.md" + ], +] diff --git a/experimental/OscarDB/docs/src/introduction.md b/experimental/OscarDB/docs/src/introduction.md new file mode 100644 index 000000000000..db31545efcff --- /dev/null +++ b/experimental/OscarDB/docs/src/introduction.md @@ -0,0 +1,64 @@ +```@meta +CurrentModule = Oscar +CollapsedDocStrings = true +DocTestSetup = Oscar.doctestsetup() +``` + +# OscarDB + +This module provides a general database framework which, conceptually, works for all OSCAR types. + +There are two main ingredients: +- the database backend is [MongoDB](https://www.mongodb.com); +- communication with the database relies on OSCAR's serialization, via the mrdi file format [D-VJL24*1](@cite). + +The overall design is inspired by polymake's [PolyDB](https://polydb.org/). + +## Collections + +The database is organized into collections. +Within each collection the datasets are uniform. + +### Vertex-transitive combinatorial manifolds [TransitiveSimplicialComplexes] +The OSCAR DB provides access to [Frank Lutz' collection of vertex transitive triangulations](https://www3.math.tu-berlin.de/IfM/Nachrufe/Frank_Lutz/stellar/vertex-transitive-triangulations.html). +It comprises all vertex-transitive combinatorial manifolds with up to 15 vertices in dimensions $d=2,3,9,10,11,12$. +In the remaining dimensions below 12, the enumeration is complete up to 13 vertices. + +See also [Lut08](@cite). + +### Leech pairs [LeechPairs] +The OSCAR DB provides access to the [fixed-point sublattices of the Leech lattice](http://monstrous-moonshine.de/~gerald/), +computed by Gerald Höhn and Geoffrey Mason. +Each entry of the collection is a pair consisting of a copy of the Leech lattice +and of the largest subgroup of the Conway group fixing pointwise the associated +fixed-point sublattice. + +See also [HM16](@cite), Table 1, and [the supplementary non-published tables](https://arxiv.org/src/1505.06420v3/anc). + +## Status + +This part of OSCAR is in an experimental state; please see [Adding new projects to experimental](@ref) for what this means. + +## Contact + +Please direct questions about this part of OSCAR to the following people: +* [Antony Della Vecchia](https://antonydellavecchia.github.io/) +* Benjamin Lorenz + +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). + +```@meta +CurrentModule = Oscar.OscarDB +``` + +```@docs +get_db +find_one +find +length(c::Collection, d::Dict=Dict()) +getindex(db::Database, name::AbstractString) +get_collection_names +``` + diff --git a/experimental/OscarDB/src/LeechPairs.jl b/experimental/OscarDB/src/LeechPairs.jl new file mode 100644 index 000000000000..58ff127bbb39 --- /dev/null +++ b/experimental/OscarDB/src/LeechPairs.jl @@ -0,0 +1,193 @@ +# this file is meant to contain the structs for the collections in the database + +################################################################################ +# Leech Pair +@doc raw""" + LeechPair + +Container type for the entries in the Leech pair database, computed by G. Höhn +and G. Mason [HM16](@ref). +See also https://arxiv.org/abs/1505.06420v3 and the ancillary files. + +Each `LeechPair` consists of a pair $(L, G)$ where $L$ is a negative definite +$\mathbb{Z}$-lattice isometric to the Leech lattice, and $G$ is a saturated +finite subgroup of the Conway group $Co_0 = O(L)$. Here ``saturated'' means +that $G$ is the pointwize stabilizer of the invariant lattice + +```math +L^G := \{v \in L | g(v) = v, \forall g \in G\}. +``` +""" +struct LeechPair + leech::ZZLat + G::MatrixGroup{QQFieldElem, QQMatrix} + _id::Int + rank::Int + order::ZZRingElem + alpha::Int + icoinvbar::Int + iinvbar::Int + ind::Int + hinv::Int + N::Int + type::String + + LeechPair(args...) = new(args...) +end + +############################################################################### +# +# Accessors and methods +# +############################################################################### + +@doc raw""" + lattice(LG::LeechPair) -> ZZLat + +Return the underlying Leech lattice ``L``. +""" +Oscar.lattice(LG::LeechPair) = LG.leech + +@doc raw""" + group(LG::LeechPair) -> MatrixGroup{QQFieldElem, QQMatrix} + +Return the underlying matrix group ``G``. +""" +Oscar.group(LG::LeechPair) = LG.G + +@doc raw""" + group_description(LG::LeechPair) -> String + +Return a description of the underlying matrix group ``G``. See also +[`describe`](@ref). +""" +group_description(LG::LeechPair) = describe(LG.G) + +@doc raw""" + number(LG::LeechPair) -> Int + +Return the number, in Höhn-Mason list, of the associated invariant lattice +$L^G$. + +Refer to Table 1 of [HM16](@cite). +""" +number(LG::LeechPair) = LG._id + +@doc raw""" + rank_invariant_lattice(LG::LeechPair) -> Int + +Return the rank of the associated invariant lattice $L^G$. + +Refer to Table 1 of [HM16](@cite). +""" +rank_invariant_lattice(LG::LeechPair) = LG.rank + +@doc raw""" + group_order(LG::LeechPair) -> ZZRingElem + +Return the order of the underlying matrix group ``G``. + +Refer to Table 1 of [HM16](@cite). +""" +group_order(LG::LeechPair) = LG.order + +@doc raw""" + alpha(LG::LeechPair) -> Int + +Return the difference between the rank of the associated invariant lattice +$L^G$ and the length of its discriminant group $D_{L^G}$. + +Refer to Table 1 of [HM16](@cite). +""" +alpha(LG::LeechPair) = LG.alpha + +@doc raw""" + index_image_discriminant_representation_coinvariant(LG::LeechPair) -> Int + +Return the index of the image of the map $O(L_G) \to O(D_{L_G})$ inside +$O(D_{L_G})$, where $L_G$ is the associated coinvariant lattice. + +Refer to Table 1 of [HM16](@cite). +""" +index_image_discriminant_representation_coinvariant(LG::LeechPair) = LG.icoinvbar + +@doc raw""" + index_image_discriminant_representation_invariant(LG::LeechPair) -> Int + +Return the index of the image of the map $O(L^G) \to O(D_{L^G})$ inside +$O(D_{L^G})$, where $L^G$ is the associated coinvariant lattice. + +Refer to Table 1 of [HM16](@cite). +""" +index_image_discriminant_representation_invariant(LG::LeechPair) = LG.iinvbar + +@doc raw""" + index_normalizer_modulo_group(LG::LeechPair) -> Int + +Return the index of the quotient $N_{O(L)}(G)/G$ inside $O(L^G)$ where $L^G$ +is the associated invariant lattice and $N_{O(L)}(G)$ is the normalizer of $G$ +in the Conway group $O(L) \cong Co_0$. + +Refer to Table 1 of [HM16](@cite). +""" +index_normalizer_modulo_group(LG::LeechPair) = LG.ind + +@doc raw""" + class_number_invariant_lattice(LG::LeechPair) -> Int + +Return the number of isometry classes in the genus of the associated invariant +lattice $L^G$. + +Refer to Table 1 of [HM16](@cite). +""" +class_number_invariant_lattice(LG::LeechPair) = LG.hinv + +@doc raw""" + number_of_niemeier_embeddings(LG::LeechPair) -> Int + +Return the number of (isometry classes of) Niemeier lattices with $(-2)$-roots +in which the associated coinvariant sublattice $L_G$ embeds. + +Refer to Table 1 of [HM16](@cite). +""" +number_of_niemeier_embeddings(LG::LeechPair) = LG.N + +@doc raw""" + case_type(LG::LeechPair) -> String + +Return the case type of the Leech pair, according to the last column in Table 1 +of [HM16](@cite). +""" +case_type(LG::LeechPair) = LG.type + +@doc raw""" + invariant_lattice(LG::LeechPair) -> ZZLat + +Return the associated invariant lattice $L^G$. +""" +Oscar.invariant_lattice(LG::LeechPair) = invariant_lattice(lattice(LG), group(LG)) + +@doc raw""" + coinvariant_lattice(LG::LeechPair) -> ZZLat + +Return the associated coinvariant lattice $L_G$. +""" +Oscar.coinvariant_lattice(LG::LeechPair) = first(coinvariant_lattice(lattice(LG), group(LG))) + +@doc raw""" + invariant_coinvariant_pair(LG::LeechPair) -> ZZLat, ZZLat + +Return the pair $(L^G, L_G)$ consisting of the associated invariant and +coinvariant lattices respectively. +""" +Oscar.invariant_coinvariant_pair(LG::LeechPair) = invariant_coinvariant_pair(lattice(LG), group(LG))[1:2] + +############################################################################### +# +# Printing +# +############################################################################### + +function Base.show(io::IO, LG::LeechPair) + print(io, "Leech pair no. $(number(LG))") +end diff --git a/experimental/OscarDB/src/OscarDB.jl b/experimental/OscarDB/src/OscarDB.jl new file mode 100644 index 000000000000..66a4849c7196 --- /dev/null +++ b/experimental/OscarDB/src/OscarDB.jl @@ -0,0 +1,244 @@ +module OscarDB + +using ..Oscar +using ..Oscar.Serialization + +import Oscar.Serialization: load_object, save_object, type_params + +# Transitivesimplicialcomplex imports +import Oscar: + simplicial_complex, + dim, + f_vector, + automorphism_group, + homology, + betti_numbers, + n_vertices + +# for ca certificates +import NetworkOptions +import Mongoc: Mongoc, find, find_one + +const OSCAR_DB = "oscar" +const OSCAR_DEV_DB = "oscar-dev" + +""" + Database + +Type for referencing a specific database (usually the `OscarDB`) +""" +struct Database + mdb::Mongoc.Database +end + +""" + Collection + +Type for referencing a specific collection. +`T<:Union{Polymake.BigObject, Mongoc.BSON}` defines the template and/or element types +returned by operations applied on objects of this type. +""" +struct Collection + mcol::Mongoc.Collection +end + +""" + Cursor + +Type for representing the results of a query. +Can be iterated, but the iterator can not be reset. For that, one has to query again. +""" +struct Cursor + mcursor::Mongoc.Cursor{Mongoc.Collection} +end + +@doc raw""" + get_db() + +Connect to the `OscarDB` and return `Database` instance. + +The uri of the server can be set in advance by writing its `String` representation +into ENV["OSCARDB_TEST_URI"]. +(used to connect to the github services container for testing) +# Examples +```julia-repl +julia> db = Oscar.OscarDB.get_db(); + +julia> typeof(db) +Oscar.OscarDB.Database +``` +""" +function get_db(;dev=false) + # we explicitly set the cacert file, otherwise we might get connection errors because the certificate cannot be validated + username = "oscar-pub" + password = "oShea%2FfooC%24ie6h" + client = Mongoc.Client(get(ENV, "OSCARDB_TEST_URI", "mongodb://$username:$password@db.oscar-system.org/oscar?directConnection=true&authSource=users&tls=true&appName=mongosh+2.4.2&sslCertificateAuthorityFile=$(NetworkOptions.ca_roots_path())")) + return Database(client[dev ? OSCAR_DEV_DB : OSCAR_DB]) +end + +""" + getindex(db::Database, name::AbstractString) + +Return a `Oscar.OscarDB.Collection` instance +from `db` with the given `name`. + +# Examples +```julia-repl +julia> Oscar.OscarDB.get_collection_names(db) +4-element Vector{String}: + "zzlattices" + "LeechPairs" + "Surfaces" + "TransitiveSimplicialComplexes" + +julia> c = db["LeechPairs"]; + +julia> length(c) +290 +``` +""" +Base.getindex(db::Database, name::AbstractString) = Collection(db.mdb[name]) + +""" + length(c::Collection, d::Dict=Dict()) + +Count documents in a collection `c` matching the criteria given by `d`. + +# Examples + +Same as above, but faster. + +```julia-repl +julia> db = Oscar.OscarDB.get_db(); + +julia> tscit = Oscar.OscarDB.find(db["TransitiveSimplicialComplexes"], Dict("data.betti_numbers" => ["0", "0", "0", "1"])); + +julia> length(tscit) +63 +``` +""" +function Base.length(c::Collection, d::Dict=Dict()) + return Base.length(c.mcol, Mongoc.BSON(d)) +end + +@doc raw""" + find(c::Collection{T}, d::Dict=Dict(); opts::Union{Nothing, Dict}) + +Returns an iterator over documents in the collection `c` which match the criteria given by `d`. +Apply search options `opts`. + +# Examples + +Here we show how to find all vertex-transitive 3-dimensional rational homology spheres in that database (i.e., with up to 15 vertices). + +The dimension $d$ of the manifold is here implicitly given as the length of the vector of Betti numbers less one. + +```julia-repl +julia> db = Oscar.OscarDB.get_db(); + +julia> tscit = Oscar.OscarDB.find(db["TransitiveSimplicialComplexes"], Dict("data.betti_numbers" => ["0", "0", "0", "1"])); + +julia> length([tsc for tsc in tscit]) +63 +``` +""" +function Mongoc.find(c::Collection, d::Dict=Dict(); + opts::Union{Nothing, Dict}=nothing) + return Cursor(Mongoc.find(c.mcol, Mongoc.BSON(d); options=(isnothing(opts) ? nothing : Mongoc.BSON(opts)))) +end + +@doc raw""" + find_one(c::Collection{T}, d::Dict=Dict(); opts::Union{Nothing, Dict}) + +Return one document from a collection `c` matching the criteria given by `d`. +`T` can be chosen from `Polymake.BigObject` and `Mongoc.BSON`. +Apply search options `opts`. + +# Examples + +Here we show how to find one vertex-transitive combinatorial surface with reduced rational Betti numbers $\tilde\beta_0 = \beta_1 = \beta_2 = 0$. +The dimension of the manifold is here implicitly given as the length of the vector of Betti numbers less one. + +In this case we find the unique six-vertex triangulation of the real projective plane. + +```julia-repl +julia> db = Oscar.OscarDB.get_db(); + +julia> tsc = Oscar.OscarDB.find_one(db["TransitiveSimplicialComplexes"], Dict("data.betti_numbers" => ["0", "0", "0", "1"])); + +julia> n_facets(simplicial_complex(tsc)) +35 +``` +""" +function find_one(c::Collection, d::Dict=Dict(); opts::Union{Nothing, Dict}=nothing) + p = Mongoc.find_one(c.mcol, Mongoc.BSON(d); options=(isnothing(opts) ? nothing : Mongoc.BSON(opts))) + return isnothing(p) ? nothing : parse_document(p) +end + +""" + parse_document(bson::Mongoc.BSON) + +Create an Oscar object from the data given by `bson`. +""" +function parse_document(bson::Mongoc.BSON) + # This is a hook for future, we would like to be able override the parent + # of objects on load, for example forcing an ideal to live in a certain Ring + str = Mongoc.as_json(bson) + return Oscar.load(IOBuffer(str)) +end + +""" + get_collection_names(db::Database) + +Return a `Vector{String}` containing the names of all collections in the +OscarDB, excluding meta collections. +# Examples +```julia-repl +julia> db = Oscar.OscarDB.get_db(); + +julia> Oscar.OscarDB.get_collection_names(db) +4-element Vector{String}: + "zzlattices" + "LeechPairs" + "Surfaces" + "TransitiveSimplicialComplexes" +``` +""" +function get_collection_names(db::Database) + opts = Mongoc.BSON("authorizedCollections" => true, "nameOnly" => true) + return Mongoc.get_collection_names(db.mdb;options=opts) +end +# Iterator + +Base.IteratorSize(::Type{<:Cursor}) = Base.SizeUnknown() +Base.IteratorSize(::Type{<:Collection}) = Base.SizeUnknown() + +# functions for `BSON` iteration +Base.iterate(cursor::Cursor, state::Nothing=nothing) = + iterate(cursor.mcursor, state) + +Base.iterate(coll::Collection) = + iterate(coll.mcol) + +Base.iterate(coll::Collection, state::Mongoc.Cursor) = + iterate(coll.mcol, state) + +# shows information about a specific Collection +function Base.show(io::IO, coll::Collection) + db = Database(coll.mcol.database) + print(io, typeof(coll), ": ", coll.mcol.name) +end + +include("exports.jl") + +include("LeechPairs.jl") +include("TransitiveSimplicialComplex.jl") +include("serialization.jl") + + +end # Module + +using .OscarDB + +include("exports.jl") + diff --git a/experimental/OscarDB/src/TransitiveSimplicialComplex.jl b/experimental/OscarDB/src/TransitiveSimplicialComplex.jl new file mode 100644 index 000000000000..f2496c5eb98c --- /dev/null +++ b/experimental/OscarDB/src/TransitiveSimplicialComplex.jl @@ -0,0 +1,66 @@ +################################################################################ +# TransitiveSimplicialComplex + +# Add your new types, functions, and methods here. + +struct TransitiveSimplicialComplex + _id::String + complex::SimplicialComplex + dim::Int + n_vertices::Int + f_vector::Vector{Int} + betti_numbers::Vector{Int} + aut_group::PermGroup + topological_type::String # this may not be there, allow Nothing? + + TransitiveSimplicialComplex(args...) = new(args...) + + TransitiveSimplicialComplex( + name::String, + K::SimplicialComplex, + top_type::String + ) = new( + name, + K, + dim(K), + n_vertices(K), + f_vector(K), + betti_numbers(K), + automorphism_group(K), + top_type + ) + + TransitiveSimplicialComplex( + name::String, + K::SimplicialComplex, + aut_group::PermGroup, + top_type::String + ) = new( + name, + K, + dim(K), + n_vertices(K), + f_vector(K), + betti_numbers(K), + aut_group, + top_type + ) +end + +function transitive_simplicial_complex(name::String, + facets::Vector{Vector{Int}}, + top_type::String) + K = simplicial_complex(facets) + TransitiveSimplicialComplex(name, K, top_type) +end + +simplicial_complex(tsc::TransitiveSimplicialComplex) = tsc.complex +automorphism_group(tsc::TransitiveSimplicialComplex) = tsc.aut_group +dim(tsc::TransitiveSimplicialComplex) = tsc.dim +n_vertices(tsc::TransitiveSimplicialComplex) = tsc.n_vertices +f_vector(tsc::TransitiveSimplicialComplex) = tsc.f_vector +betti_numbers(tsc::TransitiveSimplicialComplex) = tsc.betti_numbers +homology(tsc::TransitiveSimplicialComplex, i::Int) = homology(simplicial_complex(tsc), i) +topological_type(tsc) = tsc.topological_type + +#TODO add docs and printing etc. diff --git a/experimental/OscarDB/src/exports.jl b/experimental/OscarDB/src/exports.jl new file mode 100644 index 000000000000..583696512dcc --- /dev/null +++ b/experimental/OscarDB/src/exports.jl @@ -0,0 +1,10 @@ +export get_db +export find +export find_one +export getindex +export get_collection_names + +export LeechPair +export TransitiveSimplicialComplex +export transitive_simplicial_complex + diff --git a/experimental/OscarDB/src/serialization.jl b/experimental/OscarDB/src/serialization.jl new file mode 100644 index 000000000000..a2de23af2a0f --- /dev/null +++ b/experimental/OscarDB/src/serialization.jl @@ -0,0 +1,75 @@ +@register_serialization_type LeechPair +type_params(x::LeechPair) = TypeParams(LeechPair, group(x)) + +function save_object(s::SerializerState, LG::LeechPair) + save_data_dict(s) do + save_object(s, Oscar.number(LG), :id) + save_object(s, Oscar.rank_invariant_lattice(LG), :rank) + save_object(s, Oscar.group_order(LG), :order) + save_object(s, Oscar.alpha(LG), :alpha) + save_object(s, Oscar.index_image_discriminant_representation_coinvariant(LG), :icoinvbar) + save_object(s, Oscar.index_image_discriminant_representation_invariant(LG), :iinvbar) + save_object(s, Oscar.index_normalizer_modulo_group(LG), :ind) + save_object(s, Oscar.class_number_invariant_lattice(LG), :hinv) + save_object(s, Oscar.number_of_niemeier_embeddings(LG), :N) + # want to avoid using type key here to avoid confusion with file format + save_object(s, Oscar.case_type(LG), :leech_pair_type) + end +end + +function load_object(s::DeserializerState, ::Type{LeechPair}, G::MatrixGroup) + # dev until we move collection to offical db + db = Oscar.OscarDB.get_db(;dev=true) + leech = Oscar.OscarDB.find_one(db["zzlattices"], Dict("_id" => "leech")) + + LeechPair( + leech, + G, + load_object(s, Int, :id), + load_object(s, Int, :rank), + load_object(s, ZZRingElem, :order), + load_object(s, Int, :alpha), + load_object(s, Int, :icoinvbar), + load_object(s, Int, :iinvbar), + load_object(s, Int, :ind), + load_object(s, Int, :hinv), + load_object(s, Int, :N), + load_object(s, String, :leech_pair_type), + ) +end + +@register_serialization_type TransitiveSimplicialComplex + +type_params(tsc::TransitiveSimplicialComplex) = TypeParams( + TransitiveSimplicialComplex, + automorphism_group(tsc) +) + +function save_object(s::SerializerState, tsc::TransitiveSimplicialComplex) + save_data_dict(s) do + save_object(s, tsc._id, :name) + save_object(s, simplicial_complex(tsc), :complex) + save_object(s, dim(tsc), :dim) + save_object(s, n_vertices(tsc), :n_vertices) + save_object(s, f_vector(tsc), :f_vector) + save_object(s, betti_numbers(tsc), :betti_numbers) + save_object(s, automorphism_group(tsc), :aut_group) + save_object(s, topological_type(tsc), :topological_type) + end +end + +function load_object(s::DeserializerState, ::Type{TransitiveSimplicialComplex}, + params::PermGroup) + load_node(s) do _ + TransitiveSimplicialComplex( + load_object(s, String, :name), + load_object(s, SimplicialComplex, :complex), + load_object(s, Int, :dim), + load_object(s, Int, :n_vertices), + load_object(s, Vector{Int}, :f_vector), + load_object(s, Vector{Int}, :betti_numbers), + params, + load_object(s, String, :topological_type) + ) + end +end diff --git a/experimental/OscarDB/test/runtests.jl b/experimental/OscarDB/test/runtests.jl new file mode 100644 index 000000000000..36b835f05137 --- /dev/null +++ b/experimental/OscarDB/test/runtests.jl @@ -0,0 +1,42 @@ +using Oscar.OscarDB.Mongoc + +@testset verbose=true "OscarDB" begin + + @testset verbose=true "Basic functionality" begin + # Types + @test Oscar.OscarDB.get_db() isa Oscar.OscarDB.Database + db = Oscar.OscarDB.get_db() + try + @test Mongoc.ping(db.mdb.client)["ok"] == 1 + catch + @test "not" == "connected" + end + end + + @testset "Collections" begin + # can only test collections that are in the .github/oscardb_dump/oscar + db = Oscar.OscarDB.get_db() + collection_tsc = db["TransitiveSimplicialComplexes"] + + @testset verbose=true "Iterator (Collection)" begin + @test iterate(collection_tsc) isa Tuple{Mongoc.BSON, Mongoc.Cursor{Mongoc.Collection}} + end + + @testset "Types" begin + @test Oscar.OscarDB.get_db() isa Oscar.OscarDB.Database + @test db["TransitiveSimplicialComplexes"] isa Oscar.OscarDB.Collection + @test collection_tsc isa Oscar.OscarDB.Collection + end + + @testset "Querying" begin + tsc = Oscar.OscarDB.find_one(db["TransitiveSimplicialComplexes"], + Dict("data.betti_numbers" => ["0", "0", "0", "1"])) + @test betti_numbers(tsc) == [0, 0, 0, 1] + end + end + + # here to avoid + @testset "Doctests" begin + + end +end diff --git a/src/Serialization/main.jl b/src/Serialization/main.jl index 80db21a864d0..a31670c18e45 100644 --- a/src/Serialization/main.jl +++ b/src/Serialization/main.jl @@ -613,6 +613,7 @@ include("LieTheory.jl") include("Upgrades/main.jl") include("parallel.jl") + ################################################################################ # Interacting with IO streams and files diff --git a/test/runtests.jl b/test/runtests.jl index 8a3ba5ab68cb..93e4417c0bc1 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -124,8 +124,9 @@ test_subsets = Dict( ], :book => [ "test/book/test.jl", - ] - ) + ], + :oscar_db => ["experimental/OscarDB/test/runtests.jl"] +) test_subset = Symbol(get(ENV, "OSCAR_TEST_SUBSET", "default")) if haskey(ENV, "JULIA_PKGEVAL")