-
Notifications
You must be signed in to change notification settings - Fork 2
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
add lazy compute operations #25
base: dev
Are you sure you want to change the base?
Changes from 11 commits
a0a17ea
cda2fd9
2faf11a
5043bc4
a783626
9fbbb8e
1ca659f
294fabc
1f45f1a
cc9dbe0
d8232b8
05d965b
9117ff6
850c170
c1d52af
9d44267
89bca5d
ecbfe08
14d2e00
5bb180d
aaf300a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Since you are refactoring this, it would make sense to already think of #29. Maybe add a field |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,4 @@ | ||
|
||
struct GridRSP | ||
g::Grid | ||
θ::Float64 | ||
|
@@ -12,7 +13,6 @@ end | |
Construct a GridRSP from a `g::Grid` based on the inverse temperature parameter `θ::Real`. | ||
""" | ||
function GridRSP(g::Grid; θ=nothing) | ||
|
||
Pref = _Pref(g.affinities) | ||
W = _W(Pref, θ, g.costmatrix) | ||
|
||
|
@@ -48,9 +48,19 @@ function Base.show(io::IO, ::MIME"text/html", grsp::GridRSP) | |
write(io, "<h4>$t</h4>") | ||
show(io, MIME"text/html"(), plot_outdegrees(grsp.g)) | ||
end | ||
|
||
DimensionalData.dims(grsp::GridRSP) = dims(grsp.g) | ||
|
||
abstract type AbstractOperation end | ||
abstract type RSPOperation <: AbstractOperation end | ||
|
||
function keywords(o::T) where T<:AbstractOperation | ||
vals = map(f -> getfield(o, f), fieldnames(T)) | ||
return NamedTuple{fieldnames(T)}(vals) | ||
end | ||
|
||
struct BetweennessQweighted <: RSPOperation end | ||
|
||
compute(r::BetweennessQweighted, grsp::GridRSP) = betweenness_qweighted(grsp) | ||
|
||
""" | ||
betweenness_qweighted(grsp::GridRSP)::Matrix{Float64} | ||
|
@@ -76,7 +86,8 @@ function betweenness_qweighted(grsp::GridRSP) | |
return _maybe_raster(bet, grsp) | ||
end | ||
|
||
|
||
struct EdgeBetweennessQweighted <: RSPOperation end | ||
compute(r::EdgeBetweennessQweighted, grsp::GridRSP) = edge_betweenness_qweighted(grsp) | ||
|
||
""" | ||
edge_betweenness_qweighted(grsp::GridRSP)::Matrix{Float64} | ||
|
@@ -98,6 +109,14 @@ function edge_betweenness_qweighted(grsp::GridRSP) | |
return betmatrix | ||
end | ||
|
||
@kwdef struct BetweennessKweighted{CV,DT,DV} <: RSPOperation | ||
connectivity_function::CV=expected_cost | ||
distance_transformation::DT=nothing | ||
diagvalue::DV=nothing | ||
end | ||
|
||
compute(o::BetweennessKweighted, grsp::GridRSP) = | ||
betweenness_kweighted(grsp; keywords(o)...) | ||
|
||
""" | ||
betweenness_kweighted(grsp::GridRSP; | ||
|
@@ -153,7 +172,13 @@ function betweenness_kweighted(grsp::GridRSP; | |
return _maybe_raster(bet, grsp) | ||
end | ||
|
||
@kwdef struct EdgeBetweennessK{CV,DT,DV} <: RSPOperation | ||
distance_transformation::DT=inv(grsp.g.costfunction) | ||
diagvalue::DV=nothing | ||
end | ||
|
||
|
||
compute(r::EdgeBetweennessK, grsp::GridRSP) = edge_betweenness_kweighted(grsp; keywords(r)...) | ||
|
||
""" | ||
edge_betweenness_kweighted(grsp::GridRSP; [distance_transformation=inv(grsp.g.costfunction), diagvalue=nothing])::SparseMatrixCSC{Float64,Int} | ||
|
@@ -189,6 +214,9 @@ function edge_betweenness_kweighted(grsp::GridRSP; distance_transformation=inv(g | |
end | ||
|
||
|
||
struct ExpectedCost <: RSPOperation end | ||
|
||
compute(r::ExpectedCost, grsp::GridRSP) = expected_cost(grsp) | ||
|
||
""" | ||
expected_cost(grsp::GridRSP)::Matrix{Float64} | ||
|
@@ -200,23 +228,48 @@ function expected_cost(grsp::GridRSP) | |
return RSP_expected_cost(grsp.W, grsp.g.costmatrix, grsp.Z, targetnodes) | ||
end | ||
|
||
|
||
struct FreeDnergyDistance <: RSPOperation end | ||
|
||
compute(r::FreeDnergyDistance, grsp::GridRSP) = free_energy_distance(grsp) | ||
|
||
function free_energy_distance(grsp::GridRSP) | ||
targetidx, targetnodes = _targetidx_and_nodes(grsp.g) | ||
return RSP_free_energy_distance(grsp.Z, grsp.θ, targetnodes) | ||
|
||
end | ||
|
||
struct SurvivalProbability <: RSPOperation end | ||
|
||
compute(r::SurvivalProbability, grsp::GridRSP) = survival_probability(grsp) | ||
|
||
function survival_probability(grsp::GridRSP) | ||
targetidx, targetnodes = _targetidx_and_nodes(grsp.g) | ||
|
||
return RSP_survival_probability(grsp.Z, grsp.θ, targetnodes) | ||
end | ||
|
||
struct PowerMeanProximity <: RSPOperation end | ||
|
||
compute(r::PowerMeanProximity, grsp::GridRSP) = power_mean_proximity(grsp) | ||
|
||
function power_mean_proximity(grsp::GridRSP) | ||
|
||
targetidx, targetnodes = _targetidx_and_nodes(grsp.g) | ||
return RSP_power_mean_proximity(grsp.Z, grsp.θ, targetnodes) | ||
end | ||
|
||
struct LeastCostDistance <: RSPOperation end | ||
|
||
|
||
compute(r::LeastCostDistance, grsp::GridRSP) = least_cost_distance(grsp) | ||
|
||
least_cost_distance(grsp::GridRSP) = least_cost_distance(grsp.g) | ||
|
||
struct MeanKullbackLeiblerDivergence <: RSPOperation end | ||
|
||
compute(r::MeanKullbackLeiblerDivergence, grsp::GridRSP) = mean_kl_divergence(grsp) | ||
|
||
""" | ||
mean_kl_divergence(grsp::GridRSP)::Float64 | ||
|
||
|
@@ -229,6 +282,10 @@ function mean_kl_divergence(grsp::GridRSP) | |
return qs'*(RSP_free_energy_distance(grsp.Z, grsp.θ, targetnodes) - expected_cost(grsp))*qt*grsp.θ | ||
end | ||
|
||
struct MeanLeastCostKullbackLeiblerDivergence <: RSPOperation end | ||
|
||
compute(r::MeanLeastCostKullbackLeiblerDivergence, grsp::GridRSP) = mean_kl_divergence(grsp) | ||
|
||
|
||
""" | ||
mean_lc_kl_divergence(grsp::GridRSP)::Float64 | ||
|
@@ -281,12 +338,20 @@ function least_cost_kl_divergence(C::SparseMatrixCSC, Pref::SparseMatrixCSC, tar | |
# Pointer swap | ||
tmp = from | ||
from = to | ||
|
||
to = tmp | ||
end | ||
|
||
return kl_div | ||
end | ||
|
||
@kwdef struct LeastCostKullbackLeiblerDivergence <: RSPOperation | ||
target::Tuple{Int,Int} | ||
end | ||
|
||
compute(r::LeastCostKullbackLeiblerDivergence, grsp::GridRSP) = | ||
least_cost_kl_divergence(grsp, r.target) | ||
|
||
""" | ||
least_cost_kl_divergence(grsp::GridRSP, target::Tuple{Int,Int}) | ||
|
||
|
@@ -305,6 +370,18 @@ function least_cost_kl_divergence(grsp::GridRSP, target::Tuple{Int,Int}) | |
return reshape(div, grsp.g.nrows, grsp.g.ncols) | ||
end | ||
|
||
|
||
@kwdef struct ConnectedHabitat{CV,DT,DV} <: RSPOperation | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think that this could be better abstracted - the "equivalent connected habitat" metrics extends beyond the RSP framework. The calculation of connected habitat is simply It would be nice to have a structure like More generally, a distance object should be provided to the This reflection brings me to a second point: the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes GridRSP is pretty much hidden now in this PR. You call I'm working towards preallocating the whole problem up front like LinearSolve does but most of the code is unfortunately not written in that style. The first step will be to separate out non-allocating There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Also good point about using more appropriate abstractions. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Had a good discussion with @ninbrm about refactoring distances and fixing the abstract type structure to better represent the range of problems. Theta really doesn't need to be a parameter but the fact that distance functions are curreently used like functions rather than constructed objects currently makes it awkward to put parameters in them. So we should change them to be types like you describe. I'll implement this new abstract type hierarchy in the next iteration of this PR and we can discuss from there There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Great, looking forward to that! There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ok the new abstractions are kind of implemented now :) It works in the landmarks.jmd example at least, but needs some more polish and thought. Eventually we can refactor some of the complexity away but for now Im trying to build it on top of the current methods without changing them too much, so the old tests still run and we can use them to check the new methods. |
||
# TODO not sure which kw to use here | ||
connectivity_function::CV=expected_cost | ||
distance_transformation::DT=nothing | ||
diagvalue::DV=nothing | ||
θ::Union{Nothing,Real}=nothing | ||
approx::Bool=false | ||
end | ||
|
||
compute(r::ConnectedHabitat, grsp::GridRSP) = connected_habitat(grsp; keywords(r)...) | ||
|
||
""" | ||
connected_habitat(grsp::Union{Grid,GridRSP}; | ||
connectivity_function=expected_cost, | ||
|
@@ -436,9 +513,19 @@ function connected_habitat(grsp::GridRSP, | |
|
||
newh = GridRSP(newg, θ=grsp.θ) | ||
|
||
|
||
return connected_habitat(newh; diagvalue=diagvalue, distance_transformation=distance_transformation) | ||
end | ||
|
||
@kwdef struct EigMax{F,DT,DV,T} <: RSPOperation | ||
connectivity_function::F=expected_cost | ||
Tdistance_transformation::DT=nothing | ||
diagvalue::DV=nothing | ||
tol::T=1e-14 | ||
end | ||
|
||
compute(r::EigMax, grsp::GridRSP) = eigmax(grsp; keywords(r)...) | ||
|
||
""" | ||
eigmax(grsp::GridRSP; | ||
connectivity_function=expected_cost, | ||
|
@@ -564,6 +651,16 @@ function LinearAlgebra.eigmax(grsp::GridRSP; | |
return vˡ, λ₀[1], vʳ | ||
end | ||
|
||
@kwdef struct Criticality{DT,DV,AV,QT,QS} <: RSPOperation | ||
distance_transformation::DT=inv(grsp.g.costfunction) | ||
diagvalue::DV=nothing | ||
avalue::AV=floatmin() | ||
qˢvalue::QS=0.0 | ||
qᵗvalue::QT=0.0 | ||
end | ||
|
||
compute(r::Criticality, grsp::GridRSP) = criticality(grsp; keywords(r)...) | ||
|
||
""" | ||
criticality(grsp::GridRSP[; | ||
distance_transformation=inv(grsp.g.costfunction), | ||
|
@@ -605,3 +702,4 @@ function criticality(grsp::GridRSP; | |
|
||
return _maybe_raster(landscape, grsp) | ||
end | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would argue that memory use and flops is also related to the
prob::Problem
. It could be easy to assess the expected number of flops inVectorSolve()
where we can do the calculation for one node and multiply by the number of targets, but it may be more difficult for aMatrixSolve()
without performing the operation.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes makes sense, memory can just be checked by running one column.
Flops may need us to get some values I'm not sure we have access to (but e.g. UMFPACK dose track flops internally).