Class: Legion::Extensions::Agentic::Inference::CausalReasoning::Helpers::CausalGraph

Inherits:
Object
  • Object
show all
Defined in:
lib/legion/extensions/agentic/inference/causal_reasoning/helpers/causal_graph.rb

Instance Method Summary collapse

Constructor Details

#initializeCausalGraph

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_edgesObject



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_allObject



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_weakObject



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_hObject



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

Returns:

  • (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