{ "cells": [ { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# Lattices of compatibly embedded finite fields in Nemo/Flint\n", "\n", "*Demonstrating lattices of compatibly embedded finite fields in Nemo.*" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## Jupyter\n", "\n", "* This *Jupyter Notebook* is available on *Binder* at [https://github.com/erou/Nemo-embeddings-demo](https://github.com/erou/Nemo-embeddings-demo)\n", "* Press `Alt + r` to enter/quit slide mode if you are using the *RISE* extension\n", "* every cells are interactive so you can **play around**" ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "data": { "text/plain": [ "40" ] }, "execution_count": 1, "metadata": {}, "output_type": "execute_result" } ], "source": [ "5*8" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## Nemo and Flint\n", "\n", "
\n", "\n", "\n", "* [Nemo](http://nemocas.org/) is a computer algebra package for the [Julia](https://julialang.org/) programming language [maintained by Hart, Hofmann, Fieker, Johansson, and others]\n", " * among many things, it includes a Flint wrapper\n", "* [Flint](http://flintlib.org/) is a number theory library for the C programming language [maintained by William Hart]" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "## Nemo and Flint\n", "\n", "A quick taste of Julia:" ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "data": { "text/plain": [ "foo (generic function with 1 method)" ] }, "execution_count": 2, "metadata": {}, "output_type": "execute_result" } ], "source": [ "function foo(L)\n", " m = L[1] \n", " for i in 2:length(L)\n", " if m < L[i]\n", " m = L[i]\n", " end\n", " end\n", " return m\n", "end" ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "data": { "text/plain": [ "11" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "L = [2, 4, 1, 5, 7, 11, 3]\n", "foo(L)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "## Nemo and Flint" ] }, { "cell_type": "code", "execution_count": 4, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", "Welcome to Nemo version 0.14.3\n", "\n", "Nemo comes with absolutely no warranty whatsoever\n", "\n" ] } ], "source": [ "using Nemo" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "We can play with standard mathematical objects" ] }, { "cell_type": "code", "execution_count": 5, "metadata": { "slideshow": { "slide_type": "-" } }, "outputs": [ { "data": { "text/plain": [ "(5*x^3+x^2+8*x+8)*T^3+(6*x^3+9*x^2+9*x+8)*T^2+(9*x^2+5*x+10)*T+(6*x^3+12*x^2+5*x+1)" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "p = 13\n", "k, x = FiniteField(p, 4, \"x\")\n", "R, T = PolynomialRing(k, \"T\")\n", "P = rand(R, 3)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## The embedding problem\n", "*Example inspired by \"On the powers of 2\" [Granger, Kleinjung, Zumbrägel '14].*\n", "\n", "Let $P$ be an irreducible polynomial in $\\mathbb F_{13^4}[T]$" ] }, { "cell_type": "code", "execution_count": 6, "metadata": { "slideshow": { "slide_type": "-" } }, "outputs": [ { "data": { "text/plain": [ "1 * (T^4+(8*x^3+6*x^2+12*x+2)*T^3+(8*x^3+3*x^2+2*x+2)*T^2+(2*x^3+5*x^2+7*x+12)*T+(3*x^3+4*x^2+6*x+5))" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "P = T^4+(8*x^3+6*x^2+12*x+2)*T^3+(8*x^3+3*x^2+2*x+2)*T^2+(2*x^3+5*x^2+7*x+12)*T+(3*x^3+4*x^2+6*x+5)\n", "factor(P)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "We really want to factor it in degree $2$ factors in $\\mathbb F_{13^8}[U]$:" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "1 * (T^2+(12*y^7+2*y^6+4*y^5+2*y^4+2*y^3+4*y^2+y+7)*T+(5*y^6+2*y^5+2*y^4+9*y^3+6*y+2)) * (T^2+(12*y^7+2*y^6+8*y^5+4*y^4+3*y^3+11*y^2+6)*T+(5*y^7+7*y^6+8*y^5+5*y^4+7*y^3+4*y^2+9*y+2))" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "K, y = FiniteField(p, 8, \"y\")\n", "S, U = PolynomialRing(K, \"U\")\n", "Q = S(P)\n", "factor(Q)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "## The embedding problem\n", "\n", "* $f$ irreducible polynomial of degree $m$ in $\\mathbb F_p[X]$\n", "* $g$ irreducible polynomial of degree $n$ in $\\mathbb F_p[Y]$\n", "* $m\\;|\\;n$\n", "* $E = \\mathbb F_p[X]/(f(X))$\n", "* $F = \\mathbb F_p[Y]/(g(Y))$\n", "\n", "
$E\\cong \\mathbb F_{p^m} \\hookrightarrow F\\cong \\mathbb F_{p^n}$
\n", "\n", "* **Embedding problem:** how to compute the embedding from $E$ to $F$ ?" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## Description and evaluation\n", "\n", "[Brieulle, De Feo, Doliskani, Flori, Schost '17]\n", "\n", "**Two steps:**\n", "- Description: find $\\alpha_1, \\alpha_2$ such that:\n", " - $E = \\mathbb F_p(\\alpha_1)$\n", " - *there exists* an embedding $\\phi:E\\to F$ mapping $\\alpha_1\\mapsto\\alpha_2$\n", "- Evaluation: \n", " - Compute $\\phi(\\gamma)\\in F$ for $\\gamma\\in E$\n", " - Test if $\\delta\\in\\phi(E)$ for $\\delta\\in F$\n", " - If $\\delta\\in\\phi(E)$, compute $\\phi^{-1}(\\delta)\\in E$ " ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## Description - naive algorithm\n", "\n", "**Context:**\n", "- $E = \\mathbb{F}_p[X]/(f)$\n", "- $F=\\mathbb{F}_p[Y]/(g)$\n", "\n", "**Algorithm:**\n", "- Find a root $\\rho$ of $f$ in $F$\n", "- $\\alpha_1 = \\overline X$\n", "- $\\alpha_2 = \\rho$\n", "\n", "**Other algorithms exist:**\n", "- [Lenstra '91]\n", "- [Allombert '02]\n", "- [Rains '96]\n", "- [Narayanan '18]" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "## Description - naive algorithm\n", "\n", "Compute an embedding with `embed`." ] }, { "cell_type": "code", "execution_count": 8, "metadata": { "slideshow": { "slide_type": "-" } }, "outputs": [ { "data": { "text/plain": [] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" }, { "name": "stdout", "output_type": "stream", "text": [ "Morphism from Finite field of degree 6 over F_13\n", "to Finite field of degree 12 over F_13" ] } ], "source": [ "E, x = FiniteField(13, 6, \"x\")\n", "F, y = FiniteField(13, 12, \"y\")\n", "ϕ = embed(E, F)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "and evaluate it" ] }, { "cell_type": "code", "execution_count": 9, "metadata": { "slideshow": { "slide_type": "-" } }, "outputs": [ { "data": { "text/plain": [ "6*y^11+8*y^10+8*y^9+9*y^8+9*y^7+9*y^6+3*y^5+y^4+7*y^3+8*y^2+4" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "ϕ(x)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## Some sanity checks\n", "\n", "We can check that `ϕ` is indeed a morphism:" ] }, { "cell_type": "code", "execution_count": 10, "metadata": { "slideshow": { "slide_type": "-" } }, "outputs": [ { "data": { "text/plain": [ "true" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a = rand(E)\n", "b = rand(E)\n", "ϕ(a^2 + b^7) == ϕ(a)^2 + ϕ(b)^7" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "and that the image of ϕ is in the subfield of $F$ with $13^6$ elements" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(true, true)" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "ϕ(a)^(13^6) == ϕ(a), ϕ(b)^(13^6) == ϕ(b)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## The end ?\n", "\n", "
" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "#
No!
" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## The compatibility problem\n", "\n", "Assume the user wants to use many extensions of $\\mathbb F_p$:\n", "\n", "
" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "## The compatibility problem\n", "\n", "**Context:**\n", "* $E$, $F$, $G$ fields\n", "* $E$ subfield of $F$ and $F$ subfield of $G$\n", "* $\\phi_{E\\hookrightarrow F}$, $\\phi_{F\\hookrightarrow G}$, $\\phi_{E\\hookrightarrow G}$ embeddings\n", "\n", "
\n", "\n", "$\\phi_{F\\hookrightarrow G}\\circ\\phi_{E\\hookrightarrow F}\\overset{?}{=}\\phi_{E\\hookrightarrow G}$\n", "
" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "## The compatibility problem\n", "\n", "**Solutions:**\n", "\n", "- Conway polynomials [Parker '90], [Heath, Loehr '98]\n", " - used in Magma, Sage, PARI, ...\n", " - only practical with small finite fields\n", "- Bosma, Cannon and Steel framework [Bosma, Cannon, Steel '97]" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## Bosma, Cannon and Steel framework\n", "\n", "- Allows to work with arbitrary, user-defined finite fields\n", "- Allows to build the embeddings in arbitrary order\n", "- Used in MAGMA\n", "- based on the naive algorithm" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "## Bosma, Cannon and Steel framework\n", "
\n", "\n", "- Consider $\\alpha$ such that $F=\\mathbb{F}_p(\\alpha)$\n", "- Take $\\rho$ a root of $\\phi_{E\\hookrightarrow G}(\\text{Minpoly}_E(\\alpha))$\n", "- Map $\\alpha\\mapsto\\rho$" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "## Bosma, Cannon and Steel framework\n", "\n", "It works with multiple subfields!\n", "
\n", "\n", "- Consider $\\alpha$ such that $F=\\mathbb{F}_p(\\alpha)$\n", "- Take $\\rho$ a root of $\\text{gcd}_i(\\phi_{E_i\\hookrightarrow G}(\\text{Minpoly}_{E_i}(\\alpha)))$\n", "- Map $\\alpha\\mapsto\\rho$" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "## The compatibility problem\n", "\n", "We define some finite fields $E = \\mathbb F_{p^2}$, $F = \\mathbb F_{p^4}$ and $G = \\mathbb F_{p^8}$." ] }, { "cell_type": "code", "execution_count": 12, "metadata": { "slideshow": { "slide_type": "-" } }, "outputs": [ { "data": { "text/plain": [ "(Finite field of degree 8 over F_5, x8)" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "p = 5\n", "\n", "E, x2 = FiniteField(p, 2, \"x2\")\n", "F, x4 = FiniteField(p, 4, \"x4\")\n", "G, x8 = FiniteField(p, 8, \"x8\")" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "and we compute the embeddings $\\phi_{E\\hookrightarrow F}$, $\\phi_{F\\hookrightarrow G}$, $\\phi_{E\\hookrightarrow G}$" ] }, { "cell_type": "code", "execution_count": 13, "metadata": { "slideshow": { "slide_type": "-" } }, "outputs": [ { "data": { "text/plain": [] }, "execution_count": 13, "metadata": {}, "output_type": "execute_result" }, { "name": "stdout", "output_type": "stream", "text": [ "Morphism from Finite field of degree 4 over F_5\n", "to Finite field of degree 8 over F_5" ] } ], "source": [ "ϕE_F = embed(E, F)\n", "ϕE_G = embed(E, G)\n", "ϕF_G = embed(F, G)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "## The compatibility problem\n", "\n", "**Morphisms are compatible!**" ] }, { "cell_type": "code", "execution_count": 14, "metadata": { "scrolled": true, "slideshow": { "slide_type": "-" } }, "outputs": [ { "data": { "text/plain": [ "true" ] }, "execution_count": 14, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a = rand(E)\n", "ϕE_G(a) == (ϕF_G ∘ ϕE_F)(a)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## The compatibility problem II\n", "\n", "
\n", "$\\phi_{G\\hookrightarrow H}\\circ\\phi_{E\\hookrightarrow G}\\overset{?}{=}\\phi_{F\\hookrightarrow H}\\circ\\phi_{E\\hookrightarrow F}$\n", "
" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "## The compatibility problem II\n", "\n", "We create new finite fields" ] }, { "cell_type": "code", "execution_count": 15, "metadata": { "slideshow": { "slide_type": "-" } }, "outputs": [ { "data": { "text/plain": [ "(Finite field of degree 12 over F_5, x12)" ] }, "execution_count": 15, "metadata": {}, "output_type": "execute_result" } ], "source": [ "G, x6 = FiniteField(p, 6, \"x6\")\n", "H, x12 = FiniteField(p, 12, \"x12\")" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "and embeddings between them" ] }, { "cell_type": "code", "execution_count": 16, "metadata": { "slideshow": { "slide_type": "-" } }, "outputs": [ { "data": { "text/plain": [] }, "execution_count": 16, "metadata": {}, "output_type": "execute_result" }, { "name": "stdout", "output_type": "stream", "text": [ "Morphism from Finite field of degree 6 over F_5\n", "to Finite field of degree 12 over F_5" ] } ], "source": [ "ϕE_G = embed(E, G)\n", "ϕF_H = embed(F, H)\n", "ϕG_H = embed(G, H)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "## The compatibility problem II\n", "\n", "\n", "**Morphisms are still compatible!**" ] }, { "cell_type": "code", "execution_count": 17, "metadata": { "slideshow": { "slide_type": "-" } }, "outputs": [ { "data": { "text/plain": [ "true" ] }, "execution_count": 17, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a = rand(E)\n", "(ϕG_H ∘ ϕE_G)(a) == (ϕF_H ∘ ϕE_F)(a)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## Implicit conversion\n", "\n", "We do not need to explicitly call ``embed``. Standard object oriented conversion also works." ] }, { "cell_type": "code", "execution_count": 18, "metadata": { "slideshow": { "slide_type": "-" } }, "outputs": [ { "data": { "text/plain": [ "(Finite field of degree 24 over F_5, x24)" ] }, "execution_count": 18, "metadata": {}, "output_type": "execute_result" } ], "source": [ "k3, x3 = FiniteField(p, 3, \"x3\")\n", "k24, x24 = FiniteField(p, 24, \"x24\")" ] }, { "cell_type": "code", "execution_count": 19, "metadata": { "slideshow": { "slide_type": "-" } }, "outputs": [ { "data": { "text/plain": [ "3*x24^23+4*x24^22+3*x24^20+4*x24^19+3*x24^18+3*x24^17+2*x24^14+4*x24^12+x24^11+4*x24^10+2*x24^9+4*x24^8+3*x24^6+3*x24^5+2*x24^4+4*x24^3+x24^2+1" ] }, "execution_count": 19, "metadata": {}, "output_type": "execute_result" } ], "source": [ "z = k24(x3)" ] }, { "cell_type": "code", "execution_count": 20, "metadata": { "slideshow": { "slide_type": "-" } }, "outputs": [ { "data": { "text/plain": [ "true" ] }, "execution_count": 20, "metadata": {}, "output_type": "execute_result" } ], "source": [ "z^(p^3) == z" ] }, { "cell_type": "code", "execution_count": 21, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "x3" ] }, "execution_count": 21, "metadata": {}, "output_type": "execute_result" } ], "source": [ "k3(z)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## Sections\n", "\n", "We can also compute sections of morphisms." ] }, { "cell_type": "code", "execution_count": 22, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(Finite field of degree 21 over F_5, x21)" ] }, "execution_count": 22, "metadata": {}, "output_type": "execute_result" } ], "source": [ "k7, x7 = FiniteField(p, 7, \"x7\")\n", "k21, x21 = FiniteField(p, 21, \"x21\")" ] }, { "cell_type": "code", "execution_count": 23, "metadata": {}, "outputs": [ { "data": { "text/plain": [] }, "execution_count": 23, "metadata": {}, "output_type": "execute_result" }, { "name": "stdout", "output_type": "stream", "text": [ "Morphism from Finite field of degree 7 over F_5\n", "to Finite field of degree 21 over F_5" ] } ], "source": [ "f7_21 = embed(k7, k21)" ] }, { "cell_type": "code", "execution_count": 24, "metadata": {}, "outputs": [ { "data": { "text/plain": [] }, "execution_count": 24, "metadata": {}, "output_type": "execute_result" }, { "name": "stdout", "output_type": "stream", "text": [ "Section from Finite field of degree 21 over F_5\n", "to Finite field of degree 7 over F_5" ] } ], "source": [ "s21_7 = section(f7_21)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "## Sections\n", "\n", "Sections give the preimage of an element if it is in the codomain of the embedding" ] }, { "cell_type": "code", "execution_count": 25, "metadata": { "slideshow": { "slide_type": "-" } }, "outputs": [ { "data": { "text/plain": [ "true" ] }, "execution_count": 25, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a = rand(k7) \n", "(s21_7 ∘ f7_21)(a) == a" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "And throw an error otherwise" ] }, { "cell_type": "code", "execution_count": 26, "metadata": {}, "outputs": [ { "ename": "ArgumentError", "evalue": "ArgumentError: not an element in the subfield of degree 7 over F_5", "output_type": "error", "traceback": [ "ArgumentError: not an element in the subfield of degree 7 over F_5", "", "Stacktrace:", " [1] (::Nemo.FinFieldSection{FqNmodFiniteField})(::fq_nmod) at /home/erou/.julia/packages/Nemo/gWAgl/src/FinFieldsTypes.jl:49", " [2] top-level scope at In[26]:1" ] } ], "source": [ "s21_7(x21)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "## Sections\n", "\n", "\n", "This can also be called implicitly" ] }, { "cell_type": "code", "execution_count": 27, "metadata": { "slideshow": { "slide_type": "-" } }, "outputs": [ { "data": { "text/plain": [ "x7" ] }, "execution_count": 27, "metadata": {}, "output_type": "execute_result" } ], "source": [ "k7(k21(x7))" ] }, { "cell_type": "code", "execution_count": 28, "metadata": {}, "outputs": [ { "ename": "ArgumentError", "evalue": "ArgumentError: not an element in the subfield of degree 7 over F_5", "output_type": "error", "traceback": [ "ArgumentError: not an element in the subfield of degree 7 over F_5", "", "Stacktrace:", " [1] (::Nemo.FinFieldSection{FqNmodFiniteField})(::fq_nmod) at /home/erou/.julia/packages/Nemo/gWAgl/src/FinFieldsTypes.jl:49", " [2] (::FqNmodFiniteField)(::fq_nmod) at /home/erou/.julia/packages/Nemo/gWAgl/src/flint/fq_nmod.jl:462", " [3] top-level scope at In[28]:1" ] } ], "source": [ "k7(x21)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## Behind the scenes\n", "\n", "- root finding is done by *Flint* (in C)\n", "- minimal polynomials are computed by *Nemo* (in Julia)\n", "- additionnal requirements of Bosma, Cannon and Steel framework are done in *Nemo*\n", "- (almost) all the time is spent in *root finding*\n", "- embedding evaluation is done via *matrix-vector multiplication*" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## More features planned\n", "\n", "- Vector space morphisms,\n", "- Algorithmic improvements,\n", "- more efficient framework using Lenstra/Allombert embedding algorithm as building block" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "#
Thank you!
" ] } ], "metadata": { "celltoolbar": "Slideshow", "kernelspec": { "display_name": "Julia 1.1.0", "language": "julia", "name": "julia-1.1" }, "language_info": { "file_extension": ".jl", "mimetype": "application/julia", "name": "julia", "version": "1.1.0" } }, "nbformat": 4, "nbformat_minor": 2 }