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

Fix terrible performance with custom filtrations #171

Merged
merged 16 commits into from
Jun 4, 2024
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
# v0.16.13

Fix performance issues with high-dimensional `Custom` filtrations.

# v0.16.9

Replace LightGraps with Graphs.
Expand Down
12 changes: 10 additions & 2 deletions Project.toml
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
name = "Ripserer"
uuid = "aa79e827-bd0b-42a8-9f10-2b302677a641"
authors = ["mtsch <[email protected]>"]
version = "0.16.12"
version = "0.16.13"

[deps]
Compat = "34da2185-b29b-5c13-b0c7-acf172513d20"
DataStructures = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8"
Distances = "b4f34e82-e78d-54a5-968a-f98e89d6e8f7"
Future = "9fa8497b-333b-5362-9e8d-4d0656e87820"
Graphs = "86223c79-3864-5bf0-83f7-82e725a168b6"
IterTools = "c8e1da08-722c-5040-9ed9-7db0dc04731e"
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
Expand All @@ -21,17 +20,26 @@ StaticArrays = "90137ffa-7385-5640-81b9-e52037218182"
TupleTools = "9d95972d-f1c8-5527-a6e0-b4b365fa01f6"

[compat]
Aqua = "0.8"
Compat = "^3.10, 4"
DataStructures = "0.17, 0.18"
Distances = "0.8, 0.9, 0.10"
Documenter = "1"
Graphs = "1"
IterTools = "1"
LinearAlgebra = "1"
MLJBase = "1"
MLJModelInterface = "^0.3.5, 0.4, 1"
MiniQhull = "0.2, 0.3, 0.4"
PersistenceDiagrams = "0.9"
ProgressMeter = "1"
Random = "1"
RecipesBase = "1"
SafeTestsets = "0.1"
SparseArrays = "1"
StaticArrays = "0.12, 1"
Suppressor = "0.2"
Test = "1"
TupleTools = "1"
julia = "1.6"

