Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

sparse_row and SRow accept NCRing instead of Ring #1322

Merged
merged 23 commits into from
Jul 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
41678ac
spare_row and SRow accept NCRing instead of Ring (for modules over NC…
Lax202 Dec 13, 2023
9abef0c
left and right functionality for SRow over NCRing
Lax202 Dec 20, 2023
302c3bb
functionality and tests for scale_row
Lax202 Dec 20, 2023
950fefa
Update src/Sparse/Row.jl
Lax202 Jan 4, 2024
55e6b4a
Update src/Sparse/Row.jl
Lax202 Jan 4, 2024
8676d2a
minor documentation modification
Lax202 Jan 24, 2024
b673a30
Merge branch 'lr/ncmodules' of https://github.com/Lax202/Hecke.jl
Lax202 Jan 24, 2024
22bee55
added export functions
Lax202 Jan 24, 2024
719c07a
tests for SRow{NCRingElem}
Lax202 Jan 24, 2024
5e6150e
Merge branch 'master' of https://github.com/thofma/Hecke.jl into ncmo…
joschmitt Jan 24, 2024
25e4395
minor changes from PR comments
Lax202 Jun 5, 2024
376cbdd
fixed scale row test
Lax202 Jun 5, 2024
4228cfe
resolving conflict
Lax202 Jun 5, 2024
86cf707
Merge branch 'lr/ncmodules' of https://github.com/Lax202/Hecke.jl
Lax202 Jun 5, 2024
28a5e95
Merge branch 'master' into lr/ncmodules
Lax202 Jun 5, 2024
def37da
small fix in sparse row test
Lax202 Jun 5, 2024
a12ddce
Merge branch 'lr/ncmodules' of https://github.com/Lax202/Hecke.jl int…
Lax202 Jun 5, 2024
57a12f4
fixes to make sparse row over NCRing work
Lax202 Jun 10, 2024
bfc8d09
minor changes from PR
Lax202 Jun 10, 2024
30ef82b
test for add_scaled_row avoiding MatAlgElem
Lax202 Jun 19, 2024
b66ba3d
changed docs for sparse_row
Lax202 Jul 22, 2024
f6d359e
fixed documentation for sparse_row
Lax202 Jul 22, 2024
2e90d2c
fixed test
Lax202 Jul 22, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions docs/src/manual/misc/sparse.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,9 @@ In particular any two sparse rows over the same base ring can be added.
### Creation

```@docs
sparse_row(::ZZRing, ::Vector{Tuple{Int, ZZRingElem}})
sparse_row(::ZZRing, ::Vector{Tuple{Int, Int}})
sparse_row(::ZZRing, ::Vector{Int}, ::Vector{ZZRingElem})
sparse_row(::NCRing, ::Vector{Tuple{Int, T}}) where T
sparse_row(::NCRing, ::Vector{Tuple{Int, Int}})
sparse_row(::NCRing, ::Vector{Int}, ::Vector{T}) where T
```

### Basic operations
Expand Down
6 changes: 3 additions & 3 deletions docs/src/sparse/intro.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,9 @@ In particular any two sparse rows over the same base ring can be added.
### Creation

```@docs; canonical=false
sparse_row(::ZZRing, ::Vector{Tuple{Int, ZZRingElem}})
sparse_row(::ZZRing, ::Vector{Tuple{Int, Int}})
sparse_row(::ZZRing, ::Vector{Int}, ::Vector{ZZRingElem})
sparse_row(::NCRing, ::Vector{Tuple{Int, T}}) where T
sparse_row(::NCRing, ::Vector{Tuple{Int, Int}})
sparse_row(::NCRing, ::Vector{Int}, ::Vector{T}) where T
```

### Basic operations
Expand Down
16 changes: 8 additions & 8 deletions src/HeckeTypes.jl
Original file line number Diff line number Diff line change
Expand Up @@ -310,14 +310,14 @@
values::S
pos::Vector{Int}

function SRow(R::Ring)
function SRow(R::NCRing)
@assert R != ZZ
S = sparse_inner_type(R)
r = new{elem_type(R), S}(R, S(), Vector{Int}())
return r
end

function SRow(R::Ring, p::Vector{Int64}, S::AbstractVector; check::Bool = true)
function SRow(R::NCRing, p::Vector{Int64}, S::AbstractVector; check::Bool = true)
if check && any(iszero, S)
p = copy(p)
S = deepcopy(S)
Expand All @@ -336,7 +336,7 @@
return r
end

function SRow(R::Ring, A::Vector{Tuple{Int, T}}) where T
function SRow(R::NCRing, A::Vector{Tuple{Int, T}}) where T

Check warning on line 339 in src/HeckeTypes.jl

View check run for this annotation

Codecov / codecov/patch

src/HeckeTypes.jl#L339

Added line #L339 was not covered by tests
r = SRow(R)
for (i, v) = A
if !iszero(v)
Expand All @@ -348,7 +348,7 @@
return r
end

function SRow(R::Ring, A::Vector{Tuple{Int, Int}})
function SRow(R::NCRing, A::Vector{Tuple{Int, Int}})

Check warning on line 351 in src/HeckeTypes.jl

View check run for this annotation

Codecov / codecov/patch

src/HeckeTypes.jl#L351

Added line #L351 was not covered by tests
r = SRow(R)
for (i, v) = A
if !iszero(v)
Expand All @@ -369,7 +369,7 @@
return r
end

function SRow{T}(R::Ring, pos::Vector{Int}, val::Vector{T}) where {T}
function SRow{T}(R::NCRing, pos::Vector{Int}, val::Vector{T}) where {T}

Check warning on line 372 in src/HeckeTypes.jl

View check run for this annotation

Codecov / codecov/patch

src/HeckeTypes.jl#L372

Added line #L372 was not covered by tests
length(pos) == length(val) || error("Arrays must have same length")
r = SRow(R)
for i=1:length(pos)
Expand All @@ -390,9 +390,9 @@

# helper function used by SRow construct and also by the default
# methods for `sparse_matrix_type` and `sparse_row_type`.
sparse_inner_type(::T) where {T <: Union{Ring, RingElem}} = sparse_inner_type(T)
sparse_inner_type(::Type{T}) where {T <: Ring} = sparse_inner_type(elem_type(T))
sparse_inner_type(::Type{T}) where {T <: RingElem} = Vector{T}
sparse_inner_type(::T) where {T <: Union{NCRing, NCRingElem}} = sparse_inner_type(T)
sparse_inner_type(::Type{T}) where {T <: NCRing} = sparse_inner_type(elem_type(T))
sparse_inner_type(::Type{T}) where {T <: NCRingElem} = Vector{T}

################################################################################
#
Expand Down
146 changes: 128 additions & 18 deletions src/Sparse/Row.jl
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,9 @@
true
```
"""
sparse_row_type(::T) where {T <: Union{Ring, RingElem}} = sparse_row_type(T)
sparse_row_type(::Type{T}) where {T <: Ring} = sparse_row_type(elem_type(T))
sparse_row_type(::Type{T}) where {T <: RingElem} = SRow{T, sparse_inner_type(T)}
sparse_row_type(::T) where {T <: Union{NCRing, NCRingElem}} = sparse_row_type(T)
sparse_row_type(::Type{T}) where {T <: NCRing} = sparse_row_type(elem_type(T))
sparse_row_type(::Type{T}) where {T <: NCRingElem} = SRow{T, sparse_inner_type(T)}


==(x::SRow{T}, y::SRow{T}) where {T} = (x.pos == y.pos) && (x.values == y.values)
Expand All @@ -69,7 +69,7 @@

Constructs an empty row with base ring $R$.
"""
function sparse_row(R::Ring)
function sparse_row(R::NCRing)
return SRow(R)
end

Expand All @@ -79,7 +79,7 @@
Constructs the sparse row $(a_i)_i$ with $a_{i_j} = x_j$, where $J = (i_j, x_j)_j$.
The elements $x_i$ must belong to the ring $R$.
"""
function sparse_row(R::Ring, A::Vector{Tuple{Int, T}}; sort::Bool = true) where T
function sparse_row(R::NCRing, A::Vector{Tuple{Int, T}}; sort::Bool = true) where T

Check warning on line 82 in src/Sparse/Row.jl

View check run for this annotation

Codecov / codecov/patch

src/Sparse/Row.jl#L82

Added line #L82 was not covered by tests
if sort && length(A) > 1
A = Base.sort(A, lt=(a,b) -> isless(a[1], b[1]))
end
Expand All @@ -92,7 +92,7 @@
Constructs the sparse row $(a_i)_i$ over $R$ with $a_{i_j} = x_j$,
where $J = (i_j, x_j)_j$.
"""
function sparse_row(R::Ring, A::Vector{Tuple{Int, Int}}; sort::Bool = true)
function sparse_row(R::NCRing, A::Vector{Tuple{Int, Int}}; sort::Bool = true)

Check warning on line 95 in src/Sparse/Row.jl

View check run for this annotation

Codecov / codecov/patch

src/Sparse/Row.jl#L95

Added line #L95 was not covered by tests
if sort && length(A) > 1
A = Base.sort(A, lt=(a,b) -> isless(a[1], b[1]))
end
Expand All @@ -112,12 +112,12 @@
end

@doc raw"""
sparse_row(R::Ring, J::Vector{Int}, V::Vector{T}) -> SRow{T}
sparse_row(R::NCRing, J::Vector{Int}, V::Vector{T}) -> SRow{T}

Constructs the sparse row $(a_i)_i$ over $R$ with $a_{i_j} = x_j$, where
$J = (i_j)_j$ and $V = (x_j)_j$.
"""
function sparse_row(R::Ring, pos::Vector{Int}, val::AbstractVector{T}; sort::Bool = true) where T
function sparse_row(R::NCRing, pos::Vector{Int}, val::AbstractVector{T}; sort::Bool = true) where T
if sort && length(pos) > 1
p = sortperm(pos)
pos = pos[p]
Expand Down Expand Up @@ -294,7 +294,7 @@

Create a new sparse row by coercing all elements into the ring $R$.
"""
function change_base_ring(R::S, A::SRow{T}) where {T <: RingElem, S <: Ring}
function change_base_ring(R::S, A::SRow{T}) where {T <: NCRingElem, S <: NCRing}
z = sparse_row(R)
for (i, v) in A
nv = R(v)
Expand All @@ -321,7 +321,7 @@

Given a sparse row $(a_i)_{i}$ and an index $j$ return $a_j$.
"""
function Base.getindex(A::SRow{T}, i::Int) where {T <: RingElem}
function Base.getindex(A::SRow{T}, i::Int) where {T <: NCRingElem}
i < 1 && error("Index must be positive")
p = findfirst(isequal(i), A.pos)
if p === nothing
Expand Down Expand Up @@ -371,7 +371,7 @@
@doc raw"""
dot(A::SRow, B::SRow) -> RingElem

Returns the dot product of $A$ and $B$.
Returns the dot product of $A$ and $B$. Note the order matters in non-commutative case.
"""
function dot(A::SRow{T}, B::SRow{T}) where T
@assert length(A) != 0
Expand All @@ -385,7 +385,7 @@
return v
end
if B.pos[b] == A.pos[a]
v += B.values[b] * A.values[a]
v += A.values[a] * B.values[b]
end
end
return v
Expand Down Expand Up @@ -447,11 +447,39 @@
# Inplace scaling
#
################################################################################
@doc raw"""
scale_row!(a::SRow, b::NCRingElem) -> SRow

Returns the (left) product of $b \times a$ and reassigns the value of $a$ to this product.
For rows, the standard multiplication is from the left.
"""
function scale_row!(a::SRow{T}, b::T) where T
@assert !iszero(b)
if isone(b)
return
return a

Check warning on line 459 in src/Sparse/Row.jl

View check run for this annotation

Codecov / codecov/patch

src/Sparse/Row.jl#L459

Added line #L459 was not covered by tests
end
i = 1
while i <= length(a)
a.values[i] = b*a.values[i]
Lax202 marked this conversation as resolved.
Show resolved Hide resolved
if iszero(a.values[i])
deleteat!(a.values, i)
deleteat!(a.pos, i)
else
i += 1
end
end
return a
end

@doc raw"""
scale_row_right!(a::SRow, b::NCRingElem) -> SRow

Returns the (right) product of $a \times b$ and modifies $a$ to this product.
"""
function scale_row_right!(a::SRow{T}, b::T) where T
@assert !iszero(b)
if isone(b)
return a

Check warning on line 482 in src/Sparse/Row.jl

View check run for this annotation

Codecov / codecov/patch

src/Sparse/Row.jl#L482

Added line #L482 was not covered by tests
end
i = 1
while i <= length(a)
Expand All @@ -463,6 +491,11 @@
i += 1
end
end
return a
end

function scale_row_left!(a::SRow{T}, b::T) where T
return scale_row!(a,b)

Check warning on line 498 in src/Sparse/Row.jl

View check run for this annotation

Codecov / codecov/patch

src/Sparse/Row.jl#L497-L498

Added lines #L497 - L498 were not covered by tests
end

################################################################################
Expand Down Expand Up @@ -550,6 +583,7 @@
return A*base_ring(A)(b)
end

#left and right div not implemented
function div(A::SRow{T}, b::T) where T
B = sparse_row(base_ring(A))
if iszero(b)
Expand All @@ -572,13 +606,20 @@
return div(A, base_ring(A)(b))
end

function divexact(A::SRow{T}, b::T; check::Bool=true) where T
@doc raw"""
divexact(A::SRow, b::RingElem; check::Bool = true) -> SRow
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
divexact(A::SRow, b::RingElem; check::Bool = true) -> SRow
divexact(A::SRow, b::RingElem; check::Bool = true) -> SRow


Return $C$ such that $a = b \cdot C$. Calls the function `divexact_left(A,b;check)`
"""
divexact(A::SRow{T}, b::T; check::Bool=true) where T <: RingElem = divexact_left(A, b; check)

function divexact_left(A::SRow{T}, b::T; check::Bool=true) where T <: NCRingElem
B = sparse_row(base_ring(A))
if iszero(b)
return error("Division by zero")
end
for (p,v) = A
nv = divexact(v, b; check=check)
nv = divexact_left(v, b; check=check)
@assert !iszero(nv)
push!(B.pos, p)
push!(B.values, nv)
Expand All @@ -590,7 +631,33 @@
if length(A.values) == 0
return deepcopy(A)
end
return divexact(A, base_ring(A)(b); check=check)
return divexact_left(A, base_ring(A)(b), check=check)
end

@doc raw"""
divexact_right(A::SRow, b::NCRingElem; check::Bool = true) -> SRow

Return $C$ such that $A = C \cdot b.
"""
function divexact_right(A::SRow{T}, b::T; check::Bool=true) where T
B = sparse_row(base_ring(A))
if iszero(b)
return error("Division by zero")

Check warning on line 645 in src/Sparse/Row.jl

View check run for this annotation

Codecov / codecov/patch

src/Sparse/Row.jl#L642-L645

Added lines #L642 - L645 were not covered by tests
end
for (p,v) = A
nv = divexact_right(v, b; check=check)
@assert !iszero(nv)
push!(B.pos, p)
push!(B.values, nv)
end
return B

Check warning on line 653 in src/Sparse/Row.jl

View check run for this annotation

Codecov / codecov/patch

src/Sparse/Row.jl#L647-L653

Added lines #L647 - L653 were not covered by tests
end

function divexact_right(A::SRow{T}, b::Integer; check::Bool=true) where T
if length(A.values) == 0
return deepcopy(A)

Check warning on line 658 in src/Sparse/Row.jl

View check run for this annotation

Codecov / codecov/patch

src/Sparse/Row.jl#L656-L658

Added lines #L656 - L658 were not covered by tests
end
return divexact_right(A, base_ring(A)(b); check=check)

Check warning on line 660 in src/Sparse/Row.jl

View check run for this annotation

Codecov / codecov/patch

src/Sparse/Row.jl#L660

Added line #L660 was not covered by tests
end

################################################################################
Expand All @@ -617,11 +684,12 @@
Returns the row $c A + B$.
"""
add_scaled_row(a::SRow{T}, b::SRow{T}, c::T) where {T} = add_scaled_row!(a, deepcopy(b), c)
add_left_scaled_row(a::SRow{T}, b::SRow{T}, c::T) where {T} = add_scaled_row!(a, deepcopy(b), c)

Check warning on line 687 in src/Sparse/Row.jl

View check run for this annotation

Codecov / codecov/patch

src/Sparse/Row.jl#L687

Added line #L687 was not covered by tests

@doc raw"""
add_scaled_row!(A::SRow{T}, B::SRow{T}, c::T) -> SRow{T}

Returns the row $c A + B$ by changing $B$ in place.
Adds the left scaled row $c A$ to $B$.
"""
function add_scaled_row!(a::SRow{T}, b::SRow{T}, c::T) where T
@assert a !== b
Expand Down Expand Up @@ -657,7 +725,49 @@
return b
end

add_scaled_row!(a::SRow{T}, b::SRow{T}, c::T, tmp::SRow{T}) where T = add_scaled_row!(a, b, c)
add_scaled_row!(a::SRow{T}, b::SRow{T}, c::T, tmp::SRow{T}) where T = add_scaled_row!(a, b, c)

Check warning on line 728 in src/Sparse/Row.jl

View check run for this annotation

Codecov / codecov/patch

src/Sparse/Row.jl#L728

Added line #L728 was not covered by tests

add_right_scaled_row(a::SRow{T}, b::SRow{T}, c::T) where {T} = add_right_scaled_row!(a, deepcopy(b), c)

Check warning on line 730 in src/Sparse/Row.jl

View check run for this annotation

Codecov / codecov/patch

src/Sparse/Row.jl#L730

Added line #L730 was not covered by tests

@doc raw"""
add_right_scaled_row!(A::SRow{T}, B::SRow{T}, c::T) -> SRow{T}

Return the right scaled row $c A$ to $B$ by changing $B$ in place.
"""

function add_right_scaled_row!(a::SRow{T}, b::SRow{T}, c::T) where T
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of duplicating all this code, you could also use Val to do something like this:

Suggested change
function add_right_scaled_row!(a::SRow{T}, b::SRow{T}, c::T) where T
function add_scaled_row!(a::SRow{T}, b::SRow{T}, c::T, ::Val{left} = Val(true)) where {T, left}

and then in the critical part you can do

  if left
    t = mul!(t, c, a.values[i])
  else
    t = mul!(t, a.values[i], c)
  end

But this can also wait for a future cleanup.
Then finally you can do

add_left_scaled_row!(a::SRow{T}, b::SRow{T}, c::T) where T = add_scaled_row!(a,b,c,Val(true))
add_right_scaled_row!(a::SRow{T}, b::SRow{T}, c::T) where T = add_scaled_row!(a,b,c,Val(false))

@assert a !== b
i = 1
j = 1
t = base_ring(a)()
while i <= length(a) && j <= length(b)
if a.pos[i] < b.pos[j]
insert!(b.pos, j, a.pos[i])
insert!(b.values, j, a.values[i]*c)
i += 1
j += 1
elseif a.pos[i] > b.pos[j]
j += 1

Check warning on line 750 in src/Sparse/Row.jl

View check run for this annotation

Codecov / codecov/patch

src/Sparse/Row.jl#L738-L750

Added lines #L738 - L750 were not covered by tests
else
t = mul!(t, a.values[i], c)
b.values[j] = addeq!(b.values[j], t)

Check warning on line 753 in src/Sparse/Row.jl

View check run for this annotation

Codecov / codecov/patch

src/Sparse/Row.jl#L752-L753

Added lines #L752 - L753 were not covered by tests

if iszero(b.values[j])
deleteat!(b.values, j)
deleteat!(b.pos, j)

Check warning on line 757 in src/Sparse/Row.jl

View check run for this annotation

Codecov / codecov/patch

src/Sparse/Row.jl#L755-L757

Added lines #L755 - L757 were not covered by tests
else
j += 1

Check warning on line 759 in src/Sparse/Row.jl

View check run for this annotation

Codecov / codecov/patch

src/Sparse/Row.jl#L759

Added line #L759 was not covered by tests
end
i += 1

Check warning on line 761 in src/Sparse/Row.jl

View check run for this annotation

Codecov / codecov/patch

src/Sparse/Row.jl#L761

Added line #L761 was not covered by tests
end
end
while i <= length(a)
push!(b.pos, a.pos[i])
push!(b.values, a.values[i]*c)
i += 1
end
return b

Check warning on line 769 in src/Sparse/Row.jl

View check run for this annotation

Codecov / codecov/patch

src/Sparse/Row.jl#L763-L769

Added lines #L763 - L769 were not covered by tests
end

################################################################################
#
Expand Down
2 changes: 2 additions & 0 deletions src/exports.jl
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@ export absolute_tr
export absolute_value
export add!
export add_assertion_scope
export add_right_scaled_row
export add_scaled_row
export add_verbosity_scope
export algebra
Expand Down Expand Up @@ -813,6 +814,7 @@ export rresx
export saturate
export scale
export scale_row!
export scale_row_right!
export scales
export schur_index
export semi_global_minimal_model
Expand Down
20 changes: 20 additions & 0 deletions test/Sparse/Row.jl
Original file line number Diff line number Diff line change
Expand Up @@ -173,4 +173,24 @@
@test dense_row(A, 3) == matrix(FlintZZ, 1, 3, [-5, 0, 2])
@test dense_row(A, 6) == matrix(FlintZZ, 1, 6, [-5, 0, 2, -10, 1, 0])
@test sparse_row(dense_row(A, 6)) == A

# SRow{NCRingElem}
R = matrix_algebra(QQ,2)
a = R(matrix(QQ,[1 2; 3 4]))
b = R(matrix(QQ,[3 4; 5 6]))
i = R(1)
A = sparse_row(R,[1],[a])
AA = sparse_row(R,[1],[a])
B = sparse_row(R,[1],[b])
@test dot(A,B) != dot(B,A)
@test A*i == A == i*A
@test !(scale_row!(A,b) == scale_row_right!(AA,b))
#C = add_scaled_row(A,B,i)
#@test C == A+B

F, (x,y) = free_associative_algebra(QQ,[:x, :y])
A = sparse_row(F,[1],[x])
B = sparse_row(F,[1],[y])
C = add_scaled_row(A,B,F(1))
@test C == A+B
end
Loading