All Downloads are FREE. Search and download functionalities are using the official Maven repository.

jason.asSemantics.Agent Maven / Gradle / Ivy

Go to download

Jason is a fully-fledged interpreter for an extended version of AgentSpeak, a BDI agent-oriented logic programming language.

There is a newer version: 2.3
Show newest version
// ----------------------------------------------------------------------------
// Copyright (C) 2003 Rafael H. Bordini, Jomi F. Hubner, et al.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
// To contact the authors:
// http://www.inf.ufrgs.br/~bordini
// http://www.das.ufsc.br/~jomi
//
//----------------------------------------------------------------------------

package jason.asSemantics;

import jason.JasonException;
import jason.RevisionFailedException;
import jason.architecture.AgArch;
import jason.asSyntax.ASSyntax;
import jason.asSyntax.ArithFunctionTerm;
import jason.asSyntax.InternalActionLiteral;
import jason.asSyntax.Literal;
import jason.asSyntax.LogicalFormula;
import jason.asSyntax.Plan;
import jason.asSyntax.PlanLibrary;
import jason.asSyntax.Rule;
import jason.asSyntax.Term;
import jason.asSyntax.Trigger;
import jason.asSyntax.Trigger.TEOperator;
import jason.asSyntax.Trigger.TEType;
import jason.asSyntax.directives.FunctionRegister;
import jason.asSyntax.directives.Include;
import jason.asSyntax.parser.ParseException;
import jason.asSyntax.parser.as2j;
import jason.bb.BeliefBase;
import jason.bb.DefaultBeliefBase;
import jason.functions.Count;
import jason.functions.RuleToFunction;
import jason.mas2j.ClassParameters;
import jason.profiling.QueryProfiling;
import jason.runtime.Settings;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Queue;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.w3c.dom.Document;
import org.w3c.dom.Element;



/**
 * The Agent class has the belief base and plan library of an
 * AgentSpeak agent. It also implements the default selection
 * functions of the AgentSpeak semantics.
 */
public class Agent {

    // Members
    protected BeliefBase       bb = null;
    protected PlanLibrary      pl = null;
    protected TransitionSystem ts = null;
    protected String           aslSource = null;
    
    private List      initialGoals = null; // initial goals in the source code
    private List      initialBels  = null; // initial beliefs in the source code

    private Map internalActions = null;
    private Map  functions       = null;
    
    private boolean hasCustomSelOp = true;
    
    private ScheduledExecutorService scheduler = null; 

    //private QueryCache qCache = null;
    private QueryCacheSimple qCache = null;
    private QueryProfiling    qProfiling = null;
    
    protected Logger logger = Logger.getLogger(Agent.class.getName());

    public Agent() {
        checkCustomSelectOption();
    }
    
    /**
     * Setup the default agent configuration.
     * 
     * Creates the agent class defined by agClass, default is jason.asSemantics.Agent. 
     * Creates the TS for the agent.
     * Creates the belief base for the agent. 
     */
    public static Agent create(AgArch arch, String agClass, ClassParameters bbPars, String asSrc, Settings stts) throws JasonException {
        try {
            Agent ag = (Agent) Class.forName(agClass).newInstance();
            
            new TransitionSystem(ag, null, stts, arch);

            BeliefBase bb = (BeliefBase) Class.forName(bbPars.getClassName()).newInstance();
            ag.setBB(bb);     // the agent's BB have to be already set for the BB initialisation
            ag.initAg();

            bb.init(ag, bbPars.getParametersArray());  
            ag.load(asSrc); // load the source code of the agent
            return ag;
        } catch (Exception e) {
            throw new JasonException("as2j: error creating the customised Agent class! - ", e);
        }
    }



