ruleby 0.2 → 0.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,66 @@
1
+ # This file is part of the Ruleby project (http://ruleby.org)
2
+ #
3
+ # This application is free software; you can redistribute it and/or
4
+ # modify it under the terms of the Ruby license defined in the
5
+ # LICENSE.txt file.
6
+ #
7
+ # Copyright (c) 2007 Joe Kutner and Matt Smith. All rights reserved.
8
+ #
9
+ # * Authors: Joe Kutner, Matt Smith
10
+ #
11
+
12
+ $LOAD_PATH << File.join(File.dirname(__FILE__), '../lib/')
13
+ require 'ruleby'
14
+ require 'model'
15
+
16
+ include Ruleby
17
+
18
+ class TestRulebook < Rulebook
19
+ def rules(n)
20
+ (0..n).each do |index|
21
+ rule "Rule-#{index}".to_sym do |r|
22
+ r.when do |has|
23
+ has.a Account
24
+ has.a.status = 'standard'
25
+ has.a.title = 'mr'
26
+ has.a.account_id = "acc#{index}"
27
+ end
28
+
29
+ r.then do |e,vars|
30
+ # puts "rule #{index} fired"
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
36
+
37
+ def run_benchmark(rules, facts)
38
+ puts "running benchmark for: #{rules} rules and #{facts} facts"
39
+
40
+ t1 = Time.new
41
+ engine :engine do |e|
42
+ TestRulebook.new(e).rules(rules)
43
+
44
+ t2 = Time.new
45
+ diff = t2.to_f - t1.to_f
46
+ puts 'time to create rule set: ' + diff.to_s
47
+ for k in (0..facts)
48
+ e.assert Account.new('standard', 'mr', ('acc'+k.to_s))
49
+ end
50
+
51
+ t3 = Time.new
52
+ diff = t3.to_f - t2.to_f
53
+ puts 'time to assert facts: ' + diff.to_s
54
+ e.match
55
+
56
+ t4 = Time.new
57
+ diff = t4.to_f - t3.to_f
58
+ puts 'time to run agenda: ' + diff.to_s
59
+ end
60
+ end
61
+
62
+ run_benchmark(5, 500)
63
+ puts '-------'
64
+ run_benchmark(50, 500)
65
+ puts '-------'
66
+ run_benchmark(500, 500)
@@ -0,0 +1,73 @@
1
+ # This file is part of the Ruleby project (http://ruleby.org)
2
+ #
3
+ # This application is free software; you can redistribute it and/or
4
+ # modify it under the terms of the Ruby license defined in the
5
+ # LICENSE.txt file.
6
+ #
7
+ # Copyright (c) 2007 Joe Kutner and Matt Smith. All rights reserved.
8
+ #
9
+ # * Authors: Joe Kutner, Matt Smith
10
+ #
11
+
12
+ $LOAD_PATH << File.join(File.dirname(__FILE__), '../lib/')
13
+ require 'ruleby'
14
+ require 'model'
15
+
16
+ include Ruleby
17
+
18
+ class TestRulebook < Rulebook
19
+ def rules(n)
20
+ (0..n).each do |index|
21
+ rule "Rule-#{index}".to_sym do |r|
22
+ r.when do |has|
23
+ has.a Account
24
+ has.a.status = 'standard'
25
+ has.a.account_id :id
26
+
27
+ has.addr Address
28
+ has.addr.addr_id = :id, :%
29
+ has.addr.city = 'Foobar'
30
+ has.addr.state = 'FB'
31
+ has.addr.zip = '12345'
32
+ end
33
+
34
+ r.then do |e,vars|
35
+ # puts "rule #{index} fired"
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
41
+
42
+ def run_benchmark(rules,facts)
43
+ puts "running benchmark for: #{rules} rules and #{facts} facts"
44
+
45
+ t1 = Time.new
46
+ engine :engine do |e|
47
+ TestRulebook.new(e).rules(rules)
48
+
49
+ t2 = Time.new
50
+ diff = t2.to_f - t1.to_f
51
+ puts 'time to create rule set: ' + diff.to_s
52
+
53
+
54
+ for k in (0..facts)
55
+ e.assert Account.new('standard', nil, "acc#{k}")
56
+ e.assert Address.new("acc#{k}",'Foobar', 'FB', '12345')
57
+ end
58
+
59
+ t3 = Time.new
60
+ diff = t3.to_f - t2.to_f
61
+ puts 'time to assert facts: ' + diff.to_s
62
+
63
+ e.match
64
+
65
+ t4 = Time.new
66
+ diff = t4.to_f - t3.to_f
67
+ puts 'time to run agenda: ' + diff.to_s
68
+ end
69
+ end
70
+
71
+ run_benchmark(5, 50)
72
+ puts '-------'
73
+ run_benchmark(50, 50)
@@ -1,3 +1,14 @@
1
+ # This file is part of the Ruleby project (http://ruleby.org)
2
+ #
3
+ # This application is free software; you can redistribute it and/or
4
+ # modify it under the terms of the Ruby license defined in the
5
+ # LICENSE.txt file.
6
+ #
7
+ # Copyright (c) 2007 Joe Kutner and Matt Smith. All rights reserved.
8
+ #
9
+ # * Authors: Joe Kutner, Matt Smith
10
+ #
11
+
1
12
  module MissManners
