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

astra.core.Intention Maven / Gradle / Ivy

package astra.core;

import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Queue;
import java.util.Set;
import java.util.Stack;

import astra.core.Agent.Promise;
import astra.event.Event;
import astra.event.GoalEvent;
import astra.event.ScopedGoalEvent;
import astra.formula.Formula;
import astra.formula.Goal;
import astra.formula.Predicate;
import astra.formula.ScopedGoal;
import astra.reasoner.util.BindingsEvaluateVisitor;
import astra.reasoner.util.ContextEvaluateVisitor;
import astra.statement.StatementHandler;
import astra.statement.Subgoal;
import astra.term.FormulaTerm;
import astra.term.ModuleTerm;
import astra.term.NullTerm;
import astra.term.Operator;
import astra.term.Primitive;
import astra.term.Term;
import astra.term.Variable;

public class Intention {
	public int age = 0;
	Map> actionParams = new HashMap<>();
	Stack failureTrace;
	String failureReason;

	private Throwable exception;
	public Agent agent;
	public Event event;
	private Rule rule;
	Map bindings;
	
	boolean suspended = false;
	boolean failed = false;
	boolean recovering = false;
	
	boolean hasGoalRule = false;

	Stack executors = new Stack<>();
	
	public Intention(Agent agent, Event event, Rule rule, Map bindings) {
		this.agent = agent;
		this.event = event;
		this.bindings = bindings;
		this.rule = rule;
		
		hasGoalRule = rule instanceof GoalRule;
		executors.push(new RuleExecutor(event, rule, bindings, null, this));
	}
	
	public synchronized boolean execute() {
		if (!executors.isEmpty()) {
			RuleExecutor executor = executors.peek();
			try {
				boolean result = executor.execute(this);
				if (!this.isSuspended() && !result && !GoalRule.class.isInstance(executor.rule())) {
					// System.out.println("\t\t\tPOPPING the executor");
					executors.pop();
					if (executor.parent() != null) executor.parent().updateRuleBindings(executor.bindings(), executor.getUnboundBindings());
				}
			} catch (Throwable e) {
				e.printStackTrace();
				this.failed("Error executing statement: " + executor.getNextStatment().toString(), e);
				executor.printStackTrace();
			}
		}

		return !executors.isEmpty();
	}

	public Module getModule(String classname, String key) {
		return agent.getModule(classname,key);
	}

	@SuppressWarnings({ "unchecked" })
	public  T evaluate(Term term) {
		// System.out.println("Evaluating: " + term);
		if (term instanceof Primitive) {
			// System.out.println("Val: "  + ((Primitive) term).value().getClass().getCanonicalName());
			return ((Primitive) term).value();
		}

		if (term instanceof Variable) {
			Term val = getValue((Variable) term);
			// System.out.println("[" + agent.name() + "] Value for variable: " + term + " is: " + val);
			if (val == null || term.matches(val)) {
				ActionParam param = new ActionParam<>();
				actionParams.put((Variable) term, param);
				return (T) param;
			}

			if (val instanceof NullTerm) {
				return null;
			}

			return evaluate(val);
		}
		
		if (term instanceof Operator || term instanceof ModuleTerm) {
			// System.out.println("Here: " + term);
			// System.out.println(this.bindings());
			Term t = (Term) term.accept(new ContextEvaluateVisitor(this));
			if (t instanceof Primitive) {
				return ((Primitive) t).value();
			} else {
				return (T) t;
			}
		}
		
		if (term instanceof FormulaTerm) {
			return (T) ((FormulaTerm) term).value();
		}
		
		if (term instanceof astra.term.ListTerm) {
			// System.out.println("evaluating: " + term);
			return (T) term.accept(new ContextEvaluateVisitor(this, false));
		}
		
		if (term instanceof astra.term.Funct) {
			return (T) term.accept(new ContextEvaluateVisitor(this));
		}

		if ((term instanceof astra.term.Head) || (term instanceof astra.term.Tail) || (term instanceof astra.term.AtIndex)) {
			Term _term = (Term) term.accept(new ContextEvaluateVisitor(this));
			return evaluate(_term);
		}
		
		
		System.out.println("term: " + term);
		System.out.println("EVALUATE: " + term.getClass().getName());

		return null;
	}

