Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions docs/make.jl
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ makedocs(;
"DSatur" => "dsatur.md",
"Workstream" => "workstream.md",
],
"Storing colors" => "storage.md",
"Contributing" => "contributing.md",
"API Reference" => "apiref.md",
],
Expand Down
11 changes: 4 additions & 7 deletions docs/src/dsatur.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,15 +30,12 @@ conflicts = GraphsColoring.conflictmatrix(X)

colors = GraphsColoring.color(conflicts; algorithm=DSATUR())

for (i, color) in enumerate(colors)
println("Color $i has $(length(color)) elements")
end

facecolors = zeros(size(conflicts, 1))

for (i, color) in enumerate(colors)
for element in color
facecolors[element] = i
for color in eachindex(colors)
println("Color $color has $(length(colors[color])) elements")
for element in colors[color]
facecolors[element] = color
end
end

Expand Down
11 changes: 4 additions & 7 deletions docs/src/greedy.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,12 @@ conflicts = GraphsColoring.conflictmatrix(X)

colors = GraphsColoring.color(conflicts; algorithm=Greedy())

for (i, color) in enumerate(colors)
println("Color $i has $(length(color)) elements")
end

facecolors = zeros(size(conflicts, 1))

for (i, color) in enumerate(colors)
for element in color
facecolors[element] = i
for color in eachindex(colors)
println("Color $color has $(length(colors[color])) elements")
for element in colors[color]
facecolors[element] = color
end
end

Expand Down
93 changes: 93 additions & 0 deletions docs/src/storage.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
# Storing and Accessing Coloring Results

Coloring results in `GraphsColoring` can be stored in two primary formats:

## `GroupedColoring` (Default)

- **Storage**: Colors are stored as a vector of vectors, where each inner vector contains the indices of elements assigned to a specific color.
- **Optimization**: Efficient retrieval of all elements belonging to a specific color group.
- **Best for**: Operations that frequently access elements by color (e.g., processing color groups in parallel, analyzing group sizes, or visualizing color distributions).
- **Default behavior**: This is the default storage format when no `storage` parameter is specified.

## `Graphs.Coloring`

- **Storage**: Colors are stored as a flat vector where `colors[i]` gives the color assigned to element `i`.
- **Optimization**: Efficient access to the color of a specific element.
- **Best for**: Operations that frequently query the color of individual elements.

---

## Usage Examples

### Using `GroupedColoring` (Default)

```@example
using PlotlyJS#hide
using CompScienceMeshes#hide
using BEAST#hide
using GraphsColoring#hide

m = meshsphere(1.0, 0.1)#hide
X = raviartthomas(m)#hide

conflicts = GraphsColoring.conflictmatrix(X)#hide

colors = GraphsColoring.color(conflicts; storage=GraphsColoring.GroupedColors())
```

### Using `Graphs.Coloring`

```@example
using PlotlyJS#hide
using CompScienceMeshes#hide
using BEAST#hide
using GraphsColoring#hide

m = meshsphere(1.0, 0.1)#hide
X = raviartthomas(m)#hide

conflicts = GraphsColoring.conflictmatrix(X)#hide

colors = GraphsColoring.color(conflicts; storage=GraphsColoring.GraphsColors())
```

---

## Accessing Coloring Results

Both storage formats support standard Julia interfaces:

| Operation | Description |
|---------|-------------|
| `numcolors(c)` | Returns the total number of distinct colors |
| `eachindex(c)` | Iterates over color group indices (1-based) |
| `c[i]` | Retrieves the i-th color group (as a vector of element indices) |
| `length(c[i])` | Gets the number of elements in the i-th color group |

### Example: Accessing Colors

```@example
using PlotlyJS#hide
using CompScienceMeshes#hide
using BEAST#hide
using GraphsColoring#hide

m = meshsphere(1.0, 0.1)#hide
X = raviartthomas(m)#hide

conflicts = GraphsColoring.conflictmatrix(X)#hide

colors = GraphsColoring.color(conflicts; algorithm=WorkstreamGreedy, storage=GraphsColoring.GraphsColors()) # hide

println("We have $(numcolors(colors))")
for color in eachindex(colors)
println("Color $color has $(length(colors[color])) elements. The members of color $color are $(colors[color])")
end
```

