Skip to content

Fix coloring with empty matrix as input#300

Merged
gdalle merged 6 commits intoJuliaDiff:mainfrom
blegat:empty_coloring
Feb 18, 2026
Merged

Fix coloring with empty matrix as input#300
gdalle merged 6 commits intoJuliaDiff:mainfrom
blegat:empty_coloring

Conversation

@blegat
Copy link
Copy Markdown
Contributor

@blegat blegat commented Jan 19, 2026

The change to _coloring fixes the following error:

julia> problem = ColoringProblem(; structure = :symmetric, partition = :column)
ColoringProblem{:symmetric, :column}()

julia> algo = GreedyColoringAlgorithm(; decompression = :substitution)
GreedyColoringAlgorithm{:substitution, 1, Tuple{NaturalOrder}}((NaturalOrder(),), false)

julia> S = spzeros(Int, 0, 0)
0×0 SparseMatrixCSC{Int64, Int64} with 0 stored entries

julia> coloring(S, problem, algo)
ERROR: ArgumentError: reducing over an empty collection is not allowed; consider supplying `init` to the reducer
Stacktrace:
  [1] _empty_reduce_error()
    @ Base ./reduce.jl:311
  [2] reduce_empty(f::Function, T::Type)
    @ Base ./reduce.jl:312
  [3] mapreduce_empty(::typeof(identity), op::Function, T::Type)
    @ Base ./reduce.jl:361
  [4] reduce_empty(op::Base.MappingRF{typeof(identity), typeof(max)}, ::Type{Int64})
    @ Base ./reduce.jl:350
  [5] reduce_empty_iter
    @ ./reduce.jl:373 [inlined]
  [6] mapreduce_empty_iter(f::Function, op::Function, itr::Vector{Int64}, ItrEltype::Base.HasEltype)
    @ Base ./reduce.jl:369
  [7] _mapreduce
    @ ./reduce.jl:421 [inlined]
  [8] _mapreduce_dim
    @ ./reducedim.jl:334 [inlined]
  [9] mapreduce
    @ ./reducedim.jl:326 [inlined]
 [10] _maximum
    @ ./reducedim.jl:984 [inlined]
 [11] _maximum
    @ ./reducedim.jl:983 [inlined]
 [12] maximum
    @ ./reducedim.jl:979 [inlined]
 [13] call_composed
    @ ./operators.jl:1099 [inlined]
 [14] ComposedFunction
    @ ./operators.jl:1096 [inlined]
 [15] #argmin##0
    @ ./reduce.jl:1020 [inlined]
 [16] MappingRF
    @ ./reduce.jl:92 [inlined]
 [17] afoldl
    @ ./operators.jl:599 [inlined]
 [18] _foldl_impl
    @ ./reduce.jl:60 [inlined]
 [19] foldl_impl
    @ ./reduce.jl:40 [inlined]
 [20] mapfoldl_impl
    @ ./reduce.jl:36 [inlined]
 [21] mapfoldl
    @ ./reduce.jl:167 [inlined]
 [22] argmin
    @ ./reduce.jl:1020 [inlined]
 [23] _coloring(speed_setting::SparseMatrixColorings.WithResult, A::SparseMatrixCSC{…}, ::ColoringProblem{…}, algo::GreedyColoringAlgorithm{…}, decompression_eltype::Type{…}, symmetric_pattern::Bool)
    @ SparseMatrixColorings ~/.julia/dev/SparseMatrixColorings/src/interface.jl:311
 [24] #coloring#28
    @ ~/.julia/dev/SparseMatrixColorings/src/interface.jl:196 [inlined]
 [25] coloring(A::SparseMatrixCSC{…}, problem::ColoringProblem{…}, algo::GreedyColoringAlgorithm{…})
    @ SparseMatrixColorings ~/.julia/dev/SparseMatrixColorings/src/interface.jl:189
 [26] top-level scope
    @ REPL[22]:1
Some type information was truncated. Use `show(err)` to see complete types.