	public Term getValue(Variable term) {
		Term value = null;
		int i = executors.size()-1;

		value = executors.get(i--).getValue(term);
		
		while (value == null && i >= 0) {
			RuleExecutor executor = executors.get(i--);
			if (GoalRule.class.isInstance(executor.rule())) {
				value = executor.getValue(term);
			}
			
		}

		return value;
	}
	// synchronized
	public void addSubGoal(Event event, Rule rule, Map bindings, RuleExecutor parent) {
		if (rule instanceof GoalRule) hasGoalRule = true;
		executors.push(new RuleExecutor(event, rule, bindings, parent, this));
	}
	
	/**
	 * Moves down through the ruleexecutor stack looking for a ruleexecutor that has the variable being updated...
	 * @param term the variable to be updated
	 * @param logic the new value to be associated with the variable
	 * @return true if it was updated, false otherwise
	 */
	public boolean updateVariable(Variable term, Term logic) {
		boolean updated = false;

		int i = executors.size()-1;
		while (!updated && i >= 0) updated = executors.get(i--).updateVariable(term, logic);
		return updated;
	}

	public String toString() {
		StringBuilder out = new StringBuilder();
		for (int i=executors.size()-1 ; i >= 0; i--) {
			out.append(executors.get(i).event()).append("\n");
		}
		return out.toString();
	}

	public void failed(String reason) {
		failed(reason, null);
	}
	
	public void failed(String reason, Throwable exception) {
		failed = true;
		failureTrace = new Stack<>();
		for (RuleExecutor executor : executors) {
			executor.buildFailureTrace(failureTrace);
		}
		failureReason = reason;
		this.exception = exception;
	}
	
	public boolean isFailed() {
		return failed;
	}

	public void printStackTrace() {
		if (failureTrace == null) return;
		System.out.println("["+agent.name()+"] " + failureReason);
		for (int i=failureTrace.size()-1; i >= 0;  i--) {
			if (failureTrace.get(i).statement() instanceof Subgoal||i == failureTrace.size()-1) {
				System.out.print("["+agent.name()+"] " + failureTrace.get(i).statement().getASTRAClass() + "." + failureTrace.get(i));
				if (failureTrace.get(i).statement().isLinkedToSource()) {
					System.out.print(":" + failureTrace.get(i).statement().beginLine());
				}
				System.out.println();
			}
		}
		System.out.println("["+agent.name()+"] " + event.toString());
		if (exception != null) {
			System.err.println("["+agent.name()+"] Caused By:");
			exception.printStackTrace();
		}
	}

	public boolean rollback() {
		// DEAL WITH ROLLBACK...
		while (!executors.isEmpty()) {
			RuleExecutor executor = executors.peek();
			if (executor.rollback(this)) {
				failed = false;
				resume();
				return true;
			}
			
			executors.pop();
			
			if (failed && executor.event() instanceof GoalEvent) {
				GoalEvent goalEvent = (GoalEvent) executor.event();
				GoalEvent removalEvent =  new GoalEvent(Event.REMOVAL, goalEvent.goal(), this);
				if (goalEvent.type == Event.ADDITION && agent.addEvent(removalEvent)) {
					recovering = true;
					failed = false;
					return true;
				}
			}
		}
		return false;
	}

	public void addBelief(Predicate belief) {
		agent.beliefs().addBelief(belief);
	}

	public void removeBelief(Predicate belief) {
		// System.out.println("[Intention.removeBelief()] Removing: " + belief);
		agent.beliefs().dropBelief(belief);
	}

	public void suspend() {
		suspended = true;
	}

	public boolean isSuspended() {
		return suspended;
	}

	public boolean isRecovering() {
		return recovering;
	}

	public void resume() {
		if (recovering) recovering = false;
		suspended = false;
	}

	public void resetActionParams() {
		actionParams.clear();
	}
	
	public void applyActionParams() {
		for (Entry> entry : actionParams.entrySet()) {
			this.updateVariable(entry.getKey(), entry.getValue().toLogic());
		}
	}

