From b10efb9c13a7ef5313ca4598d1814a4a84420833 Mon Sep 17 00:00:00 2001 From: Sebastian Oehms Date: Wed, 20 May 2020 16:19:43 +0200 Subject: [PATCH] 29717: initial version --- build/pkgs/cubic_hecke_marin/SPKG.txt | 17 + build/pkgs/cubic_hecke_marin/checksums.ini | 5 + build/pkgs/cubic_hecke_marin/dependencies | 5 + .../cubic_hecke_marin/package-version.txt | 1 + build/pkgs/cubic_hecke_marin/spkg-install.in | 21 + build/pkgs/cubic_hecke_marin/spkg-install.py | 17 + build/pkgs/cubic_hecke_marin/type | 1 + .../algebras/cubic_hecke_algebra.rst | 10 + src/doc/en/reference/algebras/index.rst | 1 + src/doc/en/reference/references/index.rst | 15 + src/sage/algebras/catalog.py | 3 + .../base_rings_of_definition/__init__.py | 0 .../cubic_hecke_base_ring.py | 1231 +++++++ .../hecke_algebras/cubic_hecke_algebra.py | 3273 +++++++++++++++++ .../matrix_representations/__init__.py | 0 .../cubic_hecke_matrix_rep.py | 994 +++++ src/sage/databases/cubic_hecke_db.py | 1167 ++++++ 17 files changed, 6761 insertions(+) create mode 100644 build/pkgs/cubic_hecke_marin/SPKG.txt create mode 100644 build/pkgs/cubic_hecke_marin/checksums.ini create mode 100644 build/pkgs/cubic_hecke_marin/dependencies create mode 100644 build/pkgs/cubic_hecke_marin/package-version.txt create mode 100644 build/pkgs/cubic_hecke_marin/spkg-install.in create mode 100644 build/pkgs/cubic_hecke_marin/spkg-install.py create mode 100644 build/pkgs/cubic_hecke_marin/type create mode 100644 src/doc/en/reference/algebras/cubic_hecke_algebra.rst create mode 100644 src/sage/algebras/hecke_algebras/base_rings_of_definition/__init__.py create mode 100644 src/sage/algebras/hecke_algebras/base_rings_of_definition/cubic_hecke_base_ring.py create mode 100644 src/sage/algebras/hecke_algebras/cubic_hecke_algebra.py create mode 100644 src/sage/algebras/hecke_algebras/matrix_representations/__init__.py create mode 100644 src/sage/algebras/hecke_algebras/matrix_representations/cubic_hecke_matrix_rep.py create mode 100644 src/sage/databases/cubic_hecke_db.py diff --git a/build/pkgs/cubic_hecke_marin/SPKG.txt b/build/pkgs/cubic_hecke_marin/SPKG.txt new file mode 100644 index 00000000000..bbfeae7f9d7 --- /dev/null +++ b/build/pkgs/cubic_hecke_marin/SPKG.txt @@ -0,0 +1,17 @@ += Cubic Hecke Algebra Database = + +== Description == + +Iwan Marin's basis and matrix representations for the cubic Hecke algebra on 4 strands +as given on 'http://www.lamfa.u-picardie.fr/marin/softs/H4 + +== Dependencies == + + * Sage library + +== Changelog == + +=== cubic_hecke_marin-20200513.tar.bz2 (Sebastian Oehms, 13 May 2020) === + + * #?????: Initial version + diff --git a/build/pkgs/cubic_hecke_marin/checksums.ini b/build/pkgs/cubic_hecke_marin/checksums.ini new file mode 100644 index 00000000000..299e4ddd97a --- /dev/null +++ b/build/pkgs/cubic_hecke_marin/checksums.ini @@ -0,0 +1,5 @@ +tarball=cubic_hecke_marin-20200513.tar.bz2 +sha1=0afb0716b224b66fdd67b9b6e75b911030d15e1c +md5=3ee0a0a4fc5a7739ad9932391d2d10b5 +cksum=398008749 +upstream_url=https://trac.sagemath.org/attachment/ticket/29717/cubic_hecke_marin-20200513.tar.bz2 diff --git a/build/pkgs/cubic_hecke_marin/dependencies b/build/pkgs/cubic_hecke_marin/dependencies new file mode 100644 index 00000000000..c1b713883fe --- /dev/null +++ b/build/pkgs/cubic_hecke_marin/dependencies @@ -0,0 +1,5 @@ +| $(SAGERUNTIME) + +---------- +All lines of this file are ignored except the first. +It is copied by SAGE_ROOT/build/make/install into SAGE_ROOT/build/make/Makefile. diff --git a/build/pkgs/cubic_hecke_marin/package-version.txt b/build/pkgs/cubic_hecke_marin/package-version.txt new file mode 100644 index 00000000000..aa5d21b148b --- /dev/null +++ b/build/pkgs/cubic_hecke_marin/package-version.txt @@ -0,0 +1 @@ +20200513 diff --git a/build/pkgs/cubic_hecke_marin/spkg-install.in b/build/pkgs/cubic_hecke_marin/spkg-install.in new file mode 100644 index 00000000000..0d3fba4325b --- /dev/null +++ b/build/pkgs/cubic_hecke_marin/spkg-install.in @@ -0,0 +1,21 @@ +INSTALL="yes" +TARGET="${SAGE_SHARE}/cubic_hecke_marin" +VERSION=`cat package-version.txt` +if [ -d $TARGET ] +then + diff package-version.txt $TARGET > /dev/null 2>&1 + if [ $? -eq 0 ] + then + INSTALL="no" + echo "Version $VERSION of cubic_hecke_marin already installed" + else + OLD_VERSION=`cat $TARGET/package-version.txt` + echo "Removing former version $OLD_VERSION of cubic_hecke_marin" + rm -rf $TARGET + fi +fi + +if [ "$INSTALL" = "yes" ] +then + exec sage-python23 spkg-install.py +fi diff --git a/build/pkgs/cubic_hecke_marin/spkg-install.py b/build/pkgs/cubic_hecke_marin/spkg-install.py new file mode 100644 index 00000000000..2109e57fb9b --- /dev/null +++ b/build/pkgs/cubic_hecke_marin/spkg-install.py @@ -0,0 +1,17 @@ +import os +from sage.all import save +from sage.env import SAGE_SHARE +from sage.misc.misc import sage_makedirs +from sage.databases.cubic_hecke_db import CubicHeckeDataBase + +install_root = os.path.join(SAGE_SHARE, 'cubic_hecke_marin') + +if __name__ == '__main__': + sage_makedirs(install_root) + print("Creating Iwan Marin's Cubic Hecke database.") + cha_db = CubicHeckeDataBase() + cha_db.create_static_db_marin_basis() + cha_db.create_static_db_marin_regular() + cha_db.create_static_db_marin_regular(right=True) + cha_db.create_static_db_marin_split() + os.system('cp package-version.txt %s' %install_root) diff --git a/build/pkgs/cubic_hecke_marin/type b/build/pkgs/cubic_hecke_marin/type new file mode 100644 index 00000000000..a6a7b9cd726 --- /dev/null +++ b/build/pkgs/cubic_hecke_marin/type @@ -0,0 +1 @@ +standard diff --git a/src/doc/en/reference/algebras/cubic_hecke_algebra.rst b/src/doc/en/reference/algebras/cubic_hecke_algebra.rst new file mode 100644 index 00000000000..c0dccab3dd1 --- /dev/null +++ b/src/doc/en/reference/algebras/cubic_hecke_algebra.rst @@ -0,0 +1,10 @@ +Cubic Hecke Algebras +==================== + +.. toctree:: + :maxdepth: 2 + + sage/algebras/hecke_algebras/cubic_hecke_algebra + sage/algebras/hecke_algebras/base_rings_of_definition/cubic_hecke_base_ring + sage/algebras/hecke_algebras/matrix_representations/cubic_hecke_matrix_rep + diff --git a/src/doc/en/reference/algebras/index.rst b/src/doc/en/reference/algebras/index.rst index 2a7c43950da..5168de1f119 100644 --- a/src/doc/en/reference/algebras/index.rst +++ b/src/doc/en/reference/algebras/index.rst @@ -77,6 +77,7 @@ Hecke algebras sage/algebras/iwahori_hecke_algebra sage/algebras/nil_coxeter_algebra sage/algebras/yokonuma_hecke_algebra + cubic_hecke_algebra Various associative algebras ---------------------------- diff --git a/src/doc/en/reference/references/index.rst b/src/doc/en/reference/references/index.rst index 8c5c36ff174..dd5b2a9af5d 100644 --- a/src/doc/en/reference/references/index.rst +++ b/src/doc/en/reference/references/index.rst @@ -1418,6 +1418,10 @@ REFERENCES: \J. Algebr. Comb. **39** (2014) pp. 17-51. :doi:`10.1007/s10801-013-0437-x`, :arxiv:`1108.1776`. +.. [CM2012] \M. Cabanes, I. Marin, *On ternary quotients of cubic Hecke + algebras*, Comm. Math. Phys. (2012), Volume 314, Issue 1, + pp 57-92. :doi:`10.1007/s00220-012-1519-7`, :arxiv:`1010.1465`. + .. [CMN2014] David Coudert, Dorian Mazauric, and Nicolas Nisse, *Experimental Evaluation of a Branch and Bound Algorithm for computing Pathwidth*. In Symposium on Experimental Algorithms (SEA), volume @@ -3742,6 +3746,14 @@ REFERENCES: .. [Mar2004] \S. Marcus, Quasiperiodic infinite words, Bull. Eur. Assoc. Theor. Comput. Sci. 82 (2004) 170-174. +.. [Mar2012] \I. Marin, *The cubic Hecke algebra on at most 5 strands*, + Journal of Pure and Applied Algebra 216 (2012) 2754-2782. + :doi:`10.1016/j.jpaa.2012.04.013`, :arxiv:`1110.6621`. + +.. [Mar2018] \I. Marin, *Maximal cubic quotient of the braid algebra*, + preprint, 2018. available at + http://www.lamfa.u-picardie.fr/marin/arts/GQ.pdf + .. [Mas1994] James L. Massey, *SAFER K-64: A byte-oriented block-ciphering algorithm*; in FSE’93, Volume 809 of LNCS, pages 1-17. @@ -4052,6 +4064,9 @@ REFERENCES: .. [MW2009] Meshulam and Wallach, "Homological connectivity of random `k`-dimensional complexes", preprint, math.CO/0609773. +.. [MW2012] Ivan Marin and Emmanuel Wagner, *A CUBIC DEFINING ALGEBRA FOR THE + LINKS-GOULD POLYNOMIAL* (:arxiv:`1203.5981v1` [mathGT] 27. Mar 2012) + .. _ref-N: **N** diff --git a/src/sage/algebras/catalog.py b/src/sage/algebras/catalog.py index e3824417e89..78ee670fa74 100644 --- a/src/sage/algebras/catalog.py +++ b/src/sage/algebras/catalog.py @@ -9,6 +9,8 @@ Let ```` indicate pressing the tab key. So begin by typing ``algebras.`` to the see the currently implemented named algebras. +- :class:`algebras.CubicHecke + ` - :class:`algebras.ArikiKoike ` - :class:`algebras.AskeyWilson ` @@ -94,6 +96,7 @@ lazy_import('sage.algebras.schur_algebra', 'SchurAlgebra', 'Schur') lazy_import('sage.algebras.commutative_dga', 'GradedCommutativeAlgebra', 'GradedCommutative') lazy_import('sage.algebras.hecke_algebras.ariki_koike_algebra', 'ArikiKoikeAlgebra', 'ArikiKoike') +lazy_import('sage.algebras.hecke_algebras.cubic_hecke_algebra', 'CubicHeckeAlgebra', 'CubicHecke') lazy_import('sage.algebras.rational_cherednik_algebra', 'RationalCherednikAlgebra', 'RationalCherednik') lazy_import('sage.algebras.yokonuma_hecke_algebra', 'YokonumaHeckeAlgebra', 'YokonumaHecke') lazy_import('sage.combinat.posets.incidence_algebras', 'IncidenceAlgebra', 'Incidence') diff --git a/src/sage/algebras/hecke_algebras/base_rings_of_definition/__init__.py b/src/sage/algebras/hecke_algebras/base_rings_of_definition/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/src/sage/algebras/hecke_algebras/base_rings_of_definition/cubic_hecke_base_ring.py b/src/sage/algebras/hecke_algebras/base_rings_of_definition/cubic_hecke_base_ring.py new file mode 100644 index 00000000000..a89f3f51b5b --- /dev/null +++ b/src/sage/algebras/hecke_algebras/base_rings_of_definition/cubic_hecke_base_ring.py @@ -0,0 +1,1231 @@ +# -*- coding: utf-8 -*- +r""" +Cubic Hecke Base Rings + +This module contains special classes of polynomial rings (:class:`CubicHeckeRingOfDefinition` and :class:`CubicHeckeExtensionRing`) +used in the context of cubic Hecke algebras (:class:`~sage.algebras.hecke_algebras.cubic_hecke_algebra.CubicHeckeAlgebra`). + +AUTHORS: + +- Sebastian Oehms May 2020: initial version +""" + + + +############################################################################## +# Copyright (C) 2020 Sebastian Oehms +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# (at your option) any later version. +# http://www.gnu.org/licenses/ +############################################################################## + + +from sage.structure.category_object import normalize_names +from sage.structure.unique_representation import UniqueRepresentation +from sage.structure.element import get_coercion_model +from sage.categories.action import Action +from sage.misc.misc import verbose +from sage.misc.functional import cyclotomic_polynomial +from sage.misc.cachefunc import cached_method +from sage.rings.integer_ring import ZZ +from sage.rings.polynomial.multi_polynomial_ring import MPolynomialRing_polydict +from sage.rings.polynomial.multi_polynomial_element import MPolynomial_polydict +from sage.rings.polynomial.laurent_polynomial_ring import LaurentPolynomialRing, LaurentPolynomialRing_mpair +from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing +from sage.algebras.splitting_algebra import solve_with_extension, SplittingAlgebra + + + + +# --------------------------------------------------------------------------------- +# --------------------------------------------------------------------------------- +# helper functions and classes +# --------------------------------------------------------------------------------- +# --------------------------------------------------------------------------------- + +# --------------------------------------------------------------------------------- +# local helper functions +# --------------------------------------------------------------------------------- +def register_ring_hom(ring_hom): + r""" + This function tries to register the given ring homomorphism as conversion map + + EXAMPLES:: + + sage: import sage.algebras.hecke_algebras.base_rings_of_definition.cubic_hecke_base_ring as chbr + sage: BR = chbr.CubicHeckeRingOfDefinition() + sage: BR.create_specialization([E(5), E(7), E(3)]) # indirect doctest + Universal Cyclotomic Field + sage: _.convert_map_from(BR) + Ring morphism: + From: Multivariate Polynomial Ring in u, v + over Univariate Laurent Polynomial Ring in w + over Integer Ring + To: Universal Cyclotomic Field + Defn: u |--> E(5) + v |--> E(7) + with map of base ring + """ + domain = ring_hom.domain() + codomain = ring_hom.codomain() + conversion_cached = codomain._is_conversion_cached(domain) + + if conversion_cached: + test_map = codomain.convert_map_from(domain) + try: + if test_map != ring_hom: + verbose('\nConversion:\n%s\n already exists and is different from:\n%s\n' %(test_map,ring_hom)) + except TypeError: + verbose('\n Conversion:\n%s\n already exists and is not comparable to:\n%s\n' %(test_map,ring_hom)) + else: + try: + codomain.register_conversion(ring_hom) + except ValueError: + verbose('\nthe map:\n%s\ncannot be registerd as conversion\n' %(ring_hom)) + + return + + +def preparse_mvp(string, mvp_indet): + r""" + Preparse a string produced via GAP3 interface and containing Jean Michel's ``MVP`` (multivariate polynomials) + such that it can be evaluated by ``sage_eval``. In particular missing multiplication signs are inserted. + Furthermore, exponentiation is replaced by a special function ``xpow`` which must be defined before the + function's result can be evaluated. + + INPUT: + + - ``string`` -- string produced via ``GAP3`` interface and containing Jean Michel's ``MVP`` (multivariate polynomials) + - ``mvp_indet`` -- list of strings containing the names of the ``MVP``-variables. + + + EXAMPLES:: + + sage: import sage.algebras.hecke_algebras.base_rings_of_definition.cubic_hecke_base_ring as chbr + sage: chbr.preparse_mvp('2+a^-2bc+a^-1b^-1c^2', ['a', 'b', 'c']) + '2+xpow(a,1)^-2*xpow(b,1)*xpow(c,1)+xpow(a,1)^-1*xpow(b,1)^-1*xpow(c,1)^2' + """ + + def erase_useless_whitespace(strg): + res = strg.strip() + if res.find(' ') < 0: + return res + pos = int(len(res)/2) # len(res) must be > 1 since it is stripped and contains whitespaces + + if res[pos] != ' ': + # find a pos near to that on a whitespace + left = res[:pos] + right = res[pos+1:] + pos = right.find(' ') + if pos >= 0: + # first whitespace position in the right part + pos += len(left) + 1 + else: + # last whitespace position in the left part + left_rev = list(left) + left_rev.reverse() + pos = len(left) - left_rev.index(' ') - 1 + + end_left = res[pos-1] + start_right = res[pos+1] + left = res[:pos] + right = res[pos+1:] + if end_left.isdigit() and start_right.isdigit(): + return erase_useless_whitespace(left) + ' ' + erase_useless_whitespace(right) + return erase_useless_whitespace(left) + erase_useless_whitespace(right) + + # ------------------------------------------------------------------------ + # first erase carriage returns and useless whitespaces + # ------------------------------------------------------------------------ + new_string = string.replace('\n', ' ') + new_string = erase_useless_whitespace(new_string) + + # ------------------------------------------------------------------------------ + # Because of exponentiation with fractions we need to obtain the indeterminates + # as functions having the exponent as argument + # ------------------------------------------------------------------------------ + for indet in mvp_indet: # first the critical cases (protecting them by upper for following change) + new_string = new_string.replace('%s^(' %(indet), 'xpow(%s,' %(indet.upper())) + + for indet in mvp_indet: # than remaining trivial cases + new_string = new_string.replace('%s' %(indet), 'xpow(%s,1)' %(indet)) + + for indet in mvp_indet: # rename protected items of the first change + new_string = new_string.replace(indet.upper(), indet) + + # ------------------------------------------------------------------------------ + # Now start to insert missing '*' signs taking a pseudonym '?' for it, first + # ------------------------------------------------------------------------------ + # Insert '*' left of 'xpow' + # ------------------------------------------------------------------------------ + new_string = new_string.replace('xpow', '?xpow' ) + + # ------------------------------------------------------------------------------ + # Insert '*' right of ')' + # ------------------------------------------------------------------------------ + new_string = new_string.replace(')', ')?' ) + + # ------------------------------------------------------------------------------ + # Insert '*' left of 'E' (starting a roots of unity or a functions ('ER') of + # roots of integers) + # ------------------------------------------------------------------------------ + new_string = new_string.replace('E', '?E' ) + + # ------------------------------------------------------------------------------ + # Insert '*' left and right of 'I' (root of -1) + # ------------------------------------------------------------------------------ + new_string = new_string.replace('I', '?I?' ) + + # ------------------------------------------------------------------------------ + # remove multiples + # ------------------------------------------------------------------------------ + while '??' in new_string: + new_string = new_string.replace('??', '?') + + # ------------------------------------------------------------------------------ + # remove impossible neighbouring + # ------------------------------------------------------------------------------ + new_string = new_string.replace('^?', '^') + new_string = new_string.replace('?^', '^') + new_string = new_string.replace('+?', '+') + new_string = new_string.replace('?+', '+') + new_string = new_string.replace('-?', '-') + new_string = new_string.replace('?-', '-') + new_string = new_string.replace('/?', '/') + new_string = new_string.replace('?/', '/') + new_string = new_string.replace('[?', '[') + new_string = new_string.replace('?]', ']') + new_string = new_string.replace('(?', '(') + new_string = new_string.replace('?)', ')') + new_string = new_string.replace('?,', ',') + new_string = new_string.replace(',?', ',') + if new_string.startswith('?'): + new_string = new_string[1:] + if new_string.endswith('?'): + new_string = new_string[:len(new_string)-1] + + # ------------------------------------------------------------------------------ + # replace pseudonym + # ------------------------------------------------------------------------------ + new_string = new_string.replace('?', '*') + return new_string + + + + + +# --------------------------------------------------------------------------------- +# class for the Galois Group action on the generic extension ring corresponding +# to the cubic equation +# --------------------------------------------------------------------------------- +class GaloisGroupAction(Action): + r""" + Action on a multivariate polynomial ring by permuting the generators. + + EXAMPLES:: + + sage: import sage.algebras.hecke_algebras.base_rings_of_definition.cubic_hecke_base_ring as chbr + sage: from operator import mul + sage: R. = ZZ[] + sage: G = SymmetricGroup(3) + sage: p = 5*x*y + 3*z**2 + sage: R._unset_coercions_used() + sage: R.register_action(chbr.GaloisGroupAction(G, R, op=mul)) + sage: s = G([2,3,1]) + sage: s*p + 3*x^2 + 5*y*z + """ + def _act_(self, perm, pol): + r""" + Application of the action + EXAMPLES:: + + sage: import sage.algebras.hecke_algebras.base_rings_of_definition.cubic_hecke_base_ring as chbr + sage: from operator import mul + sage: R. = QQ[] + sage: G = SymmetricGroup(2) + sage: A = chbr.GaloisGroupAction(G, R, op=mul) + sage: p = ~5*x*y**2 + 3*x**2 + sage: s = G([2,1]) + sage: A._act_(s, p) + 1/5*x^2*y + 3*y^2 + """ + if not self.is_left(): + perm, pol = pol, perm + pol_dict = {} + for key, value in pol.dict().items(): + newkey = [0]*len(key) + for pos in range(len(key)): + newkey[perm(pos+1)-1] = key[pos] + pol_dict[tuple(newkey)] = value + return self.domain()(pol_dict) + + + + + + + + + + + +####################################################################################################################### +# EXTENSION RING +####################################################################################################################### + +# ------------------------------------------------------------------------------------------------------------------ +# Definition of the generic extension ring for the cubic Hecke algebra as Laurent polynomial ring in 3 indeterminates +# over the cyclotomic field of a third root of unity +# This is the most general ring over which the cubic Hecke algebra is semi-simple +# In opposite to the generic base ring class, this class does not inherits from UniqueRepresentation +# since _test_pickling fails +# -------------------------------------------------------------------------------------------------------- +class CubicHeckeExtensionRing(LaurentPolynomialRing_mpair): + r""" + This class implements the generic splitting algebra for the irreducible representations of the cubic Hecke algebra. + + This ring must contain three invertible indeterminats (representing the roots of the cubic equation) + together with a third root of unity (needed for the 18-dimensional irreducibles of the cubic Hecke algebra + on 4 strands). + + Therefore this ring is constructed as a multivariate Laurent polynomial ring in three indeterminates over a + polynomial quotient ring over the integers with respect to the minimal polynomial of a third root of unity. + + The polynomial quotient ring is constructed as instance of :class:`SplittingAlgebra`. The name of the third + root of unity is fixed to be ``e3``. + + INPUT: + + - ``names`` -- string containing the names of the indeterminates separated by ',' or a triple of strings each of + which is the name of one of the three indeterminates + - ``order`` -- string (optional, default='degrevlex') transferred to the corresponding input of + LaurentPolynomialRing_mpair + - ``ring_of_definition`` -- instance of CubicHeckeRingOfDefinition (optional, default=None) to specify the generic + cubic Hecke base ring over which self may be realized as splitting ring via the as_splitting_algebra method + + EXAMPLES:: + + sage: import sage.algebras.hecke_algebras.base_rings_of_definition.cubic_hecke_base_ring as chbr + sage: chbr.CubicHeckeExtensionRing('a, b, c') + Multivariate Laurent Polynomial Ring in a, b, c + over Splitting Algebra of x^2 + x + 1 + with roots [e3, -e3 - 1] + over Integer Ring + sage: _.an_element() + b^2*c^-1 + e3*a + """ + + + def __init__(self, names, order='degrevlex', ring_of_definition=None, third_unity_root_name='e3'): + r""" + Python constructor. + + TESTS:: + + sage: import sage.algebras.hecke_algebras.base_rings_of_definition.cubic_hecke_base_ring as chbr + sage: ER = chbr.CubicHeckeExtensionRing('a, b, c') + sage: TestSuite(ER).run() + """ + + # --------------------------------------------------------------------------------- + # --------------------------------------------------------------------------------- + # Setting connection with generic base ring (if given) + # --------------------------------------------------------------------------------- + # --------------------------------------------------------------------------------- + self._ring_of_definition = None + self._splitting_algebra = None + + if ring_of_definition != None: + if not isinstance(ring_of_definition, CubicHeckeRingOfDefinition): + raise TypeError( "generic base ring must be an instance of CubicHeckeRingOfDefinition") + self._ring_of_definition = ring_of_definition + + # --------------------------------------------------------------------------------- + # --------------------------------------------------------------------------------- + # defining the base ring + # note that we can't use ZZ.extension since it isn't possible to define + # homomorphisms from orders in number fields, yet + # --------------------------------------------------------------------------------- + # --------------------------------------------------------------------------------- + base_ring = SplittingAlgebra(cyclotomic_polynomial(3), [third_unity_root_name]) + + # --------------------------------------------------------------------------------- + # --------------------------------------------------------------------------------- + # defining the ring itself + # --------------------------------------------------------------------------------- + # --------------------------------------------------------------------------------- + self._names = normalize_names(3, names) + self._order = order + + pol_ring = PolynomialRing(base_ring, names=self._names, order=self._order, implementation=None) + LaurentPolynomialRing_mpair.__init__(self, pol_ring) + + # --------------------------------------------------------------------------------- + # --------------------------------------------------------------------------------- + # setting Galois group action + # --------------------------------------------------------------------------------- + # --------------------------------------------------------------------------------- + from sage.groups.perm_gps.permgroup_named import SymmetricGroup + from operator import mul + self._galois_group = SymmetricGroup(3) + galois_group_action = GaloisGroupAction(self._galois_group, self, op=mul) + self._unset_coercions_used() + self.register_action(galois_group_action) + + # --------------------------------------------------------------------------------- + # Init of data used on demand + # --------------------------------------------------------------------------------- + self._mirror = None + + return + + + + ####################################################################################################################### + # --------------------------------------------------------------------------------------------------------------------- + # overloaded inherited methods + # --------------------------------------------------------------------------------------------------------------------- + ####################################################################################################################### + + + def __reduce__(self): + r""" + Used in pickling. + + TESTS:: + + sage: import sage.algebras.hecke_algebras.base_rings_of_definition.cubic_hecke_base_ring as chbr + sage: ER = chbr.CubicHeckeExtensionRing('a, b, c') + sage: loads(dumps(ER)) == ER + True + """ + return CubicHeckeExtensionRing, (self._names, self._order, self._ring_of_definition) + + def _element_constructor_(self, x, mon=None): + r""" + Inherited element constructor overloaded to allow construction from + GAP3 Mvp exressions. + + EXAMPLES:: + + sage: CHA3 = algebras.CubicHecke(3) # optional gap3 + sage: GER = CHA3.extension_ring(generic=True) # optional gap3 + sage: sch7 = CHA3.chevie().SchurElements()[7] # optional gap3 + sage: GER(sch7) # optional gap3 + a*b*c^-2 + a^2*b^-1*c^-1 + a^-1*b^2*c^-1 + 2 + a*b^-2*c + a^-2*b*c + a^-1*b^-1*c^2 + sage: rep4_gap3 = CHA3.chevie().Representations(4) # optional gap3 + sage: matrix(GER, rep4_gap3[1]) # optional gap3 + [ b 0] + [-b c] + """ + from sage.interfaces.gap3 import GAP3Element + if isinstance(x, GAP3Element): + return self._convert_from_gap3_mvp(x) + return super(CubicHeckeExtensionRing, self)._element_constructor_(x, mon=mon) + + + def hom(self, im_gens, codomain=None, check=True, base_map=None): + r""" + Custom version overloading the corresponding method of class :class:`~sage.structure.parent_gens.ParentWithGens` + because of special effort with respect to the third root of unity. + + INPUT: according to the class :class:`~sage.structure.parent_gens.ParentWithGens`. For more information type ``ParentWithGens.hom?`` + + OUTPUT: according to the :class:`~sage.structure.parent_gens.ParentWithGens`. + + EXAMPLES:: + + sage: import sage.algebras.hecke_algebras.base_rings_of_definition.cubic_hecke_base_ring as chbr + sage: ER = chbr.CubicHeckeExtensionRing('a, b, c') + sage: UCF = UniversalCyclotomicField() + sage: map = ER.hom((UCF.gen(3),) + (UCF(3),UCF(4),UCF(5))) + sage: ER.an_element() + b^2*c^-1 + e3*a + sage: map(_) + -1/5*E(3) - 16/5*E(3)^2 + """ + + if not isinstance(im_gens, (list,tuple)): + im_gens = [im_gens] + + if len(im_gens) == 4: + e3, ia, ib, ic = im_gens + hom_cycl_gen = self.base_ring().hom([e3], codomain=e3.parent(), check=check, base_map=base_map) + verbose( "hom_cycl_gen %s" %(hom_cycl_gen)) + return super(CubicHeckeExtensionRing, self).hom([ia, ib, ic], codomain=codomain, check=check, base_map=hom_cycl_gen) + else: + if base_map is None: + raise ValueError("number of images must be four (inculding a third root of unity at first position) or a base_map (on %s) must be given" %self.base_ring()) + return super(CubicHeckeExtensionRing, self).hom([ia, ib, ic], codomain=codomain, check=check, base_map=base_map) + + def _an_element_(self): + r""" + Overwriting the original method to obtain an more interesting element for ``TestSuite``. + + EXAMPLES:: + + sage: import sage.algebras.hecke_algebras.base_rings_of_definition.cubic_hecke_base_ring as chbr + sage: ER = chbr.CubicHeckeExtensionRing('x, y, z') + sage: ER.an_element() # indirect doctest + y^2*z^-1 + e3*x + """ + + a, b, c = self.gens() + e3 = self.cyclotomic_generator() + return b**2/c+a*e3 + + + + ####################################################################################################################### + # --------------------------------------------------------------------------------------------------------------------- + # local methods + # --------------------------------------------------------------------------------------------------------------------- + ####################################################################################################################### + + + # ------------------------------------------------------------------------------- + # helper for element construction + # ------------------------------------------------------------------------------- + def _convert_from_gap3_mvp(self, mvp_expression): + r""" + Convert a string produced via GAP3 interface and containing Jean Michel's ``MVP`` (multivariate polynomials) + to an element of ``self``. + + INPUT: + + - ``string`` -- string produced via GAP3 interface and containing Jean Michel's ``MVP`` (multivariate polynomials) + + OUTPUT: + + An instance of the element class of ``self``. + + EXAMPLES:: + + sage: import sage.algebras.hecke_algebras.base_rings_of_definition.cubic_hecke_base_ring as chbr + sage: ER = chbr.CubicHeckeExtensionRing('a, b, c') + sage: ER._convert_from_gap3_mvp('2+a^-2bc+a^-1b^-1c^2+a^-1b^2c^-1+ab^-2c') + a^-1*b^2*c^-1 + 2 + a*b^-2*c + a^-2*b*c + a^-1*b^-1*c^2 + """ + E3 = self.cyclotomic_generator() + + def xpow(indet, exp): + r""" + Realizing power. + """ + return indet**exp + + a, b, c = self.gens() + na, nb, nc = var_names = self.variable_names() + lc={na:a, nb:b, nc:c, 'E3':E3} + lc['xpow'] = xpow + + sage_expression = preparse_mvp('%s' %(mvp_expression), var_names) + + from sage.misc.sage_eval import sage_eval + return sage_eval(sage_expression, locals=lc) + + + ####################################################################################################################### + # --------------------------------------------------------------------------------------------------------------------- + # global methods + # --------------------------------------------------------------------------------------------------------------------- + ####################################################################################################################### + + def cyclotomic_generator(self): + r""" + Return the third root of unity as generator of the base ring of ``self``. + + EXAMPLES:: + + sage: import sage.algebras.hecke_algebras.base_rings_of_definition.cubic_hecke_base_ring as chbr + sage: ER = chbr.CubicHeckeExtensionRing('a, b, c') + sage: ER.cyclotomic_generator() + e3 + sage: _**3 == 1 + True + """ + return self(self.base_ring().gen()) + + + + def cubic_equation_galois_group(self): + r""" + Return the Galois group of the cubic equation, which is the permutation group on the three generators + together with its action on ``self``. + + EXAMPLES:: + + sage: import sage.algebras.hecke_algebras.base_rings_of_definition.cubic_hecke_base_ring as chbr + sage: ER = chbr.CubicHeckeExtensionRing('a, b, c') + sage: G = ER.cubic_equation_galois_group() + sage: t = ER.an_element() + sage: [(g ,g*t) for g in G] + [((), b^2*c^-1 + e3*a), + ((1,3,2), a^2*b^-1 + e3*c), + ((1,2,3), e3*b + a^-1*c^2), + ((2,3), e3*a + b^-1*c^2), + ((1,3), a^-1*b^2 + e3*c), + ((1,2), a^2*c^-1 + e3*b)] + """ + + return self._galois_group + + + def mirror_involution(self): + r""" + Return the involution of ``self`` corresponding to the involution of the cubic Hecke algebra + (with the same name). This means that it maps the generators of ``self`` to their inverses. + + .. NOTE:: + + The mirror involution of the braid group does not factor through the cubic hecke algebra over its + base ring, but it does if it is considered as `\ZZ`-algebra. The base ring elements are transformed by + this automorphism. + + OUTPUT: + + The involution as automorphism of ``self``. + + EXAMPLES:: + + sage: import sage.algebras.hecke_algebras.base_rings_of_definition.cubic_hecke_base_ring as chbr + sage: ER = chbr.CubicHeckeExtensionRing('p, q, r') + sage: ER.mirror_involution() + Ring endomorphism of Multivariate Laurent Polynomial Ring in p, q, r + over Splitting Algebra of x^2 + x + 1 + with roots [e3, -e3 - 1] + over Integer Ring + Defn: p |--> p^-1 + q |--> q^-1 + r |--> r^-1 + with map of base ring + sage: _(ER.an_element()) + e3*p^-1 + q^-2*r + """ + if self._mirror == None: + a, b, c = self.gens() + e3 = self.base_ring().gen() + self._mirror = self.hom([e3, ~a, ~b, ~c]) + + return self._mirror + + + + + def create_specialization(self, im_cubic_equation_roots, var='T', third_unity_root_name='E3'): + r""" + Return an appropriate Ring containing the elements from the list ``im_cubic_equation_roots`` + defining a conversion map from self mapping the cubic equation roots of ``self`` to + ``im_cubic_equation_roots``. + + INPUT: + + - ``im_cubic_equation_roots`` -- list or tuple of three ring elements such that there exists + a ring homomorphism from the corresponding elements of ``self`` to them + + OUTPUT: + + A common parent containing the elements of ``im_cubic_equation_roots`` together with their inverses. + + EXAMPLES:: + + sage: import sage.algebras.hecke_algebras.base_rings_of_definition.cubic_hecke_base_ring as chbr + sage: ER = chbr.CubicHeckeExtensionRing('a, b, c') + sage: t = ER.an_element(); t + b^2*c^-1 + e3*a + sage: Sp1 = ER.create_specialization([E(5), E(7), E(3)]); Sp1 + Universal Cyclotomic Field + sage: Sp1(t) + -E(105)^11 - E(105)^16 - E(105)^26 - E(105)^37 - E(105)^41 + - E(105)^58 - E(105)^71 - E(105)^79 - E(105)^86 - E(105)^101 + + sage: Z3 = CyclotomicField(3); E3=Z3.gen() + sage: Sp2 = ER.create_specialization([E3, E3**2, Z3(1)]) + sage: Sp2(t) + -1 + + sage: Sp3 = ER.create_specialization([5, 7, 11]) + sage: Sp3(t) + 5*E3 + 49/11 + """ + # --------------------------------------------------------------------------------- + # interpreting user given cubic equation roots and define the corresponding + # specialized extension ring + # --------------------------------------------------------------------------------- + + if type(im_cubic_equation_roots) == tuple: + im_cubic_equation_roots = list(im_cubic_equation_roots) + + if type(im_cubic_equation_roots) != list: + raise TypeError( "cubic_equation_roots must be a list of three elements" ) + + if len(im_cubic_equation_roots) != 3: + raise ValueError( "there must be exactly three cubic_equation_roots" ) + + image_ring = get_coercion_model().common_parent(*(im_cubic_equation_roots)) + + # --------------------------------------------------------------------------------------------------------- + # make sure that all given cubic equation roots and their inverses belongs to image_ring + # --------------------------------------------------------------------------------------------------------- + try: + image_ring = image_ring.localization(tuple(im_cubic_equation_roots)) + except ValueError: + pass + + im_cubic_equation_roots = [image_ring(root) for root in im_cubic_equation_roots] + verbose("common parent of roots and inverses: %s" %(image_ring)) + + image_ring_base = image_ring.base_ring() + image_ring_map = None + + verbose("first choice: image_ring %s, image_ring_base %s" %(image_ring, image_ring_base)) + + # --------------------------------------------------------------------------------------------------------- + # make sure that a third root of unity belongs to image_ring + # --------------------------------------------------------------------------------------------------------- + + E3 = None + cp3 = cyclotomic_polynomial(3, var=var).change_ring(image_ring) + cyclotomic_roots = solve_with_extension(cp3, [third_unity_root_name], var=var, flatten=True, warning=False) + + if len(cyclotomic_roots) > 0: + E3 = cyclotomic_roots[0] + verbose("thrird root of unity %s found in %s" %(E3, E3.parent())) + + if E3 == None: + raise RuntimeError( "cannot find a ring containing a third root of unity for the this choice of cubic roots!" ) + + hom_gens = [E3] + im_cubic_equation_roots + verbose("hom_gens %s" %(hom_gens)) + + image_ring = get_coercion_model().common_parent(*(hom_gens)) + verbose("common parent of roots and third root: %s" %(image_ring)) + + hom_gens = [image_ring(gen) for gen in hom_gens] + + image_ring_base = image_ring.base_ring() + + verbose("second choice: image_ring %s, image_ring_base %s" %(image_ring, image_ring_base)) + + try: + image_ring_map = self.hom(hom_gens, codomain=image_ring) + except (ValueError, NotImplementedError): + image_ring_map = self.hom(hom_gens, codomain=image_ring, check=False) + verbose('check failed for embedding as ring morphism') + + verbose("specializing map defined %s" %(image_ring_map)) + + register_ring_hom(image_ring_map) + return image_ring + + + + def as_splitting_algebra(self): + r""" + Return ``self`` as instance of class :class:`SplittingAlgebra` that is as an + extension ring of the corresponding cubic Hecke algebra base ring + (``self._ring_of_definition``, an instance of class + :class:`CubicHeckeRingOfDefinition`) splitting its cubic equation into + linear factors, such that the roots are images of the generators + of ``self``. + + EXAMPLES:: + + sage: import sage.algebras.hecke_algebras.base_rings_of_definition.cubic_hecke_base_ring as chbr + sage: GBR = chbr.CubicHeckeRingOfDefinition() + sage: GER = GBR.extension_ring() + sage: ER = GER.as_splitting_algebra(); ER + Splitting Algebra of T^2 + T + 1 with roots [E3, -E3 - 1] + over Splitting Algebra of h^3 - u*h^2 + v*h - w + with roots [a, b, -b - a + u] + over Multivariate Polynomial Ring in u, v + over Univariate Laurent Polynomial Ring in w over Integer Ring + sage: ER(GER.an_element()) + a*E3 + (((-w^-1)*u)*a^2 + ((w^-1)*u^2 + (-w^-1)*v)*a)*b + a - u + sage: ER(GBR.an_element()) + (w^-1)*u^2 + v + """ + + if self._splitting_algebra != None: + verbose("End (short)") + return self._splitting_algebra + + if self._ring_of_definition == None: + verbose("constructing generic base ring") + self._ring_of_definition = CubicHeckeRingOfDefinition() + + BR = self._ring_of_definition + root_names = list(self._names) + root_names.pop() # Z not needed + + FSR = SplittingAlgebra(BR.cubic_equation(), root_names, warning=False) + splitting_roots = FSR.splitting_roots() + verbose("splitting roots %s" %(splitting_roots)) + + A, B, C = splitting_roots + S = self.create_specialization([A, B, C]) + a, b, c = self.gens() + e3 = self.cyclotomic_generator() + map_back = S.hom([e3, b, a, a + b + c, a*b+a*c+b*c, a*b*c]) + self.register_coercion(map_back) + + self._splitting_algebra = S + + return self._splitting_algebra + + + + + + + + + +####################################################################################################################### +# Ring of Definition +####################################################################################################################### + + + + +# -------------------------------------------------------------------------------------------------------- +# Definition of the ring of definition for the cubic hecke algebra as polynomial ring in 2 indeterminates +# over univariate Laurent polynomial ring over the integers. +# This is the most general ring over which the cubic Hecke algebra may be defined. +# This class inherits from UniqueRepresentation since otherwise an error occurs when a second instance +# is declared. This error occurs in as_splitting_algebra of the associated extension ring. +# -------------------------------------------------------------------------------------------------------- +class CubicHeckeRingOfDefinition(MPolynomialRing_polydict, UniqueRepresentation): + r""" + This class implements the *ring of definition* of the cubic Hecke algebra. + + It contains one invertible indeterminate (representing the product of the roots + of the cubic equation) and two non invertible indeterminates. + + + INPUT: + + - ``names`` -- string containing the names of the indeterminates seperated by ',' + or a triple of strings each of which is the name of one of the three indeterminates + - ``order`` -- string (optional, default='degrevlex') transferred to the corresponding + input of LaurentPolynomialRing_mpair + + EXAMPLES:: + + sage: import sage.algebras.hecke_algebras.base_rings_of_definition.cubic_hecke_base_ring as chbr + sage: BR = chbr.CubicHeckeRingOfDefinition() + sage: u, v, w = BR.gens_over_ground() + sage: ele = 3*u*v-5*w**(-2) + sage: ER = BR.extension_ring() + sage: ER(ele) + 3*a^2*b + 3*a*b^2 + 3*a^2*c + 9*a*b*c + 3*b^2*c + + 3*a*c^2 + 3*b*c^2 + (-5)*a^-2*b^-2*c^-2 + sage: phi1 = BR.hom( [4,3,1] ) + sage: phi1(ele) + 31 + + sage: LL. = LaurentPolynomialRing(ZZ) + sage: phi2=BR.hom( [LL(4),LL(3),t] ) + sage: phi2(ele) + -5*t^-2 + 36 + + sage: BR.create_specialization( [E(5), E(7), E(3)] ) + Universal Cyclotomic Field + sage: _(ele) + -3*E(105) - 5*E(105)^2 - 5*E(105)^8 - 5*E(105)^11 - 5*E(105)^17 + - 5*E(105)^23 - 5*E(105)^26 - 5*E(105)^29 - 5*E(105)^32 - 5*E(105)^38 + - 5*E(105)^41 - 5*E(105)^44 - 5*E(105)^47 - 5*E(105)^53 - 5*E(105)^59 + - 5*E(105)^62 - 5*E(105)^68 - 8*E(105)^71 - 5*E(105)^74 - 5*E(105)^83 + - 5*E(105)^86 - 5*E(105)^89 - 5*E(105)^92 - 5*E(105)^101 - 5*E(105)^104 + + """ + + def __init__( self, names=('u', 'v', 'w'), order='degrevlex'): + r""" + Python constructor. + + TESTS:: + + sage: import sage.algebras.hecke_algebras.base_rings_of_definition.cubic_hecke_base_ring as chbr + sage: BR = chbr.CubicHeckeRingOfDefinition() + sage: TestSuite(BR).run() + """ + + # --------------------------------------------------------------------------------- + # --------------------------------------------------------------------------------- + # Saving class-globals + # --------------------------------------------------------------------------------- + # --------------------------------------------------------------------------------- + names = normalize_names(3, names) + self._order = order + self._all_names = names + self._invertible_name = names[2] + self._non_invertible_names = (names[0], names[1]) + + # --------------------------------------------------------------------------------- + # --------------------------------------------------------------------------------- + # base ring containing the invertible variable + # --------------------------------------------------------------------------------- + # --------------------------------------------------------------------------------- + self._base_ring = LaurentPolynomialRing(ZZ, self._invertible_name) + + + # --------------------------------------------------------------------------------- + # --------------------------------------------------------------------------------- + # Init of self + # --------------------------------------------------------------------------------- + # --------------------------------------------------------------------------------- + MPolynomialRing_polydict.__init__(self, self._base_ring, 2, self._non_invertible_names, order) + + # --------------------------------------------------------------------------------- + # Init of data used on demand + # --------------------------------------------------------------------------------- + self._mirror = None + + return + + # note: Element assignment is missing in MPolynomialRing_polydict. It activates the element_class method for self + Element = MPolynomial_polydict + + + + + + + + ####################################################################################################################### + # --------------------------------------------------------------------------------------------------------------------- + # overloaded inherited methods + # --------------------------------------------------------------------------------------------------------------------- + ####################################################################################################################### + + def __reduce__(self): + r""" + Used in pickling. + + EXAMPLES:: + + sage: import sage.algebras.hecke_algebras.base_rings_of_definition.cubic_hecke_base_ring as chbr + sage: BR = chbr.CubicHeckeRingOfDefinition() + sage: loads(dumps(BR)) == BR + True + """ + return CubicHeckeRingOfDefinition, (self._all_names, self._order) + + + def _defining_names(self): + r""" + This method is cached in the parent class. This causes trouble if a second instance of self is used for + another cubic Hecke algebra in the same session. To avoid this it is overloaded without ``cached_method`` + decorator. + + EXAMPLES:: + + sage: import sage.algebras.hecke_algebras.base_rings_of_definition.cubic_hecke_base_ring as chbr + sage: BR = chbr.CubicHeckeRingOfDefinition() + sage: BR._defining_names() + (u, v) + """ + return self.gens() + + + def __call__(self, x, check=True): + r""" + Overloaded to fix an inherited bug concerning ``_test_category``. + + EXAMPLES:: + + sage: import sage.algebras.hecke_algebras.base_rings_of_definition.cubic_hecke_base_ring as chbr + sage: BR = chbr.CubicHeckeRingOfDefinition() + sage: BR.an_element()._test_category() # indirect doctest + """ + result = MPolynomialRing_polydict.__call__(self, x, check=check) + return self.element_class( self, result.dict() ) + + + + def _an_element_(self): + r""" + Overwriting the original method to obtain an more interesting element for ``TestSuite``. + + EXAMPLES:: + + sage: import sage.algebras.hecke_algebras.base_rings_of_definition.cubic_hecke_base_ring as chbr + sage: BR = chbr.CubicHeckeRingOfDefinition() + sage: BR.an_element() # indirect doctest + (w^-1)*u^2 + v + """ + + u, v, w = self.gens_over_ground() + return u**2/w+v + + def hom(self, im_gens, codomain=None, check=True, base_map=None): + r""" + Custom version overloading the corresponding method of class :class:`~sage.structure.parent_gens.ParentWithGens` + because of special effort with respect to invertible third parameter. + + INPUT: according to the calss :class:`~sage.structure.parent_gens.ParentWithGens`. For more information type ``ParentWithGens.hom?`` + + OUTPUT: according to the :class:`ParentWithGens`. + + EXAMPLES:: + + sage: import sage.algebras.hecke_algebras.base_rings_of_definition.cubic_hecke_base_ring as chbr + sage: BR = chbr.CubicHeckeRingOfDefinition() + sage: R = ZZ.localization((5,)) + sage: im_gens = [R(z) for z in [3, 4, ~5]] + sage: map = BR.hom(im_gens) + sage: BR.an_element() + (w^-1)*u^2 + v + sage: map(_) + 49 + """ + + if not isinstance(im_gens, (list,tuple)): + im_gens = [im_gens] + + if len(im_gens) == 3: + iu, iv, iw = im_gens + hom_on_laur = self.base_ring().hom([iw], base_map=base_map) + return super(CubicHeckeRingOfDefinition, self).hom([iu, iv], codomain=codomain, check=check, base_map=hom_on_laur) + else: + if base_map is None: + raise ValueError("number of images must be three or a base_map (on %s) must be given" %self.base_ring()) + return super(CubicHeckeRingOfDefinition, self).hom([iu, iv], codomain=codomain, check=check, base_map=base_map) + + + + + ####################################################################################################################### + # --------------------------------------------------------------------------------------------------------------------- + # Local Methods + # --------------------------------------------------------------------------------------------------------------------- + ####################################################################################################################### + + + + + + + ####################################################################################################################### + # --------------------------------------------------------------------------------------------------------------------- + # Global Methods + # --------------------------------------------------------------------------------------------------------------------- + ####################################################################################################################### + + def gens_over_ground(self): + r""" + Return the generators of self over the ground ring. These are the generators of self over the base ring (u, v) + together with the generator of the base ring over the ground ring (w). + + EXAMPLES:: + + sage: import sage.algebras.hecke_algebras.base_rings_of_definition.cubic_hecke_base_ring as chbr + sage: BR = chbr.CubicHeckeRingOfDefinition(names='A, B, C') + sage: BR.gens_over_ground() + [A, B, C] + + """ + gen_list = self.gens() + self.base_ring().gens() + return [ self(gen) for gen in gen_list ] + + + + def cubic_equation(self, var='h', as_coefficients=False): + r""" + Return the cubic equation over which the cubic Hecke algebra is defined. + + EXAMPLES:: + + sage: import sage.algebras.hecke_algebras.base_rings_of_definition.cubic_hecke_base_ring as chbr + sage: BR = chbr.CubicHeckeRingOfDefinition() + sage: BR.cubic_equation() + h^3 - u*h^2 + v*h - w + sage: BR.cubic_equation(var='t') + t^3 - u*t^2 + v*t - w + sage: BR.cubic_equation(as_coefficients=True) + [-w, v, -u, 1] + """ + u, v, w = self.gens_over_ground() + cf = [-w, v, -u, 1] + if as_coefficients == True: + return cf + P = PolynomialRing(self, var) + + return P(cf) + + + def mirror_involution(self): + r""" + Return the involution of ``self`` corresponding to the involution of the cubic Hecke algebra + (with the same name). This means that it maps the the last generator of ``self`` to its inverse + and both others to their product with the image of the former. + + From the cubic equation for a braid generator $\beta_i$: + + .. MATH:: + + \beta_i^3 - u \beta_i^2 + v\beta_i -w = 0 + + one deduces the following cubic equation for $\beta_i^{-1}$: + + .. MATH:: + + \beta_i^{-3} -\frac{v}{w} \beta_i^{-2} + \frac{u}{w}\beta_i^{-1} -\frac{1}{w} = 0 + + .. NOTE:: + + The mirror involution of the braid group does not factor through the cubic Hecke algebra over its + base ring, but it does if it is considered as $\ZZ$-algebra. The base ring elements are transformed by + this automorphism. + + OUTPUT: + + The involution as automorphism of ``self``. + + EXAMPLES:: + + sage: import sage.algebras.hecke_algebras.base_rings_of_definition.cubic_hecke_base_ring as chbr + sage: BR = chbr.CubicHeckeRingOfDefinition() + sage: BR.mirror_involution() + Ring endomorphism of Multivariate Polynomial Ring in u, v + over Univariate Laurent Polynomial Ring in w over Integer Ring + Defn: u |--> (w^-1)*v + v |--> (w^-1)*u + with map of base ring + sage: _(BR.an_element()) + (w^-1)*v^2 + (w^-1)*u + """ + + if self._mirror == None: + u, v, w = self.gens_over_ground() + self._mirror = self.hom([v/w, u/w, ~w]) + + return self._mirror + + + + def create_specialization( self, im_cubic_equation_parameters): + r""" + Return an appropriate Ring containing the elements from the list ``im_cubic_equation_parameters`` + having a conversion map from ``self`` mapping the cubic equation parameters of ``self`` to + ``im_cubic_equation_parameters``. + + INPUT: + + - ``im_cubic_equation_parameters`` -- list or tuple of three ring elements such that there exists + a ring homomorphism from the corresponding elements of ``self`` to them + + OUTPUT: + + a common parent containing the elements of ``im_cubic_equation_parameters`` together with an inverse + of the third element. + + EXAMPLES:: + + sage: import sage.algebras.hecke_algebras.base_rings_of_definition.cubic_hecke_base_ring as chbr + sage: BR = chbr.CubicHeckeRingOfDefinition() + sage: t = BR.an_element(); t + (w^-1)*u^2 + v + sage: Sp1 = BR.create_specialization([E(5), E(7), E(3)]); Sp1 + Universal Cyclotomic Field + sage: Sp1(t) + E(105) + E(105)^8 + E(105)^29 - E(105)^37 + E(105)^43 - E(105)^52 + E(105)^64 + - E(105)^67 + E(105)^71 - E(105)^82 + E(105)^92 - E(105)^97 + + sage: Z3 = CyclotomicField(3); E3=Z3.gen() + sage: Sp2 = BR.create_specialization([E3, E3**2, Z3(1)]); Sp2 + Cyclotomic Field of order 3 and degree 2 + sage: Sp2(t) + -2*zeta3 - 2 + + sage: Sp3 = BR.create_specialization([5, 7, 11]); Sp3 + Integer Ring localized at (11,) + sage: Sp3(t) + 102/11 + """ + # --------------------------------------------------------------------------------- + # --------------------------------------------------------------------------------- + # setting the base_ring according to the cubic_equation_parameters + # --------------------------------------------------------------------------------- + # --------------------------------------------------------------------------------- + if type(im_cubic_equation_parameters) == tuple: + im_cubic_equation_parameters = list(im_cubic_equation_parameters) + + if type(im_cubic_equation_parameters) != list: + raise TypeError( "cubic_equation_parameters must be a list of three elements" ) + + if len(im_cubic_equation_parameters) != 3: + raise ValueError( "there must be exactly three cubic_equation_parameters" ) + + image_ring = None + image_ring_map = None + u, v, w = im_cubic_equation_parameters + image_ring_base = w.parent() + + # --------------------------------------------------------------------------------------------------------- + # short exit on trivial invocation + # --------------------------------------------------------------------------------------------------------- + if image_ring_base is self and im_cubic_equation_parameters == self.gens_over_ground(): + return self + + image_ring = get_coercion_model().common_parent(*(im_cubic_equation_parameters)) + + # --------------------------------------------------------------------------------------------------------- + # make sure that the inverse of w belongs to image_ring + # --------------------------------------------------------------------------------------------------------- + try: + image_ring = image_ring.localization(w) + except ValueError: + pass + + im_cubic_equation_parameters = [image_ring(para) for para in im_cubic_equation_parameters] + + verbose("common parent of parameters and inverses: %s" %(image_ring)) + + try: + image_ring_map = self.hom(im_cubic_equation_parameters, codomain=image_ring) + except ValueError: + image_ring_map = self.hom(im_cubic_equation_parameters, codomain=image_ring, check=False) + verbose('Warning: check failed for embedding as ring morphism') + + register_ring_hom(image_ring_map) + + return image_ring + + + # -------------------------------------------------------------------------------------------------------- + # Definition of the generic extension ring for the cubic hecke algebra as Laurent polynomial ring in 3 + # indeterminates over cyclotomic field of order 3. The generic extension ring guarantees semisimplicity + # of the cubic Hecke algebra + # -------------------------------------------------------------------------------------------------------- + @cached_method + def extension_ring(self, names='a, b, c'): + r""" + Return the generic extension ring attached to ``self``. + + EXAMPLES:: + + sage: import sage.algebras.hecke_algebras.base_rings_of_definition.cubic_hecke_base_ring as chbr + sage: BR = chbr.CubicHeckeRingOfDefinition() + sage: BR.extension_ring() + Multivariate Laurent Polynomial Ring in a, b, c + over Splitting Algebra of x^2 + x + 1 + with roots [e3, -e3 - 1] + over Integer Ring + """ + ExtensionRing = CubicHeckeExtensionRing(names, ring_of_definition=self) + a, b, c = ExtensionRing.gens() + + # ---------------------------------------------------------------------------------------------- + # constructing a canonical embedding of the generic base ring into the extension ring + # ---------------------------------------------------------------------------------------------- + iu = a+b+c; iv = a*b+a*c+b*c; iw = a*b*c + self._embedding_into_extension_ring_ = self.hom([iu, iv, iw]) + ExtensionRing.register_conversion( self._embedding_into_extension_ring_ ) + + return ExtensionRing diff --git a/src/sage/algebras/hecke_algebras/cubic_hecke_algebra.py b/src/sage/algebras/hecke_algebras/cubic_hecke_algebra.py new file mode 100644 index 00000000000..234f358c53b --- /dev/null +++ b/src/sage/algebras/hecke_algebras/cubic_hecke_algebra.py @@ -0,0 +1,3273 @@ +# -*- coding: utf-8 -*- +r""" +Cubic Hecke Algebras + +This module is devoted to factors of the group algebra of the Artin braid groups, +such that the images $s_i$ of the braid generators satisfy a cubic equation: + +.. MATH:: + + s_i^3 = u s_i^2 - v s_i + w + +Here $u, v, w$ are elements in an arbitrary integral domain and $i$ is a positive +integer less than $n$, the number of the braid group's strands. By the analogue to the +*Iwahori Hecke algebras* (see :class:`~sage.algebras.iwahori_hecke_algebra.IwahoriHeckeAlgebra`), +in which the braid generators satisfy a quadratic relation these algebras have been called +*cubic Hecke algebras*. The relations inherited from the braid group are: + +.. MATH:: + + s_i s_{i+1} s_i = s_{i+1} s_i s_{i+1} \mbox{ where } 1\leq i < n-1 \mbox{ and } + s_i s_j = s_j s_i \mbox{ where } 1 \leq i < j - 1 < n - 1. + +The algebra epimorphism from the braid group algebra over the same base ring is realized +inside the element constructor of the present class, for example in the case of the 3 +strand cubic Hecke algebra:: + + sage: CHA3 = algebras.CubicHecke(3) + sage: BG3 = CHA3.braid_group() + sage: braid = BG3((1,2,-1,2,2,-1)); braid + c0*c1*c0^-1*c1^2*c0^-1 + sage: braid_image = CHA3(braid); braid_image + (-u*v+w)*c1^-1 + ((w^-1)*u^2+(-w^-1)*v)*c0*c1*c0 + ((-w^-1)*u^3+(w^-1)*u*v)*c0*c1 + + ((w^-1)*u^2*v+(-w^-1)*v^2)*c0*c1*c0^-1 + (-u^2)*c0^-1*c1 + + u*c1*c0^-1*c1 + u*v*c0*c1^-1*c0^-1 + +If the ring elements $u, v, w$ (which will be called the *cubic equation parameters* +in the sequel) are taken to be $u = v = 0, w = 1$ the cubic Hecke algebra specializes to the +group algebra of the *cubic braid group*, which is the factor group of the Artin braid +group under setting the generators order to be three. A sage-class to handle these groups +is attached and can be obtained by :meth:`CubicHeckeAlgebra.cubic_braid_group`. + +It is well known, that these algebras are free of finite rank as long as the number of braid +generators is less than six and infinite dimensional else wise. In the former (non trivial) +cases they are also known as *cyclotomic Hecke algebras* corresponding to the complex reflection +groups having Shepard-Todd number $4, 25$ and $32$. + +Since the *Broué, Malle, Rouquiere* conjecture has been proved in all these cases (for references +see [Mar2012]_) there exists a finite free basis of the cubic Hecke algebra which is in +bijection to the cubic braid group and compatible with the specialization to the cubic braid group +algebra as explained above. + +For the algebras corresponding to braid groups of less than five strands such a basis has been +calculated by Ivan Marin. This one is used here. In the case of 5 strands such a basis is not +available, right now. Instead the elements of the cubic braid group class themselves are used as +basis elements. This is also the case when the cubic braid group is infinite, even though it is +not known if these elements span all of the cubic Hecke algebra. + +Accordingly, be aware that the module embedding of the group algebra of the cubic braid groups +is known to be an isomorphism of free modules only in the cases of less than five strands. + +EXAMPLES: + +1. Consider the obstruction ``b`` of the *triple quadratic algebra* from section 2.6 of [Mar2018]_. +We verify that the third power of it is a scalar multiple of itself (explicitly ``2*w^2`` times the +*Schur element* of the three dimensional irreducible representation):: + + sage: CHA3 = algebras.CubicHecke(3) + sage: c1, c2 = CHA3.gens() + sage: b = c1^2*c2 - c2*c1^2 - c1*c2^2 + c2^2*c1; b + w*c1^-1*c0 + (-w)*c1*c0^-1 + (-w)*c0*c1^-1 + w*c0^-1*c1 + sage: b2 = b*b + sage: b3 = b2*b + sage: BR = CHA3.base_ring() + sage: ER = CHA3.extension_ring() + sage: u, v, w = BR.gens_over_ground() + sage: f = BR(b3.coefficients()[0]/w) + sage: try: + ....: sh = CHA3.schur_element(CHA3.irred_repr.W3_111) + ....: except NotImplementedError: # for the case GAP3 / CHEVIE not available + ....: sh = ER(f/(2*w^2)) + sage: ER(f/(2*w^2)) == sh + True + sage: b3 == f*b + True + +2. Defining the cubic Hecke algebra on 6 strands will need some seconds for initializing. But +than you can do calculations inside the infinite algebra as well:: + + sage: CHA6 = algebras.CubicHecke(6) # long time + sage: CHA6.inject_variables() # long time + Defining c0, c1, c2, c3, c4 + sage: s = c0*c1*c2*c3*c4; s # long time + c0*c1*c2*c3*c4 + sage: s^2 # long time + (c0*c1*c2*c3*c4)^2 + sage: t = CHA6.an_element()*c4; t # long time + (-w)*c0*c1^-1*c4 + v*c0*c2^-1*c4 + u*c2*c1*c4 + ((w^-1)*u-v)*c4 + +REFERENCES: + +- [Mar2012]_ +- [Mar2018]_ +- [CM2012]_ + +AUTHORS: + +- Sebastian Oehms May 2020: initial version +""" + + +############################################################################## +# Copyright (C) 2020 Sebastian Oehms +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# (at your option) any later version. +# http://www.gnu.org/licenses/ +############################################################################## + + +from warnings import warn + +from sage.combinat.free_module import CombinatorialFreeModule +from sage.misc.cachefunc import cached_method +from sage.misc.misc import verbose +from sage.groups.cubic_braid import CubicBraidGroup +from sage.rings.integer_ring import ZZ +from sage.algebras.splitting_algebra import solve_with_extension +from sage.modules.free_module_element import vector +from sage.matrix.matrix_space import MatrixSpace +from .base_rings_of_definition.cubic_hecke_base_ring import CubicHeckeRingOfDefinition +from .matrix_representations.cubic_hecke_matrix_rep import CubicHeckeMatrixSpace, AbsIrreducibeRep, RepresentationType + + + + +############################################################################## +# +# Class CubicHeckeElement (for elements) +# +############################################################################## +class CubicHeckeElement(CombinatorialFreeModule.Element): + r""" + Element class of :class:`CubicHeckeAlgebra`. + + It is inherited from :class:`CombinatorialFreeModule.Element` according to the parent class being + inherited from :class:`CombinatorialFreeModule`. The construction of the elements is + realized via :meth:`_element_constructor_` of the parent class. + + For more information see the parent class. + + EXAMPLES:: + + sage: CHA3. = algebras.CubicHecke(3) + sage: c1**3*~c2 + (-u*v+w)*c2^-1 + (u^2-v)*c1*c2^-1 + w*u*c1^-1*c2^-1 + """ + + # --------------------------------------------------------------------------------------------- + # --------------------------------------------------------------------------------------------- + # Overloading inherited methods + # --------------------------------------------------------------------------------------------- + # --------------------------------------------------------------------------------------------- + + def __invert__(self): + r""" + Return inverse of ``self`` (if possible). + + EXAMPLES:: + + sage: CHA3 = algebras.CubicHecke(3) + sage: ele1 = CHA3((1,-2,1)); ele1 + c0*c1^-1*c0 + sage: ~ele1 # indirect doctest + c0^-1*c1*c0^-1 + sage: ele2 = CHA3.an_element() + sage: ~ele2 # indirect doctest + Traceback (most recent call last): + ... + NotImplementedError: inversion of non basis elements is not implemented, yet + """ + self_Tietze = self.Tietze() + + if self_Tietze == None: + raise NotImplementedError( "inversion of non basis elements is not implemented, yet" ) + + inverse_Tietze = () + len_self = len(self_Tietze) + + inverse_Tietze = tuple([-1 *self_Tietze[len_self-i-1 ] for i in range(len_self)]) + P = self.parent() + return P(inverse_Tietze) + + + + + def Tietze(self): + r""" + Return the Tietze presentation of ``self`` if ``self`` belongs to the basis of its parent + and ``None`` else. + + OUTPUT: + + A tuple representing the pre image braid of ``self`` if ``self`` is a monomial from the basis + ``None`` else-wise + + EXAMPLES:: + + sage: CHA3 = algebras.CubicHecke(3) + sage: ele = CHA3.an_element(); ele + ((w^-1)*u-v) + u*c1 + v*c0 + (-w)*c0*c1^-1 + sage: ele.Tietze() is None + True + sage: bas_ele = CHA3(ele.leading_support()) + sage: bas_ele.Tietze() + (1, -2) + """ + vecd = self.to_vector().dict() + if len(vecd) != 1: + return None + ind = list(vecd.keys())[0] + if vecd[ind].is_one(): + P = self.parent() + return P.get_order()[ind].Tietze() + + + + def max_len(self): + r""" + Return the maximum of the length of Tietze expressions among the support of ``self``. + + EXAMPLES:: + + sage: CHA3 = algebras.CubicHecke(3) + sage: ele = CHA3.an_element(); ele + ((w^-1)*u-v) + u*c1 + v*c0 + (-w)*c0*c1^-1 + sage: ele.max_len() + 2 + """ + + return max(len(bas_ele.Tietze()) for bas_ele in self.support()) + + + + + def braid_group_algebra_pre_image(self): + r""" + Return a pre image of ``self`` in the group algebra of the braid_group (with respect to the + basis given by Iwan Marin). + + OUTPUT: + + The pre image of ``self`` as instance of the element class of the group algebra of the BraidGroup + + EXAMPLES:: + + sage: CHA3 = algebras.CubicHecke(3) + sage: ele = CHA3.an_element(); ele + ((w^-1)*u-v) + u*c1 + v*c0 + (-w)*c0*c1^-1 + sage: b_ele = ele.braid_group_algebra_pre_image(); b_ele + ((w^-1)*u-v) + v*c0 + u*c1 + (-w)*c0*c1^-1 + sage: ele in CHA3 + True + sage: b_ele in CHA3 + False + sage: b_ele in CHA3.braid_group_algebra() + True + """ + + + ch_algebra = self.parent() + braid_group_algebra = ch_algebra.braid_group_algebra() + braid_group = ch_algebra.braid_group() + + return ch_algebra._apply_module_morphism(self, lambda bas_ele: braid_group_algebra(braid_group(bas_ele)), codomain=braid_group_algebra) + + + + + def cubic_braid_group_algebra_pre_image(self): + r""" + Return a pre image of ``self`` in the group algebra of the cubic_braid_group. + + OUTPUT: + + The pre image of ``self`` as instance of the element class of the group algebra of the CubicBraidGroup + + EXAMPLES:: + + sage: CHA3 = algebras.CubicHecke(3) + sage: ele = CHA3.an_element(); ele + ((w^-1)*u-v) + u*c1 + v*c0 + (-w)*c0*c1^-1 + sage: cb_ele = ele.cubic_braid_group_algebra_pre_image(); cb_ele + ((w^-1)*u-v) + u*c1 + v*c0 + (-w)*c0*c1^-1 + sage: ele in CHA3 + True + sage: cb_ele in CHA3 + False + sage: cb_ele in CHA3.cubic_braid_group_algebra() + True + """ + + ch_algebra = self.parent() + cbraid_group_algebra = ch_algebra.cubic_braid_group_algebra() + cbraid_group = ch_algebra.cubic_braid_group() + + return ch_algebra._apply_module_morphism(self, lambda bas_ele: cbraid_group_algebra(cbraid_group(bas_ele)), codomain=cbraid_group_algebra) + + + + + + @cached_method + def matrix(self, subdivide=False, representation_type=None, original=False): + r""" + Return certain types of matrix representations of ``self``. + + The absolutely irreducible representations of the cubic Hecke algebra are constructed using + the *GAP3*-Interface and the *CHEVIE* package if GAP3 and CHEVIE are installed on the system. + Furthermore, the representations given on Ivan Marin's homepage are used: + + http://www.lamfa.u-picardie.fr/marin/softs/H4 + + INPUT: + + - ``subdivide`` -- boolean (default = False): this boolean is passed to the block_matrix + function + - ``representation_type`` -- instance of enum :class:`RepresentationType`. + This can be obtained by the attribute :attr:`CubicHeckeAlgebra.repr_type` of ``self``. The following values are possible: + + - ``RegularLeft`` -- (regular left representation given on the above URL) + - ``RegularRight`` -- (regular right representation given on the above URL) + - ``SplitIrredChevie`` -- (split irreducible representations given via GAP3 CHEVIE) + - ``SplitIrredMarin`` -- (split irreducible representations given on the above URL) + - default: ``SplitIrredChevie`` taken if GAP3 and CHEVIE are installed on the system, otherwise the + default will be ``SplitIrredMarin`` + - ``original`` -- boolean (default = False): if set to true the base_ring of the matrix will be the + generic base_ring resp. generic extension ring (for the split versions) of the parent of ``self`` + + OUTPUT: + + An instance of the class :class:`~sage.algebras.hecke_algebras.matrix_representations.cubic_hecke_matrix_rep.CubicHeckeMatrixRep` + which is inherited from :class:`~sage.matrix.matrix_generic_dense.Matrix_generic_dense`. In the case of the irreducible representations + the matrix is given as a block matrix. Each single irreducible can be obtained as item indexed by the members of the enum + :class:`AbsIrreducibeRep` available via :attr:`CubicHeckeAlgebra.irred_repr`. For details type: ``CubicHeckeAlgebra.irred_repr?``. + + + EXAMPLES:: + + sage: CHA3 = algebras.CubicHecke(3) + sage: CHA3.inject_variables() + Defining c0, c1 + sage: c0m = c0.matrix() + sage: c0m[CHA3.irred_repr.W3_111] + [ -b - a + u 0 0] + [(-2*a + u)*b - 2*a^2 + 2*u*a - v b 0] + [ b 1 a] + + using the the ``representation_type`` option:: + + sage: CHA3. = algebras.CubicHecke(3) # optional gap3 + sage: chevie = CHA3.repr_type.SplitIrredChevie + sage: c0m_ch = c0.matrix(representation_type=chevie) # optional gap3 + sage: c0m_ch[CHA3.irred_repr.W3_011] # optional gap3 + [ b 0] + [ -b -b - a + u] + sage: c0m[CHA3.irred_repr.W3_011] + [ b 0] + [a^2 - u*a + v -b - a + u] + + using the the ``original`` option:: + + sage: c0mo = c0.matrix(original=True) + sage: c0mo_ch = c0.matrix(representation_type=chevie, original=True) # optional gap3 + sage: c0mo[CHA3.irred_repr.W3_011] + [ b 0] + [b*c c] + sage: c0mo_ch[CHA3.irred_repr.W3_011] # optional gap3 + [ b 0] + [-b c] + """ + parent = self.parent() + MS = CubicHeckeMatrixSpace(parent, representation_type=representation_type, subdivide=subdivide, original=original) + return MS(self) + + + + def revert_garside(self): + r""" + Return the image of ``self`` under the Garside involution. + See also :meth:`CubicHeckeAlgebra.garside_involution` of the parent class. + + EXAMPLES:: + + sage: roots = (E(3), ~E(3), 1) + sage: CHA3. = algebras.CubicHecke(3, cubic_equation_roots=roots) + sage: e = CHA3.an_element(); e + -c1*c2^-1 + sage: _.revert_garside() + -c2*c1^-1 + sage: _.revert_garside() + -c1*c2^-1 + """ + return self.parent().garside_involution(self) + + + def revert_mirror(self): + r""" + Return the image of ``self`` under the mirror isomorphism. + See also :meth:`CubicHeckeAlgebra.mirror_isomorphism` of the parent class. + + EXAMPLES:: + + sage: CHA3. = algebras.CubicHecke(3) + sage: e = CHA3.an_element() + sage: e.revert_mirror() + ((-w^-1)*u+v) + ((w^-1)*v)*c1^-1 + ((w^-1)*u)*c0^-1 + (-w^-1)*c0^-1*c1 + sage: _.revert_mirror() == e + True + """ + return self.parent().mirror_isomorphism(self) + + + + def revert_orientation(self): + r""" + Return the image of ``self`` under the anti involution reverting the orientation of braids. + See also :meth:`CubicHeckeAlgebra.orientation_antiinvolution` of the parent class. + + EXAMPLES:: + + sage: CHA3. = algebras.CubicHecke(3) + sage: e = CHA3.an_element() + sage: e.revert_orientation() + ((w^-1)*u-v) + u*c2 + v*c1 + (-w)*c2^-1*c1 + sage: _.revert_orientation() == e + True + """ + return self.parent().orientation_antiinvolution(self) + + + + + + + + + + +class CubicHeckeAlgebra(CombinatorialFreeModule): + r""" + Return the Cubic-Hecke algebra with respect to the Artin braid group on $n$ strands. + + This is a quotient of the group algebra of the Artin braid group, such that the images $s_i$ ($1 \leq i < n$) of the + braid generators satisfy a cubic equation (see module header :mod:`~sage.algebras.hecke_algebras.cubic_hecke_algebra` + for more information, in a session type ``sage.algebras.hecke_algebras.cubic_hecke_algebra?``): + + .. MATH:: + + s_i^3 = u s_i^2 - v s_i + w + + The base ring of this algebra can be specified by giving optional keywords described below. If no keywords are given the + base ring will be an instance of the special class :class:`CubicHeckeRingOfDefinition` which is constructed as the polynomial + ring in $u, v$ over the Laurent polynomial ring in $w$ over the integers. This ring will be called the *ring of + definition* or sometimes for short *generic base ring*. But note, that in this context the word *generic* should + not remind in a generic point of the corresponding scheme. + + In addition to the base ring another ring containing the roots ($a, b$ and $c$) of the cubic equation will be needed + to handle the split irreducible representations. This ring will be called *extension ring*. Generically, the extension + ring will be an instance of the special class + :class:`~sage.algebras.hecke_algebras.base_rings_of_definition.cubic_hecke_base_ring.CubicHeckeExtensionRing` + which is constructed as the Laurent polynomial ring in $a, b$ and $c$ over the integers adjoined with a primitive third + root of unity. A special form of this *generic extension ring* is constructed as an instance of + :class:`~sage.algebras.splitting_algebra.SplittingAlgebra` for the roots of the cubic equation and a primitive third + root of unity over the ring of definition. This ring will be called the *default extension ring*. + + This class uses a static and a dynamic data library. The first one is defined as instance of + :class:`~sage.databases.cubic_hecke_db.CubicHeckeDataBase` and contains the complete basis for the algebras with + less than 5 strands and various types of representation matrices of the generators. These data have been calculated by + Ivan Marin and have been imported from: + + http://www.lamfa.u-picardie.fr/marin/softs/ + + Furthermore, representation matrices can be obtained from the *CHEVIE* package of *GAP3* via the GAP3 interface + if GAP3 is installed inside sage. For more information on how to obtain representation matrices to elements of this + class see the documentation of the matrix-method of the element class: + + ``algebras.CubicHecke.Element?`` or ``algebras.CubicHecke.Element.matrix?`` + + The second library is created as instance of :class:`~sage.databases.cubic_hecke_db.CubicHeckeFileCache` and + used while working with the class to achieve a better performance. This file cache contains images of braids and + representation matrices of basis elements from former calculations. A refresh of the file cache can be done + using the :meth:`reset_filecache`. + + INPUT: + + - ``names`` -- string containing the names of the generators as images of the braid group generators + - ``cubic_equation_parameters`` -- tuple ``(u, v, w)`` of three elements in an integral domain used as coefficients + in the cubic equation. If this argument is given the base ring will be set to the common parent of ``u, v, w``. In + addition a conversion map from the generic base ring is supplied. This keyword can also be used to change the + variable names of the generic base ring (see example 3 below). + - ``cubic_equation_roots`` -- tuple ``(a, b, c)`` of three elements in an integral domain which stand for the roots + of the cubic equation. If this argument is given the extension ring will be set to the common parent of ``a, b, c``. + In addition a conversion map from the generic extension ring and the generic base ring is supplied. This keyword + can also be used to change the variable names of the generic extension ring (see example 3 below). + + + EXAMPLES: + + 1. cubic Hecke algebra over the ring of definition:: + + sage: CHA3 = algebras.CubicHecke('s1, s2'); CHA3 + Cubic Hecke algebra on 3 strands over Multivariate Polynomial Ring in u, v + over Univariate Laurent Polynomial Ring in w over Integer Ring + with cubic equation: h^3 - u*h^2 + v*h - w = 0 + sage: CHA3.gens() + (s1, s2) + sage: GER = CHA3.extension_ring(generic=True); GER + Multivariate Laurent Polynomial Ring in a, b, c + over Splitting Algebra of x^2 + x + 1 + with roots [e3, -e3 - 1] over Integer Ring + sage: ER = CHA3.extension_ring(); ER + Splitting Algebra of T^2 + T + 1 with roots [E3, -E3 - 1] + over Splitting Algebra of h^3 - u*h^2 + v*h - w + with roots [a, b, -b - a + u] + over Multivariate Polynomial Ring in u, v + over Univariate Laurent Polynomial Ring in w over Integer Ring + + 2. element construction:: + + sage: ele = CHA3.an_element(); ele + ((w^-1)*u-v) + u*s2 + v*s1 + (-w)*s1*s2^-1 + sage: ele2 = ele**2; ele2 + (-u^2*v-v^3+(w^-2)*u^2+(-2*w^-1)*u*v+v^2) + (u^3+(2*w^-1)*u^2+(-2)*u*v)*s2 + + (w*u^2+w*v^2)*s2^-1 + (u*v^2+(2*w^-1)*u*v+(-2)*v^2+(-w)*u)*s1 + + u*v*s2*s1 + w*v^2*s1^-1 + w*u*v*s2*s1^-1 + u*v*s1*s2 + + ((-w)*u^2)*s1*s2*s1^-1 + ((-w)*u)*s1^-1*s2*s1 + + ((-w)*u*v+(-2)*u+2*w*v)*s1*s2^-1 + w*u*s1*s2*s1^-1*s2 + ((-w)*v)*s2*s1^-1*s2 + + ((-w^2)*v)*s1^-1*s2^-1 + ((-w^2)*u)*s1^-1*s2*s1^-1 + w^2*(s1^-1*s2)^2 + sage: B3 = CHA3.braid_group() + sage: braid = B3((2,-1, 2, 1)); braid + s2*s1^-1*s2*s1 + sage: ele3 = CHA3(braid); ele3 + v*s2^-1*s1 + (-u)*s1*s2*s1^-1 + u*s1^-1*s2*s1 + (-v)*s1*s2^-1 + s1*s2*s1^-1*s2 + sage: ele4 = CHA3((2,-1, 2, 1)) + sage: ele3 == ele4 + True + + + 3. cubic Hecke algebra over the ring of definition using different variable names:: + + sage: algebras.CubicHecke(3, cubic_equation_parameters='u, v, w', cubic_equation_roots='p, q, r') + Cubic Hecke algebra on 3 strands over Multivariate Polynomial Ring in u, v + over Univariate Laurent Polynomial Ring in w over Integer Ring + with cubic equation: h^3 - u*h^2 + v*h - w = 0 + sage: _.extension_ring() + Splitting Algebra of T^2 + T + 1 with roots [E3, -E3 - 1] + over Splitting Algebra of h^3 - u*h^2 + v*h - w + with roots [p, q, -q - p + u] + over Multivariate Polynomial Ring in u, v + over Univariate Laurent Polynomial Ring in w over Integer Ring + + 4. cubic Hecke algebra over a special base ring with respect to a special cubic equation:: + + sage: algebras.CubicHecke('s1, s2', cubic_equation_parameters=(QQ(1),3,1)) + Cubic Hecke algebra on 3 strands over Rational Field + with cubic equation: h^3 - h^2 + 3*h - 1 = 0 + sage: CHA3 = _ + sage: ER = CHA3.extension_ring(); ER + Number Field in T with defining polynomial T^12 + 4*T^11 + 51*T^10 + + 154*T^9 + 855*T^8 + 1880*T^7 + 5805*T^6 + 8798*T^5 + 15312*T^4 + + 14212*T^3 + 13224*T^2 + 5776*T + 1444 + sage: CHA3.cubic_equation_roots()[0] + -4321/1337904*T^11 - 4181/445968*T^10 - 4064/27873*T^9 - 51725/167238*T^8 + - 2693189/1337904*T^7 - 1272907/445968*T^6 - 704251/74328*T^5 + - 591488/83619*T^4 - 642145/83619*T^3 + 252521/111492*T^2 + 45685/5868*T + + 55187/17604 + + sage: F = GF(25,'u') + sage: algebras.CubicHecke('s1, s2', cubic_equation_parameters=(F(1), F.gen(), F(3))) + Cubic Hecke algebra on 3 strands over Finite Field in u of size 5^2 + with cubic equation: h^3 + 4*h^2 + u*h + 2 = 0 + sage: CHA3 = _ + sage: ER = CHA3.extension_ring(); ER + Finite Field in S of size 5^4 + sage: CHA3.cubic_equation_roots() + [2*S^3 + 2*S^2 + 2*S + 1, 2*S^3 + 3*S^2 + 3*S + 2, S^3 + 3] + + + 5. cubic Hecke algebra over a special extension ring with respect to special roots of the cubic equation:: + + sage: UCF = UniversalCyclotomicField() + sage: e3=UCF.gen(3); e5=UCF.gen(5) + sage: algebras.CubicHecke('s1, s2', cubic_equation_roots=(1, e5, e3)) + Cubic Hecke algebra on 3 strands over Universal Cyclotomic Field + with cubic equation: + h^3 + (-E(15) - E(15)^4 - E(15)^7 + E(15)^8)*h^2 + (-E(15)^2 - E(15)^8 + - E(15)^11 - E(15)^13 - E(15)^14)*h - E(15)^8 = 0 + + TESTS: + + sage: CHA3 = algebras.CubicHecke(3) + sage: TestSuite(CHA3).run() + """ + + Element = CubicHeckeElement + repr_type = RepresentationType + irred_repr = AbsIrreducibeRep + + ########################################################################################### + # private methods + ########################################################################################### + @staticmethod + def __classcall_private__(cls, n=None, names='c', cubic_equation_parameters=None, cubic_equation_roots=None): + r""" + Normalize input to ensure a unique representation. + + INPUT: + + - ``n`` -- integer or None (default). The number of strands. If not specified the "names" are + counted and the algebra is assumed to have one more strand than generators + + - ``names`` -- string or list/tuple/iterable of strings (default:'c'). The generator names or + name prefix. The entry can be either a string with the names of the generators, or the number + of generators and the prefix + + EXAMPLES:: + + sage: CHA2 = algebras.CubicHecke(2, 'd', cubic_equation_roots=(3,5,7)); CHA2 + Cubic Hecke algebra on 2 strands over Integer Ring localized at (3, 5, 7) + with cubic equation: + h^3 - 15*h^2 + 71*h - 105 = 0 + sage: CHA2.inject_variables() + Defining d + sage: CHA3 = algebras.CubicHecke(3, cubic_equation_parameters=(3,5,7)); CHA3 + Cubic Hecke algebra on 3 strands over Integer Ring localized at (7,) + with cubic equation: + h^3 - 3*h^2 + 5*h - 7 = 0 + sage: CHA3.cubic_equation_roots() + [a, b, -b - a + 3] + """ + # Support Freegroup('a,b') syntax + if n is not None: + try: + n = ZZ(n)-1 + except TypeError: + names = n + + n = None + # derive n from counting names + if n is None: + import six + if isinstance(names, six.string_types): + n = len(names.split(',')) + else: + names = list(names) + n = len(names) + from sage.structure.category_object import normalize_names + names = tuple(normalize_names(n, names)) + return super(CubicHeckeAlgebra, cls).__classcall__(cls, names, cubic_equation_parameters=cubic_equation_parameters, + cubic_equation_roots=cubic_equation_roots) + + + def __init__(self, names, cubic_equation_parameters=None, cubic_equation_roots=None): + r""" + Python constructor. + + TESTS:: + + sage: CHA2 = algebras.CubicHecke(2, 'd', cubic_equation_roots=(3,5,7)) + sage: TestSuite(CHA2).run() + sage: CHA2 = algebras.CubicHecke(2, cubic_equation_parameters=(3,5,7)) + sage: TestSuite(CHA2).run() + """ + + # --------------------------------------------------------------------------------- + # --------------------------------------------------------------------------------- + # saving input + # --------------------------------------------------------------------------------- + # --------------------------------------------------------------------------------- + self._names = names + + + # --------------------------------------------------------------------------------- + # --------------------------------------------------------------------------------- + # Define underlying group + # --------------------------------------------------------------------------------- + # --------------------------------------------------------------------------------- + self._cubic_braid_group = CubicBraidGroup(names) + self._braid_group = self._cubic_braid_group.braid_group() + n = len(self._cubic_braid_group.gens()) + self._nstrands = n+1 + self._dim_irr_rep = sum([irr.dimension() for irr in AbsIrreducibeRep if irr.number_gens() == n]) + + # --------------------------------------------------------------------------------- + # --------------------------------------------------------------------------------- + # preparing use of data base anf file cache + # --------------------------------------------------------------------------------- + # --------------------------------------------------------------------------------- + from sage.databases.cubic_hecke_db import CubicHeckeDataBase, CubicHeckeFileCache + self._database = CubicHeckeDataBase() + self._filecache = CubicHeckeFileCache(self._nstrands) + + + # --------------------------------------------------------------------------------- + # --------------------------------------------------------------------------------- + # interpretation of keywords + # --------------------------------------------------------------------------------- + # --------------------------------------------------------------------------------- + + # --------------------------------------------------------------------------------- + # type verifications + # --------------------------------------------------------------------------------- + + # --------------------------------------------------------------------------------- + # cubic_equation_parameters + # --------------------------------------------------------------------------------- + ring_of_definition_names = ('u', 'v', 'w') + if cubic_equation_parameters != None: + if isinstance(cubic_equation_parameters, str) == True: + # ----------------------------------------------------------------------------------- + # Input specifies names for the generic base ring + # ----------------------------------------------------------------------------------- + ring_of_definition_names = tuple(cubic_equation_parameters.split(',')) + if len(ring_of_definition_names) != 3 : + raise ValueError('cubic_equation_parameters must consist of exactly 3 elements') + cubic_equation_parameters = None + else: + # ----------------------------------------------------------------------------------- + # Input specifies a specialized base ring + # ----------------------------------------------------------------------------------- + if isinstance(cubic_equation_parameters, list) == True: + cubic_equation_parameters = tuple(cubic_equation_parameters) + if isinstance( cubic_equation_parameters, tuple ) == False: + raise TypeError('cubic_equation_parameters must be a tuple or list') + if len( cubic_equation_parameters ) != 3 : + raise ValueError('cubic_equation_parameters must consist of exactly 3 elements') + + # --------------------------------------------------------------------------------- + # cubic_equation_roots + # --------------------------------------------------------------------------------- + generic_extension_ring_names = ('a', 'b', 'c') + if cubic_equation_roots != None: + if isinstance(cubic_equation_roots, str) == True: + # ----------------------------------------------------------------------------------- + # Input specifies names for the generic extension ring + # ----------------------------------------------------------------------------------- + generic_extension_ring_names = tuple(cubic_equation_roots.split(',')) + if len(generic_extension_ring_names) != 3 : + raise ValueError('cubic_equation_roots must consist of exactly 3 elements') + cubic_equation_roots = None + else: + # ----------------------------------------------------------------------------------- + # Input specifies a specialized base ring + # ----------------------------------------------------------------------------------- + if isinstance( cubic_equation_roots, list ) == True: + cubic_equation_roots = tuple(cubic_equation_roots) + if isinstance( cubic_equation_roots, tuple ) == False: + raise TypeError('cubic_equation_roots must be a tuple or list') + if len( cubic_equation_roots ) != 3 : + raise ValueError('cubic_equation_roots must consist of exactly 3 elements') + + if len(set(ring_of_definition_names + generic_extension_ring_names)) < 6: + raise ValueError('there is an overlap of names between cubic equation parameters (%s) and cubic equation roots (%s)' %(ring_of_definition_names, generic_extension_ring_names) ) + + + # --------------------------------------------------------------------------------- + # --------------------------------------------------------------------------------- + # setting the generic rings + # --------------------------------------------------------------------------------- + # --------------------------------------------------------------------------------- + ring_of_definition = CubicHeckeRingOfDefinition(names=ring_of_definition_names) + u, v, w = ring_of_definition.gens_over_ground() + + generic_extension_ring = ring_of_definition.extension_ring(names=generic_extension_ring_names) + a, b, c = generic_extension_ring.gens() + + # --------------------------------------------------------------------------------- + # registering generic items as variables + # --------------------------------------------------------------------------------- + self._ring_of_definition = ring_of_definition + self._generic_extension_ring = generic_extension_ring + self._generic_cubic_equation_parameters = [u, v, w] + self._generic_cubic_equation_roots = [a, b, c] + + + + # --------------------------------------------------------------------------------- + # interpreting user given cubic equation parameters to define the corresponding + # specialized base ring + # --------------------------------------------------------------------------------- + + if cubic_equation_parameters == None and cubic_equation_roots != None: + pa, pb, pc = cubic_equation_roots + cubic_equation_parameters = [ pa+pb+pc, pa*pb+pb*pc+pa*pc, pa*pb*pc ] + verbose('cubic_equation_parameters %s set according to cubic_equation_roots %s' %(cubic_equation_parameters, cubic_equation_roots)) + + if cubic_equation_parameters != None: + base_ring = ring_of_definition.create_specialization(cubic_equation_parameters) + cubic_equation_parameters = [ base_ring(para) for para in cubic_equation_parameters ] + verbose('base_ring %s set according to cubic_equation_parameters %s' %(base_ring, cubic_equation_parameters)) + else: + base_ring = self._ring_of_definition + cubic_equation_parameters = self._generic_cubic_equation_parameters + + + verbose('base_ring %s and cubic_equation_parameters %s defined' %(base_ring, cubic_equation_parameters)) + + + # ------------------------------------------------------------------------------------------ + # defining the cubic equation + # ------------------------------------------------------------------------------------------ + pu, pv, pw = cubic_equation_parameters + pol_bas_ring = base_ring['h'] + cubic_equation = pol_bas_ring([-pw, pv, -pu, 1 ]) + + + verbose('cubic_equation %s defined' %(cubic_equation)) + + + + # --------------------------------------------------------------------------------- + # --------------------------------------------------------------------------------- + # defining cubic_equation_roots if not given using the cubic_equation + # --------------------------------------------------------------------------------- + # --------------------------------------------------------------------------------- + if base_ring != ring_of_definition: + if cubic_equation_roots == None: + # ------------------------------------------------------------------------------ + # No roots given + # ------------------------------------------------------------------------------ + ext_ring_names = list(generic_extension_ring_names) + cubic_equation_roots = solve_with_extension(cubic_equation, ext_ring_names, var='S', flatten=True) + + # --------------------------------------------------------------------------------- + # interpreting user given cubic equation roots to define the corresponding + # specialized extension ring + # --------------------------------------------------------------------------------- + if cubic_equation_roots != None: + extension_ring = generic_extension_ring.create_specialization(cubic_equation_roots) + cubic_equation_roots = [ extension_ring(root) for root in cubic_equation_roots ] + verbose('extension_ring %s set according to cubic_equation_roots %s' %(base_ring, cubic_equation_roots)) + + else: + extension_ring = generic_extension_ring.as_splitting_algebra() + cubic_equation_roots = [extension_ring(a), extension_ring(b), extension_ring(c)] + + verbose('cubic roots %s and extension ring %s defined' %(cubic_equation_roots, extension_ring)) + pa, pb, pc = cubic_equation_roots + + + + # --------------------------------------------------------------------------------- + # --------------------------------------------------------------------------------- + # check keywords plausibility + # --------------------------------------------------------------------------------- + # --------------------------------------------------------------------------------- + if base_ring == extension_ring: + val_a = cubic_equation.substitute(h=pa) + val_b = cubic_equation.substitute(h=pb) + val_c = cubic_equation.substitute(h=pc) + if val_a != 0 or val_b != 0 or val_c != 0 : + raise ValueError( 'cubic equation does not vanish on cubic equation roots' ) + + + # --------------------------------------------------------------------------------- + # --------------------------------------------------------------------------------- + # defining the base ring embedding into the extension ring + # --------------------------------------------------------------------------------- + # --------------------------------------------------------------------------------- + + + im_base_gens = [pa+pb+pc, pa*pb+pa*pc+pb*pc, pa*pb*pc] + + base_ring_embedding = extension_ring.coerce_map_from( base_ring ) + + def check_base_ring_embedding(base_ring_embedding): + if base_ring_embedding is None: + return False + try: + ipu = base_ring_embedding(pu) + ipv = base_ring_embedding(pv) + ipw = base_ring_embedding(pw) + if [ipu, ipv, ipw] != im_base_gens: + return False + except (TypeError, ValueError): + return False + return True + + if check_base_ring_embedding(base_ring_embedding): + verbose('base_ring_embedding defined via coercion') + else: + base_ring_embedding = extension_ring.convert_map_from( base_ring ) + if check_base_ring_embedding(base_ring_embedding): + verbose('base_ring_embedding defined via conversion') + else: + try: + if base_ring.gens() == cubic_equation_parameters: + base_ring_embedding = base_ring.hom(im_base_gens, codomain=extension_ring) + except (TypeError, ValueError): + base_ring_embedding = None + + + if base_ring_embedding == None: + warn('Warning: no base_ring_embedding found') + + + + # --------------------------------------------------------------------------------- + # --------------------------------------------------------------------------------- + # registering variables + # --------------------------------------------------------------------------------- + # --------------------------------------------------------------------------------- + self._base_ring = base_ring + self._extension_ring = extension_ring + self._base_ring_embedding = base_ring_embedding + self._ring_of_definition_map = base_ring.convert_map_from(ring_of_definition) + self._generic_extension_ring_map = extension_ring.convert_map_from(generic_extension_ring) + self._cubic_equation_parameters = cubic_equation_parameters + self._cubic_equation_roots = cubic_equation_roots + + + # --------------------------------------------------------------------------------- + # defining the associated group algebras + # --------------------------------------------------------------------------------- + # old base_ring keyword of GroupAlgebra + # self._cubic_braid_group_algebra = GroupAlgebra( self._cubic_braid_group, base_ring=base_ring) + # self._braid_group_algebra = GroupAlgebra( self._braid_group, base_ring=base_ring) + # new base_ring keyword of GroupAlgebra + from sage.algebras.group_algebra import GroupAlgebra + self._cubic_braid_group_algebra = GroupAlgebra(self._cubic_braid_group, R=base_ring) + self._braid_group_algebra = GroupAlgebra(self._braid_group, R=base_ring) + + + # ---------------------------------------------------------------------------------------- + # Setup of Basis + # ---------------------------------------------------------------------------------------- + # init of data libraries and fetch the basis of Ivan Marin for the algebras on at most 4 + # strands. The fetch does not take long time. Therefore we do this absolutely silent + # ---------------------------------------------------------------------------------------- + marin_basis_data = self._database.read(self._database.filename.basis) + + # -------------------------------------------------------------------------------------------------- + # An explicit list of basis element which represents a flat deformation of the cubic braid group + # is only available in the cases where the number of strands is less than 5. In the case of exactly + # 5 strands it is known that such a basis exist by work of Ivan Marin in [Marin2012] but it can not + # be calculated, right now. In the (infinite dimensional) cases of more than 5 strand it is even an + # open problem if the cubic Hecke algebra is a flat deformation of the group algebra of the + # corresponding cubic braid group. + # + # But anyway, we will take the elements of the cubic braid group as a basis of the cubic Hecke + # algebra in all cases. Beware that this might not cover the whole cubic Hecke algebra if the + # number of strands is larger than 4 + # + # Internally the basis is handled using two lists one of which consists of fixed braid preiimages + # of the basis elements and the other (redundant) of the corresponding Tietze expressions. + # + # In the case of less than 5 strands these lists are directly obtained from the list calculated + # by Ivan Marin available at + # + # + # In the other cases these lists are implemented as growing lists which is initialized with Marin's + # list and is extended on demand. + # ----------------------------------------------------------------------------------------------- + + if self.strands() < 5 : + self._basis_static = [bas for bas in marin_basis_data[self.strands()][0]] + else: + self._basis_static = [bas for bas in marin_basis_data[4][0]] + + # --------------------------------------------------------------------------------- + # --------------------------------------------------------------------------------- + # defining the algebra itself + # --------------------------------------------------------------------------------- + # -------------------------------------------------------------------------------- + + if self._cubic_braid_group.is_finite(): + from sage.categories.finite_dimensional_algebras_with_basis import FiniteDimensionalAlgebrasWithBasis + category = FiniteDimensionalAlgebrasWithBasis(base_ring) + else: + from sage.categories.algebras_with_basis import AlgebrasWithBasis + category = AlgebrasWithBasis(base_ring) + + + CombinatorialFreeModule.__init__(self, base_ring, self._cubic_braid_group, prefix='', bracket=False, category=category) + + # ---------------------------------------------------------------------------------------- + # init the attributes being set on demand + # ---------------------------------------------------------------------------------------- + self._cubic_hecke_subalgebra = None # the cubic Hecke subalgebra with one strand (the highest) less + self._mirror_image = None # the image of self under the mirror isomorphism + self._is_mirror = False # to see if this instance is the mirror or the original + self._base_ring_mirror = None # mirror involution map on base ring + self._gens_reg_repres_matrix = {} # a dictionary recording the generators regular representation matrices + + # ---------------------------------------------------------------------------------------- + # initializing the basis extension (in case of more than 4 strands) + # ---------------------------------------------------------------------------------------- + self._init_basis_extension() # read in the basis extensions from file cache + return + + + + + + + + + ####################################################################################################################### + # --------------------------------------------------------------------------------------------------------------------- + # overloaded inherited methods + # --------------------------------------------------------------------------------------------------------------------- + ####################################################################################################################### + + + def _repr_(self): + r""" + Return a string representation + + OUTPUT: + + String describing ``self`` + + TESTS: + + sage: CHA3 = algebras.CubicHecke(3) + sage: CHA3 # indirect doctest + Cubic Hecke algebra on 3 strands over Multivariate Polynomial Ring in u, v + over Univariate Laurent Polynomial Ring in w + over Integer Ring with cubic equation: h^3 - u*h^2 + v*h - w = 0 + """ + return "Cubic Hecke algebra on %s strands over %s with cubic equation: %s = 0"%(self.strands(), self.base_ring(), self.cubic_equation()) + + + def _element_constructor_(self, x): + r""" + Extensions to the element constructor of class :class:`CombinatorialFreeModule`. + New functionalities are: + + -- constructing element from a braid (group homomorphism) + -- constructing element from a braid giving in Tietze form + -- constructing element from an element of the braid group algebra (algebra homomorphism) + -- constructing element from an element of the cubic braid group algebra (module homomorphism) + -- constructing element from an element of an other cubic_hecke_algebra over an other base ring or with less strands + -- constructing element from an element of the mirror image of ``self`` (see method mirror_image) + + INPUT: + + - ``x`` -- can be one of the following: + -- an instance of the element class of ``self`` (but possible to a different parent) + -- an instance of the element class of the braid group + -- an instance of the element class of the braid group algebra over the base ring of ``self`` + -- an instance of the element class of the cubic braid group + -- an instance of the element class of the cubic braid group algebra over the base ring of ``self`` + -- an instance of the element class of the mirror image of ``self`` + -- a tuple representing a braid in Tietze form + -- any other object which works for the element constructor of :class:`CombinatorialFreeModule` + + OUTPUT: + + Instance of the element class of ``self``. + + EXAMPLES:: + + sage: B2 = BraidGroup(2) + sage: b, = B2.gens() + sage: b2 = b**2 + sage: CB2 = CubicBraidGroup(2) + sage: cb, = CB2.gens() + sage: cb2 = cb**2 + sage: CHA2 = algebras.CubicHecke(2) + sage: CHA2(b2) + (-v) + u*c + w*c^-1 + sage: CHA2(cb2) + c^-1 + sage: CHA3 = algebras.CubicHecke(3) + sage: B3 = CHA3.braid_group() + sage: CB3 = CHA3.cubic_braid_group() + sage: CB3GA = CHA3.cubic_braid_group_algebra() + sage: braid = B3((1,2,2,-1,2,1,1,-1)); braid + c0*c1^2*c0^-1*c1*c0 + sage: img_braid = CHA3(braid); img_braid + (u*v^2+(-w)*v)*c1^-1 + (u^2-v)*c1*c0 + u^2*v*c1*c0^-1 + (-u^3)*c0*c1*c0^-1 + + (-u^2*v+w*u)*c0*c1^-1 + u^2*c0*c1*c0^-1*c1 + (-u*v)*c1*c0^-1*c1 + + ((-w)*u*v+w^2)*c0^-1*c1^-1 + ((-w)*u^2)*c0^-1*c1*c0^-1 + + w*u*(c0^-1*c1)^2 + u*v*c0*c1^-1*c0 + sage: cbraid = CB3(braid); cbraid + c0*c1^2*c0^-1*c1*c0 + sage: img_cbraid = CHA3(cbraid); img_cbraid + c0^-1*c1^-1 + sage: img_cbraid_back = img_cbraid.cubic_braid_group_algebra_pre_image() + sage: img_cbraid_back in CB3GA + True + sage: img_cbraid_back == CB3GA(cbraid) + True + """ + braid_grp = self.braid_group() + braid_grp_alg = self.braid_group_algebra() + braid_img = self._braid_image + + cbraid_grp = self.cubic_braid_group() + cbraid_grp_alg = self.cubic_braid_group_algebra() + cbraid_img = self._cubic_braid_image + + base_ring = self.base_ring() + ngens = self.ngens() + + # ----------------------------------------------------------------------------------------- + # if x is a tuple we may interpret it as a braid in Tietze form + # ----------------------------------------------------------------------------------------- + xb = x + if type(x) in (tuple, list): + x = tuple(x) + result = self._tietze_to_finite_sub_basis_monomial(x) + if result is not None: + # x represents a monomial + verbose("End from tuple %s: %s" %(x, result)) + return result + + try: + xb=braid_grp(x) + except (TypeError, ValueError, NotImplementedError): + pass + + # ----------------------------------------------------------------------------------------- + # embedding of an element of an other cubic Hecke algebra with lower number of strands + # but same base ring + # ----------------------------------------------------------------------------------------- + if isinstance(xb, CubicHeckeElement): + OtherCHA = xb.parent() + other_base_ring = OtherCHA.base_ring() + other_ngens = OtherCHA.ngens() + if other_base_ring != base_ring: + if other_ngens == ngens: + xbv = xb.to_vector() + img_xbv = vector([self.base_ring()(cf) for cf in xbv ]) + return self.from_vector(img_xbv) + elif other_ngens < ngens: + SubAlg = SubAlg = self.cubic_hecke_subalgebra(other_ngens+1) + return self(SubAlg(xb)) + + elif other_ngens < ngens and OtherCHA.cubic_equation_parameters() == self.cubic_equation_parameters(): + + cubic_braid_preimg = xb.cubic_braid_group_algebra_pre_image() + OtherCBGA = OtherCHA.cubic_braid_group_algebra() + + result = OtherCBGA._apply_module_morphism(cubic_braid_preimg, lambda ele: cbraid_img(cbraid_grp(ele)), codomain=self) + verbose("End from smaller cubic Hecke algebra %s: %s" %(xb, result)) + return result + + elif OtherCHA == self._mirror_image: + + result = OtherCHA.mirror_isomorphism(xb) + verbose("End from mirror image %s: %s" %(xb, result)) + return result + + # ----------------------------------------------------------------------------------------- + # if xb is an element of the braid group or its group algebra over the same base ring + # the algebra morphism self._braid_image is applied + # ----------------------------------------------------------------------------------------- + if isinstance(xb, braid_grp_alg.element_class) and xb in braid_grp_alg: + + result = braid_grp_alg._apply_module_morphism(xb, lambda ele: braid_img(ele), codomain=self) + verbose("End from braid_group algebra %s: %s" %(xb, result)) + return result + + from sage.groups.braid import Braid + if isinstance(xb, Braid) and xb.strands() == self.strands(): + + result = braid_img(xb) + verbose("End from braid_group %s: %s" %(xb, result)) + return result + + # ----------------------------------------------------------------------------------------- + # if xb is an element of the cubic_braid group or its group algebra over the same base ring + # xb the module morphism self._braid_image is applied + # ----------------------------------------------------------------------------------------- + if isinstance(xb, cbraid_grp_alg.element_class) and xb in cbraid_grp_alg: + + result = cbraid_grp_alg._apply_module_morphism(xb, cbraid_img, codomain=self) + verbose("End from cubic braid_group algebra %s: %s" %(xb, result)) + return result + + from sage.groups.cubic_braid import CubicBraidElement + if isinstance(xb, CubicBraidElement) and xb.parent().strands() == self.strands(): + + result = cbraid_img(xb) + verbose("End from cubic braid_group %s: %s" %(xb, result)) + return result + + + # ----------------------------------------------------------------------------------------- + # doing the default construction by inheritance + # ----------------------------------------------------------------------------------------- + result = CombinatorialFreeModule._element_constructor_(self, x) + verbose("End (default) %s: %s" %(xb, result)) + return result + + + + def get_order(self): + r""" + Overwrites the corresponding method of :class:`CombinatorialFreeModule`. The reason is that + we have to care about the dynamical growth of the finite sub basis used for the calculation in case of + more than 4 strands. + + To see the documentation of the original method type: + + ``CombinatorialFreeModule.get_order?`` + + EXAMPLES:: + + sage: CHA3 = algebras.CubicHecke(3) + sage: len(CHA3.get_order()) + 24 + """ + if self.strands() < 5: + return self._order + else: + # detect change of order of subalgebra + cbg = self.cubic_braid_group() + sub_alg = self.cubic_hecke_subalgebra() + former_len_sub = len(sub_alg._order) + sub_order = [cbg(cb) for cb in sub_alg.get_order()] + if former_len_sub == len(sub_order): + if len(self._order) == former_len_sub + len(self._basis_extension): + return self._order + # order has changed! recalculation neccessary: + self._order = sub_order + [cbg(tup) for tup in self._basis_extension] + return self._order + + + + def _dense_free_module(self, base_ring=None): + r""" + Overwrites the corresponding method of :class:`CombinatorialFreeModule`. + The only difference is, that the dimension is not the dimension of ``self`` but + the dimension of the submodule generated by the dynamically growing basis given + by the the get_order method. In particular there is no difference if the number + of strands is less than 5. + + To see the documentation of the original method type: + + ``CombinatorialFreeModule._dense_free_module?`` + + EXAMPLES:: + + sage: CHA2 = algebras.CubicHecke(2) + sage: CHA2._dense_free_module() + Ambient free module of rank 3 over the integral domain Multivariate Polynomial Ring in u, v + over Univariate Laurent Polynomial Ring in w over Integer Ring + """ + + if base_ring is None: + base_ring = self.base_ring() + from sage.modules.free_module import FreeModule + return FreeModule(base_ring, len(self.get_order())) + + + def ngens(self): + r""" + The number of generators of the algebra. + + EXAMPLES:: + + sage: CHA2 = algebras.CubicHecke(2) + sage: CHA2.ngens() + 1 + """ + return self.strands() -1 + + def algebra_generators(self): + r""" + Return the algebra generators of ``self``. + + EXAMPLES:: + + sage: CHA2 = algebras.CubicHecke(2) + sage: CHA2.algebra_generators() + Finite family {c: c} + """ + from sage.sets.family import Family + return Family(self._cubic_braid_group.gens(), self.monomial) + + + def gens(self): + r""" + Return the generators of ``self``. + + EXAMPLES:: + + sage: CHA2 = algebras.CubicHecke(2) + sage: CHA2.gens() + (c,) + """ + return tuple(self.algebra_generators()) + + + def gen(self, i): + r""" + The ``i``-th generator of the algebra. + + EXAMPLES:: + + sage: CHA2 = algebras.CubicHecke(2) + sage: CHA2.gen(0) + c + """ + return self.gens()[i] + + + def one_basis(self): + r""" + Return the identity element in the cubic braid group, as per + AlgebrasWithBasis.ParentMethods.one_basis. + + EXAMPLES:: + + sage: CHA2 = algebras.CubicHecke(2) + sage: CHA2.one_basis() + 1 + """ + return self.cubic_braid_group().one() + + + def _an_element_(self): + r""" + Overwrite the original method from :mod:`sage.combinat.free_module` + to obtain an more interesting element for ``TestSuite``. + + EXAMPLES:: + + sage: CHA2 = algebras.CubicHecke(2) + sage: CHA2.an_element() # indirect doctest + ((w^-1)*u-v) + v*c + """ + + n = self.ngens()+1 + base_ring = self.base_ring() + u, v, w = [base_ring(para) for para in self._cubic_equation_parameters] + const = (u *~w -v)* self.one() + + gens = self.gens() + first_gens = [gen for gen in gens if gens.index(gen) < 3 ] + if n == 2 : + c1, = first_gens + return const + v*c1 + elif n == 3 : + c1, c2 = first_gens + return const + v*c1 -w*c1*~c2 + u*c2 + else: + c1, c2, c3 = first_gens + return const + v*c1*~c3 -w*c1*~c2 + u*c3*c2 + + + + + @cached_method + def chevie(self): + r""" + Return the *GAP3-CHEVIE* realization of the corresponding *cyclotomic Hecke algebra* + in the finite-dimensional case. + + EXAMPLES:: + + sage: CHA3 = algebras.CubicHecke(3) # optional gap3 + sage: CHA3.chevie() # optional gap3 + Hecke(G4,[[a,b,c]]) + """ + + from sage.combinat.root_system.reflection_group_real import is_chevie_available + if not is_chevie_available(): + raise NotImplementedError('this functionality needs GAP3 with package CHEVIE') + + n = self._nstrands + + if n == 3: + st_number = 4 + elif n == 4: + st_number = 25 + elif n == 5: + st_number = 32 + else: + raise NotImplementedError('CHEVIE version doesn\'t exist for this cubic Hecke algebra') + + gap3_function_str = """function(st_number, na, nb,nc) + local a, b, c, # embedded Indeterminates + ReflGroup, # Reflection group + HeckeAlg; # Hecke algebra + + a := Mvp(na); b := Mvp(nb); c := Mvp(nc); + ReflGroup := ComplexReflectionGroup(st_number); + HeckeAlg := Hecke(ReflGroup, [[a, b, c]] ); + return HeckeAlg; + end;""" + + from sage.interfaces.gap3 import gap3 + gap3_function = gap3(gap3_function_str) + na, nb, nc = [ '\"%s\"' %(indet) for indet in self.extension_ring(generic=True).variable_names() ] + return gap3_function(st_number, na, nb, nc) + + + @cached_method + def product_on_basis(self, g1, g2): + r""" + Return product on basis elements, as per + :meth:`~sage.categories.magmatic_algebras.MagmaticAlgebras.WithBasis.ParentMethods.product_on_basis` + + EXAMPLES:: + + sage: CHA3 = algebras.CubicHecke(3) + sage: g = CHA3.basis().keys().an_element(); g + c0*c1 + sage: CHA3.product_on_basis(g, ~g) + 1 + sage: CHA3.product_on_basis(g, g) + (-v)*c1*c0 + u*c0*c1*c0 + w*c0^-1*c1*c0 + """ + # ------------------------------------------------------------------------------------------------ + # short way for multiplications with one + # ------------------------------------------------------------------------------------------------ + if g1 == g1.parent().one(): + return self.monomial(g2) + + if g2 == g2.parent().one(): + return self.monomial(g1) + + # ------------------------------------------------------------------------------------------------ + # convert to monomials + # ------------------------------------------------------------------------------------------------ + g1 = self.monomial(g1) + g2 = self.monomial(g2) + + result = None + + g1_Tietze = g1.Tietze() + g2_Tietze = g2.Tietze() + + verbose("Tietze established (%s, %s)" %(g1_Tietze, g2_Tietze)) + + # ---------------------------------------------------------------------------------------------------- + # The product is calculated from the corresponding product of the braids + # ---------------------------------------------------------------------------------------------------- + + braid_group = self.braid_group() + braid_product = braid_group(g1_Tietze+g2_Tietze) + + result = self._braid_image(braid_product) + + return result + + + + + + + ####################################################################################################################### + # --------------------------------------------------------------------------------------------------------------------- + # local methods + # --------------------------------------------------------------------------------------------------------------------- + ####################################################################################################################### + + + + def _basis_tietze(self): + r""" + Return the complete finite sub basis as list of Tietze tuples + + EXAMPLES:: + + sage: CHA2 = algebras.CubicHecke(2) + sage: CHA2._basis_tietze() + [[], [1], [-1]] + """ + if self.strands() > 4 : + self_sub = self.cubic_hecke_subalgebra() + result_list = self_sub._basis_tietze() + self._basis_extension + else: + result_list = self._basis_static + return result_list + + + def _tietze_to_finite_sub_basis_monomial(self, tietze_tup): + r""" + Return the monomial corresponding to a tietze tuple + if it is in the finite sub basis. Else return None. + + EXAMPLES:: + + sage: CHA2 = algebras.CubicHecke(2) + sage: CHA2._tietze_to_finite_sub_basis_monomial([-1]) + c^-1 + sage: CHA2._tietze_to_finite_sub_basis_monomial([-2]) is None + True + """ + tietze_list = list(tietze_tup) + in_basis = False + if tietze_list in self._basis_tietze(): + in_basis = True + elif self.strands() > 4: + fsb_dict = self._finite_sub_basis_tuples + if tietze_list in list(fsb_dict.values()): + in_basis = True + elif self.cubic_hecke_subalgebra()._tietze_to_finite_sub_basis_monomial(tietze_tup) is not None: + in_basis = True + + if in_basis: + # tietze_tup represents a monomial + B = self.basis() + cb = self.cubic_braid_group()(tietze_tup) + return B[cb] + else: + return None + + @cached_method + def _create_matrix_list_for_one(self, representation_type): + r""" + Return the matrix list for the given representation_type for ``self.one()`. + + EXAMPLES:: + + sage: CHA2 = algebras.CubicHecke(2) + sage: CHA2._create_matrix_list_for_one(CHA2.repr_type.SplitIrredMarin) + [[1], [1], [1]] + sage: CHA2._create_matrix_list_for_one(CHA2.repr_type.RegularLeft) + [ + [1 0 0] + [0 1 0] + [0 0 1] + ] + """ + n = self.strands() + if representation_type.is_split(): + gen_base_ring = self.extension_ring(generic=True) + rep_ind = [rep.internal_index() for rep in AbsIrreducibeRep if rep.number_gens() == n-1 ] + rep_dim = [rep.dimension() for rep in AbsIrreducibeRep if rep.number_gens() == n-1 ] + dim_sort = [rep_dim[rep_ind.index(i)] for i in range(len(rep_ind))] + matrix_list = [MatrixSpace(gen_base_ring, dim_sort[i]).one() for i in range(len(rep_ind))] + else: + gen_base_ring = self.base_ring(generic=True) + matrix_list = [MatrixSpace(gen_base_ring, self.dimension()).one()] + return matrix_list + + @cached_method + def _fetch_matrix_list_from_chevie(self, number): + r""" + This method reads irreducible representation of the cubic Hecke algebra via the *GAP3* interface from *CHEVIE* + + INPUT: + + - ``number`` -- integer: number of the representation according to *CHEVIE* + + OUTPUT: + + A list of representing matrices over the generic extension ring, one matrix for each generators. + + EXAMPLES:: + + sage: CHA3 = algebras.CubicHecke(3) # optional gap3 + sage: CHA3._fetch_matrix_list_from_chevie(5) # optional gap3 + [ + [ a 0] [c c] + [-a c], [0 a] + ] + """ + GER = self.extension_ring(generic=True) + gap3_result = self.chevie().Representations(number) + from sage.matrix.constructor import matrix + matrix_list_gens = [matrix(GER, mat_gap) for mat_gap in gap3_result] + for m in matrix_list_gens: m.set_immutable() + return matrix_list_gens + + + + + # ------------------------------------------------------------------------------- + # ------------------------------------------------------------------------------- + # Methods for test_suite + # ------------------------------------------------------------------------------- + # ------------------------------------------------------------------------------------------------------------- + # _test_ring_constructions + # ------------------------------------------------------------------------------------------------------------- + def _test_ring_constructions(self, **options): + r""" + Method called by TestSuite. + + the following is checked: + - construction of base_ring and extension ring + - construction of maps between generic base and extension ring and the user defined rings + - aplication of the ring homomorphisms + + EXAMPLES:: + + sage: CHA2 = algebras.CubicHecke(2, cubic_equation_roots=(3,7,11)) + sage: CHA2._test_ring_constructions() + """ + # ------------------------------------------------------------------------ + # testing ring constructions + # ------------------------------------------------------------------------ + + + br=self.base_ring(); er=self.extension_ring() + A, B, C = self.cubic_equation_roots(); a, b, c = self.cubic_equation_roots(generic=True); + U, V, W = self.cubic_equation_parameters(); u, v, w = self.cubic_equation_parameters(generic=True); + eleB = U*V-W**2 ; eleBgen = u*v-w**2 ; eleE = A*B-C**2 ; eleEgen = a*b-c**2 + + mbr = self._ring_of_definition_map + mer = self._generic_extension_ring_map + bri = self._base_ring_embedding + + eleBgenEmb = 0 ; eleEgenEmb = 0 ; eleBembE = 0 + + try: + eleBgenEmb = br(eleBgen) + except (TypeError, ValueError, NotImplementedError): + verbose("Generic base ring map not registered") + try: + eleBgenEmb = mbr(eleBgen) + except (TypeError, ValueError, NotImplementedError): + raise RuntimeError("fatal: generic base ring map %s does not work" %(mbr)) + try: + eleEgenEmb = er(eleEgen) + except (TypeError, ValueError, NotImplementedError): + verbose("Generic extension ring map not registered") + try: + eleEgenEmb = mer(eleEgen) + except (TypeError, ValueError, NotImplementedError): + raise RuntimeError("fatal: generic extension ring map %s does not work" %(mer)) + + try: + eleBembE = er(eleB) + except (TypeError, ValueError, NotImplementedError): + verbose("base ring embedding map not registered") + try: + eleBembE = bri(eleB) + except (TypeError, ValueError, NotImplementedError): + raise RuntimeError( "fatal: base ring embedding %s does not work" %(bri) ) + + test_eleBgenEmb = self._tester(**options) + test_eleBgenEmb.assertTrue( eleBgenEmb == eleB ) + test_eleEgenEmb = self._tester(**options) + test_eleEgenEmb.assertTrue( eleEgenEmb == eleE ) + test_eleBembE = self._tester(**options) + test_eleBembE.assertTrue( eleBembE == eleB ) + + + + # ------------------------------------------------------------------------------------------------------------- + # _test_matrix_constructions + # ------------------------------------------------------------------------------------------------------------- + def _test_matrix_constructions(self, **options): + r""" + Method called by TestSuite + + the following is checked: + - construction of matrices of the following types + + - multiplication of matrices and compare with the matrix of the corresponding product of elements + - construction of maps between generic base and extension ring and the user defined rings + + EXAMPLES:: + + sage: CHA2 = algebras.CubicHecke(2, cubic_equation_roots=(3,7,11)) + sage: CHA2._test_matrix_constructions() + """ + # ------------------------------------------------------------------------ + # testing matrix constructions + # ------------------------------------------------------------ ------------ + + if self.ngens() > 4 : + return + + gens = self.gens() + b1 = gens[0 ]; b2 = self.an_element() + b12 = b1*b2 + verbose("b12 %s" %(b12)) + + def check_matrix(representation_type): + m1 = b1.matrix(representation_type=representation_type) + m2 = b2.matrix(representation_type=representation_type) + m12mult = m1*m2 + m12mat = b12.matrix(representation_type=representation_type) + test_matrix = self._tester(**options) + test_matrix.assertTrue(m12mult == m12mat) + + from sage.combinat.root_system.reflection_group_real import is_chevie_available + + if is_chevie_available(): + check_matrix(RepresentationType.SplitIrredChevie) + if self.ngens() < 3 : + check_matrix(RepresentationType.SplitIrredMarin) + elif self.ngens() < 4 : + check_matrix(RepresentationType.SplitIrredMarin) + + if self.ngens() < 3 : + check_matrix(RepresentationType.RegularLeft) + + return + + + + + + + + + # ------------------------------------------------------------------------------------------------------------- + # _init_basis_extension + # ------------------------------------------------------------------------------------------------------------- + def _init_basis_extension(self): + r""" + Return the extension of the basis for more than 4 strands hold in file cache. + The basis elements from the file are added to the elements of the Marin basis. + + EXAMPLES:: + + sage: CHA5 = algebras.CubicHecke(5) # long time + sage: fc = CHA5._filecache # long time + sage: basis_extensions = fc.section.basis_extensions # long time + sage: CHA5.reset_filecache(basis_extensions) # long time indirect doctest + sage: fc.read(basis_extensions) # long time + [[4], [-4]] + sage: ele = CHA5.an_element() # long time + sage: CHA5.inject_variables() # long time + Defining c0, c1, c2, c3 + sage: ele2 = ele*c3 # long time + sage: bex = fc.read(basis_extensions) # long time + sage: bex.sort(); bex # long time + [[-4], [1, -3, 4], [1, -2, 4], [3, 2, 4], [4]] + """ + self._basis_extension = [] + + tietze_list = self._basis_tietze() + cbg = self._cubic_braid_group + self._finite_sub_basis_tuples = {} + order_list = [cbg(tup) for tup in tietze_list] + self.set_order(order_list) + verbose('Finite sub basis length: %s' %(len(order_list))) + + if self.strands() < 5: + return + # ------------------------------------------------------------------------------------------------- + # loading the extension of the basis from data file + # ------------------------------------------------------------------------------------------------- + fc = self._filecache + former_bas_ext = fc.read(fc.section.basis_extensions) + + # ------------------------------------------------------------------------------------------------- + # pre definition of additional basis elements + # ------------------------------------------------------------------------------------------------- + cub_braid_group = self.cubic_braid_group() + if len(former_bas_ext) == 0: + gens = cub_braid_group.gens() + last_gen = gens[len(gens)-1] + self._cubic_braid_image(last_gen, check=False) + self._cubic_braid_image(~last_gen, check=False) + self._filecache.update_basis_extensions(self._basis_extension) + return + + # ------------------------------------------------------------------------------------------------- + # Installing the additional basis elements from filecache via the embedding of + # the corresponding cubic braid + # ------------------------------------------------------------------------------------------------- + for bas_Tietze in former_bas_ext: + cub_braid = cub_braid_group(bas_Tietze) + self._cubic_braid_image(cub_braid, check=False) + + verbose('Finite sub basis (extended) length: %s' %(len(self.get_order()))) + self._filecache.update_basis_extensions(self._basis_extension) + return + + + + + + # ------------------------------------------------------------------------------------------------------------- + # _braid_image_from_filecache + # ------------------------------------------------------------------------------------------------------------- + def _braid_image_from_filecache(self, braid): + r""" + Return the image of the given braid in ``self`` from file cache (if contained). + + INPUT: + + - ``braid`` -- braid as instance of the braid group of ``self`` + + OUTPUT: + + Image of braid as element of ``self``. None if the product has not been stored. + + EXAMPLES:: + + sage: CHA3 = algebras.CubicHecke(3) + sage: b1, b2 = CHA3.braid_group().gens(); br = ~b2*b1*~b2 + sage: CHA3._braid_image_from_filecache(br) + ((w^-1)*v)*c1^-1*c0 + ((-w^-1)*u)*c0*c1*c0^-1 + (w^-1)*c0*c1*c0^-1*c1 + sage: CHA3.reset_filecache(CHA3.select_filecache_section().braid_images) + sage: CHA3._braid_image_from_filecache(br) + """ + + base_ring = self.base_ring() + gen_base_ring = self.base_ring(generic=True) + result_vect = self._filecache.read_braid_image(braid.Tietze(), gen_base_ring) + if not result_vect is None: + if gen_base_ring != base_ring: + base_map = self._ring_of_definition_map + result_vect = base_map(result_vect) + return self.from_vector(result_vect) + return None + + + # ------------------------------------------------------------------------------------------------------------- + # _braid_image_to_filecache + # ------------------------------------------------------------------------------------------------------------- + def _braid_image_to_filecache(self, braid_tietze, braid_image_vect): + r""" + Write the given braid image of to file cache. + + INPUT: + + - `braid_tietze` -- braid in Tietze form + - `braid_image_vect` -- image of the given braid in ``self`` in vector representation + + EXAMPLES:: + + sage: CHA2 = algebras.CubicHecke(2) + sage: br, = CHA2.braid_group().gens(); br2 = br**2 + sage: CHA2.is_filecache_empty(CHA2.select_filecache_section().braid_images) # note: 2-strand images are not automatically cached in file system + True + sage: CHA2._braid_image_to_filecache(br2.Tietze(), CHA2(br2).to_vector()) + sage: CHA2._braid_image_from_filecache(br2) + (-v) + u*c + w*c^-1 + sage: CHA2.reset_filecache(CHA2.select_filecache_section().braid_images) + sage: CHA2._braid_image_from_filecache(br2) == None + True + """ + if self.base_ring() != self.base_ring(generic=True): + # this should not be done for specialized base rings + return + + self._filecache.write_braid_image(braid_tietze, braid_image_vect) + return + + + + + # ------------------------------------------------------------------------------------------------------------- + # _braid_image + # ------------------------------------------------------------------------------------------------------------- + def _braid_image(self, braid): + r""" + Return the image of the given braid in ``self``. + + INPUT: + + - ``braid`` - instance of :class:`~sage.groups.braid.Braid`, whose image in ``self`` should be calculated + + + OUTPUT: + + An instance of the element class of ``self``. + + EXAMPLES:: + + sage: CHA2 = algebras.CubicHecke(2) + sage: br, = CHA2.braid_group().gens(); br2 = br**2 + sage: CHA2._braid_image(br2) + (-v) + u*c + w*c^-1 + """ + + + # ----------------------------------------------------------------------------------------------------- + # first use the cubic equation to express the braid as a linear combination of braids having no other + # exponent as 1 and -1 in their defining word in the braid generators + # ----------------------------------------------------------------------------------------------------- + coeffs, braids = self._reduce_all_gen_powers(braid.Tietze()) + + # ----------------------------------------------------------------------------------------------------- + # in the second step the images of these "reduced" braids is calculated + # ----------------------------------------------------------------------------------------------------- + result = self.zero() + for i in range(len(coeffs)): + braid_image = self._braid_image_from_reduced_powers(braids[i]) + result += coeffs[i]*braid_image + + return result + + + + + # ------------------------------------------------------------------------------------------------------------- + # _braid_image_from_reduced_powers + # ------------------------------------------------------------------------------------------------------------- + @cached_method + def _braid_image_from_reduced_powers(self, braid_tietze): + r""" + Return the image of a braid in ``self`` asuming that no successive repetitions occur in the Tietze form + of the braid. + + INPUT: + + - ``braid_tietze`` -- tuple representing the Braid whose image in ``self`` should be computed. It is assumed + that no successive repetitions occur among the entries (i.e. (1,1) is not allowed but (1, -2, 1) is) + + OUTPUT: + + The image of the braid as an element of ``self``. + + EXAMPLES:: + + sage: CHA3 = algebras.CubicHecke(3) + sage: CHA3._braid_image_from_reduced_powers((1, -2, 1)) + c0*c1^-1*c0 + sage: CHA3._braid_image_from_reduced_powers((1, -2, 1, 2)) + (-v)*c1*c0^-1 + u*c0*c1*c0^-1 + w*c0^-1*c1*c0^-1 + """ + n = self.ngens() + braid_list = list(braid_tietze) + len_braid = len(braid_list) + + # --------------------------------------------------------------------------------------------------- + # in the case of two strands we calculate the power of the generator + # --------------------------------------------------------------------------------------------------- + if n == 1 : + if len_braid == 0 : + return self.one() + k = braid_tietze[0 ]*len_braid + result_vect = self._reduce_gen_power(k) + result = self.from_vector(result_vect) + return result + + # --------------------------------------------------------------------------------------------------- + # Try to use former calculations (from dynamic library) to obtain the braid image + # --------------------------------------------------------------------------------------------------- + result, word_decomposition = self._braid_image_from_former_calculations(braid_tietze) + + if word_decomposition == None: + return result + + # --------------------------------------------------------------------------------------------------- + # proceed the calculation by use of the regular representation matrices (given by Ivan Marin) + # or in case of more than 4 strands by extension of the finite sub basis + # --------------------------------------------------------------------------------------------------- + + if n > 3 and (n in braid_tietze or -n in braid_tietze) : # more than four strands + # --------------------------------------------------------------------------------------------------- + # matrices for the regular representation are at the moment just available in the case of less than + # five strands. In the higher cases the basis is realized to grow up from the basis on 4 strands + # to use the recursion, only those cubic braids are stored as new basis elements if they involve + # the generator with largest index + # --------------------------------------------------------------------------------------------------- + return self._braid_image_by_basis_extension(braid_tietze) + + + word_left, word_result, word_right = word_decomposition + + result_vect = None + + if word_left != None: + # -------------------------------------------------------------------------------------- + # Operating from the left on the precalculated result + # -------------------------------------------------------------------------------------- + + vect = result.to_vector() + braid_preimage = tuple(word_result) + result_vect = self._mult_by_regular_rep(vect, tuple(word_left), RepresentationType.RegularLeft, braid_preimage) + + if word_right != None: + # -------------------------------------------------------------------------------------- + # Operating from the right on the precalculated result + # -------------------------------------------------------------------------------------- + if result_vect != None: + vect = result_vect + braid_preimage = tuple(word_left + word_result) + else: + vect = result.to_vector() + braid_preimage = tuple(word_result) + result_vect = self._mult_by_regular_rep(vect, tuple(word_right), RepresentationType.RegularRight, braid_preimage) + + result = self.from_vector(result_vect) + + return result + + + + + # ------------------------------------------------------------------------------------------------------------- + # _braid_image_from_former_calculations + # ------------------------------------------------------------------------------------------------------------- + def _braid_image_from_former_calculations(self, braid_tietze): + r""" + Return the image of a braid in ``self`` as far as this can be done by use of former calculations and is sure not to + go into an endless recursion, that is + + - using the cubic Hecke subalgebra on one strand less + - using the file cache. + + If the image can not be calculated from former registered results this method returns None. + Therefore, it is just intended to be used as as step in the complete calculation. + + INPUT: + + - ``braid_tietze`` -- tuple representing the Braid whose image in ``self`` should be computed. The generator + exponents in the braid word are assumed to be 1 or -1 + + OUTPUT: + + A pair (image, basis_factors) where result is an element of ``self`` representing the image of the input if calculation + was possible and None else-wise. If image == None the output basis_factors is given as a list of basis element whose + product equals the input. + + EXAMPLES:: + + sage: CHA3 = algebras.CubicHecke(3) + sage: CHA3._braid_image_from_former_calculations((1, -2, 1)) + (c0*c1^-1*c0, None) + sage: CHA3._braid_image_from_former_calculations((1, -2, 1, 2)) + (c0*c1^-1*c0, ([], [1, -2, 1], [2])) + """ + + n = self.ngens() + braid_list = list(braid_tietze) + len_braid = len(braid_list) + + result = None + + # --------------------------------------------------------------------------------------------------- + # if the braid is in the basis take its image to be the corresponding monomial + # --------------------------------------------------------------------------------------------------- + result = self._tietze_to_finite_sub_basis_monomial(braid_tietze) + if result is not None: + return result, None + + # --------------------------------------------------------------------------------------------------- + # if the braid lies in a subalgebra take its image from there + # --------------------------------------------------------------------------------------------------- + SubAlg = self.cubic_hecke_subalgebra() + if n not in braid_list and -n not in braid_list: + + result = self(SubAlg(braid_tietze)) + verbose("End (%s): %s in smaller algebra" %(braid_list, result) ) + return result, None + + # --------------------------------------------------------------------------------------------------- + # proceed the calculation by splitting self into a product of basis elements and try to simplify + # --------------------------------------------------------------------------------------------------- + braid_group = self.braid_group() + braid = braid_group(braid_tietze) + result = self._braid_image_from_filecache(braid) + if result != None: + + verbose("End from file cache (%s)" %(list(braid_tietze))) + return result, None + + + # --------------------------------------------------------------------------------------------------- + # If we come here len_braid must be larger than 1 (otherwise we already have found in in the basis) + # By recursion we check if the subwords with one generator removed on the left (respectively on the + # right) side contain a subword whose image has already been calculated. We choose the longest + # such subword as our result + # --------------------------------------------------------------------------------------------------- + braid_list_red_left = [braid_tietze[j] for j in range(1 , len_braid)] + braid_list_red_right = [braid_tietze[j] for j in range(len_braid-1 )] + + result_left, word_decomp_left = self._braid_image_from_former_calculations(tuple(braid_list_red_left)) + result_right, word_decomp_right = self._braid_image_from_former_calculations(tuple(braid_list_red_right)) + if word_decomp_left == None: + return result_left, ([braid_tietze[0 ]], braid_list_red_left, []) + + if word_decomp_right == None: + return result_right, ([], braid_list_red_right, [braid_tietze[len_braid-1 ]]) + + word_decomp_left_left, word_decomp_left_result, word_decomp_left_right = word_decomp_left + word_decomp_right_left, word_decomp_right_result, word_decomp_right_right = word_decomp_right + + if len(word_decomp_left_result) >= len(word_decomp_right_result): + return result_left, ([braid_tietze[0 ]] + word_decomp_left_left, word_decomp_left_result, word_decomp_left_right) + else: + return result_right, (word_decomp_right_left, word_decomp_right_result, word_decomp_right_right + [braid_tietze[len_braid-1 ]]) + + + + + # ------------------------------------------------------------------------------------------------------------- + # _braid_image_by_basis_expansion_ + # ------------------------------------------------------------------------------------------------------------- + def _braid_image_by_basis_extension(self, braid_tietze): + r""" + Return the given braid as a new basis element of ``self`` expanding the incomplete order (which is just a part + of the whole basis) in the case of more than 4 strands. + + INPUT: + + - ``braid_tietze`` -- tuple representing the Braid whose image in ``self`` should be computed. The generator + exponents in the braid word are assumed to be 1 or -1 + + OUTPUT: + + An instance of the element class of ``self``. + + EXAMPLES:: + + sage: CHA5 = algebras.CubicHecke(5) + sage: basis_extensions = CHA5.select_filecache_section().basis_extensions + sage: CHA5.reset_filecache(basis_extensions) + sage: CHA5._basis_extension + [[4], [-4]] + sage: CHA5._braid_image_by_basis_extension((4,1)) + c3*c0 + sage: CHA5._basis_extension + [[4], [-4], [4, 1]] + + case where the braid already has an corresponding basis element:: + + sage: CHA5._braid_image_by_basis_extension((1,)) + c0 + sage: CHA5._basis_extension + [[4], [-4], [4, 1]] + + case where the braid doesn't have corresponding basis element but depends on them:: + + sage: CHA5._braid_image_by_basis_extension((1,1)) + Traceback (most recent call last): + ... + NotImplementedError: no algorithm available to calculate braid image of (1, 1) + + """ + cubic_braid = self._cubic_braid_group(braid_tietze) + tup = self._cubic_braid_basis_tuple(cubic_braid) + if tup is not None: + bgrp = self.braid_group() + if bgrp(braid_tietze) != bgrp(tup): + raise NotImplementedError("no algorithm available to calculate braid image of %s" %(str(braid_tietze))) + B = self.basis() + verbose("braid-image %s in Basis" %(str(braid_tietze))) + return self.monomial(B[cubic_braid]) + + return self._cubic_braid_append_to_basis(cubic_braid) + + + + + + + + + + + # ------------------------------------------------------------------------------------------------------------- + # _reduce_all_gen_powers + # ------------------------------------------------------------------------------------------------------------- + def _reduce_all_gen_powers(self, braid_tietze): + r""" + Return a linear combination of braids that have no higher powers in the braid generators having the same + image in ``self`` than the given braid. This linear combination is returned as a pair of lists of braids + and corresponding coefficients. + + INPUT: + + - ``braid_tietze`` -- tuple representing the Braid whose powers should be reduced given in Tietze form + + OUTPUT: + + A pair of two lists: ``coeffs``, ``braids``. The fist one contains the coefficients corresponding to the braids + in Tietze form from the second list of braids. + + EXAMPLES:: + + sage: CHA3 = algebras.CubicHecke(3) + sage: CHA3._reduce_all_gen_powers((1, 1, -2, -2)) + ([(w^-1)*u*v, (-w^-1)*v, (-w^-1)*v^2, (-w^-1)*u^2, (w^-1)*u, (w^-1)*u*v, -u, 1, v], + [(), (2,), (-2,), (1,), (1, 2), (1, -2), (-1,), (-1, 2), (-1, -2)]) + """ + + + braid_list = list(braid_tietze) + len_braid = len(braid_list) + + # ------------------------------------------------------------------------------------------------------------ + # find a higher power position in braid_list + # ------------------------------------------------------------------------------------------------------------ + power=0 + pos =0 + for i in range(len_braid-1 ): + if braid_list[i] != braid_list[i+1 ]: + continue + pos = i + for power in range(1 ,len_braid -pos+1 ): + if pos+power == len_braid: + break + if braid_list[pos] != braid_list[pos+power]: + break + break + + if power == 0 : + verbose("End (%s) no powers" %(braid_list)) + return [self.base_ring().one()], [braid_tietze] + + # ------------------------------------------------------------------------------------------------------------ + # eliminate this power from braid_tietze + # ------------------------------------------------------------------------------------------------------------ + val = braid_list[pos] + if val > 0 : + gen_ind = val + exp = power + else: + gen_ind = -val + exp = -power + + braid_list_start = [braid_list[i] for i in range(pos)] + braid_list_end = [braid_list[i] for i in range(pos+power, len_braid)] + + # ---------------------------------------------------------------------------------------- + # merging the new reduced tuple. Note that all the new tuples are smaller than the + # given one, which will make the recursion terminate + # ---------------------------------------------------------------------------------------- + tuple_one = tuple(braid_list_start + braid_list_end) + tuple_gen = tuple(braid_list_start + [gen_ind] + braid_list_end) + tuple_gen_inv = tuple(braid_list_start + [-gen_ind] + braid_list_end) + + # ---------------------------------------------------------------------------------------- + # convert them to braids (to reduce cancellation of inverses and obvious braid relations) + # Note that this will not increase the length of the word. Thus the recursion still must + # terminate + # ---------------------------------------------------------------------------------------- + braid_group = self.braid_group() + braid_one = braid_group(tuple_one) + braid_gen = braid_group(tuple_gen) + braid_gen_inv = braid_group(tuple_gen_inv) + + # ------------------------------------------------------------------------------------------------------------ + # eliminate all powers from braid_tietze by recursion. The recursion will terminate by the length + # reduction of the Tietze tuple (but not necessarily by the number of generators whose exponent + # must be reduced) + # ------------------------------------------------------------------------------------------------------------ + one_coeffs, one_braids = self._reduce_all_gen_powers(braid_one.Tietze()) + gen_coeffs, gen_braids = self._reduce_all_gen_powers(braid_gen.Tietze()) + gen_inv_coeffs, gen_inv_braids = self._reduce_all_gen_powers(braid_gen_inv.Tietze()) + + cf_one, cf_gen, cf_gen_inv = self._reduce_gen_power(exp) + + one_coeffs = [ cf*cf_one for cf in one_coeffs ] + gen_coeffs = [ cf*cf_gen for cf in gen_coeffs ] + gen_inv_coeffs = [ cf*cf_gen_inv for cf in gen_inv_coeffs ] + + return one_coeffs + gen_coeffs + gen_inv_coeffs, one_braids + gen_braids + gen_inv_braids + + + + + # ------------------------------------------------------------------------------------------------------------- + # _reduce_gen_power + # ------------------------------------------------------------------------------------------------------------- + @cached_method + def _reduce_gen_power(self, k): + r""" + Return the k-th power on an arbitrary generator, for example c0^k. + + + INPUT: + + - ``k`` -- integer giving the power + + OUTPUT: + + A list [coeff_one, coeff_gen, coeff_gen_inverse] of the three coefficients of the generators power in the span of the generator. + + EXAMPLES:: + + sage: CHA2 = algebras.CubicHecke(2) + sage: CHA2._reduce_gen_power(5) + (-u^3*v + 2*u*v^2 + w*u^2 + (-2*w)*v, u^4 + (-3)*u^2*v + + v^2 + 2*w*u, w*u^3 + (-2*w)*u*v + w^2) + """ + + + n = self.ngens() + + # --------------------------------------------------------------------------------------- + # take it from smaller subalgebras if possible + # --------------------------------------------------------------------------------------- + if n > 1 : + + SubAlg = self.cubic_hecke_subalgebra() + return SubAlg._reduce_gen_power(k) + + + # --------------------------------------------------------------------------------------- + # calculate it in the subalgebra on 2 strands + # --------------------------------------------------------------------------------------- + + if k == 0 : + + result_ele = self.one() + result = result_ele.to_vector() + + elif abs(k) == 1 : + + result_ele = self._tietze_to_finite_sub_basis_monomial(tuple([k])) + result = result_ele.to_vector() + + else: + + if k < 0 : + right_vect = self._reduce_gen_power(k+1) + genTietze = (-1 ,) + else: + right_vect = self._reduce_gen_power(k-1) + genTietze = (1 ,) + + result = self._mult_by_regular_rep(right_vect, genTietze, RepresentationType.RegularLeft) + + return result + + + + + # ------------------------------------------------------------------------------------------------------------- + # _mult_by_regular_rep + # ------------------------------------------------------------------------------------------------------------- + def _mult_by_regular_rep(self, vect, gen_tuple, representation_type, braid_preimage=None): + r""" + Return the product of an`element of ``self`` given as a coefficient vector with a sequence (tuple) of generators + (that is a braid word) using regular representation matrices. The multiplication will be performed form left or + right according to the given ``representation_type``. + + INPUT: + + - ``vect`` -- element of ``self`` in vector form (obtained by :meth:`to_vector`) + - ``gen_tuple`` -- list of generators (that is a braid in Tietze form) which operates on ``vect`` + - ``representation_type`` -- instance of :class:`RepresentationType` (one of `RegularLeft` or `RegularRight`) + - ``braid_preimage`` -- (optional) a word representing a braid whose image is vect (if it exist). + This is used to record intermediate results to the dynamic library + + + OUTPUT: + + The coefficient vector resulting after applying the multiplication of all matrices corresponding to the + generators from gen_tuple. + + EXAMPLES:: + + sage: CHA3 = algebras.CubicHecke(3) + sage: CHA3.inject_variables() + Defining c0, c1 + sage: CHA3._mult_by_regular_rep(c0.to_vector(), (1, -2, -2), CHA3.repr_type.RegularRight) + ((w^-1)*u*v, (-w^-1)*u^2, -u, (-w^-1)*v, (-w^-1)*v^2, (w^-1)*u, (w^-1)*u*v, 1, v, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) + """ + verbose("Multiply %s (preimage %s) by %s using %s" %(vect, braid_preimage, gen_tuple, representation_type)) + l = len(gen_tuple) + braid_list = None + if braid_preimage: + braid_list = list(braid_preimage) + + result = vect + for i in range(l): + verbose("Multiply image of %s with position %s" %(braid_list, i)) + + if representation_type == RepresentationType.RegularLeft: + gen_ind = gen_tuple[l-i-1 ] + if braid_list: + braid_list = [gen_ind] + braid_list + else: + gen_ind = gen_tuple[i] + if braid_list: + braid_list = braid_list + [gen_ind] + + if (gen_ind, representation_type) in list(self._gens_reg_repres_matrix.keys()): + mat = self._gens_reg_repres_matrix[(gen_ind, representation_type)] + else: + if gen_ind > 0 : + gen = self.gen(gen_ind-1 ) + mat = gen.matrix(representation_type=representation_type) + else: + # data of inverse of generators is stored under negative strand-index + gen = self.gen(-gen_ind-1 )**(-1 ) + mat = gen.matrix(representation_type=representation_type) + + self._gens_reg_repres_matrix[(gen_ind, representation_type)] = mat + + result = mat * result + + # ---------------------------------------------------------------------------------- + # save this intermediate result to the dynamic library + # ---------------------------------------------------------------------------------- + if braid_list: + verbose("Save image of %s to file cache" %braid_list) + self._braid_image_to_filecache(tuple(braid_list), result) + + verbose("Multiply %s by %s using %s result %s" %(vect, gen_tuple, representation_type, result)) + return result + + + # ------------------------------------------------------------------------------------------------------------- + # _cubic_braid_append_to_basis + # ------------------------------------------------------------------------------------------------------------- + def _cubic_braid_append_to_basis(self, cubic_braid): + r""" + Append the given cubic braid to the finite sub basis which is used for calculation of products + and representation matrices. This only makes sense if the ``cubic_braid`` is not in this + finite sub basis, before. This can happen if the number of strands is more than 4. + + INPUT: + + - ``cubic_braid`` -- instance of the :class:`~sage.groups.cubic_braid.CubicBraid` whose image in ``self`` should be appended + + OUTPUT: + + The new monomial of ``self``. + + EXAMPLES:: + + sage: CHA5 = algebras.CubicHecke(5) + sage: basis_extensions = CHA5.select_filecache_section().basis_extensions + sage: CHA5.reset_filecache(basis_extensions) + sage: CHA5._basis_extension + [[4], [-4]] + sage: CBG = CHA5.cubic_braid_group() + sage: CHA5._cubic_braid_append_to_basis(CBG((4,1))) + c3*c0 + sage: CHA5._basis_extension + [[4], [-4], [4, 1]] + + """ + cbTietze = list(cubic_braid.Tietze()) + order = self.get_order() + next_index = len(order) + self._basis_extension.append(cbTietze) + self._rank_basis.update({cubic_braid:next_index}) # supporting :meth:`get_order_key` + order.append(cubic_braid) + monomial = self.monomial(cubic_braid) + self._finite_sub_basis_tuples.update({cubic_braid:cbTietze}) + + verbose("Registering new basis element: %s (par %s ind %s)" %(cubic_braid, cubic_braid.parent(), next_index)) + self._filecache.update_basis_extensions(self._basis_extension) + return monomial + + + + # ------------------------------------------------------------------------------------------------------------- + # _cubic_braid_basis_tuple + # ------------------------------------------------------------------------------------------------------------- + def _cubic_braid_basis_tuple(self, cubic_braid): + r""" + Return the Tietze tuple that represents the given cubic_braid in the basis of ``self``. In the case ``self`` + has more than 4 strands it may happen that the given cubic braid is not contained in the finite sub basis, so far. + In this case it is automatically added to it. + + INPUT: + + - ``cubic_braid`` -- instance of the :class:`~sage.groups.cubic_braid.CubicBraid` + + OUTPUT: + + A tuple from the basis representing the cubic braid. + + EXAMPLES:: + + sage: CHA2 = algebras.CubicHecke(2) + sage: CBG = CHA2.cubic_braid_group() + sage: CHA2._cubic_braid_basis_tuple(CBG((1,1))) + (-1,) + """ + tietze_list = self._basis_tietze() + cubic_braid_tietze = cubic_braid.Tietze() + if list(cubic_braid_tietze) in tietze_list: + verbose("cubic_braid_tietze: %s in basis" %(str(cubic_braid_tietze))) + return cubic_braid_tietze + else: + if cubic_braid in self._finite_sub_basis_tuples.keys(): + verbose("cubic_braid: %s in finite_sub_basis" %(cubic_braid)) + return self._finite_sub_basis_tuples[cubic_braid] + + for tup in tietze_list: + cb_tup = self.cubic_braid_group()(tup) + if cubic_braid == cb_tup: + self._finite_sub_basis_tuples.update({cb_tup:tup}) + verbose("cubic_braid: %s added to finite_sub_basis with tuple %s" %(cubic_braid, tup)) + return tuple(tup) + return None + + + # ------------------------------------------------------------------------------------------------------------- + # _cubic_braid_image + # ------------------------------------------------------------------------------------------------------------- + def _cubic_braid_image(self, cubic_braid, check=True): + r""" + Return the given cubic braid as monomial of ``self``, that is the image under the map onto the basis. + If the number of strands is larger than 4, the corresponding basis element may not be + contained in the order of ``self``. In this case it will be appended here. + + INPUT: + + - ``cubic_braid`` -- instance of :class:`~sage.groups.cubic_braid.CubicBraid` whose image in ``self`` should be returned + - ``check`` -- (optional) boolean (default=True) to check in the given cubic braid is already + registered in the finite sub basis. If set to ``False`` duplicate entries can occur. + + OUTPUT: + + Instance of the element class of ``self``. + + EXAMPLES:: + + sage: CHA2 = algebras.CubicHecke(2) + sage: CBG = CHA2.cubic_braid_group() + sage: CHA2._cubic_braid_image(CBG((1,1))) + c^-1 + """ + if check: + tup = self._cubic_braid_basis_tuple(cubic_braid) + if tup is not None: + return self._tietze_to_finite_sub_basis_monomial(tup) + + return self._cubic_braid_append_to_basis(cubic_braid) + + + + # ------------------------------------------------------------------------------------------------------------- + # _extend_braid_automorphism + # ------------------------------------------------------------------------------------------------------------- + def _extend_braid_automorphism(self, element, braid_automorphism): + r""" + Return the image of element under the extension of the given braid group automorphism to ``self``. It is assumed + that the given ``braid_automorphism`` factors through ``self``. + + INPUT: + + - ``element`` -- instance of the element class of ``self`` + - ``braid_autompophism`` -- braid group automophism factoring through ``self`` + + OUTPUT: + + Instance of the element class of ``self`` representing the image of element under the extension of the given braid + group automorphism. + + EXAMPLES:: + + sage: CHA2 = algebras.CubicHecke(2) + sage: br, = CHA2.gens() + sage: CHA2.mirror_isomorphism(br) # indirect doctest + c^-1 + """ + + result = self.zero() + for braid in element.support(): + autom_braid = braid_automorphism(braid) + img_braid = self._braid_image_from_reduced_powers(autom_braid.Tietze()) + result += element[braid] * img_braid + + return result + + + + + ####################################################################################################################### + # --------------------------------------------------------------------------------------------------------------------- + # public methods + # --------------------------------------------------------------------------------------------------------------------- + + ####################################################################################################################### + + def select_filecache_section(self): + r""" + Return the enum to select a section in the file cache. + + EXAMPLES:: + + sage: CHA2 = algebras.CubicHecke(2) + sage: list(CHA2.select_filecache_section()) + [, + , + ] + """ + return self._filecache.section + + def is_filecache_empty(self, section=None): + r""" + Return ``True`` if the file cache of the given ``section`` is empty. If no ``section`` is given + the answer is given for complete file cache. + + INPUT: + + - ``section`` -- (optional, default is ``None`` meaning all sections) instance of enum + :class:`~sage.databases.cubic_hecke_db.CubicHeckeFileCache.section` which can be selected using :meth:`select_filecache_section` + + EXAMPLES:: + + sage: CHA2 = algebras.CubicHecke(2) + sage: CHA2.is_filecache_empty() + False + """ + return self._filecache.is_empty(section=section) + + def reset_filecache(self, section=None, commit=True): + r""" + Reset the file cache of the given ``section`` resp. the complete file cache if no ``section`` is given. + + INPUT: + + - ``section`` -- (optional, default is ``None`` meaning all sections) instance of enum + :class:`~sage.databases.cubic_hecke_db.CubicHeckeFileCache.section` which can be selected using :meth:`select_filecache_section` + + - ``commit`` -- boolean (optional, default is ``True``) if set to ``False`` the reset is not written + to the filesystem. + + + EXAMPLES:: + + sage: CHA5 = algebras.CubicHecke(5) + sage: basis_extensions = CHA5.select_filecache_section().basis_extensions + sage: CHA5.is_filecache_empty(basis_extensions) + False + sage: CHA5.reset_filecache(basis_extensions) + sage: CHA5.is_filecache_empty(basis_extensions) + True + """ + fc = self._filecache + if section == fc.section.basis_extensions: + if self.strands() < 5: + raise ValueError('not allowed for less than 5 strand') + + fc.reset_library(section=section) + + if section == fc.section.basis_extensions: + self._init_basis_extension() + + if commit: + fc.write(section=section) + + def strands(self): + r""" + Return the number of strands of the braid group whose group algebra image is ``self`` + + OUTPUT: Integer. + + EXAMPLES:: + + sage: CHA4 = algebras.CubicHecke(4) + sage: CHA4.strands() + 4 + """ + return self._nstrands + + # ------------------------------------------------------------------------------------------------------------- + # Garside involution + # ------------------------------------------------------------------------------------------------------------- + def garside_involution(self, element): + r""" + Return the image of the given element of ``self`` under the extension of the Garside involution of braids to ``self``. + + This method may be invoked by the ``revert_garside`` method of the element class of ``self``, alternatively. + + INPUT: + + - ``element`` -- instance of the element class of ``self`` + + OUTPUT: + + Instance of the element class of ``self`` representing the image of ``element`` under the extension of the Garside + involution to ``self``. + + EXAMPLES:: + + sage: CHA3 = algebras.CubicHecke(3) + sage: ele = CHA3.an_element() + sage: ele_gar = CHA3.garside_involution(ele); ele_gar + ((w^-1)*u-v) + v*c1 + u*c0 + (-w)*c1*c0^-1 + sage: ele == CHA3.garside_involution(ele_gar) + True + """ + + braid_group = self.braid_group() + reverse_gens = [ g for g in braid_group.gens()] + reverse_gens.reverse() + brgrp_garside_involution = braid_group.hom(reverse_gens, check=False) + + return self._extend_braid_automorphism(element, brgrp_garside_involution) + + + + + + # ------------------------------------------------------------------------------------------------------------- + # orientation anti involution + # ------------------------------------------------------------------------------------------------------------- + def orientation_antiinvolution(self, element): + r""" + Return the image of the given element of ``self`` under the extension of the orientation anti involution of braids to ``self``. + The orientation anti involution of a braid is given by reversing the order of generators in the braid word. + + This method may be invoked by the ``revert_orientation`` method of the element class of ``self``, alternatively. + + INPUT: + + - ``element`` -- instance of the element class of ``self`` + + OUTPUT: + + Instance of the element class of ``self`` representing the image of ``element`` under the extension of the orientation + reversing braid involution to ``self``. + + EXAMPLES:: + + sage: CHA3 = algebras.CubicHecke(3) + sage: ele = CHA3.an_element() + sage: ele_ori = CHA3.orientation_antiinvolution(ele); ele_ori + ((w^-1)*u-v) + u*c1 + v*c0 + (-w)*c1^-1*c0 + sage: ele == CHA3.orientation_antiinvolution(ele_ori) + True + """ + + braid_group = self.braid_group() + def brgrp_orientation_antiinvolution(braid): + braid_list = list(braid.Tietze()) + braid_list.reverse() + return braid_group(tuple(braid_list)) + + return self._extend_braid_automorphism(element, brgrp_orientation_antiinvolution) + + + + # ------------------------------------------------------------------------------------------------------------- + # mirror isomorphism + # ------------------------------------------------------------------------------------------------------------- + def mirror_isomorphism(self, element): + r""" + Return the image of the given element of ``self`` under the extension of the mirror involution of braids to ``self``. + The mirror involution of a braid is given by inverting all generators in the braid word. It does not + factor through ``self`` over the base ring but it factors through ``self`` considered as a $\ZZ$-module relative to the + mirror automorphism of the generic base ring. Considering ``self`` as algebra over its base ring this involution + defines an isomorphism of ``self`` onto a different cubic Hecke algebra with a different cubic equation. This + is defined over a different base (and extension) ring than ``self``. It can be obtained by the method ``mirror_image`` + or as parent of the output of this method. + + This method may be invoked by the ``CubicHeckeElelemnt.revert_mirror`` method of the element class of ``self``, alternatively. + + INPUT: + + - ``element`` -- instance of the element class of ``self`` + + OUTPUT: + + Instance of the element class of the mirror image of ``self`` representing the image of element under the extension of + the braid mirror involution to ``self``. + + EXAMPLES:: + + sage: CHA3 = algebras.CubicHecke(3) + sage: ele = CHA3.an_element() + sage: ele_mirr = CHA3.mirror_isomorphism(ele); ele_mirr + ((-w^-1)*u+v) + ((w^-1)*v)*c1^-1 + ((w^-1)*u)*c0^-1 + (-w^-1)*c0^-1*c1 + sage: ele_mirr2 = ele.revert_mirror() # indirect doctest + sage: ele_mirr == ele_mirr2 + True + sage: par_mirr = ele_mirr.parent() + sage: par_mirr == CHA3 + False + sage: par_mirr == CHA3.mirror_image() + True + sage: ele == par_mirr.mirror_isomorphism(ele_mirr) + True + """ + + mirror_image = self.mirror_image() + braid_group = self.braid_group() + mirror_involution = braid_group.hom([~g for g in braid_group.gens()], check=False) + # Todo: have mirror_involution be a method of :class:`BraidGroup_class` + base_ring_mirror = self._base_ring_mirror + element_vec = vector( [base_ring_mirror(cf) for cf in list(element.to_vector())]) + element_mirr = mirror_image.from_vector(element_vec) + return mirror_image._extend_braid_automorphism(element_mirr, mirror_involution) + + + + + def cubic_equation(self, var='h', as_coefficients=False, generic=False): + r""" + Return the cubic equation attached to ``self``. + + INPUT: + + - ``var`` -- string (optional, default ``h``) setting the indeterminate of the equation + - ``as_coefficients`` -- boolean (optional, default ``False``) if set to ``True`` the + list of coefficients is returned + - ``generic`` -- boolean (optional, default ``False``) if set to ``True`` the cubic + equation will be given over the generic base ring + + OUTPUT: + + A polynomial over the base ring (resp. generic base ring if ``generic`` is set to True). + In case ``as_coefficients`` is set to ``True`` a list of them is returned. + + EXAMPLES:: + + sage: CHA2 = algebras.CubicHecke(2, cubic_equation_roots = (E(3), ~E(3), 1)) + sage: CHA2.cubic_equation() + h^3 - 1 + sage: CHA2.cubic_equation(generic=True) + h^3 - u*h^2 + v*h - w + sage: CHA2.cubic_equation(as_coefficients=True, generic=True) + [-w, v, -u, 1] + sage: CHA2.cubic_equation(as_coefficients=True) + [-1, 0, 0, 1] + """ + + BaseRing = self.base_ring(generic=generic) + + if generic == True: + u, v, w = BaseRing.gens_over_ground() + else: + u, v, w = self._cubic_equation_parameters + + cf = [-w, v, -u, 1 ] + + if as_coefficients == True: + return cf + + from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + P = PolynomialRing(BaseRing, var) + return P(cf) + + + + + def cubic_equation_roots(self, generic=False): + r""" + Return the roots of the underlying cubic equation. + + INPUT: + + - ``generic`` -- boolean (optional, default ``False``) if set to ``True`` the roots + are returned as elements of the generic extension ring + + OUTPUT: + + A tripple consisting of the roots. + + EXAMPLES:: + + sage: CHA2 = algebras.CubicHecke(2, cubic_equation_roots = (3, 4, 5)) + sage: CHA2.cubic_equation() + h^3 - 12*h^2 + 47*h - 60 + sage: CHA2.cubic_equation_roots() + [3, 4, 5] + sage: CHA2.cubic_equation_roots(generic=True) + [a, b, c] + """ + if generic == True: + return self._generic_cubic_equation_roots + else: + return self._cubic_equation_roots + + def cubic_equation_parameters(self, generic=False): + r""" + Return the coefficients of the underlying cubic equation. + + INPUT: + + - ``generic`` -- boolean (optional, default ``False``) if set to ``True`` the coefficients + are returned as elements of the generic base ring + + OUTPUT: + + A tripple consisting of the coefficients. + + EXAMPLES:: + + sage: CHA2 = algebras.CubicHecke(2, cubic_equation_roots = (3, 4, 5)) + sage: CHA2.cubic_equation() + h^3 - 12*h^2 + 47*h - 60 + sage: CHA2.cubic_equation_parameters() + [12, 47, 60] + sage: CHA2.cubic_equation_parameters(generic=True) + [u, v, w] + """ + if generic == True: + return self._generic_cubic_equation_parameters + else: + return self._cubic_equation_parameters + + def base_ring(self, generic=False): + r""" + Return the base ring of the cubic Hecke algebra. + + INPUT: + + - ``generic`` -- boolean (optional, default ``False``) if set to ``True`` the + ring of definition (here often called the generic base ring) is returned + + OUTPUT: + + An instance of :class:`Ring`. If ``generic`` is set ``True`` this will be an + instance of :class:`CubicHeckeRingOfDefinition`, as well. + + EXAMMPLES:: + + sage: CHA2 = algebras.CubicHecke(2, cubic_equation_roots = (3, 4, 5)) + sage: CHA2.base_ring() + Integer Ring localized at (2, 3, 5) + sage: CHA2.base_ring(generic=True) + Multivariate Polynomial Ring in u, v + over Univariate Laurent Polynomial Ring in w over Integer Ring + """ + if generic == True: + return self._ring_of_definition + else: + return self._base_ring + + + def extension_ring(self, generic=False): + r""" + Return the extension ring of the cubic Hecke algebra. This is an extension + of its base ring containing the roots of the cubic equation. + + INPUT: + + - ``generic`` -- boolean (optional, default ``False``) if set to ``True`` the + extension ring of definition (here often called the generic extension ring) + is returned + + OUTPUT: + + An instance of :class:`Ring`. If ``generic`` is set ``True`` this will be an + instance of :class:`CubicHeckeExtensionRing`, as well. + + EXAMMPLES:: + + sage: CHA2 = algebras.CubicHecke(2, cubic_equation_roots = (3, 4, 5)) + sage: CHA2.extension_ring() + Splitting Algebra of T^2 + T + 1 with roots [E3, -E3 - 1] + over Integer Ring localized at (2, 3, 5) + sage: CHA2.extension_ring(generic=True) + Multivariate Laurent Polynomial Ring in a, b, c + over Splitting Algebra of x^2 + x + 1 + with roots [e3, -e3 - 1] over Integer Ring + """ + if generic == True: + return self._generic_extension_ring + else: + return self._extension_ring + + + def cyclotomic_generator(self, generic=False): + r""" + Return the third root of unity as element of the extension ring. + INPUT: + + - ``generic`` -- boolean (optional, default ``False``) if set to ``True`` the + cyclotomic_generator is returned as an element extension ring of definition. + + OUTPUT: + + An element with parent :class:`Ring`. If ``generic`` is set ``True`` the parent will be an + instance of :class:`CubicHeckeExtensionRing`, as well. + + EXAMMPLES:: + + sage: CHA2 = algebras.CubicHecke(2, cubic_equation_roots = (3, 4, 5)) + sage: CHA2.cyclotomic_generator() + E3 + sage: CHA2.cyclotomic_generator(generic=True) + e3 + """ + e3gen = self.extension_ring(generic=True).cyclotomic_generator() + if generic == True: + return e3gen + else: + return self._generic_extension_ring_map(e3gen) + + + + + + def braid_group(self): + r""" + Return the braid group attached to ``self``. + + EXAMPLES:: + + sage: CHA2 = algebras.CubicHecke(2) + sage: CHA2.braid_group() + Braid group on 2 strands + """ + return self._braid_group + + + def cubic_braid_group(self): + r""" + Return the cubic braid group attached to ``self``. + + EXAMPLES:: + + sage: CHA2 = algebras.CubicHecke(2) + sage: CHA2.cubic_braid_group() + Cubic Braid group on 2 strands + """ + return self._cubic_braid_group + + + def braid_group_algebra(self): + r""" + Return the group algebra of braid group attached to ``self`` over the base ring of ``self``. + + EXAMPLES:: + + sage: CHA2 = algebras.CubicHecke(2) + sage: CHA2.braid_group_algebra() + Algebra of Braid group on 2 strands + over Multivariate Polynomial Ring in u, v + over Univariate Laurent Polynomial Ring in w over Integer Ring + """ + return self._braid_group_algebra + + + def cubic_braid_group_algebra(self): + r""" + Return the group algebra of cubic braid group attached to ``self`` over the base ring of ``self``. + + EXAMPLES:: + + sage: CHA2 = algebras.CubicHecke(2) + sage: CHA2.cubic_braid_group_algebra() + Algebra of Cubic Braid group on 2 strands + over Multivariate Polynomial Ring in u, v + over Univariate Laurent Polynomial Ring in w over Integer Ring + """ + return self._cubic_braid_group_algebra + + + + + # ---------------------------------------------------------------------------------- + # creating a CubicHeckeAlgebra as subalgebra of self on less strands + # ---------------------------------------------------------------------------------- + def cubic_hecke_subalgebra( self, nstrands = None): + r""" + Return an instance of :class:`CubicHeckeAlgebra` which realizes a subalgebra of ``self`` on the + first ``n_strands`` strands. + + INPUT: + + - ``nstrands`` -- integer ``> 0`` and `` < self.strands()`` giving the number of strands for the subgroup. + The default is one strand less than ``self`` has + + OUTPUT: + + An instance of this class realizing the subalgebra. + + EXAMPLES:: + + sage: CHA3 = algebras.CubicHecke(3, cubic_equation_roots = (3, 4, 5)) + sage: CHA3.cubic_hecke_subalgebra() + Cubic Hecke algebra on 2 strands + over Integer Ring localized at (2, 3, 5) + with cubic equation: h^3 - 12*h^2 + 47*h - 60 = 0 + """ + + if nstrands == None: + nstrands = self.strands() -1 + + n = self.strands() + + nstrands = ZZ(nstrands) + + if nstrands >= n or nstrands <= 0 : + raise ValueError( "nstrands must be positive and less than %s" %(self.strands()) ) + + + + Gens = self.gens() + + if nstrands == self.strands() -1 and self._cubic_hecke_subalgebra != None: + return self._cubic_hecke_subalgebra + + gen_range = range(nstrands -1 ) + + GensRed = tuple([Gens[i] for i in gen_range]) + + SubHeckeAlg = CubicHeckeAlgebra(names=GensRed, cubic_equation_parameters=tuple(self._cubic_equation_parameters), + cubic_equation_roots=tuple(self._cubic_equation_roots)) + + if nstrands == self.strands() -1 : + self._cubic_hecke_subalgebra = SubHeckeAlg + + return SubHeckeAlg + + + + + # ------------------------------------------------------------------------------------------------------------- + # mirror image + # ------------------------------------------------------------------------------------------------------------- + def mirror_image(self): + r""" + Return a copy of ``self`` with the mirrored cubic equation, that is: the cubic equation has the + inverse roots to the roots with respect to ``self``. This is needed since the mirror involution of the braid + group does not factor through ``self`` (considered as an algebra over the base ring, just considered as ZZ-algebra). + Therefore, the mirror involution of an element of ``self`` belongs to ``mirror_image``. + + OUTPUT: + + An instance of the class of ``self`` over the same base and extension ring, but whose cubic equation is transformed + by the mirror involution applied to its coefficients resp. roots. + + EXAMPLES:: + + sage: CHA2 = algebras.CubicHecke(2) + sage: ce = CHA2.cubic_equation(); ce + h^3 - u*h^2 + v*h - w + sage: CHA2m = CHA2.mirror_image() + sage: cem = CHA2m.cubic_equation(); cem + h^3 + ((-w^-1)*v)*h^2 + ((w^-1)*u)*h - w^-1 + sage: mi = CHA2.base_ring().mirror_involution(); mi + Ring endomorphism of Multivariate Polynomial Ring in u, v + over Univariate Laurent Polynomial Ring in w + over Integer Ring + Defn: u |--> (w^-1)*v + v |--> (w^-1)*u + with map of base ring + sage: cem == cem.parent()([mi(cf) for cf in ce.coefficients()]) + True + + Note, that both cubic Hecke algebras have the same ring of definition and identical generic cubic equation:: + + sage: CHA2.cubic_equation(generic=True) == CHA2m.cubic_equation(generic=True) + True + sage: CHA2.cubic_equation() == CHA2m.cubic_equation(generic=True) + True + sage: CHA2.cubic_equation_roots() == CHA2m.cubic_equation_roots(generic=True) + True + sage: a, b, c = CHA2.cubic_equation_roots() + sage: CHA2m.cubic_equation_roots() + [(w^-1)*a^2 + ((-w^-1)*u)*a + (w^-1)*v, + ((-w^-1)*a)*b + (-w^-1)*a^2 + ((w^-1)*u)*a, ((w^-1)*a)*b] + sage: ai, bi, ci = _ + sage: ai == ~a, bi == ~b, ci == ~c + (True, True, True) + sage: CHA2.extension_ring(generic=True).mirror_involution() + Ring endomorphism of Multivariate Laurent Polynomial Ring in a, b, c + over Splitting Algebra of x^2 + x + 1 + with roots [e3, -e3 - 1] over Integer Ring + Defn: a |--> a^-1 + b |--> b^-1 + c |--> c^-1 + with map of base ring + + the mirror image can not be obtained for specialized cubic Hecke algebras if the specialization does not factor through + the mirror involution on the ring if definition:: + + sage: CHA2s = algebras.CubicHecke(2, cubic_equation_roots = (3, 4, 5)); CHA2s + Cubic Hecke algebra on 2 strands + over Integer Ring localized at (2, 3, 5) + with cubic equation: h^3 - 12*h^2 + 47*h - 60 = 0 + + In the next example it isn't clear what the mirror image of ``7`` should be:: + + sage: CHA2s.mirror_image() + Traceback (most recent call last): + ... + RuntimeError: base ring Integer Ring localized at (2, 3, 5) + does not factor through mirror involution + """ + + base_ring = self.base_ring() + base_gen = self.base_ring(generic=True) + + base_gen_mirror = base_gen.mirror_involution() + base_ring_mirror = self._base_ring_mirror + if not base_ring_mirror: + mirr_paras_gen = [base_gen_mirror(par) for par in self.cubic_equation_parameters(generic=True)] + mirr_paras = [base_ring(mirr_para) for mirr_para in mirr_paras_gen] + try: + base_ring_mirror = base_ring.hom(mirr_paras) + except (TypeError, ValueError, NotImplementedError): + raise RuntimeError("base ring %s does not factor through mirror involution" %(base_ring)) + + # check for involution + mirr_paras_back = [base_ring_mirror(mirr_para) for mirr_para in mirr_paras] + if mirr_paras_back != self.cubic_equation_parameters(): + raise RuntimeError("base ring %s does not factor through mirror involution" %(base_ring)) + + self._base_ring_mirror = base_ring_mirror + + mirror_image = self._mirror_image + if mirror_image == None: + extension_ring = self.extension_ring() + extension_gen = self.extension_ring(generic=True) + extension_gen_mirror = extension_gen.mirror_involution() + + mirr_paras_gen = [base_gen_mirror(par) for par in self.cubic_equation_parameters(generic=True)] + mirr_roots_gen = [extension_gen_mirror(root) for root in self.cubic_equation_roots(generic=True)] + + mirr_paras = tuple([base_ring(par) for par in mirr_paras_gen]) + mirr_roots = tuple([extension_ring(root) for root in mirr_roots_gen]) + n = self.strands() + + mirror_image = CubicHeckeAlgebra(n, cubic_equation_parameters=mirr_paras, cubic_equation_roots=mirr_roots ) + + # go back by involution property + mirror_image._mirror_image = self + mirror_image._base_ring_mirror = base_ring_mirror + mirror_image._ring_of_definition._mirror_ = base_gen_mirror + mirror_image._is_mirror = True + + self._mirror_image = mirror_image + + return mirror_image + + + + # ------------------------------------------------------------------------------------------------------------- + # Schur elements + # ------------------------------------------------------------------------------------------------------------- + def schur_elements(self, generic=False): + r""" + Return the list of Schur elements of ``self`` as elements + of the extension ring of ``self``. + + This method needs *GAP3* installed with package *CHEVIE* + + INPUT: + + - ``generic`` -- boolean (default False). If set to ``True`` + the element is returned as element of the generic + extension ring + + EXAMPLES:: + + sage: CHA3 = algebras.CubicHecke(3) # optional gap3 + sage: sch_eles = CHA3.schur_elements() # optional gap3 + sage: sch_eles[6] # optional gap3 + (w^-1)*u^3 + (w^-2)*v^3 + (-6*w^-1)*u*v + 8 + """ + gap3_result = self.chevie().SchurElements() + GER = self.extension_ring(generic=True) + generic_result = [GER(s) for s in gap3_result] + if generic: + return [s for s in generic_result] + else: + ER = self.extension_ring() + return [ER(s) for s in generic_result] + + + # ------------------------------------------------------------------------------------------------------------- + # Schur element + # ------------------------------------------------------------------------------------------------------------- + def schur_element(self, item, generic=False): + r""" + Return a single Schur element of ``self`` as elements + of the extension ring of ``self``. + + This method needs *GAP3* installed with package *CHEVIE* + + INPUT: + + - ``item`` -- instance of Enum :class:`AbsIrreducibeRep` to give + the irreducible representation of ``self`` to which the Schur + element should be returned + - ``generic`` -- boolean (default False). If set to True + the element is returned as element of the generic + extension ring + + EXAMPLES:: + + sage: CHA3 = algebras.CubicHecke(3) # optional gap3 + sage: CHA3.schur_element(CHA3.irred_repr.W3_111) # optional gap3 + (w^-1)*u^3 + (w^-2)*v^3 + (-6*w^-1)*u*v + 8 + """ + if not isinstance(item, AbsIrreducibeRep): + raise ValueError('item must be an instance of %s' %(AbsIrreducibeRep)) + return self.schur_elements(generic=generic)[item.gap_index()] diff --git a/src/sage/algebras/hecke_algebras/matrix_representations/__init__.py b/src/sage/algebras/hecke_algebras/matrix_representations/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/src/sage/algebras/hecke_algebras/matrix_representations/cubic_hecke_matrix_rep.py b/src/sage/algebras/hecke_algebras/matrix_representations/cubic_hecke_matrix_rep.py new file mode 100644 index 00000000000..cebfb979f26 --- /dev/null +++ b/src/sage/algebras/hecke_algebras/matrix_representations/cubic_hecke_matrix_rep.py @@ -0,0 +1,994 @@ +# -*- coding: utf-8 -*- +r""" +Cubic Hecke matrix representations + +This module contains the class :class:`CubicHeckeMatrixRep` which is used to handle the matrix representations of the +elements of the cubic Hecke algebra (:class:`~sage.algebras.hecke_algebras.cubic_hecke_algebra.CubicHeckeAlgebra`) +together with its parent class :class:`CubicHeckeMatrixSpace`. Furthermore, it contains enums for their +types (:class:`RepresentationType`) and names (:class:`AbsIrreducibeRep`). + + +AUTHORS: + +- Sebastian Oehms May 2020: initial version +""" + + + + +############################################################################## +# Copyright (C) 2020 Sebastian Oehms +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# (at your option) any later version. +# http://www.gnu.org/licenses/ +############################################################################## + + + +from enum import Enum +from sage.misc.cachefunc import cached_method +from sage.misc.misc import verbose +from sage.rings.integer import Integer +from sage.matrix.matrix_generic_dense import Matrix_generic_dense +from sage.matrix.matrix_space import MatrixSpace +from sage.matrix.constructor import matrix +from sage.matrix.special import block_diagonal_matrix +from sage.databases.cubic_hecke_db import CubicHeckeDataFilename as fn + + + +# -------------------------------------------------------------------------------------- +# Constants +# -------------------------------------------------------------------------------------- + + +# ------------------------------------------- +# Enum for the generators sign (of exponent) +# ------------------------------------------- +class GenSign(Enum): + r""" + Enum class to select the braid generators sign. + + EXAMPLES:: + + sage: import sage.algebras.hecke_algebras.matrix_representations.cubic_hecke_matrix_rep as chmr + sage: chmr.GenSign.pos + + sage: chmr.GenSign.neg + + """ + pos = 1 + neg = -1 + + + +# ------------------------------------------- +# Enum for typ of matrix representation +# ------------------------------------------- +class RepresentationType(Enum): + r""" + Enum class to select a representation type for the cubic Hecke algebra. + + - ``RegularLeft`` -- left regular representations + - ``RegularRight`` -- right regular representations + - ``SplitIrredMarin`` -- split irreducible representations obtained from Ivan Marin's data + - ``SplitIrredChevie`` -- the split irreducible representations obtained from CHEVIE via the GAP3-interface + + EXAMPLES:: + + sage: import sage.algebras.hecke_algebras.matrix_representations.cubic_hecke_matrix_rep as chmr + sage: chmr.RepresentationType.RegularLeft.is_regular() + True + """ + def is_split(self): + r""" + Return True if this representation type is absolutely split, False else-wise. + + EXAMPLES:: + + sage: import sage.algebras.hecke_algebras.matrix_representations.cubic_hecke_matrix_rep as chmr + sage: chevie = chmr.RepresentationType.SplitIrredChevie + sage: chevie.is_split() + True + """ + return self.value['split'] + + def is_regular(self): + r""" + Return True if this representation type is regular, False else-wise. + + EXAMPLES:: + + sage: import sage.algebras.hecke_algebras.matrix_representations.cubic_hecke_matrix_rep as chmr + sage: reg_left = chmr.RepresentationType.RegularLeft + sage: reg_left.is_regular() + True + """ + return self.value['regular'] + + def data_filename(self): + r""" + Return the name of the data file. For more information see :class:`~sage.databases.cubic_hecke_db.CubicHeckeDataBase`. + + EXAMPLES:: + + sage: import sage.algebras.hecke_algebras.matrix_representations.cubic_hecke_matrix_rep as chmr + sage: reg_left = chmr.RepresentationType.RegularLeft + sage: reg_left.data_filename() + + """ + return self.value['data'] + + def number_of_representations(self, nstrands): + r""" + Return the number of representations existing to that type. + + EXAMPLES:: + + sage: import sage.algebras.hecke_algebras.matrix_representations.cubic_hecke_matrix_rep as chmr + sage: chmr.RepresentationType.SplitIrredChevie.number_of_representations(4) + 24 + sage: chmr.RepresentationType.SplitIrredMarin.number_of_representations(4) + 24 + """ + if self.value['data'] == None: + if nstrands < 1 or nstrands > 5 : + raise ValueError( "nstrands must be between 1 and 5" ) + elif nstrands < 1 or nstrands > 4 : + raise ValueError( "nstrands must be between 1 and 4" ) + return self.value['num_rep'][nstrands-1 ] + + + RegularLeft = {'split':False, 'regular':True, 'data':fn.regular_left, 'num_rep':[1 ,1 ,1 ,1 ]} + RegularRight = {'split':False, 'regular':True, 'data':fn.regular_right, 'num_rep':[1 ,1 ,1 ,1 ]} + SplitIrredMarin = {'split':True, 'regular':False, 'data':fn.irred_split, 'num_rep':[1 ,3 ,7 ,24 ]} + SplitIrredChevie = {'split':True, 'regular':False, 'data':None, 'num_rep':[1 ,3 ,7 ,24 ,30 ]} + + + + +class AbsIrreducibeRep(Enum): + r""" + Enum class to select an absolutely irreducible representation for the cubic Hecke algebra (``CHAn``) on n-strands. + + The names are build as follows: Take the determinant of one of the generators of the ``CHAn``. This is a monomial + in the the generic extension ring (``GER``) of ``CHA``, say ``a^ib^jc^k`` where ``a, b`` and ``c`` are the generators + of ``GER``. This does not depend on the choice of the generator of ``CHA``, since these are conjugated to each other. + This monomial might be looked as the weight of the representation. Therefore we use as a name: + + ``Wn_ijk`` + + The only ambiguity among the available irreducible representations occurs for the two nine-dimensional modules, which + are conjugated to each other and distinguished by these names: + + ``W4_333`` and ``W4_333bar`` + + Examples of names: + + - ``W2_100`` -- one dimensional representation of the cubic Hecke algebra on 2 strands corresponding to the first root + of the cubic equation + - ``W3_111`` -- three dimensional irreducible representation of the cubic Hecke algebra on 3 strands + - ``W4_242`` -- eight dimensional irreducible representation of the cubic Hecke algebra on 4 strands having the second + root of the cubic equation as weight of dimension 4 + + + Alternative names are taken from [MW2012]_ and can be shown by :meth:`alternative_name`. + + EXAMPLES:: + + sage: import sage.algebras.hecke_algebras.matrix_representations.cubic_hecke_matrix_rep as chmr + sage: [irr.name for irr in chmr.AbsIrreducibeRep] + ['W2_100', 'W2_001', 'W2_010', 'W3_100', 'W3_001', 'W3_010', 'W3_011', 'W3_110', + 'W3_101', 'W3_111', 'W4_100', 'W4_001', 'W4_010', 'W4_011', 'W4_110', 'W4_101', + 'W4_111', 'W4_120', 'W4_201', 'W4_012', 'W4_102', 'W4_210', 'W4_021', 'W4_213', + 'W4_132', 'W4_321', 'W4_231', 'W4_123', 'W4_312', 'W4_422', 'W4_224', 'W4_242', + 'W4_333', 'W4_333bar', 'W5_100', 'W5_001', 'W5_010', 'W5_013', 'W5_130', 'W5_301', + 'W5_031', 'W5_103', 'W5_310', 'W5_203', 'W5_032', 'W5_320', 'W5_230', 'W5_023', + 'W5_302', 'W5_033', 'W5_330', 'W5_303', 'W5_163', 'W5_631', 'W5_316', 'W5_136', + 'W5_613', 'W5_361', 'W5_366', 'W5_663', 'W5_636', 'W5_933', 'W5_339', 'W5_393'] + + REFERENCES: + + [MW2012]_ + """ + + def alternative_name(self): + r""" + Return the name of the split irreducible representation for cubic Hecke algebras for up to four strands + as given in [MW2012]_. + + EXAMPLES:: + + sage: import sage.algebras.hecke_algebras.matrix_representations.cubic_hecke_matrix_rep as chmr + sage: chmr.AbsIrreducibeRep.W3_011.alternative_name() + 'Tyz' + """ + return self.value['alt_name'] + + def dimension(self): + r""" + Return the dimension of the representation. + + EXAMPLES:: + + sage: import sage.algebras.hecke_algebras.matrix_representations.cubic_hecke_matrix_rep as chmr + sage: chmr.AbsIrreducibeRep.W3_111.dimension() + 3 + """ + return self.value['dim'] + + def number_gens(self): + r""" + Return the number of generators of the underlying cubic Hecke algebra. + + EXAMPLES:: + + sage: import sage.algebras.hecke_algebras.matrix_representations.cubic_hecke_matrix_rep as chmr + sage: chmr.AbsIrreducibeRep.W3_001.number_gens() + 2 + sage: chmr.AbsIrreducibeRep.W4_001.number_gens() + 3 + """ + return self.value['ngens'] + + def length_orbit(self): + r""" + Return the length of the orbit of this representation under the action of the Galois group of the cubic equation. + + EXAMPLES:: + + sage: import sage.algebras.hecke_algebras.matrix_representations.cubic_hecke_matrix_rep as chmr + sage: chmr.AbsIrreducibeRep.W3_001.length_orbit() + 3 + sage: chmr.AbsIrreducibeRep.W3_111.length_orbit() + 1 + """ + return self.value['len_orbit'] + + def gap_index(self): + r""" + Return the array index of this representation for the access in GAP3 CHEVIE. + + EXAMPLES:: + + sage: import sage.algebras.hecke_algebras.matrix_representations.cubic_hecke_matrix_rep as chmr + sage: chmr.AbsIrreducibeRep.W3_111.gap_index() + 6 + """ + return self.value['gap_ind'] + + def internal_index(self): + r""" + Return the array index of this representation for the internal access. + + EXAMPLES:: + + sage: import sage.algebras.hecke_algebras.matrix_representations.cubic_hecke_matrix_rep as chmr + sage: chmr.AbsIrreducibeRep.W3_111.internal_index() + 6 + """ + return self.value['intern_ind'] + + # ------------------------------------------------------------------------------------------------- + # absolutely irreducible representations corresponding to braids on 2 strands + # ------------------------------------------------------------------------------------------------- + W2_100 = {'alt_name':'Sx', 'dim':1 , 'ngens':1 , 'len_orbit':3 , 'gap_ind': 0 , 'intern_ind': 0 } + W2_001 = {'alt_name':'Sz', 'dim':1 , 'ngens':1 , 'len_orbit':3 , 'gap_ind': 1 , 'intern_ind': 1 } + W2_010 = {'alt_name':'Sy', 'dim':1 , 'ngens':1 , 'len_orbit':3 , 'gap_ind': 2 , 'intern_ind': 2 } + + # ------------------------------------------------------------------------------------------------- + # absolutely irreducible representations corresponding to braids on 3 strands + # ------------------------------------------------------------------------------------------------- + W3_100 = {'alt_name':'Sx', 'dim':1 , 'ngens':2 , 'len_orbit':3 , 'gap_ind': 0 , 'intern_ind': 0 } + W3_001 = {'alt_name':'Sz', 'dim':1 , 'ngens':2 , 'len_orbit':3 , 'gap_ind': 1 , 'intern_ind': 1 } + W3_010 = {'alt_name':'Sy', 'dim':1 , 'ngens':2 , 'len_orbit':3 , 'gap_ind': 2 , 'intern_ind': 2 } + + W3_011 = {'alt_name':'Tyz', 'dim':2 , 'ngens':2 , 'len_orbit':3 , 'gap_ind': 3 , 'intern_ind': 3 } + W3_110 = {'alt_name':'Txy', 'dim':2 , 'ngens':2 , 'len_orbit':3 , 'gap_ind': 4 , 'intern_ind': 4 } + W3_101 = {'alt_name':'Txz', 'dim':2 , 'ngens':2 , 'len_orbit':3 , 'gap_ind': 5 , 'intern_ind': 5 } + + W3_111 = {'alt_name':'V', 'dim':3 , 'ngens':2 , 'len_orbit':1 , 'gap_ind': 6 , 'intern_ind': 6 } + + # ------------------------------------------------------------------------------------------------- + # absolutely irreducible representations corresponding to braids on 4 strands + # ------------------------------------------------------------------------------------------------- + W4_100 = {'alt_name':'Sx', 'dim':1 , 'ngens':3 , 'len_orbit':3 , 'gap_ind': 0 , 'intern_ind': 0 } + W4_001 = {'alt_name':'Sz', 'dim':1 , 'ngens':3 , 'len_orbit':3 , 'gap_ind': 1 , 'intern_ind': 1 } + W4_010 = {'alt_name':'Sy', 'dim':1 , 'ngens':3 , 'len_orbit':3 , 'gap_ind': 2 , 'intern_ind': 2 } + + W4_011 = {'alt_name':'Tyz', 'dim':2 , 'ngens':3 , 'len_orbit':3 , 'gap_ind': 3 , 'intern_ind': 3 } + W4_110 = {'alt_name':'Txy', 'dim':2 , 'ngens':3 , 'len_orbit':3 , 'gap_ind': 4 , 'intern_ind': 4 } + W4_101 = {'alt_name':'Txz', 'dim':2 , 'ngens':3 , 'len_orbit':3 , 'gap_ind': 5 , 'intern_ind': 5 } + + W4_111 = {'alt_name':'V', 'dim':3 , 'ngens':3 , 'len_orbit':1 , 'gap_ind': 6 , 'intern_ind': 6 } + + W4_120 = {'alt_name':'Uyx', 'dim':3 , 'ngens':3 , 'len_orbit':6 , 'gap_ind': 7 , 'intern_ind': 7 } + W4_201 = {'alt_name':'Uxz', 'dim':3 , 'ngens':3 , 'len_orbit':6 , 'gap_ind': 8 , 'intern_ind': 8 } + W4_012 = {'alt_name':'Uzy', 'dim':3 , 'ngens':3 , 'len_orbit':6 , 'gap_ind': 9 , 'intern_ind': 9 } + W4_102 = {'alt_name':'Uzx', 'dim':3 , 'ngens':3 , 'len_orbit':6 , 'gap_ind': 10 , 'intern_ind': 10 } + W4_210 = {'alt_name':'Uxy', 'dim':3 , 'ngens':3 , 'len_orbit':6 , 'gap_ind': 11 , 'intern_ind': 11 } + W4_021 = {'alt_name':'Vyz', 'dim':3 , 'ngens':3 , 'len_orbit':6 , 'gap_ind': 12 , 'intern_ind': 12 } + + W4_213 = {'alt_name':'Vzxy', 'dim':6 , 'ngens':3 , 'len_orbit':6 , 'gap_ind': 13 , 'intern_ind': 13 } + W4_132 = {'alt_name':'Vyzx', 'dim':6 , 'ngens':3 , 'len_orbit':6 , 'gap_ind': 14 , 'intern_ind': 14 } + W4_321 = {'alt_name':'Vxyz', 'dim':6 , 'ngens':3 , 'len_orbit':6 , 'gap_ind': 15 , 'intern_ind': 15 } + W4_231 = {'alt_name':'Vyxz', 'dim':6 , 'ngens':3 , 'len_orbit':6 , 'gap_ind': 16 , 'intern_ind': 16 } + W4_123 = {'alt_name':'Vzyx', 'dim':6 , 'ngens':3 , 'len_orbit':6 , 'gap_ind': 17 , 'intern_ind': 17 } + W4_312 = {'alt_name':'Vxzy', 'dim':6 , 'ngens':3 , 'len_orbit':6 , 'gap_ind': 18 , 'intern_ind': 18 } + + W4_422 = {'alt_name':'Wx', 'dim':8 , 'ngens':3 , 'len_orbit':3 , 'gap_ind': 19 , 'intern_ind': 19 } + W4_224 = {'alt_name':'Wz', 'dim':8 , 'ngens':3 , 'len_orbit':3 , 'gap_ind': 20 , 'intern_ind': 20 } + W4_242 = {'alt_name':'Wy', 'dim':8 , 'ngens':3 , 'len_orbit':3 , 'gap_ind': 21 , 'intern_ind': 21 } + + W4_333 = {'alt_name':'X', 'dim':9 , 'ngens':3 , 'len_orbit':2 , 'gap_ind': 22 , 'intern_ind': 22 } + W4_333bar = {'alt_name':'Xbar', 'dim':9 , 'ngens':3 , 'len_orbit':2 , 'gap_ind': 23 , 'intern_ind': 23 } + + + # ------------------------------------------------------------------------------------------------- + # absolutely irreducible representations corresponding to braids on 5 strands + # ------------------------------------------------------------------------------------------------- + W5_100 = {'alt_name':None, 'dim':1 , 'ngens':4 , 'len_orbit':3 , 'gap_ind': 0 , 'intern_ind': 0 } + W5_001 = {'alt_name':None, 'dim':1 , 'ngens':4 , 'len_orbit':3 , 'gap_ind': 1 , 'intern_ind': 1 } + W5_010 = {'alt_name':None, 'dim':1 , 'ngens':4 , 'len_orbit':3 , 'gap_ind': 2 , 'intern_ind': 2 } + + W5_013 = {'alt_name':None, 'dim':4 , 'ngens':4 , 'len_orbit':6 , 'gap_ind': 3 , 'intern_ind': 3 } + W5_130 = {'alt_name':None, 'dim':4 , 'ngens':4 , 'len_orbit':6 , 'gap_ind': 4 , 'intern_ind': 4 } + W5_301 = {'alt_name':None, 'dim':4 , 'ngens':4 , 'len_orbit':6 , 'gap_ind': 5 , 'intern_ind': 5 } + W5_031 = {'alt_name':None, 'dim':4 , 'ngens':4 , 'len_orbit':6 , 'gap_ind': 6 , 'intern_ind': 6 } + W5_103 = {'alt_name':None, 'dim':4 , 'ngens':4 , 'len_orbit':6 , 'gap_ind': 7 , 'intern_ind': 7 } + W5_310 = {'alt_name':None, 'dim':4 , 'ngens':4 , 'len_orbit':6 , 'gap_ind': 8 , 'intern_ind': 8 } + + W5_203 = {'alt_name':None, 'dim':5 , 'ngens':4 , 'len_orbit':6 , 'gap_ind': 9 , 'intern_ind': 9 } + W5_032 = {'alt_name':None, 'dim':5 , 'ngens':4 , 'len_orbit':6 , 'gap_ind': 10 , 'intern_ind': 10 } + W5_320 = {'alt_name':None, 'dim':5 , 'ngens':4 , 'len_orbit':6 , 'gap_ind': 11 , 'intern_ind': 11 } + W5_230 = {'alt_name':None, 'dim':5 , 'ngens':4 , 'len_orbit':6 , 'gap_ind': 12 , 'intern_ind': 12 } + W5_023 = {'alt_name':None, 'dim':5 , 'ngens':4 , 'len_orbit':6 , 'gap_ind': 13 , 'intern_ind': 13 } + W5_302 = {'alt_name':None, 'dim':5 , 'ngens':4 , 'len_orbit':6 , 'gap_ind': 14 , 'intern_ind': 14 } + + W5_033 = {'alt_name':None, 'dim':6 , 'ngens':4 , 'len_orbit':3 , 'gap_ind': 15 , 'intern_ind': 15 } + W5_330 = {'alt_name':None, 'dim':6 , 'ngens':4 , 'len_orbit':3 , 'gap_ind': 16 , 'intern_ind': 16 } + W5_303 = {'alt_name':None, 'dim':6 , 'ngens':4 , 'len_orbit':3 , 'gap_ind': 17 , 'intern_ind': 17 } + + W5_163 = {'alt_name':None, 'dim':10 , 'ngens':4 , 'len_orbit':6 , 'gap_ind': 18 , 'intern_ind': 18 } + W5_631 = {'alt_name':None, 'dim':10 , 'ngens':4 , 'len_orbit':6 , 'gap_ind': 19 , 'intern_ind': 19 } + W5_316 = {'alt_name':None, 'dim':10 , 'ngens':4 , 'len_orbit':6 , 'gap_ind': 20 , 'intern_ind': 20 } + W5_136 = {'alt_name':None, 'dim':10 , 'ngens':4 , 'len_orbit':6 , 'gap_ind': 21 , 'intern_ind': 21 } + W5_613 = {'alt_name':None, 'dim':10 , 'ngens':4 , 'len_orbit':6 , 'gap_ind': 22 , 'intern_ind': 22 } + W5_361 = {'alt_name':None, 'dim':10 , 'ngens':4 , 'len_orbit':6 , 'gap_ind': 23 , 'intern_ind': 23 } + + W5_366 = {'alt_name':None, 'dim':15 , 'ngens':4 , 'len_orbit':3 , 'gap_ind': 24 , 'intern_ind': 24 } + W5_663 = {'alt_name':None, 'dim':15 , 'ngens':4 , 'len_orbit':3 , 'gap_ind': 26 , 'intern_ind': 25 } + W5_636 = {'alt_name':None, 'dim':15 , 'ngens':4 , 'len_orbit':3 , 'gap_ind': 27 , 'intern_ind': 26 } + + W5_933 = {'alt_name':None, 'dim':15 , 'ngens':4 , 'len_orbit':3 , 'gap_ind': 25 , 'intern_ind': 27 } + W5_339 = {'alt_name':None, 'dim':15 , 'ngens':4 , 'len_orbit':3 , 'gap_ind': 28 , 'intern_ind': 28 } + W5_393 = {'alt_name':None, 'dim':15 , 'ngens':4 , 'len_orbit':3 , 'gap_ind': 29 , 'intern_ind': 29 } + + + + +# ------------------------------------------------------------------------------------------------------------------ +# Definition of CubicHeckeMatrixRep +# -------------------------------------------------------------------------------------------------------- +class CubicHeckeMatrixRep(Matrix_generic_dense): + r""" + Class to supervise the diagonal block matrix structure arising from cubic Hecke algebra-representations. + I is the element class of :class:`CubicHeckeMatrixSpace`. + + EXAMPLES:: + + sage: import sage.algebras.hecke_algebras.matrix_representations.cubic_hecke_matrix_rep as chmr + sage: CHA2. = algebras.CubicHecke(2) + sage: MS = chmr.CubicHeckeMatrixSpace(CHA2) + sage: m1 = MS(c1); m1 + [ a 0 0] + [ 0 b 0] + [ 0 0 -b - a + u] + sage: type(m1) + + sage: m1.block_diagonal_list() + [[a], [b], [-b - a + u]] + + sage: MSo = chmr.CubicHeckeMatrixSpace(CHA2, original=True) + sage: MSo(c1) + [a 0 0] + [0 b 0] + [0 0 c] + + sage: reg_left = chmr.RepresentationType.RegularLeft + sage: MSreg = chmr.CubicHeckeMatrixSpace(CHA2, representation_type=reg_left) + sage: MSreg(c1) + [ 0 -v 1] + [ 1 u 0] + [ 0 w 0] + sage: len(_.block_diagonal_list()) + 1 + """ + + @cached_method + def _get_block(self, ind): + r""" + Return the ``ind``-th submatrix block of ``self`` considered as block diagonal matrix. + + INPUT: + + - ``ind`` -- integer specifying the list index according to :meth:`internal_index` repectively :meth:`gap_index` + + OUTPUT: + + An instance of :class:`Matrix_generic_dense` representing the specified block of ``self``. + + EXAMPLES:: + + sage: CHA2. = algebras.CubicHecke(2) + sage: c1.matrix()._get_block(0) # indirect doctest + [a] + """ + representation_type = self.parent()._representation_type + if not representation_type.is_split(): + return matrix(self) + n = self.parent()._cubic_hecke_algebra.ngens() + s = sum(irr_rep.dimension() for irr_rep in AbsIrreducibeRep if irr_rep.number_gens() == n and irr_rep.internal_index() < ind) + for irr_rep in AbsIrreducibeRep: + if irr_rep.number_gens() == n and irr_rep.internal_index() == ind: + d = irr_rep.dimension() + return matrix(self.submatrix(s, s, d, d)) + raise ValueError('no irreducible representation for this index') + + + @cached_method + def __getitem__(self, item): + r""" + Return the submatrix block of ``self`` considered as block diagonal matrix specified by `item`. + Overloading builtin-method to select a list-item. + + INPUT: + + - ``item`` -- an instance of :class:`AbsIrreducibeRep` specifying an absolute irreducible + representation of the cubic Hecke algebra. Alternatively, it can be specified by list index + (see :meth:`internal_index` repectively :meth:`gap_index`). + + OUTPUT: + + An instance of :class:`Matrix_generic_dense` representing the specified block of ``self``. + + + EXAMPLES:: + + sage: CHA2. = algebras.CubicHecke(2) + sage: c1.matrix()[0] # indirect doctest + [a] + sage: c1.matrix()[CHA2.irred_repr.W2_001] # indirect doctest + [b] + """ + + + if isinstance(item, AbsIrreducibeRep): + representation_type = self.parent()._representation_type + if not representation_type.is_split(): + raise TypeError( "representation type is non split" ) + + ch_algebra = self.parent()._cubic_hecke_algebra + if ch_algebra.strands() != item.number_gens() +1 : + raise TypeError( "representation must have %d generators" %(ch_algebra.strands()-1 ) ) + + ind = item.gap_index() + if representation_type == RepresentationType.SplitIrredMarin: + ind = item.internal_index() + return self._get_block(ind) + elif isinstance(item, (Integer,int)): + return self._get_block(item) + + return super(CubicHeckeMatrixRep, self).__getitem__(item) + + @cached_method + def block_diagonal_list(self): + r""" + Return the list of submatrix blocks of ``self`` considered as block diagonal matrix. + + OUTPUT: + + A list of instances of :class:`Matrix_generic_dense` each of which represents a diagonal block of ``self``. + + + EXAMPLES:: + + sage: CHA2. = algebras.CubicHecke(2) + sage: c1.matrix().block_diagonal_list() + [[a], [b], [-b - a + u]] + """ + representation_type = self.parent()._representation_type + n = self.parent()._cubic_hecke_algebra.strands() + l = representation_type.number_of_representations(n) + return [self._get_block(i) for i in range(l)] + + + +# ------------------------------------------------------------------------------------------------------------------ +# Definition of CubicHeckeMatrixSpace +# -------------------------------------------------------------------------------------------------------- +class CubicHeckeMatrixSpace(MatrixSpace): + r""" + This class defines the matrix space of cubic Hecke algebra-representations. + + INPUT (to the python constructor): + + - ``cubic_hecke_algebra`` -- (default = None) instance of :class:`~sage.algebras.hecke_algebras.cubic_hecke_algebra.cubicHeckeAlgebra` must be given if + `element` fails to be an instance of its element class. + + - ``representation_type`` -- (default RepresentationType.SplitIrredChevie) instance of :class:`RepresentationType` + specifying the type of the represenstation. + + - ``subdivide`` -- boolean (default False) passed to :func:`~sage.matrix.special.block_diagonal_matrix`. + + - ``original`` -- boolean (default False) if set to True the matrix will coefficients in the generic + base / extension ring. + + + EXAMPLES:: + + sage: CHA2. = algebras.CubicHecke(2) + sage: c1.matrix() # indirect doctest + [ a 0 0] + [ 0 b 0] + [ 0 0 -b - a + u] + sage: c1.matrix(original=True) + [a 0 0] + [0 b 0] + [0 0 c] + sage: c1.matrix(representation_type = CHA2.repr_type.RegularLeft) # indirect doctest + [ 0 -v 1] + [ 1 u 0] + [ 0 w 0] + """ + @staticmethod + def __classcall_private__(cls, cubic_hecke_algebra, representation_type=None, subdivide=False, original=False): + r""" + Normalize the arguments to call the ``__init__`` constructor. + + See the documentation in ``__init__``. + + TESTS:: + + sage: import sage.algebras.hecke_algebras.matrix_representations.cubic_hecke_matrix_rep as chmr + sage: CHA2. = algebras.CubicHecke(2) + sage: MS = chmr.CubicHeckeMatrixSpace(CHA2) + sage: TestSuite(MS).run() + """ + from sage.algebras.hecke_algebras.cubic_hecke_algebra import CubicHeckeAlgebra + + if isinstance(cubic_hecke_algebra, CubicHeckeAlgebra) == False: + raise TypeError("cubic_hecke_algebra must be an instance of CubicHeckeAlgebra") + + if representation_type == None: + representation_type = RepresentationType.SplitIrredMarin + + if representation_type == RepresentationType.SplitIrredChevie: + from sage.combinat.root_system.reflection_group_real import is_chevie_available + if not is_chevie_available(): + raise ValueError('CHEVIE is not available') + + base_ring = cubic_hecke_algebra.base_ring(generic=original) + dimension = cubic_hecke_algebra.dimension() + if representation_type.is_split(): + dimension = cubic_hecke_algebra._dim_irr_rep + base_ring = cubic_hecke_algebra.extension_ring(generic=original) + + return super(CubicHeckeMatrixSpace, cls).__classcall__(cls, base_ring, dimension, cubic_hecke_algebra=cubic_hecke_algebra, + representation_type=representation_type, subdivide=subdivide, sparse=True, implementation=Matrix_generic_dense) + + + + def __init__(self, base_ring, dimension, cols, sparse=True, implementation=Matrix_generic_dense, + cubic_hecke_algebra=None, representation_type=RepresentationType.SplitIrredChevie, subdivide=False): + r""" + Python constructor. + + TESTS:: + + sage: import sage.algebras.hecke_algebras.matrix_representations.cubic_hecke_matrix_rep as chmr + sage: CHA3. = algebras.CubicHecke(3) + sage: MS = chmr.CubicHeckeMatrixSpace(CHA3, original=True) + sage: TestSuite(MS).run() # long time + """ + + from sage.algebras.hecke_algebras.cubic_hecke_algebra import CubicHeckeAlgebra + + if isinstance(cubic_hecke_algebra, CubicHeckeAlgebra) == False: + raise TypeError("cubic_hecke_algebra must be an instance of CubicHeckeAlgebra") + + # ------------------------------------------------------------------------------------------------- + # saving input parameters + # ------------------------------------------------------------------------------------------------- + self._cubic_hecke_algebra = cubic_hecke_algebra + self._representation_type = representation_type + self._subdivide = subdivide + + original_base_ring = cubic_hecke_algebra.base_ring(generic=True) + + if representation_type.is_split(): + original_base_ring = cubic_hecke_algebra.extension_ring(generic=True) + specialize = cubic_hecke_algebra._generic_extension_ring_map + else: + specialize = cubic_hecke_algebra._ring_of_definition_map + + verbose("original_base_ring %s base_ring %s" %(original_base_ring, base_ring)) + + self._original_base_ring = original_base_ring + self._specialize = specialize + + super(CubicHeckeMatrixSpace, self).__init__(base_ring, dimension, cols, sparse=sparse, implementation=implementation) + self.Element = CubicHeckeMatrixRep + return + + def __reduce__(self): + r""" + Used for pickling. + + EXAMPLES:: + + sage: CHA2. = algebras.CubicHecke(2) + sage: MS = c1.matrix().parent() + sage: loads(dumps(MS)) == MS # indirect doctest + True + """ + original = self.base_ring() == self._original_base_ring + return CubicHeckeMatrixSpace, (self._cubic_hecke_algebra, self._representation_type, self._subdivide, original) + + + def _element_constructor_(self, x): + r""" + INPUT: + + - ``x`` -- instance of the element class of :class:`~sage.algebras.hecke_algebras.cubic_hecke_algebra.CubicHeckeAlgebra` or an instance + whose parent is in instance of :class:`MatrixSpace` + + EXAMLPES:: + + sage: import sage.algebras.hecke_algebras.matrix_representations.cubic_hecke_matrix_rep as chmr + sage: CHA3. = algebras.CubicHecke(3) + sage: MS = chmr.CubicHeckeMatrixSpace(CHA3, original=True) + sage: m1 = MS._element_constructor_(c1) + sage: isinstance(m1, MS.element_class) + True + sage: isinstance(MS._element_constructor_(m1), MS.element_class) + True + + sage: m = matrix(MS.base_ring(), 12, 12, lambda i, j: 1) + sage: MS._element_constructor_(m) + Traceback (most recent call last): + ... + TypeError: incompatible block structure + """ + # ------------------------------------------------------------------------------------------------- + # checking input and setting the self._cubic_hecke_algebra + # ------------------------------------------------------------------------------------------------- + ch_algebra = self._cubic_hecke_algebra + ele_parent = x.parent() + ori_base_ring = self._original_base_ring + if isinstance(ele_parent, MatrixSpace): + # ToDo: - Find preimage in cubic hecke algebra + d1, d2 = x.dimensions() + if d1 != self.ncols() or d2 != self.nrows(): + raise ValueError('incompatible dimensions!') + + if ele_parent.base_ring() == ori_base_ring: + x = self._specialize_matrix(x) + elif ele_parent.base_ring() != self.base_ring(): + raise ValueError('incompatible base ring!') + x_in_self = self.element_class(self, x) + matrix_list = x_in_self.block_diagonal_list() + matrix = block_diagonal_matrix(matrix_list, subdivide=self._subdivide, sparse=True) + if matrix != x: + raise TypeError( "incompatible block structure" ) + + elif ele_parent == ch_algebra: + mat = ch_algebra._apply_module_morphism(x, self._image_on_basis) + return self(mat) + + else: + raise TypeError( "element must be an instance of CubicHeckeElement or a matrix" ) + + return self.element_class(self, matrix) + + def __call__(self, entries=None, coerce=True, copy=None): + r""" + Perform the instance call. This method needs to be overloaded here + since :class:`MatrixSpace` has an own implementation of it. + + EXAMLPES:: + + sage: import sage.algebras.hecke_algebras.matrix_representations.cubic_hecke_matrix_rep as chmr + sage: CHA2. = algebras.CubicHecke(2) + sage: MS = chmr.CubicHeckeMatrixSpace(CHA2) + sage: MS(c1) + [ a 0 0] + [ 0 b 0] + [ 0 0 -b - a + u] + """ + from sage.algebras.hecke_algebras.cubic_hecke_algebra import CubicHeckeAlgebra + if entries is None: + return super(CubicHeckeMatrixSpace,self).__call__(entries=entries, coerce=coerce, copy=copy) + if not hasattr(entries, 'parent'): + return super(CubicHeckeMatrixSpace,self).__call__(entries=entries, coerce=coerce, copy=copy) + ele_parent = entries.parent() + if not isinstance(ele_parent, (CubicHeckeAlgebra, MatrixSpace)): + return super(CubicHeckeMatrixSpace,self).__call__(entries=entries, coerce=coerce, copy=copy) + return self._element_constructor_(entries) + + + + + def _specialize_matrix(self, mat): + r""" + Return the given matrix specializing the original coefficients + from data import to the base ring of ``self``. + + INPUT: + + - ``mat`` -- matrix over the original base ring + + OUTPUT: + + ``mat`` over the base ring of ``self`` + + EXAMPLES:: + + sage: import sage.algebras.hecke_algebras.matrix_representations.cubic_hecke_matrix_rep as chmr + sage: CHA2. = algebras.CubicHecke(2) + sage: MS = chmr.CubicHeckeMatrixSpace(CHA2) + sage: B = MS._original_base_ring + sage: a, b, c = B.gens() + sage: mat = matrix(B, [[a, b], [0, c]]) + sage: MS._specialize_matrix(mat) + [ a b] + [ 0 -b - a + u] + """ + + base_ring = self.base_ring() + original_base_ring = self._original_base_ring + specialize = self._specialize + + if base_ring == original_base_ring: + return mat + + mat_dict = {k: specialize(original_base_ring(v)) for k, v in mat.dict().items()} + return matrix(base_ring, mat_dict) + + + @cached_method + def _image_on_gen(self, gen_ind): + r""" + Return the matrix list corresponding to the generator given by ``(gen_ind,)`` in Tietze form + under the representation_type of ``self`` from the data-file or via the gap3 interface + + INPUT: + + - ``gen_ind`` -- integer, index of a generator of the cubic Hecke algebra attached to ``self`` + 1. + Negative values correspond to the according inverses. + + EXAMPLES:: + + sage: import sage.algebras.hecke_algebras.matrix_representations.cubic_hecke_matrix_rep as chmr + sage: CHA3. = algebras.CubicHecke(3) + sage: MS = chmr.CubicHeckeMatrixSpace(CHA3) + sage: MS._image_on_gen(1) + [ + [ b 0] [ a 0] [ a 0] + [a], [c], [b], [b*c c], [a*b b], [a*c c], + + [ c 0 0] + [b^2 + a*c b 0] + [ b 1 a] + ] + + sage: CHA2 = CHA3.cubic_hecke_subalgebra() + sage: MSreg = chmr.CubicHeckeMatrixSpace(CHA2, representation_type=CHA2.repr_type.RegularRight) + sage: MSreg._image_on_gen(-1) + [ + [ 0 1 (-w^-1)*u] + [ 0 0 w^-1] + [ 1 0 (w^-1)*v] + ] + """ + + representation_type = self._representation_type + ch_algebra = self._cubic_hecke_algebra + n = ch_algebra.strands() + original_base_ring = self._original_base_ring + + def invert_gen(matr): + r""" + Return the inverse matrix of generators. + """ + cfs = ch_algebra.cubic_equation(as_coefficients=True, generic=True) + fac =-1 /cfs[0 ] + cf0, cf1, cf2, cf3 = [original_base_ring(cf*fac) for cf in cfs] + + matri = cf1*matr.parent().one() + matri += cf2*matr + matri += cf3*matr**2 + d1, d2 = matr.dimensions() + matrI = matrix(original_base_ring, d1, d2, lambda i,j: original_base_ring(matri[i,j])) + return matrI + + + if n == 2 : + if representation_type.is_split(): + # Split representations for n == 2 are missing in CHEVIE and data files + a, b, c = original_base_ring.gens() + matrix_list = [matrix(1 ,1 , [a]), matrix(1 ,1 , [b]), matrix(1 ,1 , [c])] + if gen_ind < 0 : + matrix_list = [invert_gen(mat) for mat in matrix_list] + return matrix_list + + num_rep = representation_type.number_of_representations(n) + + if representation_type == RepresentationType.SplitIrredChevie: + + rep_list = [ ch_algebra._fetch_matrix_list_from_chevie(i+1) for i in range(num_rep) ] + if gen_ind > 0 : + matrix_list = [ rep[gen_ind-1 ] for rep in rep_list ] + else: + matrix_list = [ invert_gen(rep[-gen_ind-1 ]) for rep in rep_list ] + + else: + + database = ch_algebra._database + matrix_list = database.read_matrix_representation(representation_type, gen_ind, n, original_base_ring) + + return matrix_list + + + @cached_method + def _image_on_basis(self, basis_element): + r""" + Return the image of the given basis element of the cubic Hecke algebra in ``self``. + + INUPUT: + + - ``basis_element`` -- instance of :class:`~sage.algebras.hecke_algebras.cubic_hecke_algebra.CubicHeckeElement` which is a monomial + + EXAMPLES:: + + sage: import sage.algebras.hecke_algebras.matrix_representations.cubic_hecke_matrix_rep as chmr + sage: CHA3. = algebras.CubicHecke(3) + sage: MS = chmr.CubicHeckeMatrixSpace(CHA3, original=True) + sage: MS._image_on_basis(c1) + [ a 0 0 0 0 0 0 0 0 0 0 0] + [ 0 c 0 0 0 0 0 0 0 0 0 0] + [ 0 0 b 0 0 0 0 0 0 0 0 0] + [ 0 0 0 b 0 0 0 0 0 0 0 0] + [ 0 0 0 b*c c 0 0 0 0 0 0 0] + [ 0 0 0 0 0 a 0 0 0 0 0 0] + [ 0 0 0 0 0 a*b b 0 0 0 0 0] + [ 0 0 0 0 0 0 0 a 0 0 0 0] + [ 0 0 0 0 0 0 0 a*c c 0 0 0] + [ 0 0 0 0 0 0 0 0 0 c 0 0] + [ 0 0 0 0 0 0 0 0 0 b^2 + a*c b 0] + [ 0 0 0 0 0 0 0 0 0 b 1 a] + """ + + representation_type = self._representation_type + ch_algebra = self._cubic_hecke_algebra + filecache = ch_algebra._filecache + + original_base_ring = self._original_base_ring + + ele_Tietze = basis_element.Tietze() + matrix_list = filecache.read_matrix_representation(representation_type, ele_Tietze, original_base_ring) + if matrix_list is None: + verbose("not in memory %s (Tietze %s)" %(basis_element, ele_Tietze)) + if len(ele_Tietze) == 0 : + matrix_list = ch_algebra._create_matrix_list_for_one(representation_type) + else: + for gen_ind in ele_Tietze: + gen_matrix_list = self._image_on_gen(gen_ind) + if matrix_list == None: + matrix_list = [m for m in gen_matrix_list] + else: + for i in range(len(matrix_list)): + matrix_list[i] *= gen_matrix_list[i] + + filecache.write_matrix_representation(representation_type, ele_Tietze, matrix_list) + verbose("%s saved to memory" %(basis_element)) + + mat = block_diagonal_matrix(matrix_list, subdivide=self._subdivide, sparse=True) + return self._specialize_matrix(mat) + + def zero(self): + r""" + Return the zero element of ``self``. + + EXAMPLES:: + + sage: CHA2. = algebras.CubicHecke(2) + sage: m1 = c1.matrix() + sage: m1rl = c1.matrix(representation_type = CHA2.repr_type.RegularLeft) + sage: z = m1.parent().zero() + sage: zrl = m1rl.parent().zero() + sage: matrix(z) == matrix(zrl), z.is_zero(), zrl.is_zero() + (True, True, True) + sage: z.block_diagonal_list() + [[0], [0], [0]] + sage: zrl.block_diagonal_list() + [ + [0 0 0] + [0 0 0] + [0 0 0] + ] + """ + z = self.element_class(self, super(CubicHeckeMatrixSpace, self).zero()) + z._cubic_hecke_element = self._cubic_hecke_algebra.zero() + z.set_immutable() + return z + + def one(self): + r""" + Return the one element of ``self``. + + EXAMPLES:: + + sage: CHA2. = algebras.CubicHecke(2) + sage: m1 = c1.matrix() + sage: m1rl = c1.matrix(representation_type = CHA2.repr_type.RegularLeft) + sage: o = m1.parent().one() + sage: orl = m1rl.parent().one() + sage: matrix(o) == matrix(orl), o.is_one(), orl.is_one() + (True, True, True) + sage: o.block_diagonal_list() + [[1], [1], [1]] + sage: orl.block_diagonal_list() + [ + [1 0 0] + [0 1 0] + [0 0 1] + ] + """ + o = self.element_class(self, super(CubicHeckeMatrixSpace, self).one()) + o._cubic_hecke_element = self._cubic_hecke_algebra.one() + o.set_immutable() + return o + + def _an_element_(self): + r""" + Return an element of ``self``. + + EXAMPLES:: + + sage: CHA2. = algebras.CubicHecke(2, cubic_equation_roots=(2, 3, 5)) + sage: c1.matrix() + [2 0 0] + [0 3 0] + [0 0 5] + sage: _.parent()._an_element_() + [ 94/3 0 0] + [ 0 187/3 0] + [ 0 0 373/3] + """ + x = self._cubic_hecke_algebra.an_element() + return self(x) + + def some_elements(self): + r""" + Return a generator of elements of ``self``. + + EXAMPLES:: + + sage: CHA2. = algebras.CubicHecke(2, cubic_equation_roots=(2, 3, 5)) + sage: c1.matrix() + [2 0 0] + [0 3 0] + [0 0 5] + sage: list(_.parent().some_elements()) + [ + [ 94/3 0 0] + [ 0 187/3 0] + [ 0 0 373/3] + ] + """ + for x in self._cubic_hecke_algebra.some_elements(): + yield self(x) diff --git a/src/sage/databases/cubic_hecke_db.py b/src/sage/databases/cubic_hecke_db.py new file mode 100644 index 00000000000..dd97f86054f --- /dev/null +++ b/src/sage/databases/cubic_hecke_db.py @@ -0,0 +1,1167 @@ +# -*- coding: utf-8 -*- +r""" +Cubic Hecke Database + +This module contains the class :class:`CubicHeckeDataBase` which serves as an interface to +Ivan Marin's data files with respect to the cubic Hecke algebras. Furthermore, it contains +the class :class:`CubicHeckeFileCache` which enables :class:`CubicHeckeAlgebra` to keep +intermediate results of calculations in the file system. + +AUTHORS: + +- Sebastian Oehms May 2020: initial version +""" + + +############################################################################## +# Copyright (C) 2020 Sebastian Oehms +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# (at your option) any later version. +# http://www.gnu.org/licenses/ +############################################################################## + + +import os +from enum import Enum + +from sage.structure.sage_object import SageObject +from sage.misc.persist import db_save, db, save, load +from sage.misc.misc import verbose +from sage.env import SAGE_SHARE, SAGE_ROOT +from sage.matrix.constructor import matrix, Matrix # uppercase version used in Marin's file `MatricesRegH4.maple` +from sage.rings.integer_ring import ZZ +from sage.algebras.hecke_algebras.base_rings_of_definition.cubic_hecke_base_ring import CubicHeckeRingOfDefinition + + + + + +#---------------------------------------------------------------------------------------------------------------------------- +# functions to convert matrices and ring elements to and from flat python dictionaries in order to save matrices avoiding +# compatibility problems with older or newer sage versions and to save disc space +#---------------------------------------------------------------------------------------------------------------------------- +# conversion of ring element to dictionary +#---------------------------------------------------------------------------------------------------------------------------- +def convert_poly_to_dict_recursive(ring_elem): + r""" + Convert a ring element to a python dictionary recursively using the dict method of it. + By recursion the dictionaries values are converted as well as long as they posses a + ``dict`` method. If the values are sage Integers they are converted into python integers. + + INPUT: + + -- ``ring_elem`` - ring element to be converted into python dictionary + + OUTPUT: + + A python dictionary from which ``ring_elem`` can be reconstructed via element construction by recursion. + The values of the dictionary may be dictionaries again if the parent of ring_elem has a base_ring + different from itself. + + EXAMPLES:: + + sage: from sage.databases.cubic_hecke_db import convert_poly_to_dict_recursive + sage: L.=LaurentPolynomialRing(ZZ, 'c') + sage: P. = L['a,b']; P + Multivariate Polynomial Ring in a, b + over Univariate Laurent Polynomial Ring in c over Integer Ring + sage: elem = 5*b-3*a*~c; elem + (-3*c^-1)*a + 5*b + sage: convert_poly_to_dict_recursive(elem) + {(0, 1): {0: 5}, (1, 0): {-1: -3}} + """ + + dict_res = {} + if hasattr(ring_elem, 'dict'): + ring_elem_dict = ring_elem.dict() + for k in ring_elem_dict.keys(): + dict_res[k] = convert_poly_to_dict_recursive(ring_elem_dict[k]) + else: + if ring_elem in ZZ: + return int(ring_elem) + return ring_elem + return dict_res + + + + + + +#--------------------------------------------------------------------------------------------------------------------------- +# conversion of matrix to dictionary +#--------------------------------------------------------------------------------------------------------------------------- +def convert_mat_to_dict_recursive(mat): + r""" + Convert a matrix to a python dictionary using the dict method of it. Furthermore, the dictionaries + values are converted as well by the convert_poly_to_dict_recursive function. + + INPUT: + + - ``mat`` -- matrix to be converted into python dictionary + + OUTPUT: + + A python dictionary from which mat can be reconstructed via element construction. The values of the + dictionary may be dictionaries again if entries of the matrix have a dict method as well. + + EXAMPLES:: + + sage: from sage.databases.cubic_hecke_db import convert_mat_to_dict_recursive + sage: L.=LaurentPolynomialRing(ZZ, 'c') + sage: P. = L['a,b']; P + Multivariate Polynomial Ring in a, b + over Univariate Laurent Polynomial Ring in c over Integer Ring + sage: mat = matrix(P, [[2*a, -3], [c, 4*b*~c]]); mat + [ 2*a -3] + [ c (4*c^-1)*b] + sage: convert_mat_to_dict_recursive(mat) + {(0, 0): {(1, 0): {0: 2}}, + (0, 1): {(0, 0): {0: -3}}, + (1, 0): {(0, 0): {1: 1}}, + (1, 1): {(0, 1): {-1: 4}}} + """ + + mat_dict = {} + mat_dict_temp = mat.dict() + for k in mat_dict_temp.keys(): + mat_dict[k] = convert_poly_to_dict_recursive(mat_dict_temp[k]) + return mat_dict + + + + +class CubicHeckeDataFilename(Enum): + r""" + Enum for the different data files. The following choices are possible: + + - ``basis`` -- contains the basis for the cubic Hecke algebra up to 4 strands + - ``regular_left`` -- contains the left regular representation matrices of the generators + - ``regular_right`` -- contains the right regular representation matrices of the generators + - ``irred_split`` -- contains representation matrices of the generators of the split irreducible + representations + + + Examples:: + + sage: from sage.databases.cubic_hecke_db import CubicHeckeDataBase + sage: cha_db = CubicHeckeDataBase() + sage: cha_db.filename + + """ + def download(self): + """ + Return the file name to download the data from Ivan Marin's web-page. + + Examples:: + + sage: from sage.databases.cubic_hecke_db import CubicHeckeDataBase + sage: cha_db = CubicHeckeDataBase() + sage: cha_db.filename.basis.download() + 'baseH4.maple' + """ + return self.value[0] + def py(self): + """ + Return the file name under which the data from Ivan Marin's web-page + are stored as python file. + + Examples:: + + sage: from sage.databases.cubic_hecke_db import CubicHeckeDataBase + sage: cha_db = CubicHeckeDataBase() + sage: cha_db.filename.basis.py() + 'baseH4.maple.py' + """ + return '%s.py' %(self.value[0]) + + def sobj(self, nstrands=None): + """ + Return the file name under which the data from Ivan Marin's web-page + is converted into sobj-files. + + INPUT: + + - ``nstrands`` -- Integer number of strands of the underlying braid group + if the data file depends on it. Otherwise use default None + + Examples:: + + sage: from sage.databases.cubic_hecke_db import CubicHeckeDataBase + sage: cha_db = CubicHeckeDataBase() + sage: cha_db.filename.basis.sobj() + 'monomial_basis.sobj' + sage: cha_db.filename.basis.sobj() + 'monomial_basis.sobj' + sage: cha_db.filename.irred_split.sobj(2) + 'irred_split_reprs_2.sobj' + sage: cha_db.filename.regular_left.sobj(3) + 'regular_left_reprs_3.sobj' + """ + if nstrands is None: + return '%s.sobj' %(self.value[1]) + else: + return '%s_%s.sobj' %(self.value[1], nstrands) + + basis = ['baseH4.maple', 'monomial_basis'] + regular_left = ['MatricesRegH4.maple', 'regular_left_reprs'] + regular_right = ['MatricesRegH4right.maple', 'regular_right_reprs'] + irred_split = ['RepresentationsH25', 'irred_split_reprs'] + + + + + +#---------------------------------------------------------------------------------------------------------------------------- +# Class to supply data for the basis and matrix representation for the cubic Hecke algebra +#---------------------------------------------------------------------------------------------------------------------------- +class CubicHeckeDataBase(SageObject): + r""" + Database interface needed for :class:`CubicHeckeAlgebra`. + + The original data are obtained from Ivan Marin's web-page (URL see the example below). In order + to have these data installed during the build process as a sage-package they are converted + as python files into a tarball. This tarball has been created using the method :meth:`create_spkg_tarball`. + + EXAMPLES:: + + sage: from sage.databases.cubic_hecke_db import CubicHeckeDataBase + sage: cha_db = CubicHeckeDataBase() + sage: cha_db._url_marin + 'http://www.lamfa.u-picardie.fr/marin/softs/H4' + """ + + filename = CubicHeckeDataFilename + + def __init__(self): + r""" + Python constructor. + + EXAMPLES:: + + sage: from sage.databases.cubic_hecke_db import CubicHeckeDataBase + sage: from sage.env import SAGE_SHARE + sage: cha_db = CubicHeckeDataBase() + sage: cha_db._import_path_sobj == SAGE_SHARE + '/cubic_hecke_marin/sobj' + True + """ + self._url_marin = 'http://www.lamfa.u-picardie.fr/marin/softs/H4' + + self._package = 'cubic_hecke_marin' + version_file = os.path.join(SAGE_ROOT, 'build/pkgs/%s/package-version.txt' %self._package) + f = open(version_file) + self._version = f.read().splitlines()[0] + f.close() + + self._import_path = os.path.join(SAGE_SHARE, self._package) + self._import_path_py = os.path.join(self._import_path, 'py') + self._import_path_sobj = os.path.join(self._import_path, 'sobj') + + from sage.misc.misc import sage_makedirs + sage_makedirs(self._import_path_py) + sage_makedirs(self._import_path_sobj) + + self._data_library = {} + + def version(self): + r""" + Return the current version. + + EXAMPLES:: + + sage: from sage.databases.cubic_hecke_db import CubicHeckeDataBase + sage: cha_db = CubicHeckeDataBase() + sage: cha_db.version() + '20200513' + """ + return self._version + + def _create_python_file(self, filename): + r""" + Return the data fetched from Iwan Marin's homepage as a python file + such that it can be loaded via `sage_eval`. + + EXAMPLES:: + + sage: from sage.databases.cubic_hecke_db import CubicHeckeDataBase + sage: cha_db = CubicHeckeDataBase() + sage: load(cha_db._create_python_file(cha_db.filename.basis)) # not tested (because of internet access) + Importing data for monomial_basis.sobj from http://www.lamfa.u-picardie.fr/marin/softs/H4/baseH4.maple + sage: len(baseH4) # not tested + 648 + """ + if not isinstance(filename, CubicHeckeDataBase.filename): + raise TypeError('File name must be an instance of enum %s' (CubicHeckeDataBase.filename)) + + import_file = '%s/%s' %(self._import_path_py, filename.py()) + + # import directly from the internet page + from six.moves.urllib.request import urlopen + try: + from urllib.error import HTTPError + except ImportError: + from urllib2 import HTTPError + + try: + url = '%s/%s' %(self._url_marin, filename.download()) + url_data = urlopen(url).read().decode() + print('Importing data for %s from %s' %(filename.sobj(), url)) + preparsed_data =url_data.replace(':=', '=').replace(';', '').replace('^', '**') + f = open(import_file, 'wt') + f.write(preparsed_data) + f.close() + return import_file + except HTTPError: + raise IOError('Data import file %s not found! Internet connection needed!' %(filename)) + + def create_spkg_tarball(self): + r""" + Create a tarball for the sage-package `cubic_heck_marin` in the `upstream` directory. This + utility should only be used by users who know what they do in case of a switch to a new + version of the data files (that is if the original files on Iwan Marin's homepage have changed). + In that case in invocation of `sage -package update cubic_hecke_marin ` and + `sage -package update cubic_hecke_marin` will be necessary. + + EXAMPLES:: + + sage: from sage.databases.cubic_hecke_db import CubicHeckeDataBase + sage: cha_db = CubicHeckeDataBase() + sage: cha_db.create_spkg_tarball() # not tested (because of internet access) + Importing data for monomial_basis.sobj from http://www.lamfa.u-picardie.fr/marin/softs/H4/baseH4.maple + Importing data for regular_left_reprs.sobj from http://www.lamfa.u-picardie.fr/marin/softs/H4/MatricesRegH4.maple + Importing data for regular_right_reprs.sobj from http://www.lamfa.u-picardie.fr/marin/softs/H4/MatricesRegH4right.maple + Importing data for irred_split_reprs.sobj from http://www.lamfa.u-picardie.fr/marin/softs/H4/RepresentationsH25 + py/ + py/MatricesRegH4.maple.py + py/MatricesRegH4right.maple.py + py/RepresentationsH25.py + py/baseH4.maple.py + """ + for filename in CubicHeckeDataBase.filename: + self._create_python_file(filename) + os.system('cd %s; tar -cvjSf %s/upstream/%s-%s.tar.bz2 py' %(self._import_path, SAGE_ROOT, self._package, self._version) ) + + def import_data(self, filename, from_spkg=True): + r""" + EXAMPLES:: + + sage: from sage.databases.cubic_hecke_db import CubicHeckeDataBase + sage: cha_db = CubicHeckeDataBase() + sage: load(cha_db.import_data(cha_db.filename.basis)) + sage: len(baseH4) + 648 + """ + if not isinstance(filename, CubicHeckeDataBase.filename): + raise TypeError('File name must be an instance of enum %s' (CubicHeckeDataBase.filename)) + + import_file = '%s/%s' %(self._import_path_py, filename.py()) + + try: + open(import_file) + return import_file + except IOError: + if from_spkg: + # import from the spkg tarball + print('Importing cubic Hecke database from SPKG!') + os.system('pwd') + os.system('cp src/*.py %s' %(self._import_path_py)) + open(import_file) + return import_file + else: + return self._create_python_file(filename) + + + def create_static_db_marin_basis(self): + r""" + Create the basis of the cubic Hecke algebra according to the original + data from Iwan Marin's home page. + + This method is called during the build procedure for the sage-package. + + EXAMPLES:: + + sage: from sage.databases.cubic_hecke_db import CubicHeckeDataBase + sage: cha_db = CubicHeckeDataBase() + sage: cha_db.create_static_db_marin_basis() + """ + global baseH4 # set by load + load(self.import_data(self.filename.basis)) + + basis_h1 = [] + basis_h2 = [] + basis_h3 = [] + basis_h4 = baseH4 + + len_baseH4 = len(baseH4) + + ind_h1 = [] + ind_h2 = [] + ind_h3 = [] + ind_h4 = range(len_baseH4) + + for i in ind_h4: + set_i = set(baseH4[i]) + if 3 not in set_i and -3 not in set_i: + basis_h3.append( basis_h4[i] ) + ind_h3.append(i) + if 2 not in set_i and -2 not in set_i: + basis_h2.append( basis_h4[i] ) + ind_h2.append(i) + if 1 not in set_i and -1 not in set_i: + basis_h1.append( basis_h4[i] ) + ind_h1.append(i) + + # len_bas_h1 = len(basis_h1); len_bas_h2 = len(basis_h2); len_bas_h3 = len(basis_h3) + + basis = {1:[basis_h1, ind_h1], 2:[basis_h2, ind_h2], 3: [basis_h3, ind_h3], 4:[basis_h4, ind_h4]} + save(basis, '%s/%s' %(self._import_path_sobj, self.filename.basis.sobj()) ) + + + def create_static_db_marin_regular(self, right=False): + r""" + Create the static data base for regular representations of the cubic + Hecke algebra according to the original data from Iwan Marin's home page. + + This method is called during the build procedure for the sage-package. + + The invocations are not active in the doctest, since they cause a ``MemoryError`` + here. To refresh the data base you may call this method in a session. You will + have to wait (maybe up to several minutes)! + + EXAMPLES:: + + sage: from sage.databases.cubic_hecke_db import CubicHeckeDataBase + sage: cha_db = CubicHeckeDataBase() + sage: cha_db.create_static_db_marin_regular() # not tested + sage: cha_db.create_static_db_marin_regular(right=True) # not tested + """ + + base_ring = CubicHeckeRingOfDefinition() + global u, v, w, mm1, mm2, mm3, mm1I, mm2I, mm3I, reps # set in load + u, v, w = base_ring.gens_over_ground() + + if right == False: + fname = self.filename.regular_left + else: + fname = self.filename.regular_right + before = verbose('start loading %s' %fname) + load(self.import_data(fname)) + before = verbose('end loading %s' %fname, t=before) + + + def create_mat(ind_h, mat_h4): + """ + Create restriction of regular representation of H4 to H1, H2 and H3 + """ + + dim_mat = len(ind_h) + mat = matrix(dim_mat, dim_mat, lambda i,j: mat_h4[ind_h[i], ind_h[j]]) + return convert_mat_to_dict_recursive(mat) + + basis = self.read(self.filename.basis) + ind_h1 = basis[1][1] + ind_h2 = basis[2][1] + ind_h3 = basis[3][1] + + representationH ={} + representationH[0] = [[create_mat(ind_h1, mm1)]] + representationH[1] = [[create_mat(ind_h2, mm1)]] + representationH[2] = [[create_mat(ind_h3, mm1), create_mat(ind_h3, mm2)]] + representationH[3] = [[convert_mat_to_dict_recursive(mm1), convert_mat_to_dict_recursive(mm2), convert_mat_to_dict_recursive(mm3)]] + + representationHI ={} + representationHI[0] = [[create_mat(ind_h1, mm1I)]] + representationHI[1] = [[create_mat(ind_h2, mm1I)]] + representationHI[2] = [[create_mat(ind_h3, mm1I), create_mat(ind_h3, mm2I)]] + representationHI[3] = [[convert_mat_to_dict_recursive(mm1I), convert_mat_to_dict_recursive(mm2I), convert_mat_to_dict_recursive(mm3I)]] + from sage.algebras.hecke_algebras.matrix_representations.cubic_hecke_matrix_rep import GenSign + + for i in range(4): + if right == False: + sobj_filename = '%s/%s' %(self._import_path_sobj, self.filename.regular_left.sobj(i+1)) + else: + sobj_filename = '%s/%s' %(self._import_path_sobj, self.filename.regular_right.sobj(i+1)) + + RegularMarinDict = {GenSign.pos:representationH[i], GenSign.neg:representationHI[i]} + save(RegularMarinDict, sobj_filename ) + return + + + def create_static_db_marin_split(self): + r""" + Create the static data base for split irreducible representations of the cubic + Hecke algebra according to the original data from Iwan Marin's home page. + + This method is called during the build procedure for the sage-package. + + EXAMPLES:: + + sage: from sage.databases.cubic_hecke_db import CubicHeckeDataBase + sage: cha_db = CubicHeckeDataBase() + sage: cha_db.create_static_db_marin_split() + """ + # ------------------------------------------------------ + # Ivan Marin's data file uses a, b, c for the variables + # corresponding to the eigenvalues of the cubic equation. + # Therefore, we have to use them temporarily in that way + # ------------------------------------------------------ + base_ring = CubicHeckeRingOfDefinition() + extension_ring = base_ring.extension_ring() + global a, b, c, j + a, b, c = extension_ring.gens() + j = extension_ring.cyclotomic_generator() + + load(self.import_data(self.filename.irred_split)) + + a, b, c = base_ring.gens_over_ground() # now back to usual nameing + cfs = [-c, b, -a, 1] + cfse = [extension_ring(cf/c) for cf in cfs] + + def invert(matr): + """ + Return inverse matrix for generators + """ + + matri = cfse[1]*matr.parent().one() + matri += cfse[2]*matr + matri += cfse[3]*matr**2 + d1, d2 = matr.dimensions() + matrI = matrix(extension_ring, d1, d2, lambda i,j: extension_ring(matri[i,j])) + return matrI + + # ------------------------------------------------------------------------------------------------ + # Restoring the split irreducibles from Iwan Marin's homepage + # ------------------------------------------------------------------------------------------------ + + anz_reps = len(reps) + + representation_h ={} + representation_h[0] = [[convert_mat_to_dict_recursive(Matrix(1,1,[extension_ring.one()]))]] + representation_h[1] = [] + representation_h[2] = [] + representation_h[3] = [] + + representation_hI ={} + representation_hI[0] = representation_h[0] + representation_hI[1] = [] + representation_hI[2] = [] + representation_hI[3] = [] + for i in range( anz_reps ): + repi = reps[i] + if len(repi) != 3: + raise RuntimeError( 'Error at position %d: three generators expected, got: %d' %( i, len(repi))) + mt = [] + mtI = [] + for j in range(3): + mat = matrix(repi[j]) + matI = invert(mat) + mt.append(convert_mat_to_dict_recursive(mat)) + mtI.append(convert_mat_to_dict_recursive(matI)) + + representation_h[3].append( mt ) + representation_hI[3].append( mtI ) + + if i < 7: + mt7 = [ m for m in mt ] + mt7I = [ m for m in mtI ] + mt7.pop() + mt7I.pop() + representation_h[2].append( mt7 ) + representation_hI[2].append( mt7I ) + + if i < 3: + mt3 = [ m for m in mt7 ] + mt3I = [ m for m in mt7I ] + mt3.pop() + mt3I.pop() + representation_h[1].append( mt3 ) + representation_hI[1].append( mt3I ) + + from sage.algebras.hecke_algebras.matrix_representations.cubic_hecke_matrix_rep import GenSign + for i in range(4): + sobj_filename = '%s/%s' %(self._import_path_sobj, self.filename.irred_split.sobj(i+1)) + SplitIrredMarinDict = {GenSign.pos:representation_h[i], GenSign.neg:representation_hI[i]} + save(SplitIrredMarinDict, sobj_filename) + + return + + # ------------------------------------------------------------------------------------------------------------- + # read from an sobj-file obtained from Ivan Marin's database + # ------------------------------------------------------------------------------------------------------------- + def read(self, db_filename, nstrands=None): + r""" + Access various static data library. + + INPUT: + + ``db_filename`` -- instance of enum :class:`CubicHeckeDataBase.filename` + to select the data to be read in + + OUTPUT: + + A dictionary containing the data corresponding to the db_filename. + + EXAMPLES:: + + sage: from sage.databases.cubic_hecke_db import CubicHeckeDataBase + sage: cha_db = CubicHeckeDataBase() + sage: basis = cha_db.read(cha_db.filename.basis) + sage: len(basis[3][0]) + 24 + """ + if not isinstance(db_filename, CubicHeckeDataFilename): + raise TypeError('db_filename must be an instance of enum %s' (CubicHeckeDataBase.filename)) + + data_lib = self._data_library + lib_path = self._import_path_sobj + + if (db_filename, nstrands) in data_lib.keys(): + return data_lib[(db_filename, nstrands)] + + verbose('loading data library %s ...' %(db_filename.sobj(nstrands=nstrands))) + try: + data_lib[(db_filename,nstrands)] = load('%s/%s' %(lib_path, db_filename.sobj(nstrands=nstrands))) + except IOError: + if db_filename == self.filename.basis: + self.create_static_db_marin_basis() + elif db_filename == self.filename.irred_split: + self.create_static_db_marin_split() + elif db_filename == self.filename.regular_right: + self.create_static_db_marin_regular(right=True) + else: + self.create_static_db_marin_regular() + data_lib[(db_filename, nstrands)] = load('%s/%s' %(lib_path, db_filename.sobj(nstrands=nstrands))) + + verbose('... finished!') + + return data_lib[(db_filename,nstrands)] + + + # ------------------------------------------------------------------------------------------------------------- + # matrix_reprs_from_file_cache_ + # ------------------------------------------------------------------------------------------------------------- + def read_matrix_representation(self, representation_type, gen_ind, nstrands, ring_of_definition): + r""" + Return the matrix representations from the database. + + INPUT: + + - ``representation_type`` -- instance of enum :class:`~sage.algebras.hecke_algebras.matrix_representations.cubic_hecke_matrix_rep.RepresentationType` + specifying the type of the representation + + + OUTPUT: + + EXAMPLES:: + + sage: from sage.databases.cubic_hecke_db import CubicHeckeDataBase + sage: CHA3 = algebras.CubicHecke(2) + sage: GER = CHA3.extension_ring(generic=True) + sage: cha_db = CHA3._database + sage: rt = CHA3.repr_type + sage: m1 =cha_db.read_matrix_representation(rt.SplitIrredMarin, 1, 3, GER) + sage: len(m1) + 7 + sage: GBR = CHA3.base_ring(generic=True) + sage: m1rl = cha_db.read_matrix_representation(rt.RegularLeft, 1, 3, GBR) + sage: m1rl[0].dimensions() + (24, 24) + """ + from sage.algebras.hecke_algebras.matrix_representations.cubic_hecke_matrix_rep import RepresentationType, GenSign + if not isinstance(representation_type, RepresentationType): + raise TypeError('representation_type must be an instance of enum %s' (RepresentationType)) + + num_rep = representation_type.number_of_representations(nstrands) + rep_list = self.read(representation_type.data_filename(), nstrands=nstrands) + if gen_ind > 0 : + rep_list = [rep_list[GenSign.pos][i] for i in range(num_rep)] + matrix_list = [matrix(ring_of_definition, rep[gen_ind-1 ], sparse=True) for rep in rep_list] + else: + # data of inverse of generators is stored under negative strand-index + rep_list = [rep_list[GenSign.neg][i] for i in range(num_rep) ] + matrix_list = [matrix(ring_of_definition, rep[-gen_ind-1 ], sparse=True) for rep in rep_list] + for m in matrix_list: m.set_immutable() + return matrix_list + + + + +class CubicHeckeFileCache(SageObject): + """ + A class to cache calculations of the :class:`CubicHeckeAlgebra` in the local file system. + """ + + class section(Enum): + r""" + Enum for the different sections of file cache. The following choices are possible: + + - ``matrix_representations`` -- file cache for representation matrices of basis elements + - ``braid_images`` -- file cache for images of braids + - ``basis_extensions`` -- file cache for a dynamical growing basis used in the case of + cubic Hecke algebras on more than 4 strands + + Examples:: + + sage: from sage.databases.cubic_hecke_db import CubicHeckeFileCache + sage: CHA2 = algebras.CubicHecke(2) + sage: cha_fc = CubicHeckeFileCache(CHA2) + sage: cha_fc.section + + """ + + def filename(self, nstrands=None): + r""" + Return the file name under which the data of this file cache section + is stored as an sobj-file. + + INPUT: + + - ``nstrands`` -- Integer number of strands of the underlying braid group + if the data file depends on it. Otherwise use default None + + Examples:: + + sage: from sage.databases.cubic_hecke_db import CubicHeckeFileCache + sage: CHA2 = algebras.CubicHecke(2) + sage: cha_fc = CubicHeckeFileCache(CHA2) + sage: cha_fc.section.matrix_representations.filename(2) + 'matrix_representations_2.sobj' + sage: cha_fc.section.braid_images.filename(2) + 'braid_images_2.sobj' + """ + if nstrands is None: + return '%s.sobj' %(self.value) + else: + return '%s_%s.sobj' %(self.value, nstrands) + + matrix_representations = 'matrix_representations' + braid_images = 'braid_images' + basis_extensions = 'basis_extensions' + + + def __init__(self, num_strands): + r""" + Python constructor. + + INPUT: + + - ``cubic_hecke_algebra`` -- instance of :class:`CubicHeckeAlgebra` + whose data should be cached in the file system. + + EXAMPLES:: + + sage: from sage.databases.cubic_hecke_db import CubicHeckeFileCache + sage: cha_fc = CubicHeckeFileCache(2) + sage: cha_fc._file_cache_path == 'cubic_hecke' + True + """ + self._nstrands = num_strands + self._file_cache_path = 'cubic_hecke' + self._data_library = {} + + from sage.misc.misc import sage_makedirs + from sage.misc.persist import SAGE_DB + sage_makedirs(os.path.join(SAGE_DB, self._file_cache_path)) + + def reset_library(self, section=None): + r""" + Reset the file cache corresponding to the specified ``section``. + + INPUT: + + - ``section`` -- instance of enum :class:`CubicHeckeFileCache.section` + to select the section of the file cache or ``None`` (default) + meaning all sections + + EXAMPLES:: + + sage: from sage.databases.cubic_hecke_db import CubicHeckeFileCache + sage: cha2_fc = CubicHeckeFileCache(2) + sage: cha2_fc.reset_library(cha2_fc.section.braid_images) + sage: cha2_fc.read(cha2_fc.section.braid_images) + {} + sage: cha2_fc.reset_library(cha2_fc.section.matrix_representations) + sage: data_mat = cha2_fc.read(cha2_fc.section.matrix_representations) + sage: len(data_mat.keys()) + 4 + """ + if section is None: + for sec in self.section: + self.reset_library(section=sec) + return + + if not isinstance(section, CubicHeckeFileCache.section): + raise TypeError('section must be an instance of enum %s' (CubicHeckeFileCache.section)) + + from sage.algebras.hecke_algebras.matrix_representations.cubic_hecke_matrix_rep import RepresentationType + data_lib = self._data_library + empty_dict = {} + if section == self.section.matrix_representations: + for rep_type in RepresentationType: + new_dict={} + empty_dict.update({rep_type:new_dict}) + elif section == self.section.basis_extensions: + empty_dict = [] + data_lib.update({section:empty_dict}) + + + def is_empty(self, section=None): + r""" + Return ``True`` if the cache of the given ``section`` is empty. + + INPUT: + + - ``section`` -- instance of enum :class:`CubicHeckeFileCache.section` + to select the section of the file cache or ``None`` (default) + meaning all sections + + + EXAMPLES:: + + sage: from sage.databases.cubic_hecke_db import CubicHeckeFileCache + sage: cha2_fc = CubicHeckeFileCache(2) + sage: cha2_fc.reset_library() + sage: cha2_fc.is_empty() + True + """ + if section is None: + return all(self.is_empty(section=sec) for sec in self.section) + + if not isinstance(section, CubicHeckeFileCache.section): + raise TypeError('section must be an instance of enum %s' (CubicHeckeFileCache.section)) + + self.read(section) + data_lib = self._data_library[section] + from sage.algebras.hecke_algebras.matrix_representations.cubic_hecke_matrix_rep import RepresentationType + if section == self.section.matrix_representations: + for rep_type in RepresentationType: + if len(data_lib[rep_type]) > 0: + return False + return True + + if section == self.section.basis_extensions and self._nstrands > 4: + # the new generators and their inverses are not counted + # since they are added during initialization + return len(data_lib) <= 2*(self._nstrands -4) + return len(data_lib) == 0 + + + + # ------------------------------------------------------------------------------------------------------------- + # save data file system + # ------------------------------------------------------------------------------------------------------------- + def write(self, section=None): + r""" + Write data from memory to the file system. + + INPUT: + + - ``section`` -- instance of enum :class:`CubicHeckeFileCache.section` + specifying the section where the corresponding cached data belong to. + If omitted data of all sections is written to the file system + + EXAMPLES:: + + sage: from sage.databases.cubic_hecke_db import CubicHeckeFileCache + sage: cha2_fc = CubicHeckeFileCache(2) + sage: cha2_fc.reset_library(cha2_fc.section.braid_images) + sage: cha2_fc.write(cha2_fc.section.braid_images) + """ + data_lib = self._data_library + lib_path = self._file_cache_path + + if section is None: + for sec in self.section: + if sec in data_lib.keys(): + self.write(section=sec) + return + + if not isinstance(section, CubicHeckeFileCache.section): + raise TypeError('section must be an instance of enum %s' (CubicHeckeFileCache.section)) + + if section not in data_lib.keys(): + raise ValueError("No data for file %s in memory" %(section)) + + db_save(data_lib[section], '%s/%s' %(lib_path, section.filename(self._nstrands))) + + + # ------------------------------------------------------------------------------------------------------------- + # read from file system + # ------------------------------------------------------------------------------------------------------------- + def read(self, section): + r""" + Read data into memory from the file system. + + + INPUT: + + - ``section`` -- instance of enum :class:`CubicHeckeFileCache.section` + specifying the section where the corresponding cached data belong to + + OUTPUT: + + Dictionary containing the data library corresponding to the section + of file cache + + EXAMPLES:: + + sage: from sage.databases.cubic_hecke_db import CubicHeckeFileCache + sage: cha2_fc = CubicHeckeFileCache(2) + sage: cha2_fc.reset_library(cha2_fc.section.braid_images) + sage: cha2_fc.read(cha2_fc.section.braid_images) + {} + """ + if not isinstance(section, CubicHeckeFileCache.section): + raise TypeError('section must be an instance of enum %s' (CubicHeckeFileCache.section)) + + data_lib = self._data_library + lib_path = self._file_cache_path + + if section in data_lib.keys(): + return data_lib[section] + + verbose('loading file cache %s ...' %(section)) + try: + data_lib[section] = db('%s/%s' %(lib_path, section.filename(self._nstrands))) + verbose('... finished!') + except IOError: + self.reset_library(section) + verbose('... not found!') + + return data_lib[section] + + + + + # ------------------------------------------------------------------------------------------------------------- + # matrix_reprs_from_file_cache_ + # ------------------------------------------------------------------------------------------------------------- + def read_matrix_representation(self, representation_type, monomial_tietze, ring_of_definition): + r""" + Return the matrix representations of the given monomial (in Tietze form) + if it has been stored in the file cache before. Otherwise ``None`` is returned. + + INPUT: + + - ``representation_type`` -- instance of enum :class:`~sage.algebras.hecke_algebras.matrix_representations.cubic_hecke_matrix_rep.RepresentationType` + specifying the type of the representation + + - ``monomial_tietze`` -- tuple representing the braid in Tietze form + + - ``ring_of_definition`` -- instance of :class:`CubicHeckeRingOfDefinition` resp. + :class:`CubicHeckeExtensionRing` (depending wether ``representation_type`` + is split or not) + + OUTPUT: + + Dictionary containing all matrix representations of ``self`` of the given representation_type + which have been stored in the file cache. + + EXAMPLES:: + + sage: CHA2 = algebras.CubicHecke(2) + sage: R = CHA2.base_ring(generic=True) + sage: cha_fc = CHA2._filecache + sage: g, = CHA2.gens(); gt = g.Tietze() + sage: rt = CHA2.repr_type + sage: g.matrix(representation_type=rt.RegularLeft) + [ 0 -v 1] + [ 1 u 0] + [ 0 w 0] + sage: [_] == cha_fc.read_matrix_representation(rt.RegularLeft, gt, R) + True + sage: cha_fc.reset_library(cha_fc.section.matrix_representations) + sage: cha_fc.write(cha_fc.section.matrix_representations) + sage: cha_fc.read_matrix_representation(rt.RegularLeft, gt, R) == None + True + """ + from sage.algebras.hecke_algebras.matrix_representations.cubic_hecke_matrix_rep import RepresentationType + if not isinstance(representation_type, RepresentationType): + raise TypeError('representation_type must be an instance of enum %s' (RepresentationType)) + + matrix_representations = self.read(self.section.matrix_representations)[representation_type] + if monomial_tietze in matrix_representations.keys(): + matrix_list_dict = matrix_representations[monomial_tietze] + matrix_list = [matrix(ring_of_definition, mat_dict, sparse=True) for mat_dict in matrix_list_dict] + for m in matrix_list: m.set_immutable() + return matrix_list + return None + + + + + # ------------------------------------------------------------------------------------------------------------- + # matrix_representation to file cache + # ------------------------------------------------------------------------------------------------------------- + def write_matrix_representation(self, representation_type, monomial_tietze, matrix_list): + r""" + Write the matrix representation of a monomial to the file cache. + + INPUT: + + - ``representation_type`` -- instance of enum :class:`~sage.algebras.hecke_algebras.matrix_representations.cubic_hecke_matrix_rep.RepresentationType` + specifying the type of the representation + + - ``monomial_tietze`` -- tuple representing the braid in Tietze form + + - ``matrix_list`` -- list of matrices corresponding to the irreducible representations + + EXAMPLES:: + + sage: CHA2 = algebras.CubicHecke(2) + sage: R = CHA2.base_ring(generic=True) + sage: cha_fc = CHA2._filecache + sage: g, = CHA2.gens(); gi = ~g; git = gi.Tietze() + sage: rt = CHA2.repr_type + sage: m = gi.matrix(representation_type=rt.RegularRight) + sage: cha_fc.read_matrix_representation(rt.RegularRight, git, R) + [ + [ 0 1 (-w^-1)*u] + [ 0 0 w^-1] + [ 1 0 (w^-1)*v] + ] + sage: CHA2.reset_filecache(cha_fc.section.matrix_representations) + sage: cha_fc.read_matrix_representation(rt.RegularLeft, git, R) == None + True + sage: cha_fc.write_matrix_representation(rt.RegularRight, git, [m]) + sage: [m] == cha_fc.read_matrix_representation(rt.RegularRight, git, R) + True + """ + from sage.algebras.hecke_algebras.matrix_representations.cubic_hecke_matrix_rep import RepresentationType + if not isinstance(representation_type, RepresentationType): + raise TypeError('representation_type must be an instance of enum %s' (RepresentationType)) + + matrix_representations = self.read(self.section.matrix_representations)[representation_type] + + if monomial_tietze in matrix_representations.keys(): + # entry already registered + return + + matrix_representation_dict = [convert_mat_to_dict_recursive(mat) for mat in list(matrix_list)] + matrix_representations[monomial_tietze] = matrix_representation_dict + + self.write(self.section.matrix_representations) + return + + # ------------------------------------------------------------------------------------------------------------- + # read braid images from file cache + # ------------------------------------------------------------------------------------------------------------- + def read_braid_image(self, braid_tietze, ring_of_definition): + r""" + Return the list of pre calculated braid images from file cache. + + INPUT: + + - ``braid_tietze`` -- tuple representing the braid in Tietze form + + - ``ring_of_definition`` -- instance of :class:`CubicHeckeRingOfDefinition` + + OUTPUT: + + A dictionary containing the pre calculated braid image of the given braid. + + EXAMPLES:: + + sage: from sage.databases.cubic_hecke_db import CubicHeckeFileCache + sage: CHA2 = algebras.CubicHecke(2) + sage: ring_of_definition = CHA2.base_ring(generic=True) + sage: cha_fc = CubicHeckeFileCache(2) + sage: B2 = BraidGroup(2) + sage: b, = B2.gens(); b2 = b**2 + sage: cha_fc.is_empty(CubicHeckeFileCache.section.braid_images) + True + sage: b2_img = CHA2(b2); b2_img + (-v) + u*c + w*c^-1 + sage: cha_fc.write_braid_image(b2.Tietze(), b2_img.to_vector()) + sage: cha_fc.read_braid_image(b2.Tietze(), ring_of_definition) + (-v, u, w) + """ + braid_images = self.read(self.section.braid_images) + if braid_tietze in braid_images.keys(): + braid_image = braid_images[braid_tietze] + result_list = [ring_of_definition(cf) for cf in list(braid_image)] + from sage.modules.free_module_element import vector + return vector(ring_of_definition, result_list) + return None + + + + + + # ------------------------------------------------------------------------------------------------------------- + # braid image to_file cache + # ------------------------------------------------------------------------------------------------------------- + def write_braid_image(self, braid_tietze, braid_image_vect): + r""" + Write the braid image of the given braid to the file cache. + + INPUT: + + - ``braid_tietze`` -- tuple representing the braid in Tietze form + - ``braid_image_vect`` -- image of the given braid as a vector with respect + to the basis of the cubic Hecke algebra + + EXAMPLES:: + + sage: from sage.databases.cubic_hecke_db import CubicHeckeFileCache + sage: CHA2 = algebras.CubicHecke(2) + sage: ring_of_definition = CHA2.base_ring(generic=True) + sage: cha_fc = CubicHeckeFileCache(2) + sage: B2 = BraidGroup(2) + sage: b, = B2.gens(); b3 = b**3 + sage: b3_img = CHA2(b3); b3_img + (-u*v+w) + (u^2-v)*c + w*u*c^-1 + sage: cha_fc.write_braid_image(b3.Tietze(), b3_img.to_vector()) + sage: cha_fc.read_braid_image(b3.Tietze(), ring_of_definition) + (-u*v + w, u^2 - v, w*u) + sage: cha_fc.reset_library(CubicHeckeFileCache.section.braid_images) + sage: cha_fc.write(CubicHeckeFileCache.section.braid_images) + sage: cha_fc.is_empty(CubicHeckeFileCache.section.braid_images) + True + """ + braid_images = self.read(self.section.braid_images) + + if braid_tietze in braid_images.keys(): + # entry already registered + return + + braid_image_dict = [convert_poly_to_dict_recursive(cf) for cf in list(braid_image_vect)] + braid_images[braid_tietze] = braid_image_dict + + self.write(self.section.braid_images) + return + + + # ------------------------------------------------------------------------------------------------------------- + # basis to file cache + # ------------------------------------------------------------------------------------------------------------- + def update_basis_extensions(self, new_basis_extensions): + r""" + Update the file cache for basis extensions for cubic Hecke algebras on more than 4 strands + according to the given ``new_basis_extensions``. + + INPUT: + + - ``new_basis_extensions`` -- list of additional (to the static basis) basis elements which should + replace the former such list in the file. + + EXAMPLES:: + + sage: from sage.databases.cubic_hecke_db import CubicHeckeFileCache + sage: CHA2 = algebras.CubicHecke(2) + sage: cha_fc = CubicHeckeFileCache(2) + sage: cha_fc.is_empty(CubicHeckeFileCache.section.basis_extensions) + True + sage: cha_fc.update_basis_extensions([(1,), (-1,)]) + sage: cha_fc.read(CubicHeckeFileCache.section.basis_extensions) + [(1,), (-1,)] + sage: cha_fc.reset_library(CubicHeckeFileCache.section.basis_extensions) + sage: cha_fc.write(CubicHeckeFileCache.section.basis_extensions) + sage: cha_fc.is_empty(CubicHeckeFileCache.section.basis_extensions) + True + """ + self._data_library.update({self.section.basis_extensions:new_basis_extensions}) + self.write(self.section.basis_extensions) + return