From 1e633557d618a3c5572959b8da069fca39cd8814 Mon Sep 17 00:00:00 2001 From: Lionel Zoubritzky Date: Tue, 5 Jul 2022 19:12:24 +0200 Subject: [PATCH] Slightly refine `gaussian_elimination` semantics --- src/algorithms/rings.jl | 36 +++++++++++++++++++++--------------- test/runtests.jl | 18 ++++++++++-------- 2 files changed, 31 insertions(+), 23 deletions(-) diff --git a/src/algorithms/rings.jl b/src/algorithms/rings.jl index 25f7b97..a1ee894 100644 --- a/src/algorithms/rings.jl +++ b/src/algorithms/rings.jl @@ -1187,7 +1187,19 @@ end IterativeGaussianElimination(ring, sizehint=ring[1]) = IterativeGaussianEliminationNone(ring, sizehint) IterativeGaussianElimination() = IterativeGaussianEliminationNone() -function _gaussian_elimination(gauss::IterativeGaussianElimination{T}, r::Vector{Int}) where T +""" + gaussian_elimination(gauss::IterativeGaussianElimination, r::Vector{Int}) + +Return `notindependent, info` where `notindependent` is `true` if `r` can be expressed as a +sum of vectors stored in `gauss`. + +See [`PeriodicGraphs.gaussian_elimination!`](@ref) to store `r` in `gauss` if not, and for +more details dependending on the type of `gauss`. + +Call `PeriodicGraphs.gaussian_elimination!(gauss, r, notindependent, info)` to obtain the +result of `PeriodicGraphs.gaussian_elimination!(gauss, r)` without duplicating computation. +""" +function gaussian_elimination(gauss::IterativeGaussianElimination{T}, r::Vector{Int}) where T rings = gauss.rings shortcuts = gauss.shortcuts buffer1::Vector{Int} = gauss.buffer1 @@ -1212,7 +1224,7 @@ function _gaussian_elimination(gauss::IterativeGaussianElimination{T}, r::Vector push!(track, idx) end symdiff_cycles!(buffer1, r, ridx) - isempty(buffer1) && return true, r1, maxlen, buffer1 + isempty(buffer1) && return true, (r1, maxlen, buffer1) r1 = buffer1[1] idx = r1 > lenshort ? zero(Int32) : shortcuts[r1] else @@ -1226,24 +1238,15 @@ function _gaussian_elimination(gauss::IterativeGaussianElimination{T}, r::Vector push!(track, idx) end symdiff_cycles!(buffer2, buffer1, ridx) - isempty(buffer2) && return true, r1, maxlen, buffer1 + isempty(buffer2) && return true, (r1, maxlen, buffer1) r1 = buffer2[1] idx = r1 > lenshort ? zero(Int32) : shortcuts[r1] buffer2, buffer1 = buffer1, buffer2 end - return false, r1, maxlen, buffer1 + return false, (r1, maxlen, buffer1) end -""" - gaussian_elimination(gauss::IterativeGaussianElimination, r::Vector{Int}) - -Test whether `r` can be expressed as a sum of vectors stored in `gauss`. - -See [`PeriodicGraphs.gaussian_elimination!`](@ref) to store `r` in `gauss` if not, and for -more details dependending on the type of `gauss`. -""" -gaussian_elimination(gauss::IterativeGaussianElimination, r::Vector{Int}) = first(_gaussian_elimination(gauss, r)) # For an IterativeGaussianElimination of i rings of size at most l, symdiff_cycles cost at # most (l + lenr) + (2l + lenr) + ... + (il + lenr) = O(i^2*l +i*lenr) @@ -1267,6 +1270,11 @@ to obtain the sorted list of indices of such previously encountered vectors. See also [`gaussian_elimination`](@ref) to test `r` without storing it. """ function gaussian_elimination!(gauss::IterativeGaussianElimination{T}, r::Vector{Int}) where T + notindependent, info = gaussian_elimination(gauss, r) + gaussian_elimination!(gauss, r, notindependent, info) +end + +function gaussian_elimination!(gauss::IterativeGaussianElimination{T}, r::Vector{Int}, notindependent, (r1, maxlen, buffer1)) where T rings = gauss.rings shortcuts = gauss.shortcuts if gauss isa IterativeGaussianEliminationLength @@ -1275,8 +1283,6 @@ function gaussian_elimination!(gauss::IterativeGaussianElimination{T}, r::Vector track::Vector{Int32} = first(gauss.track) end - notindependent, r1, maxlen, buffer1 = _gaussian_elimination(gauss, r) - if notindependent gauss isa IterativeGaussianEliminationLength && return maxlen < len if gauss isa IterativeGaussianEliminationDecomposition diff --git a/test/runtests.jl b/test/runtests.jl index 6a3bcc2..0d5c360 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -742,12 +742,13 @@ end @test !PeriodicGraphs.gaussian_elimination!(gausslengths, [4, 7]) @test !PeriodicGraphs.gaussian_elimination!(gausslengths, [1, 3, 5]) @test length(gausslengths.track) == length(gausslengths.rings) == 4 - @test PeriodicGraphs.gaussian_elimination(gausslengths, [1, 4, 5, 7]) + @test first(PeriodicGraphs.gaussian_elimination(gausslengths, [1, 4, 5, 7])) @test PeriodicGraphs.gaussian_elimination!(gausslengths, [1, 4, 5, 7]) @test length(gausslengths.track) == length(gausslengths.rings) == 4 @test !PeriodicGraphs.gaussian_elimination!(gausslengths, [3, 5, 6, 7]) - @test !PeriodicGraphs.gaussian_elimination(gausslengths, [2, 3]) - @test !PeriodicGraphs.gaussian_elimination!(gausslengths, [2, 3]) + notindependent, info = PeriodicGraphs.gaussian_elimination(gausslengths, [2, 3]) + @test !notindependent + @test !PeriodicGraphs.gaussian_elimination!(gausslengths, [2, 3], notindependent, info) @test !PeriodicGraphs.gaussian_elimination!(gausslengths, [1, 2, 3]) @test length(gausslengths.track) == length(gausslengths.rings) == 7 @@ -756,11 +757,11 @@ end @test !PeriodicGraphs.gaussian_elimination!(gaussnone, [4, 7]) @test !PeriodicGraphs.gaussian_elimination!(gaussnone, [1, 3, 5]) @test length(gaussnone.rings) == 4 - @test PeriodicGraphs.gaussian_elimination(gaussnone, [1, 4, 5, 7]) + @test first(PeriodicGraphs.gaussian_elimination(gaussnone, [1, 4, 5, 7])) @test PeriodicGraphs.gaussian_elimination!(gaussnone, [1, 4, 5, 7]) @test !PeriodicGraphs.gaussian_elimination!(gaussnone, [3, 5, 6, 7]) @test !PeriodicGraphs.gaussian_elimination!(gaussnone, [2, 3]) - @test !PeriodicGraphs.gaussian_elimination(gaussnone, [1, 2, 3]) + @test !first(PeriodicGraphs.gaussian_elimination(gaussnone, [1, 2, 3])) @test !PeriodicGraphs.gaussian_elimination!(gaussnone, [1, 2, 3]) @test PeriodicGraphs.gaussian_elimination!(gaussnone, [1, 2, 3]) @test gaussnone.shortcuts == Int32[4, 6, 1, 2, 5, 3, 7] @@ -771,12 +772,13 @@ end @test !PeriodicGraphs.gaussian_elimination!(gausstrack, [4, 7]) @test !PeriodicGraphs.gaussian_elimination!(gausstrack, [1, 3, 5]) @test length(gausstrack.rings) == 4 - @test PeriodicGraphs.gaussian_elimination(gausstrack, [1, 4, 5, 7]) - @test PeriodicGraphs.gaussian_elimination!(gausstrack, [1, 4, 5, 7]) + notindependent, info = PeriodicGraphs.gaussian_elimination(gausstrack, [1, 4, 5, 7]) + @test notindependent + @test PeriodicGraphs.gaussian_elimination!(gausstrack, [1, 4, 5, 7], notindependent, info) @test PeriodicGraphs.retrieve_track!(gausstrack) == Int32[5, 4, 1] @test !PeriodicGraphs.gaussian_elimination!(gausstrack, [3, 5, 6, 7]) @test !PeriodicGraphs.gaussian_elimination!(gausstrack, [2, 3]) - @test !PeriodicGraphs.gaussian_elimination(gausstrack, [1, 2, 3]) + @test !first(PeriodicGraphs.gaussian_elimination(gausstrack, [1, 2, 3])) @test !PeriodicGraphs.gaussian_elimination!(gausstrack, [1, 2, 3]) @test PeriodicGraphs.gaussian_elimination!(gausstrack, [1, 2, 3]) @test PeriodicGraphs.retrieve_track!(gausstrack) == Int32[9, 8]