Graphplan.java
Go to the documentation of this file.
00001 /*
00002  * Copyright Dept. of Mathematics & Computer Science Univ. Paris-Descartes
00003  *
00004  * This software is governed by the CeCILL  license under French law and
00005  * abiding by the rules of distribution of free software.  You can  use,
00006  * modify and/ or redistribute the software under the terms of the CeCILL
00007  * license as circulated by CEA, CNRS and INRIA at the following URL
00008  * "http://www.cecill.info".
00009  *
00010  * As a counterpart to the access to the source code and  rights to copy,
00011  * modify and redistribute granted by the license, users are provided only
00012  * with a limited warranty  and the software's author,  the holder of the
00013  * economic rights,  and the successive licensors  have only  limited
00014  * liability.
00015  *
00016  * In this respect, the user's attention is drawn to the risks associated
00017  * with loading,  using,  modifying and/or developing or reproducing the
00018  * software by the user in light of its specific status of free software,
00019  * that may mean  that it is complicated to manipulate,  and  that  also
00020  * therefore means  that it is reserved for developers  and  experienced
00021  * professionals having in-depth computer knowledge. Users are therefore
00022  * encouraged to load and test the software's suitability as regards their
00023  * requirements in conditions enabling the security of their systems and/or
00024  * data to be ensured and,  more generally, to use and operate it in the
00025  * same conditions as regards security.
00026  *
00027  * The fact that you are presently reading this means that you have had
00028  * knowledge of the CeCILL license and that you accept its terms.
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             // Checks the command line
00204             if (args.length != 2) {
00205                 Graphplan.printUsage();
00206             } else {
00207                 // Gets the pddl compiler options
00208                 Properties options = Graphplan.getParserOptions();
00209                 // Creates an instance of the java pddl compiler
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                 // Gets the error manager of the pddl compiler
00226                 ErrorManager mgr = parser.getErrorManager();
00227                 // If the compilation produces errors we print it and stop
00228                 if (mgr.contains(Message.ERROR)) {
00229                     mgr.print(Message.ALL);
00230                 }
00231                 // else we print the warning and start the planning process
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     // Methods used for search a plan                                        //
00301     //-----------------------------------------------------------------------//   
00302 
00309     public Plan solve() {
00310         Plan plan = Plan.FAILURE;
00311         int nbNoGoods = 0;
00312         // Initial expansion of the planning graph
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     // Methods used for planning graph expansion                             //
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             // Clone the proposition level k to add noop actions to the new
00567             // actions layer
00568             final BitSet ak = (BitSet) this.facts_layers.get(k).clone();
00569             // Apply an logical or with the action level k - 1 to copy the
00570             // previous actions
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             // Udpate the level where the fact appear for the first time
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             // Update the resolver to speed up the search
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             // Finally we update the mutex of the level k
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     // Methods used for planning preprocessing                               //
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         // Generate the noop action first so a noop action as the same index as
00834         // its corresponding fact.
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     // Methods used for pddl expressions manipulation                        //
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     // Methods used to print                                                 //
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                                                                 //System.out.println(action.getPredicate().toUpperCase());
01141                 for (Term parameter : action) {
01142                     as.append(" " + parameter.getImage().toUpperCase());
01143                                                                                 //System.out.println(parameter.getImage().toUpperCase());
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 }


tug_ist_diagnosis_repair
Author(s): Safdar Zaman
autogenerated on Mon Jan 6 2014 11:51:12