Utilitaire pour indexer des informations de la blockchain et dessiner des Plots. Focalisé sur la toile de confiance. http://datajune.coinduf.eu/
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

136 lines
4.8 KiB

module WotHistory
export WotSnapshot
using ..Config
using LightGraphs, Statistics, Serialization
"struct representing a snapshot of the wot"
mutable struct WotSnapshot
# global information
N::Int # total all-time number of nodes
intervals::StepRange{Int64,Int64} # range of time intervals beginnings in unix seconds
all_active::BitMatrix # N × nstep boolean array of id activity (ismember)
active::SubArray # all_active but only for current interval
# information about current state
interval::Int # index of the current interval
g::SimpleDiGraph # current directed graph
# observables
members::Int # number of active members
was_member::Int # number of total id member once
referent::BitVector # true if the node i is referent
referent_neighborhood::Matrix{Int} # N × 5 matrix of number of referent in the 1:5 neighborhood
centrality::Vector{Float64} # betweenness centrality
end
"""
WotSnapshot constructor
loads wotsate from a folder and set the state to first step
this struct will be mutated afterwards
"""
function WotSnapshot()::WotSnapshot # constructor
info = deserialize(joinpath(CACHE_PATH,"info.jls")) # load some info
active_nodes = deserialize(joinpath(CACHE_PATH,"active.jls")) # load activity status
N = info["npseudo"]
# initialize fields
wotsnapshot = WotSnapshot(
N,
info["start"] : info["step"] : info["stop"], # all time intervals
active_nodes, # all_actives
view(active_nodes,:,1), # active
0, # current interval index (not defined)
SimpleDiGraph(0), # current directed graph
0, # members
0, # was_member
falses(N), # referent
zeros(Int, N, 5), # referent_neighborhood
zeros(N), # centrality
)
set_current_interval!(wotsnapshot, 1) # initialize to first interval
return wotsnapshot
end
"""
update state to match current interval
this does mutate the states to avoid too many allocations
"""
function set_current_interval!(state::WotSnapshot, i_num::Int)
# update graph
state.interval = i_num # set current interval number
state.g = loadgraph(joinpath(LG_PATH, lpad(string(state.interval),4,'0')*".lg")) # load graph
state.active = view(state.all_active, :, state.interval) # update view
# update observables
state.members = sum(state.active) # update number of active members
state.was_member = findlast(state.active) # update number of total id that was member
do_computations!(state)
return nothing
end
"perform some computation on state"
function do_computations!(state::WotSnapshot)
referent!(state) # update referent status
referent_neighborhood!(state) # update number of referent in 1:5 neighborhood
# state.centrality = betweenness_centrality(state.g, normalize=false) ./ state.members # betweenness_centrality
end
"show"
function Base.show(io::IO, w::WotSnapshot)
print(io, "$(typeof(w)) ($(w.interval) / $(length(w)))")
end
"""
referent!(s)
sets the referent status inside s
"""
function referent!(s::WotSnapshot)
mindeg = Int(ceil(s.members^0.2)) # minimum degrees to be referent
for i in 1:s.was_member
s.referent[i] = (outdegree(s.g, i) >= mindeg && indegree(s.g, i) >= mindeg) # true if and only if requirement is met
end
end
"""
referent_neighborhood!(s)
sets the number of referents in 1:5 neighborhood
requires the referent field of the struct to be up-to-date
"""
function referent_neighborhood!(s::WotSnapshot)
distances = zeros(s.N) # initialize distance vector
invg = reverse(s.g) # reverse edge direction
for i in 1:s.N
if s.active[i] # only if node is active (others are skipped and will remain zero)
gdistances!(invg, i, distances) # compute geodesic distances
for k in 1:5 # for each distance
# this sum counts the number of active referent members inside the k_neighborhood of node i
s.referent_neighborhood[i,k] = sum(
((distances .<= k) .& (distances .> 0)) .* # true for non-null distances smaller than k (from 1 to k)
s.active[:] .* # only true for members, not for inactive nodes
s.referent # only true for referent memebrs
)
end
end
end
end
# iteration interface. is it useful?
Base.size(w::WotSnapshot) = (length(w.intervals), )
Base.length(w::WotSnapshot) = size(w)[1]
function Base.getindex(w::WotSnapshot, i::Int)
set_current_interval!(w, i)
return w
end
Base.iterate(w::WotSnapshot) = (w, nothing)
function Base.iterate(w::WotSnapshot, state)
if w.interval < length(w)
set_current_interval!(w, w.interval+1)
return (w, nothing)
else
return nothing
end
end
end