2
13
  class MannersData
3
14
  def initialize
@@ -1,6 +1,16 @@
1
+ # This file is part of the Ruleby project (http://ruleby.org)
2
+ #
3
+ # This application is free software; you can redistribute it and/or
4
+ # modify it under the terms of the Ruby license defined in the
5
+ # LICENSE.txt file.
6
+ #
7
+ # Copyright (c) 2007 Joe Kutner and Matt Smith. All rights reserved.
8
+ #
9
+ # * Authors: Joe Kutner, Matt Smith
10
+ #
11
+
1
12
  $LOAD_PATH << File.join(File.dirname(__FILE__), '../../lib/')
2
13
  require 'ruleby'
3
- require 'rulebook'
4
14
  require 'model'
5
15
  require 'data'
6
16
  require 'rules'
@@ -1,3 +1,14 @@
1
+ # This file is part of the Ruleby project (http://ruleby.org)
2
+ #
3
+ # This application is free software; you can redistribute it and/or
4
+ # modify it under the terms of the Ruby license defined in the
5
+ # LICENSE.txt file.
6
+ #
7
+ # Copyright (c) 2007 Joe Kutner and Matt Smith. All rights reserved.
8
+ #
9
+ # * Authors: Joe Kutner, Matt Smith
10
+ #
11
+
1
12
  module MissManners
2
13
 
3
14
  class Chosen
@@ -1,163 +1,102 @@
1
+ # This file is part of the Ruleby project (http://ruleby.org)
2
+ #
3
+ # This application is free software; you can redistribute it and/or
4
+ # modify it under the terms of the Ruby license defined in the
5
+ # LICENSE.txt file.
6
+ #
7
+ # Copyright (c) 2007 Joe Kutner and Matt Smith. All rights reserved.
8
+ #
9
+ # * Authors: Joe Kutner, Matt Smith
10
+ #
11
+
1
12
  require 'model'
2
13
 
3
14
  module MissManners
4
15
 
5
- class MannersRulebook < Rulebook
16
+ class MannersRulebook < Ruleby::Rulebook
6
17
  def rules
7
- rule 'assignFirstSeat' do |r|
8
- r.when do |has|
9
- has.context(Context).&.state = Context::START_UP
10
- has.guest Guest
11
- has.count Count
12
- end
13
-
14
- r.then = action do |e,vars|
15
- guestName = vars[:guest].name
16
-
18
+ rule :assignFirstSeat,
19
+ [Context,:context, m.state == Context::START_UP],
20
+ [Guest,:guest],
21
+ [Count,:count] do |e,vars|
22
+ guestName = vars[:guest].name
17
23
  seating = Seating.new(vars[:count].value,1,true,1,guestName,1,guestName)
