diff --git a/docs/src/linear_solving.md b/docs/src/linear_solving.md index 39659b20cc..aefa68ff25 100644 --- a/docs/src/linear_solving.md +++ b/docs/src/linear_solving.md @@ -19,9 +19,9 @@ The module `AbstractAlgebra.Solve` provides the following four functions for sol All of these take the same set of arguments, namely: * a matrix $A$ of type `MatElem{T}`; * a vector or matrix $B$ of type `Vector{T}` or `MatElem{T}`; -* a keyword argument `side` which can be either `:right` (default) or `:left`. +* a keyword argument `side` which can be either `:left` (default) or `:right`. -If `side` is `:right`, the system $Ax = B$ is solved, otherwise the system $xA = B$ is solved. +If `side` is `:left`, the system $xA = B$ is solved, otherwise the system $Ax = B$ is solved. For matrices defined over a field, the functions internally rely on `rref`. If the matrices are defined over a ring, the function `hnf_with_transform` is required internally. diff --git a/src/Solve.jl b/src/Solve.jl index 788e3711d4..fad94e3870 100644 --- a/src/Solve.jl +++ b/src/Solve.jl @@ -204,13 +204,13 @@ end ################################################################################ @doc raw""" - solve(A::MatElem{T}, b::Vector{T}; side::Symbol = :right) where T - solve(A::MatElem{T}, b::MatElem{T}; side::Symbol = :right) where T - solve(C::SolveCtx{T}, b::Vector{T}; side::Symbol = :right) where T - solve(C::SolveCtx{T}, b::MatElem{T}; side::Symbol = :right) where T + solve(A::MatElem{T}, b::Vector{T}; side::Symbol = :left) where T + solve(A::MatElem{T}, b::MatElem{T}; side::Symbol = :left) where T + solve(C::SolveCtx{T}, b::Vector{T}; side::Symbol = :left) where T + solve(C::SolveCtx{T}, b::MatElem{T}; side::Symbol = :left) where T -Return $x$ of same type as $b$ solving the linear system $Ax = b$, if `side == :right` -(default), or $xA = b$, if `side == :left`. +Return $x$ of same type as $b$ solving the linear system $xA = b$, if `side == :left` +(default), or $Ax = b$, if `side == :right`. If no solution exists, an error is raised. @@ -218,89 +218,89 @@ If a context object `C` is supplied, then the above applies for `A = matrix(C)`. See also [`can_solve_with_solution`](@ref). """ -function solve(A::Union{MatElem{T}, SolveCtx{T}}, b::Union{Vector{T}, MatElem{T}}; side::Symbol = :right) where T +function solve(A::Union{MatElem{T}, SolveCtx{T}}, b::Union{Vector{T}, MatElem{T}}; side::Symbol = :left) where T fl, x = can_solve_with_solution(A, b, side = side) fl || throw(ArgumentError("Unable to solve linear system")) return x end @doc raw""" - can_solve(A::MatElem{T}, b::Vector{T}; side::Symbol = :right) where T - can_solve(A::MatElem{T}, b::MatElem{T}; side::Symbol = :right) where T - can_solve(C::SolveCtx{T}, b::Vector{T}; side::Symbol = :right) where T - can_solve(C::SolveCtx{T}, b::MatElem{T}; side::Symbol = :right) where T + can_solve(A::MatElem{T}, b::Vector{T}; side::Symbol = :left) where T + can_solve(A::MatElem{T}, b::MatElem{T}; side::Symbol = :left) where T + can_solve(C::SolveCtx{T}, b::Vector{T}; side::Symbol = :left) where T + can_solve(C::SolveCtx{T}, b::MatElem{T}; side::Symbol = :left) where T -Return `true` if the linear system $Ax = b$ or $xA = b$ with `side == :right` -(default) or `side == :left`, respectively, has a solution and `false` otherwise. +Return `true` if the linear system $xA = b$ or $Ax = b$ with `side == :left` +(default) or `side == :right`, respectively, has a solution and `false` otherwise. If a context object `C` is supplied, then the above applies for `A = matrix(C)`. See also [`can_solve_with_solution`](@ref). """ -function can_solve(A::Union{MatElem{T}, SolveCtx{T}}, b::Union{Vector{T}, MatElem{T}}; side::Symbol = :right) where T +function can_solve(A::Union{MatElem{T}, SolveCtx{T}}, b::Union{Vector{T}, MatElem{T}}; side::Symbol = :left) where T return _can_solve_internal(A, b, :only_check; side = side)[1] end @doc raw""" - can_solve_with_solution(A::MatElem{T}, b::Vector{T}; side::Symbol = :right) where T - can_solve_with_solution(A::MatElem{T}, b::MatElem{T}; side::Symbol = :right) where T - can_solve_with_solution(C::SolveCtx{T}, b::Vector{T}; side::Symbol = :right) where T - can_solve_with_solution(C::SolveCtx{T}, b::MatElem{T}; side::Symbol = :right) where T + can_solve_with_solution(A::MatElem{T}, b::Vector{T}; side::Symbol = :left) where T + can_solve_with_solution(A::MatElem{T}, b::MatElem{T}; side::Symbol = :left) where T + can_solve_with_solution(C::SolveCtx{T}, b::Vector{T}; side::Symbol = :left) where T + can_solve_with_solution(C::SolveCtx{T}, b::MatElem{T}; side::Symbol = :left) where T -Return `true` and $x$ of same type as $b$ solving the linear system $Ax = b$, if +Return `true` and $x$ of same type as $b$ solving the linear system $xA = b$, if such a solution exists. Return `false` and an empty vector or matrix, if the system has no solution. -If `side == :left`, the system $xA = b$ is solved. +If `side == :right`, the system $Ax = b$ is solved. If a context object `C` is supplied, then the above applies for `A = matrix(C)`. See also [`solve`](@ref). """ -function can_solve_with_solution(A::Union{MatElem{T}, SolveCtx{T}}, b::Union{Vector{T}, MatElem{T}}; side::Symbol = :right) where T +function can_solve_with_solution(A::Union{MatElem{T}, SolveCtx{T}}, b::Union{Vector{T}, MatElem{T}}; side::Symbol = :left) where T return _can_solve_internal(A, b, :with_solution; side = side)[1:2] end @doc raw""" - can_solve_with_solution_and_kernel(A::MatElem{T}, b::Vector{T}; side::Symbol = :right) where T - can_solve_with_solution_and_kernel(A::MatElem{T}, b::MatElem{T}; side::Symbol = :right) where T - can_solve_with_solution_and_kernel(C::SolveCtx{T}, b::Vector{T}; side::Symbol = :right) where T - can_solve_with_solution_and_kernel(C::SolveCtx{T}, b::MatElem{T}; side::Symbol = :right) where T + can_solve_with_solution_and_kernel(A::MatElem{T}, b::Vector{T}; side::Symbol = :left) where T + can_solve_with_solution_and_kernel(A::MatElem{T}, b::MatElem{T}; side::Symbol = :left) where T + can_solve_with_solution_and_kernel(C::SolveCtx{T}, b::Vector{T}; side::Symbol = :left) where T + can_solve_with_solution_and_kernel(C::SolveCtx{T}, b::MatElem{T}; side::Symbol = :left) where T -Return `true`, $x$ of same type as $b$ solving the linear system $Ax = b$, -together with a matrix $K$ giving the kernel of $A$ (i.e. $AK = 0$), if such +Return `true`, $x$ of same type as $b$ solving the linear system $xA = b$, +together with a matrix $K$ giving the kernel of $A$ (i.e. $KA = 0$), if such a solution exists. Return `false`, an empty vector or matrix and an empty matrix, if the system has no solution. -If `side == :left`, the system $xA = b$ is solved. +If `side == :right`, the system $Ax = b$ is solved. If a context object `C` is supplied, then the above applies for `A = matrix(C)`. See also [`solve`](@ref) and [`kernel`](@ref). """ -function can_solve_with_solution_and_kernel(A::Union{MatElem{T}, SolveCtx{T}}, b::Union{Vector{T}, MatElem{T}}; side::Symbol = :right) where T +function can_solve_with_solution_and_kernel(A::Union{MatElem{T}, SolveCtx{T}}, b::Union{Vector{T}, MatElem{T}}; side::Symbol = :left) where T return _can_solve_internal(A, b, :with_kernel; side = side) end @doc raw""" - kernel([R::Ring], A::MatElem; side::Symbol = :right) - kernel(C::SolveCtx; side::Symbol = :right) + kernel([R::Ring], A::MatElem; side::Symbol = :left) + kernel(C::SolveCtx; side::Symbol = :left) -Return a matrix $K$ whose columns give a basis for the right kernel of $A$, that -is, $AK$ is the zero matrix. - -If `side == :left`, the rows of $K$ give a basis for the left kernel of $A$, that +Return a matrix $K$ whose columns give a basis for the left kernel of $A$, that is, $KA$ is the zero matrix. +If `side == :right`, the rows of $K$ give a basis for the right kernel of $A$, that +is, $AK$ is the zero matrix. + If a ring $R$ is supplied as a first argument, the kernel is computed over $R$. If a context object `C` is supplied, then the above applies for `A = matrix(C)`. """ -function kernel(A::MatElem{<:FieldElement}; side::Symbol = :right) +function kernel(A::MatElem{<:FieldElement}; side::Symbol = :left) check_option(side, [:right, :left], "side") if side === :left - K = kernel(lazy_transpose(A)) + K = kernel(lazy_transpose(A), side = :right) return lazy_transpose(K) end @@ -312,7 +312,7 @@ function kernel(A::MatElem{<:FieldElement}; side::Symbol = :right) return K end -function kernel(A::MatElem{<:RingElement}; side::Symbol = :right) +function kernel(A::MatElem{<:RingElement}; side::Symbol = :left) check_option(side, [:right, :left], "side") if side === :right @@ -326,7 +326,7 @@ function kernel(A::MatElem{<:RingElement}; side::Symbol = :right) end end -function kernel(C::SolveCtx{<:FieldElement}; side::Symbol = :right) +function kernel(C::SolveCtx{<:FieldElement}; side::Symbol = :left) check_option(side, [:right, :left], "side") if side === :right @@ -338,7 +338,7 @@ function kernel(C::SolveCtx{<:FieldElement}; side::Symbol = :right) end end -function kernel(C::SolveCtx{<:RingElement}; side::Symbol = :right) +function kernel(C::SolveCtx{<:RingElement}; side::Symbol = :left) check_option(side, [:right, :left], "side") if side === :right @@ -350,7 +350,7 @@ function kernel(C::SolveCtx{<:RingElement}; side::Symbol = :right) end end -function kernel(R::Ring, A::MatElem; side::Symbol = :right) +function kernel(R::Ring, A::MatElem; side::Symbol = :left) AR = change_base_ring(R, A) return kernel(AR; side) end @@ -408,7 +408,7 @@ function pivot_and_non_pivot_cols(A::MatElem, r::Int) end # Transform a right hand side of type Vector into a MatElem and do sanity checks -function _can_solve_internal(A::Union{MatElem{T}, SolveCtx{T}}, b::Vector{T}, task::Symbol; side::Symbol = :right) where T +function _can_solve_internal(A::Union{MatElem{T}, SolveCtx{T}}, b::Vector{T}, task::Symbol; side::Symbol = :left) where T check_option(task, [:only_check, :with_solution, :with_kernel], "task") check_option(side, [:right, :left], "side") @@ -431,7 +431,7 @@ function _can_solve_internal(A::Union{MatElem{T}, SolveCtx{T}}, b::Vector{T}, ta end # Do sanity checks and call _can_solve_internal_no_check -function _can_solve_internal(A::Union{MatElem{T}, SolveCtx{T}}, b::MatElem{T}, task::Symbol; side::Symbol = :right) where T +function _can_solve_internal(A::Union{MatElem{T}, SolveCtx{T}}, b::MatElem{T}, task::Symbol; side::Symbol = :left) where T check_option(task, [:only_check, :with_solution, :with_kernel], "task") check_option(side, [:right, :left], "side") if side === :right @@ -443,7 +443,7 @@ function _can_solve_internal(A::Union{MatElem{T}, SolveCtx{T}}, b::MatElem{T}, t end # _can_solve_internal_no_check over FIELDS -function _can_solve_internal_no_check(A::MatElem{T}, b::MatElem{T}, task::Symbol; side::Symbol = :right) where T <: FieldElement +function _can_solve_internal_no_check(A::MatElem{T}, b::MatElem{T}, task::Symbol; side::Symbol = :left) where T <: FieldElement R = base_ring(A) @@ -489,7 +489,7 @@ function _can_solve_internal_no_check(A::MatElem{T}, b::MatElem{T}, task::Symbol end # _can_solve_internal_no_check over RINGS -function _can_solve_internal_no_check(A::MatElem{T}, b::MatElem{T}, task::Symbol; side::Symbol = :right) where T <: RingElement +function _can_solve_internal_no_check(A::MatElem{T}, b::MatElem{T}, task::Symbol; side::Symbol = :left) where T <: RingElement R = base_ring(A) @@ -510,7 +510,7 @@ function _can_solve_internal_no_check(A::MatElem{T}, b::MatElem{T}, task::Symbol end # _can_solve_internal_no_check over FIELDS with SOLVE CONTEXT -function _can_solve_internal_no_check(C::SolveCtx{T}, b::MatElem{T}, task::Symbol; side::Symbol = :right) where T <: FieldElement +function _can_solve_internal_no_check(C::SolveCtx{T}, b::MatElem{T}, task::Symbol; side::Symbol = :left) where T <: FieldElement if side === :right fl, sol = _can_solve_with_rref(b, transformation_matrix(C), rank(C), pivot_and_non_pivot_cols(C), task) else @@ -525,7 +525,7 @@ function _can_solve_internal_no_check(C::SolveCtx{T}, b::MatElem{T}, task::Symbo end # _can_solve_internal_no_check over RINGS with SOLVE CONTEXT -function _can_solve_internal_no_check(C::SolveCtx{T}, b::MatElem{T}, task::Symbol; side::Symbol = :right) where T <: RingElement +function _can_solve_internal_no_check(C::SolveCtx{T}, b::MatElem{T}, task::Symbol; side::Symbol = :left) where T <: RingElement if side === :right fl, sol = _can_solve_with_hnf(b, reduced_matrix_of_transpose(C), transformation_matrix_of_transpose(C), task) else diff --git a/test/Solve-test.jl b/test/Solve-test.jl index b95b46c5cd..70d4696d22 100644 --- a/test/Solve-test.jl +++ b/test/Solve-test.jl @@ -3,27 +3,27 @@ M = matrix(R, [1 2 3 4 5; 0 0 8 9 10; 0 0 0 14 15]) @test_throws ErrorException AbstractAlgebra.Solve.solve(M, [ R(1) ]) - @test_throws ErrorException AbstractAlgebra.Solve.solve(M, [ R(1) ], side = :left) + @test_throws ErrorException AbstractAlgebra.Solve.solve(M, [ R(1) ], side = :right) @test_throws ErrorException AbstractAlgebra.Solve.solve(M, matrix(R, 1, 1, [ R(1) ])) - @test_throws ErrorException AbstractAlgebra.Solve.solve(M, matrix(R, 1, 1, [ R(1) ]), side = :left) + @test_throws ErrorException AbstractAlgebra.Solve.solve(M, matrix(R, 1, 1, [ R(1) ]), side = :right) @test_throws ArgumentError AbstractAlgebra.Solve.solve(M, [ R(1), R(2), R(3) ], side = :test) @test_throws ArgumentError AbstractAlgebra.Solve.solve(M, matrix(R, 3, 1, [ R(1), R(2), R(3) ]), side = :test) for b in [ [ R(1), R(2), R(3) ], matrix(R, 3, 1, [ R(1), R(2), R(3) ]), matrix(R, 3, 2, [ R(1), R(2), R(3), R(4), R(5), R(6) ]) ] - @test @inferred AbstractAlgebra.Solve.can_solve(M, b) - x = @inferred AbstractAlgebra.Solve.solve(M, b) + @test @inferred AbstractAlgebra.Solve.can_solve(M, b, side = :right) + x = @inferred AbstractAlgebra.Solve.solve(M, b, side = :right) @test M*x == b - fl, x = @inferred AbstractAlgebra.Solve.can_solve_with_solution(M, b) + fl, x = @inferred AbstractAlgebra.Solve.can_solve_with_solution(M, b, side = :right) @test fl @test M*x == b - fl, x, K = @inferred AbstractAlgebra.Solve.can_solve_with_solution_and_kernel(M, b) + fl, x, K = @inferred AbstractAlgebra.Solve.can_solve_with_solution_and_kernel(M, b, side = :right) @test fl @test M*x == b @test is_zero(M*K) @test ncols(K) == 2 - K = @inferred AbstractAlgebra.Solve.kernel(M) + K = @inferred AbstractAlgebra.Solve.kernel(M, side = :right) @test is_zero(M*K) @test ncols(K) == 2 end @@ -32,11 +32,11 @@ matrix(R, 1, 5, [ R(1), R(1), R(1), R(1), R(1) ]), matrix(R, 2, 5, [ R(1), R(1), R(1), R(1), R(1), R(1), R(1), R(1), R(1), R(1) ]) ] - @test_throws ArgumentError AbstractAlgebra.Solve.solve(M, b, side = :left) - @test @inferred !AbstractAlgebra.Solve.can_solve(M, b, side = :left) - fl, x = @inferred AbstractAlgebra.Solve.can_solve_with_solution(M, b, side = :left) + @test_throws ArgumentError AbstractAlgebra.Solve.solve(M, b) + @test @inferred !AbstractAlgebra.Solve.can_solve(M, b) + fl, x = @inferred AbstractAlgebra.Solve.can_solve_with_solution(M, b) @test !fl - fl, x, K = @inferred AbstractAlgebra.Solve.can_solve_with_solution_and_kernel(M, b, side = :left) + fl, x, K = @inferred AbstractAlgebra.Solve.can_solve_with_solution_and_kernel(M, b) @test !fl end @@ -44,48 +44,48 @@ matrix(R, 1, 5, [ R(1), R(2), R(3), R(4), R(5)]), matrix(R, 2, 5, [ R(1), R(2), R(3), R(4), R(5), R(0), R(0), R(8), R(9), R(10) ]) ] - @test @inferred AbstractAlgebra.Solve.can_solve(M, b, side = :left) - x = @inferred AbstractAlgebra.Solve.solve(M, b, side = :left) + @test @inferred AbstractAlgebra.Solve.can_solve(M, b) + x = @inferred AbstractAlgebra.Solve.solve(M, b) @test x*M == b - fl, x = @inferred AbstractAlgebra.Solve.can_solve_with_solution(M, b, side = :left) + fl, x = @inferred AbstractAlgebra.Solve.can_solve_with_solution(M, b) @test fl @test x*M == b - fl, x, K = @inferred AbstractAlgebra.Solve.can_solve_with_solution_and_kernel(M, b, side = :left) + fl, x, K = @inferred AbstractAlgebra.Solve.can_solve_with_solution_and_kernel(M, b) @test fl @test x*M == b @test is_zero(K*M) @test nrows(K) == 0 - K = @inferred AbstractAlgebra.Solve.kernel(M, side = :left) + K = @inferred AbstractAlgebra.Solve.kernel(M) @test is_zero(K*M) @test nrows(K) == 0 end N = zero_matrix(R, 2, 1) b = zeros(R, 2) - fl, x, K = @inferred AbstractAlgebra.Solve.can_solve_with_solution_and_kernel(N, b) + fl, x, K = @inferred AbstractAlgebra.Solve.can_solve_with_solution_and_kernel(N, b, side = :right) @test fl @test N*x == b @test K == identity_matrix(R, 1) - K = @inferred AbstractAlgebra.Solve.kernel(N) + K = @inferred AbstractAlgebra.Solve.kernel(N, side = :right) @test K == identity_matrix(R, 1) N = zero_matrix(R, 1, 2) b = zeros(R, 1) - fl, x, K = @inferred AbstractAlgebra.Solve.can_solve_with_solution_and_kernel(N, b) + fl, x, K = @inferred AbstractAlgebra.Solve.can_solve_with_solution_and_kernel(N, b, side = :right) @test fl @test N*x == b @test K == identity_matrix(R, 2) || K == swap_cols!(identity_matrix(R, 2), 1, 2) - K = @inferred AbstractAlgebra.Solve.kernel(N) + K = @inferred AbstractAlgebra.Solve.kernel(N, side = :right) @test K == identity_matrix(R, 2) || K == swap_cols!(identity_matrix(R, 2), 1, 2) end M = matrix(ZZ, [1 2 3 4 5; 0 0 8 9 10; 0 0 0 14 15]) - K = @inferred AbstractAlgebra.Solve.kernel(QQ, M) + K = @inferred AbstractAlgebra.Solve.kernel(QQ, M, side = :right) @test base_ring(K) === QQ @test is_zero(M*K) @test ncols(K) == 2 - K = @inferred AbstractAlgebra.Solve.kernel(QQ, M, side = :left) + K = @inferred AbstractAlgebra.Solve.kernel(QQ, M) @test base_ring(K) === QQ @test is_zero(K*M) @test nrows(K) == 0 @@ -97,27 +97,27 @@ end C = AbstractAlgebra.Solve.solve_init(M) @test_throws ErrorException AbstractAlgebra.Solve.solve(C, [ R(1) ]) - @test_throws ErrorException AbstractAlgebra.Solve.solve(C, [ R(1) ], side = :left) + @test_throws ErrorException AbstractAlgebra.Solve.solve(C, [ R(1) ], side = :right) @test_throws ErrorException AbstractAlgebra.Solve.solve(C, matrix(R, 1, 1, [ R(1) ])) - @test_throws ErrorException AbstractAlgebra.Solve.solve(C, matrix(R, 1, 1, [ R(1) ]), side = :left) + @test_throws ErrorException AbstractAlgebra.Solve.solve(C, matrix(R, 1, 1, [ R(1) ]), side = :right) @test_throws ArgumentError AbstractAlgebra.Solve.solve(C, [ R(1), R(2), R(3) ], side = :test) @test_throws ArgumentError AbstractAlgebra.Solve.solve(C, matrix(R, 3, 1, [ R(1), R(2), R(3) ]), side = :test) for b in [ [ R(1), R(2), R(3) ], matrix(R, 3, 1, [ R(1), R(2), R(3) ]), matrix(R, 3, 2, [ R(1), R(2), R(3), R(4), R(5), R(6) ]) ] - @test @inferred AbstractAlgebra.Solve.can_solve(C, b) - x = @inferred AbstractAlgebra.Solve.solve(C, b) + @test @inferred AbstractAlgebra.Solve.can_solve(C, b, side = :right) + x = @inferred AbstractAlgebra.Solve.solve(C, b, side = :right) @test M*x == b - fl, x = @inferred AbstractAlgebra.Solve.can_solve_with_solution(C, b) + fl, x = @inferred AbstractAlgebra.Solve.can_solve_with_solution(C, b, side = :right) @test fl @test M*x == b - fl, x, K = @inferred AbstractAlgebra.Solve.can_solve_with_solution_and_kernel(C, b) + fl, x, K = @inferred AbstractAlgebra.Solve.can_solve_with_solution_and_kernel(C, b, side = :right) @test fl @test M*x == b @test is_zero(M*K) @test ncols(K) == 2 - K = @inferred AbstractAlgebra.Solve.kernel(C) + K = @inferred AbstractAlgebra.Solve.kernel(C, side = :right) @test is_zero(M*K) @test ncols(K) == 2 end @@ -126,11 +126,11 @@ end matrix(R, 1, 5, [ R(1), R(1), R(1), R(1), R(1) ]), matrix(R, 2, 5, [ R(1), R(1), R(1), R(1), R(1), R(1), R(1), R(1), R(1), R(1) ]) ] - @test_throws ArgumentError AbstractAlgebra.Solve.solve(C, b, side = :left) - @test @inferred !AbstractAlgebra.Solve.can_solve(C, b, side = :left) - fl, x = @inferred AbstractAlgebra.Solve.can_solve_with_solution(C, b, side = :left) + @test_throws ArgumentError AbstractAlgebra.Solve.solve(C, b) + @test @inferred !AbstractAlgebra.Solve.can_solve(C, b) + fl, x = @inferred AbstractAlgebra.Solve.can_solve_with_solution(C, b) @test !fl - fl, x, K = @inferred AbstractAlgebra.Solve.can_solve_with_solution_and_kernel(C, b, side = :left) + fl, x, K = @inferred AbstractAlgebra.Solve.can_solve_with_solution_and_kernel(C, b) @test !fl end @@ -138,18 +138,18 @@ end matrix(R, 1, 5, [ R(1), R(2), R(3), R(4), R(5)]), matrix(R, 2, 5, [ R(1), R(2), R(3), R(4), R(5), R(0), R(0), R(8), R(9), R(10) ]) ] - @test @inferred AbstractAlgebra.Solve.can_solve(C, b, side = :left) - x = @inferred AbstractAlgebra.Solve.solve(C, b, side = :left) + @test @inferred AbstractAlgebra.Solve.can_solve(C, b) + x = @inferred AbstractAlgebra.Solve.solve(C, b) @test x*M == b - fl, x = @inferred AbstractAlgebra.Solve.can_solve_with_solution(C, b, side = :left) + fl, x = @inferred AbstractAlgebra.Solve.can_solve_with_solution(C, b) @test fl @test x*M == b - fl, x, K = @inferred AbstractAlgebra.Solve.can_solve_with_solution_and_kernel(C, b, side = :left) + fl, x, K = @inferred AbstractAlgebra.Solve.can_solve_with_solution_and_kernel(C, b) @test fl @test x*M == b @test is_zero(K*M) @test nrows(K) == 0 - K = @inferred AbstractAlgebra.Solve.kernel(C, side = :left) + K = @inferred AbstractAlgebra.Solve.kernel(C) @test is_zero(K*M) @test nrows(K) == 0 end @@ -157,21 +157,21 @@ end N = zero_matrix(R, 2, 1) C = AbstractAlgebra.Solve.solve_init(N) b = zeros(R, 2) - fl, x, K = @inferred AbstractAlgebra.Solve.can_solve_with_solution_and_kernel(C, b) + fl, x, K = @inferred AbstractAlgebra.Solve.can_solve_with_solution_and_kernel(C, b, side = :right) @test fl @test N*x == b @test K == identity_matrix(R, 1) - K = @inferred AbstractAlgebra.Solve.kernel(C) + K = @inferred AbstractAlgebra.Solve.kernel(C, side = :right) @test K == identity_matrix(R, 1) N = zero_matrix(R, 1, 2) C = AbstractAlgebra.Solve.solve_init(N) b = zeros(R, 1) - fl, x, K = @inferred AbstractAlgebra.Solve.can_solve_with_solution_and_kernel(C, b) + fl, x, K = @inferred AbstractAlgebra.Solve.can_solve_with_solution_and_kernel(C, b, side = :right) @test fl @test N*x == b @test K == identity_matrix(R, 2) || K == swap_cols!(identity_matrix(R, 2), 1, 2) - K = @inferred AbstractAlgebra.Solve.kernel(C) + K = @inferred AbstractAlgebra.Solve.kernel(C, side = :right) @test K == identity_matrix(R, 2) || K == swap_cols!(identity_matrix(R, 2), 1, 2) end end