astra.core.Agent Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of astra-interpreter Show documentation
Show all versions of astra-interpreter Show documentation
Core interpreter artifact for the ASTRA Language
package astra.core;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Observable;
import java.util.Queue;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import astra.event.Event;
import astra.event.GoalEvent;
import astra.event.ScopedBeliefEvent;
import astra.event.ScopedGoalEvent;
import astra.formula.Formula;
import astra.formula.Goal;
import astra.formula.Predicate;
import astra.formula.ScopedGoal;
import astra.messaging.AstraMessage;
import astra.messaging.MessageEvent;
import astra.reasoner.NewReasoner;
import astra.reasoner.Queryable;
import astra.reasoner.Reasoner;
import astra.term.ListTerm;
import astra.term.Performative;
import astra.term.Primitive;
import astra.term.Term;
import astra.tr.Function;
import astra.tr.TRContext;
import astra.trace.TraceEvent;
import astra.trace.TraceManager;
public class Agent extends Observable implements Queryable {
// Agent Registry
private static Map agents = new HashMap<>();
private static List listeners = new ArrayList<>();
public static void addRegistryListener(AgentRegistryListener listener) {
listeners.add(listener);
}
/**
* Interface used by external objects that wish to receive updates about new agents
*/
public static interface AgentRegistryListener {
void receive(Agent agent);
}
// static {
// try {
// out = new PrintWriter(new FileWriter("agents.log"));
// } catch (IOException e) {
// e.printStackTrace();
// }
// }
// public static PrintWriter out;
public static final Map timings = Collections.synchronizedMap(new HashMap());
public static final Map iterations = Collections.synchronizedMap(new HashMap());
/**
* This class models the notifications that are generated when an asynchronously executed action
* completes. Receipt of an instance of this class allows the agent to resume or fail the associated
* intention.
*
* @author Rem Collier
*
*/
public static class Notification {
Intention intention;
String message;
Throwable th;
public Notification(Intention intention, String message) {
this.intention = intention;
this.message = message;
}
public Notification(Intention Intention, String message, Throwable th) {
this.intention = Intention;
this.message = message;
this.th = th;
}
public void evaluate() {
if (message != null) {
intention.failed(message, th);
}
intention.resume();
}
}
/**
* Promises are used to implement WAIT statements. When one of these statements is
* executed, the agent creates a promise and suspends the intention. Promises are
* evaluated on each iteration. When a promise is fulfilled (i.e. the associated
* formula is matched), the agent executes the associated act(ion) which typically
* resumes the intention.
*
* @author Rem
*
*/
public abstract static class Promise {
public boolean isTrue;
public Promise() {
this(false);
}
public Promise(boolean isTrue) {
this.isTrue = isTrue;
}
public boolean evaluatePromise(Agent agent) {
boolean evaluated = evaluate(agent);
return (isTrue && !evaluated) || (!isTrue && evaluated);
}
public abstract boolean evaluate(Agent agent);
public abstract void act();
}
public static Agent getAgent(String name) {
return agents.get(name);
}
public static boolean hasAgent(String name) {
return agents.containsKey(name);
}
public static Set agentNames() {
return agents.keySet();
}
// Agent States
public static final int NEW = 0;
public static final int ACTIVE = 1;
public static final int STEP = 2;
public static final int INACTIVE = 3;
public static final int TERMINATING = 4;
public static final int TERMINATED = 5;
private String name;
private int state = NEW;
private Intention intention;
// Trace variable is used to indicate whether or not ignored events should be logged.
private boolean trace = false;
// Synchronization Fields
private Set tokens = new TreeSet<>();
private Map> lockQueueMap = Collections.synchronizedMap(new HashMap<>());
private Map lockMap = Collections.synchronizedMap(new HashMap<>());
// Event Queue
private Set filter = new TreeSet<>();
private BlockingQueue eventQueue = new LinkedBlockingQueue<>();
// Intention Management
private BlockingQueue completed = new LinkedBlockingQueue<>();
private List intentions = Collections.synchronizedList(new ArrayList<>());
// Activated TR Function / null if no function active
private Predicate trFunction;
// Class Hierarchy
private ASTRAClass clazz;
private Map linearization = new TreeMap<>();
// Reasoning Engine
private Reasoner reasoner;
private EventBeliefManager beliefManager;
private List promises = new ArrayList<>();
private List sensorArray = new LinkedList<>();
// Message Listeners - listener pattern to notify other classes of
// incoming/outgoing messages.
private List messageListeners = new LinkedList<>();
private long iteration = 0;
// Agent Level Rule Set
private Map> rules = new HashMap<>();
public Agent(String name) {
this.name = name;
// initialize the timings table
timings.put(name, 0l);
iterations.put(name, 0l);
beliefManager = new EventBeliefManager(this);
reasoner = new NewReasoner(this);
reasoner.addSource(beliefManager);
reasoner.addSource(this);
agents.put(name, this);
listeners.forEach(listener -> {
listener.receive(this);
});
// out.println(name() + ",NEW");
// TraceManager.getInstance().recordEvent(new TraceEvent(TraceEvent.NEW_AGENT, Calendar.getInstance().getTime(), this));
}
public boolean isRunnable() {
return clazz.isRunnable();
}
public void addSource(Queryable source) {
reasoner.addSource(source);
}
public String name() {
return name;
}
public void setMainClass(ASTRAClass clazz) throws ASTRAClassNotFoundException {
this.clazz = clazz;
List list = clazz.getLinearization();
for ( ASTRAClass claz : list ) {
filter.addAll( claz.filter() );
reasoner.addSource(claz);
}
Fragment prev = null;
for ( ASTRAClass claz : list ) {
claz.initialize(this);
Fragment fragment = claz.createFragment(this);
if (prev!=null) {
prev.next = fragment;
}
linearization.put(claz.getClass().getCanonicalName(), fragment);
prev = fragment;
}
}
private List filteredClassList(List classList, String scope) throws ASTRAClassNotFoundException {
if (trace) System.out.println("["+name()+"] Filtering classlist: " + scope);
for (ASTRAClass c : classList) {
if (c.getCanonicalName().equals(scope) || c.getClass().getSimpleName().equals(scope)) {
if (trace) System.out.println("["+name()+"] Linearisation: " + c.getLinearization());
return c.getLinearization();
}
}
return null;
}
public void addRule(Rule rule) {
String signature = rule.event.signature();
System.out.println("Adding: " + rule);
List ruleList = rules.get(signature);
if (ruleList == null) {
ruleList = new LinkedList<>();
rules.put(signature, ruleList);
filter.add(signature);
}
ruleList.add(rule);
}
public List rules() {
List ruleList = new LinkedList<>();
for (List list : rules.values()) {
ruleList.addAll(list);
}
return ruleList;
}
public boolean handleEvent(Event event) {
// out.println(name() + ",hevt");
if (trace) {
System.out.println("__________________________________________________________________________");
System.out.println("["+name+"] Handling: "+event);
System.out.println("["+name+"] EQ: "+eventQueue);
}
// Start by checking if the event should be handled through any active plan
boolean handled = false;
Object source = event.getSource();
if (source != null) {
if (Intention.class.isInstance(source)) {
handled = ((Intention) source).handleEvent(event, this);
} else if (RuleExecutor.class.isInstance(source)) {
handled = ((RuleExecutor) source).intention().handleEvent(event, this);
}
} else {
for (int i=0; i < intentions.size(); i++) {
if (intentions.get(i).handleEvent(event, this)) handled = true;
}
}
if (trace) System.out.println("[" + name() + "] NOT ACTIVE PLAN");
// If we did not handle it in the intention, check if it can be handled at the agent level
if (!handled) {
if (trace) System.out.println("["+name()+"] CHECKING LOCAL AGENT RULES");
if (trace) System.out.println("["+name()+"] Event Signature: " + event.signature());
if (trace) System.out.println("["+name()+"] Rules: " + rules.keySet());
List list = rules.get(event.signature());
if (list != null) {
int i=0;
while (i bindings = Helper.evaluateRule(this, rule, event);
if (bindings != null) {
if (source != null) {
Intention intention = null;
if (Intention.class.isInstance(source)) {
intention = (Intention) source;
intention.addSubGoal(event, rule, bindings, null);
// System.out.println("["+agent.name()+"] \tADDING SUBGOAL: " + rule.event + "\n\tbindings: " + bindings);
} else if (RuleExecutor.class.isInstance(source)) {
RuleExecutor executor = (RuleExecutor) source;
intention = executor.intention();
intention.addSubGoal(event, rule, bindings, executor);
// System.out.println("["+agent.name()+"] \tADDING RULE SUBGOAL: " + rule.event + "\n\tbindings: " + bindings);
}
intention.resume();
} else {
// Intention i = null;
// System.out.println("["+agent.name()+"] \tCREATING NEW INTENTION: " + rule.event + "\n\tbindings: " + bindings);
addIntention(new Intention(this, event, rule, bindings));
// System.out.println(i.toString());
}
handled = true;
}
}
}
}
if (trace) System.out.println("[" + name() + "] NOT LOCAL RULE");
// Next is to check the original agent program...
if (!handled) {
if (trace) System.out.println("[" + name + "] Checking program: " + event.signature());
try {
List classList = clazz.getLinearization();
if (event instanceof ScopedGoalEvent) {
// System.out.println("Scope: " + ((ScopedGoalEvent) event).scopedGoal().scope());
classList = filteredClassList(classList, ((ScopedGoalEvent) event).scopedGoal().scope());
// System.out.println("ClassList: " + classList);
if (classList == null) {
throw new RuntimeException("Agent Class could not be matched: " + ((ScopedGoalEvent) event).scopedGoal().scope());
}
}
if (event instanceof ScopedBeliefEvent) {
classList = filteredClassList(classList, ((ScopedBeliefEvent) event).scope());
event = ((ScopedBeliefEvent) event).beliefEvent();
}
if (trace) System.out.println("[" + name + "] Filtered Classlist: " + classList);
int i=0;
while (!handled && i < classList.size()) {
ASTRAClass cls = classList.get(i++);
// System.out.println("Handling: " + cls.getCanonicalName());
Fragment fragment = linearization.get(cls.getClass().getCanonicalName());
if (fragment.getASTRAClass().handleEvent(event, this)) handled = true;
}
} catch (ASTRAClassNotFoundException e) {
System.err.println("Problem generating linearisation of: " + clazz.getClass().getCanonicalName());
e.printStackTrace();
}
}
if (!handled) {
// Still not handled, so we generate an error!
if (source != null) {
Intention lIntention = null;
if (Intention.class.isInstance(source)) {
lIntention = (Intention) source;
} else if (RuleExecutor.class.isInstance(source)) {
lIntention = ((RuleExecutor) source).intention();
}
lIntention.failed("Event was not matched to rule: " + event, null);
lIntention.resume();
} else {
if (trace) System.out.println("[astra.core.Agent:"+name+"] Event: " + event +" was not handled");
}
}
if (trace) System.out.println("__________________________________________________________________________");
return handled;
}
public synchronized void execute() {
// out.println(name() + ",start_loop");
for (SensorAdaptor adaptor : sensorArray) {
adaptor.sense(this);
}
this.beliefManager.update();
for (int i=0; i> query(Formula formula, Map bindings) {
return reasoner.query(formula, bindings);
}
public List