1 /*********************************************************************
2 Copyright 2012, Ralph Ronnquist.
4 This file is part of GORITE.
6 GORITE is free software: you can redistribute it and/or modify it
7 under the terms of the Lesser GNU General Public License as published
8 by the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
11 GORITE is distributed in the hope that it will be useful, but WITHOUT
12 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
14 License for more details.
16 You should have received a copy of the Lesser GNU General Public
17 License along with GORITE. If not, see <http://www.gnu.org/licenses/>.
18 **********************************************************************/
20 package com.intendico.data;
22 import java.util.Observable;
23 import java.util.Observer;
24 import java.util.Vector;
25 import java.util.HashSet;
26 import java.util.Iterator;
29 * A RuleSet is a reason maintenance unit, which attempts to uphold
30 * given rules. In normal use, the RuleSet is populated with some
31 * number of Rule objects, via either {@link #add(Rule)} or {@link
32 * #add(Query,Query)}, which tie the {@link Rule} objects to the
33 * RuleSet. Each {@link Rule} object, qua {@link Observer}, gets
34 * notified about possible changes by their antecedent source , which
35 * result in them invoking the {@link #activate} method. The RuleSet
36 * {@link #run} method then pops and processes all activated rules to
37 * achieve their belief propagation effects.
39 public class RuleSet extends Observable implements Runnable {
42 * Utility class to observe source update
44 class RuleObserver implements Observer {
47 * The {@link Rule} concerned.
54 RuleObserver(Rule r) {
59 * Implements {@link Observer#update} by activating the rule
60 * concerned. However, if the {@link Rule} is not contained in
61 * {@link #all_rules} then this observer just deletes itself
62 * from the calling {@link Observable}.
64 public void update(Observable x,Object y) {
65 if ( ! all_rules.contains( rule ) ) {
66 x.deleteObserver( this );
73 * Returns a String representation of this object.
75 public String toString() {
76 return "RuleObserver: " + rule;
81 * The collection of {@link Rule} objects explicitly added to this
84 public HashSet/*<Rule>*/ all_rules = new HashSet/*<Rule>*/();
87 * The current set of activated rules.
89 public HashSet/*<Rule>*/ active = new HashSet/*<Rule>*/();
92 * Utility method to activate a {@link Rule} in this RuleSet. This
93 * includes adding the {@link Rule} to the {@link #active}
94 * collection, then both {@link Object#notify} on that object, and
95 * invoke {@link Observable#notifyObservers} to signal that this
96 * RuleSet has activated rules.
99 public void activate(Rule r) {
100 synchronized ( active ) {
101 if ( ! active.contains( r ) ) {
111 * Returns true if there are any activated rules.
113 public boolean hasActive() {
114 return active.size() > 0;
118 * This is a flag to signal that the run method should keep
119 * waiting for next update rather than returning.
121 public boolean wait = false;
124 * The reset method calls {@link Rule#reset} on all given rules so
125 * as to reset their antecedent snapshots.
127 public void reset(Vector/*<Rule>*/ rules) throws Exception {
128 for ( Iterator/*<Rule>*/ i = rules.iterator(); i.hasNext(); ) {
129 Rule r = (Rule) i.next();
135 * The propagate method calls {@link Rule#propagate} on all rules
136 * so as to apply the rules for all their new bindings, which
137 * previosuly have been snapshot by {@link Rule#reset} calls.
139 public void propagate(Vector/*<Rule>*/ rules) throws Exception {
140 for ( Iterator/*<Rule>*/ i = rules.iterator(); i.hasNext(); ) {
141 Rule r = (Rule) i.next();
147 * Returns a String representation of this RuleSet.
149 public String toString() {
150 StringBuilder s = new StringBuilder();
152 boolean first = true;
153 for ( Iterator/*<Rule>*/ i = all_rules.iterator(); i.hasNext(); ) {
154 Rule r = (Rule) i.next();
159 s.append( r.toString() );
166 * Utility method to add a {@link Rule} object and tie it to this
169 public void add(Rule r) {
170 if ( all_rules.contains( r ) ) {
174 r.antecedent.addObserver( new RuleObserver( r ) );
178 * Utility method to create a new {@link Rule} object with given
179 * antecedent and consequent {@link Query} objects, and add it to
182 public void add(Query a,Query c) {
183 add( new Rule( a, c ) );
187 * Deactivates this rule.
189 public void cancel(Rule r) {
190 all_rules.remove( r );
194 * Utility method that adds all currently active rules to a
195 * {@link Vector}, and clears the active set.
197 public boolean popActivated(Vector/*<Rule>*/ v,boolean w) {
198 synchronized ( active ) {
199 while ( active.size() == 0 ) {
203 } catch (InterruptedException e) {
216 /// Runnable implementation
220 * Utility method to keep refreshing the rules if and while there
221 * are source updates. The {@link #wait} flag controls whether
222 * this method should block and wait for a new update (true) or
223 * return (false) when a propagation session ends. Note that if
224 * there are rules to propagate competing assertions in a cyclic
225 * manner, then the propagation will not end and the overall
226 * application will suffer badly.
230 Vector/*<Rule>*/ rules = new Vector/*<Rule>*/();
232 if ( ! popActivated( rules, wait ) )
238 } catch (Exception e) {