    /** Initialises the TS and other components of the agent */
    public void initAg() {
        if (bb == null) bb = new DefaultBeliefBase();
        if (pl == null) pl = new PlanLibrary();
        
        if (initialGoals == null) initialGoals = new ArrayList();
        if (initialBels  == null) initialBels  = new ArrayList(); 

        if (internalActions == null) internalActions = new HashMap();
        initDefaultFunctions();
        
        if (ts == null) ts = new TransitionSystem(this, null, null, new AgArch());
        
        //if (ts.getSettings().hasQueryCache()) qCache = new QueryCache(this);
        if (ts.getSettings().hasQueryProfiling()) qProfiling = new QueryProfiling(this);
        if (ts.getSettings().hasQueryCache())     qCache = new QueryCacheSimple(this, qProfiling);
    }
    
    
    /** parse and load the agent code, asSrc may be null */
    public void initAg(String asSrc) throws JasonException {
        initAg();
        load(asSrc);
    }
    
    /** parse and load the agent code, asSrc may be null */
    public void load(String asSrc) throws JasonException {
        // set the agent
        try {
            boolean parsingOk = true;
            if (asSrc != null) {
                asSrc = asSrc.replaceAll("\\\\", "/");
                setASLSrc(asSrc);
    
                if (asSrc.startsWith(Include.CRPrefix)) {
                    // loads the class from a jar file (for example)
                    parseAS(Agent.class.getResource(asSrc.substring(Include.CRPrefix.length())).openStream());
                } else {
                    // check whether source is an URL string
                    try {
                        parsingOk = parseAS(new URL(asSrc));
                    } catch (MalformedURLException e) {
                        parsingOk = parseAS(new File(asSrc));
                    }
                }
            }

            
            if (parsingOk) {
                if (getPL().hasMetaEventPlans())
                    getTS().addGoalListener(new GoalListenerForMetaEvents(getTS()));
                
                addInitialBelsFromProjectInBB();
                addInitialBelsInBB();
                addInitialGoalsFromProjectInBB();
                addInitialGoalsInTS();
                fixAgInIAandFunctions(this); // used to fix agent reference in functions used inside includes
            }
            
            // kqml Plans at the end of the ag PS
            if (JasonException.class.getResource("/asl/kqmlPlans.asl") != null) { 
                setASLSrc("kqmlPlans.asl");
                parseAS(JasonException.class.getResource("/asl/kqmlPlans.asl"));
                setASLSrc(asSrc);
            } else {
                logger.warning("The kqmlPlans.asl was not found!");
            }
        } catch (Exception e) {
            logger.log(Level.SEVERE, "Error creating customised Agent class!", e);
            throw new JasonException("Error creating customised Agent class! - " + e);
        }
    }
    
