Discussions

J2EE patterns: Simple Inference Engine

  1. Simple Inference Engine (4 messages)

    /* This pattern is defined here as a simple, reusable framework consisting of Rule, Question, and InferenceEngine classes. The <knowledgebase> is written in XML and is identical in format to Peter Hickman's Ruby implementation of this framework which includes a sample knowledge base(http://homepage.ntlworld.com/peterhi/sie.html).

    The format of the <knowledgebase> is:

    - <goal>, with a nested <attribute> and <text>. The attribute is set when the goal has been reached and the text will be displayed
    - <rules>, a collection of <rule> entries. Each <rule> has a <name>, <conditions>, and <actions>. Each embedded <condition> and <action> has an <attribute> and <value> pair. The <condition> must be true for a rule to pass, and the <action> will be asserted as being true if the rule has passed.
    - <questions>, a collection of <question> elements each with an <attribute>, a <question> to be presented and one or more possible <response> entries.

    The engine can be exercised in the following manner:
    URL testFile = (this.getClass().getResource("Test.xml"));
    InferenceEngine engine = new InferenceEngine(new File(testFile.getPath()));
    engine.run();
    engine.setChosenAnswer("yes");
    engine.run();
    engine.setChosenAnswer("no");
    engine.run();
    engine.setChosenAnswer("blue");
    engine.run();
    ...
    */
    import org.jdom.input.SAXBuilder;
    import org.jdom.Element;
    import org.jdom.Document;
    import org.jdom.JDOMException;

    import java.util.*;
    import java.io.File;

    class Rule {
        private String name = null;
        private Hashtable conditions = null;
        private Hashtable actions = null;
        private boolean active = true;

        Rule(String name, Hashtable conditions, Hashtable actions) {
            this.name = name;
            this.conditions = conditions;
            this.actions = actions;
        }

        void setInactive() {
            active = false;
        }

        public String getName() {
            return name;
        }

        public Hashtable getConditions() {
            return conditions;
        }

        public Hashtable getActions() {
            return actions;
        }

        public boolean isActive() {
            return active;
        }
    }

    class Question {
        private String text = null;
        private Object responses = null;

        Question(String text, Object responses) {
            this.text = text;
            this.responses = responses;
        }

        public String getText() {
            return text;
        }

        public void setText(String text) {
            this.text = text;
        }

        public Object getResponses() {
            return responses;
        }

        public void setResponses(Object responses) {
            this.responses = responses;
        }
    }

    public class InferenceEngine {
        static public int ERROR = 0;
        static public int MORE = 1;
        static public int COMPLETE = 2;
        static public int FAILED = 3;

        private ArrayList rules = null;
        private Hashtable questions = null;
        private String goalVariable = null;
        private String goalDescription = null;
        private Hashtable knowledge = new Hashtable();
        private String answeredRuleAttribute = null;
        private String messageForQuerent = null;
        private ArrayList possibleResponses = null;
        private String chosenAnswer = null;
        private int status;
        private String logtext = null;

        public InferenceEngine(File file) {

            SAXBuilder builder = new SAXBuilder();
            Element inputRootElement = null;
            try {
                Document inputDocument = builder.build(file);
                inputRootElement = inputDocument.getRootElement();
            } catch (JDOMException e) {
                e.printStackTrace();
            }

            Iterator children = inputRootElement.getChildren().iterator();
            while (children.hasNext()) {
                Element child = (Element) children.next();
                if (child.getName().equals("goal")) {
                    goalVariable = child.getChild("attribute").getText();
                    goalDescription = child.getChild("text").getText();
                } else if (child.getName().equals("rules")) {
                    rules = readrules(child);
                } else if (child.getName().equals("questions")) {
                    questions = readquestions(child);
                }
            }

            Iterator ruleSet = rules.iterator();
            while (ruleSet.hasNext()) {
                Rule rule = (Rule) ruleSet.next();
                Enumeration keys = null;
                Hashtable conditions = rule.getConditions();
                keys = conditions.keys();
                while (keys.hasMoreElements()) {
                    knowledge.put(keys.nextElement(), "");
                }
                Hashtable actions = rule.getConditions();
                keys = actions.keys();
                while (keys.hasMoreElements()) {
                    knowledge.put(keys.nextElement(), "");
                }
            }
                Enumeration keys = knowledge.keys();

                while (keys.hasMoreElements()) {
                    System.out.println((String)keys.nextElement());

                }
            logging("Reading knowledge base from " + file.getAbsolutePath());
            logging("");
            logging("There are " + rules.size() + " rules");
            logging("There are " + questions.size() + " questions");
            logging("There are " + knowledge.size() + " attributes");
            logging("");
            System.out.println(log());
        }

        public String log() {
            String text = new String(logtext);
            logtext = "";
            return text;
        }

        public int run() {
            boolean didsomething = false;

            if (answeredRuleAttribute != null) {
                makeknown(answeredRuleAttribute, chosenAnswer);
                didsomething = true;
            }

            if (goalset()) {
                status = COMPLETE;
                return status;
            }

            Iterator ruleSet = rules.iterator();
            while (ruleSet.hasNext()) {
                Rule rule = (Rule) ruleSet.next();
                if (rule.isActive()) {
                    logging("\nExamining rule " + rule.getName());
                    boolean ok = true;
                    Hashtable conditions = rule.getConditions();
                    Enumeration keys;
                    keys = conditions.keys();
                    while (keys.hasMoreElements()) {
                        String key = (String) keys.nextElement();
                        if ((knowledge.get(key)).equals("")) {
                            if (!questions.containsKey(key)) {
                                logging("Rule cannot be resolved at present");
                                ok = false;
                                break;
                            }
                        }
                    }
                    if (ok) {
                        keys = conditions.keys();
                        while (keys.hasMoreElements()) {
                            String key = (String) keys.nextElement();
                            if ((knowledge.get(key)).equals("")) {
                                if (questions.containsKey(key)) {
                                    Question question = (Question) questions.get(key);
                                    logging("Question is " + question.getText());
                                    answeredRuleAttribute = key;
                                    messageForQuerent = question.getText();
                                    possibleResponses = (ArrayList) question.getResponses();
                                    status = MORE;
                                    return status;
                                }
                            }
                        }
                    }
                    if (ok) {
                        logging("Rule passed");
                        Hashtable actions = rule.getActions();
                        Enumeration actionSet = actions.keys();
                        while (actionSet.hasMoreElements()) {
                            String actionKey = (String) actionSet.nextElement();
                            makeknown(actionKey, (String) actions.get(actionKey));
                        }
                        rule.setInactive();
                        didsomething = true;
                        if (goalset()) {
                            status = COMPLETE;
                            return status;
                        }
                    }
                }
            }

            if (goalset()) {
                status = COMPLETE;
            } else if (didsomething == false) {
                messageForQuerent = "Failed";
                status = FAILED;
            } else {
                // we did something but have nothing to ask the user, recurse!
                status = run();
            }

            return status;
        }

        private boolean goalset() {
            if ((knowledge.get(goalVariable) != null)) {
                logging("\nThe goal " + goalVariable + " has been set");
                logging(theansweris());

                messageForQuerent = theansweris();

                return true;
            } else {
                return false;
            }
        }


        void makeknown(String attribute, String value) {
            logging("Setting " + attribute + " to " + value);

            knowledge.put(attribute, value);

            Iterator ruleSet = rules.iterator();
            while (ruleSet.hasNext()) {
                Rule rule = (Rule) ruleSet.next();
                if (rule.isActive()) {
                    if (rule.getConditions().containsKey(attribute)) {
                        if (!rule.getConditions().get(attribute).equals(value)) {
                            logging("Rule " + rule.getName() + " is now inactive");
                            rule.setInactive();
                        }
                    }
                }
            }
        }

        public String getMessageForQuerent() {
            return messageForQuerent;
        }

        public ArrayList getPossibleResponses() {
            return possibleResponses;
        }

        public void setChosenAnswer(String chosenAnswer) {
            this.chosenAnswer = chosenAnswer;
        }

        void logging(String message) {
            logtext = logtext + message + "\n";
        }

        String theansweris() {
            StringTokenizer tokenizer = new StringTokenizer(goalDescription);
            String response = "";
            while (tokenizer.hasMoreTokens()) {
                String token = tokenizer.nextToken();
                if (token.equals(goalVariable)) {
                    response = response + knowledge.get(token);
                } else {
                    response = response + token;
                }
                response = response + " ";
            }
            return response;
        }

        Hashtable readrulescora(Element element, String text) {
            Hashtable data = new Hashtable();

            Iterator children = element.getChildren().iterator();
            while (children.hasNext()) {
                Element child = (Element) children.next();
                String name = child.getChild("attribute").getText();
                String value = child.getChild("value").getText();
                data.put(name, value);
            }

            return data;
        }

        ArrayList readrules(Element element) {
            ArrayList rules = new ArrayList();
            Hashtable conds = null;
            Hashtable acts = null;
            String name = null;
            Iterator children = element.getChildren().iterator();
            while (children.hasNext()) {
                Element child = (Element) children.next();
                if (child.getName().equals("rule")) {
                    name = child.getChild("name").getText();
                    Iterator conditions = child.getChildren("conditions").iterator();
                    while (conditions.hasNext()) {
                        conds = readrulescora((Element) conditions.next(), "condition");
                    }
                    Iterator actions = child.getChildren("actions").iterator();
                    while (actions.hasNext()) {
                        acts = readrulescora((Element) actions.next(), "action");
                    }
                }
                rules.add(new Rule(name, conds, acts));
            }
            return rules;
        }

        Hashtable readquestions(Element element) {
            Hashtable questions = new Hashtable();
            Iterator quests = element.getChildren("question").iterator();
            while (quests.hasNext()) {
                Element question = (Element) quests.next();
                String name = question.getChild("attribute").getText();
                String value = question.getChild("text").getText();
                ArrayList responses = new ArrayList();
                Iterator resps = question.getChildren("response").iterator();
                while (resps.hasNext()) {
                    Element response = (Element) resps.next();
                    responses.add(response.getText());
                }
                questions.put(name, new Question(value, responses));
            }
            return questions;
        }

    }

    Threaded Messages (4)

  2. Simple Inference Engine- xml jar[ Go to top ]

    What JAR files are you using for XML parsing?
  3. Message Driven[ Go to top ]

    I am currenly using a similar pattern, for Message Driven Components
    in a Transacction Monitor Server in C++ and work very fine. There are another similar Patterns for a Message Driven Java Beans using State and Events, and a Inference Engine for rule based paradigm.
  4. Help Required[ Go to top ]

    Want more details on how to run the Inference Engine.
  5. Novice[ Go to top ]

    Need more information on compiling Inference engine. Any reference packages required? Is the above code complete (Inference Engine). Please help me. Waiting for your reply.