Main Page   Packages   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members  

Formula.java

00001 package gov.nasa.arc.ase.ltl;
00002 
00003 // Written by Dimitra Giannakopoulou, 19 Jan 2001
00004 // Parser by Flavio Lerda, 8 Feb 2001
00005 // Parser extended by Flavio Lerda, 21 Mar 2001
00006 import java.util.*;
00007 
00008 public class Formula implements Comparable {
00009   private char content;
00010   private boolean literal;
00011   private Formula left;
00012   private Formula right;
00013   private int id;
00014   private int untils_index; // index to the untils vector
00015   private int rightOfUntil_index;
00016   private String name;
00017 
00018   public static Vector untils = new Vector();
00019   public static Formula[] until_forms;
00020 
00021   private static int nId = 0;
00022 
00023   private static final int P_ALL        = 0;
00024   private static final int P_OR         = 1;
00025   private static final int P_AND        = 2;
00026   private static final int P_UNTIL      = 3;
00027   private static final int P_WUNTIL     = 3;
00028   private static final int P_RELEASE    = 4;
00029   private static final int P_WRELEASE   = 4;
00030   private static final int P_IMPLIES    = 5;
00031   private static final int P_NOT        = 6;
00032   private static final int P_NEXT       = 6;
00033   private static final int P_ALWAYS     = 6;
00034   private static final int P_EVENTUALLY = 6;
00035 
00036 
00037   public static class EndOfInputException extends Exception {
00038   }
00039 
00040 
00041   private static Hashtable ht = new Hashtable();
00042 
00043   private static class Input {
00044     private StringBuffer sb;
00045 
00046 
00047     public Input(String str) {
00048       sb = new StringBuffer(str);
00049     }
00050 
00051 
00052     public char get() throws EndOfInputException {
00053       try {
00054     return sb.charAt(0);
00055       } catch(StringIndexOutOfBoundsException e) {
00056     throw new EndOfInputException();
00057       }
00058     }
00059 
00060 
00061     public void skip() throws EndOfInputException {
00062       try {
00063     sb.deleteCharAt(0);
00064       } catch(StringIndexOutOfBoundsException e) {
00065     throw new EndOfInputException();
00066       }
00067     }
00068   }
00069 
00070   private static Hashtable matches = new Hashtable();
00071 
00072   private Formula(char c, boolean l, Formula sx, Formula dx, String n) {
00073     id = nId++;
00074     content = c;
00075     literal = l;
00076     left = sx;
00077     right = dx;
00078     name = n;
00079     rightOfUntil_index = -1;
00080     untils_index = -1;
00081   }  
00082   public void addLeft (Formula l)
00083   {
00084     left = l;
00085   }  
00086   private void addMatch(String name, Formula expr) {
00087     matches.put(name, expr);
00088   }  
00089   public void addRight (Formula r)
00090   {
00091     right = r;
00092   }  
00093   private static Formula Always(Formula f) {
00094     return unique(new Formula('V', false, False(), f, null));
00095   }  
00096   private static Formula And(Formula sx, Formula dx) {
00097     if(sx.id < dx.id)
00098       return unique(new Formula('A', false, sx, dx, null));
00099     else
00100       return unique(new Formula('A', false, dx, sx, null));
00101   }  
00102   private void clearMatches() {
00103     matches = new Hashtable();
00104   }  
00105   public int compareTo(Object f)
00106   {
00107     Formula ff = (Formula) f;
00108     return (this.id - ff.id);
00109 
00110 
00111   }  
00112   private static Formula Eventually(Formula f) {
00113     return unique(new Formula('U', false, True(), f, null));
00114   }  
00115   private static Formula False() {
00116     return unique(new Formula('f', true, null, null, null));
00117   }  
00118   public int get_rightOfUntils_index()
00119   {
00120     return (rightOfUntil_index);
00121   }  
00122   public int get_untils_index()
00123   {
00124     return (untils_index);
00125   }  
00126   public char getContent ()
00127   {
00128     return content;
00129   }  
00130   private Formula getMatch(String name) {
00131     return (Formula)matches.get(name);
00132   }  
00133   public String getName ()
00134   {
00135     return name;
00136   }  
00137   public Formula getNext()
00138   {
00139     switch (content)
00140     {
00141       case 'U':
00142       case 'W':
00143     return this;
00144       case 'V':
00145     return this;
00146       case 'O':
00147     return null;
00148       default:
00149     //    System.out.println(content + " Switch did not find a relevant case...");
00150     return null;
00151     }
00152   }  
00153   public Formula getSub1 ()
00154   {
00155     if (content == 'V')
00156       return right;
00157     else
00158       return left;
00159   }  
00160   public Formula getSub2 ()
00161   {
00162     if (content == 'V')
00163       return left;
00164     else
00165       return right;
00166   }  
00167   private static Formula Implies(Formula sx, Formula dx) {
00168     return Or(Not(sx), dx);
00169   }  
00170   public boolean is_literal()
00171   {
00172     return (literal);
00173   }  
00174   public static boolean is_reserved_char(char ch)
00175   {
00176     switch (ch)
00177     {
00178       //        case 't':
00179       //        case 'f':
00180       case 'U':
00181       case 'V':
00182       case 'W':
00183       case 'M':
00184       case 'X':
00185       case ' ':
00186       case '<':
00187       case '>' :
00188       case '(':
00189       case ')':
00190       case '[':
00191       case ']':
00192       case '-':
00193     // ! not allowed by Java identifiers anyway - maybe some above neither?
00194     return true;
00195       default :
00196     return false;
00197     }
00198   }  
00199   public boolean is_right_of_until()
00200   {
00201     return (rightOfUntil_index >=0);
00202   }  
00203   /*
00204      public boolean contradicts (Formula ita)
00205      {
00206   // only called for literals - that's an assumption
00207   // improve by not requiring that
00208 
00209 
00210 
00211   char otherContent = ita.getContent();
00212 
00213   if (otherContent == 't') return false;
00214 
00215   // one is the negation of the other
00216   if ( ((content == 'N') && (left ==  ita))  ||
00217   ((otherContent == 'N') && (ita.left == this)) )
00218   return true;
00219 
00220 
00221 
00222   return false; // if none of the cases above, no contradiction
00223 
00224   }
00225    */
00226 
00227   public boolean is_special_case_of_V (TreeSet check_against)
00228   {
00229     Formula form = (Release(False(), this));
00230     if (check_against.contains(form))
00231       return true;
00232     else
00233       return false;
00234   }  
00235   public boolean is_synt_implied (TreeSet old, TreeSet next)
00236   {
00237     if (this.getContent() == 't')
00238       return true;
00239     if (old.contains(this))
00240       return true;
00241 
00242 
00243     if (! is_literal()) // non-elementary formula
00244     {
00245       Formula form1 = this.getSub1();
00246       Formula form2 = this.getSub2();
00247       Formula form3 = this.getNext();
00248 
00249       boolean condition1, condition2, condition3;
00250 
00251       if (form2 != null)
00252     condition2 = form2.is_synt_implied(old, next);
00253       else
00254     condition2 = true;
00255       if (form1 != null)
00256     condition1 = form1.is_synt_implied(old, next);
00257       else
00258     condition1 = true;
00259       if (form3 != null) {
00260     if (next != null)
00261       condition3 = next.contains(form3);
00262     else
00263       condition3 = false;
00264       }
00265       else
00266     condition3 = true;
00267 
00268       switch (getContent())
00269       {
00270 
00271     case 'U':
00272     case 'W':
00273     case 'O':
00274       return (condition2 || (condition1 && condition3));
00275     case 'V':
00276       return (  (condition1 && condition2)
00277           || (condition1 && condition3)
00278           );
00279     case 'X': if (form1!=null) {
00280             if (next != null)
00281               return (next.contains(form1));
00282             else
00283               return false;
00284           } else
00285             return (true);
00286     case 'A': return (condition2 && condition1);
00287     default:
00288           System.out.println("Default case of switch at Form.synt_implied");
00289           return false;
00290 
00291       }
00292     }
00293     else
00294     {
00295       return false;
00296     }
00297   }  
00298   private boolean match(Formula rule) {
00299     if(rule.content == 'p') {
00300       Formula match = getMatch(rule.name);
00301 
00302       if(match == null) {
00303     addMatch(rule.name, this);
00304     return true;
00305       }
00306 
00307       return match == this;
00308     }
00309 
00310     if(rule.content != content) return false;
00311 
00312     Hashtable saved = (Hashtable)matches.clone();
00313 
00314     switch(content) {
00315       case 'A':
00316       case 'O':
00317     if(left.match(rule.left) && right.match(rule.right))
00318       return true;
00319 
00320     matches = saved;
00321     if(right.match(rule.left) && left.match(rule.right))
00322       return true;
00323 
00324     matches = saved;
00325     return false;
00326 
00327       case 'U':
00328       case 'V':
00329       case 'W':
00330     if(left.match(rule.left) && right.match(rule.right))
00331       return true;
00332 
00333     matches = saved;
00334     return false;
00335 
00336       case 'X':
00337       case 'N':
00338     if(left.match(rule.left))
00339       return true;
00340 
00341     matches = saved;
00342     return false;
00343 
00344       case 't':
00345       case 'f':
00346     return true;
00347     }
00348 
00349     throw new RuntimeException("code should not be reached");
00350   }  
00351   public Formula negate ()
00352   {
00353     return Not(this);
00354   }  
00355   private static Formula Next(Formula f) {
00356     return unique(new Formula('X', false, f, null, null));
00357   }  
00358   private static Formula Not(Formula f) {
00359     if (f.literal)
00360       switch (f.content)
00361       {
00362     case 't': return False();
00363     case 'f': return True();
00364     case 'N': return f.left;
00365     default : return unique(new Formula('N', true, f, null, null));
00366       }
00367 
00368     // f is not a literal, so go on...
00369 
00370 
00371     switch(f.content) {
00372       case 'A': return Or(Not(f.left), Not(f.right));
00373       case 'O': return And(Not(f.left), Not(f.right));
00374       case 'U': return Release(Not(f.left), Not(f.right));
00375       case 'V': return Until(Not(f.left), Not(f.right));
00376       case 'W': return WRelease(Not(f.left), Not(f.right));
00377       //case 'M': return WUntil(Not(f.left), Not(f.right));
00378       case 'N': return f.left;
00379       case 'X': return Next(Not(f.left));
00380       default:  throw new ParserInternalError();
00381     }
00382   }  
00383   private static Formula Or(Formula sx, Formula dx) {
00384     if(sx.id < dx.id)
00385       return unique(new Formula('O', false, sx, dx, null));
00386     else
00387       return unique(new Formula('O', false, dx, sx, null));
00388   }  
00389   static private Formula parse(Input i, int precedence) throws ParseErrorException {
00390     try {
00391       Formula formula;
00392       char ch;
00393 
00394 
00395       while(i.get() == ' ') i.skip();
00396 
00397 
00398       switch(ch = i.get()) {
00399     case '/': // and
00400     case '\\': // or
00401     case 'U': // until
00402     case 'W': // weak until
00403     case 'V': // release
00404     case 'M': // dual of W - weak release
00405     case ')':
00406       throw new ParseErrorException("invalid character: " + ch);
00407 
00408 
00409     case '!': // not
00410       i.skip();
00411       formula = Not(parse(i, P_NOT));
00412       break;
00413 
00414 
00415     case 'X': // next
00416       i.skip();
00417       formula = Next(parse(i, P_NEXT));
00418       break;
00419 
00420 
00421     case '[': // always
00422       i.skip();
00423       if(i.get() != ']')
00424         throw new ParseErrorException("expected ]");
00425       i.skip();
00426       formula = Always(parse(i, P_ALWAYS));
00427       break;
00428 
00429 
00430     case '<': // eventually
00431       i.skip();
00432       if(i.get() != '>')
00433         throw new ParseErrorException("expected >");
00434       i.skip();
00435       formula = Eventually(parse(i, P_EVENTUALLY));
00436       break;
00437 
00438 
00439     case '(':
00440       i.skip();
00441       formula = parse(i, P_ALL);
00442       if(i.get() != ')')
00443         throw new ParseErrorException("invalid character: " + ch);
00444       i.skip();
00445       break;
00446 
00447 
00448     case '"':
00449       StringBuffer sb = new StringBuffer();
00450 
00451       i.skip();
00452       while((ch = i.get()) != '"') {
00453         sb.append(ch);
00454         i.skip();
00455       }
00456       i.skip();
00457 
00458       formula = Proposition(sb.toString());
00459       break;
00460 
00461 
00462     default:
00463 
00464       if (Character.isJavaIdentifierStart(ch))
00465       {
00466         StringBuffer sbf = new StringBuffer();
00467 
00468         sbf.append(ch);
00469         i.skip();
00470 
00471         try
00472         {
00473           while(Character.isJavaIdentifierPart(ch = i.get())&&
00474           (!Formula.is_reserved_char(ch)) )
00475           {
00476         sbf.append(ch);
00477         i.skip();
00478 
00479           }
00480         } catch(EndOfInputException e) {
00481           //    return Proposition(sbf.toString());
00482         }
00483         String id = sbf.toString();
00484         if (id.equals("true"))
00485         {
00486           formula = True();
00487         } else if(id.equals("false"))
00488         {
00489           formula = False();
00490         } else
00491         {
00492           formula = Proposition(sbf.toString());
00493         }
00494 
00495       }
00496       else
00497         throw new ParseErrorException("invalid character: " + ch);
00498       break;
00499       }
00500 
00501 
00502       try {
00503     while(i.get() == ' ') i.skip();
00504     ch = i.get();
00505       } catch(EndOfInputException e) {
00506     return formula;
00507       }
00508 
00509 
00510       while(true) {
00511     switch(ch) {
00512       case '/': // and
00513         if (precedence > P_AND) return formula;
00514         i.skip();
00515         if(i.get() != '\\')
00516           throw new ParseErrorException("expected \\");
00517         i.skip();
00518         formula = And(formula, parse(i, P_AND));
00519         break;
00520 
00521 
00522       case '\\': // or
00523         if (precedence > P_OR) return formula;
00524         i.skip();
00525         if(i.get() != '/')
00526           throw new ParseErrorException("expected /");
00527         i.skip();
00528         formula = Or(formula, parse(i, P_OR));
00529         break;
00530 
00531 
00532       case 'U': // until
00533         if (precedence > P_UNTIL) return formula;
00534         i.skip();
00535         formula = Until(formula, parse(i, P_UNTIL));
00536         break;
00537 
00538       case 'W': // weak until
00539         if (precedence > P_WUNTIL) return formula;
00540         i.skip();
00541         formula = WUntil(formula, parse(i, P_WUNTIL));
00542         break;
00543 
00544       case 'V': // release
00545         if (precedence > P_RELEASE) return formula;
00546         i.skip();
00547         formula = Release(formula, parse(i, P_RELEASE));
00548         break;
00549 
00550       case 'M': // weak_release
00551         if (precedence > P_WRELEASE) return formula;
00552         i.skip();
00553         formula = WRelease(formula, parse(i, P_WRELEASE));
00554         break;
00555 
00556 
00557       case '-': // implies
00558         if (precedence > P_IMPLIES) return formula;
00559         i.skip();
00560         if(i.get() != '>')
00561           throw new ParseErrorException("expected >");
00562         i.skip();
00563         formula = Implies(formula, parse(i, P_IMPLIES));
00564         break;
00565 
00566 
00567       case ')':
00568         return formula;
00569 
00570 
00571       case '!':
00572       case 'X':
00573       case '[':
00574       case '<':
00575       case '(':
00576       default:
00577         throw new ParseErrorException("invalid character: " + ch);
00578     }
00579 
00580 
00581     try {
00582       while(i.get() == ' ') i.skip();
00583       ch = i.get();
00584     } catch(EndOfInputException e) {
00585       break;
00586     }
00587       }
00588       return formula;
00589     } catch(EndOfInputException e) {
00590       throw new ParseErrorException("unexpected end of input");
00591     }
00592   }  
00593   static public Formula parse(String str) throws ParseErrorException { // "aObAc"
00594     Input i = new Input(str);
00595     return parse(i, P_ALL);
00596   }  
00597   public int processRightUntils()
00598   { int acc_sets = 0;
00599 
00600 
00601     if (getContent() == 'U')
00602     {
00603       untils.add(this);
00604       this.untils_index = right.rightOfUntil_index = untils.size() -1;
00605       //System.out.println("Formula " + this.toString() + " has index " + this.untils_index);
00606       //System.out.println("Vector at that position contains " + untils.get(this.untils_index).toString());
00607     }
00608 
00609     if (left != null) left.processRightUntils();
00610     if (right != null) right.processRightUntils();
00611 
00612 
00613     //  System.out.println("There are " + acc_sets + " acceptance sets");
00614     return untils.size();
00615   }  
00616   private static Formula Proposition(String name) {
00617     return unique(new Formula('p', true, null, null, name));
00618   }  
00619   private static Formula Release(Formula sx, Formula dx) {
00620     return unique(new Formula('V', false, sx, dx, null));
00621   }  
00622   public static void reset_static() 
00623   { 
00624     untils = new Vector();
00625     until_forms = null;
00626   }  
00627   private Formula rewrite() {
00628     if(content == 'p')
00629       return getMatch(name);
00630 
00631     switch(content) {
00632       case 'A': return And(left.rewrite(), right.rewrite());
00633       case 'O': return Or(left.rewrite(), right.rewrite());
00634       case 'U': return Until(left.rewrite(), right.rewrite());
00635       case 'V': return Release(left.rewrite(), right.rewrite());
00636       case 'W': return WUntil(left.rewrite(), right.rewrite());
00637       case 'X': return Next(left.rewrite());
00638       case 'N': return Not(left.rewrite());
00639       case 't': return True();
00640       case 'f': return False();
00641     }
00642 
00643     throw new RuntimeException("code should not be reached");
00644   }  
00645   public Formula rewrite(Formula rule, Formula rewritten) {
00646     switch(content) {
00647       case 'A':
00648       case 'O':
00649       case 'U':
00650       case 'V':
00651       case 'W':
00652     left = left.rewrite(rule, rewritten);
00653     right = right.rewrite(rule, rewritten);
00654     break;
00655 
00656       case 'X':
00657       case 'N':
00658     left = left.rewrite(rule, rewritten);
00659     break;
00660 
00661       case 't':
00662       case 'f':
00663       case 'p':
00664     break;
00665     }
00666 
00667     if(match(rule)) {
00668       Formula expr = rewritten.rewrite();
00669 
00670       clearMatches();
00671 
00672       return expr;
00673     }
00674 
00675     clearMatches();
00676 
00677     return this;
00678   }  
00679   public int size() {
00680     switch(content) {
00681       case 'A':
00682       case 'O':
00683       case 'U':
00684       case 'V':
00685       case 'W':
00686     return left.size() + right.size() + 1;
00687 
00688       case 'X':
00689       case 'N':
00690     return left.size() + 1;
00691 
00692       default:
00693     return 0;
00694     }
00695   }  
00696   public String toString() {
00697     switch(content) {
00698       case 'A': return "( " + left.toString() + " /\\ " + right.toString() + " )";
00699       case 'O': return "( " + left.toString() + " \\/ " + right.toString() + " )";
00700       case 'U': return "( " + left.toString() + " U " + right.toString() + " )";
00701       case 'V': return "( " + left.toString() + " V " + right.toString() + " )";
00702       case 'W': return "( " + left.toString() + " W " + right.toString() + " )";
00703       //case 'M': return "( " + left.toString() + " M " + right.toString() + " )";
00704       case 'X': return "( () " + left.toString() + " )";
00705       case 'N': return "( ! " + left.toString() + " )";
00706       case 't': return "( true )";
00707       case 'f': return "( false )";
00708       case 'p': return "( \"" + name + "\" )";
00709       default:  return new Character(content).toString();
00710     }
00711   }  
00712   public String toString(boolean exprId) {
00713     if(!exprId) return toString();
00714 
00715 
00716     switch(content) {
00717       case 'A': return "( " + left.toString(true) + " /\\ " + right.toString(true) + " )[" + id + "]";
00718       case 'O': return "( " + left.toString(true) + " \\/ " + right.toString(true) + " )[" + id + "]";
00719       case 'U': return "( " + left.toString(true) + " U " + right.toString(true) + " )[" + id + "]";
00720       case 'V': return "( " + left.toString(true) + " V " + right.toString(true) + " )[" + id + "]";
00721       case 'W': return "( " + left.toString(true) + " W " + right.toString(true) + " )[" + id + "]";
00722       //case 'M': return "( " + left.toString(true) + " M " + right.toString(true) + " )[" + id + "]";
00723       case 'X': return "( () " + left.toString(true) + " )[" + id + "]";
00724       case 'N': return "( ! " + left.toString(true) + " )[" + id + "]";
00725       case 't': return "( true )[" + id + "]";
00726       case 'f': return "( false )[" + id + "]";
00727       case 'p': return "( \"" + name + "\" )[" + id + "]";
00728       default:  return "( " + content + " )[" + id + "]";
00729     }
00730   }  
00731   private static Formula True() {
00732     return unique(new Formula('t', true, null, null, null));
00733   }  
00734   private static Formula unique(Formula f) {
00735     String s = f.toString();
00736 
00737 
00738     if(ht.containsKey(s))
00739       return (Formula)ht.get(s);
00740 
00741 
00742     ht.put(s, f);
00743     return f;
00744   }  
00745   private static Formula Until(Formula sx, Formula dx) {
00746     return unique(new Formula('U', false, sx, dx, null));
00747   }  
00748   private static Formula WRelease(Formula sx, Formula dx) {
00749     return unique(new Formula('U', false, dx, And(sx, dx), null));
00750   }  
00751   private static Formula WUntil(Formula sx, Formula dx) {
00752     return unique(new Formula('W', false, sx, dx, null));
00753   }  
00754 }

Generated at Thu Feb 7 06:45:49 2002 for Bandera by doxygen1.2.10 written by Dimitri van Heesch, © 1997-2001