Expand Down
8 changes: 2 additions & 6 deletions docs/make.jl
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,8 @@ makedocs(;
"Home" => "index.md",
"Usage Guide" => "generated/basics.md",
"API" => "api.md",
"Examples" => [
"generated/stability.md",
"generated/cocycles.md",
"generated/cubical.md",
"generated/malaria.md",
],
"Examples" =>
["generated/stability.md", "generated/cocycles.md", "generated/cubical.md"],
"Benchmarks" => "benchmarks.md",
"Related Julia Packages" => "related-work.md",
"Acknowledgements and References" => "references.md",
Expand Down
213 changes: 0 additions & 213 deletions docs/src/examples/malaria.jl

This file was deleted.

5 changes: 2 additions & 3 deletions src/base/abstractcell.jl
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,8 @@ is determined by the following.
* The `birth` of type `T` determines when the cell enters the filtration. Note that two
cells with the same `index` should also have the same `birth`.

* `vertices` should return the cell's vertices as a tuple. For 0-cells (vertices), the
`vertices` are also used to index into a filtration's
[`vertices`](vertices(::AbstractFiltration)).
* `vertices` should return the cell's vertices as a tuple. For 0-cells, these are also used
to index into a filtration's [`vertices`](@ref vertices(::AbstractFiltration)).

* The `sign` determens its orientation. Note that `cell == -cell`.

Expand Down
5 changes: 1 addition & 4 deletions src/base/abstractfiltration.jl
Original file line number Diff line number Diff line change
Expand Up @@ -162,10 +162,7 @@ julia> vertices(Rips([0 1 1; 1 0 1; 1 1 0]))
Base.OneTo(3)

julia> vertices(Cubical([0 1 1; 1 0 1; 1 1 0]))
3×3 CartesianIndices{2, Tuple{Base.OneTo{Int64}, Base.OneTo{Int64}}}:
CartesianIndex(1, 1) CartesianIndex(1, 2) CartesianIndex(1, 3)
CartesianIndex(2, 1) CartesianIndex(2, 2) CartesianIndex(2, 3)
CartesianIndex(3, 1) CartesianIndex(3, 2) CartesianIndex(3, 3)
CartesianIndices((3, 3))

```
"""
Expand Down
6 changes: 5 additions & 1 deletion src/base/abstractsimplex.jl
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,11 @@ Use binary search to find index of first vertex in `(K - 1)`-dimensional simplex
"""
function _first_vertex(index::I, ::Val{K}) where {I,K}
lo = I(K - 1)
hi = I(K + 100)
if K < 3
hi = I(K + 100)
else
hi = I(K)
end
while _binomial(hi, Val(K)) ≤ index
lo = hi
hi <<= 0x01
Expand Down
2 changes: 1 addition & 1 deletion src/base/chain.jl
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ julia> data = [(rand(), rand(), rand()) for _ in 1:100];
julia> result = ripserer(data; reps=true, modulus=7);

julia> chain = result[end][end].representative
28-element Chain{Ripserer.Mod{7},Ripserer.Simplex{1, Float64, Int64}}:
28-element Chain{Mod{7},Simplex{1, Float64, Int64}}:
+Simplex{1}((68, 54), 0.25178097927369875) => 6 mod 7
+Simplex{1}((54, 46), 0.2575262844682746) => 1 mod 7
+Simplex{1}((88, 56), 0.25936896586973557) => 1 mod 7
Expand Down
7 changes: 6 additions & 1 deletion src/base/primefield.jl
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,12 @@ is_prime(::Any) = false
Like `mod`, but with prime `M`.
"""
function mod_prime(i, ::Val{M}) where {M}
is_prime(M) || throw(DomainError(M, "modulus must be a prime number"))
if !is_prime(M)
throw(DomainError(M, "modulus must be a prime number"))
end
if !(1 < M ≤ 3037000499)
throw(DomainError(M, "modulus must be smaller than √(typemax(Int))"))
end
i = i % M
return i + ifelse(signbit(i), M, 0)
end
Expand Down
2 changes: 1 addition & 1 deletion src/extra/circularcoordinates.jl
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,7 @@ CircularCoordinates(
radius=(0.9510565162951535,),
n_landmarks=10,
partition=linear,
metric=Distances.Euclidean(0.0),
metric=Euclidean(0.0),
)

julia> summary(cc(data))
Expand Down
8 changes: 4 additions & 4 deletions src/filtrations/alpha.jl
Original file line number Diff line number Diff line change
Expand Up @@ -180,13 +180,13 @@ julia> length(Ripserer.edges(rips))

julia> sort(ripserer(alpha)[2], by=persistence)[end]
[0.375, 2.01) with:
birth_simplex: Ripserer.Simplex{1, Float64, Int64}
death_simplex: Ripserer.Simplex{2, Float64, Int64}
birth_simplex: Simplex{1, Float64, Int64}
death_simplex: Simplex{2, Float64, Int64}

julia> sort(ripserer(rips)[2], by=persistence)[end]
[0.375, 2.01) with:
birth_simplex: Ripserer.Simplex{1, Float64, Int64}
death_simplex: Ripserer.Simplex{2, Float64, Int64}
birth_simplex: Simplex{1, Float64, Int64}
death_simplex: Simplex{2, Float64, Int64}
```
"""
struct Alpha{I,P<:SVector} <: AbstractCustomFiltration{I,Float64}
Expand Down
19 changes: 13 additions & 6 deletions src/filtrations/custom.jl
Original file line number Diff line number Diff line change
Expand Up @@ -100,8 +100,7 @@ struct Custom{I,T} <: AbstractCustomFiltration{I,T}
threshold::T
end

@inline insert_simplex!(::Vector{Dict{I,T}}, ::Tuple{}, _, _) where {I,T} = nothing
@inline function insert_simplex!(
function insert_simplex!(
dicts::Vector{Dict{I,T}}, vertices::NTuple{N,I}, birth, threshold
) where {N,T,I}
if birth > threshold
Expand All @@ -111,11 +110,19 @@ end
dim = N - 1
d_dict = dicts[dim + 1]
d_dict[idx] = min(birth, get(d_dict, idx, typemax(T)))
for vs in IterTools.subsets(vertices, Val(N - 1))
# Some extra work is being done here, but this tends to be type stable.
insert_simplex!(dicts, vs, birth, threshold)
end
_insert_simplex_facets!(dicts, vertices, birth, Val(N - 1))
end
end
@inline _insert_simplex_facets!(_, _, _, ::Val{0}) = nothing
@inline function _insert_simplex_facets!(dicts, vertices, birth, ::Val{N}) where {N}
dim = N - 1
d_dict = dicts[dim + 1]
T = valtype(d_dict)
for vs in IterTools.subsets(vertices, Val(N))
idx = index(vs)
d_dict[idx] = min(birth, get(d_dict, idx, typemax(T)))
end
return _insert_simplex_facets!(dicts, vertices, birth, Val(N - 1))
end

function _adjacency_matrix(dicts)
Expand Down
Loading
Loading