Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
""" Elements of Finite Algebras """
#***************************************************************************** # Copyright (C) 2011 Johan Bosman <johan.g.bosman@gmail.com> # Copyright (C) 2011, 2013 Peter Bruin <peter.bruin@math.uzh.ch> # Copyright (C) 2011 Michiel Kosters <kosters@gmail.com> # Copyright (C) 2017 Simon King <simon.king@uni-jena.de> # # Distributed under the terms of the GNU General Public License (GPL) # 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 six.moves import range
import re
from sage.misc.lazy_attribute import lazy_attribute from sage.matrix.matrix_space import MatrixSpace from sage.structure.element import is_Matrix from sage.modules.free_module_element import vector from sage.rings.integer import Integer
from cpython.object cimport PyObject_RichCompare as richcmp
cpdef FiniteDimensionalAlgebraElement unpickle_FiniteDimensionalAlgebraElement(A, vec, mat): """ Helper for unpickling of finite dimensional algebra elements.
TESTS::
sage: B = FiniteDimensionalAlgebra(QQ, [Matrix([[1,0,0], [0,1,0], [0,0,0]]), Matrix([[1,1,0], [0,1,1], [0,1,1]]), Matrix([[0,0,1], [0,1,0], [1,0,0]])]) sage: x = B([1,2,3]) sage: loads(dumps(x)) == x # indirect doctest True
"""
cdef class FiniteDimensionalAlgebraElement(AlgebraElement): r""" Create an element of a :class:`FiniteDimensionalAlgebra` using a multiplication table.
INPUT:
- ``A`` -- a :class:`FiniteDimensionalAlgebra` which will be the parent
- ``elt`` -- vector, matrix or element of the base field (default: ``None``)
- ``check`` -- boolean (default: ``True``); if ``False`` and ``elt`` is a matrix, assume that it is known to be the matrix of an element
If ``elt`` is a vector or a matrix consisting of a single row, it is interpreted as a vector of coordinates with respect to the given basis of ``A``. If ``elt`` is a square matrix, it is interpreted as a multiplication matrix with respect to this basis.
EXAMPLES::
sage: A = FiniteDimensionalAlgebra(GF(3), [Matrix([[1,0], [0,1]]), Matrix([[0,1], [0,0]])]) sage: A(17) 2*e0 sage: A([1,1]) e0 + e1 """ def __init__(self, A, elt=None, check=True): """ TESTS::
sage: A = FiniteDimensionalAlgebra(GF(3), [Matrix([[1,0], [0,1]]), Matrix([[0,1], [0,0]])]) sage: A(QQ(4)) Traceback (most recent call last): ... TypeError: elt should be a vector, a matrix, or an element of the base field
sage: B = FiniteDimensionalAlgebra(QQ, [Matrix([[1,0], [0,1]]), Matrix([[0,1], [-1,0]])]) sage: elt = B(Matrix([[1,1], [-1,1]])); elt e0 + e1 sage: TestSuite(elt).run() sage: B(Matrix([[0,1], [1,0]])) Traceback (most recent call last): ... ValueError: matrix does not define an element of the algebra """ self._vector = MatrixSpace(k,1,n)() self.__matrix = MatrixSpace(k, n)() else: mat = (<FiniteDimensionalAlgebraElement> elt).__matrix if mat is None: self.__matrix = None else: self.__matrix = mat.base_extend(k) self._vector = elt._vector.base_extend(k) else: raise ValueError("matrix does not define an element of the algebra") else: raise TypeError("algebra is not unitary") else: "or an element of the base field")
def __reduce__(self): """ TESTS::
sage: B = FiniteDimensionalAlgebra(QQ, [Matrix([[1,0,0], [0,1,0], [0,0,0]]), Matrix([[1,1,0], [0,1,1], [0,1,1]]), Matrix([[0,0,1], [0,1,0], [1,0,0]])]) sage: x = B([1,2,3]) sage: loads(dumps(x)) == x # indirect doctest True sage: loads(dumps(x)) is x False
"""
def __setstate__(self, state): """ This method serves at unpickling old pickles.
TESTS::
sage: A = FiniteDimensionalAlgebra(QQ, [Matrix([[1,0,0], [0,1,0], [0,0,0]]), Matrix([[0,1,0], [0,0,0], [0,0,0]]), Matrix([[0,0,0], [0,0,0], [0,0,1]])]) sage: x = A.element_class.__new__(A.element_class) sage: x.__setstate__((A, {'_vector':vector([1,1,1]), '_matrix':matrix(QQ,3,[1,1,0, 0,1,0, 0,0,1])})) sage: x e0 + e1 + e2 sage: x.matrix() [1 1 0] [0 1 0] [0 0 1]
Note that in old pickles, the vector actually is a vector. However, it is converted into a single-row matrix, in the new implementation::
sage: x.vector() (1, 1, 1)
""" else: self._vector = v pass
@property def _matrix(self): """ TESTS::
sage: B = FiniteDimensionalAlgebra(QQ, [Matrix([[1,0,0], [0,1,0], [0,0,0]]), Matrix([[1,1,0], [0,1,1], [0,1,1]]), Matrix([[0,0,1], [0,1,0], [1,0,0]])]) sage: x = B([1,2,3]) sage: x._matrix [3 2 3] [0 6 2] [3 2 2] """ cdef Py_ssize_t i cdef tuple table
def vector(self): """ Return ``self`` as a vector.
EXAMPLES::
sage: B = FiniteDimensionalAlgebra(QQ, [Matrix([[1,0,0], [0,1,0], [0,0,0]]), Matrix([[0,1,0], [0,0,0], [0,0,0]]), Matrix([[0,0,0], [0,0,0], [0,0,1]])]) sage: B(5).vector() (5, 0, 5) """ #By :trac:`23707`, ``self._vector`` now is a single row matrix, #not a vector, which results in a speed-up. For backwards compatibility, #this method still returns a vector.
def matrix(self): """ Return the matrix for multiplication by ``self`` from the right.
EXAMPLES::
sage: B = FiniteDimensionalAlgebra(QQ, [Matrix([[1,0,0], [0,1,0], [0,0,0]]), Matrix([[0,1,0], [0,0,0], [0,0,0]]), Matrix([[0,0,0], [0,0,0], [0,0,1]])]) sage: B(5).matrix() [5 0 0] [0 5 0] [0 0 5] """
def monomial_coefficients(self, copy=True): """ Return a dictionary whose keys are indices of basis elements in the support of ``self`` and whose values are the corresponding coefficients.
INPUT:
- ``copy`` -- ignored
EXAMPLES::
sage: B = FiniteDimensionalAlgebra(QQ, [Matrix([[1,0], [0,1]]), Matrix([[0,1], [-1,0]])]) sage: elt = B(Matrix([[1,1], [-1,1]])) sage: elt.monomial_coefficients() {0: 1, 1: 1} """ cdef Py_ssize_t i
def left_matrix(self): """ Return the matrix for multiplication by ``self`` from the left.
EXAMPLES::
sage: C = FiniteDimensionalAlgebra(QQ, [Matrix([[1,0,0], [0,0,0], [0,0,0]]), Matrix([[0,1,0], [0,0,0], [0,0,0]]), Matrix([[0,0,0], [0,1,0], [0,0,1]])]) sage: C([1,2,0]).left_matrix() [1 0 0] [0 1 0] [0 2 0]
"""
def _repr_(self): """ Return the string representation of ``self``.
EXAMPLES::
sage: A = FiniteDimensionalAlgebra(GF(3), [Matrix([[1,0], [0,1]]), Matrix([[0,1], [0,0]])]) sage: A(1) e0 """ x = "({})".format(x)
def _latex_(self): r""" Return the LaTeX representation of ``self``.
EXAMPLES::
sage: A = FiniteDimensionalAlgebra(GF(3), [Matrix([[1,0], [0,1]]), Matrix([[0,1], [0,0]])]) sage: latex(A(1)) # indirect doctest \left(\begin{array}{rr} 1 & 0 \\ 0 & 1 \end{array}\right) """
def __getitem__(self, m): """ Return the `m`-th coefficient of ``self``
EXAMPLES::
sage: A = FiniteDimensionalAlgebra(QQ, [Matrix([[1,0,0], [0,1,0], [0,0,0]]), Matrix([[0,1,0], [0,0,0], [0,0,0]]), Matrix([[0,0,0], [0,0,0], [0,0,1]])]) sage: A([2,1/4,3])[2] 3
"""
def __len__(self): """ EXAMPLES::
sage: A = FiniteDimensionalAlgebra(QQ, [Matrix([[1,0,0], [0,1,0], [0,0,0]]), Matrix([[0,1,0], [0,0,0], [0,0,0]]), Matrix([[0,0,0], [0,0,0], [0,0,1]])]) sage: len(A([2,1/4,3])) 3
"""
## (Rich) comparison cpdef _richcmp_(self, right, int op): """ EXAMPLES::
sage: A = FiniteDimensionalAlgebra(GF(3), [Matrix([[1,0], [0,1]]), Matrix([[0,1], [0,0]])]) sage: A(2) == 2 True sage: A(2) == 3 False sage: A(2) == GF(5)(2) False
sage: B = FiniteDimensionalAlgebra(QQ, [Matrix([[1,0,0], [0,1,0], [0,0,0]]), Matrix([[0,1,0], [0,0,0], [0,0,0]]), Matrix([[0,0,0], [0,0,0], [0,0,1]])]) sage: B(1) != 0 True
By :trac:`23707`, an ordering is defined on finite-dimensional algebras, corresponding to the ordering of the defining vectors; this may be handy if the vector space basis of the algebra corresponds to the standard monomials of the relation ideal, when the algebra is considered as a quotient of a path algebra. ::
sage: A(1) > 0 True sage: A(1) < 0 False sage: A(1) >= 0 True sage: A(1) <= 0 False
"""
cpdef _add_(self, other): """ EXAMPLES::
sage: A = FiniteDimensionalAlgebra(GF(3), [Matrix([[1,0], [0,1]]), Matrix([[0,1], [0,0]])]) sage: A.basis()[0] + A.basis()[1] e0 + e1 """
cpdef _sub_(self, other): """ EXAMPLES::
sage: A = FiniteDimensionalAlgebra(GF(3), [Matrix([[1,0], [0,1]]), Matrix([[0,1], [0,0]])]) sage: A.basis()[0] - A.basis()[1] e0 + 2*e1 """
cpdef _mul_(self, other): """ EXAMPLES::
sage: C = FiniteDimensionalAlgebra(QQ, [Matrix([[1,0,0], [0,0,0], [0,0,0]]), Matrix([[0,1,0], [0,0,0], [0,0,0]]), Matrix([[0,0,0], [0,1,0], [0,0,1]])]) sage: C.basis()[1] * C.basis()[2] e1 """
cpdef _lmul_(self, Element other): """ TESTS::
sage: C = FiniteDimensionalAlgebra(QQ, [Matrix([[1,0,0], [0,0,0], [0,0,0]]), Matrix([[0,1,0], [0,0,0], [0,0,0]]), Matrix([[0,0,0], [0,1,0], [0,0,1]])]) sage: c = C.random_element() sage: c * 2 == c + c True """ raise TypeError("unsupported operand parent(s) for *: '{}' and '{}'" .format(self.parent(), other.parent()))
cpdef _rmul_(self, Element other): """ TESTS::
sage: C = FiniteDimensionalAlgebra(QQ, [Matrix([[1,0,0], [0,0,0], [0,0,0]]), Matrix([[0,1,0], [0,0,0], [0,0,0]]), Matrix([[0,0,0], [0,1,0], [0,0,1]])]) sage: c = C.random_element() sage: 2 * c == c + c True """ raise TypeError("unsupported operand parent(s) for *: '{}' and '{}'" .format(self.parent(), other.parent()))
def __pow__(self, n, m): """ Return ``self`` raised to the power ``n``.
EXAMPLES::
sage: B = FiniteDimensionalAlgebra(QQ, [Matrix([[1,0,0], [0,1,0], [0,0,0]]), Matrix([[0,1,0], [0,0,0], [0,0,0]]), Matrix([[0,0,0], [0,0,0], [0,0,1]])]) sage: b = B([2,3,4]) sage: b^6 64*e0 + 576*e1 + 4096*e2 """ raise TypeError("algebra is not associative") if not A.is_unitary(): raise TypeError("algebra is not unitary") if n == 0: return A.one() cdef FiniteDimensionalAlgebraElement a = <FiniteDimensionalAlgebraElement>(~self) return A.element_class(A, a._vector * a.__matrix ** (-n - 1))
def __invert__(self): """ TESTS::
sage: C = FiniteDimensionalAlgebra(QQ, [Matrix([[1,0], [0,1]]), Matrix([[0,1], [-1,0]])]) sage: x = C([1,2]) sage: y = ~x; y # indirect doctest 1/5*e0 - 2/5*e1 sage: x*y e0 sage: C.one() e0 """
def is_invertible(self): """ Return ``True`` if ``self`` has a two-sided multiplicative inverse.
This assumes that the algebra to which ``self`` belongs is associative.
.. NOTE::
If an element of a unitary finite-dimensional algebra over a field admits a left inverse, then this is the unique left inverse, and it is also a right inverse.
EXAMPLES::
sage: C = FiniteDimensionalAlgebra(QQ, [Matrix([[1,0], [0,1]]), Matrix([[0,1], [-1,0]])]) sage: C([1,2]).is_invertible() True sage: C(0).is_invertible() False """
@property def _inverse(self): """ The two-sided inverse of ``self``, if it exists; otherwise this is ``None``.
This assumes that the algebra to which ``self`` belongs is associative.
EXAMPLES::
sage: C = FiniteDimensionalAlgebra(QQ, [Matrix([[1,0], [0,1]]), Matrix([[0,1], [-1,0]])]) sage: C([1,2])._inverse 1/5*e0 - 2/5*e1 sage: C(0)._inverse is None True """ cdef FiniteDimensionalAlgebraElement y self.__inverse = False
def inverse(self): """ Return the two-sided multiplicative inverse of ``self``, if it exists.
This assumes that the algebra to which ``self`` belongs is associative.
.. NOTE::
If an element of a finite-dimensional unitary associative algebra over a field admits a left inverse, then this is the unique left inverse, and it is also a right inverse.
EXAMPLES::
sage: C = FiniteDimensionalAlgebra(QQ, [Matrix([[1,0], [0,1]]), Matrix([[0,1], [-1,0]])]) sage: C([1,2]).inverse() 1/5*e0 - 2/5*e1 """ raise TypeError("algebra is not unitary")
raise ZeroDivisionError("element is not invertible")
def is_zerodivisor(self): """ Return ``True`` if ``self`` is a left or right zero-divisor.
EXAMPLES::
sage: C = FiniteDimensionalAlgebra(QQ, [Matrix([[1,0], [0,1]]), Matrix([[0,1], [0,0]])]) sage: C([1,0]).is_zerodivisor() False sage: C([0,1]).is_zerodivisor() True """
def is_nilpotent(self): """ Return ``True`` if ``self`` is nilpotent.
EXAMPLES::
sage: C = FiniteDimensionalAlgebra(QQ, [Matrix([[1,0], [0,1]]), Matrix([[0,1], [0,0]])]) sage: C([1,0]).is_nilpotent() False sage: C([0,1]).is_nilpotent() True
sage: A = FiniteDimensionalAlgebra(QQ, [Matrix([0])]) sage: A([1]).is_nilpotent() True """ raise TypeError("algebra is not associative")
def minimal_polynomial(self): """ Return the minimal polynomial of ``self``.
EXAMPLES::
sage: B = FiniteDimensionalAlgebra(QQ, [Matrix([[1,0,0], [0,1,0], [0,0,0]]), Matrix([[0,1,0], [0,0,0], [0,0,0]]), Matrix([[0,0,0], [0,0,0], [0,0,1]])]) sage: B(0).minimal_polynomial() x sage: b = B.random_element() sage: f = b.minimal_polynomial(); f # random x^3 + 1/2*x^2 - 7/16*x + 1/16 sage: f(b) == 0 True """ raise TypeError("algebra is not unitary") raise TypeError("algebra is not associative")
def characteristic_polynomial(self): """ Return the characteristic polynomial of ``self``.
.. NOTE::
This function just returns the characteristic polynomial of the matrix of right multiplication by ``self``. This may not be a very meaningful invariant if the algebra is not unitary and associative.
EXAMPLES::
sage: B = FiniteDimensionalAlgebra(QQ, [Matrix([[1,0,0], [0,1,0], [0,0,0]]), Matrix([[0,1,0], [0,0,0], [0,0,0]]), Matrix([[0,0,0], [0,0,0], [0,0,1]])]) sage: B(0).characteristic_polynomial() x^3 sage: b = B.random_element() sage: f = b.characteristic_polynomial(); f # random x^3 - 8*x^2 + 16*x sage: f(b) == 0 True """
|