/** * This method is the access point to the planning procedure. Initially, it adds all variables * from axioms to the set of found vars, then does the linear planning. If lp does not solve the * problem and there are subtasks, goal-driven recursive planning with backtracking is invoked. * Planning is performed until no new variables are introduced into the algorithm. */ public EvaluationAlgorithm invokePlaning(Problem problem, boolean _computeAll) { long startTime = System.currentTimeMillis(); computeAll = _computeAll; EvaluationAlgorithm algorithm = new EvaluationAlgorithm(); PlanningContext context = problem.getCurrentContext(); // add all axioms at the beginning of an algorithm Collection<Var> flattened = new HashSet<Var>(); for (Iterator<Rel> axiomIter = problem.getAxioms().iterator(); axiomIter.hasNext(); ) { Rel rel = axiomIter.next(); unfoldVarsToSet(rel.getOutputs(), flattened); // do not overwrite values of variables that come via args of compute() or as inputs of // independent subtasks if (!problem.getAssumptions().containsAll(flattened) // do not overwrite values of already known variables. // typically this is the case when a value of a variable // is given in a scheme via a properties window // && !problem.getKnownVars().containsAll( flattened ) ) { algorithm.addRel(rel); } axiomIter.remove(); context.getKnownVars().addAll(flattened); flattened.clear(); } context.getFoundVars().addAll(context.getKnownVars()); // remove all known vars with no relations for (Iterator<Var> varIter = context.getKnownVars().iterator(); varIter.hasNext(); ) { if (varIter.next().getRels().isEmpty()) { varIter.remove(); } } // start planning if (problem.getRelsWithSubtasks().isEmpty() && linearForwardSearch(context, algorithm, computeAll)) { if (isLinearLoggingOn()) logger.debug("Problem solved without subtasks"); } else if (!problem.getRelsWithSubtasks().isEmpty() && subtaskPlanning(problem, algorithm)) { if (isLinearLoggingOn()) logger.debug("Problem solved with subtasks"); } else if (!computeAll) { if (isLinearLoggingOn()) logger.debug("Problem not solved"); } if (!nested) { logger.info("Planning time: " + (System.currentTimeMillis() - startTime) + "ms."); } return algorithm; }
/** * Goal-driven recursive (depth-first, exhaustive) search with backtracking * * @param problem * @param algorithm * @param subtaskRelsInPath * @param depth */ private boolean subtaskPlanningImpl( PlanningContext context, Set<Rel> relsWithSubtasks, EvaluationAlgorithm algorithm, LinkedList<Rel> subtaskRelsInPath, int depth) { Set<Rel> relsWithSubtasksCopy = new LinkedHashSet<Rel>(relsWithSubtasks); Set<Rel> relsWithSubtasksToRemove = new LinkedHashSet<Rel>(); boolean firstMLB = true; // start building Maximal Linear Branch (MLB) MLB: while (!relsWithSubtasksCopy.isEmpty()) { if (isSubtaskLoggingOn()) { String print = p(depth) + "Starting new MLB with: "; for (Rel rel : relsWithSubtasksCopy) { print += "\n" + p(depth) + " " + rel.getParent().getFullName() + " : " + rel.getDeclaration(); } /* print += "\n" + p( depth ) + " All remaining rels in problem:"; for ( Rel rel : problem.getAllRels() ) { print += "\n" + p( depth ) + " " + rel.getParentObjectName() + " : " + rel.getDeclaration(); } print += "\n" + p( depth ) + "All found variables: "; for ( Var var : problem.getFoundVars() ) { print += "\n" + p( depth ) + " " + var.toString(); } */ logger.debug(print); } // if this is a first attempt to construct an MLB to solve a subtask(i.e. depth>0), // do not invoke linear planning because it has already been done if ((depth == 0) || !firstMLB) { boolean solvedIntermediately = linearForwardSearch(context, algorithm, true); // Having constructed some MLBs the (sub)problem may be solved // and there is no need in wasting precious time planning unnecessary branches if (solvedIntermediately && ( // on the top level optimize only if computing goals (depth == 0 && !computeAll) // otherwise (inside subtasks) always optimize || (depth != 0))) { // If the problem is solved, optimize and return if (!isOptDisabled) Optimizer.optimize(context, algorithm); return true; } } else { firstMLB = false; } // or children OR: for (Iterator<Rel> subtaskRelIterator = relsWithSubtasksCopy.iterator(); subtaskRelIterator.hasNext(); ) { Rel subtaskRel = subtaskRelIterator.next(); if (isSubtaskLoggingOn()) logger.debug( p(depth) + "OR: depth: " + (depth + 1) + " rel - " + subtaskRel.getParent().getFullName() + " : " + subtaskRel.getDeclaration()); if (subtaskRel.equals(subtaskRelsInPath.peekLast()) || (!context.isRelReadyToUse(subtaskRel)) || context.getFoundVars().containsAll(subtaskRel.getOutputs()) || (!isSubtaskRepetitionAllowed && subtaskRelsInPath.contains(subtaskRel))) { if (isSubtaskLoggingOn()) { logger.debug(p(depth) + "skipped"); if (!context.isRelReadyToUse(subtaskRel)) { logger.debug(p(depth) + "because it has unknown inputs"); // TODO print unknown } else if (context.getFoundVars().containsAll(subtaskRel.getOutputs())) { logger.debug(p(depth) + "because all outputs in FoundVars"); } else if (subtaskRel.equals(subtaskRelsInPath.peekLast())) { logger.debug(p(depth) + "because it is nested in itself"); } else if (!isSubtaskRepetitionAllowed && subtaskRelsInPath.contains(subtaskRel)) { logger.debug( p(depth) + "This rel with subtasks is already in use, path: " + subtaskRelsInPath); } } continue OR; } LinkedList<Rel> newPath = new LinkedList<Rel>(subtaskRelsInPath); newPath.add(subtaskRel); PlanningResult result = new PlanningResult(subtaskRel, true); // this is true if all subtasks are solvable boolean allSolved = true; // and children AND: for (SubtaskRel subtask : subtaskRel.getSubtasks()) { if (isSubtaskLoggingOn()) logger.debug(p(depth) + "AND: subtask - " + subtask); EvaluationAlgorithm sbtAlgorithm = null; ////////////////////// INDEPENDENT SUBTASK//////////////////////////////////////// if (subtask.isIndependent()) { if (isSubtaskLoggingOn()) logger.debug("Independent!!!"); if (subtask.isSolvable() == null) { if (isSubtaskLoggingOn()) logger.debug("Start solving independent subtask " + subtask.getDeclaration()); // independent subtask is solved only once Problem problemContext = subtask.getContext(); DepthFirstPlanner planner = new DepthFirstPlanner(); planner.indSubtasks = indSubtasks; planner.nested = true; sbtAlgorithm = planner.invokePlaning(problemContext, isOptDisabled); PlanningContext indCntx = problemContext.getCurrentContext(); boolean solved = indCntx.getFoundVars().containsAll(indCntx.getAllGoals()); if (solved) { subtask.setSolvable(Boolean.TRUE); indSubtasks.put(subtask, sbtAlgorithm); if (isSubtaskLoggingOn()) logger.debug("Solved " + subtask.getDeclaration()); } else { subtask.setSolvable(Boolean.FALSE); if (RuntimeProperties.isLogInfoEnabled()) { logger.debug("Unable to solve " + subtask.getDeclaration()); } } allSolved &= solved; } else if (subtask.isSolvable() == Boolean.TRUE) { if (isSubtaskLoggingOn()) logger.debug("Already solved"); allSolved &= true; sbtAlgorithm = indSubtasks.get(subtask); } else { if (isSubtaskLoggingOn()) logger.debug("Not solvable"); allSolved &= false; } if (isSubtaskLoggingOn()) logger.debug("End of independent subtask " + subtask); if (!allSolved) { continue OR; } assert sbtAlgorithm != null; result.addSubtaskAlgorithm(subtask, sbtAlgorithm); } ////////////////////// DEPENDENT SUBTASK////////////////////////////////////// else { // lets clone the environment PlanningContext newContext = prepareNewContext(context, subtask); sbtAlgorithm = new EvaluationAlgorithm(); // during linear planning, if some goals are found, they are removed from the set // "goals" boolean solved = linearForwardSearch( newContext, sbtAlgorithm, // do not optimize here, because the solution may require additional rels with // subtasks true); if (solved) { if (isSubtaskLoggingOn()) logger.debug(p(depth) + "SOLVED subtask: " + subtask); if (!isOptDisabled) { // if a subtask has been solved, optimize its algorithm Optimizer.optimize(newContext, sbtAlgorithm); } result.addSubtaskAlgorithm(subtask, sbtAlgorithm); allSolved &= solved; continue AND; } else if (!solved && (depth == maxDepth)) { if (isSubtaskLoggingOn()) logger.debug(p(depth) + "NOT SOLVED and cannot go any deeper, subtask: " + subtask); continue OR; } if (isSubtaskLoggingOn()) logger.debug(p(depth) + "Recursing deeper"); solved = subtaskPlanningImpl(newContext, relsWithSubtasks, sbtAlgorithm, newPath, depth + 1); if (isSubtaskLoggingOn()) logger.debug(p(depth) + "Back to depth " + (depth + 1)); // the linear planning has been performed at the end of MLB on the depth+1, // if the problem was solved, there is no need to run linear planning again if ((solved || (solved = linearForwardSearch(newContext, sbtAlgorithm, true))) && !isOptDisabled) { // if solved, optimize here with full list of goals in order to get rid of // unnecessary subtask instances and other relations Optimizer.optimize(newContext, sbtAlgorithm); } if (isSubtaskLoggingOn()) logger.debug(p(depth) + (solved ? "" : "NOT") + " SOLVED subtask: " + subtask); allSolved &= solved; // if at least one subtask is not solvable, try another // branch if (!allSolved) { continue OR; } result.addSubtaskAlgorithm(subtask, sbtAlgorithm); } } // AND if (allSolved) { algorithm.add(result); Set<Var> newVars = new LinkedHashSet<Var>(); unfoldVarsToSet(subtaskRel.getOutputs(), newVars); context.getKnownVars().addAll(newVars); context.getFoundVars().addAll(newVars); subtaskRelIterator.remove(); if (isSubtaskLoggingOn()) { logger.debug( p(depth) + "SOLVED ALL SUBTASKS for " + subtaskRel.getParent().getFullName() + " : " + subtaskRel.getDeclaration()); logger.debug(p(depth) + "Updating the problem graph and continuing building new MLB"); } // this is used for incremental dfs if (depth == 0) { relsWithSubtasksToRemove.add(subtaskRel); } continue MLB; } if (isSubtaskLoggingOn()) logger.debug( p(depth) + "NOT SOLVED ALL subtasks, removing from path " + subtaskRel.getParent().getFullName() + " : " + subtaskRel.getDeclaration()); newPath.remove(subtaskRel); } // end OR // exit loop because there are no more rels with subtasks to be // applied // (i.e. no more rels can introduce new variables into the // algorithm) if (isSubtaskLoggingOn()) logger.debug(p(depth) + "No more MLB can be constructed"); break MLB; } // incremental dfs, remove solved subtasks if (depth == 0) { relsWithSubtasks.removeAll(relsWithSubtasksToRemove); } return false; }
private boolean subtaskPlanning(Problem problem, EvaluationAlgorithm algorithm) { if (isSubtaskLoggingOn()) logger.debug("!!!--------- Starting Planning With Subtasks ---------!!!"); final int maxDepthBackup = maxDepth; if (isSubtaskLoggingOn()) logger.debug( "maxDepthBackup:" + maxDepthBackup + " sbt: " + problem.getRelsWithSubtasks().size()); PlanningContext context = problem.getCurrentContext(); try { Set<Rel> relsWithSubtasks = new LinkedHashSet<Rel>(problem.getRelsWithSubtasks()); if (isIncremental) { int incrementalDepth = 0; while (incrementalDepth <= (isSubtaskRepetitionAllowed ? maxDepthBackup : problem.getRelsWithSubtasks().size() - 1)) { if (isSubtaskLoggingOn()) logger.debug( "Incremental dfs, with max depth " + (incrementalDepth + 1) + " and " + problem.getRelsWithSubtasks().size() + " subtasks to solve"); maxDepth = incrementalDepth++; // if we need to compute some specific goals, after reaching a certain depth, but not the // maximal depth, // the problem may be solved and there is no need to go any deeper. if (subtaskPlanningImpl(context, relsWithSubtasks, algorithm, new LinkedList<Rel>(), 0)) { if (isSubtaskLoggingOn()) logger.debug("The problem was solved during idfs after some intermediate MLB"); return true; } if (isSubtaskLoggingOn()) logger.debug("Unsolved subtask left: " + problem.getRelsWithSubtasks().size()); } if (isSubtaskLoggingOn()) logger.debug("Fininshed incremental dfs"); } else { if (!isSubtaskRepetitionAllowed) { maxDepth = problem.getRelsWithSubtasks().size() - 1; } if (isSubtaskLoggingOn()) logger.debug("Starting subtask dfs with maxDepth: " + (maxDepth + 1)); if (subtaskPlanningImpl(context, relsWithSubtasks, algorithm, new LinkedList<Rel>(), 0)) { if (isSubtaskLoggingOn()) logger.debug("The problem was solved during dfs after some intermediate MLB"); return true; } } } finally { if (isSubtaskLoggingOn()) logger.debug("Fininshed dfs"); maxDepth = maxDepthBackup; indSubtasks.clear(); } if (isSubtaskLoggingOn()) logger.debug("Invoking final linear planning"); return linearForwardSearch(context, algorithm, computeAll); }