Skip to content

Commit 2b92e83

Browse files
authored
Add image and preimage to generic Map types (#2095)
* Add image and preimage to Map types * Add (pre)image for IdentityMap * Add image for MapCache * Add tests for (pre)image functions
1 parent cd318ff commit 2b92e83

File tree

7 files changed

+103
-20
lines changed

7 files changed

+103
-20
lines changed

src/generic/Map.jl

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,11 @@ map1(f::CompositeMap) = f.map1
1616
map2(f::CompositeMap) = f.map2
1717

1818
function (f::CompositeMap{D, C})(a) where {D, C}
19-
return f.map2(f.map1(a))::elem_type(C)
19+
return image(f, a)::elem_type(C)
20+
end
21+
22+
function image(f::Generic.CompositeMap{D, C}, a) where {D, C}
23+
return f.map2(f.map1(a))::elem_type(C)
2024
end
2125

2226
function preimage(f::Generic.CompositeMap{D, C}, a) where {D, C}
@@ -50,7 +54,10 @@ end
5054
#
5155
################################################################################
5256

53-
(f::IdentityMap)(a) = a
57+
(f::IdentityMap)(a) = image(f, a)
58+
59+
image(f::IdentityMap, a) = a
60+
preimage(f::IdentityMap, a) = a
5461

5562
domain(f::IdentityMap) = f.domain
5663
codomain(f::IdentityMap) = f.domain
@@ -106,10 +113,13 @@ codomain(f::FunctionalMap) = f.codomain
106113
image_fn(f::FunctionalMap) = f.image_fn
107114

108115
function (f::FunctionalMap{D, C})(a) where {D, C}
109-
parent(a) != domain(f) && throw(DomainError(f))
110-
return image_fn(f)(a)::elem_type(C)
116+
return image(f, a)::elem_type(C)
111117
end
112118

119+
function image(f::FunctionalMap{D, C}, a) where {D, C}
120+
parent(a) != domain(f) && throw(DomainError(f))
121+
return image_fn(f)(a)::elem_type(C)
122+
end
113123

114124
function Base.show(io::IO, M::FunctionalMap)
115125
if is_terse(io)
@@ -164,7 +174,11 @@ map1(f::FunctionalCompositeMap) = f.map1
164174
map2(f::FunctionalCompositeMap) = f.map2
165175

166176
function (f::FunctionalCompositeMap{D, C})(a) where {D, C}
167-
return image_fn(f)(a)::elem_type(C)
177+
return image(f, a)::elem_type(C)
178+
end
179+
180+
function image(f::FunctionalCompositeMap{D, C}, a) where {D, C}
181+
return image_fn(f)(a)::elem_type(C)
168182
end
169183

170184
function show(io::IO, M::FunctionalCompositeMap)

src/generic/MapCache.jl

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -26,21 +26,23 @@ function disable_cache!(M::MapCache)
2626
nothing
2727
end
2828

29-
function (M::MapCache{D, C, S, T, De, Ce})(a::De) where {D, C, S, T, De, Ce}
30-
if M.enabled
31-
if haskey(M.image_cache, a)
32-
return M.image_cache[a]::Ce
33-
else
34-
b = M.map(a)
35-
if M.limit > 0
36-
M.image_cache[a] = b
37-
M.limit -= 1
38-
end
39-
return b::Ce
29+
(M::MapCache{D, C, S, T, De, Ce})(a::De) where {D, C, S, T, De, Ce} = image(M, a)
30+
31+
function image(M::MapCache{D, C, S, T, De, Ce}, a::De) where {D, C, S, T, De, Ce}
32+
if M.enabled
33+
if haskey(M.image_cache, a)
34+
return M.image_cache[a]::Ce
35+
else
36+
b = M.map(a)
37+
if M.limit > 0
38+
M.image_cache[a] = b
39+
M.limit -= 1
4040
end
41-
else
41+
return b::Ce
42+
end
43+
else
4244
return M.map(a)::Ce
43-
end
45+
end
4446
end
4547

4648
show(io::IO, M::MapCache) = show(M.map)

src/generic/MapWithInverse.jl

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,15 @@ image_map(f::MapWithSection) = f.map
1919
preimage_map(f::MapWithSection) = f.section # for convenience only
2020
section_map(f::MapWithSection) = f.section
2121

22-
(f::MapWithSection{D, C})(a) where {D, C} = (f.map)(a)::elem_type(C)
22+
(f::MapWithSection{D, C})(a) where {D, C} = image(f, a)::elem_type(C)
2323

24+
function preimage(f::MapWithSection{D, C}, a) where {D, C}
25+
return inverse_fn(f)(a)::elem_type(D)
26+
end
27+
28+
function image(f::MapWithSection{D, C}, a) where {D, C}
29+
return image_fn(f)(a)::elem_type(C)
30+
end
2431

2532
function Base.show(io::IO, M::MapWithSection)
2633
if is_terse(io)
@@ -64,7 +71,15 @@ retraction_map(f::MapWithRetraction) = f.retraction
6471

6572
retraction_map(f::MapCache) = retraction_map(f.map)
6673

67-
(f::MapWithRetraction{D, C})(a) where {D, C} = (f.map)(a)::elem_type(C)
74+
(f::MapWithRetraction{D, C})(a) where {D, C} = image(f, a)::elem_type(C)
75+
76+
function preimage(f::MapWithRetraction{D, C}, a) where {D, C}
77+
return inverse_fn(f)(a)::elem_type(D)
78+
end
79+
80+
function image(f::MapWithRetraction{D, C}, a) where {D, C}
81+
return image_fn(f)(a)::elem_type(C)
82+
end
6883

6984
function Base.show(io::IO, M::MapWithRetraction)
7085
if is_terse(io)

src/generic/imports.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@ import ..AbstractAlgebra: gens
139139
import ..AbstractAlgebra: get_cached!
140140
import ..AbstractAlgebra: hom
141141
import ..AbstractAlgebra: identity_matrix
142+
import ..AbstractAlgebra: image
142143
import ..AbstractAlgebra: image_fn
143144
import ..AbstractAlgebra: inflate
144145
import ..AbstractAlgebra: integral

test/generic/Map-test.jl

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@ end
2626
@test domain(g) == AbstractAlgebra.JuliaZZ
2727
@test codomain(g) == AbstractAlgebra.JuliaQQ
2828

29+
@test image(f, ZZ(1)) == 2
30+
@test image(g, ZZ(2)) == QQ(2)
31+
2932
@test image_fn(f)(ZZ(1)) == 2
3033
@test image_fn(g)(ZZ(2)) == QQ(2)
3134
end
@@ -43,11 +46,13 @@ end
4346

4447
for i in 1:10
4548
@test h(ZZ(i)) == k(ZZ(i))
49+
@test image(h, ZZ(i)) == image(k, ZZ(i))
4650
end
4751

4852
@test domain(h) == AbstractAlgebra.JuliaZZ
4953
@test codomain(h) == AbstractAlgebra.JuliaQQ
5054

55+
@test image(h, ZZ(1)) == QQ(2)
5156
@test image_fn(h)(ZZ(1)) == QQ(2)
5257

5358
@test map1(h) === f
@@ -65,6 +70,7 @@ end
6570

6671
for i in 1:10
6772
@test t(ZZ(i)) == 2*(i + 2)
73+
@test image(t, ZZ(i)) == 2*(i + 2)
6874
end
6975

7076
@test domain(t) == AbstractAlgebra.JuliaZZ
@@ -100,6 +106,8 @@ end
100106
for i = 1:10
101107
@test g(ZZ(i)) == ZZ(i)
102108
@test h(ZZ(i)//(i + 1)) == ZZ(i)//(i + 1)
109+
@test image(g, ZZ(i)) == ZZ(i)
110+
@test image(h, ZZ(i)//(i + 1)) == ZZ(i)//(i + 1)
103111
end
104112

105113
@test compose(g, g) === g

test/generic/MapCache-test.jl

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,48 +8,62 @@
88
@test isa(h, Map(Generic.MapCache))
99

1010
@test f(ZZ(1)) == 2
11+
@test image(f, ZZ(1)) == 2
1112

1213
for i = 1:10
1314
@test g(ZZ(i)) == QQ(i)
15+
@test image(g, ZZ(i)) == QQ(i)
1416
end
1517

1618
@test h(ZZ(1)) == 3
19+
@test image(h, ZZ(1)) == 3
1720

1821
@test domain(f) == AbstractAlgebra.JuliaZZ
1922
@test codomain(g) == AbstractAlgebra.JuliaQQ
2023
@test domain(h) == AbstractAlgebra.JuliaZZ
2124

25+
@test image(f, ZZ(1)) == 2
2226
@test image_fn(f)(ZZ(1)) == 2
2327
end
2428

2529
@testset "Generic.MapCache.enable_disable" begin
2630
f = cached(map_from_func(x -> x + 1, ZZ, ZZ))
2731

2832
@test f(ZZ(1)) == 2
33+
@test image(f, ZZ(1)) == 2
2934

3035
disable_cache!(f)
3136

3237
@test f(ZZ(1)) == 2
3338
@test f(ZZ(2)) == 3
39+
@test image(f, ZZ(1)) == 2
40+
@test image(f, ZZ(2)) == 3
3441

3542
enable_cache!(f)
3643

3744
@test f(ZZ(1)) == 2
3845
@test f(ZZ(3)) == 4
46+
@test image(f, ZZ(1)) == 2
47+
@test image(f, ZZ(3)) == 4
3948

4049
g = cached(map_from_func(x -> x + 1, ZZ, ZZ), enabled=false)
4150

4251
@test g(ZZ(1)) == 2
52+
@test image(g, ZZ(1)) == 2
4353

4454
enable_cache!(g)
4555

4656
@test g(ZZ(1)) == 2
4757
@test g(ZZ(2)) == 3
58+
@test image(g, ZZ(1)) == 2
59+
@test image(g, ZZ(2)) == 3
4860

4961
disable_cache!(g)
5062

5163
@test g(ZZ(1)) == 2
5264
@test g(ZZ(3)) == 4
65+
@test image(g, ZZ(1)) == 2
66+
@test image(g, ZZ(3)) == 4
5367
end
5468

5569
@testset "Generic.MapCache.limit" begin
@@ -59,5 +73,6 @@ end
5973

6074
for i = 1:10
6175
@test g(ZZ(i)) == QQ(i)
76+
@test image(g, ZZ(i)) == QQ(i)
6277
end
6378
end

test/generic/MapWithInverse-test.jl

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ import AbstractAlgebra.PrettyPrinting
99
@test domain(s) == AbstractAlgebra.JuliaZZ
1010
@test codomain(s) == AbstractAlgebra.JuliaZZ
1111

12+
@test image(s, ZZ(1)) == 2
13+
@test preimage(s, ZZ(1)) == 0
14+
1215
@test image_fn(s)(ZZ(1)) == 2
1316
@test inverse_fn(s)(ZZ(1)) == 0
1417

@@ -22,6 +25,9 @@ import AbstractAlgebra.PrettyPrinting
2225
@test domain(t) == AbstractAlgebra.JuliaZZ
2326
@test codomain(t) == AbstractAlgebra.JuliaZZ
2427

28+
@test image(t, ZZ(1)) == 2
29+
@test preimage(t, ZZ(1)) == 0
30+
2531
@test image_fn(t)(ZZ(1)) == 2
2632
@test inverse_fn(t)(ZZ(1)) == 0
2733

@@ -34,9 +40,15 @@ import AbstractAlgebra.PrettyPrinting
3440

3541
@test u(ZZ(1)) == 2
3642

43+
@test image(u, ZZ(1)) == 2
44+
@test preimage(u, ZZ(1)) == 0
45+
3746
v = map_with_section_from_func(x -> x + 1, x -> x - 1, ZZ, ZZ)
3847

3948
@test u(ZZ(1)) == 2
49+
50+
@test image(v, ZZ(1)) == 2
51+
@test preimage(v, ZZ(1)) == 0
4052
end
4153

4254
@testset "Generic.MapWithInverse.composition" begin
@@ -52,12 +64,18 @@ end
5264

5365
@test u(ZZ(1)) == 4
5466

67+
@test image(u, ZZ(1)) == 4
68+
@test preimage(u, ZZ(4)) == 1
69+
5570
s = map_with_retraction(f, g)
5671
t = map_with_retraction(h, k)
5772

5873
u = compose(s, t)
5974

6075
@test u(ZZ(1)) == 4
76+
77+
@test image(u, ZZ(1)) == 4
78+
@test preimage(u, ZZ(4)) == 1
6179
end
6280

6381
@testset "Generic.MapWithInverse.inv" begin
@@ -77,6 +95,11 @@ end
7795
@test v(ZZ(1)) == -2
7896
@test w(ZZ(1)) == 0
7997

98+
@test image(v, ZZ(1)) == -2
99+
@test image(w, ZZ(1)) == 0
100+
@test preimage(v, ZZ(-2)) == 1
101+
@test preimage(w, ZZ(0)) == 1
102+
80103
s = map_with_retraction(f, g)
81104
t = map_with_retraction(h, k)
82105

@@ -87,6 +110,11 @@ end
87110

88111
@test v(ZZ(1)) == -2
89112
@test w(ZZ(1)) == 0
113+
114+
@test image(v, ZZ(1)) == -2
115+
@test image(w, ZZ(1)) == 0
116+
@test preimage(v, ZZ(-2)) == 1
117+
@test preimage(w, ZZ(0)) == 1
90118
end
91119

92120
@testset "Generic.MapWithInverse.printing" begin

0 commit comments

Comments
 (0)