{ "cells": [ { "cell_type": "markdown", "id": "conservative-infection", "metadata": {}, "source": [ "# Installing and starting Oscar\n", "\n", "First, you need to install the (compiler for) `julia`. For that, follow the installation \n", "instructions on the OSCAR website (https://oscar.computeralgebra.de) and make sure you \n", "install the latest julia version. \n", "\n", "Usually, you would then proceed to follow the installation instructions for \n", "OSCAR there, but for this course we will need a modified version of OSCAR which comes with some \n", "extra patches that have not (yet) made their way in the official release. \n", "To install and use that version, open a julia REPL (Terminal, notebook, ...) and type" ] }, { "cell_type": "code", "execution_count": null, "id": "blank-programmer", "metadata": {}, "outputs": [], "source": [ "using Pkg\n", "]add https://github.com/HechtiDerLachs/Oscar.jl#CIMPA_school" ] }, { "cell_type": "markdown", "id": "postal-assets", "metadata": {}, "source": [ "Then you should be able to start OSCAR with the command " ] }, { "cell_type": "code", "execution_count": null, "id": "parallel-glass", "metadata": {}, "outputs": [], "source": [ "using Oscar" ] }, { "cell_type": "markdown", "id": "appreciated-stadium", "metadata": {}, "source": [ "### Installing jupyter-notebook\n", "\n", "What you see here is a so-called `jupyter` notebook. Those notebooks do not run out of \n", "the box with julia. On Ubuntu/Debian, you need to install the package `jupyter-notebook`. \n", "In addition, you need an extension of `julia` so that it can connect to `jupyter`. \n", "According to the OSCAR website, you are supposed to run" ] }, { "cell_type": "code", "execution_count": null, "id": "indonesian-court", "metadata": {}, "outputs": [], "source": [ "using Pkg\n", "Pkg.add(\"IJulia\")" ] }, { "cell_type": "markdown", "id": "compact-speed", "metadata": {}, "source": [ "### Updating OSCAR during the course\n", "\n", "It might be necessary during the course to update OSCAR. To do so, type" ] }, { "cell_type": "code", "execution_count": null, "id": "lesser-indian", "metadata": {}, "outputs": [], "source": [ "] up" ] }, { "cell_type": "markdown", "id": "applied-summit", "metadata": {}, "source": [ "### Switching back to the official OSCAR version after the course\n", "\n", "After the course is finished and you wish to continue using OSCAR, you can switch to the \n", "official release version as follows" ] }, { "cell_type": "code", "execution_count": null, "id": "grave-characteristic", "metadata": {}, "outputs": [], "source": [ "] rm Oscar\n", "using Pkg\n", "Pkg.add(\"Oscar\")" ] }, { "cell_type": "markdown", "id": "written-toner", "metadata": {}, "source": [ "# FIrst steps in OSCAR\n", "\n", "## Polynomial rings, etc.\n", "\n", "Some standard rings and fields are already there:" ] }, { "cell_type": "code", "execution_count": null, "id": "drawn-product", "metadata": {}, "outputs": [], "source": [ "QQ" ] }, { "cell_type": "code", "execution_count": null, "id": "wrong-porcelain", "metadata": {}, "outputs": [], "source": [ "ZZ\n", "# Try 2^1000 vs. ZZ(2)^1000" ] }, { "cell_type": "code", "execution_count": null, "id": "inner-copyright", "metadata": {}, "outputs": [], "source": [ "GF(53)" ] }, { "cell_type": "markdown", "id": "divine-juvenile", "metadata": {}, "source": [ "Some others need to be manually created:" ] }, { "cell_type": "code", "execution_count": null, "id": "previous-outside", "metadata": {}, "outputs": [], "source": [ "R, (x,y,z) = QQ[\"x\", \"y\", \"z\"]" ] }, { "cell_type": "markdown", "id": "beginning-feedback", "metadata": {}, "source": [ "Note that the above command returns a tuple `(R, v)` consisting of the polynomial ring `R` and another tuple `v = (x,y,z)` containing its variables.\n", "\n", "We can now investigate both `R` and the variables:" ] }, { "cell_type": "code", "execution_count": null, "id": "bound-cookbook", "metadata": {}, "outputs": [], "source": [ "R" ] }, { "cell_type": "code", "execution_count": null, "id": "becoming-investing", "metadata": {}, "outputs": [], "source": [ "x^2 + 3*x" ] }, { "cell_type": "markdown", "id": "australian-wonder", "metadata": {}, "source": [ "This does not tell us much. But of course, there is more \n", "going on in the background. For instance, everything in \n", "julia has a type and so does our variable `x`. We will \n", "come back to that later." ] }, { "cell_type": "code", "execution_count": null, "id": "crucial-creek", "metadata": {}, "outputs": [], "source": [ "typeof(x)" ] }, { "cell_type": "markdown", "id": "upper-proposal", "metadata": {}, "source": [ "We can also access the variables via the `getindex`-function \n", "for the ring `R`:" ] }, { "cell_type": "code", "execution_count": null, "id": "creative-strap", "metadata": {}, "outputs": [], "source": [ "x == R[1]" ] }, { "cell_type": "markdown", "id": "signed-arcade", "metadata": {}, "source": [ "Any ring and its elements in Oscar have a parent-element relationship. We can check which ring an element belongs to:" ] }, { "cell_type": "code", "execution_count": null, "id": "basic-correspondence", "metadata": {}, "outputs": [], "source": [ "parent(x^2 + 4*x^3+ y)" ] }, { "cell_type": "code", "execution_count": null, "id": "antique-forty", "metadata": {}, "outputs": [], "source": [ "parent(x) == R" ] }, { "cell_type": "markdown", "id": "vital-bahrain", "metadata": {}, "source": [ "Let us create another ring over a different field. \n", "This time, we use another constructor:" ] }, { "cell_type": "code", "execution_count": null, "id": "developmental-aging", "metadata": {}, "outputs": [], "source": [ "S, w = PolynomialRing(GF(101), \"w\" => 1:5)" ] }, { "cell_type": "code", "execution_count": null, "id": "industrial-rabbit", "metadata": {}, "outputs": [], "source": [ "w[3]" ] }, { "cell_type": "code", "execution_count": null, "id": "blessed-mattress", "metadata": {}, "outputs": [], "source": [ "parent(w[2]) == R" ] }, { "cell_type": "code", "execution_count": null, "id": "confident-finance", "metadata": {}, "outputs": [], "source": [ "parent(w[2]) == S" ] }, { "cell_type": "markdown", "id": "uniform-review", "metadata": {}, "source": [ "## Matrices, ideals, and modules\n", "\n", "### Matrices over polynomial rings\n", "\n", "Given a ring `R`, we can set up matrices over it:" ] }, { "cell_type": "code", "execution_count": null, "id": "honey-cooperation", "metadata": {}, "outputs": [], "source": [ "M = R[x y z; z x y^2]" ] }, { "cell_type": "markdown", "id": "capable-shark", "metadata": {}, "source": [ "Note that the separation of a rows entries is done by whitespaces. \n", "Unfortunately, that means that you have to be careful when using\n", "blanks in your expressions:" ] }, { "cell_type": "code", "execution_count": null, "id": "monthly-fields", "metadata": {}, "outputs": [], "source": [ "M = R[x, y z; z x y^2] #TODO: Modify and play around to create a mess" ] }, { "cell_type": "markdown", "id": "living-closure", "metadata": {}, "source": [ "Especially, there is some potential of conflict with the `getindex` method when creating `1x1`-matrices:" ] }, { "cell_type": "code", "execution_count": null, "id": "express-engine", "metadata": {}, "outputs": [], "source": [ "f = R[2]^2 # the first variable of `R` squared" ] }, { "cell_type": "code", "execution_count": null, "id": "partial-confidence", "metadata": {}, "outputs": [], "source": [ "F = R[2;]^2 # the 1x1-matrix A = (2) squared" ] }, { "cell_type": "code", "execution_count": null, "id": "affected-practice", "metadata": {}, "outputs": [], "source": [ "M[1, 2] # the (1,2)-th entry of the matrix M" ] }, { "cell_type": "markdown", "id": "infrared-catalog", "metadata": {}, "source": [ "Matrices can further be processed; for instance, we can take minors:" ] }, { "cell_type": "code", "execution_count": null, "id": "infinite-contrast", "metadata": {}, "outputs": [], "source": [ "minors(M, 2) # return a list of 2x2-minors of M" ] }, { "cell_type": "markdown", "id": "arbitrary-steel", "metadata": {}, "source": [ "...or submatrices:" ] }, { "cell_type": "code", "execution_count": null, "id": "narrative-inquiry", "metadata": {}, "outputs": [], "source": [ "subM1 = M[1:end, 1:2] # this takes two `range`s as input" ] }, { "cell_type": "code", "execution_count": null, "id": "superb-optimization", "metadata": {}, "outputs": [], "source": [ "subM2 = M[1:2, [1,3]] # this takes a `range` and a `Vector{Int}` as input" ] }, { "cell_type": "markdown", "id": "written-bulletin", "metadata": {}, "source": [ "If we want a specific minor of a matrix, we have to specify the \n", "corresponding square submatrix first and then take the determinant:" ] }, { "cell_type": "code", "execution_count": null, "id": "living-silicon", "metadata": {}, "outputs": [], "source": [ "det(subM2)" ] }, { "cell_type": "markdown", "id": "champion-dictionary", "metadata": {}, "source": [ "### Ideals in polynomial rings\n", "\n", "We can create ideals in polynomial rings like `R` from a list of generators as follows:" ] }, { "cell_type": "code", "execution_count": null, "id": "plastic-serve", "metadata": {}, "outputs": [], "source": [ "I = ideal(R, [x^2 - y*z, x*y^2 - z^2, -x*z + y^3])" ] }, { "cell_type": "markdown", "id": "boring-judgment", "metadata": {}, "source": [ "Any ideal can be asked for the generators with which it was once constructed:" ] }, { "cell_type": "code", "execution_count": null, "id": "stretch-header", "metadata": {}, "outputs": [], "source": [ "g = gens(I)" ] }, { "cell_type": "markdown", "id": "supposed-former", "metadata": {}, "source": [ "We can test ideal membership in `I` for elements of `R`:" ] }, { "cell_type": "code", "execution_count": null, "id": "cathedral-influence", "metadata": {}, "outputs": [], "source": [ "x + 1 in I" ] }, { "cell_type": "code", "execution_count": null, "id": "moved-brooks", "metadata": {}, "outputs": [], "source": [ "3*(x^2 - y*z) + z*(x*y^2 - z^2) in I" ] }, { "cell_type": "markdown", "id": "rocky-france", "metadata": {}, "source": [ "Moreover, for any given element $f \\in I$, we can ask \n", "for the coefficients of $f$ in a linear combination of the generators of $I$:" ] }, { "cell_type": "code", "execution_count": null, "id": "tribal-closer", "metadata": {}, "outputs": [], "source": [ "coordinates(3*(x^2 - y*z) + z*(x*y^2 - z^2), I)" ] }, { "cell_type": "markdown", "id": "naughty-dublin", "metadata": {}, "source": [ "Note that such \"coordinates\" are not unique!" ] }, { "cell_type": "markdown", "id": "derived-nicaragua", "metadata": {}, "source": [ "## Geometry: Varieties and their singular loci\n", "\n", "For the computer, an affine variety is usually modeled by the ideal $I \\subset R$ defining it. \n", "In Oscar, we even have data types for varieties (later!), but we will stick with the algebraic \n", "side for the moment, thinking of it geometrically. \n", "\n", "Let us come back to one of our previous examples..." ] }, { "cell_type": "code", "execution_count": null, "id": "aerial-facility", "metadata": {}, "outputs": [], "source": [ "R, (x,y) = QQ[\"x\", \"y\"]\n", "f = x*y*(1-x-y)\n", "I = ideal(R, f)" ] }, { "cell_type": "markdown", "id": "instructional-complement", "metadata": {}, "source": [ "... and let us find out \n", "what we can about the underlying variety." ] }, { "cell_type": "code", "execution_count": null, "id": "advanced-bhutan", "metadata": {}, "outputs": [], "source": [ "dim(I)" ] }, { "cell_type": "markdown", "id": "portuguese-simulation", "metadata": {}, "source": [ "So the variety defined by `I` is an algebraic curve. Does it have singular points? Let's apply the jacobian criterion!" ] }, { "cell_type": "code", "execution_count": null, "id": "blind-biodiversity", "metadata": {}, "outputs": [], "source": [ "g = gens(I)\n", "Dg = jacobi_matrix(g)" ] }, { "cell_type": "code", "execution_count": null, "id": "accredited-triple", "metadata": {}, "outputs": [], "source": [ "J = ideal(R, minors(Dg, 1)) + I # Apply the jacobian criterion" ] }, { "cell_type": "markdown", "id": "educated-fetish", "metadata": {}, "source": [ "Often, the output is not very readable. Since we are only \n", "interested in the geometric locus (and not the scheme theoretic \n", "structure), there is some hope that the radical is more simple.\n", "But be warned! Taking the radical is in general a very \n", "expensive procedure. " ] }, { "cell_type": "code", "execution_count": null, "id": "academic-reception", "metadata": {}, "outputs": [], "source": [ "radical(J)" ] }, { "cell_type": "markdown", "id": "tested-lyric", "metadata": {}, "source": [ "No luck in this case. As a next step, let us try to decompose `J` using the `primary_decomposition`:" ] }, { "cell_type": "code", "execution_count": null, "id": "sunrise-cincinnati", "metadata": {}, "outputs": [], "source": [ "primary_decomposition(J)" ] }, { "cell_type": "markdown", "id": "revolutionary-range", "metadata": {}, "source": [ "We can wrap this in a new function:" ] }, { "cell_type": "code", "execution_count": null, "id": "previous-sword", "metadata": {}, "outputs": [], "source": [ "function radical_of_singular_locus(I) \n", " d = dim(I) # the dimension of the ideal \n", " R = base_ring(I) # the ring in which `I` lives\n", " g = gens(I)\n", " Dg = jacobi_matrix(g)\n", " n = ngens(R) # the number of variables of `R`\n", " Ising = I + ideal(R, minors(Dg, n-d))\n", " return radical(Ising)\n", "end" ] }, { "cell_type": "markdown", "id": "genetic-thomson", "metadata": {}, "source": [ "Let's apply it to our previous ideal and see whether it works." ] }, { "cell_type": "code", "execution_count": null, "id": "extensive-davis", "metadata": {}, "outputs": [], "source": [ "radical_of_singular_locus(I)" ] }, { "cell_type": "markdown", "id": "critical-metabolism", "metadata": {}, "source": [ "## Local rings in OSCAR\n", "\n", "In Oscar, we can localize polynomial rings at geometric points $p \\in \\mathbf A^n$. This \n", "is important in singularity theory, since geometrically the algebraic procedure of localization \n", "corresponds to passing from an affine variety to its germ at a point." ] }, { "cell_type": "code", "execution_count": null, "id": "twenty-punishment", "metadata": {}, "outputs": [], "source": [ "R, (x,y,z) = QQ[\"x\", \"y\", \"z\"]\n", "U = complement_of_ideal(R, [0,0,0]) # The multiplicative set of functions not vanishing at the origin\n", "L, map_from_R_to_L = Localization(R, U)" ] }, { "cell_type": "markdown", "id": "level-reading", "metadata": {}, "source": [ "Just like, for example, `Int` is casted to `Float` when evaluating `1 + 1.3`, \n", "elements of the original ring `R` are automatically casted to \n", "elements of `L` whenever the context requires it; we can freely \n", "do arithmetic mixing elements of both rings." ] }, { "cell_type": "code", "execution_count": null, "id": "alone-switch", "metadata": {}, "outputs": [], "source": [ "a = x + inv(L(y-1))" ] }, { "cell_type": "code", "execution_count": null, "id": "general-classification", "metadata": {}, "outputs": [], "source": [ "parent(a) == L" ] }, { "cell_type": "markdown", "id": "friendly-neighborhood", "metadata": {}, "source": [ "Also, mathematical comparison works as expected:" ] }, { "cell_type": "code", "execution_count": null, "id": "involved-horizontal", "metadata": {}, "outputs": [], "source": [ "one(L) == one(R)" ] }, { "cell_type": "markdown", "id": "closed-torture", "metadata": {}, "source": [ "For comparison of the objects in the computer (i.e. in memory), there is the `===` operator. It gives another result:" ] }, { "cell_type": "code", "execution_count": null, "id": "guilty-illness", "metadata": {}, "outputs": [], "source": [ "one(L) === one(R)" ] }, { "cell_type": "markdown", "id": "exempt-lesbian", "metadata": {}, "source": [ "Let us come back to geometry. \n", "We set up the following variety. X is the union of a \n", "hyperplane H = {z = 1} and the cylinder over a smooth\n", "conic C = {x(x-2)-y^2 = 0}. Both components are smooth, \n", "but their union is singular along the intersection of \n", "both components." ] }, { "cell_type": "code", "execution_count": null, "id": "transsexual-flash", "metadata": {}, "outputs": [], "source": [ "h = z-1\n", "f = x*(x-2)-y^2\n", "I = ideal(R, f*h)" ] }, { "cell_type": "markdown", "id": "intense-company", "metadata": {}, "source": [ "Let us use our above function to find out about the \n", "singular locus:" ] }, { "cell_type": "code", "execution_count": null, "id": "mounted-jimmy", "metadata": {}, "outputs": [], "source": [ "J = radical_of_singular_locus(I)" ] }, { "cell_type": "code", "execution_count": null, "id": "quarterly-contamination", "metadata": {}, "outputs": [], "source": [ "J_loc = L(J)" ] }, { "cell_type": "markdown", "id": "comfortable-shuttle", "metadata": {}, "source": [ "`J` is now an ideal in the ring `L`. " ] }, { "cell_type": "code", "execution_count": null, "id": "sticky-object", "metadata": {}, "outputs": [], "source": [ "base_ring(J_loc) == L" ] }, { "cell_type": "markdown", "id": "active-separation", "metadata": {}, "source": [ "In particular, it has another data type working in the background!" ] }, { "cell_type": "code", "execution_count": null, "id": "thousand-meter", "metadata": {}, "outputs": [], "source": [ "typeof(J_loc)" ] }, { "cell_type": "code", "execution_count": null, "id": "remarkable-deposit", "metadata": {}, "outputs": [], "source": [ "typeof(J)" ] }, { "cell_type": "markdown", "id": "interracial-consideration", "metadata": {}, "source": [ "Nevertheless, `J_loc` should behave just like any ideal should behave, i.e. \n", "one should be able to ask for a set of generators, one should be able \n", "to test ideal membership of elements, etc. Let us check this in our \n", "geometric example.\n", "\n", "Locally at the point p = (0,0,0), we only have the \n", "smooth component C and its singular intersection \n", "with H is far away. Hence, the localized ideal of \n", "the singular locus should be trivial. Indeed, \n", "we find:" ] }, { "cell_type": "code", "execution_count": null, "id": "indirect-america", "metadata": {}, "outputs": [], "source": [ "one(L) in J_loc" ] }, { "cell_type": "markdown", "id": "proper-holly", "metadata": {}, "source": [ "We can also try to use our above method on the localization of `I` directly:" ] }, { "cell_type": "code", "execution_count": null, "id": "speaking-journalist", "metadata": {}, "outputs": [], "source": [ "I_loc = L(I)" ] }, { "cell_type": "code", "execution_count": null, "id": "cutting-automation", "metadata": {}, "outputs": [], "source": [ "radical_of_singular_locus(I_loc) " ] } ], "metadata": { "kernelspec": { "display_name": "Julia 1.7.3", "language": "julia", "name": "julia-1.7" }, "language_info": { "file_extension": ".jl", "mimetype": "application/julia", "name": "julia", "version": "1.7.3" } }, "nbformat": 4, "nbformat_minor": 5 }