Skip to content
This repository has been archived by the owner on Jan 30, 2023. It is now read-only.

Commit

Permalink
Merge branch 't/26105/26105_base_hom' into t/21413/21413/class_ring_e…
Browse files Browse the repository at this point in the history
…xtension
  • Loading branch information
xcaruso committed Sep 13, 2019
2 parents c99fa82 + 84704ba commit 6a52519
Show file tree
Hide file tree
Showing 34 changed files with 539 additions and 225 deletions.
6 changes: 4 additions & 2 deletions src/sage/algebras/lie_algebras/lie_algebra_element.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ cdef class LieAlgebraElement(IndexedFreeModuleElement):
right = (<LieAlgebraElement> right).lift()
return left * right

def _im_gens_(self, codomain, im_gens):
def _im_gens_(self, codomain, im_gens, base_map=None):
"""
Return the image of ``self`` in ``codomain`` under the
map that sends the generators of the parent of ``self``
Expand Down Expand Up @@ -119,7 +119,9 @@ cdef class LieAlgebraElement(IndexedFreeModuleElement):
if not self: # If we are 0
return s
names = self.parent().variable_names()
return codomain.sum(c * t._im_gens_(codomain, im_gens, names)
if base_map is None:
base_map = lambda x: x
return codomain.sum(base_map(c) * t._im_gens_(codomain, im_gens, names)
for t, c in self._monomial_coefficients.iteritems())

cpdef lift(self):
Expand Down
79 changes: 68 additions & 11 deletions src/sage/algebras/lie_algebras/morphism.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
from sage.structure.richcmp import richcmp
from sage.matrix.constructor import matrix
from itertools import combinations
from six import iteritems

# TODO: Refactor out common functionality with RingHomomorphism_im_gens
class LieAlgebraHomomorphism_im_gens(Morphism):
Expand All @@ -35,6 +36,18 @@ class LieAlgebraHomomorphism_im_gens(Morphism):
`x, y \in \mathfrak{g}`. Thus homomorphisms are completely determined
by the image of the generators of `\mathfrak{g}`.
INPUT:
- ``parent`` -- a homset between two Lie algebras
- ``im_gens`` -- the image of the generators of the domain
- ``base_map`` -- a homomorphism to apply to the coefficients.
It should be a map from the base ring of the domain to the
base ring of the codomain.
Note that if base_map is nontrivial then the result will
not be a morphism in the category of lie algebras over
the base ring.
- ``check`` -- whether to run checks on the validity of the defining data
EXAMPLES::
sage: L = LieAlgebra(QQ, 'x,y,z')
Expand All @@ -51,7 +64,7 @@ class LieAlgebraHomomorphism_im_gens(Morphism):
y |--> y
z |--> z
"""
def __init__(self, parent, im_gens, check=True):
def __init__(self, parent, im_gens, base_map=None, check=True):
"""
EXAMPLES::
Expand All @@ -73,6 +86,8 @@ def __init__(self, parent, im_gens, check=True):
if check:
if len(im_gens) != len(parent.domain().lie_algebra_generators()):
raise ValueError("number of images must equal number of generators")
if base_map is not None and not (base_map.domain() is parent.domain().base_ring() and parent.codomain().base_ring().has_coerce_map_from(base_map.codomain())):
raise ValueError("Invalid base homomorphism")
# TODO: Implement a (meaningful) _is_valid_homomorphism_()
#if not parent.domain()._is_valid_homomorphism_(parent.codomain(), im_gens):
# raise ValueError("relations do not all (canonically) map to 0 under map determined by images of generators.")
Expand All @@ -81,6 +96,7 @@ def __init__(self, parent, im_gens, check=True):
im_gens = copy.copy(im_gens)
im_gens.set_immutable()
self._im_gens = im_gens
self._base_map = base_map

def _repr_type(self):
"""
Expand Down Expand Up @@ -116,6 +132,29 @@ def im_gens(self):
"""
return list(self._im_gens)

def base_map(self):
"""
Return the map on the base ring that is part of the defining
data for this morphism. May return ``None`` if a coercion is used.
EXAMPLES::
sage: R.<x> = ZZ[]
sage: K.<i> = NumberField(x^2 + 1)
sage: cc = K.hom([-i])
sage: L.<X,Y,Z,W> = LieAlgebra(K, {('X','Y'): {'Z':1}, ('X','Z'): {'W':1}})
sage: M.<A,B> = LieAlgebra(K, abelian=True)
sage: phi = L.morphism({X: A, Y: B}, base_map=cc)
sage: phi(X)
A
sage: phi(i*X)
-i*A
sage: phi.base_map()
Ring endomorphism of Number Field in i with defining polynomial x^2 + 1
Defn: i |--> -i
"""
return self._base_map

def _richcmp_(self, other, op):
"""
Rich comparisons.
Expand All @@ -136,7 +175,7 @@ def _richcmp_(self, other, op):
sage: f != h
True
"""
return richcmp(self._im_gens, other._im_gens, op)
return richcmp((self._im_gens, self._base_map), (other._im_gens, other._base_map), op)

def __hash__(self):
"""
Expand All @@ -151,7 +190,7 @@ def __hash__(self):
sage: hash(phi) == hash(phi)
True
"""
return hash(self._im_gens)
return hash((self._im_gens, self._base_map))

def _repr_defn(self):
"""
Expand All @@ -169,8 +208,11 @@ def _repr_defn(self):
z |--> z
"""
D = self.domain()
return '\n'.join('%s |--> %s' % (x, gen)
for gen, x in zip(self._im_gens, D.gens()))
s = '\n'.join('%s |--> %s' % (x, gen)
for gen, x in zip(self._im_gens, D.gens()))
if s and self._base_map is not None:
s += '\nwith map of base ring'
return s

def _call_(self, x):
"""
Expand All @@ -188,7 +230,7 @@ def _call_(self, x):
[x, [[x, z], [y, z]]] + [x, [[[x, z], z], y]]
+ [[x, y], [[x, z], z]] + [[x, [y, z]], [x, z]]
"""
return x._im_gens_(self.codomain(), self.im_gens())
return x._im_gens_(self.codomain(), self.im_gens(), base_map=self.base_map())

class LieAlgebraHomset(Homset):
"""
Expand Down Expand Up @@ -307,6 +349,12 @@ class LieAlgebraMorphism_from_generators(LieAlgebraHomomorphism_im_gens):
in ``codomain`` of elements `X` of ``domain``
- ``codomain`` -- a Lie algebra (optional); this is inferred
from the values of ``on_generators`` if not given
- ``base_map`` -- a homomorphism to apply to the coefficients.
It should be a map from the base ring of the domain to the
base ring of the codomain.
Note that if base_map is nontrivial then the result will
not be a morphism in the category of lie algebras over
the base ring.
- ``check`` -- (default: ``True``) boolean; if ``False`` the
values on the Lie brackets implied by ``on_generators`` will
not be checked for contradictory values
Expand Down Expand Up @@ -396,7 +444,7 @@ class LieAlgebraMorphism_from_generators(LieAlgebraHomomorphism_im_gens):
Z |--> 0
W |--> 0
"""
def __init__(self, on_generators, domain=None, codomain=None, check=True):
def __init__(self, on_generators, domain=None, codomain=None, check=True, base_map=None, category=None):
r"""
Initialize ``self``.
Expand Down Expand Up @@ -456,15 +504,21 @@ def __init__(self, on_generators, domain=None, codomain=None, check=True):
if codomain not in LieAlgebras:
raise TypeError("codomain %s is not a Lie algebra" % codomain)

