Class: PatternMatcher
- Inherits:
-
Object
- Object
- PatternMatcher
- Defined in:
- lib/cirrocumulus/pattern_matching.rb
Instance Method Summary collapse
- #bind_parameters(pattern, fact, current_bindings) ⇒ Object
- #find_matches_for_condition(pattern) ⇒ Object
- #generate_combination(rule, candidates, attempt) ⇒ Object
- #increment_attempt(attempt, idx, limits) ⇒ Object
-
#initialize(facts) ⇒ PatternMatcher
constructor
A new instance of PatternMatcher.
- #intersect_matches_for_each_condition(rule, candidates) ⇒ Object
- #match(pattern) ⇒ Object
- #matches?(rule) ⇒ Boolean
- #pattern_matches?(fact, pattern, current_params = {}) ⇒ Boolean
- #test_condition_parameters_combination(rule, candidates, attempt) ⇒ Object
Constructor Details
#initialize(facts) ⇒ PatternMatcher
Returns a new instance of PatternMatcher.
18 19 20 |
# File 'lib/cirrocumulus/pattern_matching.rb', line 18 def initialize(facts) @facts = facts end |
Instance Method Details
#bind_parameters(pattern, fact, current_bindings) ⇒ Object
101 102 103 104 105 106 107 108 109 110 111 112 |
# File 'lib/cirrocumulus/pattern_matching.rb', line 101 def bind_parameters(pattern, fact, current_bindings) result = {} pattern.each_with_index do |p,i| if p.is_a?(Symbol) && p.to_s.upcase == p.to_s return nil if current_bindings.has_key?(p) && current_bindings[p] != fact[i] result[p] = fact[i] end end result end |
#find_matches_for_condition(pattern) ⇒ Object
44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 |
# File 'lib/cirrocumulus/pattern_matching.rb', line 44 def find_matches_for_condition(pattern) trace "=> attempting to match pattern #{pattern.inspect}" fact_matches = true candidates = [] @facts.each do |fact| next if fact.data.size != pattern.size fact_matches = true pattern.each_with_index do |el,i| if el.is_a?(Symbol) && el.to_s.upcase == el.to_s # parameter else fact_matches = false if el != fact.data[i] end end candidates << fact if fact_matches end trace "=> candidates: #{candidates.size}" if candidates.size > 0 candidates end |
#generate_combination(rule, candidates, attempt) ⇒ Object
114 115 116 117 118 119 120 121 122 123 124 |
# File 'lib/cirrocumulus/pattern_matching.rb', line 114 def generate_combination(rule, candidates, attempt) next_attempt = [] if attempt == [] rule.conditions.each {|pattern| next_attempt << 0} else next_attempt = increment_attempt(attempt, rule.conditions.size - 1, candidates.map {|c| c.size}) end next_attempt end |
#increment_attempt(attempt, idx, limits) ⇒ Object
126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 |
# File 'lib/cirrocumulus/pattern_matching.rb', line 126 def increment_attempt(attempt, idx, limits) return [] if idx < 0 if attempt[idx] < limits[idx] - 1 attempt[idx] += 1 else i = idx while i < limits.size do attempt[i] = 0 i += 1 end return increment_attempt(attempt, idx-1, limits) end attempt end |
#intersect_matches_for_each_condition(rule, candidates) ⇒ Object
67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 |
# File 'lib/cirrocumulus/pattern_matching.rb', line 67 def intersect_matches_for_each_condition(rule, candidates) result = [] attempt = [] while (attempt = generate_combination(rule, candidates, attempt)) != [] do bindings = test_condition_parameters_combination(rule, candidates, attempt) if bindings match_data = MatchResult.new(rule) attempt.each_with_index {|a,i| match_data.matched_facts << candidates[i][a]} match_data.parameters = bindings result << match_data end end result end |
#match(pattern) ⇒ Object
22 23 24 25 26 27 28 29 |
# File 'lib/cirrocumulus/pattern_matching.rb', line 22 def match(pattern) res = [] find_matches_for_condition(pattern).each do |fact| res << bind_parameters(pattern, fact.data, {}) end res end |
#matches?(rule) ⇒ Boolean
31 32 33 34 35 36 37 38 39 40 41 42 |
# File 'lib/cirrocumulus/pattern_matching.rb', line 31 def matches?(rule) trace "Processing rule '#{rule.name}' (#{rule.conditions.size} condition(s)):" pattern_candidates = [] rule.conditions.each do |pattern| pattern_candidates << find_matches_for_condition(pattern) end return nil if !pattern_candidates.all? {|c| c.size > 0} intersect_matches_for_each_condition(rule, pattern_candidates) end |
#pattern_matches?(fact, pattern, current_params = {}) ⇒ Boolean
144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 |
# File 'lib/cirrocumulus/pattern_matching.rb', line 144 def pattern_matches?(fact, pattern, current_params = {}) return nil if fact.size != pattern.size binded_params = {} pattern.each_with_index do |el,i| if el.is_a?(Symbol) && el.to_s.upcase == el.to_s if current_params && current_params.has_key?(el) current_value = current_params[el] return nil if fact[i] != current_value else binded_params[el] = fact[i] end else return nil if el != fact[i] end end binded_params end |
#test_condition_parameters_combination(rule, candidates, attempt) ⇒ Object
83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 |
# File 'lib/cirrocumulus/pattern_matching.rb', line 83 def test_condition_parameters_combination(rule, candidates, attempt) facts = [] attempt.each_with_index {|a,i| facts << candidates[i][a].data} binded_params = {} pattern_params = {} facts.each_with_index do |fact,i| pattern_params = bind_parameters(rule.conditions[i], fact, binded_params) if pattern_params.nil? # failure, parameters mismatch return nil else binded_params.merge!(pattern_params) end end binded_params end |