class ChaosDetector::ChaosGraphs::ChaosGraph
Constants
- NODE_TYPES
- STATES
Attributes
domain_appraisal[R]
domain_edges[R]
domain_function_edges[R]
domain_module_edges[R]
domain_nodes[R]
function_appraisal[R]
function_domain_edges[R]
function_graph[R]
mod_rel_graph[R]
module_appraisal[R]
module_domain_edges[R]
module_edges[R]
module_nodes[R]
Public Class Methods
new(function_graph, mod_rel_graph)
click to toggle source
# File lib/chaos_detector/chaos_graphs/chaos_graph.rb, line 37 def initialize(function_graph, mod_rel_graph) @function_graph = function_graph @mod_rel_graph = mod_rel_graph @domain_nodes = nil @module_nodes = nil @domain_edges = nil @module_edges = nil @module_domain_edges = nil @domain_module_edges = nil @function_domain_edges = nil @domain_function_edges = nil end
Public Instance Methods
appraise_graph(graph, sort_col: :total_couplings, sort_desc: true, top: nil)
click to toggle source
Use Graph theory to appraise given graph:
# File lib/chaos_detector/chaos_graphs/chaos_graph.rb, line 154 def appraise_graph(graph, sort_col: :total_couplings, sort_desc: true, top: nil) appraiser = ChaosDetector::GraphTheory::Appraiser.new(graph) appraiser.appraise appraiser end
build_domain_graph(edges: @domain_edes)
click to toggle source
Derive domain-level graph from function-based graph
# File lib/chaos_detector/chaos_graphs/chaos_graph.rb, line 126 def build_domain_graph(edges: @domain_edes) assert_state ChaosDetector::GraphTheory::Graph.new(root_node: root_node_domain, nodes: @domain_nodes, edges: edges) end
build_module_graph(edges: @module_edges)
click to toggle source
Derive module-level graph from function-based graph
# File lib/chaos_detector/chaos_graphs/chaos_graph.rb, line 132 def build_module_graph(edges: @module_edges) assert_state ChaosDetector::GraphTheory::Graph.new(root_node: root_node_module, nodes: @module_nodes, edges: edges) end
derive_graph(graph_type:, sort_col: :total_couplings, include_root: true, sort: :desc, top: nil)
click to toggle source
ChaosDetector::ChaosGraphs::ChaosGraph
.NODE_TYPES
# File lib/chaos_detector/chaos_graphs/chaos_graph.rb, line 68 def derive_graph(graph_type:, sort_col: :total_couplings, include_root: true, sort: :desc, top: nil) sortcol = sort_col || :total_couplings graph, appraisal = graph_data_for(graph_type: graph_type) nodes = graph.nodes(include_root: false) # nodes.filter!{ |node| yield(node) } if block_given? # Use appraisal metrics for sorting: node_metrics = nodes.map{|node| appraisal.metrics_for(node: node)} n_sort = node_metrics.map{|m| m.send(sortcol)}.map.with_index.sort.map(&:last) n_sort.reverse! if sort == :desc # Limit: if top ChaosUtils.with(top.to_i) do |t| n_sort = n_sort.take(t) if t.positive? end end gnodes = n_sort.map{|i| nodes[i].clone } # gnodes = new_nodes.map(&:clone) gedges = graph.edges.filter_map do |edge| src_node = gnodes.find{ |node| node == edge.src_node } dep_node = gnodes.find{ |node| node == edge.dep_node } if src_node && dep_node edge.dup.tap do |gedge| gedge.src_node = src_node gedge.dep_node = dep_node end end end ChaosDetector::GraphTheory::Graph.new( root_node: include_root ? gnodes.find(&:is_root)&.dup : nil, nodes: gnodes, edges: gedges ) end
domain_graph()
click to toggle source
# File lib/chaos_detector/chaos_graphs/chaos_graph.rb, line 109 def domain_graph assert_state(:inferred) @domain_graph ||= build_domain_graph(edges: @domain_edges) end
domain_node_for(name:)
click to toggle source
Lookup domain node by name:
# File lib/chaos_detector/chaos_graphs/chaos_graph.rb, line 120 def domain_node_for(name:) # domain_nodes.find(->{root_node_domain}){|node| node.name.to_s == name.to_s} domain_nodes.find(->{root_node_domain}){|node| node.name.to_s == name.to_s} end
graph_data_for(graph_type:)
click to toggle source
Return [graph, appraisal] for given type:
# File lib/chaos_detector/chaos_graphs/chaos_graph.rb, line 138 def graph_data_for(graph_type:) assert_state(:inferred) case graph_type when :function [function_graph, function_appraisal] when :module [module_graph, module_appraisal] when :domain [domain_graph, domain_appraisal] else raise "graph_type should be one of #{NODE_TYPES.inspect}, actual value: #{ChaosUtils.decorate(graph_type)}" end end
infer_all()
click to toggle source
# File lib/chaos_detector/chaos_graphs/chaos_graph.rb, line 51 def infer_all assert_state infer_module_nodes infer_domain_nodes prepare_root_nodes # Now infer all edges: infer_edges # Graph theory appraisal appraise_all self # @domain_graph = build_domain_graph(@domain_edges) # @module_graph = build_domain_graph(@module_edges) end
module_graph()
click to toggle source
# File lib/chaos_detector/chaos_graphs/chaos_graph.rb, line 114 def module_graph assert_state(:inferred) @module_graph ||= build_module_graph(edges: @module_edges) end
Private Instance Methods
appraise_all()
click to toggle source
Graph theory appraisal
# File lib/chaos_detector/chaos_graphs/chaos_graph.rb, line 164 def appraise_all log("Appraising graphs") @domain_appraisal = appraise_graph(domain_graph) @module_appraisal = appraise_graph(module_graph) @function_appraisal = appraise_graph(function_graph) end
assert_state(state = nil)
click to toggle source
# File lib/chaos_detector/chaos_graphs/chaos_graph.rb, line 171 def assert_state(state = nil) raise "function_graph.nodes isn't set!" unless function_graph&.nodes if state == :inferred raise "@domain_nodes isn't set; call #build" unless @domain_nodes raise "@module_nodes isn't set; call #build" unless @module_nodes end end
check_edges(name, edges)
click to toggle source
# File lib/chaos_detector/chaos_graphs/chaos_graph.rb, line 283 def check_edges(name, edges) return edges.each do |edge| puts("#{name} EDGE: #{edge.class} / #{edge.reduction.class} / #{edge}") end end
group_edges_by(edges, src, dep)
click to toggle source
# File lib/chaos_detector/chaos_graphs/chaos_graph.rb, line 290 def group_edges_by(edges, src, dep) assert_state raise ArgumentError, 'edges argument required' unless edges # log("GROUPING EDGES by #{src} and #{dep}") groupedges = edges.group_by do |e| [ node_group_prop(e.src_node, node_type: src), node_group_prop(e.dep_node, node_type: dep) ] end # valid_edges = groupedges.select do |src_dep_pair, g_edges| # src_dep_pair.all? # end groupedges.filter_map do |src_dep_pair, g_edges| raise 'Pair should have two exactly items.' unless src_dep_pair.length == 2 # log("Looking up pair: #{src_dep_pair.inspect}") edge_src_node = lookup_node_by(node_type: src, node_info: src_dep_pair.first) edge_dep_node = lookup_node_by(node_type: dep, node_info: src_dep_pair.last) # log("Creating #{src_dep_pair.first.class} edge with #{ChaosUtils.decorate_pair(edge_src_node, edge_dep_node)}") if (edge_src_node != edge_dep_node) ChaosDetector::GraphTheory::Edge.new( edge_src_node, edge_dep_node, reduction: ChaosDetector::GraphTheory::Reduction.new( reduction_count: g_edges.count, reduction_sum: g_edges.reduce(0) do |sum, e| sum + (e.reduction&.reduction_count || 1) end ) ) end end end
infer_domain_nodes()
click to toggle source
# File lib/chaos_detector/chaos_graphs/chaos_graph.rb, line 252 def infer_domain_nodes assert_state @domain_nodes = @module_nodes.group_by(&:domain_name).map do |dom_nm, mod_nodes| mod_reductions = mod_nodes.map(&:reduction) dom_reduction = ChaosDetector::GraphTheory::Reduction.combine_all(mod_reductions) ChaosDetector::ChaosGraphs::DomainNode.new( domain_name: dom_nm, reduction: dom_reduction, is_root: dom_nm==ChaosDetector::GraphTheory::Node::ROOT_NODE_NAME || !ChaosUtils.aught?(dom_nm) ) end end
infer_edges()
click to toggle source
# File lib/chaos_detector/chaos_graphs/chaos_graph.rb, line 266 def infer_edges assert_state fn_edges = @function_graph.edges mod_edges = group_edges_by(fn_edges, :module, :module).concat(@mod_rel_graph.edges) check_edges("mod_edges", mod_edges) dom_edges = group_edges_by(mod_edges, :domain, :domain) check_edges("dom_edges", dom_edges) @domain_edges = reduce_edges(dom_edges) check_edges("@domain_edges", @domain_edges) @module_edges = reduce_edges(mod_edges) check_edges("@module_edges", @module_edges) end
infer_module_nodes()
click to toggle source
# File lib/chaos_detector/chaos_graphs/chaos_graph.rb, line 214 def infer_module_nodes assert_state grouped_nodes = @function_graph.nodes.group_by(&:mod_info_prime) # mod_nodes = grouped_nodes.select do |mod_info, _fn_nodes| # ChaosUtils.aught?(mod_info&.mod_name) # end mod_nodes = grouped_nodes.filter_map do |mod_info, fn_nodes| next unless ChaosUtils.aught?(mod_info&.mod_name) node_fn = fn_nodes.first fn_reductions = fn_nodes.map(&:reduction) mod_reduction = ChaosDetector::GraphTheory::Reduction.combine_all(fn_reductions) # puts ("mod_reduction: %s" % mod_reduction.inspect) ChaosDetector::ChaosGraphs::ModuleNode.new( mod_name: mod_info.mod_name, mod_type: mod_info.mod_type, mod_path: mod_info.mod_path, domain_name: node_fn.domain_name, reduction: mod_reduction ) end mod_nodes.uniq! @mod_rel_graph.nodes.each do |rel_node| n = mod_nodes.index(rel_node) mod_nodes << rel_node if n.nil? end @module_nodes = mod_nodes.uniq end
log(msg, **opts)
click to toggle source
# File lib/chaos_detector/chaos_graphs/chaos_graph.rb, line 384 def log(msg, **opts) ChaosUtils.log_msg(msg, subject: 'ChaosGraph', **opts) end
lookup_node_by(node_type:, node_info:)
click to toggle source
# File lib/chaos_detector/chaos_graphs/chaos_graph.rb, line 357 def lookup_node_by(node_type:, node_info:) assert_state # It is already a node: return node_info if node_info.is_a? ChaosDetector::GraphTheory::Node case node_type when :function # Look up by FnInfo n = node_info && @function_graph.nodes.index(node_info) n.nil? ? root_node_function : @function_graph.nodes[n] when :module # Look up by module info n = node_info && @module_nodes.index(node_info) n.nil? ? root_node_module : @module_nodes[n] when :domain # Look up by Domain name unless (node_info.nil? || node_info.is_a?(String) || node_info.is_a?(Symbol)) log("NodeInfo is something other than info or string type: class: (#{node_info.class}) = #{node_info.inspect}") end domain_node_for(name: node_info.to_s) || root_node_domain else raise "node_type should be one of #{NODE_TYPES.inspect}, actual value: #{ChaosUtils.decorate(node_type)}" end end
node_group_prop(node, node_type:)
click to toggle source
# File lib/chaos_detector/chaos_graphs/chaos_graph.rb, line 342 def node_group_prop(node, node_type:) unless NODE_TYPES.include? node_type raise format('node_type should be one of symbols in %s, actual value: %s (%s)', NODE_TYPES.inspect, ChaosUtils.decorate(node_type), ChaosUtils.decorate(node_type.class)) end case node_type when :function node.to_info when :module node.mod_info_prime when :domain node.domain_name end end
prepare_root_nodes()
click to toggle source
# File lib/chaos_detector/chaos_graphs/chaos_graph.rb, line 180 def prepare_root_nodes assert_state(:inferred) ChaosUtils.with(root_node_function) do |fn_root_node| @function_graph.nodes.unshift(fn_root_node) unless @function_graph.nodes.include?(fn_root_node) end ChaosUtils.with(root_node_domain) do |domain_root_node| @domain_nodes.unshift(domain_root_node) unless @domain_nodes.include?(domain_root_node) end ChaosUtils.with(root_node_module) do |mod_root_node| @module_nodes.unshift(mod_root_node) unless @module_nodes.include?(mod_root_node) end end
reduce_edges(edges)
click to toggle source
# File lib/chaos_detector/chaos_graphs/chaos_graph.rb, line 330 def reduce_edges(edges) edges.reduce(Set.new) do |memo, obj| existing = memo.find{|m| obj==m} if existing existing.merge!(obj) else memo << obj end memo end.to_a end
root_node_domain()
click to toggle source
# File lib/chaos_detector/chaos_graphs/chaos_graph.rb, line 201 def root_node_domain assert_state(:inferred) root_node = @domain_nodes.find(&:is_root) root_node || ChaosDetector::ChaosGraphs::DomainNode.root_node end
root_node_function()
click to toggle source
# File lib/chaos_detector/chaos_graphs/chaos_graph.rb, line 195 def root_node_function assert_state root_node = @function_graph.nodes.find(&:is_root) root_node || ChaosDetector::ChaosGraphs::FunctionNode.root_node end
root_node_module()
click to toggle source
# File lib/chaos_detector/chaos_graphs/chaos_graph.rb, line 207 def root_node_module assert_state(:inferred) root_node = @module_nodes.find(&:is_root) root_node || ChaosDetector::ChaosGraphs::ModuleNode.root_node end