18
- e.assert seating
19
-
24
+ e.assert seating
20
25
  path = Path.new(vars[:count].value, 1, guestName)
21
26
  e.assert path
22
-
23
27
  e.retract vars[:count]
24
28
  vars[:count].value = vars[:count].value + 1
25
29
  e.assert vars[:count]
26
-
27
30
  puts "assign first seat : #{seating.to_s} : #{path.to_s}"
28
-
29
31
  vars[:context].state = Context::ASSIGN_SEATS
30
32
  e.modify vars[:context]
31
- end
32
33
  end
33
34
 
34
- rule 'findSeating' do |r|
35
- r.when do |has|
36
- has.context(Context).&.state(:state).&.state = Context::ASSIGN_SEATS
37
-
38
- has.count(Count).&.value:countValue
39
-
40
- has.s(Seating).&.id(:seatingId).&.pid(:seatingPid).&.rightSeat(:seatingRightSeat).&.rightGuestName:seatingRightGuestName
41
- has.s.path(:p).&.path = true
42
-
43
- has.g(Guest).&.name(:name).&.sex(:rightGuestSex).&.hobby(:rightGuestHobby)
44
- has.g.name = :seatingRightGuestName, :%
45
-
46
- has.lg(Guest).&.name(:leftGuestName).&.sex:sex
47
- has.lg.hobby(:hobby).&.hobby = :rightGuestHobby, :%
48
- has.lg.sex :rightGuestSex do |s,rgs| s != rgs end
49
-
50
- has.not.path(Path).&.id = :seatingId, :%
51
- has.path.guestName = :leftGuestName, :%
52
-
53
- has.not.chosen Chosen
54
- has.chosen.id = :seatingId, :%
55
- has.chosen.guestName = :leftGuestName, :%
56
- has.chosen.hobby = :leftGuestHobby, :%
57
- end
58
-
59
- r.then = action do |e,vars|
35
+ rule :findSeating,
36
+ [Context,:context, {m.state == Context::ASSIGN_SEATS => :state}],
37
+ [Count,:count, {m.value => :countValue}],
38
+ [Seating,:seating, {m.path == true =>:p, m.id=>:seatingId, m.pid=>:seatingPid, m.rightSeat=>:seatingRightSeat, m.rightGuestName=>:seatingRightGuestName}],
39
+ [Guest,:g, {m.name=>:name, m.sex=>:rightGuestSex, m.hobby=>:rightGuestHobby}, m.name == b(:seatingRightGuestName)],
40
+ [Guest,:lg, {m.name=>:leftGuestName, m.sex=>:sex, m.hobby == b(:rightGuestHobby) => :hobby}, m.sex(:rightGuestSex, &c{|s,rgs| s != rgs} )],
41
+ [:~,Path, m.id == b(:seatingId), m.guestName == b(:leftGuestName)],
42
+ [:~,Chosen, m.id == b(:seatingId), m.guestName == b(:leftGuestName), m.hobby == b(:leftGuestHobby)] do |e,vars|
60
43
  rightSeat = vars[:seatingRightSeat]
61
44
  seatId = vars[:seatingId]
62
- countValue = vars[:count].value
63
-
45
+ countValue = vars[:count].value
64
46
  seating = Seating.new(countValue,seatId,false,rightSeat,vars[:seatingRightGuestName],rightSeat+1,vars[:leftGuestName])
65
47
  path = Path.new(countValue,rightSeat+1,vars[:leftGuestName])
66
- chosen = Chosen.new(seatId, vars[:leftGuestName], vars[:rightGuestHobby] )
67
-
48
+ chosen = Chosen.new(seatId, vars[:leftGuestName], vars[:rightGuestHobby] )
68
49
  puts "find seating : #{seating} : #{path} : #{chosen}"
