Skip to content

Commit d6b8cca

Browse files
committed
define storagetraits
1 parent 4ae0fae commit d6b8cca

File tree

13 files changed

+384
-87
lines changed

13 files changed

+384
-87
lines changed

docs/make.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ makedocs(;
6767
"DSatur" => "dsatur.md",
6868
"Workstream" => "workstream.md",
6969
],
70+
"Storing colors" => "storage.md",
7071
"Contributing" => "contributing.md",
7172
"API Reference" => "apiref.md",
7273
],

docs/src/dsatur.md

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -30,15 +30,12 @@ conflicts = GraphsColoring.conflictmatrix(X)
3030
3131
colors = GraphsColoring.color(conflicts; algorithm=DSATUR())
3232
33-
for (i, color) in enumerate(colors)
34-
println("Color $i has $(length(color)) elements")
35-
end
36-
3733
facecolors = zeros(size(conflicts, 1))
3834
39-
for (i, color) in enumerate(colors)
40-
for element in color
41-
facecolors[element] = i
35+
for color in eachindex(colors)
36+
println("Color $color has $(length(colors[color])) elements")
37+
for element in colors[color]
38+
facecolors[element] = color
4239
end
4340
end
4441

docs/src/greedy.md

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,15 +21,12 @@ conflicts = GraphsColoring.conflictmatrix(X)
2121
2222
colors = GraphsColoring.color(conflicts; algorithm=Greedy())
2323
24-
for (i, color) in enumerate(colors)
25-
println("Color $i has $(length(color)) elements")
26-
end
27-
2824
facecolors = zeros(size(conflicts, 1))
2925
30-
for (i, color) in enumerate(colors)
31-
for element in color
32-
facecolors[element] = i
26+
for color in eachindex(colors)
27+
println("Color $color has $(length(colors[color])) elements")
28+
for element in colors[color]
29+
facecolors[element] = color
3330
end
3431
end
3532

docs/src/storage.md

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
# Storing and Accessing Coloring Results
2+
3+
Coloring results in `GraphsColoring` can be stored in two primary formats:
4+
5+
## `GroupedColoring` (Default)
6+
7+
- **Storage**: Colors are stored as a vector of vectors, where each inner vector contains the indices of elements assigned to a specific color.
8+
- **Optimization**: Efficient retrieval of all elements belonging to a specific color group.
9+
- **Best for**: Operations that frequently access elements by color (e.g., processing color groups in parallel, analyzing group sizes, or visualizing color distributions).
10+
- **Default behavior**: This is the default storage format when no `storage` parameter is specified.
11+
12+
## `Graphs.Coloring`
13+
14+
- **Storage**: Colors are stored as a flat vector where `colors[i]` gives the color assigned to element `i`.
15+
- **Optimization**: Efficient access to the color of a specific element.
16+
- **Best for**: Operations that frequently query the color of individual elements.
17+
18+
---
19+
20+
## Usage Examples
21+
22+
### Using `GroupedColoring` (Default)
23+
24+
```@example
25+
using PlotlyJS#hide
26+
using CompScienceMeshes#hide
27+
using BEAST#hide
28+
using GraphsColoring#hide
29+
30+
m = meshsphere(1.0, 0.1)#hide
31+
X = raviartthomas(m)#hide
32+
33+
conflicts = GraphsColoring.conflictmatrix(X)#hide
34+
35+
colors = GraphsColoring.color(conflicts; storage=GraphsColoring.GroupedColors())
36+
```
37+
38+
### Using `Graphs.Coloring`
39+
40+
```@example
41+
using PlotlyJS#hide
42+
using CompScienceMeshes#hide
43+
using BEAST#hide
44+
using GraphsColoring#hide
45+
46+
m = meshsphere(1.0, 0.1)#hide
47+
X = raviartthomas(m)#hide
48+
49+
conflicts = GraphsColoring.conflictmatrix(X)#hide
50+
51+
colors = GraphsColoring.color(conflicts; storage=GraphsColoring.GraphsColors())
52+
```
53+
54+
---
55+
56+
## Accessing Coloring Results
57+
58+
Both storage formats support standard Julia interfaces:
59+
60+
| Operation | Description |
61+
|---------|-------------|
62+
| `numcolors(c)` | Returns the total number of distinct colors |
63+
| `eachindex(c)` | Iterates over color group indices (1-based) |
64+
| `c[i]` | Retrieves the i-th color group (as a vector of element indices) |
65+
| `length(c[i])` | Gets the number of elements in the i-th color group |
66+
67+
### Example: Accessing Colors
68+
69+
```@example
70+
using PlotlyJS#hide
71+
using CompScienceMeshes#hide
72+
using BEAST#hide
73+
using GraphsColoring#hide
74+
75+
m = meshsphere(1.0, 0.1)#hide
76+
X = raviartthomas(m)#hide
77+
78+
conflicts = GraphsColoring.conflictmatrix(X)#hide
79+
80+
colors = GraphsColoring.color(conflicts; algorithm=WorkstreamGreedy, storage=GraphsColoring.GraphsColors()) # hide
81+
82+
println("We have $(numcolors(colors))")
83+
for color in eachindex(colors)
84+
println("Color $color has $(length(colors[color])) elements. The members of color $color are $(colors[color])")
85+
end
86+
```
87+
88+
---
89+
90+
## Notes
91+
92+
- The default storage is `GroupedColoring` because it enables efficient group-based operations.
93+
- The `Graphs.Coloring` format is more efficient for very large problems when only individual element colors are needed.

