📄 reweighted_graphs.m
字号:
%% Reweighted graphs in MatlabBGL% Matlab sparse matrices only support non-zero values. Because the% structure of the sparse matrix is used to infer the edges of an% underlying graph this limitation prevents MatlabBGL from trivially % addressing graphs with 0-weight edges.%% To fix this problem, codes that accept a weighted graph allow the user to% specify a vector of edge weights for each edge in the graph using the% optional 'weights' parameter. Using the 'weights' parameter correctly% can be difficult due to issues with how edges are indexed in MatlabBGL.%% Disclaimer% The details of this section are complicated. This means their% implementation is error-prone. If you get strange behavior, please let% me know.%% "I just want the simpliest solution..."% *new in version 4.0*% In this section, we'll see the really-easy but somewhat expensive way of% reweighting a graph. I'll run through all the cases detailed below with% the simple code. If you just need something to work and don't% necessarily need to know about all the details, this section is for you!%%% Let's compute shortest paths in a cycle graph with only one weighted% edge. The simple case requires a structural and weight matrix.%%% n will be the total size of the graph, and u and v will be the special% vertices connected with a weight one edge.n = 8; % it's just an example, so let's make it small.u = 1;v = 2;%%% These commands create an undirected cycle graph. The cycle is % ... n <-> 1 <-> 2 <-> ... <-> n-1 <-> n <-> 1 ...% where the weight on every edge is 0 except for the edge between vertex% u,v. Notice that the edge list is already symmetric. %% This setup means that while there is a weight 1 edge between u and v, the% shortest path, or smallest weight path, is actually the path from u,% circling every vertex except v and so d(v) should be 0.E = [1:n 2:n 1; 2:n 1 1:n]';w = [1 zeros(1,n-1) 1 zeros(1,n-1)]';A = sparse(E(:,1), E(:,2), w, n, n); % create a weighted sparse matrixAs = sparse(E(:,1), E(:,2), true, n, n); % create a structural sparse matrix%% % The relationship between As and A is that As should have a non-zero value% for every edge, but the _values_ of As will be ignored and the% computation will proceed with the _values_ in the corresponding spots in% the matrix A.%%% The wrong way to compute shortest paths.[d pred] = shortest_paths(A,u);d(v)%% % The right way to compute shortest paths.[d pred] = shortest_paths(As,u,struct('edge_weight',edge_weight_vector(As,A)));d(v)%%% That's better, d(v) = 0 as expected.%% A first attempt% * Correct for version 3.0 *% A trivial example graph to illustrate the problem that occurs with 0% weighted graphs occurs even with a simple cycle. Suppose that the graph% corresponding to adjacency matrix A is a symmetric cycle where all edges% have weight 0 except for one edge between vertices (1,2).%%% These commands create an undirected cycle graph. The cycle is % ... n <-> 1 <-> 2 <-> ... <-> n-1 <-> n <-> 1 ...% where the weight on every edge is 0 except for the edge between vertex% u,v. Notice that the edge list is already symmetric. E = [1:n 2:n 1; 2:n 1 1:n]';w = [1 zeros(1,n-1) 1 zeros(1,n-1)]';A = sparse(E(:,1), E(:,2), w, n, n);%%% The shortest weighted path between u and v is then through the vertex % n because traversing the cycle in the other direction will use the % u,v edge of weight 1. Let's check this with the shortest_paths function.[d pred] = shortest_paths(A,u);d(v)%%% That is weird, there is a u-v path of length 0 in the graph! Let's see% what path the shortest path algorithm chose.path_from_pred(pred,v)%%% The path it chose was from u to v directly, taking the weight 1 edge.% Let's look at the sparse matrix.A%%% There are only two edges in the matrix corresponding to our symmetric% weight 1 edge between u and v. This happens because Matlab removes all 0% weight edges from the graph. %% A first solution% The solution to the problem is to use the 'edge_weight' optional% parameter to the shortest_paths function to give it a set of weights % to use for each edge. help shortest_paths%% % Well, shortest_paths says to read this document, so you are on the right% track! It also has a pointer to the function edge_weight_index. Let's% look at that functionhelp edge_weight_index%%% This function claims to help us. It requires building a structural% matrix which has a non-zero for each edge in the graph. Let's do that.As = sparse(E(:,1), E(:,2), 1, n, n)%%% Now the matrix has all of the required edges. According to the% edge_weight_index function, it returns both a matrix and an index vector.% The index vector is a way to permute an intelligently ordered set of edge% weights to the order that MatlabBGL requires the edge weights. [ei Ei] = edge_weight_index(As);full(Ei)ei%%% Now let's create a new edge weight vector for this graph corresponding to% all the edges we want. Each non-zero in the matrix should have an% associated edge weight. Most the edge weights in this case are 0, so it% makes it simple. ew = zeros(nnz(As),1);ew(Ei(u,v)) = 1;ew(Ei(v,u)) = 1;[d pred] = shortest_paths(As,u,struct('edge_weight', ew(ei)));path_from_pred(pred,v)%%% Excellent, now the shorest path _avoids_ the edge (u,v) as we would% expect it. %% A simplified solution% The current example is somewhat tedious because we have to create the% sparse matrix, then create the edge index matrix, and finally create and % edit the edge weight array. %% The indexed_sparse function makes the process easier. % % Recall that using the sparse function directly generated an incorrect% graph adjacency matrix.A = sparse(E(:,1), E(:,2), w, n, n)%%% The indexed_sparse function is designed as a replacement for sparse where% the adjacency matrix must be indexed using the edge_weight_index or% contains 0 weight edges.help indexed_sparse%%% From the documentation of indexed_sparse, the first two return values are% the structural sparse matrix (As) and the sparse matrix (A) that sparse% would have returned. The final two return values are the edge index list% that edge_weight_index returns as well as the edge index matrix.% save the old Ei as an exampleold_Ei = Ei;[As A eil Ei] = indexed_sparse(E(:,1), E(:,2), w, n, n);fprintf('old_Ei = \n\n');disp(full(old_Ei));fprintf('Ei = \n\n');disp(full(Ei))%% % Note that the edge indices changed between the two calls. The reason for% this change is that indexed_sparse generates edge indices based on order% of E(:,1) and E(:,2). Consequently, this function is much easier to use% when you already have a set of weighted edges.%% In this case, we don't have to create the ew array again! (Note that the% call uses eil instead of ei.)[d pred] = shortest_paths(As,u,struct('edge_weight', w(eil)));path_from_pred(pred,v)%% An undirected solution% The situation for undirected graphs is more complicated. The trouble% with the previous solution is that each directed edge had its own weight% in the vector w. For an undirected graph, we really want each undirected% edge to have a single weight, so the natural length of v would be% nnz(A)/2 instead of nnz(A).%% However, MatlabBGL really treats all problems as directed graphs, so it% will need a vector w of length nnz(A), but that vector should satisfy the% requirement w(ei1) = w(ei2) if the edges corresponding to ei1 and ei2 are% (i,j) and (j,i), respectively. %% Again, the edge_weight_index function provides a solution to this% problem. We just have to tell edge_weight_index we have an undirected% graph.%%% Let's start with the same sparse matrixAs = sparse(E(:,1), E(:,2), 1, n, n)%%% Here we use the edge_weight_index [ei Ei] = edge_weight_index(As,struct('undirected',1));full(Ei) % look at the matrix%%% Let's create the edge weight vectorew = zeros(nnz(As)/2,1); % only half as many zeros here.ew(Ei(u,v)) = 1; % and we only needed to set one entry to 0[d pred] = shortest_paths(As,u,struct('edge_weight', ew(ei)));path_from_pred(pred,v)%%% And we get the same output as before!%% The undirected simplification% You can probably guess that the simplification for undirected graphs will% use the indexed_sparse call again too. help indexed_sparse%% % From the documentation, we find that indexed_sparse has an option called% "undirected" which is set to 0 by default. [As A eil Ei] = indexed_sparse(E(:,1), E(:,2), w, n, n, struct('undirected',1));fprintf('Ei = \n\n');disp(full(Ei))%%% In this case, the indexed_sparse routine only issued edge indices that% were between 1 and 8, rather than 1 and 16 as in the previous case. [d pred] = shortest_paths(As,u,struct('edge_weight', w(eil)));path_from_pred(pred,v)%% Summary% The functions that support reweighted edges as of MatlabBGL 3.0 are % shortest_paths, all_shortest_paths, dijkstra_sp, bellman_ford_sp, dag_sp,% betweenness_centrality, astar_search, johnson_all_sp,% floyd_warshall_all_sp, mst, kruskal_mst, and prim_mst. Note that% max_flow does not support these indices.%%% The functions that assist working with the edge indices for the% edge_weight vector are edge_weight_index, indexed_sparse, and% edge_weight_vector.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -