Skip to content

Commit c0e2ae2

Browse files
committed
Refactored bounds
1 parent 6c4ecd1 commit c0e2ae2

File tree

3 files changed

+342
-342
lines changed

3 files changed

+342
-342
lines changed

src/CodingTheory.jl

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,12 @@ export no_round, getindex, setindex!, firstindex, lastindex, size, length, rand,
2626
# RREF
2727
export rref, rref!
2828

29-
# Messages, Distance, and Primes
29+
# Bounds, Messages, Distance, and Primes
3030
export rate, sphere_covering_bound, sphere_packing_bound, hamming_bound,
3131
singleton_bound, gilbert_varshamov_bound, elias_bassalygo_bound,
3232
plotkin_bound, construct_ham_matrix, isperfect, ishammingperfect,
33-
isgolayperfect, get_codewords_greedy, get_codewords_random,
34-
get_all_words, get_codewords
33+
isgolayperfect
34+
export get_codewords_greedy, get_codewords_random, get_all_words, get_codewords
3535
export hamming_distance, hamming_ball, code_distance, t_error_detecting,
3636
t_error_correcting, find_error_detection_max, find_error_correction_max
3737
export isprimepower
@@ -47,6 +47,7 @@ export levenshtein, levenshtein!
4747
include("abstract_types.jl")
4848
include("rref.jl")
4949
include("messages.jl") # implicitly exports distance.jl and primes.jl
50+
include("bounds.jl")
5051
include("algebra.jl")
5152
include("levenshtein.jl")
5253

src/bounds.jl

