Script pour obtenir une animation de la toile de confiance duniter. [dépôt archivé] le code a été intégré à DataJune (https://git.42l.fr/HugoTrentesaux/DataJune.jl)
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.
This repo is archived. You can view files and clone it, but cannot push or open issues/pull-requests.
 
 
 

123 lines
5.7 KiB

# utility struct for web of trust
module WotUtils
using LightGraphs
using Statistics
using TOML, JLD2
using Colors
# """struct used to manage wot along all history"""
mutable struct WotState
# global information
folder::String # root folder to look into
N::Int # total all-time number of nodes
all_fixed::Vector{Bool} # fixed nodes are true
all_indegrees::Vector{Int} # indegrees
all_communities::Vector{Int} # communities (represented by color)
all_colors::Vector{RGB} # all colors (one color per node, but less are used)
all_locs::Array{Float64} # x,y locations of nodes
all_disp::Array{Float64} # current displacement
all_prev_disp::Array{Float64} # previous displacements
all_pseudo::Vector{String} # array of pseudo of size N
intervals::StepRange{Int64,Int64} # range of time intervals beginnings in unix seconds
active::Array{Bool} # npseudo × nstep boolean array of id activity
# information about current state
interval::Int # index of the current interval
g::SimpleDiGraph # current directed graph to plot
ug::SimpleGraph # undirected equivalent of this graph
mass::Vector{Float64} # mass of the nodes of g
charge::Vector{Float64} # charge of the nodes of g
mapping::Vector{Int} # mapping to the 1:N region
n::Int # size of the current graph
fixed::SubArray # view over all_fixed
indegrees::SubArray # view over indegrees of the nodes of g
communities::SubArray # view over all_communities
colors::SubArray # view over all_colors
locs::SubArray # view over all_locs
disp::SubArray # view over all_disp
prev_disp::SubArray # view over all_prev_disp
pseudo::SubArray # view over all_pseudo
end
function WotState(folder::String)::WotState # constructor
"""load wotsate from a folder"""
pseudo = readlines(joinpath(folder,"pseudo")) # load all pseudo
info = TOML.parsefile(joinpath(folder,"info")) # load some info
@load joinpath(folder,"active") active_nodes # load activity status
N = size(pseudo,1)
wotstate = WotState(
folder,
N,
falses(N), # all_fixed
zeros(Int,N), # all_indegrees
collect(1:N), # all_communities
rand(RGB, N), # TODO improve color choice
zeros(2,N), # all_locs
zeros(2,N), # all_disp
zeros(2,N), # all_prev_disp
pseudo, # all pseudo
info["start"] : info["step"] : info["start"]+info["step"]*(info["nstep"]-1), # all time intervals
active_nodes, # actives
0, # current interval index (not defined)
SimpleDiGraph(0), # current directed graph
SimpleGraph(0), # current undirected graph
[], # mass
[], # charge
[], # mapping
0, # size of the current graph
view(falses(1),1,1), # fixed
view(zeros(Int,1),1,1), # indegrees
view(zeros(Int,1),1,1), # communities
view([colorant"blue"],1,1), # colors
view(zeros(1),1,1), # locs
view(zeros(1),1,1), # disp
view(zeros(1),1,1), # prev_disp
view(pseudo,1), # pseudo
)
set_current_interval!(wotstate, 1) # initialize to first interval
return wotstate
end
function set_current_interval!(state::WotState, i_num::Int)
"""update state to match current interval"""
# update graph
state.interval = i_num # set current interval number
state.g = loadgraph(joinpath(state.folder, "cert.lg", lpad(string(state.interval),4,'0')*".lg")) # load graph (will be modified)
state.mapping = rem_vertices!(state.g, findall(.!state.active[:,state.interval])) # remove inactive nodes and update mapping
# update views
state.fixed = view(state.all_fixed, state.mapping)
state.indegrees = view(state.all_indegrees, state.mapping)
state.communities = view(state.all_communities, state.mapping)
state.colors = view(state.all_colors, state.all_communities[state.mapping])
state.locs = view(state.all_locs, :, state.mapping)
state.disp = view(state.all_disp, :, state.mapping)
state.prev_disp = view(state.all_prev_disp, :, state.mapping)
state.pseudo = view(state.all_pseudo, state.mapping)
# update variables
state.indegrees .= indegree(state.g) # update degrees
state.fixed .= state.indegrees .<1 # fix point without link to avoid it getting too far
state.charge = Array{Float64}(state.indegrees .>=5) # not well connected points get a null charge (they do not repulse), other get a unit charge
state.indegrees[findall(state.indegrees .< 5)] .= 5 # nodes whose certifiers are gone can have indregree <5 → set to 5 (inexact)
state.mass = Array{Float64}(state.indegrees) # update mass
state.n = nv(state.g) # update n
state.ug = SimpleGraph(state.g) # update undirected equivalent
# place new nodes at barycenter of their certifiers (does not work for first interval)
if state.interval != 1
newnodes = state.active[:,state.interval] .& .!state.active[:,state.interval-1]
for newcomer in findall(newnodes)
newc = findfirst(isequal(newcomer), state.mapping) # local index (pseudo[newc] == all_pseudo[newcomer])
certifiers_locs = state.locs[:,inneighbors(state.g, newc)]
if isempty(certifiers_locs) # if certifiers of node have disappeared
println("\nwarning: no certifiers for node $(newcomer) at step $(state.interval)")
certifiers_locs = state.locs[:,newc] # take self location
end
state.locs[:,newc] = mean(certifiers_locs, dims=2)
end
end
end
end