	public void dumpStack() {
		System.out.println("Intention State: " + (this.isActive() ? "ACTIVE":"SUSPENDED"));
		for (int i=executors.size()-1 ; i >= 0; i--) {
			System.out.println(i +". " + executors.get(i).event() +": "+executors.get(i).bindings());
		}
		System.out.println("\n\n"+generateIntentionTree());
	}

	public String generateIntentionTree() {
		Set baseRules = new HashSet<>();
		Map> children = new HashMap<>();
		for (RuleExecutor executor:executors) {
			if (executor.parent() == null) {
				baseRules.add(executor.event().toString()+": "+executor.bindings());
			} else {
				String parent = executor.parent().event().toString()+": "+executor.parent().bindings();
				List list = children.computeIfAbsent(parent, s->new LinkedList<>());
				list.add(executor.event().toString()+": "+executor.bindings());
			}
		}

		StringBuffer buf = new StringBuffer();
		for (String node : baseRules) {
			buf.append(node).append("\n");
			addChildren(buf, node, children, "\t");
		}
		return buf.toString();
	}

	private void addChildren(StringBuffer buf, String node, Map> children, String tabs) {
		List list = children.get(node);
		if (list == null) return;
		for (String item : list) {
			buf.append(tabs).append(item).append("\n");
			addChildren(buf, item, children, tabs+"\t");
		}
	}

	public boolean addGoal(Goal goal) {
		return agent.addEvent(new GoalEvent(Event.ADDITION, goal));
	}

	public boolean addScopedGoal(String scope, Goal goal) {
		return agent.addEvent(new ScopedGoalEvent(Event.ADDITION, new ScopedGoal(scope, goal)));
	}

	public void notifyDone(String message) {
		agent.notifyDone(new Agent.Notification(this, message));
	}

	public void notifyDone(String message, Throwable exception) {
		agent.notifyDone(new Agent.Notification(this, message, exception));
	}

	public void schedule(Task task) {
		agent.schedule(task);
	}

	public String name() {
		return agent.name();
	}
	
	public Map query(Formula formula) {
		List> result = agent.query(formula, new HashMap<>());
		if (result == null) return null;
		if (result.isEmpty()) return null;
		return result.get(0);
	}

	public List> queryAll(Formula formula) {
		return agent.queryAll(formula);
	}

	public boolean startFunction(Predicate function) {
		return agent.startFunction(function);
	}

	public boolean stopFunction() {
		return agent.stopFunction();
	}

	public StatementHandler getNextStatement() {
		return executors.peek().getNextStatment();
	}

	public boolean addEvent(Event event) {
		return agent.addEvent(event);
	}

	public boolean hasLock(String token, Intention context) {
		return agent.hasLock(token, context);
	}

	public boolean requestLock(String token, Intention context) {
		return agent.requestLock(token, context);
	}

	public void releaseLock(String token, Intention context) {
		agent.releaseLock(token, context);
	}

	public void unrequestLock(String token, Intention context) {
		agent.unrequestLock(token, context);
	}

	public void addScopedBelief(String scope, Predicate belief) {
		agent.beliefs().addScopedBelief(scope, belief);
	}

	public void removeScopedBelief(String scope, Predicate belief) {
		agent.beliefs().dropScopedBelief(scope, belief);
	}

	public String failureReason() {
		return failureReason;
	}

	public void makePromise(Promise promise) {
		agent.addPromise(promise);
	}

	public void dropPromise(Promise promise) {
		agent.dropPromise(promise);
	}

	public boolean handleEvent(Event event, Agent agent) {
		boolean success = false;

		int i=executors.size()-1;
		while (!success && i>=0) {
			RuleExecutor executor = executors.get(i);
			if (GoalRule.class.isInstance(executor.rule())) {
				if (agent.trace()) System.out.println("["+agent.name()+"] \tChecking Rule: " + executor.event());
				success = evaluateRules(event, executor);
			}
			i--;
		}

		return success;
	}