docs/src/workstream.md

Lines changed: 9 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -44,15 +44,12 @@ conflicts = GraphsColoring.conflictmatrix(X)
4444
4545
colors = GraphsColoring.color(conflicts; algorithm=WorkstreamDSATUR)
4646
47-
for (i, color) in enumerate(colors)
48-
println("Color $i has $(length(color)) elements")
49-
end
50-
5147
facecolors = zeros(size(conflicts, 1))
5248
53-
for (i, color) in enumerate(colors)
54-
for element in color
55-
facecolors[element] = i
49+
for color in eachindex(colors)
50+
println("Color $color has $(length(colors[color])) elements")
51+
for element in colors[color]
52+
facecolors[element] = color
5653
end
5754
end
5855
@@ -92,17 +89,14 @@ conflicts = GraphsColoring.conflictmatrix(X)#hide
9289
9390
colors = GraphsColoring.color(conflicts; algorithm=WorkstreamGreedy)
9491
95-
for (i, color) in enumerate(colors)#hide
96-
println("Color $i has $(length(color)) elements")#hide
97-
end#hide
98-
9992
facecolors = zeros(size(conflicts, 1))#hide
10093
101-
for (i, color) in enumerate(colors)#hide
102-
for element in color#hide
103-
facecolors[element] = i#hide
94+
for color in eachindex(colors)#hide
95+
println("Color $color has $(length(colors[color])) elements")#hide
96+
for element in colors[color]#hide
97+
facecolors[element] = color#hide
10498
end#hide
105-
end #hide
99+
end#hide
106100
107101
p = PlotlyJS.plot(#hide
108102
patch(m, facecolors; showscale=false),#hide

ext/GraphsColoringGraphs.jl

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ using GraphsColoring
33
using Graphs
44

55
import GraphsColoring: conflictgraph, conflictmatrix, _neighbors, _numelements, noconflicts
6+
import GraphsColoring: numcolors, colors
67

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

97+
function numcolors(c::Graphs.Coloring)
98+
return c.num_colors
99+
end
100+
101+
function colors(c::Graphs.Coloring)
102+
return c.colors
103+
end
104+
105+
function (::GraphsColoring.GraphsColors)(maxcolor, colors, elements)
106+
return Graphs.Coloring(maxcolor, colors)
107+
end
108+
function (::GraphsColoring.GraphsColors)(colors)
109+
numcolors, colors = _groupedcolorstographcoloring(colors)
110+
return Graphs.Coloring(numcolors, colors)
111+
end
112+
113+
function _groupedcolorstographcoloring(colors)
114+
newcolors = zeros(eltype(eltype(colors)), sum(length, colors))
115+
for (i, color) in enumerate(colors)
116+
newcolors[color] .= i
117+
end
118+
return length(colors), newcolors
119+
end
120+
121+
function Base.convert(::Type{<:Graphs.Coloring}, colors::GraphsColoring.GroupedColoring)
122+
numcolors, colors = _groupedcolorstographcoloring(GraphsColoring.colors(colors))
123+
return Graphs.Coloring(numcolors, colors)
124+
end
125+
126+
function Base.eachindex(c::Graphs.Coloring)
127+
return Base.OneTo(numcolors(c))
128+
end
129+
130+
function Base.getindex(c::Graphs.Coloring, color)
131+
return findall(isequal(color), colors(c))
132+
end
133+
96134
end # module GraphsColoringGraphs

src/GraphsColoring.jl

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ function conflicts end
1313
"""
1414
function conflictgraph end
1515

16+
include("storage.jl")
1617
include("conflicts.jl")
1718
include("greedy.jl")
1819
include("dsatur.jl")
@@ -34,11 +35,12 @@ not have any conflicts.
3435
3536
- A `Vector{Vector{Int}}` where each inner `Vector` represents the elements of one color.
3637
"""
37-
function color(conflicts; algorithm=Workstream(DSATUR()))
38-
return color(conflicts, algorithm)
38+
function color(conflicts; algorithm=Workstream(DSATUR()), storage=GroupedColors())
39+
return color(conflicts, algorithm, storage)
3940
end
4041

41-
export color, WorkstreamDSATUR, WorkstreamGreedy, Workstream, DSATUR, Greedy
42+
export numcolors,
43+
colors, color, WorkstreamDSATUR, WorkstreamGreedy, Workstream, DSATUR, Greedy
4244
export PassThroughConflictFunctor
4345

4446
if !isdefined(Base, :get_extension)

src/color.jl

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,9 @@ The colors are sorted such that the number of their members decrease.
1717
1818
This function implements a generic coloring workflow that can be used with different algorithms, such as DSATUR and Greedy.
1919
"""
20-
function color(conflicts, algorithm, elements=1:_numelements(conflicts))
20+
function color(
21+
conflicts, algorithm, storage=GroupedColorConst, elements=1:_numelements(conflicts)
22+
)
2123
elementtoelementid = Dict{Int,Int}(zip(elements, eachindex(elements)))
2224

2325
maxcolor = 1
@@ -75,7 +77,5 @@ function color(conflicts, algorithm, elements=1:_numelements(conflicts))
7577
end
7678
end
7779

78-
colors = Vector{Int}[elements[findall(isequal(color), colors)] for color in 1:maxcolor]
79-
sort!(colors; by=length, rev=true)
80-
return colors
80+
return storage(maxcolor, colors, elements)
8181
end

src/storage.jl

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
"""
2+
GroupedColors
3+
4+
A trait that indicates that a coloring operation should return results as a `GroupedColoring`.
5+
"""
6+
struct GroupedColors end
7+
const GroupedColorConst = GroupedColors()
8+
function (::GroupedColors)(maxcolor, colors, elements)
9+
colors = Vector{Int}[elements[findall(isequal(color), colors)] for color in 1:maxcolor]
10+
return GroupedColoring(colors)
11+
end
12+
function (::GroupedColors)(colors)
13+
return GroupedColoring(colors)
14+
end
15+
16+
"""
17+
GroupedColors
18+
19+
A trait that indicates that a coloring operation should return results as a `Graphs.Coloring`.
20+
"""
21+
struct GraphsColors end
22+
const GraphColorsConst = GraphsColors()
23+
24+
"""
25+
GroupedColoring{I}
26+
27+
A data structure that represents a coloring of elements as a vector of vectors, where each
28+
inner vector contains the indices of elements assigned to a particular color.
29+
30+
This representation is optimized for efficiently retrieving all elements belonging to a
31+
specific color group, making it ideal for operations that frequently access elements by color.
32+
33+
# Type Parameters
34+
35+
- `I`: The integer type used to represent element indices (e.g., `Int`, `Int64`, `UInt32`).
36+
37+
# Fields
38+
39+
- `colors`: A vector of vectors, where `colors[i]` contains the indices of all elements assigned
40+
to color `i`. The vector is sorted by group size in descending order (largest groups first)
41+
for consistency.
42+
43+
# Notes
44+
45+
The constructor automatically sorts the color groups by size in descending order using `sort!`
46+
with `by=length, rev=true`.
47+
"""
48+
struct GroupedColoring{I}
49+
colors::Vector{Vector{I}}
50+
function GroupedColoring(colors)
51+
return new{eltype(eltype(colors))}(sort!(colors; by=length, rev=true))
52+
end
53+
end
54+
55+
"""
56+
numcolors(c)
57+
58+
Return the number of distinct colors used in the coloring.
59+
60+
# Arguments
61+
62+
- `c`: A coloring object representing a coloring of a graph or similar structure,
63+
where elements are grouped by color.
64+
65+
# Returns
66+
67+
- An integer representing the number of distinct colors used in the coloring.
68+
"""
69+
function numcolors(c::GroupedColoring)
70+
return length(colors(c))
71+
end
72+
73+
function colors(c::GroupedColoring)
74+
return c.colors
75+
end
76+
77+
"""
78+
Base.eachindex(c::Union{GroupedColoring,Graphs.Coloring})
79+
80+
Return an iterator over the indices of the color groups in `c`.
81+
82+
# Arguments
83+
84+
- `c`: An object representing a coloring.
85+
86+
# Returns
87+
88+
- An iterator over the indices of the color groups (typically `1:numcolors(c))`).
89+
90+
# Notes
91+
92+
This method implements the `eachindex` interface for `GroupedColoring` and `Graphs.Coloring`, making it compatible
93+
with Julia's standard iteration patterns.
94+
"""
95+
function Base.eachindex(c::GroupedColoring)
96+
return Base.eachindex(colors(c))
97+
end
98+
99+
"""
100+
Base.getindex(c::Union{GroupedColoring,Graphs.Coloring}, color)
101+
102+
Return the i-th color group from the coloring object `c`.
103+
104+
# Arguments
105+
106+
- `c`: An object representing a coloring.
107+
- `color`: An integer index specifying which color group to retrieve (must be within valid bounds).
108+
109+
# Returns
110+
111+
- The i-th color group (typically a vector of elements assigned to that color).
112+
"""
113+
function Base.getindex(c::GroupedColoring, i)
114+
return Base.getindex(colors(c), i)
115+
end

0 commit comments

Comments
 (0)