---

## Notes

- The default storage is `GroupedColoring` because it enables efficient group-based operations.
- The `Graphs.Coloring` format is more efficient for very large problems when only individual element colors are needed.
24 changes: 9 additions & 15 deletions docs/src/workstream.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,15 +44,12 @@ conflicts = GraphsColoring.conflictmatrix(X)

colors = GraphsColoring.color(conflicts; algorithm=WorkstreamDSATUR)

for (i, color) in enumerate(colors)
println("Color $i has $(length(color)) elements")
end

facecolors = zeros(size(conflicts, 1))

for (i, color) in enumerate(colors)
for element in color
facecolors[element] = i
for color in eachindex(colors)
println("Color $color has $(length(colors[color])) elements")
for element in colors[color]
facecolors[element] = color
end
end

Expand Down Expand Up @@ -92,17 +89,14 @@ conflicts = GraphsColoring.conflictmatrix(X)#hide

colors = GraphsColoring.color(conflicts; algorithm=WorkstreamGreedy)

for (i, color) in enumerate(colors)#hide
println("Color $i has $(length(color)) elements")#hide
end#hide

facecolors = zeros(size(conflicts, 1))#hide

for (i, color) in enumerate(colors)#hide
for element in color#hide
facecolors[element] = i#hide
for color in eachindex(colors)#hide
println("Color $color has $(length(colors[color])) elements")#hide
for element in colors[color]#hide
facecolors[element] = color#hide
end#hide
end #hide
end#hide

