class MiniPGM::Model
Represents a Probabilistic Graphical Model
(PGM)
Attributes
edges[R]
Edges between individual nodes, sorted by label of the outgoing edge, e.g:
Pollution -> Cancer Smoker -> Cancer
error[R]
most recent error after calling `valid?`
nodes[R]
Lookup table of labelled nodes, each associated with a set of labels for all incoming edges, e.g:
{ Pollution, Smoker } -> Cancer -> { } { } -> Pollution -> { Cancer } { } -> Smoker -> { Cancer }
Public Class Methods
new(*edges)
click to toggle source
# File lib/mini_pgm/model.rb, line 32 def initialize(*edges) @edges = sort_edges(edges) @nodes = reduce_edges(edges) end
Public Instance Methods
add_cpd(cpd)
click to toggle source
# File lib/mini_pgm/model.rb, line 37 def add_cpd(cpd) node = @nodes[cpd.variable.label] raise ArgumentError, "node does not exist for label #{node.label}" unless node check_cpd_evidence!(cpd.evidence.map(&:label), node.incoming_edges) node.cpd = cpd end
to_s()
click to toggle source
# File lib/mini_pgm/model.rb, line 45 def to_s ['Edges:', edges_to_s, '', 'Nodes:', nodes_to_s, '', 'Valid:', valid?, ''].join("\n") end
valid?()
click to toggle source
# File lib/mini_pgm/model.rb, line 60 def valid? @error = nil validate! true rescue ModelError => e @error = e false end
validate!()
click to toggle source
# File lib/mini_pgm/model.rb, line 49 def validate! @nodes.each_value do |node| raise ModelError, "node '#{node.label}' does not have a CPD" unless node.cpd end # validate cardinality between nodes for each edge @edges.each do |edge| validate_cardinality!(@nodes[edge.to], @nodes[edge.from]) end end
Private Instance Methods
check_cpd_evidence!(cpd_evidence, node_dependencies)
click to toggle source
# File lib/mini_pgm/model.rb, line 71 def check_cpd_evidence!(cpd_evidence, node_dependencies) cpd_evidence.each do |evidence| raise ArgumentError, "node is missing dependency for CPD evidence '#{evidence}'" \ unless node_dependencies.include?(evidence) end node_dependencies.each do |dependency| raise ArgumentError, "CPD is missing evidence for node dependency '#{dependency}'" \ unless cpd_evidence.include?(dependency) end end
edges_to_s()
click to toggle source
# File lib/mini_pgm/model.rb, line 83 def edges_to_s @edges.map(&:to_s).join("\n") end
nodes_to_s()
click to toggle source
# File lib/mini_pgm/model.rb, line 87 def nodes_to_s @nodes.keys.sort.map { |key| @nodes[key].to_s }.join("\n") end
reduce_edges(edges)
click to toggle source
# File lib/mini_pgm/model.rb, line 91 def reduce_edges(edges) edges.each_with_object({}) do |edge, reduced| # create node for incoming edge (reduced[edge.to] ||= MiniPGM::Node.new(edge.to)).incoming_edges.add(edge.from) # create node for outgoing edge (reduced[edge.from] ||= MiniPGM::Node.new(edge.from)).outgoing_edges.add(edge.to) end end
sort_edges(edges)
click to toggle source
# File lib/mini_pgm/model.rb, line 101 def sort_edges(edges) edges.sort_by(&:from) end
validate_cardinality!(to, from)
click to toggle source
# File lib/mini_pgm/model.rb, line 105 def validate_cardinality!(to, from) expected = to.cpd.evidence.find { |ev| ev.label == from.label }.cardinality actual = from.cpd.variable.cardinality raise ModelError, "cardinality mismatch in CPDs of '#{from.label}' (#{actual}) and '#{to.label}' (#{expected})" \ unless expected == actual end