1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 package zeus.rete;
25
26 import java.util.*;
27 import zeus.util.*;
28 import zeus.actors.AgentContext;
29 import zeus.concepts.*;
30 import zeus.concepts.fn.*;
31 import zeus.actors.event.*;
32 import zeus.actors.*;
33
34 public class ReteEngine {
35 static final int RULE_ACTIVATED = 0;
36 static final int RULE_DEACTIVATED = 1;
37 static final int RULE_ADDED = 2;
38 static final int RULE_REMOVED = 3;
39 static final int RULE_FIRED = 4;
40
41 protected Hashtable factDb = new Hashtable();
42 protected static final String PATH = "path#";
43 protected static final String JPATH = "path@";
44
45 protected Hashtable roots = new Hashtable();
46 protected Hashtable ids = new Hashtable();
47 protected Vector singles = new Vector();
48 protected Vector joins = new Vector();
49 protected Vector tests = new Vector();
50
51 protected int pathNo = 0;
52 protected int joinPathNo = 0;
53 protected ConflictSet conflictSet;
54 protected Fact initial_fact = null;
55 protected AgentContext context = null;
56 protected OntologyDb ontologyDb = null;
57 private HSet[] eventMonitor = new HSet[5];
58 private HSet localMonitor = new HSet();
59
60
61 public ReteEngine () {
62 ;
63 }
64
65 public ReteEngine(AgentContext context) {
66 Assert.notNull(context);
67 this.context = context;
68 context.set(this);
69
70 for(int i = 0; i < eventMonitor.length; i++ )
71 eventMonitor[i] = new HSet();
72
73 conflictSet = new ConflictSet(context);
74 initial_fact = context.OntologyDb().getFact(Fact.FACT,Rule.INITIAL_FACT);
75 ResourceDb database = context.ResourceDb();
76 database.addFactMonitor(new SymFactAction(),
77 FactEvent.ADD_MASK|FactEvent.DELETE_MASK,true);
78 }
79
80
81 public ReteEngine(OntologyDb ontologyDb) {
82 Assert.notNull(ontologyDb);
83 this.ontologyDb = ontologyDb;
84
85 for(int i = 0; i < eventMonitor.length; i++ )
86 eventMonitor[i] = new HSet();
87
88 conflictSet = new ConflictSet(this,ontologyDb);
89 initial_fact = ontologyDb.getFact(Fact.FACT,Rule.INITIAL_FACT);
90 }
91
92
93 public AgentContext getAgentContext() {
94 return context;
95 }
96
97 public void run() {
98 update(Node.ADD,initial_fact);
99 conflictSet.start();
100 }
101
102
103 public void reset() {
104 conflictSet.reset();
105
106 JoinNode node;
107 for(int i = 0; i < joins.size(); i++ ) {
108 node = (JoinNode)joins.elementAt(i);
109 node.reset();
110 }
111
112
113 Enumeration enum = factDb.elements();
114 while( enum.hasMoreElements() )
115 update(Node.ADD,(Fact)enum.nextElement());
116 }
117
118
119 ConflictSet getConfictSet() {
120 return conflictSet;
121 }
122
123
124 Hashtable getFactDb() {
125 return factDb;
126 }
127
128
129 public void update(int tag, ReteFact token) {
130
131 Fact f = ontology().getFact(Fact.FACT,token.type);
132 String attribute;
133 ValueFunction value;
134 Enumeration enum = token.data.keys();
135 while( enum.hasMoreElements() ) {
136 attribute = (String)enum.nextElement();
137 value = (ValueFunction)token.data.get(attribute);
138 f.setValue(attribute,value);
139 }
140 update(tag,f);
141 }
142
143
144 /***
145 * Update is the method which is called to decide if a rule should be fired or not
146 * when a fact is added to the ResourceDb.
147 * Change Log
148 * ----------
149 * 26/06/01 - 1.3 - Simon Thompson added some code to check not only for rootnodes of
150 * the same type as the added fact, but also the ancestors of the fact to.
151 * However, note that only one rule will be fired!
152 */
153 public void update(int tag, Fact f) {
154
155 if ( context == null ) {
156 if ( tag == Node.ADD )
157 factDb.put(f.getId(),f);
158 else if ( tag == Node.REMOVE )
159 factDb.remove(f.getId());
160 }
161 fireLocalFactMonitor(tag, f);
162 Vector input = new Vector();
163 input.addElement(f);
164 /***
165 change */
166 boolean fired = false;
167
168 TypeNode node = (TypeNode)roots.get(f.getType());
169 if ( node != null ) {
170 fired = true;
171 synchronized(conflictSet.queue) {
172 node.evaluate(null, tag, Node.SINGLE, input, new Bindings());
173 }
174
175 }
176 Iterator supers = ontology().allAncestors(f.getType());
177 while (supers.hasNext()&& !fired) {
178 node = (TypeNode)roots.get((String)supers.next());
179 if ( node != null ) {
180 fired = true;
181 synchronized(conflictSet.queue) {
182 node.evaluate(null, tag, Node.SINGLE, input, new Bindings());
183 }
184
185 }
186 }
187 }
188
189
190 private OntologyDb ontology() {
191 return ((ontologyDb != null) ? ontologyDb : context.OntologyDb());
192 }
193
194
195 protected class SymFactAction extends FactAdapter {
196 public void factAddedEvent(FactEvent event) {
197 Fact f = event.getFact();
198 update(Node.ADD,f);
199 }
200 public void factDeletedEvent(FactEvent event) {
201 Fact f = event.getFact();
202 update(Node.REMOVE,f);
203 }
204 }
205
206 public void add(ReteKB kb) {
207 Rule[] rule = kb.getRules();
208 for(int i = 0; i < rule.length; i++ ) {
209 rule[i].setName(kb.getName() + "$" + rule[i].getName());
210 add(rule[i]);
211 }
212 }
213
214 public void add(Rule r) {
215 Node node = null;
216 Node[] term;
217 ReteFact token;
218 boolean found;
219 String path;
220 Pattern p;
221
222 r = r.duplicate(Fact.VAR,ontology().GenSym());
223
224 Core.DEBUG(2,"Compiling rule " + r.name);
225
226 term = new Node[r.nTerminals()];
227 int position = 0;
228 for(int i = 0; i < r.patterns.size(); i++, position++ ) {
229 p = (Pattern)r.patterns.elementAt(i);
230 switch(p.tag) {
231 case Pattern.TEST:
232 case Pattern.CMD:
233 position--;
234 break;
235
236 default:
237 path = PATH + (pathNo + position);
238 token = (ReteFact)p.data;
239
240
241
242 if ( roots.containsKey(token.type) ) {
243 term[position] = (Node)roots.get(token.type);
244 Core.DEBUG(4,"=t");
245 Core.DEBUG(5,"=t[" + term[position] + "]");
246 }
247 else {
248 term[position] = new TypeNode(this,token.type);
249 roots.put(token.type,term[position]);
250 Core.DEBUG(4,"+t");
251 Core.DEBUG(5,"+t[" + term[position] + "]");
252 }
253 term[position].use_count++;
254 node = term[position];
255
256
257
258 if ( p.id != null ) {
259 if ( ids.containsKey(p.id) ) {
260 term[position] = (Node)ids.get(p.id);
261 Core.DEBUG(4,"=i");
262 Core.DEBUG(5,"=i[" + term[position] + "]");
263 }
264 else {
265 term[position] = new IdNode(this,p.id);
266 ids.put(p.id,term[position]);
267 Core.DEBUG(4,"+i");
268 Core.DEBUG(5,"+i[" + term[position] + "]");
269 }
270 term[position].use_count++;
271 node.addSuccessor(path,term[position],Node.SINGLE);
272 node = term[position];
273 }
274
275
276
277 ValueFunction[] value = token.listValues();
278 String[] attribute = token.listAttributes();
279
280
281 Vector temp1 = new Vector();
282 String a;
283 ValueFunction v;
284
285 for(int k = 0; k < value.length; k++ ) {
286 if ( value[k].isDeterminate() ) {
287 term[position] =
288 new AttributeNode(this,attribute[k],value[k]);
289 found = false;
290 for(int j = 0; !found && j < singles.size(); j++ ) {
291 found = term[position].equals(singles.elementAt(j));
292 if (found)
293 term[position] = (Node)singles.elementAt(j);
294 }
295 if ( !found ) {
296 singles.addElement(term[position]);
297 Core.DEBUG(4,"+d");
298 Core.DEBUG(5,"+d[" + term[position] + "]");
299 }
300 else {
301 Core.DEBUG(4,"=d");
302 Core.DEBUG(5,"=d[" + term[position] + "]");
303 }
304 term[position].use_count++;
305 node.addSuccessor(path,term[position],Node.SINGLE);
306 node = term[position];
307 }
308 else {
309 temp1.addElement(attribute[k]);
310 temp1.addElement(value[k]);
311 }
312 }
313
314
315 for(int k = 0; k < temp1.size(); k += 2 ) {
316 a = (String)temp1.elementAt(k);
317 v = (ValueFunction)temp1.elementAt(k+1);
318 term[position] = new AttributeNode(this,a,v);
319 found = false;
320 for(int j = 0; !found && j < singles.size(); j++ ) {
321 found = term[position].equals(singles.elementAt(j));
322 if (found)
323 term[position] = (Node)singles.elementAt(j);
324 }
325 if ( !found ) {
326 singles.addElement(term[position]);
327 Core.DEBUG(4,"+n");
328 Core.DEBUG(5,"+n[" + term[position] + "]");
329 }
330 else {
331 Core.DEBUG(4,"=n");
332 Core.DEBUG(5,"=n[" + term[position] + "]");
333 }
334 term[position].use_count++;
335 node.addSuccessor(path,term[position],Node.SINGLE);
336 node = term[position];
337 }
338 break;
339 }
340 }
341
342
343
344
345
346
347 position = 0;
348 JoinNode[] jn = new JoinNode[term.length-1];
349
350 for(int i = 1; i < r.patterns.size(); i++, position++ ) {
351 p = (Pattern)r.patterns.elementAt(i);
352
353 switch( p.tag ) {
354 case Pattern.TEST:
355 case Pattern.CMD:
356 position--;
357 break;
358
359 default:
360 token = (ReteFact)p.data;
361
362 jn[position] = (p.tag == Pattern.NONE)
363 ? new JoinNode(this) : new NotNode(this);
364
365 ValueFunction[] r_value = token.listValues();
366 String[] r_attribute = token.listAttributes();
367
368 ValueFunction[] vars = token.variables();
369
370 int q = -1;
371 for(int j = 0; j < i; j++) {
372 p = (Pattern)r.patterns.elementAt(j);
373 if ( p.tag == Pattern.NONE ) {
374 q++;
375 token = (ReteFact)p.data;
376
377 ValueFunction[] l_value = token.listValues();
378 String[] l_attribute = token.listAttributes();
379
380 boolean[][] local =
381 new boolean[l_value.length][r_value.length];
382
383 for(int m = 0; m < local.length; m++ )
384 for(int n = 0; n < local[m].length; n++ )
385 local[m][n] = false;
386
387 for(int k = 0; k < vars.length; k++ ) {
388 for(int m = 0; m < l_value.length; m++ ) {
389 if ( l_value[m].references(vars[k]) ) {
390 for(int n = 0; n < r_value.length; n++ ) {
391 if ( !local[m][n] &&
392 r_value[n].references(vars[k]) ) {
393 local[m][n] = true;
394 jn[position].add(q,l_attribute[m],l_value[m],
395 0,r_attribute[n],r_value[n]);
396
397
398
399
400
401 }
402 }
403 }
404 }
405 }
406 }
407 }
408 break;
409 }
410 }
411
412
413
414
415 String rightPath;
416
417 Node leftNode = term[0];
418 String leftPath = PATH+pathNo;
419 position = 0;
420 for(int i = 1; i < r.patterns.size(); i++, position++ ) {
421 p = (Pattern)r.patterns.elementAt(i);
422
423 switch( p.tag ) {
424 case Pattern.CMD:
425 position--;
426 break;
427
428 case Pattern.TEST:
429 position--;
430 node = leftNode;
431 leftNode = new TestNode(this,(ValueFunction)p.data);
432 found = false;
433 for(int j = 0; !found && j < tests.size(); j++ ) {
434 found = leftNode.equals(tests.elementAt(j));
435 if (found) leftNode = (Node)tests.elementAt(j);
436 }
437 if ( !found ) {
438 tests.addElement(leftNode);
439 Core.DEBUG(4,"+c");
440 Core.DEBUG(5,"+c[" + leftNode + "]");
441 }
442 else {
443 Core.DEBUG(4,"=c");
444 Core.DEBUG(5,"=c[" + leftNode + "]");
445 }
446 leftNode.use_count++;
447 node.addSuccessor(leftPath,leftNode,Node.SINGLE);
448 break;
449
450 default:
451
452 found = false;
453 for(int j = 0; !found && j < joins.size(); j++ ) {
454 found = jn[position].equals(joins.elementAt(j));
455 if ( found ) jn[position] = (JoinNode)joins.elementAt(j);
456 }
457 if ( !found ) {
458 joins.addElement(jn[position]);
459 Core.DEBUG(4,"+j");
460 Core.DEBUG(5,"+j[" + jn[position] + "]");
461 }
462 else {
463 Core.DEBUG(4,"=j");
464 Core.DEBUG(5,"=j[" + jn[position] + "]");
465 }
466 jn[position].use_count++;
467 path = JPATH + (joinPathNo++);
468 rightPath = PATH+(pathNo+position+1);
469
470 jn[position].addPath(leftPath,rightPath,path);
471 leftNode.addSuccessor(leftPath,jn[position],Node.LEFT);
472 term[position+1].addSuccessor(rightPath,jn[position],Node.RIGHT);
473 leftNode = jn[position];
474 leftPath = path;
475 break;
476 }
477 }
478
479
480
481
482 ActionNode action = new ActionNode(this,r.name,r.salience,r.actions);
483 action.use_count++;
484 leftNode.addSuccessor(leftPath,action,Node.ACTION);
485 Core.DEBUG(4,"+a");
486 Core.DEBUG(5,"+a[" + action + "]");
487 pathNo += term.length;
488
489 String diagnostic = "ADD [" + action.rule_name + "]";
490 fireEvent(RULE_ADDED,action,diagnostic);
491 }
492
493
494 public void remove(Rule r) {
495 Core.USER_ERROR("Function ReteEngine.remove(Rule r) not yet implemented");
496 }
497
498
499 public void addLocalFactMonitor(LocalFactMonitor monitor) {
500 localMonitor.add(monitor);
501 }
502
503
504 public void removeLocalFactMonitor(LocalFactMonitor monitor) {
505 localMonitor.remove(monitor);
506 }
507
508
509 void fireLocalFactMonitor(int tag, Fact f) {
510 LocalFactMonitor monitor;
511 Enumeration enum = localMonitor.elements();
512 while( enum.hasMoreElements() ) {
513 monitor = (LocalFactMonitor)enum.nextElement();
514 if ( tag == Node.ADD )
515 monitor.reteFactAdded(f);
516 else
517 monitor.reteFactDeleted(f);
518 }
519 }
520
521
522 public void addMonitor(ReteEngineMonitor monitor, long event_type) {
523 if ( (event_type & ReteEngineEvent.ADD_MASK) != 0 )
524 eventMonitor[RULE_ADDED].add(monitor);
525 if ( (event_type & ReteEngineEvent.DELETE_MASK) != 0 )
526 eventMonitor[RULE_REMOVED].add(monitor);
527 if ( (event_type & ReteEngineEvent.ACTIVATE_MASK) != 0 )
528 eventMonitor[RULE_ACTIVATED].add(monitor);
529 if ( (event_type & ReteEngineEvent.DEACTIVATE_MASK) != 0 )
530 eventMonitor[RULE_DEACTIVATED].add(monitor);
531 if ( (event_type & ReteEngineEvent.FIRE_MASK) != 0 )
532 eventMonitor[RULE_FIRED].add(monitor);
533 }
534 public void removeMonitor(ReteEngineMonitor monitor, long event_type) {
535 if ( (event_type & ReteEngineEvent.ADD_MASK) != 0 )
536 eventMonitor[RULE_ADDED].remove(monitor);
537 if ( (event_type & ReteEngineEvent.DELETE_MASK) != 0 )
538 eventMonitor[RULE_REMOVED].remove(monitor);
539 if ( (event_type & ReteEngineEvent.ACTIVATE_MASK) != 0 )
540 eventMonitor[RULE_ACTIVATED].remove(monitor);
541 if ( (event_type & ReteEngineEvent.DEACTIVATE_MASK) != 0 )
542 eventMonitor[RULE_DEACTIVATED].remove(monitor);
543 if ( (event_type & ReteEngineEvent.FIRE_MASK) != 0 )
544 eventMonitor[RULE_FIRED].remove(monitor);
545 }
546
547
548 void fireEvent(int type, ActionNode node, String diagnostic) {
549 if ( eventMonitor[type].isEmpty() ) return;
550
551 ReteEngineMonitor monitor;
552 ReteEngineEvent event;
553 Enumeration enum = eventMonitor[type].elements();
554 switch(type) {
555 case RULE_ADDED:
556 event = new ReteEngineEvent(this,node.rule_name,node.salience,diagnostic,ReteEngineEvent.ADD_MASK);
557 while( enum.hasMoreElements() ) {
558 monitor = (ReteEngineMonitor)enum.nextElement();
559 monitor.reteRuleAddedEvent(event);
560 }
561 break;
562 case RULE_REMOVED:
563 event = new ReteEngineEvent(this,node.rule_name,node.salience,diagnostic,ReteEngineEvent.DELETE_MASK);
564 while( enum.hasMoreElements() ) {
565 monitor = (ReteEngineMonitor)enum.nextElement();
566 monitor.reteRuleDeletedEvent(event);
567 }
568 break;
569 case RULE_ACTIVATED:
570 event = new ReteEngineEvent(this,node.rule_name,node.salience,diagnostic,ReteEngineEvent.ACTIVATE_MASK);
571 while( enum.hasMoreElements() ) {
572 monitor = (ReteEngineMonitor)enum.nextElement();
573 monitor.reteRuleActivatedEvent(event);
574 }
575 break;
576 case RULE_DEACTIVATED:
577 event = new ReteEngineEvent(this,node.rule_name,node.salience,diagnostic,ReteEngineEvent.DEACTIVATE_MASK);
578 while( enum.hasMoreElements() ) {
579 monitor = (ReteEngineMonitor)enum.nextElement();
580 monitor.reteRuleDeactivatedEvent(event);
581 }
582 break;
583 case RULE_FIRED:
584 event = new ReteEngineEvent(this,node.rule_name,node.salience,diagnostic,ReteEngineEvent.FIRE_MASK);
585 while( enum.hasMoreElements() ) {
586 monitor = (ReteEngineMonitor)enum.nextElement();
587 monitor.reteRuleFiredEvent(event);
588 }
589 break;
590 }
591 }
592
593 }