parent = Hom(domain, codomain)
if base_map is not None and category is None:
from sage.categories.sets_with_partial_maps import SetsWithPartialMaps
# We can't make any guarantee about the category of this morphism
# (in particular, it won't usually be linear over the base)
# so we default to a very lax category
category = SetsWithPartialMaps()
parent = Hom(domain, codomain, category=category)
m = domain.module()
cm = codomain.module()

spanning_set = [X.to_vector() for X in on_generators]
im_gens = [Y.to_vector() for Y in on_generators.values()]

if not im_gens:
LieAlgebraHomomorphism_im_gens.__init__(self, parent, [], check=check)
LieAlgebraHomomorphism_im_gens.__init__(self, parent, [], base_map=base_map, check=check)
return

# helper function to solve linear systems Ax = b, where both x and b
Expand Down Expand Up @@ -520,7 +574,7 @@ def solve_linear_system(A, b, check):
A = matrix(m.base_ring(), spanning_set)
im_gens = solve_linear_system(A, im_gens, check)

LieAlgebraHomomorphism_im_gens.__init__(self, parent, im_gens, check=check)
LieAlgebraHomomorphism_im_gens.__init__(self, parent, im_gens, base_map=base_map, check=check)

def _call_(self, x):
"""
Expand Down Expand Up @@ -554,4 +608,7 @@ def _call_(self, x):
1/3*A - 1/3*B + 2/3*C
"""
C = self.codomain()
return C.sum(c * self._im_gens[i] for i, c in x.to_vector().iteritems())
bh = self._base_map
if bh is None:
bh = lambda t: t
return C.sum(bh(c) * self._im_gens[i] for i, c in iteritems(x.to_vector()))
26 changes: 24 additions & 2 deletions src/sage/categories/finite_dimensional_lie_algebras_with_basis.py
Original file line number Diff line number Diff line change
Expand Up @@ -1344,7 +1344,7 @@ def as_finite_dimensional_algebra(self):
from sage.algebras.finite_dimensional_algebras.finite_dimensional_algebra import FiniteDimensionalAlgebra
return FiniteDimensionalAlgebra(R, mats, names=self._names)

