-
Notifications
You must be signed in to change notification settings - Fork 63
/
ModuleHomomorphism.jl
141 lines (122 loc) · 4.73 KB
/
ModuleHomomorphism.jl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
###############################################################################
#
# ModuleHomomorphism.jl : Generic homomorphisms of free/sub/quotient modules
#
###############################################################################
###############################################################################
#
# Basic manipulation
#
###############################################################################
domain(f::ModuleHomomorphism) = f.domain
codomain(f::ModuleHomomorphism) = f.codomain
image_fn(f::ModuleHomomorphism) = f.image_fn
domain(f::ModuleIsomorphism) = f.domain
codomain(f::ModuleIsomorphism) = f.codomain
image_fn(f::ModuleIsomorphism) = f.image_fn
inverse_mat(f::Map(ModuleIsomorphism)) = f.inverse_matrix
inverse_image_fn(f::Map(ModuleIsomorphism)) = f.inverse_image_fn
###############################################################################
#
# String I/O
#
###############################################################################
function show(io::IO, f::Map(ModuleIsomorphism))
if get(io, :supercompact, false)
print(io, "Module isomorphism")
else
io = pretty(io)
print(io, "Hom: ", Lowercase(), domain(f))
print(io, " -> ", Lowercase(), codomain(f))
end
end
###############################################################################
#
# Composition
#
###############################################################################
function compose(f::Map(ModuleIsomorphism), g::Map(ModuleIsomorphism))
check_composable(f, g)
T = elem_type(base_ring(domain(f)))
return ModuleIsomorphism{T}(domain(f), codomain(g), f.matrix*g.matrix,
g.inverse_matrix*f.inverse_matrix)
end
###############################################################################
#
# Inverse
#
###############################################################################
@doc raw"""
Base.inv(f::Map(ModuleIsomorphism))
Return the inverse map of the given module isomorphism. This is computed
cheaply.
"""
function Base.inv(f::Map(ModuleIsomorphism))
T = elem_type(base_ring(domain(f)))
return ModuleIsomorphism{T}(codomain(f), domain(f), inverse_mat(f), matrix(f))
end
###############################################################################
#
# Call overload
#
###############################################################################
function (f::ModuleHomomorphism{T})(a::AbstractAlgebra.FPModuleElem{T}) where T <: RingElement
parent(a) !== domain(f) && error("Incompatible module element")
return image_fn(f)(a)
end
function (f::ModuleIsomorphism{T})(a::AbstractAlgebra.FPModuleElem{T}) where T <: RingElement
parent(a) !== domain(f) && error("Incompatible module element")
return image_fn(f)(a)
end
###############################################################################
#
# ModuleHomomorphism constructor
#
###############################################################################
function ModuleHomomorphism(M1::AbstractAlgebra.FPModule{T},
M2::AbstractAlgebra.FPModule{T}, m::AbstractAlgebra.MatElem{T}) where
T <: RingElement
(nrows(m) == ngens(M1) && ncols(m) == ngens(M2)) ||
error("dimension mismatch")
return ModuleHomomorphism{T}(M1, M2, m)
end
function ModuleHomomorphism(M1::AbstractAlgebra.FPModule{T},
M2::AbstractAlgebra.FPModule{T}, v::Vector{S}) where
{T <: RingElement, S<:AbstractAlgebra.FPModuleElem{T}}
return ModuleHomomorphism(M1, M2, vcat([Generic._matrix(x) for x = v]...))
end
function ModuleIsomorphism(M1::AbstractAlgebra.FPModule{T},
M2::AbstractAlgebra.FPModule{T}, M::AbstractAlgebra.MatElem{T}) where
T <: RingElement
# Put rows of m and target relations into a matrix
R = base_ring(M1)
R != base_ring(M2) && error("Incompatible modules")
trels = rels(M2)
q = length(trels)
m = nrows(M)
n = ncols(M)
(ngens(M1) != m || ngens(M2) != n) &&
error("Matrix of the wrong dimensions")
if m == 0 || n == 0
M_inv = matrix(R, n, m, T[])
else
# Put matrix M and target relations in a matrix
mat = zero_matrix(R, m + q, n)
for i = 1:m
for j = 1:n
mat[i, j] = M[i, j]
end
end
for i = 1:q
for j = 1:n
mat[m + i, j] = trels[i].v[1, j]
end
end
# Find left inverse of mat
N = identity_matrix(R, n)
X = AbstractAlgebra._solve_left(mat, N)
# Construct matrix of inverse homomorphism from first m columns of X
M_inv = X[:, 1:m]
end
return ModuleIsomorphism{T}(M1, M2, M, M_inv)
end