listobj.h

00001 /*
00002  * All of the documentation and software included in the
00003  * Alchemy Software is copyrighted by Stanley Kok, Parag
00004  * Singla, Matthew Richardson, Pedro Domingos, Marc
00005  * Sumner, Hoifung Poon, and Daniel Lowd.
00006  * 
00007  * Copyright [2004-07] Stanley Kok, Parag Singla, Matthew
00008  * Richardson, Pedro Domingos, Marc Sumner, Hoifung
00009  * Poon, and Daniel Lowd. All rights reserved.
00010  * 
00011  * Contact: Pedro Domingos, University of Washington
00012  * (pedrod@cs.washington.edu).
00013  * 
00014  * Redistribution and use in source and binary forms, with
00015  * or without modification, are permitted provided that
00016  * the following conditions are met:
00017  * 
00018  * 1. Redistributions of source code must retain the above
00019  * copyright notice, this list of conditions and the
00020  * following disclaimer.
00021  * 
00022  * 2. Redistributions in binary form must reproduce the
00023  * above copyright notice, this list of conditions and the
00024  * following disclaimer in the documentation and/or other
00025  * materials provided with the distribution.
00026  * 
00027  * 3. All advertising materials mentioning features or use
00028  * of this software must display the following
00029  * acknowledgment: "This product includes software
00030  * developed by Stanley Kok, Parag Singla, Matthew
00031  * Richardson, Pedro Domingos, Marc Sumner, Hoifung
00032  * Poon, and Daniel Lowd in the Department of Computer Science and
00033  * Engineering at the University of Washington".
00034  * 
00035  * 4. Your publications acknowledge the use or
00036  * contribution made by the Software to your research
00037  * using the following citation(s): 
00038  * Stanley Kok, Parag Singla, Matthew Richardson and
00039  * Pedro Domingos (2005). "The Alchemy System for
00040  * Statistical Relational AI", Technical Report,
00041  * Department of Computer Science and Engineering,
00042  * University of Washington, Seattle, WA.
00043  * http://www.cs.washington.edu/ai/alchemy.
00044  * 
00045  * 5. Neither the name of the University of Washington nor
00046  * the names of its contributors may be used to endorse or
00047  * promote products derived from this software without
00048  * specific prior written permission.
00049  * 
00050  * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY OF WASHINGTON
00051  * AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
00052  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00053  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
00054  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY
00055  * OF WASHINGTON OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
00056  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00057  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
00058  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
00059  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
00060  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00061  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
00062  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
00063  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00064  * 
00065  */
00066 #ifndef LISTOBJ_H_JUN_21_2005
00067 #define LISTOBJ_H_JUN_21_2005
00068 
00069 #include <string>
00070 #include <list>
00071 #include <ostream>
00072 #include <ext/hash_map>
00073 using namespace __gnu_cxx;
00074 #include "array.h"
00075 #include "hashstring.h"
00076 #include "domain.h"
00077 #include "arraysaccessor.h"
00078 
00079 typedef hash_map<const string, int, HashString, EqualString> VarTypeMap;
00080 
00081 
00082 // Modified from http://aima.cs.berkeley.edu/lisp/doc/overview-LOGIC.html 
00083 // Represent a first-order formula in prefix form e.g. (AND (OR (P x)) (Q y)).
00084 // Egs of expression in prefix form (! P), (^ P Q), (v P Q), (=> P Q), 
00085 // (<=> P Q), (P x) (a predicate or function), (FORALL (x) (P x)), 
00086 // (EXIST (x) (P x)) 
00087 
00088 class ListObj
00089 {
00090  public:
00091   ListObj() 
00092   {
00093     str_ = new char[1];
00094     str_[0] = '\0';
00095   }
00096     
00097   
00098   ListObj(const char* const & str)
00099   {
00100     if (str != NULL)
00101     {
00102       str_ = new char[strlen(str)+1];
00103       strcpy(str_, str);
00104     }
00105     else
00106     {
00107       str_ = new char[1];
00108       str_[0] = '\0';
00109     }
00110   }
00111 
00112 
00113   ListObj(const ListObj* const & p)
00114   {
00115     for (int i = 0; i < p->size(); i++)
00116       list_.append(new ListObj((*p)[i]));   
00117     str_ = new char[strlen(p->str_)+1];
00118     strcpy(str_, p->str_);
00119        
00120     assert(p->list_.size() == list_.size());
00121 
00122   }
00123 
00124 
00125   ~ListObj() { delete [] str_; list_.deleteItemsAndClear(); }
00126 
00127 
00128   void clear() { list_.clear(); delete [] str_; str_=new char[1];str_[0]='\0'; }
00129 
00130   void deleteAndClear() { list_.deleteItemsAndClear(); clear(); }
00131 
00132   void clearList() { list_.clear(); }
00133 
00134   ostream& print(ostream& out) const
00135   {
00136     if (isStr()) 
00137       out << str_;
00138     else
00139     {
00140       out << "(";
00141       for (int i = 0; i < list_.size(); i++)
00142       {
00143         list_[i]->print(out); 
00144         out << ((i<list_.size()-1)? " " : "");
00145       }
00146       out << ")";
00147     }
00148     return out;
00149   }
00150 
00151 
00152     // caller should not modify the returned Array
00153   const Array<ListObj*>& getList() const { return list_; }
00154 
00155     // caller should not modify or delete the returned string
00156   const char* getStr() const { return str_; }
00157 
00158     // if isStr(), replace str_ with the provided str
00159     // caller is responsible for deleting str if necessary
00160   void setStrIfStr(const char* str)
00161   {
00162     if (isStr())
00163     {
00164       delete [] str_;
00165       str_ = new char[strlen(str)+1];
00166       strcpy(str_,str);
00167     }
00168   }
00169 
00170   bool isStr() const { return (strlen(str_) > 0); }
00171 
00172   bool isList() const { return !isStr(); }
00173 
00174   void append(ListObj* const & p) { list_.append(p); }  
00175 
00176   void append(const char* const & s) { list_.append(new ListObj(s)); }
00177 
00178   ListObj* removeLast()
00179   {
00180     ListObj* lo = list_.removeLastItem();
00181     list_.compress();
00182     return lo;
00183   }
00184 
00185   int size() const { return list_.size(); }
00186 
00187   ListObj* operator[](const int& index) const { return list_[index]; } 
00188 
00189 
00190   static ListObj* toCNF(const ListObj* const & p, const ListObj* const & vars, 
00191                         const Domain* const & domain, 
00192                         const VarTypeMap * const& vtMap, bool& hasExist)
00193   {
00194     ListObj* p1 = eliminateImplication(p);
00195 
00196     const char* opp = op(p1)->str_;
00197     
00198     if (strcmp(opp, "!")==0)
00199     {
00200       ListObj* p2 = moveNotInwards(arg1(p1));
00201       if (isLiteralClause(p2)) { delete p1; return p2; }
00202 
00203       ListObj* ret = toCNF(p2, vars, domain, vtMap, hasExist);
00204       delete p2; delete p1;
00205       return ret;
00206     }
00207     
00208     if (strcmp(opp, "^")==0)
00209     {
00210       ListObj* n = NULL;
00211       int numConj = 0;
00212       ListObj* firstConj = NULL;
00213 
00214       for (int i = 1; i < p1->size(); i++) // for each arg
00215       {        
00216         ListObj* conj = toCNF((*p1)[i], vars, domain, vtMap, hasExist);
00217 
00218         bool isConj = strcmp(op(conj)->str_, "^")==0;
00219         int jbeg = (isConj) ? 1 : 0;
00220         int jmax = (isConj) ? conj->size() : 1;
00221         ListObj* conjj;
00222 
00223         for (int j = jbeg; j < jmax; j++) 
00224         {
00225           if (isConj) conjj = (*conj)[j];
00226           else        conjj = conj;
00227 
00228           numConj++;
00229           if (numConj==1) { firstConj = conjj; continue; }
00230           else 
00231           if (numConj==2) {n=new ListObj; n->append("^"); n->append(firstConj);}
00232           n->append(conjj);
00233         }
00234 
00235         if (isConj) { delete (*conj)[0]; conj->clearList(); delete conj; }
00236 
00237       }
00238 
00239       delete p1;
00240       if (numConj == 1) { return firstConj; }        
00241       return n;
00242     }
00243     
00244     if (strcmp(opp, "v")==0)
00245     {
00246       ListObj* n = new ListObj;
00247       for (int i = 1; i < p1->size(); i++) // for each arg
00248         n->append(toCNF((*p1)[i], vars, domain, vtMap, hasExist));
00249       ListObj* ret = mergeDisjuncts(n, n->size());
00250 
00251       delete n; delete p1;
00252       return ret;
00253     }
00254     
00255     if (strcmp(opp, "FORALL")==0)
00256     {
00257       const ListObj* arg1var = arg1(p1);
00258 
00259       ListObj* newVar = new ListObj;
00260       for (int i = 0; i < arg1var->size(); i++)
00261         newVar->append(newVariable((*arg1var)[i]));
00262       assert(newVar->size() == arg1var->size());
00263       
00264       const ListObj* aarg2 = new ListObj(arg2(p1));
00265 
00266       for (int i = 0; i < newVar->size(); i++)
00267         for (int j = 0; j < aarg2->size(); j++)
00268           (*aarg2)[j]->sub((*arg1var)[i], (*newVar)[i]);
00269 
00270       ListObj* app = new ListObj;
00271       for (int i = 0; i < newVar->size(); i++)  app->append((*newVar)[i]);
00272       for (int i = 0; i < vars->size(); i++)    app->append((*vars)[i]);
00273       
00274       newVar->clearList();
00275       delete newVar;
00276       ListObj* ret = toCNF(aarg2, app, domain, vtMap, hasExist);
00277       delete aarg2; delete app; delete p1;
00278       return ret;
00279     }
00280 
00281     if (strcmp(opp, "EXIST")==0)
00282     {
00283       hasExist = true;
00284       const ListObj* a2 = arg2(p1); // formula
00285       const ListObj* a1 = arg1(p1); // variables
00286 
00287         // without a domain, there are no constants to ground an existentially
00288         // quantified clause, so we must skolemize
00289       if (domain == NULL)
00290       {
00291         ListObj* sk = skolemize(a2, a1, vars);
00292         ListObj* c  = toCNF(sk, vars, domain, vtMap, hasExist);
00293         delete sk; delete p1;
00294         return c;
00295       }
00296         // get the variable names
00297       Array<string> varNames;
00298       for (int i = 0; i < a1->size(); i++)
00299         varNames.append((*a1)[i]->getStr());
00300 
00301       ArraysAccessor<int> arrAccessor;
00302       for (int i = 0; i < varNames.size(); i++)
00303       {        
00304         VarTypeMap::const_iterator mit = vtMap->find(varNames[i]);
00305         assert(mit != vtMap->end());
00306         int typeId = (*mit).second;
00307         assert(typeId > 0);
00308         const Array<int>* constArr = domain->getConstantsByType(typeId);
00309         if (constArr->size() == 0)
00310         {
00311           cout << "You must declare constants for type " 
00312                << domain->getTypeName(typeId) 
00313                << " in order to ground the variable " << varNames[i] << endl;
00314           exit(-1);
00315         }
00316         arrAccessor.appendArray(constArr);
00317       }
00318 
00319       if (varNames.size()==0){cout<<"ERROR: EXIST has no vars."<<endl;exit(-1);}
00320 
00321       ListObj* newFormula = new ListObj;
00322       newFormula->append("v");
00323       Array<int> constIds;
00324       while (arrAccessor.getNextCombination(constIds))
00325       {
00326         ListObj* replacedFormula = new ListObj(a2);
00327 
00328         assert(constIds.size() == varNames.size());
00329         for (int i = 0; i < varNames.size(); i++)
00330         {
00331           const char* constName = domain->getConstantName(constIds[i]);
00332           replace(replacedFormula, varNames[i].c_str(), constName, domain);
00333         }
00334         newFormula->append(replacedFormula);
00335       }
00336       //arrAccessor.deleteArraysAndClear();
00337       //newFormula->print(cout); cout << endl;
00338 
00339       delete p1;
00340       ListObj* c  = toCNF(newFormula, vars, domain, vtMap, hasExist);
00341 
00342       delete newFormula; 
00343       return c;
00344     }
00345 
00346     return p1;
00347   }
00348 
00349 
00350   void replaceAsterisk(const Array<bool>& bArr, int& idx)
00351   {
00352     if (!isStr())
00353     {
00354       const char* opp = op(this)->str_;
00355 
00356       if (strcmp(opp, "*")==0)
00357       {
00358         assert(size()==2);
00359           // if false, replace the * with !, 
00360           // else set (*this) to be the formula without the !
00361         if (!bArr[idx]) 
00362           (*this)[0]->setStrIfStr("!");
00363         else            
00364         { 
00365           ListObj* unNegatedFormula = new ListObj((*this)[1]); 
00366           assert(!unNegatedFormula->isStr());
00367           deleteAndClear();
00368           for (int i = 0; i < unNegatedFormula->size(); i++)
00369             append((*unNegatedFormula)[i]);
00370           unNegatedFormula->clear();
00371           delete unNegatedFormula;
00372         }
00373         idx++;
00374         if (idx == bArr.size()) return;
00375       }
00376 
00377       for (int i = 0; i < size(); i++)
00378       {
00379         (*this)[i]->replaceAsterisk(bArr, idx);
00380         if (idx == bArr.size()) return;
00381       }
00382     }
00383   }
00384 
00385 
00386     // removes $ and .10 from $x.10
00387   void cleanUpVars()
00388   {
00389     if (isStr())
00390     {
00391       if (str_[0] != '$') return;
00392       char* dot = strrchr(str_, '.'); 
00393       if (dot==NULL) return; // dealing with skolem constant of function
00394       int numChar = dot-str_-1;
00395       char* tmp = new char[numChar+1];
00396       strncpy(tmp, str_+1, numChar);
00397       tmp[numChar] = '\0';
00398       delete [] str_;
00399       str_ = tmp;
00400     }
00401     else
00402       for (int i = 0; i < list_.size(); i++)
00403         list_[i]->cleanUpVars(); 
00404   }
00405 
00406 
00407   void removeRedundantPredicates()
00408   {
00409     const char* opp = op(this)->str_;
00410 
00411     if (strcmp(opp,"^")==0)
00412     {
00413       for (int i = 1; i < size(); i++) // for each clause
00414         removeRedundantPredicates((*this)[i]);      
00415     }
00416     else
00417       removeRedundantPredicates(this);
00418   }
00419 
00420 
00421   void removeRedundantClauses()
00422   {
00423     //for each clause, remove redundant predicates
00424     //for each clause
00425     //  compare it to every other clause c
00426     //  if it contains c, remove it from *this
00427 
00428     const char* opp = op(this)->str_;
00429 
00430     if (strcmp(opp,"^")==0)
00431     {
00432       for (int i = 1; i < size(); i++) // for each clause
00433         removeRedundantPredicates((*this)[i]);
00434       
00435       Array<ListObj*> clauses, redundantClauses;
00436       for (int i = 1; i < size(); i++)
00437       {
00438         bool keep = true;
00439         for (int j = 1; j < size(); j++)
00440         {
00441           if (i==j) continue;
00442           if (subsetOf((*this)[j],(*this)[i])) 
00443             if ((*this)[i]->size() != (*this)[j]->size() || i < j) 
00444             { keep = false; break; }
00445         }
00446       if (keep) clauses.append((*this)[i]);
00447       else      redundantClauses.append((*this)[i]);
00448       }
00449 
00450       ListObj* andOper = (*this)[0];
00451       assert(strcmp(andOper->str_,"^")==0);
00452         //delete the operator and redundant clauses
00453       for (int i = 0; i < redundantClauses.size(); i++)
00454         delete redundantClauses[i];
00455       clear();
00456       append(andOper);
00457       for (int i = 0; i < clauses.size(); i++) append(clauses[i]);
00458     }
00459     else
00460       removeRedundantPredicates(this);
00461   }
00462 
00463 
00464   static void replace(const ListObj* const & p, const char* const & varName,
00465                       const char* const& constName, const Domain* const& domain)
00466   {
00467     const char* opp = op(p)->str_;
00468     
00469       //if there is variable of the same name that is existentially/universally
00470       //in an inner scope, then return;
00471     if (strcmp(opp, "EXIST")==0 || strcmp(opp, "FORALL")==0)
00472       if (containsVarName((*p)[1], varName)) return;
00473 
00474       // if we are currently looking at a predicate or a function
00475     const bool isPredFunc = (   domain->isPredicate(opp) 
00476                              || domain->isFunction(opp));
00477 
00478     for (int i = 1; i < p->size(); i++)
00479     {
00480         // if we are currently looking at a predicate/function 
00481         // AND the param is a possible var
00482       if (isPredFunc && (*p)[i]->isStr())
00483       {
00484           //if we found the variable
00485         if (strcmp((*p)[i]->getStr(), varName)==0)
00486           (*p)[i]->setStrIfStr(constName);
00487       }
00488       else
00489         replace((*p)[i], varName, constName, domain);
00490     }
00491   }
00492 
00493 
00494   void replace(const char* const & oldop, const char* const & newop)
00495   {
00496     for (int i = 0; i < size(); i++)
00497     {
00498       if (strcmp((*this)[i]->getStr(), oldop)==0)
00499         (*this)[i]->setStrIfStr(newop);
00500       else
00501         (*this)[i]->replace(oldop, newop);
00502     }
00503   }
00504 
00505   
00506   bool hasOrOp()
00507   {
00508     if (!isList()) return false;
00509     return (strcmp(op(this)->str_,"v")==0);
00510   }
00511 
00512   
00513   bool hasAndOp()
00514   {
00515     if (!isList()) return false;
00516     return (strcmp(op(this)->str_,"^")==0);
00517   }
00518 
00519 
00520  private:
00521   static bool same(const ListObj* const & lo1, const ListObj* const & lo2)
00522   {
00523     if (lo1->isStr() && lo2->isStr()) 
00524     {
00525       if (strcmp(lo1->str_, lo2->str_)==0) return true;
00526       return false;
00527     }
00528 
00529     if (lo1->isList() && lo2->isList())
00530     {
00531       if (lo1->size() == lo2->size())
00532       {
00533         for (int i = 0; i < lo1->size(); i++)
00534           if (!same((*lo1)[i],(*lo2)[i])) return false;
00535         return true;
00536       }
00537       return false;        
00538     }
00539     return false;
00540   }
00541 
00542 
00543   void sub(const ListObj* const & oldlo, const ListObj* const & newlo)
00544   {
00545     if (isStr()) 
00546     {
00547       if (same(this, oldlo))
00548       {
00549         if (newlo->isStr()) 
00550         {
00551           delete [] str_;
00552           str_ = new char[strlen(newlo->str_)+1];
00553           strcpy(str_, newlo->str_);
00554         }
00555         else
00556         {
00557           delete [] str_;
00558           str_ = new char[1];
00559           str_[0] = '\0';
00560           list_.deleteItemsAndClear();
00561 
00562           for (int i = 0; i < newlo->size(); i++)
00563             list_.append(new ListObj((*newlo)[i]));
00564         }
00565       }
00566       return;
00567     }
00568     
00569     for (int i = 0; i < list_.size(); i++)
00570     {
00571       if (same(list_[i],oldlo)) {delete list_[i]; list_[i]=new ListObj(newlo); }
00572       else                       list_[i]->sub(oldlo, newlo);
00573     }
00574   }
00575 
00576 
00577   static const ListObj* op(const ListObj* const & exp)
00578   {
00579     assert(exp->isList());
00580     if (exp->size() == 0) return exp;
00581     return (*exp)[0];
00582   }
00583 
00584 
00585   static const ListObj* arg1(const ListObj* const & exp)
00586   { 
00587     if (exp->isList() && exp->size() > 1) return (*exp)[1];
00588     else                                  return null_;
00589   }
00590   
00591 
00592   static const ListObj* arg2(const ListObj* const & exp)  
00593   { 
00594     if (exp->isList() && exp->size() > 2) return (*exp)[2];
00595     else                                  return null_;
00596   }
00597   
00598 
00599 
00600   static bool isConnective(const char* const & c)
00601   {
00602     if (strcmp(c, "^")==0 || strcmp(c, "v")==0 || strcmp(c, "!")==0 || 
00603         strcmp(c, "=>")==0 || strcmp(c, "<=>")==0 )
00604       return true;
00605     return false;
00606   }
00607 
00608 
00609   static bool isQuantifier(const char* const & q)
00610   {
00611     if (strcmp(q, "FORALL")==0 || strcmp(q, "EXIST")==0)
00612       return true;
00613     return false;
00614   }
00615   
00616 
00617     // An atomic clause has no connectives or quantifiers.
00618   static bool isAtomicClause(const ListObj* const & sentence)
00619   {
00620       //op(sentence) is a temporary object. Assigning opp as in 
00621       //"const char* opp = op(sentence).str_" cause opp to be mangled.
00622     const char* opp = op(sentence)->str_;
00623     if (!isConnective(opp) && !isQuantifier(opp)) return true;
00624     return false;      
00625   }
00626 
00627 
00628   static bool isNegatedClause(const ListObj* const & sentence)
00629   {
00630     if (strcmp(op(sentence)->str_, "!")==0) return true;
00631     return false;
00632   }
00633 
00634 
00635   static bool isLiteralClause(const ListObj* const & sentence)
00636   {
00637     if (isAtomicClause(sentence) || (isNegatedClause(sentence) 
00638                                      && isAtomicClause(arg1(sentence))))
00639       return true;
00640     return false;
00641   }
00642 
00643 
00644   static ListObj* eliminateImplication(const ListObj* const & p)
00645   {
00646     if (isLiteralClause(p)) return new ListObj(p);
00647 
00648     const char* opp = op(p)->str_;
00649 
00650     if (strcmp(opp, "=>")==0)
00651     {
00652       ListObj* n1 = new ListObj; 
00653       n1->append("!"); n1->append(new ListObj(arg1(p)));
00654       ListObj* n = new ListObj; 
00655       n->append("v"); n->append(new ListObj(arg2(p))); n->append(n1);
00656       return n;
00657     }
00658     else
00659     if (strcmp(opp, "<=>")==0)
00660     {        
00661       ListObj* n1a = new ListObj;
00662       n1a->append("!"); n1a->append(new ListObj(arg1(p)));
00663       ListObj* na = new ListObj; 
00664       na->append("v"); na->append(n1a); na->append(new ListObj(arg2(p)));
00665 
00666       ListObj* n1b = new ListObj; 
00667       n1b->append("!"); n1b->append(new ListObj(arg2(p)));
00668       ListObj* nb = new ListObj; 
00669       nb->append("v"); nb->append(new ListObj(arg1(p)));
00670       nb->append(n1b); 
00671       
00672       ListObj* n = new ListObj; n->append("^"); n->append(nb); n->append(na);
00673       return n;
00674     }
00675     else
00676     {
00677       ListObj* n = new ListObj; n->append(opp);
00678       for (int i = 1; i < p->size(); i++) // for each arg
00679         n->append(eliminateImplication((*p)[i]));
00680       return n;
00681     }
00682   }
00683 
00684 
00685   static ListObj* moveNotInwards(const ListObj* const & p)
00686   {
00687     const char* opp = op(p)->str_;
00688 
00689     if (strcmp(opp, "!")==0) return new ListObj((*p)[1]);
00690 
00691     if (strcmp(opp, "^")==0)
00692     {
00693       ListObj* n = NULL;
00694       int numDisj = 0;
00695       ListObj* firstDisj = NULL;
00696 
00697       for (int i = 1; i < p->size(); i++) //for each arg
00698       {
00699         numDisj++;
00700         if (numDisj == 1) { firstDisj = moveNotInwards((*p)[i]); continue; }
00701         else 
00702         if (numDisj == 2) {n=new ListObj; n->append("v"); n->append(firstDisj);}
00703         n->append(moveNotInwards((*p)[i]));
00704       }
00705       if (numDisj == 1) return firstDisj;
00706       return n;
00707     }
00708 
00709     if (strcmp(opp, "v")==0)
00710     {
00711       ListObj* n = NULL;
00712       int numConj = 0;
00713       ListObj* firstConj = NULL;
00714       
00715       for (int i = 1; i < p->size(); i++) //for each arg
00716       {
00717         numConj++;
00718         if (numConj == 1) { firstConj = moveNotInwards((*p)[i]); continue; }
00719         else 
00720         if (numConj == 2) { n=new ListObj; n->append("^");n->append(firstConj);}
00721         n->append(moveNotInwards((*p)[i]));
00722       }
00723 
00724       if (numConj == 1) return firstConj;     
00725       return n;
00726     }
00727 
00728     if (strcmp(opp, "FORALL")==0)
00729     {
00730       ListObj* n = new ListObj;
00731       n->append("EXIST"); 
00732       n->append(new ListObj((*p)[1]));
00733       n->append(moveNotInwards((*p)[2]));
00734       return n;
00735     }
00736 
00737     if (strcmp(opp, "EXIST")==0)
00738     {
00739       ListObj* n = new ListObj;
00740       n->append("FORALL");
00741       n->append(new ListObj((*p)[1]));
00742       n->append(moveNotInwards((*p)[2]));
00743       return n;
00744     }    
00745 
00746     ListObj* n = new ListObj; n->append("!");  n->append(new ListObj(p));
00747     return n;
00748   }
00749 
00750 
00751   static ListObj* disjunctionAndAppend(const ListObj* const & p1, 
00752                                        const ListObj* const & p2)
00753   {
00754     bool p1IsDisjunc = (strcmp(op(p1)->str_, "v")==0);
00755     int ibeg = (p1IsDisjunc) ? 1 : 0;
00756     int iend = (p1IsDisjunc) ? p1->size() : 1;
00757 
00758     bool p2IsDisjunc = (strcmp(op(p2)->str_, "v")==0);
00759     int jbeg = (p2IsDisjunc) ? 1 : 0;
00760     int jend = (p2IsDisjunc) ? p2->size() : 1;
00761 
00762     ListObj* n = new ListObj();
00763     if (p1->size()+p2->size() > 1) n->append("v");
00764 
00765     for (int i = ibeg; i < iend; i++)
00766     {
00767       if (p1IsDisjunc) n->append(new ListObj((*p1)[i]));
00768       else             n->append(new ListObj(p1));
00769     }
00770 
00771     for (int j = jbeg; j < jend; j++)  
00772     {
00773       if (p2IsDisjunc) n->append(new ListObj((*p2)[j]));
00774       else             n->append(new ListObj(p2));
00775     }
00776     return n;
00777   }
00778 
00779 
00780   static ListObj* mergeDisjuncts(const ListObj* const & ddisjuncts, 
00781                                  const int& numDisj)
00782   {
00783     assert(ddisjuncts->size() >= 1);    
00784     if (numDisj == 1) return new ListObj((*ddisjuncts)[ ddisjuncts->size()-1 ]);
00785   
00786     ListObj* y = mergeDisjuncts(ddisjuncts, numDisj-1);
00787     ListObj* x = new ListObj((*ddisjuncts)[ ddisjuncts->size()-numDisj ]);
00788     int numConj = 0;
00789     ListObj* result = NULL;
00790     ListObj* firstConj = NULL;
00791     ListObj* yj, * xi;
00792 
00793     bool yIsConj = strcmp(op(y)->str_, "^")==0;
00794     int jbeg = (yIsConj) ? 1 : 0;
00795     int jmax = (yIsConj) ? y->size() : 1;
00796 
00797     bool xIsConj = strcmp(op(x)->str_, "^")==0;
00798     int xbeg = (xIsConj) ? 1 : 0;
00799     int xmax = (xIsConj) ? x->size() : 1;
00800 
00801     for (int j = jbeg; j < jmax; j++)
00802     {
00803       if (yIsConj) yj = (*y)[j];
00804       else         yj = y;
00805 
00806       for (int i = xbeg; i < xmax; i++)
00807       {
00808         if (xIsConj) xi = (*x)[i];
00809         else         xi = x;
00810 
00811         numConj++;
00812         if (numConj == 1) 
00813         { 
00814           firstConj = disjunctionAndAppend(xi, yj); 
00815           continue; 
00816         }
00817         else
00818         if (numConj == 2) 
00819         { 
00820           result = new ListObj(); 
00821           result->append("^"); 
00822           result->append(firstConj);
00823         }
00824 
00825         result->append(disjunctionAndAppend(xi, yj));
00826       }
00827     }
00828 
00829     delete y; delete x;
00830     if (numConj == 1) return firstConj;
00831     return result;
00832   }
00833 
00834 
00835   static bool isVariable(const ListObj* const & x) 
00836   {
00837     if (strlen(x->str_) == 0) return false;
00838     return ((x->str_)[0] == '$'); 
00839   }
00840 
00841 
00842   static ListObj* newVariable(const ListObj* const & var)
00843   {
00844     assert(var->isStr());
00845     string s;
00846     if (!isVariable(var)) s.append("$");
00847     char buf[128];
00848     sprintf(buf, "%d", ++newVarCounter_);
00849     s.append(var->str_).append(".").append(buf);
00850     return new ListObj(s.c_str());
00851   }
00852 
00853 
00854   static ListObj* skolemConstant(const ListObj* const & name)
00855   {
00856     assert(name->isStr());
00857     char buf[1024];
00858     sprintf(buf, "$%s_%d", name->str_, ++newVarCounter_);
00859     return new ListObj(buf);
00860   }
00861   
00862     //only used in skolemize()
00863   static ListObj* cons(ListObj* const & p1, const ListObj* const & p2)
00864   {
00865     assert(p2->isList());
00866     ListObj* n = new ListObj;
00867     n->append(p1);
00868     for (int i = 0; i < p2->size(); i++) 
00869       n->append(new ListObj((*p2)[i]));
00870     return n;
00871   }
00872 
00873 
00874   static ListObj* skolemize(const ListObj* const & p, 
00875                             const ListObj* const & vars, 
00876                             const ListObj* const & outsideVars)
00877   {
00878     ListObj* pcopy = new ListObj(p);
00879     
00880     ListObj* skolemSym = new ListObj; //skolem constants or functions
00881     if (outsideVars->size() == 0)
00882     {
00883       for (int i = 0; i < vars->size(); i++) 
00884         skolemSym->append(skolemConstant((*vars)[i]));
00885     }
00886     else
00887     {
00888       for (int i = 0; i < vars->size(); i++) 
00889         skolemSym->append( cons(skolemConstant((*vars)[i]),outsideVars) );
00890     }
00891     assert(skolemSym->size() == vars->size());
00892     
00893     for (int i = 0; i < pcopy->size(); i++)
00894       for (int j = 0; j < skolemSym->size(); j++)
00895         (*pcopy)[i]->sub((*vars)[j], (*skolemSym)[j]);
00896 
00897     delete skolemSym;
00898 
00899     return pcopy;
00900   }
00901 
00902 
00903   static bool containsVarName(const ListObj* const & vars, 
00904                               const char* const & varName)
00905   {
00906     for (int i = 0; i < vars->size(); i++)
00907       if (strcmp((*vars)[i]->getStr(), varName)==0) return true;
00908     return false;
00909   }
00910 
00911 
00912     // remove redundant predicates from a clause with two or more predicates
00913   static void removeRedundantPredicates(ListObj* const & p)
00914   {
00915     const char* opp = op(p)->str_;
00916 
00917       // if not a clause with two or more predicates
00918     if (strcmp(opp,"v")!=0) return; 
00919 
00920     Array<ListObj*> preds, redundantPreds;   
00921     for (int i = 1; i < p->size(); i++)
00922     {
00923       bool unique = true;
00924       for (int j = i+1; j < p->size(); j++)
00925         if (same((*p)[i],(*p)[j])) { unique = false; break; }
00926       if (unique) preds.append((*p)[i]);
00927       else        redundantPreds.append((*p)[i]);
00928     }
00929     
00930     ListObj* orOper = (*p)[0];
00931     assert(strcmp(orOper->str_,"v")==0);
00932     for (int i = 0; i < redundantPreds.size(); i++) 
00933       delete redundantPreds[i];
00934     p->clear();
00935       // If clause has reduced to a unit clause, we can't just append
00936     if (preds.size() > 1)
00937     {
00938       p->append(orOper);
00939       for (int i = 0; i < preds.size(); i++) p->append(preds[i]);
00940     }
00941     else if (preds.size() == 1)
00942     {
00943       p->str_ = preds[0]->str_;
00944       p->list_ = preds[0]->list_;
00945     }
00946   }
00947 
00948 
00949   static bool subsetOf(const ListObj* const & p, const ListObj* const & q)
00950   {
00951     if (p->size() > q->size()) return false;
00952     for (int i = 0; i < p->size(); i++)
00953     {
00954       bool sameAsOneElt = false;
00955       for (int j = 0; j < q->size(); j++)
00956         if (same((*p)[i],(*q)[j])) { sameAsOneElt = true; break; }
00957       if (!sameAsOneElt) return false;
00958     }
00959     return true;
00960   }
00961 
00962 
00963  private:
00964     // If the formula is (v (P x) (Q y)), 
00965     // list_[0]: is a ListObj with str_ == "v"
00966     // list_[1]: is a ListObj lo1 s.t lo1.list_[0].str_ == "P", 
00967     //                                lo1.list_[1].str_ == "x"
00968 
00969   Array<ListObj*> list_;
00970 
00971   char* str_;
00972 
00973   static int newVarCounter_;
00974   static ListObj* null_;
00975 };
00976 
00977 
00978 inline
00979 ostream& operator<<(ostream& out, const ListObj& p) { return p.print(out); }
00980 
00981 
00982 #endif

Generated on Sun Jun 7 11:55:19 2009 for Alchemy by  doxygen 1.5.1