69
-
70
50
  e.assert seating
71
51
  e.assert path
72
52
  e.assert chosen
73
-
74
53
  vars[:count].value = countValue + 1
75
54
  e.modify vars[:count]
76
-
77
55
  vars[:context].state = Context::MAKE_PATH
78
56
  e.modify vars[:context]
79
- end
80
-
81
57
  end
82
58
 
83
- rule 'makePath' do |r|
84
- r.when do |has|
85
- has.context(Context).&.state(:s).&.state = Context::MAKE_PATH
86
-
87
- has.seating(Seating).&.id(:seatingId).&.pid:seatingPid
88
- has.seating.path(:p).&.path = false
89
-
90
- has.path(Path).&.guestName(:pathGuestName).&.seat(:pathSeat)
91
- has.path.id = :seatingPid, :%
92
-
93
- has.not.path2 Path
94
- has.path2.id = :seatingId, :%
95
- has.path2.guestName = :pathGuestName, :%
96
- end
97
-
98
- r.then = action do |e,vars|
59
+ rule :makePath,
60
+ [Context,:context, {m.state == Context::MAKE_PATH => :s}],
61
+ [Seating,:seating, {m.id=>:seatingId, m.pid=>:seatingPid, m.path == false =>:p}],
62
+ [Path,:path, {m.guestName=>:pathGuestName, m.seat=>:pathSeat}, m.id == b(:seatingPid)],
63
+ [:~,Path,m.id == b(:seatingId), m.guestName == b(:pathGuestName)] do |e,vars|
99
64
  path = Path.new(vars[:seatingId],vars[:pathSeat],vars[:pathGuestName])
100
65
  e.assert path
101
66
  puts "make Path : #{path}"
102
- end
103
67
  end
104
68
 
105
- rule 'pathDone' do |r|
106
- r.when do |has|
107
- has.context(Context).&.state = Context::MAKE_PATH
108
- has.seating(Seating).&.path = false
109
- end
110
-
111
- r.then = action do |e,vars|
69
+ # NOTE We had to add this because Ruleby's conflict resolution strategy
70
+ # is not robust enough. If it worked correctly, this priority would not
71
+ # be nessecary because the 'make path' activations would have more
72
+ # recent facts supporting it.
73
+ rule :pathDone, {:priority => -5},
74
+ [Context,:context, m.state == Context::MAKE_PATH],
75
+ [Seating,:seating, m.path == false] do |e,vars|
112
76
  vars[:seating].path = true
113
- e.modify vars[:seating]
114
-
77
+ e.modify vars[:seating]
115
78
  vars[:context].state = Context::CHECK_DONE
116
79
  e.modify vars[:context]
117
80
  puts "path Done : #{vars[:seating]}"
118
- end
119
-
120
- # HACK We had to add this because Ruleby's conflict resolution strategy
121
- # is not robust enough. If it worked correctly, this priority would not
122
- # be nessecary because the 'make path' activations would have more
123
- # recent facts supporting it.
124
- r.priority = -5
125
81
  end
126
82
 
127
- rule 'areWeDone' do |r|
128
- r.when do |has|
129
- has.context(Context).&.state = Context::CHECK_DONE
130
- has.ls(LastSeat).&.seat:lastSeat
131
- has.seating(Seating).&.rightSeat = :lastSeat, :%
132
- end
133
-
134
- r.then = action do |e,vars|
83
+ rule :areWeDone,
84
+ [Context,:context, m.state == Context::CHECK_DONE],
85
+ [LastSeat,:ls, {m.seat => :lastSeat}],
86
+ [Seating,:seating, m.rightSeat == b(:lastSeat)] do |e,vars|
135
87
  vars[:context].state = Context::PRINT_RESULTS
136
88
  e.modify vars[:context]
137
- end
138
89
  end
139
90
 