    /** @deprecated Prefer the initAg method with only the source code of the agent as parameter.
     *  
     *  A call of this method like
     *     
     *     TransitionSystem ts = ag.initAg(arch, bb, asSrc, stts)
     *     
* can be replaced by *
     *     new TransitionSystem(ag, new Circumstance(), stts, arch);
     *     ag.setBB(bb); // only if you use a custom BB
     *     ag.initAg(asSrc);
     *     TransitionSystem ts = ag.getTS();
     *     
*/ public TransitionSystem initAg(AgArch arch, BeliefBase bb, String asSrc, Settings stts) throws JasonException { try { if (bb != null) setBB(bb); new TransitionSystem(this, null, stts, arch); initAg(asSrc); return ts; } catch (Exception e) { logger.log(Level.SEVERE, "Error creating the agent class!", e); throw new JasonException("Error creating the agent class! - " + e); } } public void stopAg() { bb.stop(); if (qProfiling != null) qProfiling.show(); if (scheduler != null) scheduler.shutdownNow(); for (InternalAction ia: internalActions.values()) try { ia.destroy(); } catch (Exception e) { e.printStackTrace(); } } /** * Clone BB, PL, Circumstance. * A new TS is created (based on the cloned circumstance). */ public Agent clone(AgArch arch) { Agent a = null; try { a = this.getClass().newInstance(); } catch (InstantiationException e1) { logger.severe(" cannot create derived class" +e1); return null; } catch (IllegalAccessException e2) { logger.severe(" cannot create derived class" +e2); return null; } a.setLogger(arch); if (this.getTS().getSettings().verbose() >= 0) a.logger.setLevel(this.getTS().getSettings().logLevel()); a.bb = this.bb.clone(); a.pl = this.pl.clone(); try { fixAgInIAandFunctions(a); } catch (Exception e) { e.printStackTrace(); } a.aslSource = this.aslSource; a.internalActions = new HashMap(); a.setTS(new TransitionSystem(a, this.getTS().getC().clone(), this.getTS().getSettings(), arch)); if (a.getPL().hasMetaEventPlans()) a.getTS().addGoalListener(new GoalListenerForMetaEvents(a.getTS())); a.initAg(); //for initDefaultFunctions() and for overridden/custom agent return a; } private void fixAgInIAandFunctions(Agent a) throws Exception { // find all internal actions and functions and change the pointer for agent for (Plan p: a.getPL()) { // search context if (p.getContext() instanceof Literal) fixAgInIAandFunctions(a, (Literal)p.getContext()); // search body if (p.getBody() instanceof Literal) fixAgInIAandFunctions(a, (Literal)p.getBody()); } } private void fixAgInIAandFunctions(Agent a, Literal l) throws Exception { // if l is internal action/function if (l instanceof InternalActionLiteral) { ((InternalActionLiteral)l).setIA(null); // reset the IA in the literal, the IA there will be updated next getIA call } if (l instanceof ArithFunctionTerm) { ((ArithFunctionTerm)l).setAgent(a); } if (l instanceof Rule) { LogicalFormula f = ((Rule)l).getBody(); if (f instanceof Literal) { fixAgInIAandFunctions(a, (Literal)f); } } for (int i=0; i(); addFunction(Count.class, false); } /** register an arithmetic function implemented in Java */ public void addFunction(Class c) { addFunction(c,true); } /** register an arithmetic function implemented in Java */ private void addFunction(Class c, boolean user) { try { ArithFunction af = c.newInstance(); String error = null; if (user) error = FunctionRegister.checkFunctionName(af.getName()); if (error != null) logger.warning(error); else functions.put(af.getName(),af); } catch (Exception e) { logger.log(Level.SEVERE, "Error registering function "+c.getName(),e); } } /** register an arithmetic function implemented in AS (by a rule, literal, or internal action) */ public void addFunction(String function, int arity, String literal) { try { String error = FunctionRegister.checkFunctionName(function); if (error != null) logger.warning(error); else functions.put(function, new RuleToFunction(literal, arity)); } catch (Exception e) { logger.log(Level.SEVERE, "Error registering function "+literal,e); } } /** get the object the implements the arithmetic function function/arity, * either global (like math.max) or local (like .count). */ public ArithFunction getFunction(String function, int arity) { if (functions == null) return null; ArithFunction af = functions.get(function); if (af == null || !af.checkArity(arity)) // try global function af = FunctionRegister.getFunction(function, arity); if (af != null && af.checkArity(arity)) return af; else return null; } /** Belief b will be stored to be included as an ordinary belief when the agent will start running. * This method is usually called by the parser; at compile time, when the TS may not be ready yet and thus * no events can be produced. Beliefs are then scheduled here to be definitely included later when the * TS is ready. */ public void addInitialBel(Literal b) { initialBels.add(b); } public List getInitialBels() { return initialBels; } /** add the initial beliefs in BB and produce the corresponding events */ public void addInitialBelsInBB() throws RevisionFailedException { // Once beliefs are stored in a Stack in the BB, insert them in inverse order for (int i=initialBels.size()-1; i >=0; i--) { Literal b = initialBels.get(i); // if l is not a rule and has free vars (like l(X)), convert it into a rule like "l(X) :- true." if (!b.isRule() && !b.isGround()) b = new Rule(b,Literal.LTrue); b.apply(new Unifier()); // to solve arithmetic expressions // does not do BRF for rules (and so do not produce events +bel for rules) if (b.isRule()) getBB().add(b); else addBel(b); } initialBels.clear(); } protected void addInitialBelsFromProjectInBB() { String sBels = getTS().getSettings().getUserParameter("beliefs"); if (sBels != null) { try { for (Term t: ASSyntax.parseList("["+sBels+"]")) { getBB().add((Literal)t); } } catch (Exception e) { logger.log(Level.WARNING, "Initial beliefs from project '["+sBels+"]' is not a list of literals."); } } } /** goal g will be stored to be included as an initial goal when the agent will start running */ public void addInitialGoal(Literal g) { initialGoals.add(g); } /** includes all initial goals in the agent reasoner */ public void addInitialGoalsInTS() { for (Literal g: initialGoals) { g.makeVarsAnnon(); if (! g.hasSource()) g.addAnnot(BeliefBase.TSelf); getTS().getC().addAchvGoal(g,Intention.EmptyInt); } } protected void addInitialGoalsFromProjectInBB() { String sGoals = getTS().getSettings().getUserParameter("goals"); if (sGoals != null) { try { for (Term t: ASSyntax.parseList("["+sGoals+"]")) { Literal g = (Literal)t; g.makeVarsAnnon(); if (! g.hasSource()) g.addAnnot(BeliefBase.TSelf); getTS().getC().addAchvGoal(g,Intention.EmptyInt); } } catch (Exception e) { logger.log(Level.WARNING, "Initial goals from project '["+sGoals+"]' is not a list of literals."); } } } /** Imports beliefs, plans and initial goals from another agent. Initial beliefs and goals * are stored in "initialBels" and "initialGoals" lists but not included in the BB / TS. * The methods addInitialBelsInBB and addInitialGoalsInTS should be called in the sequel to * add those beliefs and goals into the agent. */ public void importComponents(Agent a) throws JasonException { if (a != null) { for (Literal b: a.initialBels) { this.addInitialBel(b); try { fixAgInIAandFunctions(this,b); } catch (Exception e) { e.printStackTrace(); } } for (Literal g: a.initialGoals) this.addInitialGoal(g); for (Plan p: a.getPL()) this.getPL().add(p, false); if (getPL().hasMetaEventPlans()) getTS().addGoalListener(new GoalListenerForMetaEvents(getTS())); } } /** * Follows the default implementation for the agent's message acceptance * relation and selection functions */ public boolean socAcc(Message m) { return true; } /** Returns true if this agent accepts to be killed by another agent called agName. * This method can be overridden to customize this option. */ public boolean killAcc(String agName) { //System.out.println("I am being killed by "+agName+", but that is ok..."); return true; } public Event selectEvent(Queue events) { // make sure the selected Event is removed from 'events' queue return events.poll(); } public Option selectOption(List

In its return, List[0] has the list of actual additions to * the belief base, and List[1] has the list of actual deletions; * this is used to generate the appropriate internal events. If * nothing change, returns null. */ @SuppressWarnings("unchecked") public List[] brf(Literal beliefToAdd, Literal beliefToDel, Intention i, boolean addEnd) throws RevisionFailedException { // This class does not implement belief revision! It // is supposed that a subclass will do it. // It simply add/del the belief. int position = 0; // add in the begin if (addEnd) position = 1; List[] result = null; try { if (beliefToAdd != null) { if (logger.isLoggable(Level.FINE)) logger.fine("Adding belief " + beliefToAdd); if (getBB().add(position, beliefToAdd)) { result = new List[2]; result[0] = Collections.singletonList(beliefToAdd); result[1] = Collections.emptyList(); } } if (beliefToDel != null) { Unifier u = null; try { u = i.peek().unif; // get from current intention } catch (Exception e) { u = new Unifier(); } if (logger.isLoggable(Level.FINE)) logger.fine("Doing brf for " + beliefToDel + " in BB=" + believes(beliefToDel, u)); boolean removed = getBB().remove(beliefToDel); if (!removed && !beliefToDel.isGround()) { // then try to unify the parameter with a belief in BB if (believes(beliefToDel, u)) { beliefToDel.apply(u); removed = getBB().remove(beliefToDel); } } if (removed) { if (logger.isLoggable(Level.FINE)) logger.fine("Removed:" + beliefToDel); if (result == null) { result = new List[2]; result[0] = Collections.emptyList(); } result[1] = Collections.singletonList(beliefToDel); } } } catch (Exception e) { logger.log(Level.WARNING, "Error at BRF.",e); } return result; } /** * Adds bel in belief base (calling brf) and generates the * events. If bel has no source, add * source(self). (the belief is not cloned!) */ public boolean addBel(Literal bel) throws RevisionFailedException { if (!bel.hasSource()) { bel.addAnnot(BeliefBase.TSelf); } List[] result = brf(bel, null, Intention.EmptyInt); if (result != null && ts != null) { ts.updateEvents(result, Intention.EmptyInt); return true; } else { return false; } } /** * If the agent believes in bel, removes it (calling brf) * and generate the event. */ public boolean delBel(Literal bel) throws RevisionFailedException { if (!bel.hasSource()) { bel.addAnnot(BeliefBase.TSelf); } List[] result = brf(null, bel, Intention.EmptyInt); if (result != null && ts != null) { ts.updateEvents(result, Intention.EmptyInt); return true; } else { return false; } } /** Removes all occurrences of bel in BB. If un is null, an empty Unifier is used. */ public void abolish(Literal bel, Unifier un) throws RevisionFailedException { List toDel = new ArrayList(); if (un == null) un = new Unifier(); Iterator il = getBB().getCandidateBeliefs(bel, un); if (il != null) { while (il.hasNext()) { Literal inBB = il.next(); if (!inBB.isRule()) { // need to clone unifier since it is changed in previous iteration if (un.clone().unifiesNoUndo(bel, inBB)) { toDel.add(inBB); } } } } for (Literal l: toDel) { delBel(l); } } private void checkCustomSelectOption() { hasCustomSelOp = false; for (Method m: this.getClass().getMethods()) { if (!m.getDeclaringClass().equals(Agent.class) && m.getName().equals("selectOption")) { hasCustomSelOp = true; } } } public boolean hasCustomSelectOption() { return hasCustomSelOp; } static DocumentBuilder builder = null; /** Gets the agent "mind" (beliefs, plans, and circumstance) as XML */ public Document getAgState() { if (builder == null) { try { builder = DocumentBuilderFactory.newInstance().newDocumentBuilder(); } catch (Exception e) { logger.log(Level.SEVERE, "Error creating XML builder\n"); return null; } } Document document = builder.newDocument(); document.appendChild(document.createProcessingInstruction("xml-stylesheet", "href='http://jason.sf.net/xml/agInspection.xsl' type='text/xsl' ")); Element ag = getAsDOM(document); document.appendChild(ag); ag.appendChild(ts.getC().getAsDOM(document)); return document; } @Override public String toString() { return "Agent "+getASLSrc(); } /** Gets the agent "mind" as XML */ public Element getAsDOM(Document document) { Element ag = (Element) document.createElement("agent"); ag.setAttribute("name", ts.getUserAgArch().getAgName()); ag.setAttribute("cycle", ""+ts.getUserAgArch().getCycleNumber()); ag.appendChild(bb.getAsDOM(document)); // ag.appendChild(ps.getAsDOM(document)); return ag; } /** Gets the agent program (Beliefs and plans) as XML */ public Document getAgProgram() { if (builder == null) { try { builder = DocumentBuilderFactory.newInstance().newDocumentBuilder(); } catch (Exception e) { logger.log(Level.SEVERE, "Error creating XML builder\n"); return null; } } Document document = builder.newDocument(); Element ag = (Element) document.createElement("agent"); if (getASLSrc() != null && getASLSrc().length() > 0) { ag.setAttribute("source", getASLSrc()); } ag.appendChild(bb.getAsDOM(document)); ag.appendChild(pl.getAsDOM(document)); document.appendChild(ag); return document; } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy