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

net.sf.gluebooster.java.booster.basic.math.planning.MetaPlanner Maven / Gradle / Ivy

Go to download

Basic classes to support the development of applications. There should be as few dependencies on other frameworks as possible.

The newest version!
package net.sf.gluebooster.java.booster.basic.math.planning;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.apache.commons.collections4.Transformer;
import org.apache.commons.lang3.tuple.Pair;

import net.sf.gluebooster.java.booster.basic.container.BoostedNode;
import net.sf.gluebooster.java.booster.basic.math.Operation;
import net.sf.gluebooster.java.booster.basic.math.OperationSorter;
import net.sf.gluebooster.java.booster.basic.math.graph.BoostedNodeGraph;
import net.sf.gluebooster.java.booster.basic.transformation.CallableBySelecting;
import net.sf.gluebooster.java.booster.basic.transformation.CallableDelegate;
import net.sf.gluebooster.java.booster.essentials.eventsCommands.Callable;
import net.sf.gluebooster.java.booster.essentials.eventsCommands.CallableAbstraction;
import net.sf.gluebooster.java.booster.essentials.math.Condition;
import net.sf.gluebooster.java.booster.essentials.meta.HasName;
import net.sf.gluebooster.java.booster.essentials.meta.objects.ObjectAttributes;

/**
 * Meta planning algorithms.
 * 
 * 
 * @author CBauer
 * @defaultParamText planning the current state of the planning with all necessary data
 *
 * 
 */
