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

ai.libs.jaicore.planning.hierarchical.algorithms.forwarddecomposition.graphgenerators.tfd.TFDGraphGenerator Maven / Gradle / Ivy

package ai.libs.jaicore.planning.hierarchical.algorithms.forwarddecomposition.graphgenerators.tfd;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import ai.libs.jaicore.logging.ToJSONStringUtil;
import ai.libs.jaicore.logic.fol.structure.Literal;
import ai.libs.jaicore.logic.fol.structure.Monom;
import ai.libs.jaicore.planning.classical.algorithms.strips.forward.StripsUtil;
import ai.libs.jaicore.planning.classical.problems.strips.Operation;
import ai.libs.jaicore.planning.core.Action;
import ai.libs.jaicore.planning.hierarchical.algorithms.forwarddecomposition.graphgenerators.TaskPlannerUtil;
import ai.libs.jaicore.planning.hierarchical.problems.htn.IHTNPlanningProblem;
import ai.libs.jaicore.planning.hierarchical.problems.stn.Method;
import ai.libs.jaicore.planning.hierarchical.problems.stn.MethodInstance;
import ai.libs.jaicore.search.core.interfaces.GraphGenerator;
import ai.libs.jaicore.search.core.interfaces.PathUnifyingGraphGenerator;
import ai.libs.jaicore.search.model.travesaltree.NodeExpansionDescription;
import ai.libs.jaicore.search.model.travesaltree.NodeType;
import ai.libs.jaicore.search.structure.graphgenerator.NodeGoalTester;
import ai.libs.jaicore.search.structure.graphgenerator.SingleRootGenerator;
import ai.libs.jaicore.search.structure.graphgenerator.SuccessorGenerator;

public class TFDGraphGenerator implements GraphGenerator, PathUnifyingGraphGenerator {

	private static Logger logger = LoggerFactory.getLogger(TFDGraphGenerator.class);
	protected TaskPlannerUtil util = new TaskPlannerUtil(null);
	protected final IHTNPlanningProblem problem;
	protected final Map primitiveTasks = new HashMap<>();

	public TFDGraphGenerator(final IHTNPlanningProblem problem) {
		this.problem = problem;
		for (Operation op : problem.getDomain().getOperations()) {
			this.primitiveTasks.put(op.getName(), op);
		}
	}

	protected Collection getSuccessorsResultingFromResolvingPrimitiveTask(final Monom state, final Literal taskToBeResolved, final List remainingOtherTasks) throws InterruptedException {
		Collection successors = new ArrayList<>();
		for (Action applicableAction : this.util.getActionsForPrimitiveTaskThatAreApplicableInState(null, this.primitiveTasks.get(taskToBeResolved.getPropertyName()), taskToBeResolved, state)) {
			Monom stateCopy = new Monom(state);
			StripsUtil.updateState(stateCopy, applicableAction);
			successors.add(this.postProcessPrimitiveTaskNode(new TFDNode(stateCopy, remainingOtherTasks, null, applicableAction)));
		}
		return successors;
	}

	protected Collection getSuccessorsResultingFromResolvingComplexTask(final Monom state, final Literal taskToBeResolved, final List remainingOtherTasks) throws InterruptedException {
		Collection successors = new ArrayList<>();
		Collection applicableMethodInstances = this.util.getMethodInstancesForTaskThatAreApplicableInState(null, this.problem.getDomain().getMethods(), taskToBeResolved, state, remainingOtherTasks);
		assert this.areLonelyMethodsContainedAtMostOnce(applicableMethodInstances);
		for (MethodInstance instance : applicableMethodInstances) {

			/* derive remaining network for this instance */
			List remainingTasks = this.stripTNPrefixes(this.util.getTaskChainOfTotallyOrderedNetwork(instance.getNetwork()));
			remainingTasks.addAll(remainingOtherTasks);
			successors.add(this.postProcessComplexTaskNode(new TFDNode(state, remainingTasks, instance, null)));
		}
		return successors;
	}

	private boolean areLonelyMethodsContainedAtMostOnce(final Collection instances) {
		List usedMethods = new ArrayList<>();
		for (MethodInstance mi : instances) {
			if (!mi.getMethod().isLonely()) {
				continue;
			}
			boolean doubleUseDetected = usedMethods.contains(mi.getMethod());
			assert !doubleUseDetected : "Lonely method " + mi.getMethod() + " has been generated several times as being applicable!";
			usedMethods.add(mi.getMethod());
		}
		return true;
	}

