lib/bio/pathway.rb in bio-1.2.1 vs lib/bio/pathway.rb in bio-1.3.0

- old
+ new

@@ -4,11 +4,11 @@ # Copyright: Copyright (C) 2001 # Toshiaki Katayama <k@bioruby.org>, # Shuichi Kawashima <shuichi@hgc.jp> # License:: The Ruby License # -# $Id: pathway.rb,v 1.36 2007/04/05 23:35:39 trevor Exp $ +# $Id:$ # require 'matrix' module Bio @@ -182,10 +182,19 @@ # # Returns the adjacency matrix expression of the graph as a Matrix # object. If the first argument was assigned, the matrix will be # filled with the given value. The second argument indicates the # value of the diagonal constituents of the matrix besides the above. + # + # The result of this method depends on the order of Hash#each + # (and each_key, etc.), which may be variable with Ruby version + # and Ruby interpreter variations (JRuby, etc.). + # For a workaround to remove such dependency, you can use @index + # to set order of Hash keys. Note that this behavior might be + # changed in the future. Be careful that @index is overwritten by + # this method. + # def to_matrix(default_value = nil, diagonal_value = nil) #-- # Note: following code only fills the outer Array with the reference # to the same inner Array object. @@ -204,13 +213,35 @@ nodes.times do |i| matrix[i][i] = diagonal_value end end - # assign index number for each node - @graph.keys.each_with_index do |k, i| - @index[k] = i + # assign index number + if @index.empty? then + # assign index number for each node + @graph.keys.each_with_index do |k, i| + @index[k] = i + end + else + # begin workaround removing depencency to order of Hash#each + # assign index number from the preset @index + indices = @index.to_a + indices.sort! { |i0, i1| i0[1] <=> i1[1] } + indices.collect! { |i0| i0[0] } + @index.clear + v = 0 + indices.each do |k, i| + if @graph[k] and !@index[k] then + @index[k] = v; v += 1 + end + end + @graph.each_key do |k| + unless @index[k] then + @index[k] = v; v += 1 + end + end + # end workaround removing depencency to order of Hash#each end if @relations.empty? # only used after clear_relations! @graph.each do |from, hash| hash.each do |to, relation| @@ -234,26 +265,60 @@ # Pretty printer of the adjacency matrix. # # The dump_matrix method accepts the same arguments as to_matrix. # Useful when you want to check the internal state of the matrix # (for debug purpose etc.) easily. + # + # This method internally calls to_matrix method. + # Read documents of to_matrix for important informations. + # def dump_matrix(*arg) matrix = self.to_matrix(*arg) sorted = @index.sort {|a,b| a[1] <=> b[1]} "[# " + sorted.collect{|x| x[0]}.join(", ") + "\n" + matrix.to_a.collect{|row| ' ' + row.inspect}.join(",\n") + "\n]" end # Pretty printer of the adjacency list. # - # The dump_matrix method accepts the same arguments as to_matrix. # Useful when you want to check the internal state of the adjacency # list (for debug purpose etc.) easily. + # + # The result of this method depends on the order of Hash#each + # (and each_key, etc.), which may be variable with Ruby version + # and Ruby interpreter variations (JRuby, etc.). + # For a workaround to remove such dependency, you can use @index + # to set order of Hash keys. Note that this behavior might be + # changed in the future. + # def dump_list + # begin workaround removing depencency to order of Hash#each + if @index.empty? then + pref = nil + enum = @graph + else + pref = {}.merge(@index) + i = pref.values.max + @graph.each_key do |node| + pref[node] ||= (i += 1) + end + graph_to_a = @graph.to_a + graph_to_a.sort! { |x, y| pref[x[0]] <=> pref[y[0]] } + enum = graph_to_a + end + # end workaround removing depencency to order of Hash#each + list = "" - @graph.each do |from, hash| + enum.each do |from, hash| list << "#{from} => " + # begin workaround removing depencency to order of Hash#each + if pref then + ary = hash.to_a + ary.sort! { |x,y| pref[x[0]] <=> pref[y[0]] } + hash = ary + end + # end workaround removing depencency to order of Hash#each a = [] hash.each do |to, relation| a.push("#{to} (#{relation})") end list << a.join(", ") + "\n" @@ -283,10 +348,11 @@ end end sub_graph = Pathway.new([], @undirected) @graph.each do |from, hash| next unless @label[from] + sub_graph.graph[from] ||= {} hash.each do |to, relation| next unless @label[to] sub_graph.append(Relation.new(from, to, relation)) end end @@ -308,18 +374,27 @@ # Returns completeness of the edge density among the surrounded nodes. # # Calculates the value of cliquishness around the 'node'. This value # indicates completeness of the edge density among the surrounded nodes. + # + # Note: cliquishness (clustering coefficient) for a directed graph + # is also calculated. + # Reference: http://en.wikipedia.org/wiki/Clustering_coefficient + # + # Note: Cliquishness (clustering coefficient) for a node that has + # only one neighbor node is undefined. Currently, it returns NaN, + # but the behavior may be changed in the future. + # def cliquishness(node) neighbors = @graph[node].keys sg = subgraph(neighbors) if sg.graph.size != 0 - edges = sg.edges / 2.0 - nodes = sg.nodes - complete = (nodes * (nodes - 1)) / 2.0 - return edges/complete + edges = sg.edges + nodes = neighbors.size + complete = (nodes * (nodes - 1)) + return edges.quo(complete) else return 0.0 end end @@ -394,23 +469,48 @@ # # If $DEBUG is true (e.g. ruby -d), this method prints the progression # of the search. # # The weight of the edges are not considered in this method. + # + # Note: The result of this method depends on the order of Hash#each + # (and each_key, etc.), which may be variable with Ruby version + # and Ruby interpreter variations (JRuby, etc.). + # For a workaround to remove such dependency, you can use @index + # to set order of Hash keys. Note that this bahavior might be + # changed in the future. def depth_first_search visited = {} timestamp = {} tree_edges = {} back_edges = {} cross_edges = {} forward_edges = {} count = 0 + # begin workaround removing depencency to order of Hash#each + if @index.empty? then + preference_of_nodes = nil + else + preference_of_nodes = {}.merge(@index) + i = preference_of_nodes.values.max + @graph.each_key do |node0| + preference_of_nodes[node0] ||= (i += 1) + end + end + # end workaround removing depencency to order of Hash#each + dfs_visit = Proc.new { |from| visited[from] = true timestamp[from] = [count += 1] - @graph[from].each_key do |to| + ary = @graph[from].keys + # begin workaround removing depencency to order of Hash#each + if preference_of_nodes then + ary = ary.sort_by { |node0| preference_of_nodes[node0] } + end + # end workaround removing depencency to order of Hash#each + ary.each do |to| if visited[to] if timestamp[to].size > 1 if timestamp[from].first < timestamp[to].first # forward edge (black) p "#{from} -> #{to} : forward edge" if $DEBUG @@ -433,11 +533,17 @@ end end timestamp[from].push(count += 1) } - @graph.each_key do |node| + ary = @graph.keys + # begin workaround removing depencency to order of Hash#each + if preference_of_nodes then + ary = ary.sort_by { |node0| preference_of_nodes[node0] } + end + # end workaround removing depencency to order of Hash#each + ary.each do |node| unless visited[node] dfs_visit.call(node) end end return timestamp, tree_edges, back_edges, cross_edges, forward_edges @@ -541,11 +647,11 @@ if rel[i] == rel[j] index << j end end end - index.sort{|x, y| y<=>x}.each do |i| - rel[i, 1] = [] + index.sort{|x, y| y<=>x}.each do |idx| + rel[idx, 1] = [] end mst = [] seen = Hash.new() @graph.each_key do |x| seen[x] = nil