{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# About the organization of the notebook\n", "\n", "In this document, the implementation of different mathematical objects is explained. For each one, the information is structured in the following way:\n", "\n", "1) First section: Definition. The object is defined using mathematical language.\n", "2) Second section: Implementation.\n", " 1) Ideas and decisions made\n", " 2) Initial declaration of the main class\n", " 3) Implementation of a new method and examples\n", "\n", "Each class is declared iteratively, i.e., each method is added in a different cell in order to explain it properly and to show examples. This is done in that way for a didactic purpose. For that reason, the subsection 2.c) is repeated for each new method that is added to the main class.\n", "\n", "***" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# The cochain algebra $(A_{PL})_{n}$\n", "In this section it is implemented the graded commutative differential cochain algebra $(A_{PL})_{n}$. For more information, see [Rational homotopy theory, Felix, Halperin, Thomas, chapter 10.c)].\n", "\n", "## Definition\n", "First, consider the free graded commutative algebra $\\Lambda(t_0,\\dots,t_n,y_0,\\dots,y_n)$, where the generators $t_i$ have degree $0$, and the generators $y_j$ have degree $1$. The differential, $d$, is given by \n", "\n", "* $d(t_i)=y_i$\n", "* $d(y_j)=0$\n", "\n", "The cochain algebra $(A_{PL})_n$ is defined as the quotient of the previous algebra by the relations:\n", "\n", "\n", "\n", "$$(A_{PL})_n=\\frac{\\Lambda(t_0,\\dots,t_n,y_0,\\dots,y_n)}{<\\sum {t_i}-1,\\sum{y_j}>}$$\n", "\n", "\n", "## Implementation\n", "\n", "$(A_{PL})_{n}$ is a graded commutatite differential algebra, GCDA. In order to work with GCDA's that are finitely generated by elements of $degree \\geq 1$, there is defined in SAGE a class called \"DifferentialGCAlgebra\". Our first problem is that our GCDA has generators of $degree=0$ (the generators $t_i$) and this class doesn't allow us to create such object. \n", "\n", "As a first approximation, in order to solve this problem, we will define a new class of GCDA's that internally will work with multigraded generators, but this feature will be transparent for the user. For that reason, we will extend the class \"DifferentialGCAlgebra_multigraded\" in order to add new methods that will be useful later." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Initial declaration of the main class" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from sage.algebras.commutative_dga import *\n", "import copy\n", "\n", "class AplN(DifferentialGCAlgebra_multigraded, UniqueRepresentation):\n", " \"\"\"\n", " A differential multi-graded commutative algebra\n", " \n", " This class extends the DifferentialGCAlgebra_multigraded class\n", " to create the algebra of polynomial differential forms with coefficients in QQ\n", "\n", " INPUT:\n", "\n", " - ``A`` -- a multi-graded commutative algebra\n", " - ``differential`` -- the differential rules\n", "\n", " \"\"\"\n", "\n", " def __init__(self, A, differential):\n", " \"\"\"\n", " Initialize ``self``.\n", "\n", " INPUT:\n", "\n", " - ``A`` -- a multi-graded commutative algebra\n", " - ``differential`` -- a differential\n", " \"\"\"\n", "\n", " self.n = len(A._names)/2-1\n", " DifferentialGCAlgebra_multigraded.__init__(self, A, differential)\n", " self.t_relation = sum(self.gens()[:self.n+1])-1\n", " self.y_relation = sum(self.gens()[self.n+1:])\n", "\n", " def _base_repr(self):\n", " \"\"\"\n", " Return the base string representation of ``self``.\n", " \"\"\"\n", "\n", " s = DifferentialGCAlgebra._base_repr(self)\n", " old = '{}'.format(self._degrees)\n", " new = '{}'.format([i[0] for i in self._degrees_multi])\n", " return s.replace(old, new)\n", "\n", " class Element(GCAlgebra_multigraded.Element, DifferentialGCAlgebra.Element):\n", " \"\"\"\n", " Element class of the commutative differential multi-graded algebra (Apl)n.\n", " \"\"\"\n", " pass\n", " \n", "def AlgebraPL(n):\n", " \"\"\"\n", " The graded commutative differential cochain algebra Apl of dimension ``n``\n", "\n", " INPUT:\n", "\n", " - ``n`` -- A non-negative integer corresponding to the number of generators of degree 0.\n", " \"\"\"\n", "\n", " if (n<0):\n", " raise ValueError('`n` must be a non-negative integer')\n", " ts = ['t'+str(t) for t in range(n+1)]\n", " ys = ['y'+str(t) for t in range(n+1)]\n", " degrees = tuple((n+1)*[(0,2)])+tuple((n+1)*[(1,2)])\n", " gca = GradedCommutativeAlgebra(QQ, names=ts+ys, degrees=degrees)\n", " differentials = {gca.gens_dict()[ts[i]]:gca.gens_dict()[ys[i]] for i in range(n+1)}\n", " return AplN(gca,differentials)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Example: creating an element of $(Apl)_{n}$" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Commutative Differential Graded Algebra with generators ('t0', 't1', 'y0', 'y1') in degrees [0, 0, 1, 1] over Rational Field with differential:\n", " t0 --> y0\n", " t1 --> y1\n", " y0 --> 0\n", " y1 --> 0\n", "Defining t0, t1, y0, y1\n" ] } ], "source": [ "apl = AlgebraPL(1)\n", "print(apl)\n", "apl.inject_variables()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "y0 + y1 + t0" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "p = t0 + y0 + y1\n", "p" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Adding new methods: homogeneity and total degree of a polynomial\n", "\n", "As we mentioned before, we use a multigraded algebra internally. Specifically, we use a bigraded algebra, where the generators have either degree $(0,2)$ or degree $(1,2)$ The first component of the bigrade represents the actual degree we want to use, and the second component is ignored (it is only needed to be an even number $>0$). In particular, the generators $t_i$ have internally a degree $(0,2)$ and the generators $y_j$ have degree $(1,2)$. In order to make it transparent for the user, we implement a several methods to get, for example, the homogeneous part of a polynomial, ignoring the mentioned bigrade, and taking into account only the first compoment of the multigrade." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "class AplN(AplN,UniqueRepresentation):\n", " class Element(AplN.Element):\n", " \"\"\"\n", " Element class of the commutative differential multi-graded algebra (Apl)n.\n", " \"\"\"\n", " \n", " def is_homogeneous(self):\n", " \"\"\"\n", " Return \"True\" if \"self\" is homogeneous and \"False\" otherwise.\n", " \"\"\"\n", " \n", " degrees = set([k[0] for k in self.homogeneous_parts()])\n", " return len(degrees) == 1\n", " \n", " def total_degree(self):\n", " \"\"\"\n", " Return the total degree of this element.\n", " \"\"\" \n", " \n", " degrees = set([k[0] for k in self.homogeneous_parts()])\n", " return max(degrees)\n", " \n", " def homogeneous_part(self,degree):\n", " \"\"\"\n", " Returns the homogeneous part of the element for a given degree.\n", " \"\"\"\n", "\n", " if (degree<0):\n", " raise ValueError('`degree` must be a non-negative integer')\n", " parts = [self.homogeneous_parts()[k] for k in self.homogeneous_parts() if list(k)[0]==degree]\n", " return sum(parts)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Example: checking the homogeneity of a given polynomial" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Defining t0, t1, y0, y1\n" ] } ], "source": [ "apl = AlgebraPL(1)\n", "apl.inject_variables()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "False" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "p = t0 + y0 + y1\n", "p.is_homogeneous()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Example: getting the homogeneous part of a polynomial for a given degree" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Original polynomial: y0 + y1 + t0\n", "Homogeneous part of degree 1 of p: y0 + y1\n" ] } ], "source": [ "p = t0 + y0 + y1\n", "deg = 1\n", "print(\"Original polynomial:\", p)\n", "print(\"Homogeneous part of degree\", deg, \"of p: \", p.homogeneous_part(degree=deg))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Example: getting the total degree of a polynomial" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "2" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "q = y0*y1 + t0*y1 + 1\n", "q.total_degree()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Adding new method: reduce a polynomial by relations\n", "\n", "As seen in the definition, the algebra $(A_{PL})_{n}$ is the quiotient algebra\n", "\n", "$$(A_{PL})_n=\\frac{\\Lambda(t_0,\\dots,t_n,y_0,\\dots,y_n)}{<\\sum {t_i}-1,\\sum{y_j}>}$$\n", "\n", "Notice that there is an isomorphism between this algebra and the free algebra:\n", "\n", "$$ (A_{PL})_n \\cong \\Lambda(t_1,\\dots,t_n,y_1,\\dots,y_n) $$\n", "\n", "\n", "In order to obtain a representative of a particular element on the free algebra, a method called \"reduce\" is added to the elements of our class. This method reduces the variables $t_0,y_0$ applying the following rules:\n", "\n", "$$t_0 = 1 - \\sum_{i=1}^{n} t_i$$\n", "$$y_0 = -\\sum_{j=1}^{n} y_j$$\n", "\n", "Thus, after applying this method, an element of $(A_{PL})_{n}$ will be represented as an element of the algebra $\\Lambda(t_1,\\dots,t_n,y_1,\\dots,y_n)$.\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "class AplN(AplN,UniqueRepresentation):\n", " class Element(AplN.Element):\n", " \"\"\"\n", " Element class of the commutative differential multi-graded algebra (Apl)n.\n", " \"\"\"\n", " def reduce(self, relations=[]):\n", " \"\"\"\" \n", " The method reduces the polynomial by the Ideal \n", " \n", " INPUT::\n", " - p: polynomial in variables t_0,..t_n,y_0,...,y_n\n", " - relations (optional): if relations are given, the polynomial is reduced following\n", " this rules. If no relations are given, the polynomial is reduced taking into\n", " account the relations of the parent algebra.\n", " \n", " OUTPUT::\n", " - The polynomial after applying the corresponding relations \n", " \"\"\"\n", " apl = self.parent()\n", " dim = len(apl.gens())//2-1\n", " if relations:\n", " return DifferentialGCAlgebra.Element.reduce(self, relations)\n", " else:\n", " return DifferentialGCAlgebra.Element.reduce(self, [apl.t_relation, apl.y_relation])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Example: getting the reduced polynomial of a given element" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Defining t0, t1, y0, y1\n" ] } ], "source": [ "apl = AlgebraPL(1)\n", "apl.inject_variables()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "unreduced polynomial: y0 + y1 + t0\n", "reduced polynomial: -t1 + 1\n" ] } ], "source": [ "p=t0+y0+y1\n", "print(\"unreduced polynomial: \", p)\n", "print(\"reduced polynomial: \", p.reduce())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Adding new methods: The definite integral map\n", "\n", "We define a linear map:\n", "\n", "$$ \\int_{n}: (A_{PL})_{n}^{n} \\rightarrow \\mathbb{Q} $$\n", "\n", "by setting\n", "\n", "$$ \\int_{n}t_1^{k_1}t_2^{k_2}\\dots t_n^{k_n}dt_1\\wedge \\dots \\wedge dt_n = \\int_{0}^{1} dt_1 \\int_{0}^{1-t_1}dt_2 \\dots \\int_{0}^{1-\\sum_{1}^{n-1}t_i}t_1^{k_1}t_2^{k_2}\\dots t_n^{k_n}dt_n = \\frac{k_1!k_2! \\dots k_n!}{(k_1+ \\dots +k_n+n)!} $$" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "class AplN(AplN,UniqueRepresentation):\n", " class Element(AplN.Element):\n", " \"\"\"\n", " Element class of the commutative differential multi-graded algebra (Apl)n.\n", " \"\"\"\n", " def _integrable_part(self):\n", " \n", " \"\"\"\n", " The method returns the coefficient in Q[t_1,...,t_n] of the term\n", " of degree `n`\n", "\n", " OUTPUT:\n", " - A polynomial in the ring Q.\n", " (After reducing the variables t_{0},y_{0} by the corresponding relations, \n", " the algorithm removes the variables y_{1},..,y_{n}). \n", " \"\"\"\n", " \n", " apl = self.parent()\n", " pol = apl(self.reduce()) #needed in case reduce() returns an integer\n", " relations = []\n", " for i in range(apl.n+1): \n", " relations.append(apl.gens()[apl.n+1+i]-1)\n", " pol = apl(pol.homogeneous_part(degree=apl.n)) \n", " return apl(pol.reduce(relations=relations))\n", "\n", " def integral(self):\n", " \"\"\"\n", " Returns the definite integral of the term of degree `n`\n", " \n", " OUTPUT:\n", " - The rational number obtained by the definite integral \n", " of the term of degree `n`\n", " \n", " \"\"\"\n", "\n", " apl = self.parent()\n", " pol = self._integrable_part()\n", " result = 0\n", " for k in pol.dict().keys(): # k is a monomial\n", " numerator = 1\n", " denominator = apl.n\n", " for e in k: # e is an exponents\n", " numerator *= factorial(e)\n", " denominator += e\n", " coef = pol.dict()[k]\n", " result += coef*numerator/factorial(denominator)\n", " #return ((-1)**(apl.n*(apl.n-1)/2))*result\n", " return result" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Example" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Defining t0, t1, y0, y1\n" ] } ], "source": [ "apl = AlgebraPL(1)\n", "apl.inject_variables()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Integrable part: -t1 + 2\n", "Definite integral: 3/2\n" ] } ], "source": [ "p=t0+y1*(t0+1)\n", "print(\"Integrable part: \",p._integrable_part())\n", "print(\"Definite integral: \", p.integral())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Adding new method: find an integrand for a given definite integral\n", "\n", "The linear map we have defined above is not injective, but we can consider one way to find a polynomial whose image by the definite integral map is given. We call \"integrand\" to this particular element of the preimage set of the given element by the linear map.\n", "\n", "$$ \\int_{n}^{-1} c = c (n!) dt_1 \\wedge \\dots \\wedge dt_n$$\n", "$$ c \\in \\mathbb{Q} $$\n", "\n", "It is easy to see that $ \\int_{n}\\int_{n}^{-1} c = c $ although the inverse is not always true. \n", "\n", "We define a class method, called \"integrand\", that returns a polynomial whose definite integral image is equal to a rational number given as input." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "class AplN(AplN,UniqueRepresentation):\n", " def integrand(self, value): \n", " \"\"\"\n", " Returns a polynomial whose definite integral is equal to 'value'\n", "\n", " OUTPUT:\n", " - A polynomial\n", " \"\"\"\n", " return value*factorial(self.n)*prod(self.gens()[self.n+2:])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Example: getting a polynomial for whose definite integral is given" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Defining t0, t1, y0, y1\n" ] } ], "source": [ "apl = AlgebraPL(1)\n", "apl.inject_variables()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "5*y1" ] }, "execution_count": 17, "metadata": {}, "output_type": "execute_result" } ], "source": [ "value = 5\n", "apl.integrand(value)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 18, "metadata": {}, "output_type": "execute_result" } ], "source": [ "#checking that the composition of the integral and the lift is the identity map\n", "p = apl.integrand(value)\n", "p.integral()==value" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Adding new methods: find a primitive of the coboundary operator\n", "\n", "As we have mentioned before, there is an isomorphism between the cochain algebra $(A_{PL})_n$ and the algebra $\\Lambda (t_1, \\dots, t_n,y_1, \\dots, y_n)$, where the variables $t_i$ have degree $0$, and the variables $y_j$ have degree $1$. This algebra is the tensor product of the polynomial ring in the variables $t_i$ with the exterior algebra in the variables $y_j$:\n", "\n", "$$(A_{PL})_n \\cong \\mathbb{Q}[t_1, \\dots, t_n]\\otimes_{\\mathbb{Q}} \\Lambda ^{\\mathbb{Q}}(y_1, \\dots, y_n)$$\n", "\n", "In this algebra, we define the lexicographic monomial order in the variables $y_i$ as \n", "\n", "$$y_i > y_j, \\: if \\: i k_{1}^{i+1}$\n", "- $\\exists m \\in \\mathbb{N}, 1 < m \\leq n $ so that $k_{l}^{i} = k_{l}^{i+1}$ for $1 \\leq l < m$, and $k_{l}^{i} > k_{l}^{i+1}$ for $l= m$.\n", "\n", "\n", "Our algebra $(A_{PL})_n$, as a cochain algebra, has a coboundary operator, $d$, and by definition, we know that $d^2=0$. Also, we know that $H^p((A_{PL})_n)=0$ for $p \\geq 1$, meaning that, for every element $\\theta \\in (A_{PL})_n$ so that $d\\theta=0$ (i.e., $\\theta$ is closed), there exists an element $\\omega \\in (A_{PL})_n$ so that $\\theta = d\\omega$.\n", "\n", "Our problem here is to find a primitive $\\omega$ whose differential $\\theta$ is known, $\\theta = d\\omega$. As we know that $\\theta$ is the differential of some element, for now on we will consider polynomials where all terms have at least one exponent $k_{j}^{i} \\neq 0$ (i.e., our polynomial $\\theta$ has no terms of degree $0$)." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Definition**. (pseudo-primitive of a monomial) Let $\\theta \\in (A_{PL})_n$ be a polynomial formed by only one term of degree $p$ of the form:\n", "\n", "$$\\theta = ct_{1}^{l_{1}^{0}} \\dots t_{n}^{l_{n}^{0}} y_{1}^{k_{1}^{0}} \\dots y_{n}^{k_{n}^{0}}$$\n", "\n", "satisfying:\n", "\n", "- $c \\in \\mathbb{Q}$\n", "- $k_{j}^{i} \\in \\mathbb{Z}_2$\n", "- $\\sum k_{j}^{i} = p$\n", "- $l_{j}^{i} \\in \\mathbb{N} \\cup \\{0\\}$\n", "\n", "We define the *pseudo-primitive of $\\theta$* (in relation to the coboundary operator) as the homogeneous polynomial $\\omega$, of degree $p-1$, whose differential is the polynomial $\\theta$ plus some homogeneous polynomial $\\epsilon$ of degree $p$:\n", "\n", "$$d\\omega = \\theta+\\epsilon$$\n", "\n", "This polynomial is calculated in the following way:\n", "\n", "**Step 1:** Choose the lowest $i$ for which $k_{i}^{0}=1$\n", "\n", "**Step 2:** Set $k_{i}^{0}=0$ and increase $l_{i}^{0}$ by 1\n", "\n", "$$ \\omega = ct_{1}^{l_{1}^{0}} \\dots t_{i}^{l_{i}^{0}+1} \\dots t_{n}^{l_{n}^{0}} y_{1}^{0} \\dots y_{i}^{0} \\dots y_{n}^{k_{n}^{0}}$$\n", "\n", "**Step 3:** Divide the coefficient $c$ by $l_{i}^{0}+1$\n", "\n", "$$ \\omega = \\frac{c}{l_{i}^{0}+1}t_{1}^{l_{1}^{0}} \\dots t_{i}^{l_{i}^{0}+1} \\dots t_{n}^{l_{n}^{0}} y_{1}^{0} \\dots y_{i}^{0} \\dots y_{n}^{k_{n}^{0}}$$\n", "\n", "\n", "**Lemma**: $d\\omega= \\theta + \\epsilon$\n", "\n", "**Proof**: TODO\n", "***\n", "\n", "\n", "#### **The algorithm**\n", "\n", "The input of our algorithm is a polynomial $\\theta \\in (A_{PL})_n$ that has the form:\n", "\n", "$$ \\theta = p^0 y_{1}^{k_{1}^{0}} \\dots y_{n}^{k_{n}^{0}} + p^1 y_{1}^{k_{1}^{1}} \\dots y_{n}^{k_{n}^{1}} + \\dots $$\n", "\n", "$$p^i \\in \\mathbb{Q}[t_1, \\dots, t_n]$$\n", "\n", "**Step 1**: Find a pseudo-primitive of the leading term of $\\theta$.\n", "\n", "First, we define the variables $\\omega, \\theta_0$, and we initialize them as \n", "\n", "$$\\omega=0$$\n", "$$\\theta_0=\\theta$$\n", "\n", "The leading term of $\\theta_0$, $LT(\\theta_0)$, has the form:\n", "\n", "$$LT(\\theta_0) = c_0t_{1}^{l_{1}^{0}} \\dots t_{n}^{l_{n}^{0}} y_{1}^{k_{1}^{0}} \\dots y_{n}^{k_{n}^{0}}$$\n", "$$ c_0\\in \\mathbb{Q}$$\n", "$$ l_{i}^{0} \\geq 0$$\n", "\n", "What we want to do in this step is to find a polynomial $\\omega_0$ whose differential contains the leading term of the element $\\theta_0$ plus some extra terms $\\epsilon_0$:\n", "\n", "$$d\\omega_0 = LT(\\theta_0)+\\epsilon_0$$\n", "\n", "Knowing that the coboundary operator increases the degree in 1 unit, and the degree of every term comes from the variables $y_j$, one approach is the following:\n", "\n", "1) Assign to $\\omega_0$ the leading term of $\\theta_0$, \n", "2) Choose the lowest $i$ for which $k_{i}^{0}=1$\n", "3) Set $k_{i}^{0}=0$ and increase $l_{i}^{0}$ by 1\n", "4) Divide the coefficient $c_0$ by $l_{i}^{0}+1$\n", "\n", "$$ \\omega_0 = \\frac{c_0}{l_{i}^{0}+1}t_{1}^{l_{1}^{0}} \\dots t_{i}^{l_{i}^{0}+1} \\dots t_{n}^{l_{n}^{0}} y_{1}^{0} \\dots y_{i}^{0} \\dots y_{n}^{k_{n}^{0}}$$\n", "\n", "TODO: Prueba de que esto funciona:\n", "\n", "$$\\omega_0 = c_0a(t)*b(y)$$\n", "$$d\\omega_0 = d(c_0a(t))*b(y)) = c_0d(a(t))b(y)$$\n", "\n", "**Step 2**: Calculate the new $\\theta_i$:\n", "\n", "Once we have found the element $\\omega_0$, we update the variable $\\omega$ as:\n", "\n", "$$ \\omega = \\omega + \\omega_0$$\n", "\n", "and we define the new variable $\\theta_{1}$ as:\n", "\n", "$$ \\theta_{1} = \\theta-d\\omega $$\n", "\n", "If $\\theta_{1}=0$ we have finished and $\\omega$ is the element we were looking for. If $\\theta_{1} \\neq 0$, continue with the following steps.\n", "\n", "\n", "**Step 3**:\n", "\n", "Get the leading term of $\\theta_{1}$, and obtain its pseudo-primitive $\\omega_1$.\n", "\n", "**Step 4:**\n", "\n", "Update the variable $\\omega$ as:\n", "\n", "$$ \\omega = \\omega + \\omega_1$$\n", "\n", "and define the new variable $\\theta_{2}$ as:\n", "\n", "$$ \\theta_{2} = \\theta-d\\omega $$\n", "\n", "**Step 5:**\n", "If $\\theta_{2}=0$ we have finished and $\\omega$ is the element we were looking for. If $\\theta_{2} \\neq 0$, go back to step 3 and repeat the steps 3 and 4 several times until we get that $\\theta_{i+1}=0$.\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "class AplN(AplN,UniqueRepresentation):\n", " class Element(AplN.Element):\n", " \"\"\"\n", " Element class of the commutative differential multi-graded algebra (Apl)n.\n", " \"\"\"\n", " \n", " def _get_term(self, coef, exp, gens):\n", " \"\"\"\" \n", " \n", " Returns the term specified by its coefficient, exponents and generators\n", " \n", " INPUT::\n", " - coef: The coefficient of the term\n", " - exp: A tuple with the exponents of each variable\n", " - gens: The generators\n", " \n", " OUTPUT::\n", " - A polynomial\n", " \"\"\"\n", " return coef*prod(list(map(lambda exp, gen: gen^exp, exp, gens)))\n", "\n", " def _get_terms(self):\n", " \"\"\"\" \n", " \n", " Returns self seen as a collection of terms in the variables y_j with coefficients in QQ\n", " \n", " OUTPUT::\n", " - A dictionary with all terms\n", " \n", " \"\"\"\n", " a = self.parent()\n", " n = len(a.gens())/2\n", " ts_only_gens = a.gens()[:n]+tuple(n*[1])\n", " ys_only_gens = tuple(n*[1])+a.gens()[n:]\n", " terms = {}\n", " pol = self.dict()\n", " for exp in pol.keys():\n", " key = self._get_term(1, exp,ys_only_gens)\n", " coef = self._get_term(pol[exp],exp,ts_only_gens)\n", " if key not in terms.keys():\n", " terms[key] = coef\n", " else:\n", " terms[key] += coef \n", " return terms\n", "\n", " def _get_leading_pol(self):\n", " \"\"\"\" \n", " \n", " Returns the leading polynomial\n", " \n", " OUTPUT::\n", " - A polynomial\n", " \"\"\"\n", " terms = self._get_terms()\n", " keys = list(terms.keys())\n", " keys.sort(reverse=True)\n", " return terms[keys[0]]*keys[0]\n", "\n", " def _get_idx(self, exp):\n", " \"\"\"\" \n", " \n", " Returns the idx 'i' of the first generator 'y_i' that appears in exp\n", " \n", " INPUT::\n", " - exp: A tuple with the exponents\n", " \n", " OUTPUT::\n", " - A non-negative number lower or equal to 'n'\n", " \"\"\"\n", " n = len(exp)/2\n", " filter_ts = n*[0]+n*[1]\n", " diff_forms = list(map(lambda v, f: v*f, exp, filter_ts))\n", " return next((i for i, x in enumerate(list(diff_forms)) if x), None)-n\n", "\n", " def _monomial_primitive(self, monomial, idx):\n", " \"\"\"\" \n", " \n", " Returns the primitive of the given monomial\n", " \n", " INPUT::\n", " - monomial: A monomial\n", " - idx: the index of the variable y_j that will be used to calculate the pseudo-primitive\n", " \n", " OUTPUT::\n", " - A polynomial\n", " \"\"\"\n", " exp = list(monomial.dict().keys())[0]\n", " coef = monomial.dict()[exp]\n", " n = len(exp)/2\n", " if (exp[n+idx]==0):\n", " raise IndexError(\"It is not possible to get a primitive using the given idx.\")\n", " primitive = list(copy.deepcopy(exp))\n", " primitive[n+idx] = 0\n", " primitive[idx] += 1\n", " new_coef = coef/primitive[idx]\n", " a = monomial.parent()\n", " return self._get_term(new_coef, primitive, a.gens())\n", "\n", " def _leading_primitive(self):\n", " \"\"\"\" \n", " Returns the primitive of the leading term of self\n", " \n", " OUTPUT::\n", " - A polynomial\n", " \"\"\"\n", " polynomial = self._get_leading_pol()\n", " # necessary condition: all monomials have apl.gens[n+idx] factor\n", " exp = list(polynomial.dict().keys())[0]\n", " idx = self._get_idx(exp)\n", " aGens = polynomial.parent().gens()\n", " primitive = 0\n", " for exp in polynomial.dict().keys():\n", " coef = polynomial.dict()[exp]\n", " monomial = self._get_term(coef, exp, aGens)\n", " primitive += self._monomial_primitive(monomial, idx)\n", " terms = primitive._get_terms()\n", " result = sum([terms[key]*key for key in terms.keys()])\n", " return result\n", "\n", " def primitive(self):\n", " \"\"\"\" \n", " Retuns a polynomial whose differential is self\n", " \n", " OUTPUT::\n", " - A polynomial\n", " \"\"\"\n", " if self.differential()!=0 :\n", " raise ValueError(\"This polynomial is not closed.\")\n", " w = self._leading_primitive()\n", " theta = self - w.differential()\n", " if (theta == 0):\n", " return w\n", " else:\n", " return w+theta.primitive()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Example" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Defining t0, t1, t2, t3, t4, t5, y0, y1, y2, y3, y4, y5\n" ] } ], "source": [ "apl = AlgebraPL(5)\n", "apl.inject_variables()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "True\n", "False\n" ] } ], "source": [ "omega_orig = t0+5*y1*y2+y3*y4*t1*y5\n", "theta = omega_orig.differential()\n", "print(theta.primitive().differential()==theta)\n", "print(theta.primitive()==omega_orig)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "0\n", "True\n", "t0*t1^2*y1*y3 + 1/2*t0^2*y1*y3 + t0*y1*y3\n" ] } ], "source": [ "theta = (t0+t1^2+1)*y0*y1*y3\n", "print(theta.differential())\n", "print(theta.primitive().differential()==theta)\n", "print(theta.primitive())" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# The simplicial cochain algebra $A_{PL}$\n", "This class implements the simplicial cochain algebra $A_{PL} = \\{(A_{PL})_{n}\\}_{n\\geq0}$. For more information, see [Rational homotopy theory, Felix, Halperin, Thomas, chapter 10.c)].\n", "\n", "## Definition\n", "\n", "A simplicial object $K$ with values in a category $\\mathfrak{C}$ is a sequence $\\{K_n\\}_{n \\geq 0}$ of objects in $\\mathfrak{C}$, together with $\\mathfrak{C}$-morphisms:\n", "\n", "$$\\delta_i: K_{n} \\rightarrow K_{n-1}, \\; 0 \\leq i \\leq n $$ \n", "\n", "$$s_j: K_{n} \\rightarrow K_{n+1}, \\; 0 \\leq j \\leq n$$\n", "\n", "that satisfy the identities:\n", "\n", "$$\\delta_i \\delta_j = \\delta_{j-1} \\delta_i,\\; i j+1\n", "\\end{matrix}\\right.$$\n", "\n", "We define the **simplicial cochain algebra** $A_{PL} = \\{(A_{PL})_n\\}_{n \\geq 0}$ by:\n", "\n", "The cochain algebra $(A_{PL})_n$ is given by:\n", "$$(A_{PL})_n = \\frac{\\wedge(t_0, \\dots, t_n,y_0,\\dots, y_n)}{<\\sum{t_i}-1, \\sum{y_j}>}$$\n", "\n", "The face and degeneracy morphisms are the unique cochain algebra morphisms:\n", "\n", "$$\\delta_i: (A_{PL})_{n} \\rightarrow (A_{PL})_{n-1}, \\; 0 \\leq i \\leq n$$\n", "\n", "$$s_j: (A_{PL})_{n} \\rightarrow (A_{PL})_{n+1}, \\; 0 \\leq j \\leq n$$\n", "\n", "satisfying\n", "\n", "$$\\delta_i = t_k \\rightarrow \\left\\{\\begin{matrix}\n", "t_k,& ki\n", "\\end{matrix}\\right. \\; \\; \\; \\;\\;\n", "s_j = t_k \\rightarrow \\left\\{\\begin{matrix}\n", "t_k,& kj\n", "\\end{matrix}\\right.$$\n", "\n", "## Implementation\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "class SimplicialAplN(AplN, UniqueRepresentation):\n", " \"\"\"\n", " \n", " The simplicial commutative cochain algebra Apl\n", " \n", " \"\"\"\n", "\n", " def _base_repr(self):\n", " \"\"\"\n", " Return the base string representation of ``self``.\n", " \"\"\"\n", "\n", " s = DifferentialGCAlgebra._base_repr(self)\n", " old = '{}'.format(self._degrees)\n", " new = '{}'.format([i[0] for i in self._degrees_multi])\n", " return \"Simplicial \" + s.replace(old, new)\n", "\n", " class Element(AplN.Element):\n", " \"\"\"\n", " Element class of the simplicial commutative differential algebra (Apl)n.\n", " \"\"\"\n", " \n", " def face_morphism(self,i):\n", " \"\"\"\" \n", " \n", " Returns the morphism face 'i' of self\n", " \n", " INPUT::\n", " \n", " - i: A non-negative integer lower or equal to 'n'. Represents the face index\n", " \n", " OUTPUT::\n", " \n", " - A morphism of cochain algebras\n", " \"\"\"\n", " n = self.parent().n\n", " if(n==0):\n", " return 0\n", " domain = self.parent()\n", " codomain = SimplicialAlgebraplN(n-1)\n", " tImages = []\n", " yImages = []\n", " n = len(domain.gens())//2\n", " for k in range(n):\n", " if(ki):\n", " tImages.append(codomain.gens()[k-1])\n", " yImages.append(codomain.gens()[n+k-2])\n", " images = tImages+yImages\n", " return domain.hom(codomain=codomain,im_gens=images)\n", " \n", " def face(self,i):\n", " \"\"\"\" \n", " \n", " Returns the face 'i' of self\n", " \n", " INPUT::\n", " \n", " - i: A non-negative integer lower or equal to 'n'. Represents the face index\n", " \n", " OUTPUT::\n", " \n", " - A polynomial that is the face 'i' of self\n", " \"\"\"\n", " \n", " return self.face_morphism(i)(self)\n", " \n", " def degeneration_morphism(self,j):\n", " \"\"\"\" \n", " \n", " Returns the morphism degeneration 'j' of self\n", " \n", " INPUT::\n", " - j: A non-negative integer lower or equal to 'n'. Represents the degeneration index\n", " \n", " OUTPUT::\n", " - A morphism of cochain algebras\n", " \"\"\"\n", " \n", " n = self.parent().n\n", " domain = self.parent()\n", " codomain = SimplicialAlgebraplN(n+1)\n", " if(j>n):\n", " print(\"the degeneration index must be a non-negative number lower or equal to \"+str(n))\n", " return False\n", " elif(j<0):\n", " print(\"the degeneration index must be non-negative\")\n", " return False\n", " else:\n", " tImages = []\n", " yImages = []\n", " n = len(domain.gens())/2\n", " for k in range(n):\n", " if(kj):\n", " tImages.append(codomain.gens()[k+1])\n", " yImages.append(codomain.gens()[n+1+k+1])\n", " images = tImages+yImages\n", " return domain.hom(codomain=codomain,im_gens=images)\n", " \n", " def degeneration(self,j):\n", " \"\"\"\" \n", " \n", " Returns the degeneration 'j' of self\n", " \n", " INPUT::\n", " - j: A non-negative integer lower or equal to 'n'. Represents the degeneration index\n", " \n", " OUTPUT::\n", " - A polynomial that is the degeneration 'j' of self\n", " \"\"\"\n", " return self.degeneration_morphism(j)(self)\n", " \n", "def SimplicialAlgebraplN(n):\n", " \"\"\"\n", " Returns the graded commutative differential cochain algebra (Apl)_n as part of\n", " the simplicial cochain algebra A_{PL}\n", "\n", " INPUT:\n", "\n", " - ``n`` -- A non-negative integer corresponding to the number of generators of degree 0.\n", " \"\"\"\n", "\n", " if (n<0):\n", " raise ValueError('`n` must be a non-negative integer')\n", " ts = ['t'+str(t) for t in range(n+1)]\n", " ys = ['y'+str(t) for t in range(n+1)]\n", " degrees = tuple((n+1)*[(0,2)])+tuple((n+1)*[(1,2)])\n", " gca = GradedCommutativeAlgebra(QQ, names=ts+ys, degrees=degrees)\n", " differentials = {gca.gens_dict()[ts[i]]:gca.gens_dict()[ys[i]] for i in range(n+1)}\n", " return SimplicialAplN(gca,differentials)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Defining t0, t1, t2, t3, t4, t5, y0, y1, y2, y3, y4, y5\n" ] } ], "source": [ "s = SimplicialAlgebraplN(5)\n", "s.inject_variables()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 25, "metadata": {}, "output_type": "execute_result" } ], "source": [ "p = t1+y2\n", "p.degeneration(0).face(1)==p" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 26, "metadata": {}, "output_type": "execute_result" } ], "source": [ "m1 = p.degeneration(1).face_morphism(1)\n", "m2 = p.degeneration_morphism(1)\n", "(m1*m2).is_identity()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Adding new methods: propagate a simplex through the simplicial structure\n", "\n", "In this part, we want to obtain an homogeneous $(n+k)$-simplex of degree $n$, $p_{n+k} \\in (A_{PL})_{n+k}^n$, for $k>0$, where a given homogeneous $n$-simplex of degree $n$, $p_n \\in (A_{PL})_n^n$ is a face of $p_{n+k}$ of dimension $n$, and the rest of faces of dimension lower or equal to $n$ are $0$. We call this map **propagation**,denoted by $\\Gamma$ :\n", "\n", "$$\\Gamma_{n+k}^n: (A_{PL})_n^n \\rightarrow (A_{PL})_{n+k}^n$$\n", "\n", "Without lost of generality, we asume that our polynomial of degree $n$ is expressed as a polynomial in the variables $y_1,\\dots,y_n$. Let $p_n \\in (A_{PL})_n^n$ be the polynomial:\n", "\n", "$$p_n = q_t y_{1} \\dots y_{n}$$\n", "\n", "$$q_t \\in \\mathbb{Q}[t_0,\\dots,t_n]$$\n", "\n", "\n", "\n", "Let $I$ be the index set $\\{0,\\dots, n+k\\}$. For some subsets $(i_1, \\dots, i_k) \\subset I$ we know by definition that \n", "\n", "$$p_n = \\delta_{i_1} \\dots \\delta_{i_k} \\Gamma_{n+k}^n(p_n)$$\n", "\n", "and due to the relations between face morphisms, we know that we can chose a unique subset $(i_1, \\dots, i_k)$ in a way that $i_1 < \\dots < i_k$.\n", "\n", "Just to point the definition, notice that any other combination of faces $\\delta_{j_1} \\dots \\delta_{j_k}$ not equivalent to $\\delta_{i_1} \\dots \\delta_{i_k}$ (i.e., applying the relations between face morphisms), makes the result:\n", "\n", "$$\\delta_{j_1} \\dots \\delta_{j_k}\\Gamma_{n+k}^n(p_n) = 0$$\n", "\n", "Let $J=\\{j_0,\\dots,j_n\\} \\subset I$ be the subset $\\{i_1, \\dots, i_k\\}^C$, i.e., those elements of $I$ $\\notin \\{i_1, \\dots, i_k\\}$, and where $j_l < j_m$, for $l max_dim:\n", " max_dim = dim\n", " apl = SimplicialAlgebraplN(dim)\n", " if dim>0:\n", " values[k] = ((-1)**(dim*(dim-1)/2))*apl.integrand(cochain[k])\n", " else:\n", " values[k]= apl(cochain[k])\n", " \n", " # second, we propagate the simplicial information\n", " simplicial_structure = {}\n", " for n in reversed(range(max_dim+1)):\n", " keys = [k for k in values.keys() if len(k) == n+1] # keys of the n-simplices\n", " for k in keys:\n", " simplicial_structure[k] = values[k] + self._propagate(cochain, k) \n", " #print(simplicial_structure)\n", " return AlgebraAplK.Element(self,simplicial_structure)\n", " \n", " def _propagate(self, cochain, simplex):\n", " \"\"\"\n", " Returns the part of the polynomial assigned to 'simplex' related to the\n", " propagation of the simplicial information of its faces\n", " \"\"\"\n", " dim = len(simplex)-1\n", " apl = SimplicialAlgebraplN(dim)\n", " propagation = apl(0)\n", " for n in reversed(range(dim)):\n", " faces = self._faces_of_length(simplex, n+1)\n", " apl = SimplicialAlgebraplN(n)\n", " pol = apl(prod(apl.gens()[n+2:])) # we propagate the polynomial (y_1...y_n)\n", " for f in faces:\n", " if f in cochain.keys():\n", " value = cochain[f]\n", " face_indexes = [simplex.index(i) for i in f]\n", " #print(\"dim: \",n,\" pol: \",pol,\" face_idx: \",face_indexes,\" dim: \", n)\n", " propagation += value*((-1)**(n*(n-1)/2))*factorial(n)*pol.propagate(face_indexes, dim)\n", " return propagation" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Example" ] }, { "cell_type": "code", "execution_count": 73, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{(0, 1, 2, 3): -6*y1*y2*y3 - 2*t3*y1*y2 + 2*t2*y1*y3 - 2*t1*y2*y3 - t3*y1 + t1*y3, (0, 1, 2): 0, (0, 1, 3): -t2*y1 + t1*y2, (0, 2, 3): 0, (1, 2, 3): -2*y1*y2 + t2*y1 - t1*y2 + y2, (0, 1): 0, (0, 2): 0, (0, 3): 0, (1, 2): 0, (1, 3): y1, (2, 3): 0, (0,): 0, (1,): 0, (2,): 0, (3,): 0}" ] }, "execution_count": 73, "metadata": {}, "output_type": "execute_result" } ], "source": [ "S = SimplicialComplex([[0,1,2,3]],is_mutable=False) \n", "A = AlgebraAplK(S)\n", "cochain = {(0,): 0, (1,): 0, (2,):0, (3,): 0, (0,1): 0, (0,2): 0, (0,3): 0,(1,2): 0, (1,3): 1, (2,3): 0, (0,1,2):0, (0,1,3):0, (0,2,3):0, (1,2,3):1, (0,1,2,3):1}\n", "p = A.lift_cochain(cochain)\n", "p" ] }, { "cell_type": "code", "execution_count": 74, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "True\n", "True\n" ] } ], "source": [ "print(p.integral()==cochain)\n", "print(A.lift_cochain(p.integral())==p)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Adding new methods: Managing simplicial-cohomology generators" ] }, { "cell_type": "code", "execution_count": 75, "metadata": {}, "outputs": [], "source": [ "class AlgebraAplK(AlgebraAplK, UniqueRepresentation):\n", " \"\"\"\n", " \n", " The graded commutative differential cochain algebra Apl(K)\n", " \n", " \"\"\"\n", " def cohomology_gens(self,degree):\n", " \"\"\"\n", " Returns the cohomolosy generators of a given degree\n", " \"\"\"\n", " gens = {}\n", " basis = self.K.cohomology_ring(QQ).basis()\n", " for k in basis.keys():\n", " if k[0] == degree:\n", " gens[k] = basis[k]\n", " return gens\n", " \n", " def cohomology_group(self, n):\n", " chainComplex = self.K.chain_complex(base_ring=QQ)\n", " cochainComplex = chainComplex.dual()\n", " Hn = cochainComplex.differential(n).right_kernel()/cochainComplex.differential(n-1).column_space()\n", " return Hn\n", "\n", " def cochain_to_vector(self, cochain, dim):\n", " \"\"\"\n", " Converts a cochain, given as a dictionary, to a vector\n", " \"\"\"\n", " basis = self.K.n_chains(dim, base_ring=QQ, cochains=True).basis()\n", " v = vector(QQ,len(basis)*[0])\n", " i=0\n", " for simplex in basis.keys():\n", " v[i] = cochain[tuple(simplex)]\n", " i = i+1\n", " return v\n", "\n", " def vector_to_cochain(self, v, dim):\n", " \"\"\"\n", " Converts a cochain, given as a vector, to a dictionary\n", " \"\"\"\n", " cochain = {}\n", " for d in range(self.K.dimension()+1):\n", " basis = self.K.n_chains(d, base_ring=QQ, cochains=True).basis()\n", " if d!=dim:\n", " for simplex in basis.keys():\n", " cochain[tuple(simplex)] = 0\n", " else:\n", " i=0\n", " for simplex in basis.keys():\n", " cochain[tuple(simplex)] = v[i]\n", " i = i+1\n", " return cochain\n", " \n", " def lift_cochain_complex(self, cochain, dim):\n", " \"\"\"\n", " (REVISAR)\n", " Returns an element of the preimage by the differential of a given cochain\n", " \n", " INPUT:\n", " - cochain: a cochain as a vector\n", " - dim: dimension of the cochain\n", " \"\"\"\n", " # S = the Simplicial Complex\n", " # cochain = the cochain you want to find a preimage by the differential\n", " # dim = the dimension of the cochain\n", " cochain_vector = self.cochain_to_vector(cochain, dim)\n", " cochainComplex = self.K.chain_complex(base_ring=QQ).dual()\n", " diff = cochainComplex.differential(dim-1)\n", " show(diff.echelon_form())\n", " result = diff.solve_right(cochain_vector)\n", " return self.vector_to_cochain(result)\n", "\n", " def lift_cohomology_generator(self, g):\n", " \"\"\"\n", " Returns a representative cochain associated to a given cohomology generator.\n", " \"\"\"\n", " cycle = g.to_cycle()\n", " cochain = {}\n", " for n in range(self.K.dimension()+1):\n", " for simplex in self.K._n_cells_sorted(n):\n", " cochain[simplex.tuple()] = 0\n", " for i in cycle:\n", " #print(type(i[0].tuple()))\n", " cochain[i[0].tuple()] = i[1]\n", " return cochain\n", " \n", " def get_cohomology_aplk(self,degree):\n", " \"\"\"\n", " Returns a set of representative elements of Apl(K), one for each cohomology generator of a given degree\n", " \"\"\"\n", " representative_aplk_elements = {}\n", " dic_gens = self.cohomology_gens(degree)\n", " for key in dic_gens.keys():\n", " gen = dic_gens[key]\n", " cochain = self.lift_cohomology_generator(gen)\n", " representative_aplk_elements[key] = self.lift_cochain(cochain)\n", " return representative_aplk_elements\n", " \n", " def first_cohomology_group(self):\n", " \"\"\"\n", " Returns the degree >= 1 of the first non-null cohomology generator. \n", " \"\"\"\n", " basis = self.K.cohomology_ring(base_ring=QQ).basis()\n", " indexes = list(basis.keys())\n", " indexes.sort(reverse=False)\n", "# print(indexes)\n", " for n in range(1,len(indexes)):\n", " if indexes[n][0] > 0:\n", " return indexes[n][0]\n", " return -1" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Examples" ] }, { "cell_type": "code", "execution_count": 76, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{(1, 0): h^{1,0}}" ] }, "execution_count": 76, "metadata": {}, "output_type": "execute_result" } ], "source": [ "S = SimplicialComplex([[0,1,2],[1,3],[2,3]],is_mutable=False) \n", "A = AlgebraAplK(S)\n", "g = A.cohomology_gens(1)\n", "g" ] }, { "cell_type": "code", "execution_count": 77, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\\[\\newcommand{\\Bold}[1]{\\mathbf{#1}}\\left(1,\\,0,\\,-1,\\,0,\\,0\\right)\\]" ], "text/latex": [ "$$\\newcommand{\\Bold}[1]{\\mathbf{#1}}\\left(1,\\,0,\\,-1,\\,0,\\,0\\right)$$" ], "text/plain": [ "(1, 0, -1, 0, 0)" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/plain": [ "{(0,): 0,\n", " (1,): 0,\n", " (2,): 0,\n", " (3,): 0,\n", " (0, 1): 1,\n", " (0, 2): 0,\n", " (1, 2): -1,\n", " (1, 3): 0,\n", " (2, 3): 0,\n", " (0, 1, 2): 0}" ] }, "execution_count": 77, "metadata": {}, "output_type": "execute_result" } ], "source": [ "H1 = A.cohomology_group(1)\n", "l = []\n", "for v in H1.basis():\n", " l.append(H1.lift_map()(v))\n", "show(l[0])\n", "A.vector_to_cochain(l[0],1)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": 78, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{(0,): 0,\n", " (1,): 0,\n", " (2,): 0,\n", " (3,): 0,\n", " (0, 1): 0,\n", " (0, 2): 0,\n", " (1, 2): 0,\n", " (1, 3): 0,\n", " (2, 3): 1,\n", " (0, 1, 2): 0}" ] }, "execution_count": 78, "metadata": {}, "output_type": "execute_result" } ], "source": [ "gen = list(g.values())[0]\n", "cochain = A.lift_cohomology_generator(gen)\n", "cochain" ] }, { "cell_type": "code", "execution_count": 79, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{(1,\n", " 0): {(0, 1, 2): 0, (0, 1): 0, (0, 2): 0, (1, 2): 0, (1, 3): 0, (2, 3): y1, (0,): 0, (1,): 0, (2,): 0, (3,): 0}}" ] }, "execution_count": 79, "metadata": {}, "output_type": "execute_result" } ], "source": [ "A.get_cohomology_aplk(1)" ] }, { "cell_type": "code", "execution_count": 80, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{(2, 0): h^{2,0}, (2, 1): h^{2,1}}" ] }, "execution_count": 80, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# get the cohomology generators of a given degree\n", "S2 = SimplicialComplex([[0,1,2],[0,1,3],[0,2,3],[1,2,3],[3,4,5],[3,4,6],[3,5,6],[4,5,6]],is_mutable=False) \n", "A2 = AlgebraAplK(S2)\n", "g = A2.cohomology_gens(2)\n", "g" ] }, { "cell_type": "code", "execution_count": 81, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{(0,): 0,\n", " (1,): 0,\n", " (2,): 0,\n", " (3,): 0,\n", " (4,): 0,\n", " (5,): 0,\n", " (6,): 0,\n", " (0, 1): 0,\n", " (0, 2): 0,\n", " (0, 3): 0,\n", " (1, 2): 0,\n", " (1, 3): 0,\n", " (2, 3): 0,\n", " (3, 4): 0,\n", " (3, 5): 0,\n", " (3, 6): 0,\n", " (4, 5): 0,\n", " (4, 6): 0,\n", " (5, 6): 0,\n", " (0, 1, 2): 0,\n", " (0, 1, 3): 0,\n", " (0, 2, 3): 0,\n", " (1, 2, 3): 1,\n", " (3, 4, 5): 0,\n", " (3, 4, 6): 0,\n", " (3, 5, 6): 0,\n", " (4, 5, 6): 0}" ] }, "execution_count": 81, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# get a representative cochain for a given cohomology generator\n", "gen = list(g.values())[0]\n", "cochain = A2.lift_cohomology_generator(gen)\n", "cochain" ] }, { "cell_type": "code", "execution_count": 82, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{(2,\n", " 0): {(0, 1, 2): 0, (0, 1, 3): 0, (0, 2, 3): 0, (1, 2, 3): -2*y1*y2, (3, 4, 5): 0, (3, 4, 6): 0, (3, 5, 6): 0, (4, 5, 6): 0, (0, 1): 0, (0, 2): 0, (0, 3): 0, (1, 2): 0, (1, 3): 0, (2, 3): 0, (3, 4): 0, (3, 5): 0, (3, 6): 0, (4, 5): 0, (4, 6): 0, (5, 6): 0, (0,): 0, (1,): 0, (2,): 0, (3,): 0, (4,): 0, (5,): 0, (6,): 0},\n", " (2,\n", " 1): {(0, 1, 2): 0, (0, 1, 3): 0, (0, 2, 3): 0, (1, 2, 3): 0, (3, 4, 5): 0, (3, 4, 6): 0, (3, 5, 6): 0, (4, 5, 6): -2*y1*y2, (0, 1): 0, (0, 2): 0, (0, 3): 0, (1, 2): 0, (1, 3): 0, (2, 3): 0, (3, 4): 0, (3, 5): 0, (3, 6): 0, (4, 5): 0, (4, 6): 0, (5, 6): 0, (0,): 0, (1,): 0, (2,): 0, (3,): 0, (4,): 0, (5,): 0, (6,): 0}}" ] }, "execution_count": 82, "metadata": {}, "output_type": "execute_result" } ], "source": [ "phi = A2.get_cohomology_aplk(2)\n", "phi" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Adding new methods: find a primitive of a closed element" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### methods related to find a polynomial where the differential is given" ] }, { "cell_type": "code", "execution_count": 83, "metadata": {}, "outputs": [], "source": [ "from sage.rings.polynomial.polydict import ETuple\n", "\n", "class SimplicialAplN(SimplicialAplN,UniqueRepresentation):\n", " class Element(SimplicialAplN.Element):\n", " \"\"\"\n", " Element class of the commutative differential multi-graded algebra (Apl)n.\n", " \"\"\"\n", "\n", " def _get_primitive_basis_of_a_monomial(self, monomial): \n", " \"\"\"\n", " Returns a basis of the primitive of a given monomial\n", "\n", " Example: \n", "\n", " \"\"\"\n", " n_vars = len(monomial)/2\n", " combinations = []\n", " for i in range(n_vars):\n", " mono = list(copy.deepcopy(monomial))\n", " if mono[n_vars+i]:\n", " mono[i] += 1\n", " mono[n_vars+i] = 0\n", " combinations.append(tuple(mono))\n", " return list(set(combinations))\n", "\n", " def _add_kernel_terms_to_primitive_basis(self, basis): \n", " new_elements = []\n", " for e in basis:\n", " monomial = list(copy.deepcopy(e))\n", " n = len(e)/2\n", " monomial[:n] = n*[0]\n", " new_elements.append(tuple(monomial))\n", " return new_elements\n", " \n", " def _get_primitive_basis(self):\n", " \"\"\"\n", " Returns a basis of the primitive of 'self'\n", " \"\"\"\n", " basis = []\n", " p = self.reduce()\n", " for monomial in p.dict().keys():\n", " basis += p._get_primitive_basis_of_a_monomial(monomial)\n", " basis = list(set(basis))\n", " basis += p._add_kernel_terms_to_primitive_basis(basis)\n", " basis = list(set(basis))\n", " terms = []\n", " apl = self.parent()\n", " for b in basis:\n", " dim = len(monomial)/2-1\n", " terms.append(self._get_term(1, b, apl.gens()))\n", " terms.sort(reverse=False)\n", " return terms\n", "\n", " def _get_differential_basis(self):\n", " \"\"\"\n", " Returns a basis of the differential of 'self'\n", " \"\"\"\n", " primitive_basis = self._get_primitive_basis()\n", " differential_basis = []\n", " for b in primitive_basis:\n", " diff = b.differential().reduce()\n", " if diff: # as we want a basis, we don't consider the coeffient of the differential\n", " for monomial in diff.dict().keys():\n", " term = self._get_term(1, monomial, self.parent().gens())\n", " differential_basis.append(term)\n", " differential_basis = list(set(differential_basis))\n", " differential_basis.sort(reverse=False)\n", " return differential_basis\n", "\n", " def _get_coordinate_vector_differential(self, diff_basis):\n", " \"\"\"\n", " Returns the coordinates of 'self' \n", " in terms of the differential basis\n", " \"\"\"\n", " p_reduced = self.reduce()\n", " #dic = p.dict()\n", " #terms = [p_reduced.parent()({t: dic[t]}) for t in dic.keys()]\n", " monomials = list(p_reduced.dict().keys())\n", " v = vector(QQ,len(diff_basis)*[0])\n", " for i in range(len(diff_basis)):\n", " t = diff_basis[i]\n", " term = list(t.dict().keys())[0] # there is only one monomial\n", " if term in monomials:\n", " v[i] = p_reduced.dict()[term]\n", " return v\n", "\n", " def _differential_matrix(self, primitive_basis, differential_basis):\n", " \"\"\"\n", " Returns the matrix of the differential map\n", " \"\"\"\n", " #primitive_basis = get_primitive_basis_of_a_polynomial(p.reduce())\n", " #differential_basis = get_differential_basis_of_a_polynomial(p.reduce())\n", " nrows = len(differential_basis)\n", " ncols = len(primitive_basis)\n", " M = matrix(QQ, nrows, ncols, nrows*ncols*[0])\n", " for j in range(ncols):\n", " primitive = primitive_basis[j]\n", " #diff_dict = self._tuple_differential(primitive)\n", " diff_primitive = primitive.differential().reduce()\n", " monomials = list(diff_primitive.dict().keys())\n", " for i in range(nrows):\n", " diff_basis_element = differential_basis[i]\n", " term = list(diff_basis_element.dict().keys())[0] # there is only one monomial\n", " if term in monomials:\n", " M[i,j] = diff_primitive.dict()[term] \n", " return M\n", "\n", " def solve_primitive(self):\n", " p = self.reduce()\n", " primitive_basis = p._get_primitive_basis()\n", " diff_basis = p._get_differential_basis()\n", " v = p._get_coordinate_vector_differential(diff_basis)\n", " Mdif = p._differential_matrix(primitive_basis, diff_basis)\n", " sol = Mdif.solve_right(v)\n", " return sum(map(lambda x,y: x*y, sol, primitive_basis))" ] }, { "cell_type": "code", "execution_count": 84, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Defining t0, t1, t2, t3, t4, t5, y0, y1, y2, y3, y4, y5\n" ] }, { "data": { "text/plain": [ "[1, y4, y3, y2, t1^2, t2*t3*y4, t2*t4*y3, t3*t4*y2]" ] }, "execution_count": 84, "metadata": {}, "output_type": "execute_result" } ], "source": [ "dim = 5\n", "s = SimplicialAlgebraplN(dim)\n", "s.inject_variables()\n", "p = -3*t1^2 +10* y2*t3*t4\n", "p = p.differential()\n", "primitive_basis = p._get_primitive_basis()\n", "primitive_basis" ] }, { "cell_type": "code", "execution_count": 85, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[t1*y1, t2*y3*y4, t3*y2*y4, t4*y2*y3]" ] }, "execution_count": 85, "metadata": {}, "output_type": "execute_result" } ], "source": [ "diff_basis = p._get_differential_basis()\n", "diff_basis" ] }, { "cell_type": "code", "execution_count": 86, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(-6, 0, -10, -10)" ] }, "execution_count": 86, "metadata": {}, "output_type": "execute_result" } ], "source": [ "v = p._get_coordinate_vector_differential(diff_basis)\n", "v" ] }, { "cell_type": "code", "execution_count": 87, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[ 0 0 0 0 2 0 0 0]\n", "[ 0 0 0 0 0 1 -1 0]\n", "[ 0 0 0 0 0 1 0 -1]\n", "[ 0 0 0 0 0 0 1 -1]" ] }, "execution_count": 87, "metadata": {}, "output_type": "execute_result" } ], "source": [ "Mdif = p._differential_matrix(primitive_basis, diff_basis)\n", "Mdif" ] }, { "cell_type": "code", "execution_count": 88, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "-10*t2*t4*y3 - 10*t2*t3*y4 - 3*t1^2" ] }, "execution_count": 88, "metadata": {}, "output_type": "execute_result" } ], "source": [ "p.solve_primitive()" ] }, { "cell_type": "code", "execution_count": 89, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 89, "metadata": {}, "output_type": "execute_result" } ], "source": [ "p.solve_primitive().differential() == p" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### find an element of the preimage by the differential of an element of Alp(K)" ] }, { "cell_type": "code", "execution_count": 90, "metadata": {}, "outputs": [], "source": [ "class AlgebraAplK(AlgebraAplK, UniqueRepresentation):\n", " \"\"\"\n", " \n", " The graded commutative differential cochain algebra Apl(K)\n", " \n", " \"\"\"\n", " \n", " class Element(AlgebraAplK.Element):\n", " \"\"\"\n", " Element class of the simplicial commutative differential algebra (Apl)n.\n", " \"\"\"\n", " \n", " def _face_basis(self, basis, face_idx):\n", " face_basis = []\n", " for b in basis:\n", " face_pol = b.face(face_idx).reduce()\n", " if face_pol:\n", " for monomial in face_pol.dict().keys():\n", " #remove coefficients\n", " term = face_pol._get_term(1, monomial, face_pol.parent().gens())\n", " face_basis.append(term)\n", " face_basis = list(set(face_basis))\n", " face_basis.sort(reverse=False)\n", " return face_basis\n", " \n", " def _get_primitive_basis(self):\n", " \n", " primitive_basis = {}\n", " S = self.parent().simplicialComplex()\n", " dim = S.dimension()\n", " min_dim = self.degree()\n", " for n in reversed(range(min_dim,dim+1)):\n", " for simplex in S._n_cells_sorted(n):\n", " if simplex.tuple() not in primitive_basis.keys():\n", " primitive_basis[simplex.tuple()] = []\n", " # add primitive elements related to the assigned polynomial\n", " pol = self.elements[simplex.tuple()]\n", " primitive_basis[simplex.tuple()] += pol._get_primitive_basis()\n", " primitive_basis[simplex.tuple()] = list(set(primitive_basis[simplex.tuple()]))\n", " primitive_basis[simplex.tuple()].sort(reverse=False)\n", " # propagate the primitive basis through its faces\n", " for f in range(n+1):\n", " simplex_face = S.face(simplex,f).tuple()\n", " if simplex_face not in primitive_basis.keys():\n", " primitive_basis[simplex_face] = []\n", " primitive_basis[simplex_face] += self._face_basis(primitive_basis[simplex.tuple()], f)\n", " primitive_basis[simplex_face] = list(set(primitive_basis[simplex_face]))\n", " primitive_basis[simplex_face].sort(reverse=False)\n", " return primitive_basis\n", " \n", " def _diff_basis(self, basis):\n", " diff_basis = []\n", " for b in basis:\n", " b_diff = b.differential().reduce()\n", " if b_diff:\n", " for monomial in b_diff.dict().keys():\n", " #remove coefficients\n", " term = b_diff._get_term(1, monomial, b_diff.parent().gens())\n", " diff_basis.append(term)\n", " diff_basis = list(set(diff_basis))\n", " diff_basis.sort(reverse=False)\n", " return diff_basis\n", " \n", " def _get_differential_basis(self, primitive_basis):\n", " differential_basis = {}\n", " S = self.parent().simplicialComplex()\n", " dim = S.dimension()\n", " min_dim = self.degree()\n", " for n in reversed(range(min_dim,dim+1)):\n", " for simplex in S._n_cells_sorted(n):\n", " prim_diff_basis = primitive_basis[simplex.tuple()]\n", " differential_basis[simplex.tuple()] = self._diff_basis(prim_diff_basis)\n", " return differential_basis\n", " \n", " def _get_differential_matrix(self, p_basis, d_basis):\n", " S = self.parent().simplicialComplex()\n", " dim = S.dimension()\n", " min_dim = self.degree()\n", " ncols = sum([len(l) for l in p_basis.values()])\n", " nrows = sum([len(l) for l in d_basis.values()])\n", " M = zero_matrix(QQ, nrows, ncols)\n", " row_offset = 0\n", " col_index = 0\n", " for n in reversed(range(min_dim-1,dim+1)):\n", " for simplex in S._n_cells_sorted(n):\n", "# print(simplex.tuple(), row_offset, col_index)\n", " if simplex.tuple() in p_basis.keys():\n", " primitives = p_basis[simplex.tuple()]\n", " if simplex.tuple() in d_basis.keys():\n", " differentials = d_basis[simplex.tuple()]\n", " if primitives and differentials:\n", " for p in primitives:\n", " dif_p = p.differential().reduce()\n", " dic = dif_p.dict()\n", " for monomial in dic.keys():\n", " term = dif_p._get_term(1, monomial, dif_p.parent().gens())\n", " if term in differentials:\n", " row_index = differentials.index(term)\n", " M[row_offset + row_index, col_index] = dic[monomial]\n", " col_index += 1\n", " row_offset += len(differentials)\n", " elif primitives:\n", " col_index += len(primitives)\n", " elif primitives:\n", " col_index += len(primitives)\n", " \n", " return M\n", " \n", " def _get_vector_diff_coordinates(self, d_basis):\n", " len_v = sum([len(l) for l in d_basis.values()])\n", " v = zero_vector(QQ, len_v)\n", " offset = 0\n", " S = self.parent().simplicialComplex()\n", " dim = S.dimension()\n", " min_dim = self.degree()\n", " for n in reversed(range(min_dim,dim+1)):\n", " for s in S._n_cells_sorted(n):\n", " simplex = s.tuple()\n", " if simplex in d_basis.keys():\n", " differentials = d_basis[simplex]\n", " pol = self.elements[simplex].reduce()\n", " if pol and differentials:\n", " dic = pol.dict()\n", " for monomial in dic.keys():\n", " term = pol._get_term(1, monomial, pol.parent().gens())\n", " if term in differentials:\n", " v_index = differentials.index(term)\n", " v[offset + v_index] = dic[monomial]\n", " offset += len(differentials)\n", " return v\n", " \n", " def _get_offsets_matrix(self, p_basis):\n", " offsets = {}\n", " S = self.parent().simplicialComplex()\n", " dim = S.dimension()\n", " min_dim = self.degree()\n", " offset = 0\n", " first_simplex = True\n", " for n in reversed(range(min_dim-1,dim+1)):\n", " for simplex in S._n_cells_sorted(n):\n", " if simplex.tuple() in p_basis.keys():\n", " primitives = p_basis[simplex.tuple()]\n", " if first_simplex:\n", " offsets[simplex.tuple()] = 0\n", " first_simplex = False\n", " else:\n", " offsets[simplex.tuple()] = offset\n", " offset += len(primitives)\n", " return offsets\n", " \n", " def _get_row_face_matrix(self, primitives, face_idx, face_basis,\n", " offset_simplex, offset_face, len_row):\n", " M = zero_matrix(QQ,1, len_row)\n", " for fb in face_basis: \n", " fb_idx = face_basis.index(fb)\n", " row = zero_matrix(QQ,1, len_row)\n", " row[0,offset_face+fb_idx] = -1\n", " for term in primitives:\n", " face_term = term.face(face_idx).reduce()\n", " dic = face_term.dict()\n", " i = primitives.index(term)\n", " for monomial in dic:\n", " t = face_term._get_term(1, monomial, face_term.parent().gens())\n", " if t == fb:\n", " coef = dic[monomial]\n", " row[0,offset_simplex+i] = coef\n", " M = M.stack(row)\n", " return M[1:]\n", " \n", " \n", " def _get_face_matrix(self, p_basis):\n", " \n", " offsets = self._get_offsets_matrix(p_basis)\n", " len_row = sum([len(l) for l in p_basis.values()])\n", " M = zero_matrix(QQ,1, len_row)\n", " min_dim = self.degree()\n", " for n in reversed(range(min_dim,dim+1)):\n", " for simplex in S._n_cells_sorted(n):\n", " offset_simplex = offsets[simplex.tuple()]\n", " primitives = p_basis[simplex.tuple()]\n", " for f in range(n+1):\n", " simplex_face = S.face(simplex,f).tuple()\n", " face_primitives = p_basis[simplex_face]\n", " offset_face = offsets[simplex_face]\n", " rows = self._get_row_face_matrix(primitives, f, face_primitives,\n", " offset_simplex, offset_face,\n", " len_row)\n", " M = M.stack(rows)\n", " return M[1:]\n", " \n", " def _get_solution(self, sol, p_basis):\n", " S = self.parent().simplicialComplex()\n", " dim = S.dimension()\n", " min_dim = self.degree()-1\n", " offset = 0\n", " values = {}\n", " for n in reversed(range(dim+1)):\n", " apl = SimplicialAlgebraplN(n)\n", " for s in S._n_cells_sorted(n):\n", " simplex = s.tuple()\n", " pol = apl(0)\n", " if simplex in p_basis.keys():\n", " primitives = p_basis[simplex]\n", " if primitives:\n", " for p in primitives:\n", " i = primitives.index(p)\n", " coef = sol[offset+i]\n", " pol += coef*p\n", " offset += len(primitives)\n", " values[simplex] = pol \n", " A = self.parent()\n", "# return values\n", " return A._element_constructor_(values)\n", " \n", " def solve_primitive(self):\n", " p_basis = self._get_primitive_basis()\n", " d_basis = self._get_differential_basis(p_basis)\n", " diff_matrix = self._get_differential_matrix(p_basis, d_basis)\n", " v_dif = self._get_vector_diff_coordinates(d_basis)\n", " face_matrix = self._get_face_matrix(p_basis)\n", " nrows = face_matrix.nrows()\n", " v = vector(QQ, list(v_dif)+nrows*[0])\n", " M = diff_matrix.stack(face_matrix)\n", " sol = M.solve_right(v)\n", " return self._get_solution(sol, p_basis)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Example" ] }, { "cell_type": "code", "execution_count": 91, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Defining t0, t1, t2, y0, y1, y2\n" ] }, { "data": { "text/plain": [ "{(0,): 0, (1,): 0, (2,): 0, (3,): 0, (4,): 0, (0, 1): 0, (0, 2): 0, (0, 3): 0, (0, 4): 0, (1, 2): 0, (1, 3): 0, (1, 4): 0, (2, 3): 0, (2, 4): 0, (3, 4): 0, (0, 1, 2): 0, (0, 1, 3): 0, (0, 1, 4): 0, (0, 2, 3): 0, (0, 2, 4): 0, (0, 3, 4): 0, (1, 2, 3): 0, (1, 2, 4): 0, (1, 3, 4): 0, (2, 3, 4): 0, (0, 1, 2, 3): 3*y1*y2*y3, (0, 1, 2, 4): -3*y1*y2*y3, (0, 1, 3, 4): -3*y1*y2*y3, (0, 2, 3, 4): 0, (1, 2, 3, 4): -3*y1*y2*y3, (0, 1, 2, 3, 4): 3*y1*y2*y3 - 3*y1*y2*y4 - 3*y1*y3*y4}" ] }, "execution_count": 91, "metadata": {}, "output_type": "execute_result" } ], "source": [ "S = SimplicialComplex([[0,1,2,3,4]],is_mutable=False)\n", "A = AlgebraAplK(S)\n", "s0 = SimplicialAlgebraplN(0)\n", "s1 = SimplicialAlgebraplN(1)\n", "s2 = SimplicialAlgebraplN(2)\n", "s3 = SimplicialAlgebraplN(3)\n", "s4 = SimplicialAlgebraplN(4)\n", "s2.inject_variables()\n", "p012 = y1*y2\n", "p013 = y1*y2\n", "p023 = y1*y2\n", "p024 = y1*y2\n", "p034 = y1*y2\n", "p123 = y1*y2\n", "p124 = y1*y2\n", "p134 = y1*y2\n", "p234 = y1*y2\n", "\n", "p0123 = p012.propagate([0,1,2],3) + p123.propagate([1,2,3],3)+p013.propagate([0,1,3],3)\n", "p0134 = p013.propagate([0,1,2],3)\n", "p0124 = p012.propagate([0,1,2],3)\n", "p1234 = p123.propagate([0,1,2],3)\n", "p01234 = p012.propagate([0,1,2],4) + p123.propagate([1,2,3],4) + p013.propagate([0,1,3],4)\n", "\n", "values = {(0,): s0(0), (1,): s0(0), (2,): s0(0), (3,): s0(0), (4,): s0(0), \n", " (0,1): s1(0), (0,2): s1(0), (0,3): s1(0), (0,4): s1(0),\n", " (1,2): s1(0), (1,3): s1(0), (1,4): s1(0), \n", " (2,3): s1(0), (2,4): s1(0), \n", " (3,4): s1(0), \n", " (0,1,2): p012, (0,1,3): p013, (0,1,4): s2(0), \n", " (0,2,3): s2(0), (0,2,4): s2(0), (0,3,4): s2(0),\n", " (1,2,3): p123, (1,2,4): s2(0), (1,3,4): s2(0),\n", " (2,3,4): s2(0), \n", " (0,1,2,3): p0123,(0,1,2,4):p0124,(0,1,3,4): p0134,\n", " (0,2,3,4): s3(0),(1,2,3,4): p1234,\n", " (0,1,2,3,4): p01234}\n", "e1 = A._element_constructor_(values)\n", "dife1 = e1.differential()\n", "dife1" ] }, { "cell_type": "code", "execution_count": 92, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{(0, 1, 2, 3, 4): t3*y1*y2 - t4*y1*y2 - t2*y1*y3 - t4*y1*y3 + t1*y2*y3 + t2*y1*y4 + t3*y1*y4 - t1*y2*y4 - t1*y3*y4 + y1*y2 + y1*y3, (0, 1, 2, 3): t3*y1*y2 - t2*y1*y3 + t1*y2*y3 + y1*y2 + y1*y3, (0, 1, 2, 4): -t3*y1*y2 + t2*y1*y3 - t1*y2*y3 + y1*y2, (0, 1, 3, 4): -t3*y1*y2 + t2*y1*y3 - t1*y2*y3 + y1*y2, (0, 2, 3, 4): 0, (1, 2, 3, 4): -t3*y1*y2 + t2*y1*y3 - t1*y2*y3 + y1*y2, (0, 1, 2): y1*y2, (0, 1, 3): y1*y2, (0, 1, 4): 0, (0, 2, 3): 0, (0, 2, 4): 0, (0, 3, 4): 0, (1, 2, 3): y1*y2, (1, 2, 4): 0, (1, 3, 4): 0, (2, 3, 4): 0, (0, 1): 0, (0, 2): 0, (0, 3): 0, (0, 4): 0, (1, 2): 0, (1, 3): 0, (1, 4): 0, (2, 3): 0, (2, 4): 0, (3, 4): 0, (0,): 0, (1,): 0, (2,): 0, (3,): 0, (4,): 0}" ] }, "execution_count": 92, "metadata": {}, "output_type": "execute_result" } ], "source": [ "primitive = dife1.solve_primitive()\n", "primitive" ] }, { "cell_type": "code", "execution_count": 93, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 93, "metadata": {}, "output_type": "execute_result" } ], "source": [ "primitive.differential() == dife1" ] }, { "cell_type": "code", "execution_count": 94, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 94, "metadata": {}, "output_type": "execute_result" } ], "source": [ "primitive == e1" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Example Torus" ] }, { "cell_type": "code", "execution_count": 95, "metadata": {}, "outputs": [], "source": [ "# S = simplicial_complexes.Torus()\n", "# A = AlgebraAplK(S)\n", "# s0 = SimplicialAlgebraplN(0)\n", "# s1 = SimplicialAlgebraplN(1)\n", "# s2 = SimplicialAlgebraplN(2)\n", "# s2.inject_variables()\n", "# values = {(0, 1, 2): s2(0), (0, 1, 5): s2(0), (0, 2, 6): s2(0), (0, 3, 4): s2(0), (0, 3, 5): s2(0), \n", "# (0, 4, 6): s2(0), (1, 2, 4): s2(0), (1, 3, 4): s2(0), (1, 3, 6): -y1*y2, (1, 5, 6): s2(0), \n", "# (2, 3, 5): s2(0), (2, 3, 6): s2(0), (2, 4, 5): y1*y2, (4, 5, 6): s2(0), \n", "# (0, 1): s1(0), (0, 2): s1(0), (0, 3): s1(0), (0, 4): s1(0), (0, 5): s1(0), (0, 6): s1(0), \n", "# (1, 2): s1(0), (1, 3): s1(0), (1, 4): s1(0), (1, 5): s1(0), (1, 6): s1(0), (2, 3): s1(0), (2, 4): s1(0), \n", "# (2, 5): s1(0), (2, 6): s1(0), (3, 4): s1(0), (3, 5): s1(0), (3, 6): s1(0), (4, 5): s1(0), (4, 6): s1(0), (5, 6): s1(0), \n", "# (0,): s0(0), (1,): s0(0), (2,): s0(0), (3,): s0(0), (4,): s0(0), (5,): s0(0), (6,): s0(0)}\n", "# e = A._element_constructor_(values)\n", "# preimage = e.solve_primitive()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Test with random complexes and random elements of Apl(K)" ] }, { "cell_type": "code", "execution_count": 96, "metadata": {}, "outputs": [], "source": [ "def sublist(lst1, lst2):\n", " return set(lst1) <= set(lst2)\n", "\n", "def sublist_of_lists(list1,list_of_lists):\n", " is_sublist = False\n", " for list2 in list_of_lists:\n", " if sublist(list1,list2):\n", " is_sublist = True\n", " break\n", " return is_sublist\n", "\n", "def random_simplicial_complex(num_vertices,max_num_facets):\n", " vertices = list(range(num_vertices))\n", " simplices = []\n", " partitions = []\n", " for length in range(num_vertices):\n", " partitions += [tuple(e) for e in powerset(vertices) if len(e)==length and e]\n", " for i in range(max_num_facets):\n", " r = randint(0,len(partitions)-1)\n", " candidate = partitions[r]\n", " if not sublist_of_lists(candidate,simplices):\n", " simplices.append(candidate)\n", " return SimplicialComplex(simplices,is_mutable=False)\n", "\n", "def random_cochain(S):\n", " dim = S.dimension()\n", " cochain = {}\n", " for n in range(dim+1):\n", " for s in S._n_cells_sorted(n):\n", " cochain[s.tuple()] = randint(-100,100)\n", " return cochain" ] }, { "cell_type": "code", "execution_count": 97, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "Simplicial complex with vertex set (0, 1, 2, 3, 4, 5) and facets {(0,), (2, 3), (4, 5), (1, 2, 5)}" ] }, "execution_count": 97, "metadata": {}, "output_type": "execute_result" } ], "source": [ "S = random_simplicial_complex(6,4)\n", "# S = SimplicialComplex([5],is_mutable=False)\n", "cochain = random_cochain(S)\n", "S" ] }, { "cell_type": "code", "execution_count": 98, "metadata": {}, "outputs": [], "source": [ "A = AlgebraAplK(S)\n", "e = A.lift_cochain(cochain)\n", "dife = e.differential()" ] }, { "cell_type": "code", "execution_count": 99, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "deg: 1\n", "deg: 2\n", "dif(recover) == dif(e): True\n" ] } ], "source": [ "hom_parts = dife.homogeneous_parts()\n", "recover = A.null_element()\n", "for deg in hom_parts.keys():\n", " print(\"deg: \", deg)\n", " recover += hom_parts[deg].solve_primitive()\n", "print(\"dif(recover) == dif(e): \", recover.differential() == dife)\n", "# print(\"recover == e: \", recover == e) # Although their differentials are equal, this is not always True" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Example" ] }, { "cell_type": "code", "execution_count": 100, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Defining t0, t1, t2, t3, y0, y1, y2, y3\n", "\n", "e1:\n", "{(0,): 0, (1,): 0, (2,): 0, (3,): 0, (0, 1): 0, (0, 2): 0, (0, 3): 0, (1, 2): 0, (1, 3): 0, (2, 3): 0, (0, 1, 2): 0, (0, 1, 3): 0, (0, 2, 3): 0, (1, 2, 3): 0, (0, 1, 2, 3): y1*y2*y3}\n", "\n", "e2\n", "{(0, 1, 2, 3): 1/3*t3*y1*y2 - 1/3*t2*y1*y3 + 1/3*t1*y2*y3 - 1/3*y1*y2, (0, 1, 2): -1/3*y1*y2, (0, 1, 3): 0, (0, 2, 3): 0, (1, 2, 3): 0, (0, 1): 0, (0, 2): 0, (0, 3): 0, (1, 2): 0, (1, 3): 0, (2, 3): 0, (0,): 0, (1,): 0, (2,): 0, (3,): 0}\n", "\n", "d(e2) == e1: True\n" ] } ], "source": [ "S = SimplicialComplex([[0,1,2,3]],is_mutable=False)\n", "A = AlgebraAplK(S)\n", "s0 = SimplicialAlgebraplN(0)\n", "s1 = SimplicialAlgebraplN(1)\n", "s2 = SimplicialAlgebraplN(2)\n", "s3 = SimplicialAlgebraplN(3)\n", "s3.inject_variables()\n", "p0123 = y1*y2*y3\n", "values = {(0,): s0(0), (1,): s0(0), (2,): s0(0), (3,): s0(0), (0,1): s1(0), (0,2): s1(0),\n", " (0,3): s1(0), (1,2): s1(0), (1,3): s1(0), (2,3): s1(0), (0,1,2): s2(0), (0,1,3): s2(0), \n", " (0,2,3): s2(0), (1,2,3): s2(0), (0,1,2,3): p0123}\n", "e1 = A._element_constructor_(values)\n", "print(\"\")\n", "print(\"e1:\")\n", "print(e1)\n", "print(\"\")\n", "e2 = e1.solve_primitive()\n", "print(\"e2\")\n", "print(e2)\n", "print(\"\")\n", "print(\"d(e2) == e1: \", e2.differential() == e1)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Example of degree 0" ] }, { "cell_type": "code", "execution_count": 101, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Defining t0, t1, t2, y0, y1, y2\n" ] }, { "data": { "text/plain": [ "True" ] }, "execution_count": 101, "metadata": {}, "output_type": "execute_result" } ], "source": [ "S = SimplicialComplex([[0,1,2], [0,1,3]],is_mutable=False)\n", "A = AlgebraAplK(S)\n", "s0 = SimplicialAlgebraplN(0)\n", "s2 = SimplicialAlgebraplN(2)\n", "s2.inject_variables()\n", "p012 = y0\n", "p013 = y0\n", "values = {(0,): s0(0), (1,): s0(0), (2,): s0(0), (3,): s0(0), (0,1): p012.face(2), (0,2): p012.face(1),\n", " (0,3): p013.face(1), (1,2): p012.face(0), (1,3): p013.face(0), (0,1,2): p012, (0,1,3): p013}\n", "e1 = A._element_constructor_(values)\n", "e2 = e1.solve_primitive()\n", "e2.differential() == e1" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Example" ] }, { "cell_type": "code", "execution_count": 102, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Defining t0, t1, t2, t3, y0, y1, y2, y3\n" ] }, { "data": { "text/plain": [ "True" ] }, "execution_count": 102, "metadata": {}, "output_type": "execute_result" } ], "source": [ "S = SimplicialComplex([[0,1,2,3]],is_mutable=False)\n", "A = AlgebraAplK(S)\n", "s0 = SimplicialAlgebraplN(0)\n", "s1 = SimplicialAlgebraplN(1)\n", "s2 = SimplicialAlgebraplN(2)\n", "s3 = SimplicialAlgebraplN(3)\n", "s3.inject_variables()\n", "p0123 = y1*y2*y3\n", "values = {(0,): s0(0), (1,): s0(0), (2,): s0(0), (3,): s0(0), (0,1): s1(0), (0,2): s1(0),\n", " (0,3): s1(0), (1,2): s1(0), (1,3): s1(0), (2,3): s1(0), (0,1,2): s2(0), (0,1,3): s2(0), \n", " (0,2,3): s2(0), (1,2,3): s2(0), (0,1,2,3): p0123}\n", "e1 = A._element_constructor_(values)\n", "primitive = e1.solve_primitive()\n", "primitive.differential() == e1" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Another example" ] }, { "cell_type": "code", "execution_count": 103, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Defining t0, t1, t2, y0, y1, y2\n" ] }, { "data": { "text/plain": [ "{(0,): 0, (1,): 0, (2,): 0, (3,): 0, (4,): 0, (0, 1): 0, (0, 2): 0, (0, 3): 0, (0, 4): 0, (1, 2): 0, (1, 3): 0, (1, 4): 0, (2, 3): 0, (2, 4): 0, (3, 4): 0, (0, 1, 2): y1*y2, (0, 1, 3): y1*y2, (0, 1, 4): 0, (0, 2, 3): 0, (0, 2, 4): 0, (0, 3, 4): 0, (1, 2, 3): y1*y2, (1, 2, 4): 0, (1, 3, 4): 0, (2, 3, 4): 0, (0, 1, 2, 3): t3*y1*y2 - t2*y1*y3 + t1*y2*y3 + y1*y2 + y1*y3, (0, 1, 2, 4): -t3*y1*y2 + t2*y1*y3 - t1*y2*y3 + y1*y2, (0, 1, 3, 4): -t3*y1*y2 + t2*y1*y3 - t1*y2*y3 + y1*y2, (0, 2, 3, 4): 0, (1, 2, 3, 4): -t3*y1*y2 + t2*y1*y3 - t1*y2*y3 + y1*y2, (0, 1, 2, 3, 4): t3*y1*y2 - t4*y1*y2 - t2*y1*y3 - t4*y1*y3 + t1*y2*y3 + t2*y1*y4 + t3*y1*y4 - t1*y2*y4 - t1*y3*y4 + y1*y2 + y1*y3}" ] }, "execution_count": 103, "metadata": {}, "output_type": "execute_result" } ], "source": [ "S = SimplicialComplex([[0,1,2,3,4]],is_mutable=False)\n", "A = AlgebraAplK(S)\n", "s0 = SimplicialAlgebraplN(0)\n", "s1 = SimplicialAlgebraplN(1)\n", "s2 = SimplicialAlgebraplN(2)\n", "s3 = SimplicialAlgebraplN(3)\n", "s4 = SimplicialAlgebraplN(4)\n", "s2.inject_variables()\n", "p012 = y1*y2\n", "p013 = y1*y2\n", "p023 = y1*y2\n", "p024 = y1*y2\n", "p034 = y1*y2\n", "p123 = y1*y2\n", "p124 = y1*y2\n", "p134 = y1*y2\n", "p234 = y1*y2\n", "\n", "p0123 = p012.propagate([0,1,2],3) + p123.propagate([1,2,3],3)+p013.propagate([0,1,3],3)\n", "p0134 = p013.propagate([0,1,2],3)\n", "p0124 = p012.propagate([0,1,2],3)\n", "p1234 = p123.propagate([0,1,2],3)\n", "p01234 = p012.propagate([0,1,2],4) + p123.propagate([1,2,3],4) + p013.propagate([0,1,3],4)\n", "\n", "values = {(0,): s0(0), (1,): s0(0), (2,): s0(0), (3,): s0(0), (4,): s0(0), \n", " (0,1): s1(0), (0,2): s1(0), (0,3): s1(0), (0,4): s1(0),\n", " (1,2): s1(0), (1,3): s1(0), (1,4): s1(0), \n", " (2,3): s1(0), (2,4): s1(0), \n", " (3,4): s1(0), \n", " (0,1,2): p012, (0,1,3): p013, (0,1,4): s2(0), \n", " (0,2,3): s2(0), (0,2,4): s2(0), (0,3,4): s2(0),\n", " (1,2,3): p123, (1,2,4): s2(0), (1,3,4): s2(0),\n", " (2,3,4): s2(0), \n", " (0,1,2,3): p0123,(0,1,2,4):p0124,(0,1,3,4): p0134,\n", " (0,2,3,4): s3(0),(1,2,3,4): p1234,\n", " (0,1,2,3,4): p01234}\n", "e1 = A._element_constructor_(values)\n", "e1" ] }, { "cell_type": "code", "execution_count": 104, "metadata": {}, "outputs": [], "source": [ "dife1 = e1.differential()\n", "#dife1" ] }, { "cell_type": "code", "execution_count": 105, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "dif(recovery) == diff(e1): True\n" ] } ], "source": [ "recovery = dife1.solve_primitive()\n", "print(\"dif(recovery) == diff(e1): \",recovery.differential() == dife1)\n", "#recovery" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Minimal model" ] }, { "cell_type": "code", "execution_count": 106, "metadata": {}, "outputs": [], "source": [ "def update_cdga(gca, diff_dict={}):\n", "\n", " gens_dict = gca.gens_dict()\n", " differentials = {}\n", " if diff_dict:\n", " for gen_name in diff_dict.keys():\n", " gen = gens_dict[gen_name]\n", " product_gens = diff_dict[gen_name]\n", " gen0 = gens_dict[product_gens[0]]\n", " if type(product_gens[1]) == int: # is a power\n", " power = product_gens[1]\n", " mult = gen0\n", " for i in range(1, power):\n", " mult *= gen0\n", " differentials.update({gen:mult})\n", " else:\n", " gen1 = gens_dict[product_gens[1]]\n", " differentials.update({gen:gen0*gen1})\n", "# print(\"differentials\", differentials)\n", " return gca.cdg_algebra(differentials) \n", "\n", " \n", "def has_preimage(M, element):\n", " \n", " d = M.differential()\n", " deg = element.degree()-1\n", "# print(\"differential of \", element, \"degree: \", deg)\n", " Md = d.differential_matrix(deg)\n", " gens = M.basis(deg)\n", " try:\n", " solution = Md.solve_left(vector(QQ,element.basis_coefficients()))\n", " primitive = sum(map(lambda coef, gen: coef*gen, solution, gens))\n", " print(element, \" has preimage \", primitive)\n", " return True\n", " except ValueError:\n", " return False\n", "\n", "def injectivity_step(M, phi, check_dim, names, \n", " degrees, differentials, index=0, depth=0, max_depth=5):\n", " \n", " print(\"Injectivity at dimension \", check_dim)\n", " if depth > max_depth:\n", " return [M, phi, names, degrees, differentials, True]\n", " deg = check_dim -1\n", " gens = [g for g in M.gens() if g.degree() < check_dim]\n", "# gens.sort(reverse=True)\n", " gen_products = []\n", " for i in range(len(gens)):\n", " e0 = gens[i]\n", " d = e0.degree()\n", " mcd = gcd(d, check_dim)\n", " if d%2 == 0 and mcd == d:\n", " power = True\n", " exp = check_dim / d\n", " mult = e0\n", " for j in range(1,exp-1):\n", " mult *= e0\n", " gen_products.append([e0, mult, power, exp])\n", " for j in range(i+1,len(gens)):\n", " power = False\n", " e1 = gens[j]\n", " if e0.degree() + e1.degree() == check_dim:\n", " gen_products.append([e0, e1, power])\n", "# print(\"products at dim \",check_dim,\": \", gen_products)\n", " new_M = M\n", " new_phi = phi\n", " new_names = names\n", " new_degrees = degrees\n", " new_differentials = differentials\n", " for pair in gen_products:\n", " # Looking at the minimal model side\n", " gen0 = pair[0]\n", " deg_0 = gen0.degree()\n", " gen1 = pair[1]\n", " deg_1 = gen1.degree()\n", " M_product = gen0*gen1\n", " # Looking at the AplK side\n", " gen0_name = list(M.gens_dict().keys())[list(M.gens_dict().values()).index(gen0)]\n", " aplk_gen0 = phi[deg_0][gen0_name]\n", " is_power = pair[2]\n", " power = 0\n", " if is_power:\n", " power = pair[3]\n", " aplk_gen1 = aplk_gen0\n", " for i in range(1, power):\n", " aplk_gen1 *= aplk_gen0\n", " else:\n", " gen1_name = list(M.gens_dict().keys())[list(M.gens_dict().values()).index(gen1)]\n", " aplk_gen1 = phi[deg_1][gen1_name]\n", " aplk_product = aplk_gen0*aplk_gen1\n", " A = aplk_product.parent()\n", " # Check conditions\n", " if (M_product == M(0)) and (aplk_product == A.null_element()): # zero element\n", " pass\n", " elif (M_product == M(0)) and (aplk_product != A.null_element()): #check\n", " if aplk_product.is_closed():\n", " pass #trivial cohomology class (assuming aplk_product has preimage by differential)\n", " else:\n", " raise ValueError('zero associated to a non-closed element in AplK')\n", " elif (M_product.differential() != 0): # is not closed\n", " print(\"The element \",M_product, \" is not closed\")\n", " pass \n", " elif (M_product.differential() == 0) and aplk_product.is_closed() and has_preimage(M, M_product):\n", " pass #trivial cohomology class (assuming aplk_product has preimage by differential)\n", " elif (M_product.differential() == 0) and aplk_product.is_closed(): #key step because M_product doesn't have preimage\n", " new_gen = 'y'+str(deg)+'_'+str(index)\n", " if aplk_product != A.null_element():\n", " try:\n", " preimage = aplk_product.solve_primitive()\n", " except ValueError:\n", " print(\" The element \",M_product, \" has non trivial cohomology class. No generator added.\")\n", " continue # we don't add a new generator because the element has non trivial cohomology class\n", " phi_new_gen = {new_gen: preimage}\n", " else: \n", " phi_new_gen = {new_gen: A.null_element()}\n", " print(\" Proceed to kill\", M_product, \" because has associated trivial cohomology class\")\n", " print(\"Adding generator \"+new_gen)\n", " new_names = names + [new_gen]\n", " new_degrees = tuple(list(degrees)+[deg])\n", " new_differentials = copy.deepcopy(differentials)\n", " if not is_power:\n", " new_differentials.update({new_gen: [gen0_name, gen1_name]})\n", " else:\n", " new_differentials.update({new_gen: [gen0_name, int(power)]})\n", " gca = GradedCommutativeAlgebra(QQ, names=new_names, degrees=new_degrees)\n", " new_M = update_cdga(gca, new_differentials)\n", " new_phi = copy.deepcopy(phi)\n", " d = new_phi[deg]\n", " d.update(phi_new_gen)\n", " return injectivity_step(new_M, new_phi, check_dim, new_names, \n", " new_degrees, new_differentials, index=index+1, depth=depth+1, max_depth=max_depth)\n", " else:\n", " pass\n", "\n", " return [new_M, new_phi, new_names, new_degrees, new_differentials, False]\n", "\n", "def get_unmapped_generators(dim, coho_aplk, coho_gens, correspondence):\n", "\n", " dimensions = list(correspondence.keys())\n", " unmmaped_elements = copy.deepcopy(coho_aplk)\n", " for gen_key in coho_gens.keys():\n", " gen = coho_gens[gen_key]\n", " found = False\n", " for i in range(1,dim):\n", " if (not found) and (i in dimensions):\n", " for j in range(i,dim):\n", " if (j in dimensions) and (i+j == dim):\n", " gensi = correspondence[i]\n", " gensj = correspondence[j]\n", " for gi in gensi.values():\n", " if not found:\n", " for gj in gensj.values():\n", " product = gi.cup_product(gj) \n", " if product == gen or -product == gen:\n", " found = True\n", " i_name = list(gensi.keys())[list(gensi.values()).index(gi)]\n", " j_name = list(gensj.keys())[list(gensj.values()).index(gj)]\n", " if gen_key in unmmaped_elements.keys():\n", " print(\"The element \",i_name+\"*\"+j_name,\" is already mapped\")\n", " del unmmaped_elements[gen_key]\n", " break\n", " return unmmaped_elements\n", "\n", "def surjective_step(A, M, phi, dim, names, degrees, differentials, cohomology_correspondence):\n", " \n", " print(\"Surjectivity at dimension \", dim)\n", " coho_aplk = A.get_cohomology_aplk(dim)\n", " cohomology_gens = A.cohomology_gens(dim)\n", " g = get_unmapped_generators(dim, coho_aplk, cohomology_gens, cohomology_correspondence)\n", " new_names = copy.deepcopy(names)\n", " new_degrees = copy.deepcopy(degrees)\n", " new_phi = copy.deepcopy(phi)\n", " new_correspondence = copy.deepcopy(cohomology_correspondence)\n", " phi_n_map = {}\n", " correspondence_n_map = {}\n", " for gen_key in g.keys():\n", " deg = gen_key[0]\n", " index = gen_key[1]\n", " new_var = 'x'+str(deg)+'_'+str(index)\n", " new_names += [new_var]\n", " new_degrees += [deg]\n", " phi_n_map[new_var] = g[gen_key]\n", " correspondence_n_map[new_var] = cohomology_gens[gen_key]\n", " gca = GradedCommutativeAlgebra(QQ, names=new_names, degrees=new_degrees)\n", " new_M = update_cdga(gca, differentials)\n", " new_phi[dim] = phi_n_map\n", " new_correspondence[dim] = correspondence_n_map\n", " return [new_M, new_phi, new_names, new_degrees, new_correspondence]\n", " \n", "def minimal_model(S, max_depth=5, max_dim=5):\n", " \n", " fundamental_group = S.fundamental_group()\n", " if (fundamental_group.order() != 1):\n", " print(\"Warning: The space is not simply-connected\")\n", " phi = {}\n", " cohomology_correspondence = {}\n", " A = AlgebraAplK(S)\n", " # First step of the algorithm\n", " first_dim = A.first_cohomology_group()\n", " phi_n_map = {}\n", " correspondence_n_map = {}\n", " if first_dim < 0:\n", " return [0,{},{}] # due to the function returns multiple objects\n", " elif first_dim > max_dim:\n", " return [0,{},{}] # due to the function returns multiple objects\n", " g = A.get_cohomology_aplk(first_dim)\n", " cohomology_gens = A.cohomology_gens(first_dim)\n", " names = []\n", " degrees = []\n", " for gen_key in g.keys():\n", " deg = gen_key[0]\n", " index = gen_key[1]\n", " new_var = 'x'+str(deg)+'_'+str(index)\n", " names += [new_var]\n", " degrees += [deg]\n", " phi_n_map[new_var] = g[gen_key]\n", " correspondence_n_map[new_var] = cohomology_gens[gen_key]\n", " differentials={}\n", " gca = GradedCommutativeAlgebra(QQ, names=names, degrees=degrees)\n", " M = gca.cdg_algebra(differentials)\n", " phi[first_dim] = phi_n_map\n", " cohomology_correspondence[first_dim] = correspondence_n_map\n", " # Now we have an isomorphism in the first non-null cohomology group\n", " # we check if phi is a monomorphism\n", " [M, phi, names, degrees, differentials, limit] = injectivity_step(M, phi, first_dim+1, names, \n", " degrees, differentials, index=0, depth=0, max_depth=5)\n", " if limit:\n", " print(\"The algorithm has reach the injectivity depth-limit at dimension \", first_dim)\n", " return [M, phi]\n", " else:\n", " dim = first_dim + 1\n", " for i in range(dim, max_dim):\n", " [M, phi, names, degrees, cohomology_correspondence] = surjective_step(A, M, phi, i, names, degrees, \n", " differentials, cohomology_correspondence)\n", " [M, phi, names, degrees, differentials, limit] = injectivity_step(M, phi, i+1, names, \n", " degrees, differentials, index=0, depth=0, max_depth=5)\n", " if limit:\n", " print(\"The algorithm has reach the injectivity depth-limit at dimension\", dim)\n", " break \n", " \n", " return [M, phi, cohomology_correspondence]\n", "\n", "# def minimal_model():\n", "# names = ['x1_0','x1_1']\n", "# degrees = (1,1)\n", "# differentials={}\n", "# gca = GradedCommutativeAlgebra(QQ, names=names, degrees=degrees)\n", "# cdga = gca.cdg_algebra(differentials)\n", "# print(cdga)\n", "# # aƱadimos el generador de grado uno con differencial producto de los anteriores\n", "# new_gen = 'y1_0'\n", "# names = names + [new_gen]\n", "# deg = 1\n", "# degrees = tuple(list(degrees)+[deg])\n", "# differentials.update({'y1_0':['x1_0','x1_1']})\n", "# gca = GradedCommutativeAlgebra(QQ, names=names, degrees=degrees)\n", "# new_cdga = update_cdga(gca, differentials)\n", "# print(new_cdga)\n" ] }, { "cell_type": "code", "execution_count": 107, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Injectivity at dimension 3\n", "Surjectivity at dimension 3\n", "Injectivity at dimension 4\n", " Proceed to kill x2_0^2 because has associated trivial cohomology class\n", "Adding generator y3_0\n", "Injectivity at dimension 4\n", "x2_0^2 has preimage y3_0\n", " Proceed to kill x2_0*x2_1 because has associated trivial cohomology class\n", "Adding generator y3_1\n", "Injectivity at dimension 4\n", "x2_0^2 has preimage y3_0\n", "x2_0*x2_1 has preimage y3_1\n", " Proceed to kill x2_1^2 because has associated trivial cohomology class\n", "Adding generator y3_2\n", "Injectivity at dimension 4\n", "x2_0^2 has preimage y3_0\n", "x2_0*x2_1 has preimage y3_1\n", "x2_1^2 has preimage y3_2\n", "Surjectivity at dimension 4\n", "Injectivity at dimension 5\n", "The element x2_0*y3_0 is not closed\n", "The element x2_0*y3_1 is not closed\n", "The element x2_0*y3_2 is not closed\n", "The element x2_1*y3_0 is not closed\n", "The element x2_1*y3_1 is not closed\n", "The element x2_1*y3_2 is not closed\n", "Surjectivity at dimension 5\n", "Injectivity at dimension 6\n", "x2_0^3 has preimage x2_0*y3_0\n", "x2_1^3 has preimage x2_1*y3_2\n", "The element y3_0*y3_1 is not closed\n", "The element y3_0*y3_2 is not closed\n", "The element y3_1*y3_2 is not closed\n", "Surjectivity at dimension 6\n", "Injectivity at dimension 7\n", "Surjectivity at dimension 7\n", "Injectivity at dimension 8\n", "x2_0^4 has preimage x2_0^2*y3_0\n", "x2_1^4 has preimage x2_1^2*y3_2\n", "Surjectivity at dimension 8\n", "Injectivity at dimension 9\n", "Surjectivity at dimension 9\n", "Injectivity at dimension 10\n", "x2_0^5 has preimage x2_0^3*y3_0\n", "x2_1^5 has preimage x2_1^3*y3_2\n" ] }, { "data": { "text/plain": [ "Commutative Differential Graded Algebra with generators ('x2_0', 'x2_1', 'y3_0', 'y3_1', 'y3_2') in degrees (2, 2, 3, 3, 3) over Rational Field with differential:\n", " x2_0 --> 0\n", " x2_1 --> 0\n", " y3_0 --> x2_0^2\n", " y3_1 --> x2_0*x2_1\n", " y3_2 --> x2_1^2" ] }, "execution_count": 107, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# S = SimplicialComplex([[0,1],[0,2],[1,2]],is_mutable=False) # S^1\n", "# S = SimplicialComplex([[0,1],[0,2],[1,2],[1,3],[2,3]],is_mutable=False) # S^1 wedge S^1\n", "# S = SimplicialComplex([[0,1,2],[0,1,3],[0,2,3],[1,2,3]],is_mutable=False) # S^2\n", "# S = SimplicialComplex([[0,1,2],[0,1,3],[0,2,3],[1,2,3],[3,4],[3,5],[4,5]],is_mutable=False) # S^1 wedge S^2\n", "# S = SimplicialComplex([[0,1,2],[0,3,4],[1,3,5]],is_mutable=False) # S^1 surrounded by 2-cells\n", "# S = SimplicialComplex([[0,1,2],[0,1,3],[0,2,3],[1,2,3],[3,4,5],[3,4,6],[3,5,6],[4,5,6]],is_mutable=False) # S^2 wedge S^2\n", "# S = SimplicialComplex([[0,1,2],[0,1,3],[0,2,3],[1,2,3],[0,2,4],[0,3,4],[2,3,4]],is_mutable=False) # S^2 wedge S^2\n", "# S = SimplicialComplex([[0,2,3],[0,2,4,5],[0,1,2,5],[1,2,3,6],[2,3,4,6],[0,1,3,7],[0,3,4,7]],is_mutable=False) # S^2 wedge S^2\n", "# S = simplicial_complexes.Torus()\n", "#######################################################\n", "# S = simplicial_complexes.Sphere(2)\n", "#######################################################\n", "# S = simplicial_complexes.K3Surface()\n", "#######################################################\n", "S1 = simplicial_complexes.Sphere(2)\n", "S2 = simplicial_complexes.Sphere(2)\n", "S = S1.wedge(S2, is_mutable=False)\n", "#######################################################\n", "#S = simplicial_complexes.ComplexProjectivePlane()\n", "#######################################################\n", "# S = simplicial_complexes.BrucknerGrunbaumSphere()\n", "#######################################################\n", "# S = simplicial_complexes.ProjectivePlane().wedge(simplicial_complexes.Sphere(2), is_mutable=False)\n", "#######################################################\n", "[sullivan_model, model_morphism, cohomology_correspondence] = minimal_model(S, max_depth=5, max_dim=10)\n", "sullivan_model" ] }, { "cell_type": "code", "execution_count": 108, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[x2_0^3, x2_0^2*x2_1, x2_0*x2_1^2, x2_1^3, y3_0*y3_1, y3_0*y3_2, y3_1*y3_2]" ] }, "execution_count": 108, "metadata": {}, "output_type": "execute_result" } ], "source": [ "sullivan_model.basis(6)" ] }, { "cell_type": "code", "execution_count": 109, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{2: [x2_0, x2_1], 5: [x2_1*y3_0 - x2_0*y3_1, x2_1*y3_1 - x2_0*y3_2]}" ] }, "execution_count": 109, "metadata": {}, "output_type": "execute_result" } ], "source": [ "sullivan_model.cohomology_generators(10)" ] }, { "cell_type": "code", "execution_count": 110, "metadata": {}, "outputs": [], "source": [ "a = model_morphism[2]['x2_0']^2\n", "b = model_morphism[3]['y3_0'] # no deberia salir 0" ] }, { "cell_type": "code", "execution_count": 111, "metadata": {}, "outputs": [ { "ename": "KeyError", "evalue": "()", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mKeyError\u001b[0m Traceback (most recent call last)", "\u001b[0;32m/tmp/ipykernel_7283/764669733.py\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0ma\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0msolve_primitive\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;32m/tmp/ipykernel_7283/334124851.py\u001b[0m in \u001b[0;36msolve_primitive\u001b[0;34m(self)\u001b[0m\n\u001b[1;32m 214\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 215\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0msolve_primitive\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 216\u001b[0;31m \u001b[0mp_basis\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_get_primitive_basis\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 217\u001b[0m \u001b[0md_basis\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_get_differential_basis\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mp_basis\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 218\u001b[0m \u001b[0mdiff_matrix\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_get_differential_matrix\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mp_basis\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0md_basis\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;32m/tmp/ipykernel_7283/334124851.py\u001b[0m in \u001b[0;36m_get_primitive_basis\u001b[0;34m(self)\u001b[0m\n\u001b[1;32m 35\u001b[0m \u001b[0mprimitive_basis\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0msimplex\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mtuple\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 36\u001b[0m \u001b[0;31m# add primitive elements related to the assigned polynomial\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 37\u001b[0;31m \u001b[0mpol\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0melements\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0msimplex\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mtuple\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 38\u001b[0m \u001b[0mprimitive_basis\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0msimplex\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mtuple\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m+=\u001b[0m \u001b[0mpol\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_get_primitive_basis\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 39\u001b[0m \u001b[0mprimitive_basis\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0msimplex\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mtuple\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mlist\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mset\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mprimitive_basis\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0msimplex\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mtuple\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;31mKeyError\u001b[0m: ()" ] } ], "source": [ "a.solve_primitive()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": 112, "metadata": {}, "outputs": [], "source": [ "S1 = simplicial_complexes.Sphere(2)\n", "S2 = simplicial_complexes.Sphere(2)\n", "S = S1.wedge(S2, is_mutable=False)\n", "A = AlgebraAplK(S)" ] }, { "cell_type": "code", "execution_count": 113, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "Finite family {(0, 0): h^{0,0}, (2, 0): h^{2,0}, (2, 1): h^{2,1}}" ] }, "execution_count": 113, "metadata": {}, "output_type": "execute_result" } ], "source": [ "S.cohomology_ring().basis()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": 137, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{[x2_1*y3_0 - x2_0*y3_1]: (), [x2_1*y3_1 - x2_0*y3_2]: ()}" ] }, "execution_count": 137, "metadata": {}, "output_type": "execute_result" } ], "source": [ "#def get_ker_elements(sullivan_model, model_morphism, A, dim):\n", "dim = 5\n", "# Get the basis of Hm\n", "hm_basis = sullivan_model.cohomology(dim).basis()\n", "Hc = A.cohomology_group(dim)\n", "apl_correspondence = {}\n", "cochain_correspondence = {}\n", "Hc_correspondence = {}\n", "M = zero_matrix(QQ,len(Hc.basis()),len(hm_basis))\n", "i = 0\n", "hm_basis_keys = list(hm_basis.keys())\n", "for gen in hm_basis_keys:\n", " # get an element of the basis of Hm\n", " # get a representative of a cohomology class in M\n", " gen_repr = gen.representative()\n", " # get the apl representative for each generator of M^p\n", " m_gens = gen_repr.parent().gens()\n", " aplgens = [model_morphism[g.degree()][str(g)] for g in m_gens]\n", " apl_correspondence[gen] = A.null_element()\n", " for exp in gen_repr.dict().keys():\n", " coef = gen_repr.dict()[exp]\n", " term = coef*prod([gen^e for gen,e in zip(aplgens, exp)])\n", " apl_correspondence[gen] += term\n", " cochain = apl_correspondence[gen].integral()\n", " cochain_correspondence[gen] = cochain\n", " vcochain = A.cochain_to_vector(cochain,dim)\n", " Hc_correspondence[gen] = Hc(vcochain)\n", " M[:,i] = Hc_correspondence[gen]\n", " i+=1\n", " \n", "Hc_correspondence\n", "\n", "# falta crear la matriz" ] }, { "cell_type": "code", "execution_count": 138, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "((1, 0), (0, 1))" ] }, "execution_count": 138, "metadata": {}, "output_type": "execute_result" } ], "source": [ "Kgens = M.right_kernel().gens()\n", "Kgens" ] }, { "cell_type": "code", "execution_count": 148, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[x2_1*y3_0 - x2_0*y3_1, x2_1*y3_1 - x2_0*y3_2]" ] }, "execution_count": 148, "metadata": {}, "output_type": "execute_result" } ], "source": [ "[e.representative() for e in hm_basis_keys]" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "gdca_basis = gen_repr.parent().basis(gen_repr.degree())\n", "gdca_basis" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "print(gen_repr.dict())\n", "gen_repr.parent().gens()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "Hc_2 = A.cohomology_group(2).basis()\n", "#A.lift_cochain(A.vector_to_cochain(Hc_2.lift((0,1)),2))\n", "Hc_2" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "\n", "\n", "element = Hm_basis[2][0] + Hm_basis[2][1]\n", "def integralPhiCohomology(element):\n", " aplelement = model_morphism[2][str(element)]\n", " cochain = aplelement.integral()\n", " vcochain = A.cochain_to_vector(cochain,2)\n", " Hc_2 = A.cohomology_group(2)\n", " return Hc_2(vcochain)\n", "integralPhiCohomology(element)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "Hc_basis = A.cohomology_gens(2)\n", "cochain0 = A.lift_cohomology_generator(list(Hc_basis.values())[0])\n", "cochain1 = A.lift_cohomology_generator(list(Hc_basis.values())[1])\n", "vcochain0 = A.cochain_to_vector(cochain0,2)\n", "vcochain1 = A.cochain_to_vector(cochain1,2)\n", "vcochain = vcochain0-3*vcochain1" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "Hc_2 = A.cohomology_group(2)\n", "Hc_2(vcochain)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Example step by step" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "K = simplicial_complexes.ComplexProjectivePlane()\n", "A = AlgebraAplK(K)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# get the lowest dim for which H^{dim} is not trivial\n", "first_dim = A.first_cohomology_group()\n", "first_dim" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "g = A.get_cohomology_aplk(first_dim)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "g = A.get_cohomology_aplk(first_dim)\n", "cohomology_gens = A.cohomology_gens(first_dim)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "cohomology_gens" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "names = []\n", "degrees = []\n", "phi = {}\n", "phi_n_map = {}\n", "cohomology_correspondence = {}\n", "correspondence_n_map = {}\n", "for gen_key in g.keys():\n", " deg = gen_key[0]\n", " index = gen_key[1]\n", " new_var = 'x'+str(deg)+'_'+str(index)\n", " names += [new_var]\n", " degrees += [deg]\n", " phi_n_map[new_var] = g[gen_key]\n", " correspondence_n_map[new_var] = cohomology_gens[gen_key]\n", "differentials={}\n", "gca = GradedCommutativeAlgebra(QQ, names=names, degrees=degrees)\n", "M = gca.cdg_algebra(differentials)\n", "phi[first_dim] = phi_n_map\n", "cohomology_correspondence[first_dim] = correspondence_n_map" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "r = phi[2]['x2_0']" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "count = 0\n", "for s in r.elements.keys():\n", " if len(s)==5:\n", " v = r.elements[s]\n", " if v != 0:\n", " count += 1\n", " print(s, \" ==> \", v)\n", "print(count)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "r = (phi[2]['x2_0']^2)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "count = 0\n", "for s in r.elements.keys():\n", " if len(s)==5:\n", " v = r.elements[s]\n", " if v != 0:\n", " count += 1\n", " print(s, \" ==> \", v)\n", "print(count)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "M.cohomology(4)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "A.cohomology_gens(4)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "c = M.cohomology(4)\n", "c" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "K.cohomology(4,base_ring=QQ)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "M" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "dim = 2\n", "# Get the basis of Hm\n", "hm_basis = M.cohomology(dim).basis()\n", "Hc = A.cohomology_group(dim)\n", "apl_correspondence = {}\n", "cochain_correspondence = {}\n", "Hc_correspondence = {}\n", "Mat = zero_matrix(QQ,len(Hc.basis()),len(hm_basis))\n", "i = 0\n", "for gen in list(hm_basis.keys()):\n", " # get an element of the basis of Hm\n", " # get a representative of a cohomology class in M\n", " gen_repr = gen.representative()\n", " # get the apl representative for each generator of M^p\n", " m_gens = gen_repr.parent().gens()\n", " aplgens = [phi[g.degree()][str(g)] for g in m_gens]\n", " apl_correspondence[gen] = A.null_element()\n", " for exp in gen_repr.dict().keys():\n", " coef = gen_repr.dict()[exp]\n", " term = coef*prod([gen^e for gen,e in zip(aplgens, exp)])\n", " apl_correspondence[gen] += term\n", " cochain = apl_correspondence[gen].integral()\n", " cochain_correspondence[gen] = cochain\n", " vcochain = A.cochain_to_vector(cochain,dim)\n", " Hc_correspondence[gen] = Hc(vcochain)\n", " Mat[:,i] = Hc_correspondence[gen]\n", " i+=1\n", "Hc_correspondence" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "M.cohomology(2)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "K.cohomology(5,base_ring=QQ)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "gca = GradedCommutativeAlgebra(QQ, names=['x2_0','y5_0'], degrees=(2,5))\n", "differentials = {gca.gens()[1]:gca.gens()[0]^3}\n", "M = gca.cdg_algebra(differentials)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "SageMath 9.2", "language": "sage", "name": "sagemath" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.8.5" }, "toc-autonumbering": false, "toc-showmarkdowntxt": false }, "nbformat": 4, "nbformat_minor": 4 }