140
- rule 'continue' do |r|
141
- r.when do |has|
142
- has.context Context
143
- has.context.state = Context::CHECK_DONE
144
- end
145
- r.then = action do |e,vars|
91
+ rule :continue, {:priority => -5},
92
+ [Context,:context,m.state == Context::CHECK_DONE] do |e,vars|
146
93
  vars[:context].state = Context::ASSIGN_SEATS
147
94
  e.modify vars[:context]
148
- end
149
- r.priority = -5
150
95
  end
151
96
 
152
- rule 'allDone' do |r|
153
- r.when do |has|
154
- has.c Context
155
- has.c.state = Context::PRINT_RESULTS
156
- end
157
-
158
- r.then = action do |e,vars|
97
+ rule :allDone,
98
+ [Context,:context,m.state == Context::PRINT_RESULTS] do |e,vars|
159
99
  puts 'All done'
160
- end
161
100
  end
162
101
  end
163
102
  end
@@ -0,0 +1,36 @@
1
+ # This file is part of the Ruleby project (http://ruleby.org)
2
+ #
3
+ # This application is free software; you can redistribute it and/or
4
+ # modify it under the terms of the Ruby license defined in the
5
+ # LICENSE.txt file.
6
+ #
7
+ # Copyright (c) 2007 Joe Kutner and Matt Smith. All rights reserved.
8
+ #
9
+ # * Authors: Joe Kutner, Matt Smith
10
+ #
11
+
12
+ class Account
13
+ def initialize(status, title, account_id)
14
+ @status = status
15
+ @title = title
16
+ @account_id = account_id
17
+ end
18
+
19
+ attr :status, true
20
+ attr :title, true
21
+ attr :account_id, true
22
+ end
23
+
24
+ class Address
25
+ def initialize(addr_id, city, state, zip)
26
+ @addr_id = addr_id
27
+ @city = city
28
+ @state = state
29
+ @zip = zip
30
+ end
31
+
32
+ attr :addr_id, true
33
+ attr :city, true
34
+ attr :state, true
35
+ attr :zip, true
36
+ end
@@ -1,6 +1,16 @@
1
+ # This file is part of the Ruleby project (http://ruleby.org)
2
+ #
3
+ # This application is free software; you can redistribute it and/or
4
+ # modify it under the terms of the Ruby license defined in the
5
+ # LICENSE.txt file.
6
+ #
7
+ # Copyright (c) 2007 Joe Kutner and Matt Smith. All rights reserved.
8
+ #
9
+ # * Authors: Joe Kutner, Matt Smith
10
+ #
11
+
1
12
  $LOAD_PATH << File.join(File.dirname(__FILE__), '../lib/')
2
13
  require 'ruleby'
3
- require 'rulebook'
4
14
 
5
15
  class Patient
6
16
  def initialize(name,fever,spots,rash,sore_throat,innoculated)
@@ -37,104 +47,56 @@ class Treatment
37
47
  attr:treatment,true
38
48
  end
39
49
 
40
- class DiagnosisRulebook < Rulebook
50
+ class DiagnosisRulebook < Ruleby::Rulebook
41
51
  def rules
42
- rule 'Measles' do |r|
43
- r.when do |exists|
44
- exists.p(Patient).&.name:n
45
- exists.p.fever=:high
46
- exists.p.spots=true
47
- exists.p.innoculated=true
48
- end
49
- r.then = action do |e,vars|
50
- name = vars[:n]
52
+ rule :Measles, {:priority => 100},
53
+ [Patient,:p,{m.name=>:n},m.fever==:high,m.spots==true,m.innoculated==true] do |e,v|
54
+ name = v[:n]
51
55
  e.assert Diagnosis.new(name, :measles)
52
- puts "Measles diagnosed for #{name}"
53
- end
54
- r.priority = 100
56
+ puts "Measles diagnosed for #{name}"
55
57
  end
56
58
 
