Skip to content

Commit b32c1b8

Browse files
KlausCViralBShah
authored andcommitted
Argument checks for SparseMatrixCSC constructors (#31724)
* reconstruct PR #31118 * reconstruct PR 31118 2 * Check arguments of SparseMatrixCSC #31024 #31435 * fix SuiteSparse test * added NEWS, fixed tests * loosen restrictions - resize to useful length * cleaned up NEWS, revert minor change * add non-checking and checking constructor - improve check performance
1 parent d6b6cb5 commit b32c1b8

File tree

5 files changed

+160
-40
lines changed

5 files changed

+160
-40
lines changed

NEWS.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,11 @@ Standard library changes
4848

4949
#### SparseArrays
5050

51+
* `SparseMatrixCSC(m,n,colptr,rowval,nzval)` perform consistency checks for arguments:
52+
`colptr` must be properly populated and lengths of `colptr`, `rowval`, and `nzval`
53+
must be compatible with `m`, `n`, and `eltype(colptr)`.
54+
* `sparse(I, J, V, m, n)` verifies lengths of `I`, `J`, `V` are equal and compatible with
55+
`eltype(I)` and `m`, `n`.
5156

5257
#### Dates
5358

stdlib/SparseArrays/src/higherorderfns.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -229,7 +229,7 @@ _maxnnzfrom(shape::NTuple{2}, A::SparseMatrixCSC) = nnz(A) * div(shape[1], A.m)
229229
return SparseVector(shape..., storedinds, storedvals)
230230
end
231231
@inline function _allocres(shape::NTuple{2}, indextype, entrytype, maxnnz)
232-
pointers = Vector{indextype}(undef, shape[2] + 1)
232+
pointers = ones(indextype, shape[2] + 1)
233233
storedinds = Vector{indextype}(undef, maxnnz)
234234
storedvals = Vector{entrytype}(undef, maxnnz)
235235
return SparseMatrixCSC(shape..., pointers, storedinds, storedvals)

stdlib/SparseArrays/src/sparsematrix.jl

Lines changed: 96 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
# This file is a part of Julia. License is MIT: https://julialang.org/license
22

33
# Compressed sparse columns data structure
4-
# Assumes that no zeros are stored in the data structure
4+
# No assumptions about stored zeros in the data structure
55
# Assumes that row values in rowval for each column are sorted
66
# issorted(rowval[colptr[i]:(colptr[i+1]-1)]) == true
7+
# Assumes that 1 <= colptr[i] <= colptr[i+1] for i in 1..n
8+
# Assumes that nnz <= length(rowval) < typemax(Ti)
9+
# Assumes that 0 <= length(nzval) < typemax(Ti)
710

811
"""
912
SparseMatrixCSC{Tv,Ti<:Integer} <: AbstractSparseMatrix{Tv,Ti}
@@ -20,8 +23,8 @@ struct SparseMatrixCSC{Tv,Ti<:Integer} <: AbstractSparseMatrix{Tv,Ti}
2023
rowval::Vector{Ti} # Row indices of stored values
2124
nzval::Vector{Tv} # Stored values, typically nonzeros
2225

23-
function SparseMatrixCSC{Tv,Ti}(m::Integer, n::Integer, colptr::Vector{Ti}, rowval::Vector{Ti},
24-
nzval::Vector{Tv}) where {Tv,Ti<:Integer}
26+
function SparseMatrixCSC{Tv,Ti}(m::Integer, n::Integer, colptr::Vector{Ti},
27+
rowval::Vector{Ti}, nzval::Vector{Tv}) where {Tv,Ti<:Integer}
2528
@noinline throwsz(str, lbl, k) =
2629
throw(ArgumentError("number of $str ($lbl) must be ≥ 0, got $k"))
2730
m < 0 && throwsz("rows", 'm', m)
@@ -32,9 +35,42 @@ end
3235
function SparseMatrixCSC(m::Integer, n::Integer, colptr::Vector, rowval::Vector, nzval::Vector)
3336
Tv = eltype(nzval)
3437
Ti = promote_type(eltype(colptr), eltype(rowval))
38+
sparse_check_Ti(m, n, Ti)
39+
sparse_check(n, colptr, rowval, nzval)
40+
# silently shorten rowval and nzval to usable index positions.
41+
maxlen = abs(widemul(m, n))
42+
isbitstype(Ti) && (maxlen = min(maxlen, typemax(Ti) - 1))
43+
length(rowval) > maxlen && resize!(rowval, maxlen)
44+
length(nzval) > maxlen && resize!(nzval, maxlen)
3545
SparseMatrixCSC{Tv,Ti}(m, n, colptr, rowval, nzval)
3646
end
3747

48+
function sparse_check_Ti(m::Integer, n::Integer, Ti::Type)
49+
@noinline throwTi(str, lbl, k) =
50+
throw(ArgumentError("$str ($lbl = $k) does not fit in Ti = $(Ti)"))
51+
0 m && (!isbitstype(Ti) || m typemax(Ti)) || throwTi("number of rows", "m", m)
52+
0 n && (!isbitstype(Ti) || n typemax(Ti)) || throwTi("number of columns", "n", n)
53+
end
54+
55+
function sparse_check(n::Integer, colptr::Vector{Ti}, rowval, nzval) where Ti
56+
sparse_check_length("colptr", colptr, n+1, String) # don't check upper bound
57+
ckp = Ti(1)
58+
ckp == colptr[1] || throw(ArgumentError("$ckp == colptr[1] != 1"))
59+
@inbounds for k = 2:n+1
60+
ck = colptr[k]
61+
ckp <= ck || throw(ArgumentError("$ckp == colptr[$(k-1)] > colptr[$k] == $ck"))
62+
ckp = ck
63+
end
64+
sparse_check_length("rowval", rowval, ckp-1, Ti)
65+
sparse_check_length("nzval", nzval, 0, Ti) # we allow empty nzval !!!
66+
end
67+
function sparse_check_length(rowstr, rowval, minlen, Ti)
68+
len = length(rowval)
69+
len >= minlen || throw(ArgumentError("$len == length($rowstr) < $minlen"))
70+
!isbitstype(Ti) || len < typemax(Ti) ||
71+
throw(ArgumentError("$len == length($rowstr) >= $(typemax(Ti))"))
72+
end
73+
3874
size(S::SparseMatrixCSC) = (S.m, S.n)
3975

4076
# Define an alias for views of a SparseMatrixCSC which include all rows and a unit range of the columns.
@@ -497,7 +533,10 @@ function sparse(I::AbstractVector{Ti}, J::AbstractVector{Ti}, V::AbstractVector{
497533
"length(I) (=$(length(I))) == length(J) (= $(length(J))) == length(V) (= ",
498534
"$(length(V)))")))
499535
end
500-
536+
Tj = Ti
537+
while isbitstype(Tj) && coolen >= typemax(Tj)
538+
Tj = widen(Tj)
539+
end
501540
if m == 0 || n == 0 || coolen == 0
502541
if coolen != 0
503542
if n == 0
@@ -509,13 +548,13 @@ function sparse(I::AbstractVector{Ti}, J::AbstractVector{Ti}, V::AbstractVector{
509548
SparseMatrixCSC(m, n, fill(one(Ti), n+1), Vector{Ti}(), Vector{Tv}())
510549
else
511550
# Allocate storage for CSR form
512-
csrrowptr = Vector{Ti}(undef, m+1)
551+
csrrowptr = Vector{Tj}(undef, m+1)
513552
csrcolval = Vector{Ti}(undef, coolen)
514553
csrnzval = Vector{Tv}(undef, coolen)
515554

516555
# Allocate storage for the CSC form's column pointers and a necessary workspace
517556
csccolptr = Vector{Ti}(undef, n+1)
518-
klasttouch = Vector{Ti}(undef, n)
557+
klasttouch = Vector{Tj}(undef, n)
519558

520559
# Allocate empty arrays for the CSC form's row and nonzero value arrays
521560
# The parent method called below automagically resizes these arrays
@@ -580,25 +619,28 @@ transposition," ACM TOMS 4(3), 250-269 (1978) inspired this method's use of a pa
580619
counting sorts.
581620
"""
582621
function sparse!(I::AbstractVector{Ti}, J::AbstractVector{Ti},
583-
V::AbstractVector{Tv}, m::Integer, n::Integer, combine, klasttouch::Vector{Ti},
584-
csrrowptr::Vector{Ti}, csrcolval::Vector{Ti}, csrnzval::Vector{Tv},
585-
csccolptr::Vector{Ti}, cscrowval::Vector{Ti}, cscnzval::Vector{Tv}) where {Tv,Ti<:Integer}
622+
V::AbstractVector{Tv}, m::Integer, n::Integer, combine, klasttouch::Vector{Tj},
623+
csrrowptr::Vector{Tj}, csrcolval::Vector{Ti}, csrnzval::Vector{Tv},
624+
csccolptr::Vector{Ti}, cscrowval::Vector{Ti}, cscnzval::Vector{Tv}) where {Tv,Ti<:Integer,Tj<:Integer}
586625

