https://github.com/mstrauss/hotspots
Tip revision: da1858af13aadee03c9b4d395b6e612a0ee6963c authored by Markus Strauss on 08 March 2017, 13:15:52 UTC
insert published article information
insert published article information
Tip revision: da1858a
weights.m
function [ tess, unaccounted ] = weights( obj )
% Calculates weights as network length per mark.
% It does so, by iterating over all network edges and assigning to each
% mark accordingly.
% W..vector of weights
% unaccounted...total unaccounted network length
%
% NB: This function implements KIND-OF Voronoi Network tesselation.
% Differences: THIS METHOD WORKS WITH NON-SIMPLE NETWORK LAYOUTS, i.e.
% WE ALLOW FOR CRITICAL NODES.
% See 2012-Okabe/Sugihara-Spatial Analysis along Networks Statistical and
% Computational Methods, chap. 4.3.
% debugging?
dbg = false;
if dbg
obj.plot('debug',1);
end
unaccounted = 0;
% fetch the incidence matrix of the network
I = obj.net.graph.incidence;
% no of network edges
N = obj.net.numedges;
% initialize weights, indexed by ordering of sorted_edge_network
% (this is fixed at the end of the function)
%W = zeros( M, 1 );
% sorting the mark coordinates
[sorted_edge_network, original_mark_index] = sortrows(obj.edge_network);
% retrieve network metrics
V1 = obj.net.V1;
V2 = obj.net.V2;
L = obj.net.L;
% resulting tessellation, tuples of [edge_index edge_distance] representing
% network cell boundaries
tess = NetworkTessellation( obj.nummarks );
% we can discern btw. 2 types of network cells: shared and non-shared; the
% shared cells belong to more than one mark; the resulting assignments of
% marks to network cells are stored as tuples of [cell
if dbg; old_W_sum = 0; end
% loop over all edges
for edge = 1:N
if dbg; fprintf('Calculating for edge %d (L=%f):\n', edge, obj.net.L(edge) ); end
% n1: neighboring marks of start vertex
n1 = I( V1(edge), : );
n1(edge) = 0;
mark_distances_1 = zeros(nnz(n1),1);
mark_ids_1 = zeros(nnz(n1),1);
n1i = find(n1);
for j = 1:nnz(n1)
visited_edges = false(1,N);
visited_edges(edge) = true;
[mark_distances_1(j), mark_ids_1(j)] = mark_distance( n1i(j), V1(edge) );
%mark_distances_1(j) = obj.graph.Nodes.D(V1(i));
%mark_ids_1(j) = obj.graph.Nodes.T(V1(i));
end
% n2: neighboring marks of end vertex
n2 = I( V2(edge), : );
n2(edge) = 0;
mark_distances_2 = zeros(nnz(n2),1);
mark_ids_2 = zeros(nnz(n2),1);
n2i = find(n2);
for j = 1:nnz(n2)
visited_edges = false(1,N);
visited_edges(edge) = true;
[mark_distances_2(j), mark_ids_2(j)] = mark_distance( n2i(j), V2(edge) );
%mark_distances_2(j) = obj.graph.Nodes.D(V2(i));
%mark_ids_2(j) = obj.graph.Nodes.T(V2(i));
end
if dbg
fprintf( 'mark_distances_1: %f\n', mark_distances_1 );
fprintf( 'mark_ids_1: %d\n', mark_ids_1 );
fprintf( 'mark_distances_2: %f\n', mark_distances_2 );
fprintf( 'mark_ids_2: %d\n', mark_ids_2 );
fprintf( '----\n' );
end
% marks on currently enumerated edge
marks_on_edge_index = sorted_edge_network(:,1) == edge;
no_of_marks_on_edge = nnz(marks_on_edge_index);
mark_distances = sorted_edge_network(marks_on_edge_index,2);
assert( all( mark_distances < L(edge) ) );
marks_in_edge_network = find(marks_on_edge_index);
if no_of_marks_on_edge > 0
% assign start part weights to marks
assignable_length = mark_distances(1);
if assignable_length > 0
sel = mark_distances_1 < assignable_length;
assign_weights( tess, mark_ids_1(sel), mark_distances_1(sel), false )
end
% assign end part weights to marks
assignable_length = L(edge) - mark_distances(end);
if assignable_length > 0
sel = mark_distances_2 < assignable_length;
assign_weights( tess, mark_ids_2(sel), mark_distances_2(sel), true )
end
for j = 1:no_of_marks_on_edge-1
assignable_length = mark_distances(j+1)-mark_distances(j);
if assignable_length > 0
local_weights = 0.5 * ones(2,1);
local_mark_ids = [marks_in_edge_network(j); marks_in_edge_network(j+1)];
%assert(~isempty(local_mark_ids));
%W(local_mark_ids) = W(local_mark_ids) + assignable_length * local_weights/sum(local_weights);
tess.weights(local_mark_ids) = tess.weights(local_mark_ids) + assignable_length * local_weights/sum(local_weights);
end
end
else % no_of_marks_on_edge == 0
assignable_length = L(edge);
local_weights = [ 1./(assignable_length+mark_distances_1); 1./(assignable_length+mark_distances_2) ];
valid_weights = local_weights>0;
local_weights = local_weights(valid_weights);
if isempty(local_weights)
unaccounted = unaccounted + assignable_length;
else
local_mark_ids = [ mark_ids_1; mark_ids_2 ];
local_mark_ids = local_mark_ids(valid_weights);
% account for possible duplicate mark ids
%assert(~isempty(local_mark_ids));
[s,si] = sort(local_mark_ids);
[a,~,c] = unique(s);
asum = assignable_length * local_weights(si)/sum(local_weights);
%W(a) = W(a) + accumarray( c, asum );
tess.weights(a) = tess.weights(a) + accumarray( c, asum );
end
end
% checkup
if dbg
assert( abs( sum(tess.weights) + unaccounted - old_W_sum - obj.net.L(edge) ) < 100000*eps );
old_W_sum = sum(tess.weights) + unaccounted;
end
end
% check that for the total network length is accounted for
assert( abs( (sum(tess.weights) + unaccounted - sum(obj.net.L))/sum(obj.net.L) ) < 1e-10 );
% fix ordering of weights
tess.weights = tess.weights(original_mark_index);
if unaccounted > 0
warning('Disconnected network? %f unaccounted for.', unaccounted);
end
function [D, Marks, L] = mark_distance_vectorized( edge_index_vector, start_vertex )
D = inf( length(edge_index_vector), 1 );
Marks = zeros( length(edge_index_vector), 1 );
L = zeros( length(edge_index_vector), 1 );
for k = 1:length(edge_index_vector)
[D(k), Marks(k), L(k)] = mark_distance( edge_index_vector(k), start_vertex);
end
end
function [d, mark, path_len] = mark_distance( edge_index, start_vertex )
%%MARK_DISTANCE returns the distance d to the closest mark, starting
%%from given edge and vertex. Also returns the mark index and the
%%total path length. BUT: does not search on the starting edge!
%assert( isscalar(start_vertex) );
visited_edges(edge_index) = true;
% marks on that edge
marks_on_edge_index = sorted_edge_network(:,1) == edge_index;
table_offset = find( marks_on_edge_index, 1 ) - 1;
no_of_marks_on_edge = nnz(marks_on_edge_index);
path_len = L( edge_index );
if no_of_marks_on_edge > 0
marks_on_sorted_edge_network = sorted_edge_network(marks_on_edge_index,:);
if start_vertex == V1(edge_index)
[d, idx] = min( marks_on_sorted_edge_network(:,2) );
else
%assert( start_vertex == V2(edge_index) );
[tmp, idx] = max( marks_on_sorted_edge_network(:,2) );
d = L(edge_index) - tmp;
end
mark = table_offset + idx;
else
% need to look further
if start_vertex == V1(edge_index)
new_start_vertex = V2(edge_index);
else
%assert( start_vertex == V2(edge_index) );
new_start_vertex = V1(edge_index);
end
neighboring_edges = I( new_start_vertex, : );
neighboring_edges(visited_edges) = 0;
neighboring_edges_index = find(neighboring_edges);
[mark_dists, mark_ids, path_lens] = mark_distance_vectorized( neighboring_edges_index, new_start_vertex );
[d, minIndex] = min([Inf; mark_dists]);
if minIndex > 1; mark = mark_ids(minIndex-1); else mark = 0; end
path_len = path_len + sum(path_lens);
% update inf to the subnetwork length
d = d + L( edge_index );
end
end
function assign_weights( tess, mark_ids, mark_distances, from_end )
% assignable_length lies either on the beginning or the end
% (iff from_end=true) of the given edge
local_weights = [ 1/assignable_length; 1./(assignable_length+mark_distances) ];
valid_weights = local_weights>0;
local_weights = local_weights(valid_weights);
if from_end
local_mark_ids = marks_in_edge_network(end);
else
local_mark_ids = marks_in_edge_network(1);
end
local_mark_ids = [ local_mark_ids; mark_ids ];
local_mark_ids = local_mark_ids(valid_weights);
% account for possible duplicate mark ids
%assert(~isempty(local_mark_ids));
[s,si] = sort(local_mark_ids);
[a,~,c] = unique(s);
asum = assignable_length * local_weights(si)/sum(local_weights);
%W(a) = W(a) + accumarray( c, asum );
tess.weights(a) = tess.weights(a) + accumarray( c, asum );
end
end