After this, we have the following error that is fixed by the change in group_by_color:

julia> coloring(S, problem, algo)
ERROR: ArgumentError: reducing over an empty collection is not allowed; consider supplying `init` to the reducer
Stacktrace:
  [1] _empty_reduce_error()
    @ Base ./reduce.jl:311
  [2] mapreduce_empty(f::Function, op::Function, T::Type)
    @ Base ./reduce.jl:313
  [3] reduce_empty(op::Base.MappingRF{Base.ExtremaMap{typeof(identity)}, typeof(Base._extrema_rf)}, ::Type{Int64})
    @ Base ./reduce.jl:350
  [4] reduce_empty_iter
    @ ./reduce.jl:373 [inlined]
  [5] mapreduce_empty_iter(f::Function, op::Function, itr::Vector{Int64}, ItrEltype::Base.HasEltype)
    @ Base ./reduce.jl:369
  [6] _mapreduce
    @ ./reduce.jl:421 [inlined]
  [7] _mapreduce_dim
    @ ./reducedim.jl:334 [inlined]
  [8] mapreduce
    @ ./reducedim.jl:326 [inlined]
  [9] _extrema
    @ ./reducedim.jl:984 [inlined]
 [10] _extrema
    @ ./reducedim.jl:983 [inlined]
 [11] extrema
    @ ./reducedim.jl:979 [inlined]
 [12] group_by_color(::Type{Int64}, color::Vector{Int64})
    @ SparseMatrixColorings ~/.julia/dev/SparseMatrixColorings/src/result.jl:88
 [13] SparseMatrixColorings.TreeSetColoringResult(A::SparseMatrixCSC{…}, ag::SparseMatrixColorings.AdjacencyGraph{…}, color::Vector{…}, tree_set::SparseMatrixColorings.TreeSet{…}, decompression_eltype::Type{…})
    @ SparseMatrixColorings ~/.julia/dev/SparseMatrixColorings/src/result.jl:409
 [14] _coloring(speed_setting::SparseMatrixColorings.WithResult, A::SparseMatrixCSC{…}, ::ColoringProblem{…}, algo::GreedyColoringAlgorithm{…}, decompression_eltype::Type{…}, symmetric_pattern::Bool)
    @ SparseMatrixColorings ~/.julia/dev/SparseMatrixColorings/src/interface.jl:318
 [15] #coloring#28
    @ ~/.julia/dev/SparseMatrixColorings/src/interface.jl:196 [inlined]
 [16] coloring(A::SparseMatrixCSC{…}, problem::ColoringProblem{…}, algo::GreedyColoringAlgorithm{…})
    @ SparseMatrixColorings ~/.julia/dev/SparseMatrixColorings/src/interface.jl:189
 [17] top-level scope
    @ REPL[22]:1
Some type information was truncated. Use `show(err)` to see complete types.

Will add tests if this changes looks reasonable.

@codecov
Copy link
Copy Markdown

codecov Bot commented Jan 19, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 100.00%. Comparing base (921c7a0) to head (9caca0f).
⚠️ Report is 2 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff            @@
##              main      #300   +/-   ##
=========================================
  Coverage   100.00%   100.00%           
=========================================
  Files           20        20           
  Lines         2139      2143    +4     
=========================================
+ Hits          2139      2143    +4     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copy link
Copy Markdown
Member

@gdalle gdalle left a comment

Choose a reason for hiding this comment

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