public class MetaPlanner
		extends CallableAbstraction, Planning>
{

	/**
	 * The variant that does nothing
	 */
	private static final int VARIANT_IDLE = 0;

	/**
	 * One (the first) planning algorithm
	 */
	private static final int VARIANT_1 = 1;

	/**
	 * A variant that just expands not but does not solve conflicts.
	 */
	private static final int VARIANT_JUST_EXPAND = 2;

	/**
	 * The description of the algorithm of the planning.
	 */
	private int variant = VARIANT_IDLE;

	/**
	 * Selects one of the expanders that are selected with World.getExpander
	 */
	private Transformer>, Callable> planNodeExpanderSelector = new CallableDelegate(
			CallableBySelecting.selectFirstElement("select first element"));

	public MetaPlanner(int variant) {
		this.variant = variant;
	}

	/**
	 * Create a planner that does nothing.
	 * 
	 * @return the created planner
	 */
	public static  Callable, Planning>/*
																								 * ,
																								 * NameOfObjects> Transformer,
																								 * Planning>
																								 */ createIdlePlanner() {
		return new MetaPlanner/**/(VARIANT_IDLE);
	}

	/**
	 * Create a planner with a default planning algorithm
	 * 
	 * @return the created planner
	 */
	public static  Callable, Planning>/*
																								 * ,
																								 * NameOfObjects> Transformer,
																								 * Planning>
																								 */ createPlanner1() {
		return new MetaPlanner/**/(VARIANT_1);
	}

	/**
	 * Create a planner that just expands the nodes, but does no conflict solving, etc.
	 * 
	 * @return the created planner
	 */
	public static  Callable, Planning>/*
																								 * ,
																								 * NameOfObjects> Transformer,
																								 * Planning>
																								 */ createPlannerThatJustExpands() {
		return new MetaPlanner/**/(VARIANT_JUST_EXPAND);
	}

	// /**
	// * Does the planning
	// *
	// * @param planningInstance
	// * instance of Planning
	// * @return Planning
	// */
	// @Override
	// public Object getObjectInstance(Object planningInstance, Name name,
	// Context nameCtx, Hashtable environment) throws Exception {
	//
	// Planning planning = (Planning) planningInstance;
	// switch (variant) {
	// case VARIANT_IDLE:
	// planIdle(planning);
	// break;
	// case VARIANT_1:
	// plan1(planning);
	// break;
	// case VARIANT_JUST_EXPAND:
	// planJustExpand(planning);
	// break;
	// default:
	// throw new IllegalStateException("variant " + variant
	// + " not (yet) supported");
	// }
	// return planningInstance;
	// }


	/**
	 * Does nothing
	 * 
	 * @param configuration
	 *            the planning
	 */
	private void planIdle(Planning configuration)
			throws Exception {
		configuration.info("idle planner, no planning is done");
	}

	/**
	 * Algorithm 1
	 * 
	 * @param planning
	 */
	private void plan1(Planning planning)
			throws Exception {
		// planning.debug("planner 1");
		
		int i = 0;
		int maxSteps = planning.getEnv().getMaxSteps();

		while (i < maxSteps && !planning.getPlan().isSolved()) {
			i++;


			planning.info("planner ", variant, ": step ", i, " of at most ",
					maxSteps);

			// TODO use a time dependent combineNodes instead of i
			if (!nextStep1(planning, i < 30)) {
				simplify1(planning);
			}

			if (planning.getPlan().isSolved())
				planning.getPlan().removeSuperfluousOperators();

			if (planning.getPlan().getVersion() == null) {
				planning.getPlan().setVersion(1);
			} else {
				planning.getPlan().setVersion(
						planning.getPlan().getVersion().intValue() + 1);
			}

		}
		

	}

	/**
	 * Algorithm 1
	 * 
	 * @param plan
	 * @param env
	 * @throws Exception
	 */
	private void planJustExpand(Planning planning)
			throws Exception {

		int i = 0;
		int maxSteps = planning.getEnv().getMaxSteps();
		planning.getPlan().setVersion(1);

		while (i < maxSteps && !planning.getPlan().isSolved()) {
			i++;

			planning.info("planner ", variant, ": step ", i, " of at most ",
					maxSteps);

			nextStepJustExpandOneNode(planning);


			planning.getPlan().setVersion(
					planning.getPlan().getVersion().intValue() + 1);

		}

	}

	/**
	 * Do one step (of planning algorithm 1)
	 * 
	 * @param combineNodes
	 *            the nodes to combine
	 * @return true, if the plan has been modified
	 */
	private boolean nextStep1(Planning planning,
			boolean combineNodes) throws Exception {


		boolean result = instantiateOneRandomVirtualObject(planning);

		result |= solveSomeUnsolvedNodeWithMaximumAbstraction(planning, 10);


		if (combineNodes) {
			result |= combineNodes(planning);
			while (combineNodes(planning)) {
				// just repeat the combining process as long as possible
			}
		}

		result |= solveEarlyConflictSeries(planning);
		while (solveEarlyConflictSeries(planning)) {
			// just repeat the solving process as long as possible
		}

		if (!result) {
			result = solveGoalConflict(planning);
		}

		if (!result) {
			// plan->combine_above = 0;
			result = combineNodes(planning);
			// plan->combine_above = 1;
		}

		return result;

	}

	/**
	 * Do one step (of planning algorithm 1)
	 * 
	 * @param plan
	 * @return true, if the plan has been modified
	 */
	private boolean nextStepJustExpandOneNode(
			Planning planning)
			throws Exception {

		boolean result = planning.removeSuperfluousOperators();

		if (!result) {
			result = instantiateOneRandomVirtualObject(planning);
		}

		if (!result) {
			result = solveSomeUnsolvedNodeWithMaximumAbstraction(planning, 1);
		}

		return result;
	}

	/**
	 * Tries to solve the nodes with the highest abstraction level.
	 * 
	 * If the highest abstraction level is not solvable continue with the next lower level. Try to solve all nodes with the same abstraction level. If any node
	 * is solved, do not continue with the next lower abstraction level, but stop
	 * 
	 * @param maxNumberOfNodes
	 *            the maximum number of nodes to solve/expand
	 * @return true, if the plan has been modified
	 * @throws Exception
	 */
	public boolean solveSomeUnsolvedNodeWithMaximumAbstraction(
			Planning planning, int maxNumberOfNodes)
			throws Exception {

		int abstractionLevel = 0;
		boolean solved = false;

		Collection unsolvedNodes = planning.getPlan()
				.getUnsolvedNodes(
						OperationSorter.createSortByOperatorAbstractionDesc());
		int counter = 0;
		for (BoostedNode unsolvedNode : unsolvedNodes) {
			int newAbstractionLevel = Operation.getOperation(unsolvedNode)
					.getOperator()
					.getAbstractionLevel();
			if (solved) {
				if (newAbstractionLevel < abstractionLevel) {
					break; // stop solving
				}
			} else {
				abstractionLevel = newAbstractionLevel;
			}
			if (counter < maxNumberOfNodes) {
				boolean tempResult = expandUnsolvedNode(planning, unsolvedNode);
				solved |= tempResult;
				if (tempResult) {
					counter++;
				}
			} else {
				break;
			}
		}

		return solved;



	}

	/**
	 * Expands an unsolved node to a graph with of (easier solvable ) nodes. The plan is modified
	 * 
	 * @param planning
	 *            contains the plan
	 * @param unsolvedNode
	 *            the node to expland
	 * @return true if something has been changed
	 * @throws Exception
	 */
	public boolean expandUnsolvedNode(
			Planning planning,
			BoostedNode unsolvedNode) throws Exception {

		// Refactor.checkPredecessorSuccessor(unsolvedNode);

		Collection> solvers = planning
				.getPlan().getWorld()
				.getExpander(unsolvedNode);
		if (solvers.isEmpty()) {
			return false;
		} else {
			boolean result = planning.transformNode(unsolvedNode,
					planNodeExpanderSelector.transform(solvers));

			// planning.getPlan().simpleDisplay();
			return result;
		}

	}

	/**
	 * If nodes do the same operation in parallel branches, it may be possible
	 * merge the two operations into one by changing the plan structure. One
	 * operation is removed, its predecessors become predecessors of the other
	 * operation; its successors become successors of the other operation.
	 * 
	 * @return true, if the plan has been modified
	 */
	public boolean combineNodes(Planning planning) throws Exception {

		// Algorithm
		// first get all nodes with equal operators
		// try to merge two of them.

		// first get all nodes with equal operators

		Set> setsOfnodesWithEqualOperators = planning
				.getPlan()
				.getNodesWithEqualOperations(null, null); // TODO use a higher level

		// TODO check abstraction level here

		// get pairs of the nodes ant try to combine them until something was
		// sucessful or you run out of nodes
		for (Set nodesWithEqualOperators : setsOfnodesWithEqualOperators) {
			ArrayList otherNodes = new ArrayList(
					nodesWithEqualOperators);
			for (BoostedNode node : nodesWithEqualOperators) {
				otherNodes.remove(node); // so that there is no duplicate
				for (BoostedNode otherNode : otherNodes) {
					HashSet nodesToCombine = new HashSet(Arrays.asList(node, otherNode));
					if (planning.getPlan().combineNodesWithEqualOperators(nodesToCombine)) {
						return true;
					}
				}
			}
		}

		return false;
	}

	/**
	 * Solves the possible conflicts in the order of their graph position
	 * 
	 * @return true, if the plan has been modified
	 */
	public boolean solveEarlyConflictSeries(
			Planning planning) throws Exception {

		List>*/> possibleConflicts = planning
				.getPlan().orderPossibleConflictsByGraphPosition();

		for (ObjectAttributes/* > */ possibleConflict : possibleConflicts) {
			if (planning.getPlan().solvePossibleConflictByReordering(
					possibleConflict)) {
				return true;
			}
		}

		return false;


	}

	/**
	 * Solve a goal conflict.
	 * 
	 * @return true, if the plan has been modified
	 */
	public boolean solveGoalConflict(Planning planning) {
		planning.error("solveGoalConflict is not yet implemented");
		// TODO do something
		// updateGlobalConditions();
		return false;
	}

	/**
	 * Instantiates a temporary object with a random instance.
	 * 
	 * @return true, if the plan has been modified
	 */
	public boolean instantiateOneRandomVirtualObject(
			Planning planning)
			throws Exception {

		Plan plan = planning.getPlan();

		Set nodes = plan.getNodesWithVirtualProperties();
		if (nodes.isEmpty()) {
			return false;
		} else {
			// take the first object and instantiate it with a random instance
			BoostedNode node = nodes.iterator().next();
			Set initializers = plan.getWorld()
					.getVirtualObjectInitializer(node);
			Pair virtualAndConcreteObject = (Pair) initializers
					.iterator().next()
					.call(node, Planning.createHashtableWithPlan(plan));

			if (virtualAndConcreteObject != null) {
				planning.instantiateVirtualObject(node,
						virtualAndConcreteObject.getLeft(),
						virtualAndConcreteObject.getRight());
				return true;
			}
			else
				return false;
		}


	}

	/**
	 * Simplify a plan by replacing subtrees with new nodes that are to be
	 * solved. Simplifies the plan according to planning algorithm 1.
	 * 
	 * @param plan
	 */
	public void simplify1(Planning planning) {
		planning.error("simplify1 is not yet implemented");
		// TODO implement plan->undo();
	}

	/**
	 * Does the planning
	 * 
	 */
	@Override
	protected Planning callImpl(Planning... parameters) throws Exception {
		Planning planning = parameters[0];
		switch (variant) {
		case VARIANT_IDLE:
			planIdle(planning);
			break;
		case VARIANT_1:
			plan1(planning);
			break;
		case VARIANT_JUST_EXPAND:
			planJustExpand(planning);
			break;
		default:
			throw new IllegalStateException("variant " + variant + " not (yet) supported");
		}
		return planning;
	}

}