Class: PatternMatcher

Inherits:
Object
  • Object
show all
Defined in:
lib/cirrocumulus/pattern_matching.rb

Instance Method Summary collapse

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

Returns:

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

Returns:

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