	protected List stripTNPrefixes(final List taskList) {
		return taskList.stream().map(l -> {
			String taskName = l.getPropertyName().substring(l.getPropertyName().indexOf('-') + 1, l.getPropertyName().length());
			return new Literal(taskName, l.getParameters(), l.isPositive());
		}).collect(Collectors.toList());
	}

	/**
	 * A hook for extending classes that can be used to change the nodes before they are attached
	 *
	 * @param node
	 * @return
	 */
	protected TFDNode postProcessPrimitiveTaskNode(final TFDNode node) {
		return node;
	}

	/**
	 * A hook for extending classes that can be used to change the nodes before they are attached
	 *
	 * @param node
	 * @return
	 */
	protected TFDNode postProcessComplexTaskNode(final TFDNode node) {
		return node;
	}

	@Override
	public SingleRootGenerator getRootGenerator() {
		return () -> new TFDNode(this.problem.getInit(), this.stripTNPrefixes(new TaskPlannerUtil(null).getTaskChainOfTotallyOrderedNetwork(this.problem.getNetwork())));
	}

	@Override
	public SuccessorGenerator getSuccessorGenerator() {
		return l -> {
			Monom state = l.getState();
			List currentlyRemainingTasks = new ArrayList<>(l.getRemainingTasks());
			if (currentlyRemainingTasks.isEmpty()) {
				return new ArrayList<>();
			}
			Literal nextTaskTmp = currentlyRemainingTasks.get(0);
			currentlyRemainingTasks.remove(0);
			String nextTaskName = nextTaskTmp.getPropertyName();
			Literal nextTask = new Literal(nextTaskName, nextTaskTmp.getParameters());

			/* get the child nodes */
			long creationStartTime = System.currentTimeMillis();
			Collection successors = this.primitiveTasks.containsKey(nextTask.getPropertyName()) ? this.getSuccessorsResultingFromResolvingPrimitiveTask(state, nextTask, currentlyRemainingTasks)
					: this.getSuccessorsResultingFromResolvingComplexTask(state, nextTask, currentlyRemainingTasks);
			logger.info("Node generation finished and took {}ms", System.currentTimeMillis() - creationStartTime);

			/* change order in remaining tasks based on numbered prefixes */
			successors = successors.stream().map(this::orderRemainingTasksByPriority).collect(Collectors.toList());

			/* derive successor descriptions from the nodes */
			return successors.stream().map(n -> new NodeExpansionDescription(l, n, n.getAppliedAction() != null ? n.getAppliedAction().getEncoding() : n.getAppliedMethodInstance().getEncoding(), NodeType.OR)).collect(Collectors.toList());
		};
	}

	public TFDNode orderRemainingTasksByPriority(final TFDNode node) {

		/* determine order of tasks based on the prefixes */
		Pattern p = Pattern.compile("(\\d+)_");
		List unorderedLiterals = new ArrayList<>();
		Map> orderedLiterals = new HashMap<>();
		node.getRemainingTasks().forEach(t -> {
			Matcher m = p.matcher(t.getPropertyName());
			if (m.find()) {
				int order = Integer.parseInt(m.group(1));
				if (!orderedLiterals.containsKey(order)) {
					orderedLiterals.put(order, new ArrayList<>());
				}
				List tasksWithorder = orderedLiterals.get(order);
				tasksWithorder.add(t);
			} else {
				unorderedLiterals.add(t);
			}
		});

		/* reorganize task network */
		List newLiteralList = new ArrayList<>();
		orderedLiterals.keySet().stream().sorted().forEach(order -> newLiteralList.addAll(orderedLiterals.get(order)));
		newLiteralList.addAll(unorderedLiterals);
		return new TFDNode(node.getState(), newLiteralList, node.getAppliedMethodInstance(), node.getAppliedAction());
	}

	@Override
	public NodeGoalTester getGoalTester() {
		return l -> l.getRemainingTasks().isEmpty();
	}

	@Override
	public boolean isSelfContained() {
		return false;
	}

	@Override
	public void setNodeNumbering(final boolean nodenumbering) {
		throw new UnsupportedOperationException();
	}

	@Override
	public boolean isPathSemanticallySubsumed(final List path, final List potentialSuperPath) throws InterruptedException {
		int n = path.size();
		for (int i = 0; i < n; i++) {
			if (!path.get(i).equals(potentialSuperPath.get(i))) {
				return false;
			}
		}
		return true;
	}

	@Override
	public String toString() {
		Map fields = new HashMap<>();
		fields.put("util", this.util);
		fields.put("problem", this.problem);
		fields.put("primitiveTasks", this.primitiveTasks);
		return ToJSONStringUtil.toJSONString(this.getClass().getSimpleName(), fields);
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy