00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031 import java.io.File;
00032 import java.util.ArrayList;
00033 import java.util.BitSet;
00034 import java.util.HashMap;
00035 import java.util.HashSet;
00036 import java.util.Iterator;
00037 import java.util.List;
00038 import java.util.Properties;
00039 import java.util.Set;
00040 import java.util.Stack;
00041
00042 import pddl4j.ErrorManager;
00043 import pddl4j.PDDLObject;
00044 import pddl4j.Parser;
00045 import pddl4j.RequireKey;
00046 import pddl4j.Source;
00047 import pddl4j.ErrorManager.Message;
00048 import pddl4j.InvalidExpException;
00049 import pddl4j.exp.AndExp;
00050 import pddl4j.exp.Exp;
00051 import pddl4j.exp.ExpID;
00052 import pddl4j.exp.InitEl;
00053 import pddl4j.exp.Literal;
00054 import pddl4j.exp.NotAtomicFormula;
00055 import pddl4j.exp.NotExp;
00056 import pddl4j.exp.term.Substitution;
00057 import pddl4j.exp.term.Variable;
00058 import pddl4j.exp.term.Term;
00059 import pddl4j.exp.AtomicFormula;
00060 import pddl4j.exp.action.Action;
00061 import pddl4j.exp.action.ActionDef;
00062 import pddl4j.exp.action.ActionID;
00063 import pddl4j.exp.fcomp.FCompExp;
00064 import pddl4j.exp.term.Constant;
00065
00073 public final class Graphplan {
00074
00078 public PDDLObject problem;
00079
00083 private BitSet goals;
00084
00088 private ArrayList<BitSet> ops_layers;
00089
00093 private ArrayList<BitSet> facts_layers;
00094
00098 private ArrayList<BitMatrix> ops_mutex;
00099
00103 private ArrayList<BitMatrix> facts_mutex;
00104
00108 private ArrayList<Op> ops_table = new ArrayList<Op>(1000);
00109
00113 private ArrayList<Fact> facts_table;
00114
00118 private BitMatrix dependences;
00119
00123 private int levelOff = -1;
00124
00128 private int ops_index;
00129
00133 private HashMap<Integer, Set<BitSet>> nogoods;
00134
00138 private ArrayList<BitMatrix> resolvers;
00139
00143 private int facts_table_size;
00144
00148 private int ops_table_size;
00149
00153 private long g_time = 0;
00154
00158 private long s_time = 0;
00159
00163 private long p_time = 0;
00164
00168 private long m_time = 0;
00169
00173 public long a_tried = 0;
00174
00178 public long noop_tried = 0;
00179
00185 public Graphplan(PDDLObject problem) {
00186 this.problem = problem;
00187 this.facts_layers = new ArrayList<BitSet>(100);
00188 this.ops_layers = new ArrayList<BitSet>(100);
00189 this.facts_mutex = new ArrayList<BitMatrix>(100);
00190 this.ops_mutex = new ArrayList<BitMatrix>(100);
00191 this.resolvers = new ArrayList<BitMatrix>(100);
00192 }
00193
00194
00201 public static void main(String[] args) {
00202 try {
00203
00204 if (args.length != 2) {
00205 Graphplan.printUsage();
00206 } else {
00207
00208 Properties options = Graphplan.getParserOptions();
00209
00210 if (!new File(args[0]).exists()) {
00211 System.out.println("domain file " + args[0] + " does not exist");
00212 System.exit(0);
00213 }
00214 if (!new File(args[1]).exists()) {
00215 System.out.println("problem file " + args[0] + " does not exist");
00216 System.exit(0);
00217 }
00218 Parser parser = new Parser(options);
00219 PDDLObject domain = parser.parse(new File(args[0]));
00220 PDDLObject problem = parser.parse(new File(args[1]));
00221 PDDLObject pb = null;
00222 if (domain != null && problem != null) {
00223 pb = parser.link(domain, problem);
00224 }
00225
00226 ErrorManager mgr = parser.getErrorManager();
00227
00228 if (mgr.contains(Message.ERROR)) {
00229 mgr.print(Message.ALL);
00230 }
00231
00232 else {
00233
00234 mgr.print(Message.WARNING);
00235
00236 System.out.println("\nParsing domain \"" + domain.getDomainName() + "\" done successfully ...");
00237 System.out.println("Parsing problem \"" + problem.getProblemName() + "\" done successfully ...\n");
00238
00239 Graphplan planner = new Graphplan(pb);
00240 planner.preprocessing();
00241 Plan plan = planner.solve();
00242
00243 if (plan != Plan.FAILURE) {
00244 System.out.println("\nfound plan as follows:\n");
00245 Graphplan.printPlan(plan);
00246 } else {
00247 System.out.println("\nno solution plan found\n");
00248 }
00249 System.out.printf("\nnumber of actions tried : %12d \n", planner.a_tried);
00250 System.out.printf("number of noops tried : %12d \n\n", planner.noop_tried);
00251
00252 final double p_time = planner.p_time/1000000000.0;
00253 final double g_time = planner.g_time/1000000000.0;
00254 final double s_time = planner.s_time/1000000000.0;
00255 final double m_time = planner.m_time/1000000000.0;
00256 final double t_time = p_time + g_time + s_time;
00257 System.out.printf("Time spent : %8.2f seconds preprocessing \n", p_time);
00258 System.out.printf(" %8.2f seconds build graph \n", g_time);
00259 System.out.printf(" %8.2f seconds calculating exclusions \n", m_time);
00260 System.out.printf(" %8.2f seconds searching graph \n", s_time);
00261 System.out.printf(" %8.2f seconds total time \n", t_time);
00262 }
00263 }
00264 } catch (Throwable t) {
00265 System.err.println(t.getMessage());
00266 t.printStackTrace(System.err);
00267 }
00268 }
00269
00270
00276 public static Properties getParserOptions() {
00277 Properties options = new Properties();
00278 options.put("source", Source.V3_0);
00279 options.put(RequireKey.STRIPS, true);
00280 options.put(RequireKey.TYPING, true);
00281 options.put(RequireKey.EQUALITY, true);
00282 options.put(RequireKey.NEGATIVE_PRECONDITIONS, false);
00283 options.put(RequireKey.DISJUNCTIVE_PRECONDITIONS, true);
00284 options.put(RequireKey.EXISTENTIAL_PRECONDITIONS, true);
00285 options.put(RequireKey.UNIVERSAL_PRECONDITIONS, true);
00286 options.put(RequireKey.CONDITIONAL_EFFECTS, true);
00287 return options;
00288 }
00289
00290
00294 public static void printUsage() {
00295 System.out.println("Usage: graphplan [domain] [problem]");
00296 System.exit(0);
00297 }
00298
00299
00300
00301
00302
00309 public Plan solve() {
00310 Plan plan = Plan.FAILURE;
00311 int nbNoGoods = 0;
00312
00313 int k = 0;
00314 while ((!this.contains(this.goals, k) || !this.isMutexFree(this.goals, k)) && !this.isLevelOff()) {
00315 this.expand(k);
00316 k++;
00317 if (this.contains(this.goals, k) && this.isMutexFree(this.goals, k)) {
00318 System.out.print("\ngoals first reachable in " + k + " times steps\n\n");
00319 }
00320 }
00321
00322 if (!this.contains(this.goals, k) || !this.isMutexFree(goals, k)) {
00323 return Plan.FAILURE;
00324 }
00325
00326 long begin = System.nanoTime();
00327 plan = this.extract(goals, k);
00328 long end = System.nanoTime();
00329 this.s_time += end -begin;
00330
00331 if (this.isLevelOff()) {
00332 nbNoGoods = nogoods.get(this.levelOff).size();
00333 } else {
00334 nbNoGoods = 0;
00335 }
00336
00337 while (plan == Plan.FAILURE) {
00338 this.expand(k);
00339 k++;
00340 begin = System.nanoTime();
00341 plan = this.extract(goals, k);
00342 end = System.nanoTime();
00343 this.s_time += end - begin;
00344 if (plan == Plan.FAILURE && this.isLevelOff()) {
00345 final int nbNoGoodsAtLevelOff = nogoods.get(this.levelOff).size();
00346 if (nbNoGoods == nbNoGoodsAtLevelOff) {
00347 plan = Plan.FAILURE;
00348 } else {
00349 nbNoGoods = nbNoGoodsAtLevelOff;
00350 }
00351 }
00352 }
00353 return plan;
00354 }
00355
00364 private Plan extract(final BitSet goals, final int k) {
00365 Plan plan = null;
00366 if (k == 0) {
00367 return plan = Plan.EMPTY;
00368 }
00369 Set<BitSet> ngk = nogoods.get(k);
00370 if (ngk != null && ngk.contains(goals)) {
00371 return Plan.FAILURE;
00372 }
00373 plan = this.search(goals, new BitSet(this.ops_table_size), k, new BitSet(this.facts_table_size));
00374 if (plan == Plan.FAILURE) {
00375 ngk = nogoods.get(k);
00376 if (ngk == null) {
00377 ngk = new HashSet<BitSet>();
00378 nogoods.put(k, ngk);
00379 }
00380 ngk.add(goals);
00381 }
00382 return plan;
00383 }
00384
00385
00395 private Plan search(final BitSet goals, final BitSet ak, final int k, final BitSet mutex) {
00396 Plan plan = Plan.FAILURE;
00397 if (goals.isEmpty()) {
00398 for (int i = ak.nextSetBit(0); i >= 0; i = ak.nextSetBit(i + 1)) {
00399 goals.or(this.ops_table.get(i).getPositivePreconditon());
00400 }
00401 plan = this.extract(goals, k - 1);
00402 if (plan != Plan.FAILURE) {
00403 for (int i = ak.nextSetBit(0); i >= 0; i = ak.nextSetBit(i + 1)) {
00404 AtomicFormula op_name = this.ops_table.get(i).getName();
00405 if (!op_name.getPredicate().startsWith("noop")) {
00406 plan.add(op_name, k - 1);
00407 }
00408 }
00409
00410 }
00411 } else {
00412
00413 final Fact goal = this.selectGoal(goals);
00414 final BitSet resolvers = (BitSet) this.getResolvers(goal.getId(), k).clone();
00415 resolvers.andNot(mutex);
00416
00417 while (!resolvers.isEmpty() && plan == null) {
00418 final Op resolver = this.selectResolver(resolvers);
00419 final int resolver_id = resolver.getId();
00420 resolvers.clear(resolver_id);
00421 final BitSet newAk = (BitSet) ak.clone();
00422 newAk.set(resolver_id);
00423 final BitSet newMutex = (BitSet) mutex.clone();
00424 newMutex.or(this.ops_mutex.get(k - 1).getRow(resolver_id));
00425 final BitSet newGoals = (BitSet) goals.clone();
00426 newGoals.andNot(resolver.getPositiveEffect());
00427 plan = this.search(newGoals, newAk, k, newMutex);
00428 }
00429 }
00430 return plan;
00431
00432 }
00433
00442 private Fact selectGoal(BitSet goals) {
00443 int i = goals.nextSetBit(0);
00444 Fact fact = this.facts_table.get(i);
00445 i = goals.nextSetBit(i + 1);
00446 while (i >= 0) {
00447 final Fact fi = this.facts_table.get(i);
00448 if (fact.getLevel() < fi.getLevel()) {
00449 fact = fi;
00450 }
00451 i = goals.nextSetBit(i + 1);
00452 }
00453 return fact;
00454 }
00455
00464 private Op selectResolver(final BitSet resolvers) {
00465 int i = resolvers.nextSetBit(0);
00466 Op resolver = this.ops_table.get(i);
00467 int lr = resolver.getLevel();
00468 i = resolvers.nextSetBit(i + 1);
00469 while (i >= 0) {
00470 final Op opi = this.ops_table.get(i);
00471 final int li = opi.getLevel();
00472 if (lr > li) {
00473 lr = li;
00474 resolver = opi;
00475 }
00476 i = resolvers.nextSetBit(i + 1);
00477 }
00478
00479 if (resolver.getId() > this.ops_index) {
00480 this.a_tried++;
00481 } else {
00482 this.noop_tried++;
00483 }
00484 return resolver;
00485 }
00486
00487
00488
00489
00490
00500 private BitSet getResolvers(final int i, final int k) {
00501 return this.resolvers.get(k - 1).getRow(i);
00502 }
00503
00515 private boolean isApplicable(final Op op, final int k) {
00516 final BitSet pre = op.getPositivePreconditon();
00517 return this.contains(pre, k) && this.isMutexFree(pre, k);
00518
00519 }
00520
00531 private boolean isMutexFree(final BitSet facts, final int k) {
00532 boolean free = true;
00533 final BitMatrix mk = this.facts_mutex.get(k);
00534 int i = facts.nextSetBit(0);
00535 while (i >= 0 && free) {
00536 free = !mk.getRow(i).intersects(facts);
00537 i = facts.nextSetBit(i + 1);
00538 }
00539 return free;
00540
00541 }
00542
00552 private boolean contains(final BitSet facts, final int k) {
00553 final BitSet pi = (BitSet) this.facts_layers.get(k).clone();
00554 pi.and(facts);
00555 return pi.equals(facts);
00556 }
00557
00563 private void expand(final int k) {
00564 if (!this.isLevelOff()) {
00565 final long t1 = System.nanoTime();
00566
00567
00568 final BitSet ak = (BitSet) this.facts_layers.get(k).clone();
00569
00570
00571 if (k > 0) {
00572 ak.or(this.ops_layers.get(k - 1));
00573 }
00574 this.ops_layers.add(ak);
00575 this.ops_mutex.add(new BitMatrix(this.ops_table.size()));
00576 final BitSet pk_1 = (BitSet) this.facts_layers.get(k).clone();
00577 this.facts_layers.add(pk_1);
00578 this.facts_mutex.add(new BitMatrix(this.facts_table_size));
00579 final BitMatrix rk = new BitMatrix(this.facts_table_size, this.ops_table_size);
00580 this.resolvers.add(rk);
00581
00582 for (int i = ak.nextClearBit(this.ops_index); i >= 0
00583 && i < this.ops_table_size; i = ak.nextClearBit(i + 1)) {
00584 final Op opi = this.ops_table.get(i);
00585 if (this.isApplicable(opi, k)) {
00586 opi.setLevel(k);
00587 ak.set(opi.getId(), true);
00588 pk_1.or(opi.getPositiveEffect());
00589 pk_1.or(opi.getNegativeEffect());
00590 }
00591 }
00592
00593
00594 final BitSet newFacts = (BitSet) this.facts_layers.get(k).clone();
00595 newFacts.xor(pk_1);
00596 for (int i = newFacts.nextSetBit(0); i >= 0; i = newFacts.nextSetBit(i + 1)) {
00597 this.facts_table.get(i).setLevel(k);
00598 }
00599
00600
00601 for (int i = pk_1.nextSetBit(0); i >= 0; i = pk_1.nextSetBit(i + 1)) {
00602 for (int j = ak.nextSetBit(0); j >= 0; j = ak.nextSetBit(j + 1)) {
00603 if (this.ops_table.get(j).getPositiveEffect().get(i)) {
00604 rk.set(i, j);
00605 }
00606 }
00607 }
00608
00609
00610 long t2 = System.nanoTime();
00611 final BitMatrix mak = this.ops_mutex.get(k);
00612 for (int i = ak.nextSetBit(0); i >= 0; i = ak.nextSetBit(i + 1)) {
00613 for (int j = ak.nextSetBit(0); j >= 0; j = ak.nextSetBit(j + 1)) {
00614 if (i > j && this.areMutexOps(i, j, k)) {
00615 mak.set(i, j);
00616 mak.set(j, i);
00617 }
00618 }
00619 }
00620
00621 final BitMatrix mpk_1 = this.facts_mutex.get(k + 1);
00622 for (int i = pk_1.nextSetBit(0); i >= 0; i = pk_1.nextSetBit(i + 1)) {
00623 for (int j = pk_1.nextSetBit(0); j >= 0; j = pk_1.nextSetBit(j + 1)) {
00624 if (i > j && areMutexFact(i, j, k + 1)) {
00625 mpk_1.set(i, j);
00626 mpk_1.set(j, i);
00627 }
00628 }
00629 }
00630
00631 final long t3 = System.nanoTime();
00632 this.m_time += t3 - t2;
00633 final long lTime = t3 - t1;
00634 this.g_time += lTime;
00635 final int facts = this.facts_layers.get(k).cardinality();
00636 final int fm = this.facts_mutex.get(k).cardinality() / 2;
00637 final int ops = this.ops_layers.get(k).cardinality();
00638 final int om = this.ops_mutex.get(k).cardinality() / 2;
00639 System.out.printf("time: %4d, %8d facts, %10d and exlusive pairs (%2.4fs)\n",
00640 k, facts, fm, lTime / 1000000000.0);
00641 System.out.printf(" %8d ops, %12d exlusive pairs\n", ops, om);
00642
00643 if (this.isLevelOff()) {
00644 System.out.print("\ngraph has leveled off! wave front mechanism is taking over\n\n");
00645 }
00646
00647 } else {
00648 this.ops_layers.add(this.ops_layers.get(k - 1));
00649 this.ops_mutex.add(this.ops_mutex.get(k - 1));
00650 this.facts_layers.add(this.facts_layers.get(k));
00651 this.facts_mutex.add(this.facts_mutex.get(k));
00652 this.resolvers.add(this.resolvers.get(k - 1));
00653 System.out.printf("expanding wave front to level %4d\n", k);
00654 }
00655 }
00656
00657
00658
00670 private boolean areMutexFact(int i, int j, int k) {
00671 boolean mutex = false;
00672 if (k > 0) {
00673 mutex = true;
00674 BitMatrix mak = this.ops_mutex.get(k - 1);
00675 BitSet rak = this.getResolvers(i, k);
00676 BitSet rbk = this.getResolvers(j, k);
00677 int ra = rak.nextSetBit(0);
00678 while (ra >= 0 && mutex) {
00679 int rb = rbk.nextSetBit(0);
00680 while (rb >= 0 && mutex) {
00681 mutex = mak.get(ra, rb);
00682 rb = rbk.nextSetBit(rb + 1);
00683 }
00684 ra = rak.nextSetBit(ra + 1);
00685 }
00686 }
00687 return mutex;
00688 }
00689
00701 private boolean areMutexOps(final int i, final int j, final int k) {
00702 if (!this.dependences.get(i, j)) {
00703 boolean mutex = false;
00704 final BitSet ppi = this.ops_table.get(i).getPositivePreconditon();
00705 final BitSet ppj = this.ops_table.get(j).getPositivePreconditon();
00706 final BitMatrix mk = this.facts_mutex.get(k);
00707 int mi = ppi.nextSetBit(0);
00708 while (mi >= 0 && !mutex) {
00709 mutex = mk.getRow(mi).intersects(ppj);
00710 mi = ppi.nextSetBit(mi + 1);
00711 }
00712 return mutex;
00713 }
00714 return true;
00715 }
00716
00724 public boolean isLevelOff() {
00725 if (this.levelOff == -1) {
00726 if (this.facts_layers.size() > 3) {
00727 int last = this.facts_layers.size() - 1;
00728 final BitSet pn = this.facts_layers.get(last);
00729 final BitMatrix mpn = this.facts_mutex.get(last);
00730 final BitSet an = this.ops_layers.get(last - 2);
00731 final BitMatrix man = this.ops_mutex.get(last - 2);
00732 final BitSet pn_1 = this.facts_layers.get(last - 2);
00733 final BitMatrix mpn_1 = this.facts_mutex.get(last - 2);
00734 final BitSet an_1 = this.ops_layers.get(last - 3);
00735 final BitMatrix man_1 = this.ops_mutex.get(last - 3);
00736 if (pn.equals(pn_1) && an.equals(an_1) && mpn.equals(mpn_1)
00737 && man.equals(man_1)) {
00738 this.levelOff = last;
00739 return true;
00740 }
00741 }
00742 return false;
00743 }
00744 return true;
00745 }
00746
00747
00748
00749
00750
00759 public void preprocessing() throws InvalidExpException {
00760 long begin = System.nanoTime();
00761 System.out.println("Preprocessing ...\n");
00762 this.initFacts();
00763 this.initOps();
00764 this.initOpsDependences();
00765 this.initGoals();
00766 this.initPlanningGraph();
00767 this.initNogoodsTable();
00768 long end = System.nanoTime();
00769 this.p_time = (end - begin);
00770 }
00771
00775 private void initNogoodsTable() {
00776 this.nogoods = new HashMap<Integer, Set<BitSet>>();
00777 }
00778
00782 private void initFacts() {
00783 this.facts_table = new ArrayList<Fact>(100);
00784 Iterator<AtomicFormula> i = this.problem.predicatesIterator();
00785 while (i.hasNext()) {
00786 AtomicFormula skeleton = i.next();
00787 final List<Term> args = new ArrayList<Term>();
00788 for (Term arg: skeleton) {
00789 args.add(arg);
00790 }
00791 this.instantiateFacts(skeleton, args, new Substitution());
00792 }
00793 this.facts_table_size = this.facts_table.size();
00794 }
00795
00806 private void instantiateFacts(final AtomicFormula skeleton,
00807 final List<Term> args,
00808 final Substitution sigma) {
00809 if (args.isEmpty()) {
00810 final Fact fact = new Fact(skeleton.apply(sigma), this.facts_table.size());
00811 this.facts_table.add(fact);
00812 } else {
00813 final Variable var = (Variable) args.get(0);
00814 final Set<Constant> values = this.problem.getTypedDomain(var.getTypeSet());
00815 for (Constant c : values) {
00816 sigma.bind(var, c);
00817 final List<Term> newArgs = new ArrayList<Term>(args);
00818 Term t = newArgs.remove(0);
00819 this.instantiateFacts(skeleton, newArgs, sigma);
00820 }
00821
00822 }
00823 }
00824
00825
00832 private void initOps() throws InvalidExpException {
00833
00834
00835 for (int i = 0; i < this.facts_table_size; i++) {
00836 this.addNewNoOp(this.facts_table.get(i));
00837 }
00838 this.ops_index = this.ops_table.size();
00839 Iterator<ActionDef> i = this.problem.actionsIterator();
00840 while (i.hasNext()) {
00841 ActionDef a = i.next();
00842 if (a.getActionID().equals(ActionID.ACTION)) {
00843 Action op = (Action) a;
00844 List<Term> parameters = new ArrayList<Term>(op.getParameters());
00845 this.instantiateOps(op, parameters, new Substitution());
00846 }
00847 }
00848 this.ops_table_size = this.ops_table.size();
00849 }
00850
00861 private void instantiateOps(final Action action,
00862 final List<Term> param,
00863 final Substitution sigma)
00864 throws InvalidExpException {
00865
00866 if (param.isEmpty()) {
00867 this.addNewOp(action, sigma);
00868 } else {
00869 final Variable var = (Variable) param.get(0);
00870 final Set<Constant> values = this.problem.getTypedDomain(var.getTypeSet());
00871 for (Constant c : values) {
00872 sigma.bind(var, c);
00873 final List<Term> newParam = new ArrayList<Term>(param);
00874 newParam.remove(0);
00875 this.instantiateOps(action, newParam, sigma);
00876 }
00877 }
00878 }
00879
00880
00890 private boolean addNewOp(Action action, Substitution sigma)
00891 throws InvalidExpException {
00892 boolean added = false;
00893 AtomicFormula name = new AtomicFormula(action.getName());
00894 for (Term p : action.getParameters()) {
00895 name.add((Constant) sigma.getBinding((Variable) p));
00896 }
00897 BitSet[] pre = expToBitSet(action.getPrecondition().apply(sigma));
00898 if (pre != null) {
00899 BitSet[] eff = expToBitSet(action.getEffect().apply(sigma));
00900 Op op = new Op(name, pre[0], pre[1], eff[0], eff[1], this.ops_table.size());
00901 this.ops_table.add(op);
00902 added = true;
00903 }
00904 return added;
00905
00906 }
00907
00913 private void addNewNoOp(final Fact fact) {
00914 AtomicFormula name = fact.clone();
00915 name.setPredicate("noop-" + name.getPredicate());
00916 BitSet pp = new BitSet(this.facts_table_size);
00917 pp.set(fact.getId());
00918 BitSet np = new BitSet(this.facts_table_size);
00919 BitSet pe = new BitSet(this.facts_table_size);
00920 pe.set(fact.getId());
00921 BitSet ne = new BitSet(this.facts_table_size);
00922 Op op = new Op(name, pp, np, pe, ne, this.ops_table.size());
00923 this.ops_table.add(op);
00924 }
00925
00929 private void initOpsDependences() {
00930 this.dependences = new BitMatrix(this.ops_table.size());
00931 final int ops_size = this.ops_table.size();
00932 for (int i = this.ops_index; i < ops_size; i++) {
00933 final Op opi = this.ops_table.get(i);
00934 for (int j = 0; j < this.ops_index; j++) {
00935 final Op opj = this.ops_table.get(j);
00936 if (opi.getId() > opj.getId() && are_dependent(opi, opj)) {
00937 this.dependences.set(opi.getId(), opj.getId());
00938 this.dependences.set(opj.getId(), opi.getId());
00939 }
00940 }
00941 }
00942 for (int i = 0; i < ops_size; i++) {
00943 final Op opi = this.ops_table.get(i);
00944 for (int j = this.ops_index; j < ops_size; j++) {
00945 final Op opj = this.ops_table.get(j);
00946 if (opi.getId() > opj.getId() && are_dependent(opi, opj)) {
00947 this.dependences.set(opi.getId(), opj.getId());
00948 this.dependences.set(opj.getId(), opi.getId());
00949 }
00950 }
00951 }
00952
00953 }
00954
00964 private boolean are_dependent(final Op op1, final Op op2) {
00965 return op1.getNegativeEffect().intersects(op2.getPositivePreconditon())
00966 || op1.getNegativeEffect().intersects(op2.getPositiveEffect())
00967 || op2.getNegativeEffect().intersects(op1.getPositivePreconditon())
00968 || op2.getNegativeEffect().intersects(op1.getPositiveEffect());
00969 }
00970
00978 private void initPlanningGraph() throws InvalidExpException {
00979 final BitSet p0 = new BitSet(this.facts_table_size);
00980 final List<InitEl> init = this.problem.getInit();
00981 for (InitEl el : init) {
00982 if (el.getExpID().equals(ExpID.ATOMIC_FORMULA)) {
00983 AtomicFormula predicate = (AtomicFormula) el;
00984 p0.set(this.facts_table.indexOf(predicate), true);
00985 } else {
00986 throw new InvalidExpException(el.getExpID());
00987 }
00988 }
00989 this.facts_layers.add(p0);
00990 this.facts_mutex.add(new BitMatrix(this.facts_table_size));
00991 }
00992
00993
01001 private void initGoals() throws InvalidExpException {
01002 final Exp goal = this.problem.getGoal();
01003 this.goals = new BitSet(this.facts_table_size);
01004 if (goal.getExpID().equals(ExpID.AND)) {
01005 final AndExp andExp = (AndExp) goal;
01006 for (Exp e : andExp) {
01007 if (e.getExpID().equals(ExpID.ATOMIC_FORMULA)) {
01008 final AtomicFormula predicate = (AtomicFormula) e;
01009 this.goals.set(this.facts_table.indexOf(predicate), true);
01010 } else {
01011 throw new InvalidExpException(e.getExpID());
01012 }
01013 }
01014 } else {
01015 throw new InvalidExpException(goal.getExpID());
01016 }
01017 }
01018
01019
01020
01021
01022
01033 private BitSet[] expToBitSet(final Exp exp)
01034 throws InvalidExpException {
01035 BitSet[] bitSet = new BitSet[2];
01036 bitSet[0] = new BitSet(this.facts_table_size);
01037 bitSet[1] = new BitSet(this.facts_table_size);
01038 HashSet<Literal> literals = null;
01039
01040 literals = this.toLiteralSet(exp);
01041 if (literals != null) {
01042 for (Literal literal : literals) {
01043 if (literal.getExpID().equals(ExpID.ATOMIC_FORMULA)) {
01044 AtomicFormula predicate = (AtomicFormula) literal;
01045 final int index = this.facts_table.indexOf(predicate);
01046 bitSet[0].set(index);
01047 } else {
01048 NotAtomicFormula notExp = (NotAtomicFormula) literal;
01049 AtomicFormula predicate = (AtomicFormula) notExp.getExp();
01050 final int index = this.facts_table.indexOf(predicate);
01051 bitSet[1].set(index);
01052 }
01053 }
01054 } else {
01055 bitSet = null;
01056 }
01057 return bitSet;
01058
01059 }
01060
01069 private HashSet<Literal> toLiteralSet(final Exp exp) throws InvalidExpException {
01070 HashSet<Literal> literals = new HashSet<Literal>();
01071
01072 Stack<Exp> stack = new Stack<Exp>();
01073 stack.add(exp);
01074 boolean failure = false;
01075
01076 while (!stack.isEmpty() && !failure) {
01077 Exp e = stack.pop();
01078 switch (e.getExpID()) {
01079 case AND:
01080 AndExp andExp = (AndExp) e;
01081 for (Exp sexp : andExp) {
01082 stack.push(sexp);
01083 }
01084 break;
01085 case ATOMIC_FORMULA:
01086 AtomicFormula p = (AtomicFormula) e;
01087 literals.add(p.clone());
01088 break;
01089 case F_COMP:
01090 FCompExp fcomp = (FCompExp) e;
01091 failure = !fcomp.evaluate();
01092 break;
01093 case NOT:
01094 NotExp notExp = (NotExp) e;
01095 Exp nexp = notExp.getExp();
01096 switch (nexp.getExpID()) {
01097 case F_COMP:
01098 fcomp = (FCompExp) nexp;
01099 failure = fcomp.evaluate();
01100 break;
01101 default:
01102 HashSet<Literal> pl = toLiteralSet(notExp.getExp());
01103 if (pl != null) {
01104 for (Literal l : pl) {
01105 NotAtomicFormula f = new NotAtomicFormula((AtomicFormula) l);
01106 literals.add(f);
01107 }
01108 } else {
01109 failure = true;
01110 }
01111 }
01112 break;
01113 default:
01114 throw new InvalidExpException(exp.getExpID());
01115 }
01116 }
01117 return failure ? null : literals;
01118 }
01119
01120
01121
01122
01123
01124
01125
01131 public static void printPlan(Plan plan) {
01132 int i = 0;
01133 for (Set<AtomicFormula> layer : plan) {
01134 StringBuffer str = new StringBuffer();
01135 System.out.printf("time step %4d: ", i);
01136 int j = 0;
01137 for (AtomicFormula action : layer) {
01138 StringBuffer as = new StringBuffer();
01139 as.append(action.getPredicate().toUpperCase());
01140
01141 for (Term parameter : action) {
01142 as.append(" " + parameter.getImage().toUpperCase());
01143
01144 }
01145 if (j > 0) str.append(" ");
01146 str.append(as.toString());
01147 if (j < layer.size() - 1) str.append("\n");
01148 j++;
01149 }
01150 System.out.println(str.toString());
01151 i++;
01152 }
01153
01154 }
01155
01159 private void printOpsTable() {
01160 for (Op op : this.ops_table) {
01161 System.out.println(this.opToString(op));
01162 }
01163 }
01164
01165
01171 private void printPropAt(int k) {
01172 BitSet ops = this.facts_layers.get(k);
01173 for (int i = ops.nextSetBit(0); i >= 0; i = ops.nextSetBit(i + 1)) {
01174 System.out.println(this.facts_table.get(i));
01175 }
01176 System.out.println("");
01177 }
01178
01184 private void printOpAt(int k) {
01185 BitSet ops = this.ops_layers.get(k);
01186 for (int i = ops.nextSetBit(0); i >= 0; i = ops.nextSetBit(i + 1)) {
01187 System.out.println(this.ops_table.get(i).getName());
01188 }
01189 System.out.println("");
01190 }
01191
01197 private void printOpMutexAt(int k) {
01198 BitMatrix mutex = this.ops_mutex.get(k);
01199 BitSet ops = this.ops_layers.get(k);
01200 for (int i = ops.nextSetBit(0); i >= 0; i = ops.nextSetBit(i + 1)) {
01201 System.out.print(this.ops_table.get(i).getName() + "\n mutex:");
01202 BitSet vector = mutex.getRow(i);
01203 for (int j = vector.nextSetBit(0); j >= 0; j = vector.nextSetBit(j+1)) {
01204 System.out.print(" " + this.ops_table.get(j).getName());
01205 }
01206 System.out.println("");
01207 }
01208 }
01209
01215 private void printPropMutexAt(int k) {
01216 BitMatrix mutex = this.facts_mutex.get(k);
01217 BitSet props = this.facts_layers.get(k);
01218 for (int i = props.nextSetBit(0); i >= 0; i = props.nextSetBit(i + 1)) {
01219 System.out.print(this.facts_table.get(i) + "\n mutex:");
01220 BitSet vector = mutex.getRow(i);
01221 for (int j = vector.nextSetBit(0); j >= 0; j = vector.nextSetBit(j+1)) {
01222 System.out.print(" " + this.facts_table.get(j));
01223 }
01224 System.out.println("");
01225 }
01226 }
01227
01235 public String opToString(Op op) {
01236 StringBuffer str = new StringBuffer();
01237 str.append("Op ");
01238 str.append(op.getName());
01239 str.append("\n");
01240 str.append("precondition:\n");
01241 str.append("(");
01242 if (!op.getPositivePreconditon().isEmpty()) {
01243 int i =op.getPositivePreconditon().nextSetBit(0);
01244 if (i >= 0) {
01245 str.append(this.facts_table.get(i));
01246 }
01247 i = op.getPositivePreconditon().nextSetBit(i + 1);
01248 while (i >= 0) {
01249 str.append(" AND ");
01250 str.append(this.facts_table.get(i));
01251 i = op.getPositivePreconditon().nextSetBit(i + 1);
01252 }
01253 }
01254 if (!op.getNegativePrecondition().isEmpty()) {
01255 int i = op.getNegativePrecondition().nextSetBit(0);
01256 if (i >= 0) {
01257 str.append(this.facts_table.get(i));
01258 }
01259 i = op.getNegativePrecondition().nextSetBit(i + 1);
01260 while (i >= 0) {
01261 str.append(" AND (NOT ");
01262 str.append(this.facts_table.get(i));
01263 str.append(")");
01264 i = op.getNegativePrecondition().nextSetBit(i + 1);
01265 }
01266 }
01267 str.append(")\n");
01268 str.append("effect:\n");
01269 str.append("(");
01270 if (!op.getPositiveEffect().isEmpty()) {
01271 int i = op.getPositiveEffect().nextSetBit(0);
01272 if (i >= 0) {
01273 str.append(this.facts_table.get(i));
01274 }
01275 i = op.getPositiveEffect().nextSetBit(i + 1);
01276 while (i >= 0) {
01277 str.append(" AND ");
01278 str.append(this.facts_table.get(i));
01279 i = op.getPositiveEffect().nextSetBit(i + 1);
01280 }
01281 }
01282 if (!op.getNegativeEffect().isEmpty()) {
01283 int i = op.getNegativeEffect().nextSetBit(0);
01284 if (i >= 0) {
01285 str.append(this.facts_table.get(i));
01286 }
01287 i = op.getNegativeEffect().nextSetBit(i + 1);
01288 while (i >= 0) {
01289 str.append(" AND (NOT ");
01290 str.append(this.facts_table.get(i));
01291 str.append(")");
01292 i = op.getNegativeEffect().nextSetBit(i + 1);
01293 }
01294 }
01295 str.append(")");
01296 return str.toString();
01297
01298 }
01299 }