587626
require_one_based_indexing(I, J, V)
627+
sparse_check_Ti(m, n, Ti)
628+
sparse_check_length("I", I, 0, Tj)
588629
# Compute the CSR form's row counts and store them shifted forward by one in csrrowptr
589-
fill!(csrrowptr, Ti(0))
630+
fill!(csrrowptr, Tj(0))
590631
coolen = length(I)
632+
min(length(J), length(V)) >= coolen || throw(ArgumentError("J and V need length >= length(I) = $coolen"))
591633
@inbounds for k in 1:coolen
592634
Ik = I[k]
593635
if 1 > Ik || m < Ik
594636
throw(ArgumentError("row indices I[k] must satisfy 1 <= I[k] <= m"))
595637
end
596-
csrrowptr[Ik+1] += Ti(1)
638+
csrrowptr[Ik+1] += Tj(1)
597639
end
598640

599641
# Compute the CSR form's rowptrs and store them shifted forward by one in csrrowptr
600-
countsum = Ti(1)
601-
csrrowptr[1] = Ti(1)
642+
countsum = Tj(1)
643+
csrrowptr[1] = Tj(1)
602644
@inbounds for i in 2:(m+1)
603645
overwritten = csrrowptr[i]
604646
csrrowptr[i] = countsum
@@ -613,7 +655,8 @@ function sparse!(I::AbstractVector{Ti}, J::AbstractVector{Ti},
613655
throw(ArgumentError("column indices J[k] must satisfy 1 <= J[k] <= n"))
614656
end
615657
csrk = csrrowptr[Ik+1]
616-
csrrowptr[Ik+1] = csrk + Ti(1)
658+
@assert csrk >= Tj(1) "index into csrcolval exceeds typemax(Ti)"
659+
csrrowptr[Ik+1] = csrk + Tj(1)
617660
csrcolval[csrk] = Jk
618661
csrnzval[csrk] = V[k]
619662
end
@@ -626,21 +669,21 @@ function sparse!(I::AbstractVector{Ti}, J::AbstractVector{Ti},
626669
# Minimizing extraneous communication and nonlocality of reference, primarily by using
627670
# only a single auxiliary array in this step, is the key to this method's performance.
628671
fill!(csccolptr, Ti(0))
629-
fill!(klasttouch, Ti(0))
630-
writek = Ti(1)
672+
fill!(klasttouch, Tj(0))
673+
writek = Tj(1)
631674
newcsrrowptri = Ti(1)
632-
origcsrrowptri = Ti(1)
675+
origcsrrowptri = Tj(1)
633676
origcsrrowptrip1 = csrrowptr[2]
634677
@inbounds for i in 1:m
635-
for readk in origcsrrowptri:(origcsrrowptrip1-Ti(1))
678+
for readk in origcsrrowptri:(origcsrrowptrip1-Tj(1))
636679
j = csrcolval[readk]
637680
if klasttouch[j] < newcsrrowptri
638681
klasttouch[j] = writek
639682
if writek != readk
640683
csrcolval[writek] = j
641684
csrnzval[writek] = csrnzval[readk]
642685
end
643-
writek += Ti(1)
686+
writek += Tj(1)
644687
csccolptr[j+1] += Ti(1)
645688
else
646689
klt = klasttouch[j]
@@ -654,23 +697,24 @@ function sparse!(I::AbstractVector{Ti}, J::AbstractVector{Ti},
654697
end
655698

656699
# Compute the CSC form's colptrs and store them shifted forward by one in csccolptr
657-
countsum = Ti(1)
700+
countsum = Tj(1)
658701
csccolptr[1] = Ti(1)
659702
@inbounds for j in 2:(n+1)
660703
overwritten = csccolptr[j]
661704
csccolptr[j] = countsum
662705
countsum += overwritten
706+
countsum <= typemax(Ti) || throw(ArgumentError("more than typemax(Ti)-1 == $(typemax(Ti)-1) entries"))
663707
end
664708

665709
# Now knowing the CSC form's entry count, resize cscrowval and cscnzval if necessary
666-
cscnnz = countsum - Ti(1)
710+
cscnnz = countsum - Tj(1)
667711
length(cscrowval) < cscnnz && resize!(cscrowval, cscnnz)
668712
length(cscnzval) < cscnnz && resize!(cscnzval, cscnnz)
669713

670714
# Finally counting-sort the row and nonzero values from the CSR form into cscrowval and
671715
# cscnzval. Tracking write positions in csccolptr corrects the column pointers.
672716
@inbounds for i in 1:m
673-
for csrk in csrrowptr[i]:(csrrowptr[i+1]-Ti(1))
717+
for csrk in csrrowptr[i]:(csrrowptr[i+1]-Tj(1))
674718
j = csrcolval[csrk]
675719
x = csrnzval[csrk]
676720
csck = csccolptr[j+1]
@@ -683,16 +727,16 @@ function sparse!(I::AbstractVector{Ti}, J::AbstractVector{Ti},
683727
SparseMatrixCSC(m, n, csccolptr, cscrowval, cscnzval)
684728
end
685729
function sparse!(I::AbstractVector{Ti}, J::AbstractVector{Ti},
686-
V::AbstractVector{Tv}, m::Integer, n::Integer, combine, klasttouch::Vector{Ti},
687-
csrrowptr::Vector{Ti}, csrcolval::Vector{Ti}, csrnzval::Vector{Tv},
688-
csccolptr::Vector{Ti}) where {Tv,Ti<:Integer}
730+
V::AbstractVector{Tv}, m::Integer, n::Integer, combine, klasttouch::Vector{Tj},
731+
csrrowptr::Vector{Tj}, csrcolval::Vector{Ti}, csrnzval::Vector{Tv},
732+
csccolptr::Vector{Ti}) where {Tv,Ti<:Integer,Tj<:Integer}
689733
sparse!(I, J, V, m, n, combine, klasttouch,
690734
csrrowptr, csrcolval, csrnzval,
691735
csccolptr, Vector{Ti}(), Vector{Tv}())
692736
end
693737
function sparse!(I::AbstractVector{Ti}, J::AbstractVector{Ti},
694-
V::AbstractVector{Tv}, m::Integer, n::Integer, combine, klasttouch::Vector{Ti},
695-
csrrowptr::Vector{Ti}, csrcolval::Vector{Ti}, csrnzval::Vector{Tv}) where {Tv,Ti<:Integer}
738+
V::AbstractVector{Tv}, m::Integer, n::Integer, combine, klasttouch::Vector{Tj},
739+
csrrowptr::Vector{Tj}, csrcolval::Vector{Ti}, csrnzval::Vector{Tv}) where {Tv,Ti<:Integer,Tj<:Integer}
696740
sparse!(I, J, V, m, n, combine, klasttouch,
697741
csrrowptr, csrcolval, csrnzval,
698742
Vector{Ti}(undef, n+1), Vector{Ti}(), Vector{Tv}())
@@ -826,7 +870,7 @@ adjoint!(X::SparseMatrixCSC{Tv,Ti}, A::SparseMatrixCSC{Tv,Ti}) where {Tv,Ti} = f
826870

827871
function ftranspose(A::SparseMatrixCSC{Tv,Ti}, f::Function) where {Tv,Ti}
828872
X = SparseMatrixCSC(A.n, A.m,
829-
Vector{Ti}(undef, A.m+1),
873+
ones(Ti, A.m+1),
830874
Vector{Ti}(undef, nnz(A)),
831875
Vector{Tv}(undef, nnz(A)))
832876
halfperm!(X, A, 1:A.n, f)
@@ -1045,7 +1089,7 @@ function permute!(X::SparseMatrixCSC{Tv,Ti}, A::SparseMatrixCSC{Tv,Ti},
10451089
_checkargs_sourcecompatdest_permute!(A, X)
10461090
_checkargs_sourcecompatperms_permute!(A, p, q)
10471091
C = SparseMatrixCSC(A.n, A.m,
1048-
Vector{Ti}(undef, A.m + 1),
1092+
ones(Ti, A.m + 1),
10491093
Vector{Ti}(undef, nnz(A)),
10501094
Vector{Tv}(undef, nnz(A)))
10511095
_checkargs_permutationsvalid_permute!(p, C.colptr, q, X.colptr)
@@ -1064,7 +1108,7 @@ function permute!(A::SparseMatrixCSC{Tv,Ti}, p::AbstractVector{<:Integer},
10641108
q::AbstractVector{<:Integer}) where {Tv,Ti}
10651109
_checkargs_sourcecompatperms_permute!(A, p, q)
10661110
C = SparseMatrixCSC(A.n, A.m,
1067-
Vector{Ti}(undef, A.m + 1),
1111+
ones(Ti, A.m + 1),
10681112
Vector{Ti}(undef, nnz(A)),
10691113
Vector{Tv}(undef, nnz(A)))
10701114
workcolptr = Vector{Ti}(undef, A.n + 1)
@@ -1135,11 +1179,11 @@ function permute(A::SparseMatrixCSC{Tv,Ti}, p::AbstractVector{<:Integer},
11351179
q::AbstractVector{<:Integer}) where {Tv,Ti}
11361180
_checkargs_sourcecompatperms_permute!(A, p, q)
11371181
X = SparseMatrixCSC(A.m, A.n,
1138-
Vector{Ti}(undef, A.n + 1),
1182+
ones(Ti, A.n + 1),
11391183
Vector{Ti}(undef, nnz(A)),
11401184
Vector{Tv}(undef, nnz(A)))
11411185
C = SparseMatrixCSC(A.n, A.m,
1142-
Vector{Ti}(undef, A.m + 1),
1186+
ones(Ti, A.m + 1),
11431187
Vector{Ti}(undef, nnz(A)),
11441188
Vector{Tv}(undef, nnz(A)))
11451189
_checkargs_permutationsvalid_permute!(p, C.colptr, q, X.colptr)
@@ -2331,15 +2375,32 @@ function _setindex_scalar!(A::SparseMatrixCSC{Tv,Ti}, _v, _i::Integer, _j::Integ
23312375
# Column j does not contain entry A[i,j]. If v is nonzero, insert entry A[i,j] = v
23322376
# and return. If to the contrary v is zero, then simply return.
23332377
if !iszero(v)
2334-
insert!(A.rowval, searchk, i)
2335-
insert!(A.nzval, searchk, v)
2378+
nz = A.colptr[A.n+1]
2379+
# throw exception before state is partially modified
2380+
!isbitstype(Ti) || nz < typemax(Ti) ||
2381+
throw(ArgumentError("nnz(A) going to exceed typemax(Ti) = $(typemax(Ti))"))
2382+
2383+
# if nnz(A) < length(rowval/nzval): no need to grow rowval and preserve values
2384+
_insert!(A.rowval, searchk, i, nz)
2385+
_insert!(A.nzval, searchk, v, nz)
23362386
@simd for m in (j + 1):(A.n + 1)
2337-
@inbounds A.colptr[m] += 1
2387+
@inbounds A.colptr[m] += Ti(1)
23382388
end
23392389
end
23402390
return A
23412391
end
23422392

2393+
# insert item at position pos, shifting only from pos+1 to nz
2394+
function _insert!(v::Vector, pos::Integer, item, nz::Integer)
2395+
if nz > length(v)
2396+
insert!(v, pos, item)
2397+
else # nz < length(v)
2398+
Base.unsafe_copyto!(v, pos+1, v, pos, nz - pos)
2399+
v[pos] = item
2400+
v
2401+
end
2402+
end
2403+
23432404
function Base.fill!(V::SubArray{Tv, <:Any, <:SparseMatrixCSC, Tuple{Vararg{Union{Integer, AbstractVector{<:Integer}},2}}}, x) where Tv
23442405
A = V.parent
23452406
I, J = V.indices

stdlib/SparseArrays/test/sparse.jl

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2597,6 +2597,7 @@ end
25972597
A = SparseMatrixCSC(Complex{BigInt}[1+im 2+2im]')'[1:1, 2:2]
25982598
# ...ensure it does! If necessary, the test needs to be updated to use
25992599
# another mechanism to create a suitable A.
2600+
resize!(A.nzval, 2)
26002601
@assert length(A.nzval) > nnz(A)
26012602
@test -A == fill(-2-2im, 1, 1)
26022603
@test conj(A) == fill(2-2im, 1, 1)
@@ -2617,4 +2618,59 @@ end
26172618
@test sum(x1, dims=2) == sum(x2, dims=2)
26182619
end
26192620

2621+
@testset "Ti cannot store all potential values #31024" begin
2622+
# m * n >= typemax(Ti) but nnz < typemax(Ti)
2623+
A = SparseMatrixCSC(12, 12, fill(Int8(1),13), Int8[], Int[])
2624+
@test size(A) == (12,12) && nnz(A) == 0
2625+
I1 = [Int8(i) for i in 1:20 for _ in 1:20]
2626+
J1 = [Int8(i) for _ in 1:20 for i in 1:20]
2627+
# m * n >= typemax(Ti) and nnz >= typemax(Ti)
2628+
@test_throws ArgumentError sparse(I1, J1, ones(length(I1)))
2629+
I1 = Int8.(rand(1:10, 500))
2630+
J1 = Int8.(rand(1:10, 500))
2631+
V1 = ones(500)
2632+
# m * n < typemax(Ti) and length(I) >= typemax(Ti) - combining values
2633+
@test sparse(I1, J1, V1, 10, 10) !== nothing
2634+
# m * n >= typemax(Ti) and length(I) >= typemax(Ti)
2635+
@test sparse(I1, J1, V1, 12, 13) !== nothing
2636+
I1 = Int8.(rand(1:10, 126))
2637+
J1 = Int8.(rand(1:10, 126))
2638+
V1 = ones(126)
2639+
# m * n >= typemax(Ti) and length(I) < typemax(Ti)
2640+
@test sparse(I1, J1, V1, 100, 100) !== nothing
2641+
end
2642+
2643+
@testset "Typecheck too strict #31435" begin
2644+
A = SparseMatrixCSC{Int,Int8}(70, 2, fill(Int8(1), 3), Int8[], Int[])
2645+
A[5:67,1:2] .= ones(Int, 63, 2)
2646+
@test nnz(A) == 126
2647+
# nnz >= typemax
2648+
@test_throws ArgumentError A[2,1] = 42
2649+
# colptr short
2650+
@test_throws ArgumentError SparseMatrixCSC(1, 1, Int[], Int[], Float64[])
2651+
# colptr[1] must be 1
2652+
@test_throws ArgumentError SparseMatrixCSC(10, 3, [0,1,1,1], Int[], Float64[])
2653+
# colptr not ascending
2654+
@test_throws ArgumentError SparseMatrixCSC(10, 3, [1,2,1,2], Int[], Float64[])
2655+
# rowwal (and nzval) short
2656+
@test_throws ArgumentError SparseMatrixCSC(10, 3, [1,2,2,4], [1,2], Float64[])
2657+
# nzval short
2658+
@test SparseMatrixCSC(10, 3, [1,2,2,4], [1,2,3], Float64[]) !== nothing
2659+
# length(rowval) >= typemax
2660+
@test_throws ArgumentError SparseMatrixCSC(5, 1, Int8[1,2], fill(Int8(1),127), Int[1,2,3])
2661+
@test SparseMatrixCSC{Int,Int8}(5, 1, Int8[1,2], fill(Int8(1),127), Int[1,2,3]) != 0
2662+
# length(nzval) >= typemax
2663+
@test_throws ArgumentError SparseMatrixCSC(5, 1, Int8[1,2], Int8[1], fill(7, 127))
2664+
@test SparseMatrixCSC{Int,Int8}(5, 1, Int8[1,2], Int8[1], fill(7, 127)) != 0
2665+
2666+
# length(I) >= typemax
2667+
@test_throws ArgumentError sparse(UInt8.(1:255), fill(UInt8(1), 255), fill(1, 255))
2668+
# m > typemax
2669+
@test_throws ArgumentError sparse(UInt8.(1:254), fill(UInt8(1), 254), fill(1, 254), 256, 1)
2670+
# n > typemax
2671+
@test_throws ArgumentError sparse(UInt8.(1:254), fill(UInt8(1), 254), fill(1, 254), 255, 256)
2672+
# n, m maximal
2673+
@test sparse(UInt8.(1:254), fill(UInt8(1), 254), fill(1, 254), 255, 255) !== nothing
2674+
end
2675+
26202676
end # module

stdlib/SuiteSparse/test/cholmod.jl

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -764,10 +764,8 @@ end
764764
end
765765

766766
@testset "Check inputs to Sparse. Related to #20024" for A_ in (
767-
SparseMatrixCSC(2, 2, [1, 2], CHOLMOD.SuiteSparse_long[], Float64[]),
768-
SparseMatrixCSC(2, 2, [1, 2, 3], CHOLMOD.SuiteSparse_long[1], Float64[]),
769-
SparseMatrixCSC(2, 2, [1, 2, 3], CHOLMOD.SuiteSparse_long[], Float64[1.0]),
770-
SparseMatrixCSC(2, 2, [1, 2, 3], CHOLMOD.SuiteSparse_long[1], Float64[1.0]))
767+
SparseMatrixCSC(2, 2, [1, 2, 3], CHOLMOD.SuiteSparse_long[1,2], Float64[]),
768+
SparseMatrixCSC(2, 2, [1, 2, 3], CHOLMOD.SuiteSparse_long[1,2], Float64[1.0]))
771769
@test_throws ArgumentError CHOLMOD.Sparse(size(A_)..., A_.colptr .- 1, A_.rowval .- 1, A_.nzval)
772770
@test_throws ArgumentError CHOLMOD.Sparse(A_)
773771
end

0 commit comments

Comments
 (0)