Class: Legion::Extensions::Agentic::Inference::Bayesian::Helpers::BeliefNetwork

Inherits:
Object
  • Object
show all
Includes:
Constants
Defined in:
lib/legion/extensions/agentic/inference/bayesian/helpers/belief_network.rb

Constant Summary

Constants included from Constants

Constants::CONFIDENCE_LABELS, Constants::DECAY_RATE, Constants::DEFAULT_PRIOR, Constants::LIKELIHOOD_CEILING, Constants::LIKELIHOOD_FLOOR, Constants::MAX_EVIDENCE, Constants::MAX_HISTORY, Constants::MAX_HYPOTHESES, Constants::PRIOR_CEILING, Constants::PRIOR_FLOOR, Constants::STALE_THRESHOLD

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeBeliefNetwork

Returns a new instance of BeliefNetwork.



14
15
16
# File 'lib/legion/extensions/agentic/inference/bayesian/helpers/belief_network.rb', line 14

def initialize
  @beliefs = {}
end

Instance Attribute Details

#beliefsObject (readonly)

Returns the value of attribute beliefs.



12
13
14
# File 'lib/legion/extensions/agentic/inference/bayesian/helpers/belief_network.rb', line 12

def beliefs
  @beliefs
end

Instance Method Details

#add_belief(content:, domain:, prior: Constants::DEFAULT_PRIOR) ⇒ Object



18
19
20
21
22
23
24
# File 'lib/legion/extensions/agentic/inference/bayesian/helpers/belief_network.rb', line 18

def add_belief(content:, domain:, prior: Constants::DEFAULT_PRIOR)
  return nil if @beliefs.size >= Constants::MAX_HYPOTHESES

  belief = Belief.new(content: content, domain: domain, prior: prior)
  @beliefs[belief.id] = belief
  belief
end

#batch_update(evidence_id:, likelihoods:) ⇒ Object



34
35
36
37
38
39
40
41
42
43
44
45
# File 'lib/legion/extensions/agentic/inference/bayesian/helpers/belief_network.rb', line 34

def batch_update(evidence_id:, likelihoods:)
  return {} if likelihoods.empty?

  updated = {}
  likelihoods.each do |belief_id, likelihood|
    belief = update_belief(belief_id: belief_id, evidence_id: evidence_id, likelihood: likelihood)
    updated[belief_id] = belief.posterior if belief
  end

  normalize_posteriors(updated.keys)
  updated
end

#by_domain(domain:) ⇒ Object



55
56
57
# File 'lib/legion/extensions/agentic/inference/bayesian/helpers/belief_network.rb', line 55

def by_domain(domain:)
  @beliefs.values.select { |b| b.domain == domain }
end

#countObject



101
102
103
# File 'lib/legion/extensions/agentic/inference/bayesian/helpers/belief_network.rb', line 101

def count
  @beliefs.size
end

#decay_allObject



91
92
93
94
95
96
97
98
99
# File 'lib/legion/extensions/agentic/inference/bayesian/helpers/belief_network.rb', line 91

def decay_all
  @beliefs.each_value do |belief|
    shift = (belief.posterior - belief.prior) * Constants::DECAY_RATE
    new_posterior = belief.posterior - shift
    belief.instance_variable_set(:@posterior, new_posterior.clamp(Constants::PRIOR_FLOOR, Constants::PRIOR_CEILING))
    belief.instance_variable_set(:@last_updated_at, Time.now.utc)
  end
  @beliefs.size
end

#entropy(domain: nil) ⇒ Object



80
81
82
83
84
85
86
87
88
89
# File 'lib/legion/extensions/agentic/inference/bayesian/helpers/belief_network.rb', line 80

def entropy(domain: nil)
  dist = posterior_distribution(domain: domain)
  return 0.0 if dist.empty?

  -dist.values.sum do |prob|
    next 0.0 if prob <= 0.0

    prob * Math.log2(prob)
  end
end

#information_gain(belief_id:, evidence_id:, likelihood:) ⇒ Object

rubocop:disable Lint/UnusedMethodArgument



67
68
69
70
71
72
73
74
75
76
77
78
# File 'lib/legion/extensions/agentic/inference/bayesian/helpers/belief_network.rb', line 67

def information_gain(belief_id:, evidence_id:, likelihood:) # rubocop:disable Lint/UnusedMethodArgument
  belief = @beliefs[belief_id]
  return 0.0 unless belief

  prior_p = belief.posterior
  clamped = likelihood.clamp(Constants::LIKELIHOOD_FLOOR, Constants::LIKELIHOOD_CEILING)
  marginal = (clamped * prior_p) + ((1.0 - clamped) * (1.0 - prior_p))
  post_p = (clamped * prior_p) / marginal
  post_p = post_p.clamp(Constants::PRIOR_FLOOR, Constants::PRIOR_CEILING)

  kl_divergence(prior_p, post_p)
end

#least_probable(domain: nil, limit: 5) ⇒ Object



51
52
53
# File 'lib/legion/extensions/agentic/inference/bayesian/helpers/belief_network.rb', line 51

def least_probable(domain: nil, limit: 5)
  filtered(domain).sort_by(&:posterior).first(limit)
end

#most_probable(domain: nil, limit: 5) ⇒ Object



47
48
49
# File 'lib/legion/extensions/agentic/inference/bayesian/helpers/belief_network.rb', line 47

def most_probable(domain: nil, limit: 5)
  filtered(domain).sort_by { |b| -b.posterior }.first(limit)
end

#posterior_distribution(domain: nil) ⇒ Object



59
60
61
62
63
64
65
# File 'lib/legion/extensions/agentic/inference/bayesian/helpers/belief_network.rb', line 59

def posterior_distribution(domain: nil)
  subset = filtered(domain)
  total  = subset.sum(&:posterior)
  return {} if total.zero?

  subset.to_h { |b| [b.id, b.posterior / total] }
end

#to_hObject



105
106
107
108
109
110
# File 'lib/legion/extensions/agentic/inference/bayesian/helpers/belief_network.rb', line 105

def to_h
  {
    belief_count: @beliefs.size,
    beliefs:      @beliefs.transform_values(&:to_h)
  }
end

#update_belief(belief_id:, evidence_id:, likelihood:) ⇒ Object



26
27
28
29
30
31
32
# File 'lib/legion/extensions/agentic/inference/bayesian/helpers/belief_network.rb', line 26

def update_belief(belief_id:, evidence_id:, likelihood:)
  belief = @beliefs[belief_id]
  return nil unless belief

  belief.update(likelihood: likelihood, evidence_id: evidence_id)
  belief
end