	private boolean evaluateRules(Event event ,RuleExecutor executor) {
		GoalRule goalRule = (GoalRule) executor.rule();

		List list = goalRule.rules().get(event.signature());
		if (list == null) return false;
		
		for (Rule lRule : list) {
			Rule revisedRule = lRule.accept(new BindingsEvaluateVisitor(executor.getAllBindings(), agent));
			if (agent.trace()) System.out.println("["+agent.name()+"] Revised Rule: " + revisedRule.event + " / bindings: " + executor.getAllBindings());
			Map lBindings = Helper.evaluateRule(agent,  revisedRule, event);
			if (lBindings != null) {
				if (RuleExecutor.class.isInstance(event.getSource())) {
					if (agent.trace()) System.out.println("["+agent.name()+"]\tADDED AS RULE SUBGOAL");
					addSubGoal(event, lRule, lBindings, (RuleExecutor) event.getSource());
				} else {
					if (agent.trace()) System.out.println("["+agent.name()+"]\tADDED AS SUBGOAL");
					addSubGoal(event, lRule, lBindings, executor);
				}
				resume();
				return true;
			}
		}
		
		return false;
	}	

	public Rule rule() {
		if (executors.isEmpty()) return rule;
		return executors.peek().rule();
	}

	public boolean isGoalCompleted() {
		if (executors.isEmpty()) return true;
		return executors.peek().isDone();
	}

	/**
	 * Used by DONE statement to drop the currently active g-rule (or goal if no g-rule used)
	 */
	public synchronized void done() {
		if (agent.trace()) System.out.println("---------------------------------------------------------------------------");
		if (agent.trace()) System.out.println("done() called for intention: " +event);
		boolean updated = false;
		while (!updated) {
			RuleExecutor executor = executors.pop();
			if (agent.trace()) System.out.println("\tRemoved: " + executor.event());
			if (executors.isEmpty()) updated = true;
			else {
				executors.peek().updateRuleBindings(executor.getUnboundBindings());
				updated = GoalRule.class.isInstance(executor.rule());
			}
        }
	}

	public boolean isActive() {
		return !suspended && !failed;
	}

	public synchronized boolean checkEvent(Event event) {
		if (!hasGoalRule) return false;
		// System.out.println("Checking: " + rule.event +" / " + event);
		String signature = event.signature();
		for (int i=executors.size()-1; i>=0; i--) {
			Rule lRule = executors.get(i).rule();
			// System.out.println("\tchecking rule exec: " + rule.event);
			if (GoalRule.class.isInstance(lRule) && ((GoalRule) lRule).filter().contains(signature)) 
				return true;
		}

		return false;
	}

	public Map bindings() {
		return executors.peek().bindings();
	}

	public void addGoals(Queue queue, Goal goal) {
		if (this.event instanceof GoalEvent) {
			Goal gl = ((GoalEvent) event).goal();
			if (gl.formula().id() == goal.formula().id()) 
				queue.add(gl);
			for(RuleExecutor executor : executors) {
				executor.addGoals(queue, goal);
			}
		}
	}

	public boolean reviseGoals() {
		if (!hasGoalRule) return executors.isEmpty();

		int i = executors.size() -1;
		while (i >= 0) {
			RuleExecutor executor = executors.get(i);
			if (GoalRule.class.isInstance(executor.rule()) && evaluationDropCondition((GoalRule) executor.rule())) {
				while (executors.size() > i) {
					RuleExecutor ex = executors.pop();
					if (ex.parent() != null) ex.parent().updateRuleBindings(ex.getUnboundBindings());
					else if (!executors.isEmpty()) executors.peek().updateRuleBindings(ex.getUnboundBindings());
				}
				// if (!executors.isEmpty()) executors.peek().updateRuleBindings(executor.getUnboundBindings());
			}
			i--;
		}

		return executors.isEmpty();
	}

	private boolean evaluationDropCondition(GoalRule rule) {
		return agent.query((Formula) rule.dropCondition.accept(new ContextEvaluateVisitor(this)), new HashMap<>()) != null;
	}

	public RuleExecutor executor() {
		return executors.peek();
	}

	public boolean trace() {
		return agent.trace();
	}

	public boolean isDone() {
		return executors.size() == 1 && executors.get(0).isDone();
	}

	public boolean isProcessing() {
		// TODO: This is a stub - really, needs to return true if there is an active plan.
		// need to think of this. False will work for basic rules but not goal rules.
		return true;
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy