Class: Legion::Extensions::Agentic::Inference::CausalReasoning::Helpers::CausalGraph
- Inherits:
-
Object
- Object
- Legion::Extensions::Agentic::Inference::CausalReasoning::Helpers::CausalGraph
- Defined in:
- lib/legion/extensions/agentic/inference/causal_reasoning/helpers/causal_graph.rb
Instance Method Summary collapse
- #add_edge(cause:, effect:, edge_type:, domain: :general, strength: Constants::DEFAULT_STRENGTH) ⇒ Object
- #add_evidence(edge_id:) ⇒ Object
- #add_variable(name:, domain: :general) ⇒ Object
- #by_domain(domain:) ⇒ Object
- #by_type(type:) ⇒ Object
- #causal_chain(from:, to:, max_depth: 5) ⇒ Object
- #causes_of(variable:) ⇒ Object
- #confident_edges ⇒ Object
- #confounders(var_a:, var_b:) ⇒ Object
- #decay_all ⇒ Object
- #effects_of(variable:) ⇒ Object
-
#initialize ⇒ CausalGraph
constructor
A new instance of CausalGraph.
- #intervene(variable:, value:) ⇒ Object
- #observe(variable:, value:, evidence:) ⇒ Object
- #prune_weak ⇒ Object
- #remove_edge(edge_id:) ⇒ Object
- #remove_evidence(edge_id:) ⇒ Object
- #to_h ⇒ Object
- #variable_exists?(name) ⇒ Boolean
Constructor Details
#initialize ⇒ CausalGraph
Returns a new instance of CausalGraph.
10 11 12 13 14 |
# File 'lib/legion/extensions/agentic/inference/causal_reasoning/helpers/causal_graph.rb', line 10 def initialize @variables = {} @edges = {} @edge_index = {} end |
Instance Method Details
#add_edge(cause:, effect:, edge_type:, domain: :general, strength: Constants::DEFAULT_STRENGTH) ⇒ Object
27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
# File 'lib/legion/extensions/agentic/inference/causal_reasoning/helpers/causal_graph.rb', line 27 def add_edge(cause:, effect:, edge_type:, domain: :general, strength: Constants::DEFAULT_STRENGTH) return nil if @edges.size >= Constants::MAX_EDGES return nil unless Constants::EDGE_TYPES.include?(edge_type) add_variable(name: cause, domain: domain) add_variable(name: effect, domain: domain) edge = CausalEdge.new(cause: cause, effect: effect, edge_type: edge_type, domain: domain, strength: strength) @edges[edge.id] = edge @edge_index[cause] ||= [] @edge_index[cause] << edge.id edge end |
#add_evidence(edge_id:) ⇒ Object
122 123 124 125 126 127 |
# File 'lib/legion/extensions/agentic/inference/causal_reasoning/helpers/causal_graph.rb', line 122 def add_evidence(edge_id:) edge = @edges[edge_id] return nil unless edge edge.add_evidence end |
#add_variable(name:, domain: :general) ⇒ Object
16 17 18 19 20 21 |
# File 'lib/legion/extensions/agentic/inference/causal_reasoning/helpers/causal_graph.rb', line 16 def add_variable(name:, domain: :general) return nil if @variables.key?(name) return nil if @variables.size >= Constants::MAX_VARIABLES @variables[name] = { name: name, domain: domain, added_at: Time.now.utc } end |
#by_domain(domain:) ⇒ Object
140 141 142 |
# File 'lib/legion/extensions/agentic/inference/causal_reasoning/helpers/causal_graph.rb', line 140 def by_domain(domain:) @edges.values.select { |e| e.domain == domain } end |
#by_type(type:) ⇒ Object
144 145 146 |
# File 'lib/legion/extensions/agentic/inference/causal_reasoning/helpers/causal_graph.rb', line 144 def by_type(type:) @edges.values.select { |e| e.edge_type == type } end |
#causal_chain(from:, to:, max_depth: 5) ⇒ Object
59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 |
# File 'lib/legion/extensions/agentic/inference/causal_reasoning/helpers/causal_graph.rb', line 59 def causal_chain(from:, to:, max_depth: 5) return [] if from == to queue = [[from, [from]]] visited = { from => true } paths = [] until queue.empty? current, path = queue.shift next if path.size > max_depth + 1 effects_of(variable: current).each do |edge| neighbor = edge.effect new_path = path + [neighbor] if neighbor == to paths << new_path next end next if visited[neighbor] visited[neighbor] = true queue << [neighbor, new_path] end end paths end |
#causes_of(variable:) ⇒ Object
50 51 52 |
# File 'lib/legion/extensions/agentic/inference/causal_reasoning/helpers/causal_graph.rb', line 50 def causes_of(variable:) @edges.values.select { |e| e.effect == variable } end |
#confident_edges ⇒ Object
136 137 138 |
# File 'lib/legion/extensions/agentic/inference/causal_reasoning/helpers/causal_graph.rb', line 136 def confident_edges @edges.values.select(&:confident?) end |
#confounders(var_a:, var_b:) ⇒ Object
115 116 117 118 119 120 |
# File 'lib/legion/extensions/agentic/inference/causal_reasoning/helpers/causal_graph.rb', line 115 def confounders(var_a:, var_b:) ancestors_a = ancestors_of(var_a) ancestors_b = ancestors_of(var_b) common = ancestors_a & ancestors_b common.reject { |v| v == var_a || v == var_b } end |
#decay_all ⇒ Object
148 149 150 151 |
# File 'lib/legion/extensions/agentic/inference/causal_reasoning/helpers/causal_graph.rb', line 148 def decay_all @edges.each_value(&:decay) @edges.size end |
#effects_of(variable:) ⇒ Object
54 55 56 57 |
# File 'lib/legion/extensions/agentic/inference/causal_reasoning/helpers/causal_graph.rb', line 54 def effects_of(variable:) ids = @edge_index.fetch(variable, []) ids.filter_map { |id| @edges[id] } end |
#intervene(variable:, value:) ⇒ Object
89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 |
# File 'lib/legion/extensions/agentic/inference/causal_reasoning/helpers/causal_graph.rb', line 89 def intervene(variable:, value:) downstream = [] queue = [variable] visited = { variable => true } until queue.empty? current = queue.shift effects_of(variable: current).each do |edge| neighbor = edge.effect downstream << { variable: neighbor, via_edge: edge.id, edge_type: edge.edge_type } next if visited[neighbor] visited[neighbor] = true queue << neighbor end end { intervention: variable, value: value, downstream_effects: downstream } end |
#observe(variable:, value:, evidence:) ⇒ Object
109 110 111 112 113 |
# File 'lib/legion/extensions/agentic/inference/causal_reasoning/helpers/causal_graph.rb', line 109 def observe(variable:, value:, evidence:) affected = causes_of(variable: variable) + effects_of(variable: variable) affected.each { |edge| edge.add_evidence if evidence } { variable: variable, value: value, edges_updated: affected.size } end |
#prune_weak ⇒ Object
153 154 155 156 157 |
# File 'lib/legion/extensions/agentic/inference/causal_reasoning/helpers/causal_graph.rb', line 153 def prune_weak weak_ids = @edges.select { |_, e| e.strength <= Constants::STRENGTH_FLOOR }.keys weak_ids.each { |id| remove_edge(edge_id: id) } weak_ids.size end |
#remove_edge(edge_id:) ⇒ Object
42 43 44 45 46 47 48 |
# File 'lib/legion/extensions/agentic/inference/causal_reasoning/helpers/causal_graph.rb', line 42 def remove_edge(edge_id:) edge = @edges.delete(edge_id) return nil unless edge @edge_index[edge.cause]&.delete(edge_id) edge end |
#remove_evidence(edge_id:) ⇒ Object
129 130 131 132 133 134 |
# File 'lib/legion/extensions/agentic/inference/causal_reasoning/helpers/causal_graph.rb', line 129 def remove_evidence(edge_id:) edge = @edges[edge_id] return nil unless edge edge.remove_evidence end |
#to_h ⇒ Object
159 160 161 162 163 164 165 166 |
# File 'lib/legion/extensions/agentic/inference/causal_reasoning/helpers/causal_graph.rb', line 159 def to_h { variables: @variables.size, edges: @edges.size, confident_edges: confident_edges.size, edge_types: Constants::EDGE_TYPES.to_h { |t| [t, by_type(type: t).size] } } end |
#variable_exists?(name) ⇒ Boolean
23 24 25 |
# File 'lib/legion/extensions/agentic/inference/causal_reasoning/helpers/causal_graph.rb', line 23 def variable_exists?(name) @variables.key?(name) end |