p = PlotlyJS.plot(#hide
patch(m, facecolors; showscale=false),#hide
Expand Down
38 changes: 38 additions & 0 deletions ext/GraphsColoringGraphs.jl
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ using GraphsColoring
using Graphs

import GraphsColoring: conflictgraph, conflictmatrix, _neighbors, _numelements, noconflicts
import GraphsColoring: numcolors, colors

# creates conflict graph as SimpleGraph from Graphs.jl (https://github.com/JuliaGraphs/Graphs.jl)
# from conflictmatrix
Expand Down Expand Up @@ -93,4 +94,41 @@ function noconflicts(g::AbstractGraph)
return iszero(ne(g))
end

function numcolors(c::Graphs.Coloring)
return c.num_colors
end

function colors(c::Graphs.Coloring)
return c.colors
end

function (::GraphsColoring.GraphsColors)(maxcolor, colors, elements)
return Graphs.Coloring(maxcolor, colors)
end
function (::GraphsColoring.GraphsColors)(colors)
numcolors, colors = _groupedcolorstographcoloring(colors)
return Graphs.Coloring(numcolors, colors)
end

function _groupedcolorstographcoloring(colors)
newcolors = zeros(eltype(eltype(colors)), sum(length, colors))
for (i, color) in enumerate(colors)
newcolors[color] .= i
end
return length(colors), newcolors
end

function Base.convert(::Type{<:Graphs.Coloring}, colors::GraphsColoring.GroupedColoring)
numcolors, colors = _groupedcolorstographcoloring(GraphsColoring.colors(colors))
return Graphs.Coloring(numcolors, colors)
end

function Base.eachindex(c::Graphs.Coloring)
return Base.OneTo(numcolors(c))
end

function Base.getindex(c::Graphs.Coloring, color)
return findall(isequal(color), colors(c))
end

end # module GraphsColoringGraphs
8 changes: 5 additions & 3 deletions src/GraphsColoring.jl
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ function conflicts end
"""
function conflictgraph end

include("storage.jl")
include("conflicts.jl")
include("greedy.jl")
include("dsatur.jl")
Expand All @@ -34,11 +35,12 @@ not have any conflicts.

- A `Vector{Vector{Int}}` where each inner `Vector` represents the elements of one color.
"""
function color(conflicts; algorithm=Workstream(DSATUR()))
return color(conflicts, algorithm)
function color(conflicts; algorithm=Workstream(DSATUR()), storage=GroupedColors())
return color(conflicts, algorithm, storage)
end

export color, WorkstreamDSATUR, WorkstreamGreedy, Workstream, DSATUR, Greedy
export numcolors,
colors, color, WorkstreamDSATUR, WorkstreamGreedy, Workstream, DSATUR, Greedy
export PassThroughConflictFunctor

if !isdefined(Base, :get_extension)
Expand Down
8 changes: 4 additions & 4 deletions src/color.jl
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@ The colors are sorted such that the number of their members decrease.

This function implements a generic coloring workflow that can be used with different algorithms, such as DSATUR and Greedy.
"""
function color(conflicts, algorithm, elements=1:_numelements(conflicts))
function color(
conflicts, algorithm, storage=GroupedColorConst, elements=1:_numelements(conflicts)
)
elementtoelementid = Dict{Int,Int}(zip(elements, eachindex(elements)))

maxcolor = 1
Expand Down Expand Up @@ -75,7 +77,5 @@ function color(conflicts, algorithm, elements=1:_numelements(conflicts))
end
end

colors = Vector{Int}[elements[findall(isequal(color), colors)] for color in 1:maxcolor]
sort!(colors; by=length, rev=true)
return colors
return storage(maxcolor, colors, elements)
end
115 changes: 115 additions & 0 deletions src/storage.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
"""
GroupedColors

A trait that indicates that a coloring operation should return results as a `GroupedColoring`.
"""
struct GroupedColors end
const GroupedColorConst = GroupedColors()
function (::GroupedColors)(maxcolor, colors, elements)
colors = Vector{Int}[elements[findall(isequal(color), colors)] for color in 1:maxcolor]
return GroupedColoring(colors)
end
function (::GroupedColors)(colors)
return GroupedColoring(colors)
end

"""
GroupedColors

A trait that indicates that a coloring operation should return results as a `Graphs.Coloring`.
"""
struct GraphsColors end
const GraphColorsConst = GraphsColors()

"""
GroupedColoring{I}

A data structure that represents a coloring of elements as a vector of vectors, where each
inner vector contains the indices of elements assigned to a particular color.

This representation is optimized for efficiently retrieving all elements belonging to a
specific color group, making it ideal for operations that frequently access elements by color.

# Type Parameters

- `I`: The integer type used to represent element indices (e.g., `Int`, `Int64`, `UInt32`).

# Fields

- `colors`: A vector of vectors, where `colors[i]` contains the indices of all elements assigned
to color `i`. The vector is sorted by group size in descending order (largest groups first)
for consistency.

# Notes

The constructor automatically sorts the color groups by size in descending order using `sort!`
with `by=length, rev=true`.
"""
struct GroupedColoring{I}
colors::Vector{Vector{I}}
function GroupedColoring(colors)
return new{eltype(eltype(colors))}(sort!(colors; by=length, rev=true))
end
end

"""
numcolors(c)

Return the number of distinct colors used in the coloring.

# Arguments

- `c`: A coloring object representing a coloring of a graph or similar structure,
where elements are grouped by color.

# Returns

- An integer representing the number of distinct colors used in the coloring.
"""
function numcolors(c::GroupedColoring)
return length(colors(c))
end

function colors(c::GroupedColoring)
return c.colors
end

"""
Base.eachindex(c::Union{GroupedColoring,Graphs.Coloring})

Return an iterator over the indices of the color groups in `c`.

# Arguments

- `c`: An object representing a coloring.

# Returns

- An iterator over the indices of the color groups (typically `1:numcolors(c))`).

# Notes

This method implements the `eachindex` interface for `GroupedColoring` and `Graphs.Coloring`, making it compatible
with Julia's standard iteration patterns.
"""
function Base.eachindex(c::GroupedColoring)
return Base.eachindex(colors(c))
end

"""
Base.getindex(c::Union{GroupedColoring,Graphs.Coloring}, color)

Return the i-th color group from the coloring object `c`.

# Arguments

- `c`: An object representing a coloring.
- `color`: An integer index specifying which color group to retrieve (must be within valid bounds).

# Returns

- The i-th color group (typically a vector of elements assigned to that color).
"""
function Base.getindex(c::GroupedColoring, i)
return Base.getindex(colors(c), i)
end
Loading
Loading