Is acyclic coloring the only kind where empty matrices are problematic? What happens if only one dimension of the matrix is zero?
The fix is welcome (even though its usefulness isn't obvious to me), but then we may want to fix everything at once

Comment thread src/result.jl Outdated
blegat and others added 2 commits January 29, 2026 10:08
Co-authored-by: Guillaume Dalle <22795598+gdalle@users.noreply.github.com>
Comment thread test/check.jl
Comment thread test/check.jl
Copy link
Copy Markdown
Member

@gdalle gdalle left a comment

Choose a reason for hiding this comment

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

Thanks! Let's merge if the tests pass

@gdalle gdalle merged commit 4789944 into JuliaDiff:main Feb 18, 2026
10 checks passed
gdalle added a commit that referenced this pull request Apr 28, 2026
* Bump julia-actions/julia-downgrade-compat from 1 to 2 (#258)

Bumps [julia-actions/julia-downgrade-compat](https://github.com/julia-actions/julia-downgrade-compat) from 1 to 2.
- [Release notes](https://github.com/julia-actions/julia-downgrade-compat/releases)
- [Commits](julia-actions/julia-downgrade-compat@v1...v2)

---
updated-dependencies:
- dependency-name: julia-actions/julia-downgrade-compat
  dependency-version: '2'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Bump actions/checkout from 4 to 5 (#259)

* ensure `UnsupportedDecompressionError <: Exception` (#260)

Not sure if there is any benefit, but I suppose the intention is for
this type, as an exception type, to subtype `Exception`.

* Bump peter-evans/create-or-update-comment from 4 to 5 (#261)

* Bump peter-evans/find-comment from 3 to 4 (#262)

Bumps [peter-evans/find-comment](https://github.com/peter-evans/find-comment) from 3 to 4.
- [Release notes](https://github.com/peter-evans/find-comment/releases)
- [Commits](peter-evans/find-comment@v3...v4)

---
updated-dependencies:
- dependency-name: peter-evans/find-comment
  dependency-version: '4'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Allow picking the best of several orders for GreedyColoringAlgorithm (#265)

* Allow picking the best of several orders for GreedyColoringAlgorithm

* Fix type params

* Tuple

* Better tests

* Better test

* Fix foc

* Fix type inference inside closure

* Fix seed

* Test on 1.11

* Avoid duplicate remap_colors

* chore: bump version to 0.4.22 (#268)

* chore: fix typo in package UUID (#269)

* Make any coloring algorithm compatible with SMC (#263)

* Make any coloring algorithm compatible with SMC

* Fix StackOverflow

* Run tests on 1.11

* Start working on optimal coloring

* Fix tests

* Improve feasibility check

* Format

* Fix

* Fix

* Typo

* Use HiGHS

* Remove OptimalColoringAlgorithm

* Remove test deps

* Don't handle forced colors in acyclic

* Run GPU CI on 1.11 too

* Actually use forced colors

* Format

* Deactivate JuliaFormatter (can't figure out why it fails)

* Optimal coloring algorithm with JuMP formulation (#271)

* Add a file postprocessing.jl (#275)

* Rename has_diagonal into augmented_graph (#273)

* Rename has_diagonal into augmented_graph

* Fix a typo in  postprocessing.jl

* Update src/graph.jl

Co-authored-by: Guillaume Dalle <22795598+gdalle@users.noreply.github.com>

---------

Co-authored-by: Guillaume Dalle <22795598+gdalle@users.noreply.github.com>

* Try tests on Julia 1.12 (#276)

* Bump SMC to v0.4.23 (#277)

* Patch failing alloc test (#278)

* Add postprocess_with_star_set! and postprocess_with_tree_set! (#279)

* Bump actions/checkout from 5 to 6 (#282)

Bumps [actions/checkout](https://github.com/actions/checkout) from 5 to 6.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](actions/checkout@v5...v6)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Replace is_solved_and_feasible with assert_is_solved_and_feasible (#284)

* Fix JET tests (#285)

* Fix JET tests

* Move JuliaFormatter to action

* Fix formatting

* Use diagonal_indices in the general decompress! for acyclic coloring (#287)

* Enhance decompress! for bicoloring (#288)

* Add a compat entry for CUDA.jl in test/Project.toml (#293)

* Add nb_self_loops in AdjacencyGraph (#290)

* Remove unused arguments from internal functions (#295)

* Add test functions substitutable_columns and substitutable_bidirectional (#297)

* Document fields of TreeSet (#296)

* Fix respectful_similar with SparsityPatternCSC (#299)

* Fix respectful_similar with SparsityPatternCSC

* Add test

* Fix format

* Add test

---------

Co-authored-by: Alexis Montoison <35051714+amontoison@users.noreply.github.com>

* Fix coloring with empty matrix as input (#300)

* Fix coloring with empty matrix as input

* Update src/result.jl

Co-authored-by: Guillaume Dalle <22795598+gdalle@users.noreply.github.com>

* Add check

* Fix format

* Change check

* Apply suggestion from @gdalle

---------

Co-authored-by: Guillaume Dalle <22795598+gdalle@users.noreply.github.com>

* test: skip failing MiniZinc tests (#305)

* Fix eltype invalidation for SparsityPatternCSC (#304)

SparsityPatternCSC{Ti} <: AbstractMatrix{Bool} but the custom
Base.eltype method was returning Ti (the index type) instead of Bool.
This caused 24,906 method invalidations when loading the package,
as it invalidated the backedge from Base.eltype(::AbstractArray).

Change the custom method to SparseArrays.indtype instead, since
that's what the type parameter Ti actually represents. The eltype
is now correctly inherited from AbstractMatrix{Bool}.

Co-authored-by: ChrisRackauckas-Claude <accounts@chrisrackauckas.com>
Co-authored-by: Guillaume Dalle <22795598+gdalle@users.noreply.github.com>

* chore: bump version (#306)

* Bump julia-actions/cache from 2 to 3 (#307)

* Update repo owner to JuliaDiff org (#309)

* Update repo owner

* Bump version

* Switch GPU CI to buildkite

* Add badge

* Fix buildkite badge [skip tests] (#310)

* Accept AbstractSparseMatrixCSC for decompression (#298)

* Accept AbstractSparseMatrixCSC for decompression

* Define decompress_csc

* Remove unused import of AbstractSparseMatrixCSC

* Apply suggestion from @blegat

* Change return statement to return nothing

* Apply suggestion from @blegat

* Add to docs

* Apply suggestion from @gdalle

Co-authored-by: Guillaume Dalle <22795598+gdalle@users.noreply.github.com>

* Move to internals

---------

Co-authored-by: Guillaume Dalle <22795598+gdalle@users.noreply.github.com>

* Bump version (#311)

* Bump codecov/codecov-action from 5 to 6 (#312)

Bumps [codecov/codecov-action](https://github.com/codecov/codecov-action) from 5 to 6.
- [Release notes](https://github.com/codecov/codecov-action/releases)
- [Changelog](https://github.com/codecov/codecov-action/blob/main/CHANGELOG.md)
- [Commits](codecov/codecov-action@v5...v6)

---
updated-dependencies:
- dependency-name: codecov/codecov-action
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* chore: bump CUDA compat to v6 (cuSPARSE now a separate package) (#314)

* chore: bump CUDA compat to v6 (cuSPARSE now a separate package)

* More renaming

* Format

* Fix compression?

* Generic compression and result

* Import

* No generic result

* Fix ambiguity

* Bump julia-actions/setup-julia from 2 to 3 (#315)

Bumps [julia-actions/setup-julia](https://github.com/julia-actions/setup-julia) from 2 to 3.
- [Release notes](https://github.com/julia-actions/setup-julia/releases)
- [Commits](julia-actions/setup-julia@v2...v3)

---
updated-dependencies:
- dependency-name: julia-actions/setup-julia
  dependency-version: '3'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Neven Sajko <4944410+nsajko@users.noreply.github.com>
Co-authored-by: Guillaume Dalle <22795598+gdalle@users.noreply.github.com>
Co-authored-by: Alexis Montoison <35051714+amontoison@users.noreply.github.com>
Co-authored-by: Benoît Legat <benoit.legat@gmail.com>
Co-authored-by: Chris Rackauckas - Beep Boop Edition <admin@chrisrackauckas.com>
Co-authored-by: ChrisRackauckas-Claude <accounts@chrisrackauckas.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants