text: r"""
  Coalgebras
  """
  # ****************************************************************************
  #  Copyright (C) 2008 Teresa Gomez-Diaz (CNRS) <Teresa.Gomez-Diaz@univ-mlv.fr>
  #  Copyright (C) 2008-2009 Nicolas M. Thiery <nthiery at users.sf.net>
  #
  #  Distributed under the terms of the GNU General Public License (GPL)
  #                  https://www.gnu.org/licenses/
  # *****************************************************************************
  from __future__ import absolute_import
  
  from .category_types import Category_over_base_ring
  from sage.categories.all import Modules
  from sage.categories.category_with_axiom import CategoryWithAxiom_over_base_ring
  from sage.categories.tensor import TensorProductsCategory
  from sage.categories.dual import DualObjectsCategory
  from sage.categories.filtered_modules import FilteredModulesCategory
  from sage.categories.super_modules import SuperModulesCategory
  from sage.categories.realizations import RealizationsCategory
  from sage.categories.with_realizations import WithRealizationsCategory
  from sage.misc.abstract_method import abstract_method
  from sage.misc.cachefunc import cached_method
  from sage.misc.lazy_import import LazyImport
  
  
  class Coalgebras(Category_over_base_ring):
      """
      The category of coalgebras
  
      EXAMPLES::
  
          sage: Coalgebras(QQ)
          Category of coalgebras over Rational Field
          sage: Coalgebras(QQ).super_categories()
          [Category of vector spaces over Rational Field]
  
      TESTS::
  
          sage: TestSuite(Coalgebras(ZZ)).run()
      """
      def super_categories(self):
          """
          EXAMPLES::
  
              sage: Coalgebras(QQ).super_categories()
              [Category of vector spaces over Rational Field]
          """
          return [Modules(self.base_ring())]
  
      WithBasis = LazyImport('sage.categories.coalgebras_with_basis',  'CoalgebrasWithBasis')
      Graded = LazyImport('sage.categories.graded_coalgebras', 'GradedCoalgebras')
  
      class ParentMethods:
          #def __init_add__(self): # The analogue of initDomainAdd
          #    # Will declare the coproduct of self to the coercion mechanism when it exists
          #    pass
  
          @abstract_method
          def counit(self, x):
              """
              Return the counit of ``x``.
  
              Eventually, there will be a default implementation,
              delegating to the overloading mechanism and forcing the
              conversion back
  
              EXAMPLES::
  
                  sage: A = HopfAlgebrasWithBasis(QQ).example(); A
                  An example of Hopf algebra with basis:
                   the group algebra of the Dihedral group of order 6 as a permutation group over Rational Field
                  sage: [a,b] = A.algebra_generators()
                  sage: a, A.counit(a)
                  (B[(1,2,3)], 1)
                  sage: b, A.counit(b)
                  (B[(1,3)], 1)
  
              TODO: implement some tests of the axioms of coalgebras, bialgebras
              and Hopf algebras using the counit.
              """
  
  
          @abstract_method
          def coproduct(self, x):
              """
              Return the coproduct of ``x``.
  
              Eventually, there will be a default implementation,
              delegating to the overloading mechanism and forcing the
              conversion back
  
              EXAMPLES::
  
                  sage: A = HopfAlgebrasWithBasis(QQ).example(); A
                  An example of Hopf algebra with basis:
                   the group algebra of the Dihedral group of order 6 as a permutation group over Rational Field
                  sage: [a,b] = A.algebra_generators()
                  sage: a, A.coproduct(a)
                  (B[(1,2,3)], B[(1,2,3)] # B[(1,2,3)])
                  sage: b, A.coproduct(b)
                  (B[(1,3)], B[(1,3)] # B[(1,3)])
              """
              #return self.tensor_square()(overloaded_coproduct(x))
  
      class ElementMethods:
          def coproduct(self):
              """
              Return the coproduct of ``self``.
  
              EXAMPLES::
  
                  sage: A = HopfAlgebrasWithBasis(QQ).example(); A
                  An example of Hopf algebra with basis:
                   the group algebra of the Dihedral group of order 6 as a permutation group over Rational Field
                  sage: [a,b] = A.algebra_generators()
                  sage: a, a.coproduct()
                  (B[(1,2,3)], B[(1,2,3)] # B[(1,2,3)])
                  sage: b, b.coproduct()
                  (B[(1,3)], B[(1,3)] # B[(1,3)])
              """
              return self.parent().coproduct(self)
  
          def counit(self):
              """
              Return the counit of ``self``.
  
              EXAMPLES::
  
                  sage: A = HopfAlgebrasWithBasis(QQ).example(); A
                  An example of Hopf algebra with basis:
                   the group algebra of the Dihedral group of order 6 as a permutation group over Rational Field
                  sage: [a,b] = A.algebra_generators()
                  sage: a, a.counit()
                  (B[(1,2,3)], 1)
                  sage: b, b.counit()
                  (B[(1,3)], 1)
              """
              return self.parent().counit(self)
  
      class SubcategoryMethods:
          @cached_method
          def Cocommutative(self):
              r"""
              Return the full subcategory of the cocommutative objects
              of ``self``.
  
              A coalgebra `C` is said to be *cocommutative* if
  
              .. MATH::
  
                  \Delta(c) = \sum_{(c)} c_{(1)} \otimes c_{(2)}
                  = \sum_{(c)} c_{(2)} \otimes c_{(1)}
  
              in Sweedler's notation for all `c \in C`.
  
              EXAMPLES::
  
                  sage: C1 = Coalgebras(ZZ).Cocommutative().WithBasis(); C1
                  Category of cocommutative coalgebras with basis over Integer Ring
                  sage: C2 = Coalgebras(ZZ).WithBasis().Cocommutative()
                  sage: C1 is C2
                  True
                  sage: BialgebrasWithBasis(QQ).Cocommutative()
                  Category of cocommutative bialgebras with basis over Rational Field
  
              TESTS::
  
                  sage: TestSuite(Coalgebras(ZZ).Cocommutative()).run()
              """
              return self._with_axiom("Cocommutative")
  
      class Cocommutative(CategoryWithAxiom_over_base_ring):
          """
          Category of cocommutative coalgebras.
          """
  
      class TensorProducts(TensorProductsCategory):
          @cached_method
          def extra_super_categories(self):
              """
              EXAMPLES::
  
                  sage: Coalgebras(QQ).TensorProducts().extra_super_categories()
                  [Category of coalgebras over Rational Field]
                  sage: Coalgebras(QQ).TensorProducts().super_categories()
                  [Category of tensor products of vector spaces over Rational Field,
                   Category of coalgebras over Rational Field]
  
              Meaning: a tensor product of coalgebras is a coalgebra
              """
              return [self.base_category()]
  
          class ParentMethods:
              # TODO: provide this default implementation of one if one_basis is not implemented
              #def one(self):
              #    return tensor(module.one() for module in self.modules)
              pass
  
          class ElementMethods:
              pass
  
      class DualObjects(DualObjectsCategory):
  
          def extra_super_categories(self):
              r"""
              Return the dual category.
  
              EXAMPLES:
  
              The category of coalgebras over the Rational Field is dual
              to the category of algebras over the same field::
  
                  sage: C = Coalgebras(QQ)
                  sage: C.dual()
                  Category of duals of coalgebras over Rational Field
                  sage: C.dual().super_categories() # indirect doctest
                  [Category of algebras over Rational Field,
                   Category of duals of vector spaces over Rational Field]
  
              .. WARNING::
  
                  This is only correct in certain cases (finite dimension, ...).
                  See :trac:`15647`.
              """
              from sage.categories.algebras import Algebras
              return [Algebras(self.base_category().base_ring())]
  
      class Super(SuperModulesCategory):
          def extra_super_categories(self):
              """
              EXAMPLES::
  
                  sage: Coalgebras(ZZ).Super().extra_super_categories()
                  [Category of graded coalgebras over Integer Ring]
                  sage: Coalgebras(ZZ).Super().super_categories()
                  [Category of graded coalgebras over Integer Ring,
                   Category of super modules over Integer Ring]
  
              Compare this with the situation for bialgebras::
  
                  sage: Bialgebras(ZZ).Super().extra_super_categories()
                  []
                  sage: Bialgebras(ZZ).Super().super_categories()
                  [Category of super algebras over Integer Ring,
                   Category of super coalgebras over Integer Ring]
  
              The category of bialgebras does not occur in these results,
              since super bialgebras are not bialgebras.
              """
              return [self.base_category().Graded()]
  
          class SubcategoryMethods:
              @cached_method
              def Supercocommutative(self):
                  r"""
                  Return the full subcategory of the supercocommutative
                  objects of ``self``.
  
                  EXAMPLES::
  
                      sage: Coalgebras(ZZ).WithBasis().Super().Supercocommutative()
                      Category of supercocommutative super coalgebras with basis over Integer Ring
                      sage: BialgebrasWithBasis(QQ).Super().Supercocommutative()
                      Join of Category of super algebras with basis over Rational Field
                       and Category of super bialgebras over Rational Field
                       and Category of super coalgebras with basis over Rational Field
                       and Category of supercocommutative super coalgebras over Rational Field
  
                  TESTS::
  
                      sage: TestSuite(HopfAlgebras(ZZ).Super().Supercocommutative()).run()
                  """
                  return self._with_axiom("Supercocommutative")
  
          class Supercocommutative(CategoryWithAxiom_over_base_ring):
              """
              Category of supercocommutative coalgebras.
              """
  
      class Filtered(FilteredModulesCategory):
          """
          Category of filtered coalgebras.
          """
  
      class WithRealizations(WithRealizationsCategory):
  
          class ParentMethods:
  
              def coproduct(self, x):
                  r"""
                  Return the coproduct of ``x``.
  
                  EXAMPLES::
  
                      sage: N = NonCommutativeSymmetricFunctions(QQ)
                      sage: S = N.complete()
                      sage: N.coproduct.__module__
                      'sage.categories.coalgebras'
                      sage: N.coproduct(S[2])
                      S[] # S[2] + S[1] # S[1] + S[2] # S[]
                  """
                  return self.a_realization()(x).coproduct()
  
              def counit(self, x):
                  r"""
                  Return the counit of ``x``.
  
                  EXAMPLES::
  
                      sage: Sym = SymmetricFunctions(QQ)
                      sage: s = Sym.schur()
                      sage: f = s[2,1]
                      sage: f.counit.__module__
                      'sage.categories.coalgebras'
                      sage: f.counit()
                      0
  
                  ::
  
                      sage: N = NonCommutativeSymmetricFunctions(QQ)
                      sage: N.counit.__module__
                      'sage.categories.coalgebras'
                      sage: N.counit(N.one())
                      1
                      sage: x = N.an_element(); x
                      2*S[] + 2*S[1] + 3*S[1, 1]
                      sage: N.counit(x)
                      2
                  """
                  return self.a_realization()(x).counit()
  
      class Realizations(RealizationsCategory):
  
          class ParentMethods:
  
              def coproduct_by_coercion(self, x):
                  r"""
                  Return the coproduct by coercion if ``coproduct_by_basis``
                  is not implemented.
  
                  EXAMPLES::
  
                      sage: Sym = SymmetricFunctions(QQ)
                      sage: m = Sym.monomial()
                      sage: f = m[2,1]
                      sage: f.coproduct.__module__
                      'sage.categories.coalgebras'
                      sage: m.coproduct_on_basis
                      NotImplemented
                      sage: m.coproduct == m.coproduct_by_coercion
                      True
                      sage: f.coproduct()
                      m[] # m[2, 1] + m[1] # m[2] + m[2] # m[1] + m[2, 1] # m[]
  
                  ::
  
                      sage: N = NonCommutativeSymmetricFunctions(QQ)
                      sage: R = N.ribbon()
                      sage: R.coproduct_by_coercion.__module__
                      'sage.categories.coalgebras'
                      sage: R.coproduct_on_basis
                      NotImplemented
                      sage: R.coproduct == R.coproduct_by_coercion
                      True
                      sage: R[1].coproduct()
                      R[] # R[1] + R[1] # R[]
                  """
                  R = self.realization_of().a_realization()
                  return self.tensor_square()(R(x).coproduct())
  
              def counit_by_coercion(self, x):
                  r"""
                  Return the counit of ``x`` if ``counit_by_basis`` is
                  not implemented.
  
                  EXAMPLES::
  
                      sage: sp = SymmetricFunctions(QQ).sp()
                      sage: sp.an_element()
                      2*sp[] + 2*sp[1] + 3*sp[2]
                      sage: sp.counit(sp.an_element())
                      2
  
                      sage: o = SymmetricFunctions(QQ).o()
                      sage: o.an_element()
                      2*o[] + 2*o[1] + 3*o[2]
                      sage: o.counit(o.an_element())
                      -1
                  """
                  R = self.realization_of().a_realization()
                  return R(x).counit()
  
  