Lines changed: 338 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,338 @@
1+
"""
2+
```julia
3+
rate(q::Integer, M::Integer, n::Integer) -> Real
4+
```
5+
6+
Calculate the rate of a code. That is, how efficient the code is.
7+
8+
Parameters:
9+
- `q::Integer`: the number of symbols in the code.
10+
- `M::Integer`: the size/number of elements in the code.
11+
- `n::Integer`: The word length.
12+
13+
Returns:
14+
- `Real`: Rate of the code.
15+
16+
---
17+
18+
### Examples
19+
20+
```julia
21+
julia> rate(3, 5, 4) # the rate of the code which has 3 symbols, 5 words in the code, and word length of 4 (e.g., Σ = {A, B, C}, C = {ABBA,CABA,BBBB,CAAB,ACBB})
22+
0.3662433801794817
23+
```
24+
"""
25+
rate(q::T, M::T, n::T) where {T <: Integer} = log(q, M) / n
26+
27+
__spheres(q::T, n::T, r::T) where {T <: Integer} = sum(Integer[((big(q) - 1)^i) * binomial(big(n), big(i)) for i in 0:r])
28+
__sphere_bound(round_func::Function, q::T, n::T, d::T) where {T <: Integer} = round_func((big(q)^n) / __spheres(q, n, d))
29+
30+
"""
31+
```julia
32+
sphere_covering_bound(q::Integer, n::Integer, d::Integer) -> Integer
33+
```
34+
35+
Computes the sphere covering bound of a ``[n, d]_q``-code.
36+
37+
Parameters:
38+
- `q::Integer`: the number of symbols in the code.
39+
- `n::Integer`: the word length.
40+
- `d::Integer`: the distance of the code.
41+
42+
Returns:
43+
- `Integer`: the sphere covering bound.
44+
45+
---
46+
47+
### Examples
48+
49+
```julia
50+
julia> sphere_covering_bound(5,7,3)
51+
215
52+
```
53+
"""
54+
sphere_covering_bound(q::T, n::T, d::T) where {T <: Integer} = __sphere_bound(ceil, q, n, d - 1)
55+
56+
"""
57+
```julia
58+
sphere_packing_bound(q::Integer, n::Integer, d::Integer) -> Integer
59+
sphere_packing_bound(q::Integer, n::Integer, d::Integer, ::Rounding) -> Real
60+
```
61+
62+
Computes the sphere packing bound of a ``[n, d]_q``-code. The sphere packing bound is also known as the hamming bound. You can use `hamming_bound` to compute the same thing.
63+
64+
Parameters:
65+
- `q::Integer`: the number of symbols in the code.
66+
- `n::Integer`: the word length.
67+
- `d::Integer`: the distance of the code.
68+
- `::Rounding`: use the argument `no_round` in this position to preserve the rounding of the code &mdash; which usually by default rounds down.
69+
70+
Returns:
71+
- `Integer`: the sphere packing bound.
72+
73+
---
74+
75+
### Examples
76+
77+
```julia
78+
julia> sphere_packing_bound(5,7,3)
79+
2693
80+
```
81+
"""
82+
sphere_packing_bound(q::T, n::T, d::T) where T <: Integer =
83+
__sphere_bound(a -> floor(T, a), q, n, floor(T, (d - 1) / 2))
84+
sphere_packing_bound(q::T, n::T, d::T, ::Rounding) where T <: Integer =
85+
__sphere_bound(identity, q, n, floor(T, (d - 1) / 2))
86+
hamming_bound(q::T, n::T, d::T) where T <: Integer =
87+
sphere_packing_bound(q, n, d)
88+
hamming_bound(q::T, n::T, d::T, ::Rounding) where T <: Integer =
89+
sphere_packing_bound(q, n, d, no_round)
90+
91+
"""
92+
```julia
93+
sphere_packing_bound(q::Integer, n::Integer, d::Integer) -> Real
94+
```
95+
96+
Computes the Singleton bound of a ``[n, d]_q``-code.
97+
98+
Parameters:
99+
- `q::Integer`: the number of symbols in the code.
100+
- `n::Integer`: the word length.
101+
- `d::Integer`: the distance of the code.
102+
103+
Returns:
104+
- `Real`: the Singleton bound. Can round down, as it is an equivalent to the Hamming bound in that it is an upper bound.
105+
"""
106+
# promote()
107+
# _T = typeof(T)
108+
109+
singleton_bound(q::T, n::T, d::T) where T <: Integer =
110+
floor(T, float(big(q))^(big(n) - big(d) + 1))
111+
singleton_bound(q::T, n::T, d::T, ::Rounding) where T <: Integer =
112+
float(big(q))^(big(n) - big(d) + 1)
113+
114+
115+
gilbert_varshamov_bound(q::T, n::T, d::T) where T <: Integer =
116+
__sphere_bound(a -> floor(T, a), q, n, d - 1)
117+
gilbert_varshamov_bound(q::T, n::T, d::T, ::Rounding) where T <: Integer =
118+
__sphere_bound(identity, q, n, d - 1)
119+
120+
function __plotkin_bound_core(round_func::Function, q::T, n::T, d::T) where T <: Integer
121+
if ! isequal(q, 2)
122+
throw(error("The Plotkin bound only works for the binary code."))
123+
end
124+
125+
if iseven(d) && 2d > n
126+
return round_func((d) / (2d + 1 - n))
127+
elseif isodd(d) && 2d + 1 > n
128+
return round_func((d + 1) / (2d + 1 - n))
129+
elseif iseven(d)
130+
return T(4d)
131+
# return A_2(2d, d) ≤ 4d
132+
elseif isodd(d)
133+
return T(4d + 4)
134+
# return A_2(2d + 1, d) ≤ 4d + 4
135+
end
136+
end
137+
138+
plotkin_bound(q::T, n::T, d::T) where T <: Integer =
139+
__plotkin_bound_core(a -> floor(T, a), q, n, d)
140+
plotkin_bound(q::T, n::T, d::T, ::Rounding) where T <: Integer =
141+
__plotkin_bound_core(identity, q, n, d, no_round)
142+
143+
elias_bassalygo_bound(q::T, n::T, d::T) where T <: Integer =
144+
elias_bassalygo_bound(q::T, n::T, d::T, ::Rounding) where T <: Integer =
145+
146+
function __johnson_bound_core(round_func::Function, q::T, n::T, d::T) where T <: Integer
147+
if isinteger((d - 1) / 2) # is odd
148+
t = T((d - 1) / 2)
149+
__sphere_bound(round_func, q, n, t) # if d = 2t + 1
150+
elseif isinteger(d / 2)
151+
t = T(d / 2)
152+
__sphere_bound(round_func, q, n, t)
153+
end
154+
end
155+
156+
@doc raw"""
157+
```julia
158+
construct_ham_matrix(r::Int, q::Int) -> Matrix
159+
```
160+
161+
Construct a Hamming parity-check matrix.
162+
163+
Parameters:
164+
- `r::Int`: number of rows of a parity check matrix.
165+
- `q:::Int`: The size of the alphabet of the code.
166+
167+
Returns:
168+
- `Matrix`: The Hamming matrix, denoted as ``\text{Ham}(r, q)``
169+
170+
---
171+
172+
### Examples
173+
174+
```julia
175+
julia> construct_ham_matrix(3,2)
176+
3×7 Array{Int64,2}:
177+
0 0 0 1 1 1 1
178+
0 1 1 0 0 1 1
179+
1 0 1 0 1 0 1
180+
```
181+
"""
182+
function construct_ham_matrix(r::Int, q::Int)
183+
ncols = Int(floor((q^r - 1) / (q - 1)))
184+
M = Matrix{Int}(undef, r, ncols)
185+
186+
for i in 1:ncols
187+
M[:, i] = reverse(digits(parse(Int, string(i, base = q)), pad = r), dims = 1)
188+
end
189+
190+
return M
191+
end
192+
193+
"""
194+
```julia
195+
isperfect(n::Int, k::Int, d::Int, q::Int) -> Bool
196+
```
197+
198+
Checks if a code is perfect. That is, checks if the number of words in the code is exactly the "Hamming bound", or the "Sphere Packing Bound".
199+
200+
Parameters:
201+
- `q:::Int`: The size of the alphabet of the code.
202+
- `n::Int`: The length of the words in the code (block length).
203+
- `d::Int`: The distance of the code.
204+
- `k::Int`: The dimension of the code.
205+
206+
Returns:
207+
- `Bool`: true or false
208+
209+
---
210+
211+
### Examples
212+
213+
```julia
214+
julia> isperfect(11, 6, 5, 3)
215+
true
216+
```
217+
"""
218+
function isperfect(n::T, k::T, d::T, q::T) where T <: Int
219+
isprimepower(q) || throw(error("Cannot check if the code is perfect with q not a prime power."))
220+
M = q^k
221+
222+
isequal(sphere_packing_bound(q, n, d), M) && return true
223+
return false
224+
end
225+
226+
"""
227+
```julia
228+
ishammingbound(r::Int, q::Int) -> Bool
229+
```
230+
231+
Checks if the code is a perfect code that is of the form of a generalised Hamming code.
232+
233+
Parameters:
234+
- `r::Int`: number of rows of a parity check matrix.
235+
- `q::Int`: The size of the alphabet of the code.
236+
237+
Returns:
238+
- `Bool`: true or false
239+
"""
240+
function ishammingperfect(r::Int, q::Int)
241+
n = 2^r - 1
242+
k = n - r
243+
M = q^k
244+
d = size(construct_ham_matrix(r, q), 1) # the number of rows of the hamming matrix (which is, by design, linearly independent)
245+
d = r
246+
# r is dim of dueal code; dim of code itself is block length minus r
247+
# println(n)
248+
# println((q^r - 1) / (q - 1))
249+
250+
isequal(n, (q^r - 1) / (q - 1)) && \
251+
isequal(d, 3) && \
252+
isequal(M, q^(((q^r - 1) / (q - 1)) - r)) && \
253+
return true
254+
return false
255+
end
256+
257+
"""
258+
```julia
259+
ishammingperfect(n::Int, k::Int, d::Int, q::Int) -> Bool
260+
ishammingperfect(q::Int, n::Int, d::Int) -> Bool
261+
```
262+
263+
Checks if the code is a perfect code that is of the form of a generalised Hamming code.
264+
265+
Parameters:
266+
- `q:::Int`: The size of the alphabet of the code.
267+
- `n::Int`: The length of the words in the code (block length).
268+
- `d::Int`: The distance of the code.
269+
- `k::Int`: The dimension of the code.
270+
271+
Returns:
272+
- `Bool`: true or false
273+
274+
---
275+
276+
### Examples
277+
278+
```julia
279+
julia> isgolayperfect(11, 6, 5, 3) # this is one of golay's perfect codes
280+
true
281+
```
282+
"""
283+
function ishammingperfect(n::T, k::T, d::T, q::T) where T <: Int
284+
isprimepower(q) || return false
285+
286+
M = q^k
287+
r = log(ℯ, ((n * log(ℯ, 1)) / (log(ℯ, 2))) + 1) / log(ℯ, 2)
288+
289+
if isequal(n, (q^(r - 1)) / (q - 1)) && isequal(d, 3) && isequal(M, q^(((q^r - 1) / (q - 1)) - r))
290+
return true
291+
end
292+
293+
return false
294+
end
295+
function ishammingperfect(q::Int, n::Int, d::Int)
296+
isprimepower(q) || return false # we are working in finite fields, so q must be a prime power
297+
d 3 && return false
298+
299+
r = 1
300+
while ((q^r - 1) / (q - 1)) < n
301+
r = r + 1
302+
end
303+
304+
return ifelse(isequal(((q^r - 1) / (q - 1)), n), true, false)
305+
end
306+
307+
"""
308+
```julia
309+
isgolayperfect(n::Int, k::Int, d::Int, q::Int) -> Bool
310+
```
311+
312+
Golay found two perfect codes. `isgolayperfect` checks if a code of block length n, distance d, alphabet size q, and dimension k, is a perfect code as described by Golay.
313+
314+
Parameters:
315+
- `n::Int`: The block length of words in the code (e.g., word "abc" has block length 3).
316+
- `k::Int`: The dimension of the code.
317+
- `d::Int`: The distance of the code (i.e., the minimum distance between codewords in the code).
318+
- `q::Int`: An Int that is a prime power. The modulus of the finite field.
319+
320+
Returns:
321+
- `Bool`: true or false.
322+
323+
---
324+
325+
### Examples
326+
327+
```julia
328+
julia> isgolayperfect(11, 6, 5, 3) # this is one of golay's perfect codes
329+
true
330+
```
331+
"""
332+
function isgolayperfect(n::T, k::T, d::T, q::T) where T <: Int
333+
isprimepower(q) || false # we are working in finite fields, so q must be a prime power
334+
M = q^k
335+
(isequal(q, 2) && isequal(n, 23) && isequal(d, 7) && isequal(M, 2^12)) && return true
336+
(isequal(q, 3) && isequal(n, 11) && isequal(d, 5) && isequal(M, 3^6)) && return true
337+
return false
338+
end

0 commit comments

Comments
 (0)