57
- rule 'Allergy1' do |r|
58
- r.when do |exists|
59
- exists.p Patient
60
- exists.p.name:n
61
- exists.p.spots=true
62
-
63
- exists.not.d Diagnosis
64
- exists.d.name = :n, :%
65
- exists.d.diagnosis = :measles
66
- end
67
- r.then = action do |e,vars|
68
- name = vars[:n]
59
+ rule :Allergy1,
60
+ [Patient,:p, {m.name=>:n}, m.spots==true],
61
+ [:not, Diagnosis, m.name==b(:n), m.diagnosis==:measles] do |e,v|
62
+ name = v[:n]
69
63
  e.assert Diagnosis.new(name, :allergy)
70
64
  puts "Allergy diagnosed for #{name} from spots and lack of measles"
71
- end
72
65
  end
73
66
 
74
- rule 'Allergy2' do |r|
75
- r.when do |exists|
76
- exists.p Patient
77
- exists.p.name :n2
78
- exists.p.rash = true
79
- end
80
- r.then = action do |e,vars|
81
- name = vars[:n2]
67
+ rule :Allergy2,
68
+ [Patient,:p, {m.name=>:n}, m.rash==true] do |e,v|
69
+ name = v[:n]
82
70
  e.assert Diagnosis.new(name, :allergy)
83
71
  puts "Allergy diagnosed from rash for #{name}"
84
- end
85
72
  end
86
73
 
87
- rule 'Flu' do |r|
88
- r.when do |exists|
89
- exists.p Patient
90
- exists.p.name :n3
91
- exists.p.sore_throat=true
92
- exists.p.fever do |f| f == :mild || f == :high end
93
- end
94
- r.then = action do |e,vars|
95
- name = vars[:n3]
74
+ rule :Flu,
75
+ [Patient,:p, {m.name=>:n}, m.sore_throat==true, m.fever(&c{|f| f==:mild || f==:high})] do |e,v|
76
+ name = v[:n]
96
77
  e.assert Diagnosis.new(name, :flu)
97
78
  puts "Flu diagnosed for #{name}"
98
- end
99
79
  end
100
80
 
101
- rule 'Penicillin' do |r|
102
- r.when do |exists|
103
- exists.d Diagnosis
104
- exists.d.name :n4
105
- exists.d.diagnosis = :measles
106
- end
107
- r.then = action do |e,vars|
108
- name = vars[:n4]
81
+ rule :Penicillin,
82
+ [Diagnosis, :d, {m.name => :n}, m.diagnosis==:measles] do |e,v|
83
+ name = v[:n]
109
84
  e.assert Treatment.new(name, :penicillin)
110
85
  puts "Penicillin prescribed for #{name}"
111
- end
112
86
  end
113
87
 
114
- rule 'Allergy_pills' do |r|
115
- r.when do |exists|
116
- exists.d Diagnosis
117
- exists.d.name :n5
118
- exists.d.diagnosis = :allergy
119
- end
120
- r.then = action do |e,vars|
121
- name = vars[:n5]
88
+ rule :Allergy_pills,
89
+ [Diagnosis, :d, {m.name => :n}, m.diagnosis==:allergy] do |e,v|
90
+ name = v[:n]
122
91
  e.assert Treatment.new(name, :allergy_shot)
123
92
  puts "Allergy shot prescribed for #{name}"
124
- end
125
93
  end
126
94
 
127
- rule 'Bed_rest' do |r|
128
- r.when do |exists|
129
- exists.d Diagnosis
130
- exists.d.name :n6
131
- exists.d.diagnosis = :flu
132
- end
133
- r.then = action do |e,vars|
134
- name = vars[:n6]
95
+ rule :Bed_rest,
96
+ [Diagnosis, :d, {m.name => :n}, m.diagnosis==:flu] do |e,v|
97
+ name = v[:n]
135
98
  e.assert Treatment.new(name, :bed_rest)
136
99
  puts "Bed rest prescribed for #{name}"
137
- end
138
100
  end
139
101
  end
140
102
  end