{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Category Framework in Sage\n",
    "## Universidad de Zaragoza\n",
    "### Travis Scrimshaw 29 June, 2018\n",
    "----"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Mathematically, a *category* is a class of objects and a class of morphisms between the objects such that $f \\circ (g \\circ h) = (f \\circ g) \\circ h$ and every object has an identity morphism."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "In Sage, a category (currently) is a mathematical concrete category, there exists the forgetful functor to the category `Sets`. They serve dual roles: indication of mathematical structures and as abstract base classes (i.e., generic implementations of the mathematical objects)."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "In Sage, a `Parent` is an object in `Sets` that represents (abstractly) a collection of `Element` objects. For example, a polynomial in $x$ with coefficients in $\\mathbb{Q}$ is an `Element` and the ring of polynomials $\\mathbb{Q}[x]$ is the `Parent`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "R.<x> = QQ[]\n",
    "p = x^3 - 3/2*x^2 + 8123/17*x + 5"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "isinstance(R, Parent)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from sage.structure.element import Element\n",
    "isinstance(p, Element)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "R in Sets()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "For example, $m \\times n$ matrices over a commutative ring $R$ are always a module over $R$, but when $m = n$, then we can multiply matrices and they form an algebra over $R$."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Category of infinite enumerated finite dimensional modules with basis over (euclidean domains and infinite enumerated sets and metric spaces)"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "M32 = MatrixSpace(ZZ, 3, 2)\n",
    "M32.category()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Category of infinite enumerated finite dimensional algebras with basis over (euclidean domains and infinite enumerated sets and metric spaces)"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "M33 = MatrixSpace(ZZ, 3, 3)\n",
    "M33.category()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[ 0  1]    [ 0  1 -1]\n",
       "[-1  2]    [ 2 -2  3]\n",
       "[-2  3]    [-3  4 -4]"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "x = M32.an_element()\n",
    "y = M33.an_element()\n",
    "ascii_art(x, \"    \", y)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{(0, 1): 1, (1, 0): -1, (1, 1): 2, (2, 0): -2, (2, 1): 3}"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "x.monomial_coefficients()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{(0, 1): 1,\n",
       " (0, 2): -1,\n",
       " (1, 0): 2,\n",
       " (1, 1): -2,\n",
       " (1, 2): 3,\n",
       " (2, 0): -3,\n",
       " (2, 1): 4,\n",
       " (2, 2): -4}"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "y.monomial_coefficients()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(\n",
       "[1 0 0]\n",
       "[0 1 0]\n",
       "[0 0 1]\n",
       ")"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "M33.center_basis()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "ename": "AttributeError",
     "evalue": "'MatrixSpace_with_category' object has no attribute 'center_basis'",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mAttributeError\u001b[0m                            Traceback (most recent call last)",
      "\u001b[0;32m<ipython-input-11-a6baaad529e0>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mM32\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mcenter_basis\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/home/travis/sage-build/local/lib/python2.7/site-packages/sage/structure/category_object.pyx\u001b[0m in \u001b[0;36msage.structure.category_object.CategoryObject.__getattr__ (build/cythonized/sage/structure/category_object.c:7996)\u001b[0;34m()\u001b[0m\n\u001b[1;32m    853\u001b[0m             \u001b[0mAttributeError\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0;34m'PrimeNumbers_with_category'\u001b[0m \u001b[0mobject\u001b[0m \u001b[0mhas\u001b[0m \u001b[0mno\u001b[0m \u001b[0mattribute\u001b[0m \u001b[0;34m'sadfasdf'\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    854\u001b[0m         \"\"\"\n\u001b[0;32m--> 855\u001b[0;31m         \u001b[0;32mreturn\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mgetattr_from_category\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mname\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    856\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    857\u001b[0m     \u001b[0mcdef\u001b[0m \u001b[0mgetattr_from_category\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mname\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;32m/home/travis/sage-build/local/lib/python2.7/site-packages/sage/structure/category_object.pyx\u001b[0m in \u001b[0;36msage.structure.category_object.CategoryObject.getattr_from_category (build/cythonized/sage/structure/category_object.c:8159)\u001b[0;34m()\u001b[0m\n\u001b[1;32m    868\u001b[0m                 \u001b[0mcls\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_category\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mparent_class\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    869\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 870\u001b[0;31m             \u001b[0mattr\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mgetattr_from_other_class\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mcls\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mname\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    871\u001b[0m             \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m__cached_methods\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mname\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mattr\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    872\u001b[0m             \u001b[0;32mreturn\u001b[0m \u001b[0mattr\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;32m/home/travis/sage-build/local/lib/python2.7/site-packages/sage/cpython/getattr.pyx\u001b[0m in \u001b[0;36msage.cpython.getattr.getattr_from_other_class (build/cythonized/sage/cpython/getattr.c:2468)\u001b[0;34m()\u001b[0m\n\u001b[1;32m    387\u001b[0m         \u001b[0mdummy_error_message\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mcls\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mtype\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    388\u001b[0m         \u001b[0mdummy_error_message\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mname\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mname\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 389\u001b[0;31m         \u001b[0;32mraise\u001b[0m \u001b[0mAttributeError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mdummy_error_message\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    390\u001b[0m     \u001b[0mcdef\u001b[0m \u001b[0mPyObject\u001b[0m\u001b[0;34m*\u001b[0m \u001b[0mattr\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0minstance_getattr\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mcls\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mname\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    391\u001b[0m     \u001b[0;32mif\u001b[0m \u001b[0mattr\u001b[0m \u001b[0;32mis\u001b[0m \u001b[0mNULL\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;31mAttributeError\u001b[0m: 'MatrixSpace_with_category' object has no attribute 'center_basis'"
     ]
    }
   ],
   "source": [
    "M32.center_basis()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The fact that we obtain an `AttributeError` comes from the abstract base class properties of the categories. Because `M33` is in `FiniteDimensionalAlgebrasWithBasis`, it obtains extra (generic) methods from the category."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(<class 'sage.matrix.matrix_space.MatrixSpace_with_category'>,\n",
       " <class 'sage.matrix.matrix_space.MatrixSpace'>,\n",
       " <class 'sage.structure.unique_representation.UniqueRepresentation'>,\n",
       " <class 'sage.structure.unique_representation.CachedRepresentation'>,\n",
       " <type 'sage.misc.fast_methods.WithEqualityById'>,\n",
       " <type 'sage.structure.parent_gens.ParentWithGens'>,\n",
       " <type 'sage.structure.parent_base.ParentWithBase'>,\n",
       " <type 'sage.structure.parent_old.Parent'>,\n",
       " <type 'sage.structure.parent.Parent'>,\n",
       " <type 'sage.structure.category_object.CategoryObject'>,\n",
       " <type 'sage.structure.sage_object.SageObject'>,\n",
       " <class 'sage.categories.category.JoinCategory.parent_class'>,\n",
       " <class 'sage.categories.finite_dimensional_modules_with_basis.FiniteDimensionalModulesWithBasis.parent_class'>,\n",
       " <class 'sage.categories.modules_with_basis.ModulesWithBasis.parent_class'>,\n",
       " <class 'sage.categories.modules.Modules.FiniteDimensional.parent_class'>,\n",
       " <class 'sage.categories.modules.Modules.parent_class'>,\n",
       " <class 'sage.categories.bimodules.Bimodules.parent_class'>,\n",
       " <class 'sage.categories.right_modules.RightModules.parent_class'>,\n",
       " <class 'sage.categories.left_modules.LeftModules.parent_class'>,\n",
       " <class 'sage.categories.commutative_additive_groups.CommutativeAdditiveGroups.parent_class'>,\n",
       " <class 'sage.categories.additive_groups.AdditiveGroups.parent_class'>,\n",
       " <class 'sage.categories.additive_magmas.AdditiveMagmas.AdditiveUnital.AdditiveInverse.parent_class'>,\n",
       " <class 'sage.categories.commutative_additive_monoids.CommutativeAdditiveMonoids.parent_class'>,\n",
       " <class 'sage.categories.additive_monoids.AdditiveMonoids.parent_class'>,\n",
       " <class 'sage.categories.additive_magmas.AdditiveMagmas.AdditiveUnital.parent_class'>,\n",
       " <class 'sage.categories.commutative_additive_semigroups.CommutativeAdditiveSemigroups.parent_class'>,\n",
       " <class 'sage.categories.additive_magmas.AdditiveMagmas.AdditiveCommutative.parent_class'>,\n",
       " <class 'sage.categories.additive_semigroups.AdditiveSemigroups.parent_class'>,\n",
       " <class 'sage.categories.additive_magmas.AdditiveMagmas.parent_class'>,\n",
       " <class 'sage.categories.infinite_enumerated_sets.InfiniteEnumeratedSets.parent_class'>,\n",
       " <class 'sage.categories.enumerated_sets.EnumeratedSets.parent_class'>,\n",
       " <class 'sage.categories.sets_cat.Sets.Infinite.parent_class'>,\n",
       " <class 'sage.categories.sets_cat.Sets.parent_class'>,\n",
       " <class 'sage.categories.sets_with_partial_maps.SetsWithPartialMaps.parent_class'>,\n",
       " <class 'sage.categories.objects.Objects.parent_class'>,\n",
       " <type 'object'>)"
      ]
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "M32.__class__.__mro__"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(<class 'sage.matrix.matrix_space.MatrixSpace_with_category'>,\n",
       " <class 'sage.matrix.matrix_space.MatrixSpace'>,\n",
       " <class 'sage.structure.unique_representation.UniqueRepresentation'>,\n",
       " <class 'sage.structure.unique_representation.CachedRepresentation'>,\n",
       " <type 'sage.misc.fast_methods.WithEqualityById'>,\n",
       " <type 'sage.structure.parent_gens.ParentWithGens'>,\n",
       " <type 'sage.structure.parent_base.ParentWithBase'>,\n",
       " <type 'sage.structure.parent_old.Parent'>,\n",
       " <type 'sage.structure.parent.Parent'>,\n",
       " <type 'sage.structure.category_object.CategoryObject'>,\n",
       " <type 'sage.structure.sage_object.SageObject'>,\n",
       " <class 'sage.categories.category.JoinCategory.parent_class'>,\n",
       " <class 'sage.categories.finite_dimensional_algebras_with_basis.FiniteDimensionalAlgebrasWithBasis.parent_class'>,\n",
       " <class 'sage.categories.algebras_with_basis.AlgebrasWithBasis.parent_class'>,\n",
       " <class 'sage.categories.algebras.Algebras.parent_class'>,\n",
       " <class 'sage.categories.rings.Rings.parent_class'>,\n",
       " <class 'sage.categories.associative_algebras.AssociativeAlgebras.parent_class'>,\n",
       " <class 'sage.categories.rngs.Rngs.parent_class'>,\n",
       " <class 'sage.categories.semirings.Semirings.parent_class'>,\n",
       " <class 'sage.categories.distributive_magmas_and_additive_magmas.DistributiveMagmasAndAdditiveMagmas.AdditiveAssociative.AdditiveCommutative.AdditiveUnital.Associative.parent_class'>,\n",
       " <class 'sage.categories.unital_algebras.UnitalAlgebras.WithBasis.parent_class'>,\n",
       " <class 'sage.categories.magmatic_algebras.MagmaticAlgebras.WithBasis.parent_class'>,\n",
       " <class 'sage.categories.unital_algebras.UnitalAlgebras.parent_class'>,\n",
       " <class 'sage.categories.magmatic_algebras.MagmaticAlgebras.parent_class'>,\n",
       " <class 'sage.categories.distributive_magmas_and_additive_magmas.DistributiveMagmasAndAdditiveMagmas.AdditiveAssociative.AdditiveCommutative.AdditiveUnital.parent_class'>,\n",
       " <class 'sage.categories.distributive_magmas_and_additive_magmas.DistributiveMagmasAndAdditiveMagmas.AdditiveAssociative.AdditiveCommutative.parent_class'>,\n",
       " <class 'sage.categories.distributive_magmas_and_additive_magmas.DistributiveMagmasAndAdditiveMagmas.AdditiveAssociative.parent_class'>,\n",
       " <class 'sage.categories.distributive_magmas_and_additive_magmas.DistributiveMagmasAndAdditiveMagmas.parent_class'>,\n",
       " <class 'sage.categories.magmas_and_additive_magmas.MagmasAndAdditiveMagmas.parent_class'>,\n",
       " <class 'sage.categories.monoids.Monoids.parent_class'>,\n",
       " <class 'sage.categories.semigroups.Semigroups.parent_class'>,\n",
       " <class 'sage.categories.magmas.Magmas.Unital.parent_class'>,\n",
       " <class 'sage.categories.magmas.Magmas.parent_class'>,\n",
       " <class 'sage.categories.finite_dimensional_modules_with_basis.FiniteDimensionalModulesWithBasis.parent_class'>,\n",
       " <class 'sage.categories.modules_with_basis.ModulesWithBasis.parent_class'>,\n",
       " <class 'sage.categories.modules.Modules.FiniteDimensional.parent_class'>,\n",
       " <class 'sage.categories.modules.Modules.parent_class'>,\n",
       " <class 'sage.categories.bimodules.Bimodules.parent_class'>,\n",
       " <class 'sage.categories.right_modules.RightModules.parent_class'>,\n",
       " <class 'sage.categories.left_modules.LeftModules.parent_class'>,\n",
       " <class 'sage.categories.commutative_additive_groups.CommutativeAdditiveGroups.parent_class'>,\n",
       " <class 'sage.categories.additive_groups.AdditiveGroups.parent_class'>,\n",
       " <class 'sage.categories.additive_magmas.AdditiveMagmas.AdditiveUnital.AdditiveInverse.parent_class'>,\n",
       " <class 'sage.categories.commutative_additive_monoids.CommutativeAdditiveMonoids.parent_class'>,\n",
       " <class 'sage.categories.additive_monoids.AdditiveMonoids.parent_class'>,\n",
       " <class 'sage.categories.additive_magmas.AdditiveMagmas.AdditiveUnital.parent_class'>,\n",
       " <class 'sage.categories.commutative_additive_semigroups.CommutativeAdditiveSemigroups.parent_class'>,\n",
       " <class 'sage.categories.additive_magmas.AdditiveMagmas.AdditiveCommutative.parent_class'>,\n",
       " <class 'sage.categories.additive_semigroups.AdditiveSemigroups.parent_class'>,\n",
       " <class 'sage.categories.additive_magmas.AdditiveMagmas.parent_class'>,\n",
       " <class 'sage.categories.infinite_enumerated_sets.InfiniteEnumeratedSets.parent_class'>,\n",
       " <class 'sage.categories.enumerated_sets.EnumeratedSets.parent_class'>,\n",
       " <class 'sage.categories.sets_cat.Sets.Infinite.parent_class'>,\n",
       " <class 'sage.categories.sets_cat.Sets.parent_class'>,\n",
       " <class 'sage.categories.sets_with_partial_maps.SetsWithPartialMaps.parent_class'>,\n",
       " <class 'sage.categories.objects.Objects.parent_class'>,\n",
       " <type 'object'>)"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "M33.__class__.__mro__"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now the mathematical aspects can also be used in defining morphisms. For instance, if we consider the endomorphisms as rings on $\\mathbb{Z}$, we can see there is only $1$: the identity map. However, if we instead consider this as additive (abelian) groups, we obtain an infinite number of morphisms."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(Set of Homomorphisms from Integer Ring to Integer Ring,\n",
       " Set of Morphisms from Integer Ring to Integer Ring in Category of commutative additive groups)"
      ]
     },
     "execution_count": 17,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "AAG = AdditiveMagmas().AdditiveAssociative().AdditiveUnital().AdditiveInverse().AdditiveCommutative()\n",
    "HR = Hom(ZZ, ZZ, Rings())\n",
    "HG = Hom(ZZ, ZZ, AAG)\n",
    "HR, HG"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Ring endomorphism of Integer Ring\n",
       "  Defn: 1 |--> 1"
      ]
     },
     "execution_count": 18,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "HR([1])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [
    {
     "ename": "ValueError",
     "evalue": "relations do not all (canonically) map to 0 under map determined by images of generators",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mValueError\u001b[0m                                Traceback (most recent call last)",
      "\u001b[0;32m<ipython-input-21-bcbb89ae9b5d>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mHR\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mInteger\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m2\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/home/travis/sage-build/local/lib/python2.7/site-packages/sage/rings/homset.pyc\u001b[0m in \u001b[0;36m__call__\u001b[0;34m(self, im_gens, check)\u001b[0m\n\u001b[1;32m    181\u001b[0m             \u001b[0;32mreturn\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_coerce_impl\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mim_gens\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    182\u001b[0m         \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 183\u001b[0;31m             \u001b[0;32mreturn\u001b[0m \u001b[0mmorphism\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mRingHomomorphism_im_gens\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mim_gens\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mcheck\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mcheck\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    184\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    185\u001b[0m     \u001b[0;32mdef\u001b[0m \u001b[0mnatural_map\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[0m\n",
      "\u001b[0;32m/home/travis/sage-build/local/lib/python2.7/site-packages/sage/rings/morphism.pyx\u001b[0m in \u001b[0;36msage.rings.morphism.RingHomomorphism_im_gens.__init__ (build/cythonized/sage/rings/morphism.c:8397)\u001b[0;34m()\u001b[0m\n\u001b[1;32m   1051\u001b[0m             \u001b[0mt\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mparent\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdomain\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_is_valid_homomorphism_\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mparent\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mcodomain\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mim_gens\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m   1052\u001b[0m             \u001b[0;32mif\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0mt\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 1053\u001b[0;31m                 \u001b[0;32mraise\u001b[0m \u001b[0mValueError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"relations do not all (canonically) map to 0 under map determined by images of generators\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m   1054\u001b[0m         \u001b[0;32mif\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0mim_gens\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mis_immutable\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   1055\u001b[0m             \u001b[0;32mimport\u001b[0m \u001b[0mcopy\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;31mValueError\u001b[0m: relations do not all (canonically) map to 0 under map determined by images of generators"
     ]
    }
   ],
   "source": [
    "HR([2])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "6"
      ]
     },
     "execution_count": 22,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "phi = HG(lambda x: 2*x)\n",
    "phi(3)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now I am betting you've asked me what was all that stuff about about `AdditiveMagmas()` and the stuff that followed it. If you haven't, maybe you're curious about it. The answer is an additive magma is a set with a binary operation `+`, and in order to get a group, it should be associative, have a unit, and an inverse for every element. Finally, we wanted abelian groups as well. What these are are *axioms* for a group, and so we also called these axioms for a category. An axiom is guaranteed to have the same interpretation for all *subcategories* of a particular category $\\mathcal{C}$.\n",
    "\n",
    "**WARNING**:\n",
    "\n",
    "A subcategory of $\\mathcal{C}$ in Sage means a category with a forgetful functor to $\\mathcal{C}$. This can differ from other notions of a subcategory (e.g., take a subclass of the objects and morphisms)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "frozenset({'AdditiveAssociative',\n",
       "           'AdditiveCommutative',\n",
       "           'AdditiveInverse',\n",
       "           'AdditiveUnital'})"
      ]
     },
     "execution_count": 23,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "AAG.axioms()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Because of this, we are required to have different axioms for additive and multiplicative magmas, but for simplicity, we have dropped the 'multiplicative'. However, this allows us to construct the category of rings using additive and multiplicative magmas."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Join of Category of semigroups and Category of commutative additive groups"
      ]
     },
     "execution_count": 24,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "Cat = AAG & Magmas().Associative()\n",
    "Cat"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Category of rngs"
      ]
     },
     "execution_count": 25,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "Rngs = Cat.Distributive()\n",
    "Rngs"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 26,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "Rngs.Unital() == Rings()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Sage also has a notion of functors and functorial constructions. Let us consider tensor products of algebras (over some commutative ring $R$), then Sage knows how to construct its tensor products and also knows that it is also naturally an algebra."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {},
   "outputs": [],
   "source": [
    "F.<x,y,z> = algebras.Free(QQ)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "F[z] # F[y] + F[z] # F[z^2] - F[z] # F[x^3] + F[x*y] # F[y] + F[x*y] # F[z^2] - F[x*y] # F[x^3]"
      ]
     },
     "execution_count": 28,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "tensor([x*y+z, z^2+y-x^3])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "F[x*y] # F[y*x] - F[x*y] # F[y*z] + F[x*z] # F[y*x] - F[x*z] # F[y*z]"
      ]
     },
     "execution_count": 29,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "tensor([x,y]) * tensor([z+y,x-z])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Free Algebra on 3 generators (x, y, z) over Rational Field # Free Algebra on 3 generators (x, y, z) over Rational Field # Free Algebra on 3 generators (x, y, z) over Rational Field # Free Algebra on 3 generators (x, y, z) over Rational Field"
      ]
     },
     "execution_count": 30,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "T = tensor([F,F,F,F])\n",
    "T"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Category of tensor products of algebras with basis over Rational Field"
      ]
     },
     "execution_count": 31,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "T.category()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 32,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "T in Algebras(QQ)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Another common functorial construction in algebra is imposing a grading, such as a graded algebra. This is an example of a *covariant functorial construction*, where if a category $\\mathcal{D}$ is a subcategory of $\\mathcal{C}$, and we have the functorially constructed categories $\\mathcal{FD}$ and $\\mathcal{FC}$, then $\\mathcal{FD}$ is a subcategory of $\\mathcal{FC}$. However, where this differs from an axiom is that an object $X \\in \\mathcal{FC} \\cap \\mathcal{D}$ does not imply $X \\in \\mathcal{FD}$ (which would be the case for an axiom). For a concrete example, a graded module that is an algebra is not necessarily a graded algebra."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Join of Category of algebras over Rational Field and Category of graded modules over Rational Field"
      ]
     },
     "execution_count": 34,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "Modules(QQ).Graded() & Algebras(QQ)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Category of graded algebras over Rational Field"
      ]
     },
     "execution_count": 35,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "Algebras(QQ).Graded()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 36,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "Algebras(QQ).Graded().is_subcategory(Modules(QQ).Graded() & Algebras(QQ))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Sage also knows some category theoretical facts, such as Wedderburn's theorem"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Category of finite enumerated fields"
      ]
     },
     "execution_count": 37,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "Rings().Division().Finite()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Next, we want to construct a new category to discuss how categories are implemented. For this example, we will be considering magmatic (i.e., not necessarily associative or unital) algebras that are power associative. So we start with a `Category_over_base_ring` and say its immediate super category is `MagmaticAlgebras`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 38,
   "metadata": {},
   "outputs": [],
   "source": [
    "from sage.categories.category_types import Category_over_base_ring\n",
    "from sage.categories.magmatic_algebras import MagmaticAlgebras\n",
    "class PowerAssociativeAlgebras(Category_over_base_ring):\n",
    "    def super_categories(self):\n",
    "        return [MagmaticAlgebras(self.base_ring())]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 39,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Category of power associative algebras over Rational Field"
      ]
     },
     "execution_count": 39,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "PAA = PowerAssociativeAlgebras(QQ)\n",
    "PAA"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 40,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[Category of magmatic algebras over Rational Field]"
      ]
     },
     "execution_count": 40,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "PAA.super_categories()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 41,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(<class '__main__.PowerAssociativeAlgebras_with_category'>,\n",
       " <class '__main__.PowerAssociativeAlgebras'>,\n",
       " <class 'sage.categories.category_types.Category_over_base_ring'>,\n",
       " <class 'sage.categories.category_types.Category_over_base'>,\n",
       " <class 'sage.categories.category.CategoryWithParameters'>,\n",
       " <class 'sage.categories.category.Category'>,\n",
       " <class 'sage.structure.unique_representation.UniqueRepresentation'>,\n",
       " <class 'sage.structure.unique_representation.CachedRepresentation'>,\n",
       " <type 'sage.misc.fast_methods.WithEqualityById'>,\n",
       " <type 'sage.structure.sage_object.SageObject'>,\n",
       " <class '__main__.PowerAssociativeAlgebras.subcategory_class'>,\n",
       " <class 'sage.categories.magmatic_algebras.MagmaticAlgebras.subcategory_class'>,\n",
       " <class 'sage.categories.distributive_magmas_and_additive_magmas.DistributiveMagmasAndAdditiveMagmas.AdditiveAssociative.AdditiveCommutative.AdditiveUnital.subcategory_class'>,\n",
       " <class 'sage.categories.distributive_magmas_and_additive_magmas.DistributiveMagmasAndAdditiveMagmas.AdditiveAssociative.AdditiveCommutative.subcategory_class'>,\n",
       " <class 'sage.categories.distributive_magmas_and_additive_magmas.DistributiveMagmasAndAdditiveMagmas.AdditiveAssociative.subcategory_class'>,\n",
       " <class 'sage.categories.distributive_magmas_and_additive_magmas.DistributiveMagmasAndAdditiveMagmas.subcategory_class'>,\n",
       " <class 'sage.categories.magmas_and_additive_magmas.MagmasAndAdditiveMagmas.subcategory_class'>,\n",
       " <class 'sage.categories.magmas.Magmas.subcategory_class'>,\n",
       " <class 'sage.categories.vector_spaces.VectorSpaces.subcategory_class'>,\n",
       " <class 'sage.categories.modules.Modules.subcategory_class'>,\n",
       " <class 'sage.categories.bimodules.Bimodules.subcategory_class'>,\n",
       " <class 'sage.categories.right_modules.RightModules.subcategory_class'>,\n",
       " <class 'sage.categories.left_modules.LeftModules.subcategory_class'>,\n",
       " <class 'sage.categories.commutative_additive_groups.CommutativeAdditiveGroups.subcategory_class'>,\n",
       " <class 'sage.categories.additive_groups.AdditiveGroups.subcategory_class'>,\n",
       " <class 'sage.categories.additive_magmas.AdditiveMagmas.AdditiveUnital.AdditiveInverse.subcategory_class'>,\n",
       " <class 'sage.categories.commutative_additive_monoids.CommutativeAdditiveMonoids.subcategory_class'>,\n",
       " <class 'sage.categories.additive_monoids.AdditiveMonoids.subcategory_class'>,\n",
       " <class 'sage.categories.additive_magmas.AdditiveMagmas.AdditiveUnital.subcategory_class'>,\n",
       " <class 'sage.categories.commutative_additive_semigroups.CommutativeAdditiveSemigroups.subcategory_class'>,\n",
       " <class 'sage.categories.additive_magmas.AdditiveMagmas.AdditiveCommutative.subcategory_class'>,\n",
       " <class 'sage.categories.additive_semigroups.AdditiveSemigroups.subcategory_class'>,\n",
       " <class 'sage.categories.additive_magmas.AdditiveMagmas.subcategory_class'>,\n",
       " <class 'sage.categories.sets_cat.Sets.subcategory_class'>,\n",
       " <class 'sage.categories.sets_with_partial_maps.SetsWithPartialMaps.subcategory_class'>,\n",
       " <class 'sage.categories.objects.Objects.subcategory_class'>,\n",
       " <type 'object'>)"
      ]
     },
     "execution_count": 41,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "PAA.__class__.__mro__"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 42,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Category of unital power associative algebras over Rational Field"
      ]
     },
     "execution_count": 42,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "PAA.Unital()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Next, we want to give some extra methods for parents and elements our category. We do so by adding classes called `ParentMethods` and `ElementMethods` accordingly."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 43,
   "metadata": {},
   "outputs": [],
   "source": [
    "class PowerAssociativeAlgebras(Category_over_base_ring):\n",
    "    def super_categories(self):\n",
    "        return [MagmaticAlgebras(self.base_ring())]\n",
    "    \n",
    "    class ParentMethods:\n",
    "        def foo(self):\n",
    "            return self.an_element()\n",
    "    class ElementMethods:\n",
    "        def square(self):\n",
    "            return self * self"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 44,
   "metadata": {},
   "outputs": [],
   "source": [
    "class TestParent(Parent):\n",
    "    def __init__(self, R, cat):\n",
    "        Parent.__init__(self, R, category=cat)\n",
    "    def _an_element_(self):\n",
    "        return self.element_class(self, self.base_ring().an_element())\n",
    "    class Element(Element):\n",
    "        def __init__(self, parent, value):\n",
    "            self.value = value\n",
    "            Element.__init__(self, parent)\n",
    "        def _repr_(self):\n",
    "            return repr(self.value)\n",
    "        def _add_(self, other):\n",
    "            return type(self)(self.parent(), self.value + other.value)\n",
    "        def _sub_(self, other):\n",
    "            return type(self)(self.parent(), self.value - other.value)\n",
    "        def _mul_(self, other):\n",
    "            return type(self)(self.parent(), self.value * other.value)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 45,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "1/2"
      ]
     },
     "execution_count": 45,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "P = TestParent(QQ, PowerAssociativeAlgebras(QQ))\n",
    "x = P.an_element()\n",
    "x"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 46,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(<class '__main__.Element'>,\n",
       " <type 'sage.structure.element.Element'>,\n",
       " <type 'sage.structure.sage_object.SageObject'>,\n",
       " <type 'object'>)"
      ]
     },
     "execution_count": 46,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "P.Element.__mro__"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 47,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(<class '__main__.TestParent_with_category.element_class'>,\n",
       " <class '__main__.Element'>,\n",
       " <type 'sage.structure.element.Element'>,\n",
       " <type 'sage.structure.sage_object.SageObject'>,\n",
       " <class '__main__.PowerAssociativeAlgebras.element_class'>,\n",
       " <class 'sage.categories.magmatic_algebras.MagmaticAlgebras.element_class'>,\n",
       " <class 'sage.categories.distributive_magmas_and_additive_magmas.DistributiveMagmasAndAdditiveMagmas.AdditiveAssociative.AdditiveCommutative.AdditiveUnital.element_class'>,\n",
       " <class 'sage.categories.distributive_magmas_and_additive_magmas.DistributiveMagmasAndAdditiveMagmas.AdditiveAssociative.AdditiveCommutative.element_class'>,\n",
       " <class 'sage.categories.distributive_magmas_and_additive_magmas.DistributiveMagmasAndAdditiveMagmas.AdditiveAssociative.element_class'>,\n",
       " <class 'sage.categories.distributive_magmas_and_additive_magmas.DistributiveMagmasAndAdditiveMagmas.element_class'>,\n",
       " <class 'sage.categories.magmas_and_additive_magmas.MagmasAndAdditiveMagmas.element_class'>,\n",
       " <class 'sage.categories.magmas.Magmas.element_class'>,\n",
       " <class 'sage.categories.vector_spaces.VectorSpaces.element_class'>,\n",
       " <class 'sage.categories.modules.Modules.element_class'>,\n",
       " <class 'sage.categories.bimodules.Bimodules.element_class'>,\n",
       " <class 'sage.categories.right_modules.RightModules.element_class'>,\n",
       " <class 'sage.categories.left_modules.LeftModules.element_class'>,\n",
       " <class 'sage.categories.commutative_additive_groups.CommutativeAdditiveGroups.element_class'>,\n",
       " <class 'sage.categories.additive_groups.AdditiveGroups.element_class'>,\n",
       " <class 'sage.categories.additive_magmas.AdditiveMagmas.AdditiveUnital.AdditiveInverse.element_class'>,\n",
       " <class 'sage.categories.commutative_additive_monoids.CommutativeAdditiveMonoids.element_class'>,\n",
       " <class 'sage.categories.additive_monoids.AdditiveMonoids.element_class'>,\n",
       " <class 'sage.categories.additive_magmas.AdditiveMagmas.AdditiveUnital.element_class'>,\n",
       " <class 'sage.categories.commutative_additive_semigroups.CommutativeAdditiveSemigroups.element_class'>,\n",
       " <class 'sage.categories.additive_magmas.AdditiveMagmas.AdditiveCommutative.element_class'>,\n",
       " <class 'sage.categories.additive_semigroups.AdditiveSemigroups.element_class'>,\n",
       " <class 'sage.categories.additive_magmas.AdditiveMagmas.element_class'>,\n",
       " <class 'sage.categories.sets_cat.Sets.element_class'>,\n",
       " <class 'sage.categories.sets_with_partial_maps.SetsWithPartialMaps.element_class'>,\n",
       " <class 'sage.categories.objects.Objects.element_class'>,\n",
       " <type 'object'>)"
      ]
     },
     "execution_count": 47,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "P.element_class.__mro__"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 48,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "3/2"
      ]
     },
     "execution_count": 48,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "x * P(4) - x"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 49,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "1/2"
      ]
     },
     "execution_count": 49,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "P.foo()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 50,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "1/4"
      ]
     },
     "execution_count": 50,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "x.square()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Next, we add some axioms."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 54,
   "metadata": {},
   "outputs": [],
   "source": [
    "from sage.categories.category_with_axiom import CategoryWithAxiom_over_base_ring\n",
    "class PowerAssociativeAlgebras(Category_over_base_ring):\n",
    "    def super_categories(self):\n",
    "        return [MagmaticAlgebras(self.base_ring())]\n",
    "    \n",
    "    class ParentMethods:\n",
    "        def foo(self):\n",
    "            return self.an_element()\n",
    "    class ElementMethods:\n",
    "        def square(self):\n",
    "            return self * self\n",
    "        \n",
    "    class Commutative(CategoryWithAxiom_over_base_ring):\n",
    "        class ParentMethods:\n",
    "            def bar(self):\n",
    "                return self.an_element().square()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 55,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Category of commutative power associative algebras over Rational Field"
      ]
     },
     "execution_count": 55,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "PAAC = PowerAssociativeAlgebras(QQ).Commutative()\n",
    "PAAC"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 56,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[Category of commutative power associative algebras over Rational Field,\n",
       " Category of power associative algebras over Rational Field,\n",
       " Category of magmatic algebras over Rational Field,\n",
       " Category of additive commutative additive associative additive unital distributive magmas and additive magmas,\n",
       " Category of additive commutative additive associative distributive magmas and additive magmas,\n",
       " Category of additive associative distributive magmas and additive magmas,\n",
       " Category of distributive magmas and additive magmas,\n",
       " Category of magmas and additive magmas,\n",
       " Category of commutative magmas,\n",
       " Category of magmas,\n",
       " Category of vector spaces over Rational Field,\n",
       " Category of modules over Rational Field,\n",
       " Category of bimodules over Rational Field on the left and Rational Field on the right,\n",
       " Category of right modules over Rational Field,\n",
       " Category of left modules over Rational Field,\n",
       " Category of commutative additive groups,\n",
       " Category of additive groups,\n",
       " Category of additive inverse additive unital additive magmas,\n",
       " Category of commutative additive monoids,\n",
       " Category of additive monoids,\n",
       " Category of additive unital additive magmas,\n",
       " Category of commutative additive semigroups,\n",
       " Category of additive commutative additive magmas,\n",
       " Category of additive semigroups,\n",
       " Category of additive magmas,\n",
       " Category of sets,\n",
       " Category of sets with partial maps,\n",
       " Category of objects]"
      ]
     },
     "execution_count": 56,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "PAAC.all_super_categories()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 57,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "1/4"
      ]
     },
     "execution_count": 57,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "P = TestParent(QQ, PAAC)\n",
    "P.bar()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now let us suppose that a unital power associative algebra is a unital associative algebra (in parallel with Wedderburn's theorem) (this is not a true mathematical property, but just for the sake of example). We do implement that by adding an `AXIOM_extra_super_categories` method to give the extra data."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 60,
   "metadata": {},
   "outputs": [],
   "source": [
    "class PowerAssociativeAlgebras(Category_over_base_ring):\n",
    "    def super_categories(self):\n",
    "        return [MagmaticAlgebras(self.base_ring())]\n",
    "    \n",
    "    class ParentMethods:\n",
    "        def foo(self):\n",
    "            return self.an_element()\n",
    "    class ElementMethods:\n",
    "        def square(self):\n",
    "            return self * self\n",
    "\n",
    "    class Commutative(CategoryWithAxiom_over_base_ring):\n",
    "        class ParentMethods:\n",
    "            def bar(self):\n",
    "                return self.an_element().square()\n",
    "    def Unital_extra_super_categories(self):\n",
    "        return (MagmaticAlgebras(self.base_ring()).Associative(),)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 61,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "frozenset({'AdditiveAssociative',\n",
       "           'AdditiveCommutative',\n",
       "           'AdditiveInverse',\n",
       "           'AdditiveUnital',\n",
       "           'Associative',\n",
       "           'Distributive',\n",
       "           'Unital'})"
      ]
     },
     "execution_count": 61,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "PAA = PowerAssociativeAlgebras(QQ)\n",
    "PAA.Unital().axioms()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 62,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "frozenset({'AdditiveAssociative',\n",
       "           'AdditiveCommutative',\n",
       "           'AdditiveInverse',\n",
       "           'AdditiveUnital',\n",
       "           'Associative',\n",
       "           'Commutative',\n",
       "           'Distributive',\n",
       "           'FiniteDimensional',\n",
       "           'Unital'})"
      ]
     },
     "execution_count": 62,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "PAA.FiniteDimensional().Commutative().Unital().axioms()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Last, we include the functorial constructions of tensor products and grading."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 63,
   "metadata": {},
   "outputs": [],
   "source": [
    "from sage.categories.graded_modules import GradedModulesCategory\n",
    "class GradedPowerAssociativeAlgebras(GradedModulesCategory):\n",
    "    class ParentMethods:\n",
    "        def baz(self):\n",
    "            x = self.foo()\n",
    "            return x * x * x\n",
    "\n",
    "class PowerAssociativeAlgebras(Category_over_base_ring):\n",
    "    def super_categories(self):\n",
    "        return [MagmaticAlgebras(self.base_ring())]\n",
    "    \n",
    "    class ParentMethods:\n",
    "        def foo(self):\n",
    "            return self.an_element()\n",
    "    class ElementMethods:\n",
    "        def square(self):\n",
    "            return self * self\n",
    "\n",
    "    class Commutative(CategoryWithAxiom_over_base_ring):\n",
    "        class ParentMethods:\n",
    "            def bar(self):\n",
    "                return self.an_element().square()\n",
    "    def Unital_extra_super_categories(self):\n",
    "        return (AssociativeAlgebras(self.base_ring()),)\n",
    "\n",
    "    Graded = GradedPowerAssociativeAlgebras"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 64,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "1/8"
      ]
     },
     "execution_count": 64,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "cat = PowerAssociativeAlgebras(QQ).Graded()\n",
    "P = TestParent(QQ, cat)\n",
    "P.baz()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 65,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[Category of power associative algebras over Rational Field,\n",
       " Category of graded modules over Rational Field]"
      ]
     },
     "execution_count": 65,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "cat.super_categories()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "For further reading, see: http://doc.sagemath.org/html/en/reference/categories/sage/categories/category_with_axiom.html"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "SageMath 8.3.beta7",
   "language": "",
   "name": "sagemath"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 2
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython2",
   "version": "2.7.15"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