def morphism(self, on_generators, codomain=None, check=True):
def morphism(self, on_generators, codomain=None, base_map=None, check=True):
r"""
Return a Lie algebra morphism defined by images of a Lie
generating subset of ``self``.
Expand All @@ -1355,6 +1355,8 @@ def morphism(self, on_generators, codomain=None, check=True):
in ``codomain`` of elements `X` of ``domain``
- ``codomain`` -- a Lie algebra (optional); this is inferred
from the values of ``on_generators`` if not given
- ``base_map`` -- a homomorphism from the base ring to something
coercing into the codomain
- ``check`` -- (default: ``True``) boolean; if ``False`` the
values on the Lie brackets implied by ``on_generators`` will
not be checked for contradictory values
Expand Down Expand Up @@ -1391,10 +1393,30 @@ def morphism(self, on_generators, codomain=None, check=True):
...
ValueError: this does not define a Lie algebra morphism;
contradictory values for brackets of length 2
However, it is still possible to create a morphism that acts nontrivially
on the coefficients, even though it's not a Lie algebra morphism
(since it isn't linear)::
sage: R.<x> = ZZ[]
sage: K.<i> = NumberField(x^2 + 1)
sage: cc = K.hom([-i])
sage: L.<X,Y,Z,W> = LieAlgebra(K, {('X','Y'): {'Z':1}, ('X','Z'): {'W':1}})
sage: M.<A,B> = LieAlgebra(K, abelian=True)
sage: phi = L.morphism({X: A, Y: B}, base_map=cc)
sage: phi(X)
A
sage: phi(i*X)
-i*A
Note that ``phi`` is not a morphism of Lie algebras over `K`::
sage: phi.category_for()
Category of sets with partial maps
"""
from sage.algebras.lie_algebras.morphism import LieAlgebraMorphism_from_generators
return LieAlgebraMorphism_from_generators(on_generators, domain=self,
codomain=codomain, check=check)
codomain=codomain, base_map=base_map, check=check)

class ElementMethods:
def adjoint_matrix(self): # In #11111 (more or less) by using matrix of a morphism
Expand Down
2 changes: 2 additions & 0 deletions src/sage/categories/homset.py
Original file line number Diff line number Diff line change
Expand Up @@ -922,6 +922,8 @@ def _element_constructor_(self, x, check=None, **options):
try:
call_with_keywords = self.__call_on_basis__
except AttributeError:
if 'base_map' in options:
raise NotImplementedError("base_map not supported for this Homset; you may need to specify a category")
raise NotImplementedError("no keywords are implemented for constructing elements of {}".format(self))
options.setdefault("category", self.homset_category())
return call_with_keywords(**options)
Expand Down
8 changes: 3 additions & 5 deletions src/sage/modules/fg_pid/fgp_morphism.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
from sage.categories.morphism import Morphism, is_Morphism
from .fgp_module import DEBUG
from sage.structure.richcmp import richcmp, op_NE

from sage.misc.cachefunc import cached_method

class FGP_Morphism(Morphism):
"""
Expand Down Expand Up @@ -132,6 +132,7 @@ def _repr_(self):
self.domain().base_ring(), self.domain().invariants(), self.codomain().invariants(),
list(self.im_gens()))

@cached_method
def im_gens(self):
"""
Return tuple of the images of the generators of the domain
Expand All @@ -146,10 +147,7 @@ def im_gens(self):
sage: phi.im_gens() is phi.im_gens()
True
"""
try: return self.__im_gens
except AttributeError: pass
self.__im_gens = tuple([self(x) for x in self.domain().gens()])
return self.__im_gens
return tuple([self(x) for x in self.domain().gens()])

def _richcmp_(self, right, op):
"""
Expand Down
4 changes: 2 additions & 2 deletions src/sage/quivers/representation.py
Original file line number Diff line number Diff line change
Expand Up @@ -2425,7 +2425,7 @@ def algebraic_dual(self, basis=False):
from sage.quivers.homspace import QuiverHomSpace
return QuiverHomSpace(self, self._semigroup.free_module(self.base_ring())).left_module(basis)

