-
Notifications
You must be signed in to change notification settings - Fork 11
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #44 from RexWzh/rex-dev
Gauss elimination for linear equation
- Loading branch information
Showing
9 changed files
with
210 additions
and
10 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,4 @@ | ||
Copyright (c) 2019 Jérémie Gillet <[email protected]> | ||
Copyright (c) 2019 Jérémie Gillet <[email protected]> and contributors | ||
|
||
Permission is hereby granted, free of charge, to any person obtaining a copy | ||
of this software and associated documentation files (the "Software"), to deal | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
# Tools for linear equation | ||
|
||
""" | ||
gauss_elimination(A::AbstractMatrix, b::AbstractVector) | ||
Solve the linear equations `Ax=b` by Gauss elimination. | ||
""" | ||
gauss_elimination(A::AbstractMatrix, b::AbstractVector) = gauss_elimination!(copy(A), copy(b)) | ||
function gauss_elimination!(A::AbstractMatrix, b::AbstractVector) | ||
x = gauss_elimination!(A, reshape(b, :, 1)) | ||
reshape(x, :) # convert to vector | ||
end | ||
|
||
""" | ||
gauss_elimination(A::AbstractMatrix, B::AbstractMatrix) | ||
Solve the linear equations `Ax=B` by Gauss elimination. | ||
In particular, `Ax=I` returns the inverse of `A`. | ||
""" | ||
gauss_elimination(A::AbstractMatrix, B::AbstractMatrix) = gauss_elimination!(copy(A), copy(B)) | ||
function gauss_elimination!(A::AbstractMatrix, B::AbstractMatrix) | ||
# check the size of A and B | ||
m, n = size(A) | ||
m == n || throw(DimensionMismatch("A must be square")) | ||
size(B, 1) == m || throw(DimensionMismatch("A and B have different size")) | ||
# Gauss elimination | ||
@inbounds for i in 1:n | ||
# Find the pivot | ||
pivot = findfirst(!iszero, @view(A[i:end, i])) | ||
pivot === nothing && throw(ArgumentError("A is singular")) | ||
pivot += i - 1 | ||
# Swap the pivot row with the current row | ||
currow = @views divide.(A[pivot, :], A[pivot, i]) # set leading entry to 1 | ||
curval = @views divide.(B[pivot, :], A[pivot, i]) | ||
A[pivot, :] = @view(A[i, :]) # `=` is faster than `.=` in general | ||
B[pivot, :] = @view(B[i, :]) | ||
A[i, :], B[i, :] = currow, curval | ||
# Eliminate the current column | ||
for j in 1:n | ||
j == i && continue | ||
# rowⱼ = rowⱼ - Aⱼᵢ * rowᵢ | ||
if !iszero(A[j, i]) | ||
B[j, :] .⊻= mult.(A[j, i], curval) | ||
A[j, :] .⊻= mult.(A[j, i], currow) | ||
end | ||
end | ||
end | ||
return B | ||
end | ||
|
||
""" | ||
gfinv(A::AbstractMatrix) | ||
Return the inverse of `A` in GF(256). | ||
""" | ||
Polynomial.gfinv(A::AbstractMatrix) = gauss_elimination(A, one(A)) | ||
|
||
""" | ||
fillblank( block::AbstractVector{<:Integer} | ||
, validinds::AbstractVector{<:Integer} | ||
, necwords::Int) | ||
Use Gauss elimination to fill the blank entries in `block` | ||
with valid indices `misinds`. | ||
""" | ||
function fillblank( block::AbstractVector{<:Integer} | ||
, validinds::AbstractVector{<:Integer} | ||
, necwords::Int) | ||
reclen = length(block) | ||
length(validinds) + necwords == reclen || throw(DimensionMismatch( | ||
"The number of missing indices must be equal to `necwords`")) | ||
msglen = reclen - necwords | ||
G = generator_matrix(eltype(block), msglen, necwords) | ||
G = @view(G[end:-1:1, end:-1:1]) # rotate by 180 degree | ||
msg = @views gauss_elimination(G[validinds, :], block[validinds]) | ||
return mult(G, msg) # encode message | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
# Test for Gauss elimination | ||
function fillblankbyFA( block::AbstractVector{<:Integer} | ||
, misinds::AbstractVector{<:Integer} | ||
, necwords::Int) | ||
n = length(block) # number of bytes | ||
recpoly = Poly(reverse(block)) | ||
orgpoly = fillerasures!(recpoly, n .- misinds, necwords) | ||
return @view(orgpoly.coeff[end:-1:1]) | ||
end | ||
|
||
@testset "Fill blank -- Gauss elimination vs Forney algorithm" begin | ||
# test for fillblank | ||
msglen = rand(1:100) | ||
necwords = rand(1:255 - msglen) | ||
reclen = msglen + necwords | ||
block = rand(0:255, reclen) | ||
validinds = sample(1:msglen, msglen, replace=false) | ||
misinds = setdiff(1:reclen, validinds) | ||
# Note that Gauss elimination takes O(N^3) | ||
# while Forney Algorithm takes O(N^2) | ||
validblock = fillblank(block, validinds, necwords) | ||
blockbyFA = fillblankbyFA(block, misinds, necwords) | ||
@test validblock == blockbyFA | ||
@test validblock[validinds] == block[validinds] | ||
# test for UInt8 | ||
msglen = rand(1:100) | ||
necwords = rand(1:255 - msglen) | ||
reclen = msglen + necwords | ||
block = rand(UInt8, reclen) | ||
validinds = sample(1:msglen, msglen, replace=false) | ||
misinds = setdiff(1:reclen, validinds) | ||
validblock = fillblank(block, validinds, necwords) | ||
blockbyFA = fillblankbyFA(block, misinds, necwords) | ||
@test validblock == blockbyFA | ||
@test validblock[validinds] == block[validinds] | ||
end | ||
|
||
## use Gauss elimination to find the inverse of the matrix | ||
@testset "Generator matrix -- inverse of submatrix" begin | ||
# Test for matrix inverse | ||
## Int | ||
A = [1 2 3; 4 5 6; 7 8 9] | ||
A1 = gfinv(A) | ||
@test mult(A, A1) |> isone | ||
A = [1 2 3; 4 5 6; 5 7 9] # note that this matrix is invertible in GF(256) | ||
A1 = gfinv(A) | ||
@test mult(A, A1) |> isone | ||
## UInt8 | ||
A = UInt8[1 2 3; 4 5 6; 7 8 9] | ||
A1 = gfinv(A) | ||
@test mult(A, A1) |> isone | ||
## test throw | ||
@test_throws ArgumentError gfinv([1 2; 1 2]) | ||
A = [1 2 3; 4 5 6; 7 8 9] | ||
A[3, :] = A[1, :] .⊻ A[2, :] | ||
@test_throws ArgumentError gfinv(A) | ||
## any `msglen` rows of a generator matrix are linearly dependent | ||
msglen = 3 | ||
necwords = 5 | ||
reclen = msglen + necwords | ||
A = generator_matrix(msglen, necwords) | ||
rows = sample(1:reclen, msglen, replace=false) | ||
@test mult(gfinv(A[rows, :]), A[rows, :]) |> isone | ||
|
||
necwords, _, msglen = getecinfo(1, Medium()) | ||
A = generator_matrix(msglen, necwords) | ||
rows = sample(1:msglen + necwords, msglen, replace=false) | ||
@test mult(gfinv(A[rows, :]), A[rows, :]) |> isone | ||
### random test | ||
for eclevel in eclevels, v in 1:40 | ||
necwords, _, msglen, _, msglen2 = getecinfo(v, eclevel) | ||
A = generator_matrix(msglen, necwords) | ||
rows = sample(1:msglen + necwords, msglen, replace=false) | ||
@test mult(gfinv(A[rows, :]), A[rows, :]) |> isone | ||
A = generator_matrix(msglen2, necwords) | ||
rows = sample(1:msglen2 + necwords, msglen2, replace=false) | ||
@test mult(gfinv(A[rows, :]), A[rows, :]) |> isone | ||
end | ||
|
||
end | ||
|
||
@testset "Linear equations" begin | ||
A = [1 2 3; 4 5 6; 7 8 9] | ||
b = [1, 2, 3] | ||
x = gauss_elimination(A, b) | ||
@test mult(A, x) == b | ||
b = reshape([1, 2, 3], :, 1) | ||
x = gauss_elimination(A, b) | ||
@test mult(A, x) == b | ||
B = rand(0:255, 3, rand(1:10)) | ||
x = gauss_elimination(A, B) | ||
@test mult(A, x) == B | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters