Class: Glymour::StructureLearning::LearningNet
- Inherits:
-
Object
- Object
- Glymour::StructureLearning::LearningNet
- Includes:
- Glymour::Statistics
- Defined in:
- lib/glymour.rb
Instance Attribute Summary collapse
-
#directed_edges ⇒ Object
Returns the value of attribute directed_edges.
-
#n ⇒ Object
Returns the value of attribute n.
-
#net ⇒ Object
Returns the value of attribute net.
-
#p_value ⇒ Object
readonly
Returns the value of attribute p_value.
Instance Method Summary collapse
-
#compatible_orientations ⇒ Object
Gives a list of all orientations of @net compatible with @directed_edges (i.e., all directed acyclic graphs with edge structure given partially by @directed_edges).
-
#direct_edges ⇒ Object
Direct remaining edges in @net as much as possible.
-
#initialize(variable_container, p_value = 0.05) ⇒ LearningNet
constructor
A new instance of LearningNet.
-
#learn_structure ⇒ Object
Perform the PC algorithm in full.
-
#step ⇒ Object
Perform one step of the PC algorithm.
Methods included from Glymour::Statistics
Constructor Details
#initialize(variable_container, p_value = 0.05) ⇒ LearningNet
Returns a new instance of LearningNet.
139 140 141 142 143 144 145 |
# File 'lib/glymour.rb', line 139 def initialize(variable_container, p_value = 0.05) @net = complete_graph(variable_container.variables).extend(GraphAlgorithms) @directed_edges = {} @directed_edges.default = [] @n = -1 @p_value = p_value end |
Instance Attribute Details
#directed_edges ⇒ Object
Returns the value of attribute directed_edges.
136 137 138 |
# File 'lib/glymour.rb', line 136 def directed_edges @directed_edges end |
#n ⇒ Object
Returns the value of attribute n.
136 137 138 |
# File 'lib/glymour.rb', line 136 def n @n end |
#net ⇒ Object
Returns the value of attribute net.
136 137 138 |
# File 'lib/glymour.rb', line 136 def net @net end |
#p_value ⇒ Object (readonly)
Returns the value of attribute p_value.
137 138 139 |
# File 'lib/glymour.rb', line 137 def p_value @p_value end |
Instance Method Details
#compatible_orientations ⇒ Object
Gives a list of all orientations of @net compatible with @directed_edges (i.e., all directed acyclic graphs with edge structure given partially by @directed_edges)
216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 |
# File 'lib/glymour.rb', line 216 def compatible_orientations compat_list = [] edges = net.edges.extend(PowerSet) # Every orientation of net corresponds to a subset of its edges edges.power_set.each do |subset| # Orient edges in subset as source => target, outside of it as target => source # Any edges conflicting with directed_edges will be cyclic and therefore not counted current_orientation = make_directed(net.vertices, @directed_edges) edges.each do |e| if subset.include? e current_orientation.add_edge(e.source, e.target) else current_orientation.add_edge(e.target, e.source) end end compat_list << current_orientation if current_orientation.acyclic? end compat_list end |
#direct_edges ⇒ Object
Direct remaining edges in @net as much as possible
194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 |
# File 'lib/glymour.rb', line 194 def direct_edges puts "Directing edges where possible..." net.non_transitive.each do |triple| a, b, c = *triple intersect = (net.adjacent_either(a, c) & net.verts_on_paths(a, c)).extend(PowerSet) if intersect.power_set.select {|s| s.include? b}.none? { |subset| coindependent?(p_value, a, c, *subset) } puts "Adding directed edge #{a.name} => #{b.name}..." @directed_edges[a] = (@directed_edges[a] << b).uniq puts "Adding directed edge #{c.name} => #{b.name}..." @directed_edges[c] = (@directed_edges[c] << b).uniq end end end |
#learn_structure ⇒ Object
Perform the PC algorithm in full
178 179 180 181 182 183 184 185 186 187 188 189 190 191 |
# File 'lib/glymour.rb', line 178 def learn_structure puts "Learning undirected net structure..." # Perform step until every pair of adjacent variables is dependent, and # set final_net to the _second-to-last_ state of @net begin puts "n = #{n}" final_net = net step end while n < 1 net = final_net direct_edges end |
#step ⇒ Object
Perform one step of the PC algorithm
148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 |
# File 'lib/glymour.rb', line 148 def step any_independent = false net.edges.each do |e| a, b = e.source, e.target intersect = (@net.adjacent_either(a, b) & @net.verts_on_paths(a, b)).extend(PowerSet) # Is |Aab ^ Uab| > n? if intersect.length <= n next else # Are a and b independent conditioned on any subsets of Aab ^ Uab of cardinality n+1? valid_intersects = intersect.power_set.select {|s| s.length == n+1}.reject { |subset| subset.include?(a) || subset.include?(b) } if valid_intersects.any? { |subset| print "Testing independence between #{a.name} and #{b.name}, conditioning on #{(subset.any? ? subset.map(&:name).join(', ') : 'nothing') + '...'}" print (coindependent?(p_value, a, b, *subset) ? "[+]\n" : "[-]\n") coindependent?(p_value, a, b, *subset) } @net = remove_edge(net, e) net.edges.each do |e| puts "#{e.source.name} => #{e.target.name}" end any_independent = true end end end @n += 1 any_independent end |