Morphisms of modules with a basis¶
This module contains a hierarchy of classes for morphisms of modules
with a basis (category Modules.WithBasis
):
These are internal classes; it is recommended not to use them
directly, and instead to construct morphisms through the
ModulesWithBasis.ParentMethods.module_morphism()
method of the
domain, or through the homset. See the former for an overview
of the possible arguments.
EXAMPLES:
We construct a morphism through the method
ModulesWithBasis.ParentMethods.module_morphism()
, by specifying
the image of each element of the distinguished basis:
sage: X = CombinatorialFreeModule(QQ, [1,2,3]); x = X.basis()
sage: Y = CombinatorialFreeModule(QQ, [1,2,3,4]); y = Y.basis()
sage: on_basis = lambda i: Y.monomial(i) + 2*Y.monomial(i+1)
sage: phi1 = X.module_morphism(on_basis, codomain=Y)
sage: phi1(x[1])
B[1] + 2*B[2]
sage: phi1
Generic morphism:
From: Free module generated by {1, 2, 3} over Rational Field
To: Free module generated by {1, 2, 3, 4} over Rational Field
sage: phi1.parent()
Set of Morphisms from Free module generated by {1, 2, 3} over Rational Field to Free module generated by {1, 2, 3, 4} over Rational Field in Category of finite dimensional vector spaces with basis over Rational Field
sage: phi1.__class__
<class 'sage.modules.with_basis.morphism.ModuleMorphismByLinearity_with_category'>
>>> from sage.all import *
>>> X = CombinatorialFreeModule(QQ, [Integer(1),Integer(2),Integer(3)]); x = X.basis()
>>> Y = CombinatorialFreeModule(QQ, [Integer(1),Integer(2),Integer(3),Integer(4)]); y = Y.basis()
>>> on_basis = lambda i: Y.monomial(i) + Integer(2)*Y.monomial(i+Integer(1))
>>> phi1 = X.module_morphism(on_basis, codomain=Y)
>>> phi1(x[Integer(1)])
B[1] + 2*B[2]
>>> phi1
Generic morphism:
From: Free module generated by {1, 2, 3} over Rational Field
To: Free module generated by {1, 2, 3, 4} over Rational Field
>>> phi1.parent()
Set of Morphisms from Free module generated by {1, 2, 3} over Rational Field to Free module generated by {1, 2, 3, 4} over Rational Field in Category of finite dimensional vector spaces with basis over Rational Field
>>> phi1.__class__
<class 'sage.modules.with_basis.morphism.ModuleMorphismByLinearity_with_category'>
Constructing the same morphism from the homset:
sage: H = Hom(X,Y)
sage: phi2 = H(on_basis=on_basis)
sage: phi1 == phi2
True
>>> from sage.all import *
>>> H = Hom(X,Y)
>>> phi2 = H(on_basis=on_basis)
>>> phi1 == phi2
True
Constructing the same morphism directly using the class; no backward compatibility is guaranteed in this case:
sage: from sage.modules.with_basis.morphism import ModuleMorphismByLinearity
sage: phi3 = ModuleMorphismByLinearity(X, on_basis, codomain=Y)
sage: phi3 == phi1
True
>>> from sage.all import *
>>> from sage.modules.with_basis.morphism import ModuleMorphismByLinearity
>>> phi3 = ModuleMorphismByLinearity(X, on_basis, codomain=Y)
>>> phi3 == phi1
True
Warning
The hierarchy of classes implemented in this module is one of the first non-trivial hierarchies of classes for morphisms. It is hitting a couple scaling issues:
There are many independent properties from which module morphisms can get code (being defined by linearity, from a matrix, or a function; being triangular, being diagonal, …). How to mitigate the class hierarchy growth?
This will become even more stringent as more properties are added (e.g. being defined from generators for an algebra morphism, …)
Categories, whose primary purpose is to provide infrastructure for handling such large hierarchy of classes, can’t help at this point: there is no category whose morphisms are triangular morphisms, and it’s not clear such a category would be sensible.
How to properly handle
__init__
method calls and multiple inheritance?Who should be in charge of setting the default category: the classes themselves, or
ModulesWithBasis.ParentMethods.module_morphism()
?
Because of this, the hierarchy of classes, and the specific APIs, is likely to be refactored as better infrastructure and best practices emerge.
AUTHORS:
Nicolas M. Thiery (2008-2015)
Jason Bandlow and Florent Hivert (2010): Triangular Morphisms
Christian Stump (2010): Issue #9648 module_morphism’s to a wider class of codomains
Before Issue #8678, this hierarchy of classes used to be in sage.categories.modules_with_basis; see Issue #8678 for the complete log.
- class sage.modules.with_basis.morphism.DiagonalModuleMorphism(domain, diagonal, codomain=None, category=None)[source]¶
Bases:
ModuleMorphismByLinearity
A class for diagonal module morphisms.
See
ModulesWithBasis.ParentMethods.module_morphism()
.INPUT:
domain
,codomain
– two modules with basis \(F\) and \(G\), respectivelydiagonal
– a function \(d\)
Assumptions:
domain
andcodomain
have the same base ring \(R\),their respective bases \(F\) and \(G\) have the same index set \(I\),
\(d\) is a function \(I \to R\).
Return the diagonal module morphism from
domain
tocodomain
sending \(F(i) \mapsto d(i) G(i)\) for all \(i \in I\).By default,
codomain
is currently assumed to bedomain
. (Todo: make a consistent choice with*ModuleMorphism
.)Todo
Implement an optimized
_call_()
function.Generalize to a mapcoeffs.
Generalize to a mapterms.
EXAMPLES:
sage: X = CombinatorialFreeModule(QQ, [1, 2, 3]); X.rename('X') sage: phi = X.module_morphism(diagonal=factorial, codomain=X) sage: x = X.basis() sage: phi(x[1]), phi(x[2]), phi(x[3]) (B[1], 2*B[2], 6*B[3])
>>> from sage.all import * >>> X = CombinatorialFreeModule(QQ, [Integer(1), Integer(2), Integer(3)]); X.rename('X') >>> phi = X.module_morphism(diagonal=factorial, codomain=X) >>> x = X.basis() >>> phi(x[Integer(1)]), phi(x[Integer(2)]), phi(x[Integer(3)]) (B[1], 2*B[2], 6*B[3])
- class sage.modules.with_basis.morphism.ModuleMorphism(domain, codomain=None, category=None, affine=False)[source]¶
Bases:
Morphism
The top abstract base class for module with basis morphisms.
INPUT:
domain
– a parent inModulesWithBasis(...)
codomain
– a parent inModules(...)
category
– a category orNone
(default:None
)affine
– whether we define an affine module morphism (default:False
)
Construct a module morphism from
domain
tocodomain
in the categorycategory
. By default, the category is the first ofModules(R).WithBasis().FiniteDimensional()
,Modules(R).WithBasis()
,Modules(R)
,CommutativeAdditiveMonoids()
that contains both the domain and the codomain. If initializing an affine morphism, then \(Sets()\) is used instead.See also
ModulesWithBasis.ParentMethods.module_morphism()
for usage information and examples;sage.modules.with_basis.morphism
for a technical overview of the classes for module morphisms;
The role of this class is minimal: it provides an
__init__()
method which:handles the choice of the default category
handles the proper inheritance from categories by updating the class of
self
upon construction.
- class sage.modules.with_basis.morphism.ModuleMorphismByLinearity(domain, on_basis=None, codomain=None, category=None, position=0, zero=None)[source]¶
Bases:
ModuleMorphism
A class for module morphisms obtained by extending a function by linearity.
INPUT:
domain
,codomain
,category
– as forModuleMorphism
on_basis
– a function which accepts indices of the basis ofdomain
asposition
-th argumentcodomain
– a parent inModules(...)
(default:
on_basis.codomain()
)
position
– nonnegative integer (default: 0)zero
– the zero of the codomain (defaults:codomain.zero()
)
See also
ModulesWithBasis.ParentMethods.module_morphism()
for usage information and examples;sage.modules.with_basis.morphism
for a technical overview of the classes for module morphisms;
Note
on_basis
may alternatively be provided in derived classes by passingNone
as argument, and implementing or setting the attribute_on_basis
- on_basis()[source]¶
Return the action of this morphism on basis elements, as per
ModulesWithBasis.Homsets.ElementMethods.on_basis()
.OUTPUT:
a function from the indices of the basis of the domain to the codomain
EXAMPLES:
sage: X = CombinatorialFreeModule(ZZ, [-2, -1, 1, 2]) sage: Y = CombinatorialFreeModule(ZZ, [1, 2]) sage: phi_on_basis = Y.monomial * abs sage: phi = sage.modules.with_basis.morphism.ModuleMorphismByLinearity(X, on_basis = phi_on_basis, codomain=Y) sage: x = X.basis() sage: phi.on_basis()(-2) B[2] sage: phi.on_basis() == phi_on_basis True
>>> from sage.all import * >>> X = CombinatorialFreeModule(ZZ, [-Integer(2), -Integer(1), Integer(1), Integer(2)]) >>> Y = CombinatorialFreeModule(ZZ, [Integer(1), Integer(2)]) >>> phi_on_basis = Y.monomial * abs >>> phi = sage.modules.with_basis.morphism.ModuleMorphismByLinearity(X, on_basis = phi_on_basis, codomain=Y) >>> x = X.basis() >>> phi.on_basis()(-Integer(2)) B[2] >>> phi.on_basis() == phi_on_basis True
- class sage.modules.with_basis.morphism.ModuleMorphismFromFunction(domain, function, codomain=None, category=None)[source]¶
Bases:
ModuleMorphism
,SetMorphism
A class for module morphisms implemented by a plain function.
INPUT:
domain
,codomain
,category
– as forModuleMorphism
function
– any function or callable from domain to codomain
See also
ModulesWithBasis.ParentMethods.module_morphism()
for usage information and examples;sage.modules.with_basis.morphism
for a technical overview of the classes for module morphisms;
- class sage.modules.with_basis.morphism.ModuleMorphismFromMatrix(domain, matrix, codomain=None, category=None, side='left')[source]¶
Bases:
ModuleMorphismByLinearity
A class for module morphisms built from a matrix in the distinguished bases of the domain and codomain.
See also
ModulesWithBasis.FiniteDimensional.MorphismMethods.matrix()
INPUT:
domain
,codomain
– two finite dimensional modules over the same base ring \(R\) with basis \(F\) and \(G\), respectivelymatrix
– a matrix with base ring \(R\) and dimensions matching that of \(F\) and \(G\), respectivelyside
–'left'
or'right'
(default:'left'
)If
side
is “left”, this morphism is considered as acting on the left; i.e. each column of the matrix represents the image of an element of the basis of the domain.category
– a category orNone
(default:None
)
EXAMPLES:
sage: X = CombinatorialFreeModule(ZZ, [1,2]); X.rename('X'); x = X.basis() sage: Y = CombinatorialFreeModule(ZZ, [3,4]); Y.rename('Y'); y = Y.basis() sage: m = matrix([[1,2],[3,5]]) sage: phi = X.module_morphism(matrix=m, codomain=Y) sage: phi.parent() Set of Morphisms from X to Y in Category of finite dimensional modules with basis over Integer Ring sage: phi.__class__ <class 'sage.modules.with_basis.morphism.ModuleMorphismFromMatrix_with_category'> sage: phi(x[1]) B[3] + 3*B[4] sage: phi(x[2]) 2*B[3] + 5*B[4] sage: m = matrix([[1,2],[3,5]]) sage: phi = X.module_morphism(matrix=m, codomain=Y, side='right', ....: category=Modules(ZZ).WithBasis()) sage: phi.parent() Set of Morphisms from X to Y in Category of modules with basis over Integer Ring sage: phi(x[1]) B[3] + 2*B[4] sage: phi(x[2]) 3*B[3] + 5*B[4]
>>> from sage.all import * >>> X = CombinatorialFreeModule(ZZ, [Integer(1),Integer(2)]); X.rename('X'); x = X.basis() >>> Y = CombinatorialFreeModule(ZZ, [Integer(3),Integer(4)]); Y.rename('Y'); y = Y.basis() >>> m = matrix([[Integer(1),Integer(2)],[Integer(3),Integer(5)]]) >>> phi = X.module_morphism(matrix=m, codomain=Y) >>> phi.parent() Set of Morphisms from X to Y in Category of finite dimensional modules with basis over Integer Ring >>> phi.__class__ <class 'sage.modules.with_basis.morphism.ModuleMorphismFromMatrix_with_category'> >>> phi(x[Integer(1)]) B[3] + 3*B[4] >>> phi(x[Integer(2)]) 2*B[3] + 5*B[4] >>> m = matrix([[Integer(1),Integer(2)],[Integer(3),Integer(5)]]) >>> phi = X.module_morphism(matrix=m, codomain=Y, side='right', ... category=Modules(ZZ).WithBasis()) >>> phi.parent() Set of Morphisms from X to Y in Category of modules with basis over Integer Ring >>> phi(x[Integer(1)]) B[3] + 2*B[4] >>> phi(x[Integer(2)]) 3*B[3] + 5*B[4]
Todo
Possibly implement rank, addition, multiplication, matrix, etc, from the stored matrix.
- class sage.modules.with_basis.morphism.PointwiseInverseFunction(f)[source]¶
Bases:
SageObject
A class for pointwise inverse functions.
The pointwise inverse function of a function \(f\) is the function sending every \(x\) to \(1 / f(x)\).
EXAMPLES:
sage: from sage.modules.with_basis.morphism import PointwiseInverseFunction sage: f = PointwiseInverseFunction(factorial) sage: f(0), f(1), f(2), f(3) (1, 1, 1/2, 1/6)
>>> from sage.all import * >>> from sage.modules.with_basis.morphism import PointwiseInverseFunction >>> f = PointwiseInverseFunction(factorial) >>> f(Integer(0)), f(Integer(1)), f(Integer(2)), f(Integer(3)) (1, 1, 1/2, 1/6)
- class sage.modules.with_basis.morphism.TriangularModuleMorphism(triangular='upper', unitriangular=False, key=None, inverse=None, inverse_on_support=<built-in function identity>, invertible=None)[source]¶
Bases:
ModuleMorphism
An abstract class for triangular module morphisms.
Let \(X\) and \(Y\) be modules over the same base ring, with distinguished bases \(F\) indexed by \(I\) and \(G\) indexed by \(J\), respectively.
A module morphism \(\phi\) from \(X\) to \(Y\) is triangular if its representing matrix in the distinguished bases of \(X\) and \(Y\) is upper triangular (echelon form).
More precisely, \(\phi\) is upper triangular w.r.t. a total order \(<\) on \(J\) if, for any \(j\in J\), there exists at most one index \(i\in I\) such that the leading support of \(\phi(F_i)\) is \(j\) (see
leading_support()
). We denote by \(r(j)\) this index, setting \(r(j)\) toNone
if it does not exist.Lower triangular morphisms are defined similarly, taking the trailing support instead (see
trailing_support()
).A triangular morphism is unitriangular if all its pivots (i.e. coefficient of \(j\) in each \(\phi(F[r(j)])\)) are \(1\).
INPUT:
domain
– a module with basis \(X\)codomain
– a module with basis \(Y\) (default: \(X\))category
– a category, as forModuleMorphism
triangular
–'upper'
or'lower'
(default:'upper'
)unitriangular
– boolean (default:False
) As a shorthand, one may useunitriangular='lower'
fortriangular='lower', unitriangular=True
.key
– a comparison key on \(J\) (default: the usual comparison of elements of \(J\))inverse_on_support
– a function \(J \to I\cup \{None\}\) implementing \(r\) (default: the identity function). If set to “compute”, the values of \(r(j)\) are precomputed by running through the index set \(I\) of the basis of the domain. This of course requires the domain to be finite dimensional.invertible
– boolean orNone
(default:None
); can be set to specify that \(\phi\) is known to be (or not to be) invertible. If the domain and codomain share the same indexing set, this is by default automatically set toTrue
ifinverse_on_support
is the identity, or in the finite dimensional case.
See also
ModulesWithBasis.ParentMethods.module_morphism()
for usage information and examples;sage.modules.with_basis.morphism
for a technical overview of the classes for module morphisms;
OUTPUT: a morphism from \(X\) to \(Y\)
Warning
This class is meant to be used as a complement for a concrete morphism class. In particular, the
__init__()
method focuses on setting up the data structure describing the triangularity of the morphism. It purposely does not callModuleMorphism.__init__()
which should be called (directly or indirectly) beforehand.EXAMPLES:
We construct and invert an upper unitriangular module morphism between two free \(\QQ\)-modules:
sage: I = range(1,200) sage: X = CombinatorialFreeModule(QQ, I); X.rename('X'); x = X.basis() sage: Y = CombinatorialFreeModule(QQ, I); Y.rename('Y'); y = Y.basis() sage: ut = Y.sum_of_monomials * divisors # This * is map composition. sage: phi = X.module_morphism(ut, unitriangular='upper', codomain=Y) sage: phi(x[2]) B[1] + B[2] sage: phi(x[6]) B[1] + B[2] + B[3] + B[6] sage: phi(x[30]) B[1] + B[2] + B[3] + B[5] + B[6] + B[10] + B[15] + B[30] sage: phi.preimage(y[2]) -B[1] + B[2] sage: phi.preimage(y[6]) B[1] - B[2] - B[3] + B[6] sage: phi.preimage(y[30]) -B[1] + B[2] + B[3] + B[5] - B[6] - B[10] - B[15] + B[30] sage: (phi^-1)(y[30]) -B[1] + B[2] + B[3] + B[5] - B[6] - B[10] - B[15] + B[30]
>>> from sage.all import * >>> I = range(Integer(1),Integer(200)) >>> X = CombinatorialFreeModule(QQ, I); X.rename('X'); x = X.basis() >>> Y = CombinatorialFreeModule(QQ, I); Y.rename('Y'); y = Y.basis() >>> ut = Y.sum_of_monomials * divisors # This * is map composition. >>> phi = X.module_morphism(ut, unitriangular='upper', codomain=Y) >>> phi(x[Integer(2)]) B[1] + B[2] >>> phi(x[Integer(6)]) B[1] + B[2] + B[3] + B[6] >>> phi(x[Integer(30)]) B[1] + B[2] + B[3] + B[5] + B[6] + B[10] + B[15] + B[30] >>> phi.preimage(y[Integer(2)]) -B[1] + B[2] >>> phi.preimage(y[Integer(6)]) B[1] - B[2] - B[3] + B[6] >>> phi.preimage(y[Integer(30)]) -B[1] + B[2] + B[3] + B[5] - B[6] - B[10] - B[15] + B[30] >>> (phi**-Integer(1))(y[Integer(30)]) -B[1] + B[2] + B[3] + B[5] - B[6] - B[10] - B[15] + B[30]
A lower triangular (but not unitriangular) morphism:
sage: X = CombinatorialFreeModule(QQ, [1, 2, 3]); X.rename('X'); x = X.basis() sage: def lt(i): return sum(j*x[j] for j in range(i, 4)) sage: phi = X.module_morphism(lt, triangular='lower', codomain=X) sage: phi(x[2]) 2*B[2] + 3*B[3] sage: phi.preimage(x[2]) 1/2*B[2] - 1/2*B[3] sage: phi(phi.preimage(x[2])) B[2]
>>> from sage.all import * >>> X = CombinatorialFreeModule(QQ, [Integer(1), Integer(2), Integer(3)]); X.rename('X'); x = X.basis() >>> def lt(i): return sum(j*x[j] for j in range(i, Integer(4))) >>> phi = X.module_morphism(lt, triangular='lower', codomain=X) >>> phi(x[Integer(2)]) 2*B[2] + 3*B[3] >>> phi.preimage(x[Integer(2)]) 1/2*B[2] - 1/2*B[3] >>> phi(phi.preimage(x[Integer(2)])) B[2]
Using the
key
keyword, we can use triangularity even if the map becomes triangular only after a permutation of the basis:sage: X = CombinatorialFreeModule(QQ, [1, 2, 3]); X.rename('X'); x = X.basis() sage: def ut(i): return (x[1] + x[2] if i == 1 else x[2] + (x[3] if i == 3 else 0)) sage: perm = [0, 2, 1, 3] sage: phi = X.module_morphism(ut, triangular='upper', codomain=X, ....: key=lambda a: perm[a]) sage: [phi(x[i]) for i in range(1, 4)] [B[1] + B[2], B[2], B[2] + B[3]] sage: [phi.preimage(x[i]) for i in range(1, 4)] [B[1] - B[2], B[2], -B[2] + B[3]]
>>> from sage.all import * >>> X = CombinatorialFreeModule(QQ, [Integer(1), Integer(2), Integer(3)]); X.rename('X'); x = X.basis() >>> def ut(i): return (x[Integer(1)] + x[Integer(2)] if i == Integer(1) else x[Integer(2)] + (x[Integer(3)] if i == Integer(3) else Integer(0))) >>> perm = [Integer(0), Integer(2), Integer(1), Integer(3)] >>> phi = X.module_morphism(ut, triangular='upper', codomain=X, ... key=lambda a: perm[a]) >>> [phi(x[i]) for i in range(Integer(1), Integer(4))] [B[1] + B[2], B[2], B[2] + B[3]] >>> [phi.preimage(x[i]) for i in range(Integer(1), Integer(4))] [B[1] - B[2], B[2], -B[2] + B[3]]
The same works in the lower-triangular case:
sage: def lt(i): return (x[1] + x[2] + x[3] if i == 2 else x[i]) sage: phi = X.module_morphism(lt, triangular='lower', codomain=X, ....: key=lambda a: perm[a]) sage: [phi(x[i]) for i in range(1, 4)] [B[1], B[1] + B[2] + B[3], B[3]] sage: [phi.preimage(x[i]) for i in range(1, 4)] [B[1], -B[1] + B[2] - B[3], B[3]]
>>> from sage.all import * >>> def lt(i): return (x[Integer(1)] + x[Integer(2)] + x[Integer(3)] if i == Integer(2) else x[i]) >>> phi = X.module_morphism(lt, triangular='lower', codomain=X, ... key=lambda a: perm[a]) >>> [phi(x[i]) for i in range(Integer(1), Integer(4))] [B[1], B[1] + B[2] + B[3], B[3]] >>> [phi.preimage(x[i]) for i in range(Integer(1), Integer(4))] [B[1], -B[1] + B[2] - B[3], B[3]]
An injective but not surjective morphism cannot be inverted, but the
inverse_on_support
keyword allows Sage to find a partial inverse:sage: X = CombinatorialFreeModule(QQ, [1,2,3]); x = X.basis() sage: Y = CombinatorialFreeModule(QQ, [1,2,3,4,5]); y = Y.basis() sage: ult = lambda i: sum( y[j] for j in range(i+1,6) ) sage: phi = X.module_morphism(ult, unitriangular='lower', codomain=Y, ....: inverse_on_support=lambda i: i-1 if i in [2,3,4] else None) sage: phi(x[2]) B[3] + B[4] + B[5] sage: phi.preimage(y[3]) B[2] - B[3]
>>> from sage.all import * >>> X = CombinatorialFreeModule(QQ, [Integer(1),Integer(2),Integer(3)]); x = X.basis() >>> Y = CombinatorialFreeModule(QQ, [Integer(1),Integer(2),Integer(3),Integer(4),Integer(5)]); y = Y.basis() >>> ult = lambda i: sum( y[j] for j in range(i+Integer(1),Integer(6)) ) >>> phi = X.module_morphism(ult, unitriangular='lower', codomain=Y, ... inverse_on_support=lambda i: i-Integer(1) if i in [Integer(2),Integer(3),Integer(4)] else None) >>> phi(x[Integer(2)]) B[3] + B[4] + B[5] >>> phi.preimage(y[Integer(3)]) B[2] - B[3]
The
inverse_on_support
keyword can also be used if the bases of the domain and the codomain are identical but one of them has to be permuted in order to render the morphism triangular. For example:sage: X = CombinatorialFreeModule(QQ, [1, 2, 3]); X.rename('X'); x = X.basis() sage: def ut(i): ....: return (x[3] if i == 1 else x[1] if i == 2 ....: else x[1] + x[2]) sage: def perm(i): ....: return (2 if i == 1 else 3 if i == 2 else 1) sage: phi = X.module_morphism(ut, triangular='upper', codomain=X, ....: inverse_on_support=perm) sage: [phi(x[i]) for i in range(1, 4)] [B[3], B[1], B[1] + B[2]] sage: [phi.preimage(x[i]) for i in range(1, 4)] [B[2], -B[2] + B[3], B[1]]
>>> from sage.all import * >>> X = CombinatorialFreeModule(QQ, [Integer(1), Integer(2), Integer(3)]); X.rename('X'); x = X.basis() >>> def ut(i): ... return (x[Integer(3)] if i == Integer(1) else x[Integer(1)] if i == Integer(2) ... else x[Integer(1)] + x[Integer(2)]) >>> def perm(i): ... return (Integer(2) if i == Integer(1) else Integer(3) if i == Integer(2) else Integer(1)) >>> phi = X.module_morphism(ut, triangular='upper', codomain=X, ... inverse_on_support=perm) >>> [phi(x[i]) for i in range(Integer(1), Integer(4))] [B[3], B[1], B[1] + B[2]] >>> [phi.preimage(x[i]) for i in range(Integer(1), Integer(4))] [B[2], -B[2] + B[3], B[1]]
The same works if the permutation induces lower triangularity:
sage: X = CombinatorialFreeModule(QQ, [1, 2, 3]); X.rename('X'); x = X.basis() sage: def lt(i): ....: return (x[3] if i == 1 else x[2] if i == 2 ....: else x[1] + x[2]) sage: def perm(i): ....: return 4 - i sage: phi = X.module_morphism(lt, triangular='lower', codomain=X, ....: inverse_on_support=perm) sage: [phi(x[i]) for i in range(1, 4)] [B[3], B[2], B[1] + B[2]] sage: [phi.preimage(x[i]) for i in range(1, 4)] [-B[2] + B[3], B[2], B[1]]
>>> from sage.all import * >>> X = CombinatorialFreeModule(QQ, [Integer(1), Integer(2), Integer(3)]); X.rename('X'); x = X.basis() >>> def lt(i): ... return (x[Integer(3)] if i == Integer(1) else x[Integer(2)] if i == Integer(2) ... else x[Integer(1)] + x[Integer(2)]) >>> def perm(i): ... return Integer(4) - i >>> phi = X.module_morphism(lt, triangular='lower', codomain=X, ... inverse_on_support=perm) >>> [phi(x[i]) for i in range(Integer(1), Integer(4))] [B[3], B[2], B[1] + B[2]] >>> [phi.preimage(x[i]) for i in range(Integer(1), Integer(4))] [-B[2] + B[3], B[2], B[1]]
In the finite dimensional case, one can ask Sage to recover
inverse_on_support
by a precomputation:sage: X = CombinatorialFreeModule(QQ, [1, 2, 3]); x = X.basis() sage: Y = CombinatorialFreeModule(QQ, [1, 2, 3, 4]); y = Y.basis() sage: ut = lambda i: sum( y[j] for j in range(1,i+2) ) sage: phi = X.module_morphism(ut, triangular='upper', codomain=Y, ....: inverse_on_support='compute') sage: tx = "{} {} {}" sage: for j in Y.basis().keys(): ....: i = phi._inverse_on_support(j) ....: print(tx.format(j, i, phi(x[i]) if i is not None else None)) 1 None None 2 1 B[1] + B[2] 3 2 B[1] + B[2] + B[3] 4 3 B[1] + B[2] + B[3] + B[4]
>>> from sage.all import * >>> X = CombinatorialFreeModule(QQ, [Integer(1), Integer(2), Integer(3)]); x = X.basis() >>> Y = CombinatorialFreeModule(QQ, [Integer(1), Integer(2), Integer(3), Integer(4)]); y = Y.basis() >>> ut = lambda i: sum( y[j] for j in range(Integer(1),i+Integer(2)) ) >>> phi = X.module_morphism(ut, triangular='upper', codomain=Y, ... inverse_on_support='compute') >>> tx = "{} {} {}" >>> for j in Y.basis().keys(): ... i = phi._inverse_on_support(j) ... print(tx.format(j, i, phi(x[i]) if i is not None else None)) 1 None None 2 1 B[1] + B[2] 3 2 B[1] + B[2] + B[3] 4 3 B[1] + B[2] + B[3] + B[4]
The
inverse_on_basis
andkey
keywords can be combined:sage: X = CombinatorialFreeModule(QQ, [1, 2, 3]); X.rename('X') sage: x = X.basis() sage: def ut(i): ....: return (2*x[2] + 3*x[3] if i == 1 ....: else x[1] + x[2] + x[3] if i == 2 ....: else 4*x[2]) sage: def perm(i): ....: return (2 if i == 1 else 3 if i == 2 else 1) sage: perverse_key = lambda a: (a - 2) % 3 sage: phi = X.module_morphism(ut, triangular='upper', codomain=X, ....: inverse_on_support=perm, key=perverse_key) sage: [phi(x[i]) for i in range(1, 4)] [2*B[2] + 3*B[3], B[1] + B[2] + B[3], 4*B[2]] sage: [phi.preimage(x[i]) for i in range(1, 4)] [-1/3*B[1] + B[2] - 1/12*B[3], 1/4*B[3], 1/3*B[1] - 1/6*B[3]]
>>> from sage.all import * >>> X = CombinatorialFreeModule(QQ, [Integer(1), Integer(2), Integer(3)]); X.rename('X') >>> x = X.basis() >>> def ut(i): ... return (Integer(2)*x[Integer(2)] + Integer(3)*x[Integer(3)] if i == Integer(1) ... else x[Integer(1)] + x[Integer(2)] + x[Integer(3)] if i == Integer(2) ... else Integer(4)*x[Integer(2)]) >>> def perm(i): ... return (Integer(2) if i == Integer(1) else Integer(3) if i == Integer(2) else Integer(1)) >>> perverse_key = lambda a: (a - Integer(2)) % Integer(3) >>> phi = X.module_morphism(ut, triangular='upper', codomain=X, ... inverse_on_support=perm, key=perverse_key) >>> [phi(x[i]) for i in range(Integer(1), Integer(4))] [2*B[2] + 3*B[3], B[1] + B[2] + B[3], 4*B[2]] >>> [phi.preimage(x[i]) for i in range(Integer(1), Integer(4))] [-1/3*B[1] + B[2] - 1/12*B[3], 1/4*B[3], 1/3*B[1] - 1/6*B[3]]
- cokernel_basis_indices()[source]¶
Return the indices of the natural monomial basis of the cokernel of
self
.INPUT:
self
– a triangular morphism over a field or a unitriangular morphism over a ring, with a finite dimensional codomain.
OUTPUT:
A list \(E\) of indices of the basis \((B_e)_e\) of the codomain of
self
so that \((B_e)_{e\in E}\) forms a basis of a supplementary of the image set ofself
.Thinking of this triangular morphism as a row echelon matrix, this returns the complementary of the characteristic columns. Namely \(E\) is the set of indices which do not appear as leading support of some element of the image set of
self
.EXAMPLES:
sage: X = CombinatorialFreeModule(ZZ, [1,2,3]); x = X.basis() sage: Y = CombinatorialFreeModule(ZZ, [1,2,3,4,5]); y = Y.basis() sage: uut = lambda i: sum( y[j] for j in range(i+1,6) ) # uni-upper sage: phi = X.module_morphism(uut, unitriangular='upper', codomain=Y, ....: inverse_on_support=lambda i: i-1 if i in [2,3,4] else None) sage: phi.cokernel_basis_indices() [1, 5] sage: phi = X.module_morphism(uut, triangular='upper', codomain=Y, ....: inverse_on_support=lambda i: i-1 if i in [2,3,4] else None) sage: phi.cokernel_basis_indices() Traceback (most recent call last): ... NotImplementedError: cokernel_basis_indices for a triangular but not unitriangular morphism over a ring sage: Y = CombinatorialFreeModule(ZZ, NN); y = Y.basis() sage: phi = X.module_morphism(uut, unitriangular='upper', codomain=Y, ....: inverse_on_support=lambda i: i-1 if i in [2,3,4] else None) sage: phi.cokernel_basis_indices() Traceback (most recent call last): ... NotImplementedError: cokernel_basis_indices implemented only for morphisms with a finite dimensional codomain
>>> from sage.all import * >>> X = CombinatorialFreeModule(ZZ, [Integer(1),Integer(2),Integer(3)]); x = X.basis() >>> Y = CombinatorialFreeModule(ZZ, [Integer(1),Integer(2),Integer(3),Integer(4),Integer(5)]); y = Y.basis() >>> uut = lambda i: sum( y[j] for j in range(i+Integer(1),Integer(6)) ) # uni-upper >>> phi = X.module_morphism(uut, unitriangular='upper', codomain=Y, ... inverse_on_support=lambda i: i-Integer(1) if i in [Integer(2),Integer(3),Integer(4)] else None) >>> phi.cokernel_basis_indices() [1, 5] >>> phi = X.module_morphism(uut, triangular='upper', codomain=Y, ... inverse_on_support=lambda i: i-Integer(1) if i in [Integer(2),Integer(3),Integer(4)] else None) >>> phi.cokernel_basis_indices() Traceback (most recent call last): ... NotImplementedError: cokernel_basis_indices for a triangular but not unitriangular morphism over a ring >>> Y = CombinatorialFreeModule(ZZ, NN); y = Y.basis() >>> phi = X.module_morphism(uut, unitriangular='upper', codomain=Y, ... inverse_on_support=lambda i: i-Integer(1) if i in [Integer(2),Integer(3),Integer(4)] else None) >>> phi.cokernel_basis_indices() Traceback (most recent call last): ... NotImplementedError: cokernel_basis_indices implemented only for morphisms with a finite dimensional codomain
- cokernel_projection(category=None)[source]¶
Return a projection on the co-kernel of
self
.INPUT:
category
– the category of the result
EXAMPLES:
sage: X = CombinatorialFreeModule(QQ, [1,2,3]); x = X.basis() sage: Y = CombinatorialFreeModule(QQ, [1,2,3,4,5]); y = Y.basis() sage: lt = lambda i: sum( y[j] for j in range(i+1,6) ) # lower sage: phi = X.module_morphism(lt, triangular='lower', codomain=Y, ....: inverse_on_support=lambda i: i-1 if i in [2,3,4] else None) sage: phipro = phi.cokernel_projection() sage: phipro(y[1] + y[2]) B[1] sage: all(phipro(phi(x)).is_zero() for x in X.basis()) True sage: phipro(y[1]) B[1] sage: phipro(y[4]) -B[5] sage: phipro(y[5]) B[5]
>>> from sage.all import * >>> X = CombinatorialFreeModule(QQ, [Integer(1),Integer(2),Integer(3)]); x = X.basis() >>> Y = CombinatorialFreeModule(QQ, [Integer(1),Integer(2),Integer(3),Integer(4),Integer(5)]); y = Y.basis() >>> lt = lambda i: sum( y[j] for j in range(i+Integer(1),Integer(6)) ) # lower >>> phi = X.module_morphism(lt, triangular='lower', codomain=Y, ... inverse_on_support=lambda i: i-Integer(1) if i in [Integer(2),Integer(3),Integer(4)] else None) >>> phipro = phi.cokernel_projection() >>> phipro(y[Integer(1)] + y[Integer(2)]) B[1] >>> all(phipro(phi(x)).is_zero() for x in X.basis()) True >>> phipro(y[Integer(1)]) B[1] >>> phipro(y[Integer(4)]) -B[5] >>> phipro(y[Integer(5)]) B[5]
- coreduced(y)[source]¶
Return \(y\) reduced w.r.t. the image of
self
.INPUT:
self
– a triangular morphism over a field, or a unitriangular morphism over a ringy
– an element of the codomain ofself
Suppose that
self
is a morphism from \(X\) to \(Y\). Then, for any \(y \in Y\), the callself.coreduced(y)
returns a normal form for \(y\) in the quotient \(Y / I\) where \(I\) is the image ofself
.EXAMPLES:
sage: X = CombinatorialFreeModule(QQ, [1,2,3]); x = X.basis() sage: Y = CombinatorialFreeModule(QQ, [1,2,3,4,5]); y = Y.basis() sage: ult = lambda i: sum( y[j] for j in range(i+1,6) ) sage: phi = X.module_morphism(ult, unitriangular='lower', codomain=Y, ....: inverse_on_support=lambda i: i-1 if i in [2,3,4] else None) sage: [phi(v) for v in X.basis()] [B[2] + B[3] + B[4] + B[5], B[3] + B[4] + B[5], B[4] + B[5]] sage: [phi.coreduced(y[1]-2*y[4])] [B[1] + 2*B[5]] sage: [phi.coreduced(v) for v in y] [B[1], 0, 0, -B[5], B[5]]
>>> from sage.all import * >>> X = CombinatorialFreeModule(QQ, [Integer(1),Integer(2),Integer(3)]); x = X.basis() >>> Y = CombinatorialFreeModule(QQ, [Integer(1),Integer(2),Integer(3),Integer(4),Integer(5)]); y = Y.basis() >>> ult = lambda i: sum( y[j] for j in range(i+Integer(1),Integer(6)) ) >>> phi = X.module_morphism(ult, unitriangular='lower', codomain=Y, ... inverse_on_support=lambda i: i-Integer(1) if i in [Integer(2),Integer(3),Integer(4)] else None) >>> [phi(v) for v in X.basis()] [B[2] + B[3] + B[4] + B[5], B[3] + B[4] + B[5], B[4] + B[5]] >>> [phi.coreduced(y[Integer(1)]-Integer(2)*y[Integer(4)])] [B[1] + 2*B[5]] >>> [phi.coreduced(v) for v in y] [B[1], 0, 0, -B[5], B[5]]
Now with a non unitriangular morphism:
sage: lt = lambda i: sum( j*y[j] for j in range(i+1,6) ) sage: phi = X.module_morphism(lt, triangular='lower', codomain=Y, ....: inverse_on_support=lambda i: i-1 if i in [2,3,4] else None) sage: [phi(v) for v in X.basis()] [2*B[2] + 3*B[3] + 4*B[4] + 5*B[5], 3*B[3] + 4*B[4] + 5*B[5], 4*B[4] + 5*B[5]] sage: [phi.coreduced(y[1]-2*y[4])] [B[1] + 5/2*B[5]] sage: [phi.coreduced(v) for v in y] [B[1], 0, 0, -5/4*B[5], B[5]]
>>> from sage.all import * >>> lt = lambda i: sum( j*y[j] for j in range(i+Integer(1),Integer(6)) ) >>> phi = X.module_morphism(lt, triangular='lower', codomain=Y, ... inverse_on_support=lambda i: i-Integer(1) if i in [Integer(2),Integer(3),Integer(4)] else None) >>> [phi(v) for v in X.basis()] [2*B[2] + 3*B[3] + 4*B[4] + 5*B[5], 3*B[3] + 4*B[4] + 5*B[5], 4*B[4] + 5*B[5]] >>> [phi.coreduced(y[Integer(1)]-Integer(2)*y[Integer(4)])] [B[1] + 5/2*B[5]] >>> [phi.coreduced(v) for v in y] [B[1], 0, 0, -5/4*B[5], B[5]]
For general rings, this method is only implemented for unitriangular morphisms:
sage: X = CombinatorialFreeModule(ZZ, [1,2,3]); x = X.basis() sage: Y = CombinatorialFreeModule(ZZ, [1,2,3,4,5]); y = Y.basis() sage: phi = X.module_morphism(ult, unitriangular='lower', codomain=Y, ....: inverse_on_support=lambda i: i-1 if i in [2,3,4] else None) sage: [phi.coreduced(y[1]-2*y[4])] [B[1] + 2*B[5]] sage: [phi.coreduced(v) for v in y] [B[1], 0, 0, -B[5], B[5]] sage: phi = X.module_morphism(lt, triangular='lower', codomain=Y, ....: inverse_on_support=lambda i: i-1 if i in [2,3,4] else None) sage: [phi.coreduced(v) for v in y] Traceback (most recent call last): ... NotImplementedError: coreduce for a triangular but not unitriangular morphism over a ring
>>> from sage.all import * >>> X = CombinatorialFreeModule(ZZ, [Integer(1),Integer(2),Integer(3)]); x = X.basis() >>> Y = CombinatorialFreeModule(ZZ, [Integer(1),Integer(2),Integer(3),Integer(4),Integer(5)]); y = Y.basis() >>> phi = X.module_morphism(ult, unitriangular='lower', codomain=Y, ... inverse_on_support=lambda i: i-Integer(1) if i in [Integer(2),Integer(3),Integer(4)] else None) >>> [phi.coreduced(y[Integer(1)]-Integer(2)*y[Integer(4)])] [B[1] + 2*B[5]] >>> [phi.coreduced(v) for v in y] [B[1], 0, 0, -B[5], B[5]] >>> phi = X.module_morphism(lt, triangular='lower', codomain=Y, ... inverse_on_support=lambda i: i-Integer(1) if i in [Integer(2),Integer(3),Integer(4)] else None) >>> [phi.coreduced(v) for v in y] Traceback (most recent call last): ... NotImplementedError: coreduce for a triangular but not unitriangular morphism over a ring
Note
Before Issue #8678 this method used to be called co_reduced.
- preimage(f)[source]¶
Return the preimage of \(f\) under
self
.EXAMPLES:
sage: X = CombinatorialFreeModule(QQ, [1, 2, 3]); x = X.basis() sage: Y = CombinatorialFreeModule(QQ, [1, 2, 3]); y = Y.basis() sage: ult = lambda i: sum( y[j] for j in range(i,4) ) # uni-lower sage: phi = X.module_morphism(ult, triangular='lower', codomain=Y) sage: phi.preimage(y[1] + y[2]) B[1] - B[3]
>>> from sage.all import * >>> X = CombinatorialFreeModule(QQ, [Integer(1), Integer(2), Integer(3)]); x = X.basis() >>> Y = CombinatorialFreeModule(QQ, [Integer(1), Integer(2), Integer(3)]); y = Y.basis() >>> ult = lambda i: sum( y[j] for j in range(i,Integer(4)) ) # uni-lower >>> phi = X.module_morphism(ult, triangular='lower', codomain=Y) >>> phi.preimage(y[Integer(1)] + y[Integer(2)]) B[1] - B[3]
The morphism need not be surjective. In the following example, the codomain is of larger dimension than the domain:
sage: X = CombinatorialFreeModule(QQ, [1, 2, 3]); x = X.basis() sage: Y = CombinatorialFreeModule(QQ, [1, 2, 3, 4]); y = Y.basis() sage: lt = lambda i: sum( y[j] for j in range(i,5) ) sage: phi = X.module_morphism(lt, triangular='lower', codomain=Y) sage: phi.preimage(y[1] + y[2]) B[1] - B[3]
>>> from sage.all import * >>> X = CombinatorialFreeModule(QQ, [Integer(1), Integer(2), Integer(3)]); x = X.basis() >>> Y = CombinatorialFreeModule(QQ, [Integer(1), Integer(2), Integer(3), Integer(4)]); y = Y.basis() >>> lt = lambda i: sum( y[j] for j in range(i,Integer(5)) ) >>> phi = X.module_morphism(lt, triangular='lower', codomain=Y) >>> phi.preimage(y[Integer(1)] + y[Integer(2)]) B[1] - B[3]
Here are examples using
inverse_on_support
to handle a morphism that shifts the leading indices by \(1\):sage: X = CombinatorialFreeModule(QQ, [1, 2, 3]); x = X.basis() sage: Y = CombinatorialFreeModule(QQ, [1, 2, 3, 4, 5]); y = Y.basis() sage: lt = lambda i: sum( y[j] for j in range(i+1,6) ) # lower sage: phi = X.module_morphism(lt, triangular='lower', codomain=Y, ....: inverse_on_support=lambda i: i-1 if i in [2,3,4] else None) sage: phi(x[1]) B[2] + B[3] + B[4] + B[5] sage: phi(x[3]) B[4] + B[5] sage: phi.preimage(y[2] + y[3]) B[1] - B[3] sage: phi(phi.preimage(y[2] + y[3])) == y[2] + y[3] True sage: el = x[1] + 3*x[2] + 2*x[3] sage: phi.preimage(phi(el)) == el True sage: phi.preimage(y[1]) Traceback (most recent call last): ... ValueError: B[1] is not in the image sage: phi.preimage(y[4]) Traceback (most recent call last): ... ValueError: B[4] is not in the image
>>> from sage.all import * >>> X = CombinatorialFreeModule(QQ, [Integer(1), Integer(2), Integer(3)]); x = X.basis() >>> Y = CombinatorialFreeModule(QQ, [Integer(1), Integer(2), Integer(3), Integer(4), Integer(5)]); y = Y.basis() >>> lt = lambda i: sum( y[j] for j in range(i+Integer(1),Integer(6)) ) # lower >>> phi = X.module_morphism(lt, triangular='lower', codomain=Y, ... inverse_on_support=lambda i: i-Integer(1) if i in [Integer(2),Integer(3),Integer(4)] else None) >>> phi(x[Integer(1)]) B[2] + B[3] + B[4] + B[5] >>> phi(x[Integer(3)]) B[4] + B[5] >>> phi.preimage(y[Integer(2)] + y[Integer(3)]) B[1] - B[3] >>> phi(phi.preimage(y[Integer(2)] + y[Integer(3)])) == y[Integer(2)] + y[Integer(3)] True >>> el = x[Integer(1)] + Integer(3)*x[Integer(2)] + Integer(2)*x[Integer(3)] >>> phi.preimage(phi(el)) == el True >>> phi.preimage(y[Integer(1)]) Traceback (most recent call last): ... ValueError: B[1] is not in the image >>> phi.preimage(y[Integer(4)]) Traceback (most recent call last): ... ValueError: B[4] is not in the image
Over a base ring like \(\ZZ\), the morphism need not be surjective even when the dimensions match:
sage: X = CombinatorialFreeModule(ZZ, [1, 2, 3]); x = X.basis() sage: Y = CombinatorialFreeModule(ZZ, [1, 2, 3]); y = Y.basis() sage: lt = lambda i: sum( 2* y[j] for j in range(i,4) ) # lower sage: phi = X.module_morphism(lt, triangular='lower', codomain=Y) sage: phi.preimage(2*y[1] + 2*y[2]) B[1] - B[3]
>>> from sage.all import * >>> X = CombinatorialFreeModule(ZZ, [Integer(1), Integer(2), Integer(3)]); x = X.basis() >>> Y = CombinatorialFreeModule(ZZ, [Integer(1), Integer(2), Integer(3)]); y = Y.basis() >>> lt = lambda i: sum( Integer(2)* y[j] for j in range(i,Integer(4)) ) # lower >>> phi = X.module_morphism(lt, triangular='lower', codomain=Y) >>> phi.preimage(Integer(2)*y[Integer(1)] + Integer(2)*y[Integer(2)]) B[1] - B[3]
The error message in case of failure could be more specific though:
sage: phi.preimage(y[1] + y[2]) Traceback (most recent call last): ... TypeError: no conversion of this rational to integer
>>> from sage.all import * >>> phi.preimage(y[Integer(1)] + y[Integer(2)]) Traceback (most recent call last): ... TypeError: no conversion of this rational to integer
- section()[source]¶
Return the section (partial inverse) of
self
.This returns a partial triangular morphism which is a section of
self
. The section morphism raises aValueError
if asked to apply on an element which is not in the image ofself
.EXAMPLES:
sage: X = CombinatorialFreeModule(QQ, [1,2,3]); x = X.basis() sage: X.rename('X') sage: Y = CombinatorialFreeModule(QQ, [1,2,3,4,5]); y = Y.basis() sage: ult = lambda i: sum( y[j] for j in range(i+1,6) ) # uni-lower sage: phi = X.module_morphism(ult, triangular='lower', codomain=Y, ....: inverse_on_support=lambda i: i-1 if i in [2,3,4] else None) sage: ~phi Traceback (most recent call last): ... ValueError: Morphism not known to be invertible; see the invertible option of module_morphism sage: phiinv = phi.section() sage: list(map(phiinv*phi, X.basis().list())) == X.basis().list() True sage: phiinv(Y.basis()[1]) Traceback (most recent call last): ... ValueError: B[1] is not in the image
>>> from sage.all import * >>> X = CombinatorialFreeModule(QQ, [Integer(1),Integer(2),Integer(3)]); x = X.basis() >>> X.rename('X') >>> Y = CombinatorialFreeModule(QQ, [Integer(1),Integer(2),Integer(3),Integer(4),Integer(5)]); y = Y.basis() >>> ult = lambda i: sum( y[j] for j in range(i+Integer(1),Integer(6)) ) # uni-lower >>> phi = X.module_morphism(ult, triangular='lower', codomain=Y, ... inverse_on_support=lambda i: i-Integer(1) if i in [Integer(2),Integer(3),Integer(4)] else None) >>> ~phi Traceback (most recent call last): ... ValueError: Morphism not known to be invertible; see the invertible option of module_morphism >>> phiinv = phi.section() >>> list(map(phiinv*phi, X.basis().list())) == X.basis().list() True >>> phiinv(Y.basis()[Integer(1)]) Traceback (most recent call last): ... ValueError: B[1] is not in the image
- class sage.modules.with_basis.morphism.TriangularModuleMorphismByLinearity(domain, on_basis, codomain=None, category=None, **keywords)[source]¶
Bases:
ModuleMorphismByLinearity
,TriangularModuleMorphism
A concrete class for triangular module morphisms obtained by extending a function by linearity.
See also
ModulesWithBasis.ParentMethods.module_morphism()
for usage information and examples;sage.modules.with_basis.morphism
for a technical overview of the classes for module morphisms;
- class sage.modules.with_basis.morphism.TriangularModuleMorphismFromFunction(domain, function, codomain=None, category=None, **keywords)[source]¶
Bases:
ModuleMorphismFromFunction
,TriangularModuleMorphism
A concrete class for triangular module morphisms implemented by a function.
See also
ModulesWithBasis.ParentMethods.module_morphism()
for usage information and examples;sage.modules.with_basis.morphism
for a technical overview of the classes for module morphisms;
- sage.modules.with_basis.morphism.pointwise_inverse_function(f)[source]¶
Return the function \(x \mapsto 1 / f(x)\).
INPUT:
f
– a function
EXAMPLES:
sage: from sage.modules.with_basis.morphism import pointwise_inverse_function sage: def f(x): return x sage: g = pointwise_inverse_function(f) sage: g(1), g(2), g(3) (1, 1/2, 1/3)
>>> from sage.all import * >>> from sage.modules.with_basis.morphism import pointwise_inverse_function >>> def f(x): return x >>> g = pointwise_inverse_function(f) >>> g(Integer(1)), g(Integer(2)), g(Integer(3)) (1, 1/2, 1/3)
pointwise_inverse_function()
is an involution:sage: f is pointwise_inverse_function(g) True
>>> from sage.all import * >>> f is pointwise_inverse_function(g) True
Todo
This has nothing to do here!!! Should there be a library for pointwise operations on functions somewhere in Sage?