def Hom(self, codomain):
def Hom(self, codomain, category=None):
"""
Return the hom space from ``self`` to ``codomain``.
Expand All @@ -2438,7 +2438,7 @@ def Hom(self, codomain):
Dimension 2 QuiverHomSpace
"""
from sage.quivers.homspace import QuiverHomSpace
return QuiverHomSpace(self, codomain)
return QuiverHomSpace(self, codomain, category=category)

def direct_sum(self, modules, return_maps=False):
"""
Expand Down
12 changes: 8 additions & 4 deletions src/sage/rings/finite_rings/element_base.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -110,14 +110,14 @@ cdef class FinitePolyExtElement(FiniteRingElement):
sage: k.<a> = GF(64)
sage: TestSuite(a).run()
"""
def _im_gens_(self, codomain, im_gens):
def _im_gens_(self, codomain, im_gens, base_map=None):
"""
Used for applying homomorphisms of finite fields.
EXAMPLES::
sage: k.<a> = FiniteField(73^2, 'a')
sage: K.<b> = FiniteField(73^4, 'b')
sage: k.<a> = FiniteField(73^2)
sage: K.<b> = FiniteField(73^4)
sage: phi = k.hom([ b^(73*73+1) ]) # indirect doctest
sage: phi(0)
0
Expand All @@ -130,7 +130,11 @@ cdef class FinitePolyExtElement(FiniteRingElement):
## NOTE: see the note in sage/rings/number_field_element.pyx,
## in the comments for _im_gens_ there -- something analogous
## applies here.
return codomain(self.polynomial()(im_gens[0]))
f = self.polynomial()
if base_map is not None:
Cx = codomain['x']
f = Cx([base_map(c) for c in f])
return codomain(f(im_gens[0]))

def minpoly(self,var='x',algorithm='pari'):
"""
Expand Down
3 changes: 2 additions & 1 deletion src/sage/rings/finite_rings/integer_mod.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -444,7 +444,7 @@ cdef class IntegerMod_abstract(FiniteRingElement):
"""
return sage.rings.finite_rings.integer_mod.mod, (self.lift(), self.modulus(), self.parent())

def _im_gens_(self, codomain, im_gens):
def _im_gens_(self, codomain, im_gens, base_map=None):
"""
Return the image of ``self`` under the map that sends the
generators of the parent to ``im_gens``.
Expand All @@ -456,6 +456,7 @@ cdef class IntegerMod_abstract(FiniteRingElement):
sage: a._im_gens_(R, (R(1),))
2
"""
# The generators are irrelevant (Zmod(n) is its own base), so we ignore base_map
return codomain._coerce_(self)

def __mod__(self, modulus):
Expand Down
17 changes: 14 additions & 3 deletions src/sage/rings/fraction_field_element.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ cdef class FractionFieldElement(FieldElement):
if self.__denominator.is_zero():
raise ZeroDivisionError("fraction field element division by zero")

def _im_gens_(self, codomain, im_gens):
def _im_gens_(self, codomain, im_gens, base_map=None):
"""
EXAMPLES::
Expand All @@ -147,9 +147,20 @@ cdef class FractionFieldElement(FieldElement):
(a^2 + 2*a*b + b^2)/(a*b)
sage: (x^2/y)._im_gens_(K, [a, a*b])
a/b
::
sage: Zx.<x> = ZZ[]
sage: K.<i> = NumberField(x^2 + 1)
sage: cc = K.hom([-i])
sage: R.<a,b> = K[]
sage: F = R.fraction_field()
sage: phi = F.hom([F(b),F(a)], base_map=cc, category=Fields())
sage: phi(i/a)
((-i))/b
"""
nnum = codomain.coerce(self.__numerator._im_gens_(codomain, im_gens))
nden = codomain.coerce(self.__denominator._im_gens_(codomain, im_gens))
nnum = codomain.coerce(self.__numerator._im_gens_(codomain, im_gens, base_map=base_map))
nden = codomain.coerce(self.__denominator._im_gens_(codomain, im_gens, base_map=base_map))
return codomain.coerce(nnum/nden)

cpdef reduce(self):
Expand Down
Loading

0 comments on commit 6a52519

Please sign in to comment.