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 and Hoifung Poon.
00006  * 
00007  * Copyright [2004-07] Stanley Kok, Parag Singla, Matthew
00008  * Richardson, Pedro Domingos, Marc Sumner and Hoifung
00009  * Poon. 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 and Hoifung
00032  * Poon 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   int size() const { return list_.size(); }
00179 
00180   ListObj* operator[](const int& index) const { return list_[index]; } 
00181 
00182 
00183   static ListObj* toCNF(const ListObj* const & p, const ListObj* const & vars, 
00184                         const Domain* const & domain, 
00185                         const VarTypeMap * const& vtMap, bool& hasExist)
00186   {
00187     ListObj* p1 = eliminateImplication(p);
00188 
00189     const char* opp = op(p1)->str_;
00190     
00191     if (strcmp(opp, "!")==0)
00192     {
00193       ListObj* p2 = moveNotInwards(arg1(p1));
00194       if (isLiteralClause(p2)) { delete p1; return p2; }
00195 
00196       ListObj* ret = toCNF(p2, vars, domain, vtMap, hasExist);
00197       delete p2; delete p1;
00198       return ret;
00199     }
00200     
00201     if (strcmp(opp, "^")==0)
00202     {
00203       ListObj* n = NULL;
00204       int numConj = 0;
00205       ListObj* firstConj = NULL;
00206 
00207       for (int i = 1; i < p1->size(); i++) // for each arg
00208       {        
00209         ListObj* conj = toCNF((*p1)[i], vars, domain, vtMap, hasExist);
00210 
00211         bool isConj = strcmp(op(conj)->str_, "^")==0;
00212         int jbeg = (isConj) ? 1 : 0;
00213         int jmax = (isConj) ? conj->size() : 1;
00214         ListObj* conjj;
00215 
00216         for (int j = jbeg; j < jmax; j++) 
00217         {
00218           if (isConj) conjj = (*conj)[j];
00219           else        conjj = conj;
00220 
00221           numConj++;
00222           if (numConj==1) { firstConj = conjj; continue; }
00223           else 
00224           if (numConj==2) {n=new ListObj; n->append("^"); n->append(firstConj);}
00225           n->append(conjj);
00226         }
00227 
00228         if (isConj) { delete (*conj)[0]; conj->clearList(); delete conj; }
00229 
00230       }
00231 
00232       delete p1;
00233       if (numConj == 1) { return firstConj; }        
00234       return n;
00235     }
00236     
00237     if (strcmp(opp, "v")==0)
00238     {
00239       ListObj* n = new ListObj;
00240       for (int i = 1; i < p1->size(); i++) // for each arg
00241         n->append(toCNF((*p1)[i], vars, domain, vtMap, hasExist));
00242       ListObj* ret = mergeDisjuncts(n, n->size());
00243 
00244       delete n; delete p1;
00245       return ret;
00246     }
00247     
00248     if (strcmp(opp, "FORALL")==0)
00249     {
00250       const ListObj* arg1var = arg1(p1);
00251 
00252       ListObj* newVar = new ListObj;
00253       for (int i = 0; i < arg1var->size(); i++)
00254         newVar->append(newVariable((*arg1var)[i]));
00255       assert(newVar->size() == arg1var->size());
00256       
00257       const ListObj* aarg2 = new ListObj(arg2(p1));
00258 
00259       for (int i = 0; i < newVar->size(); i++)
00260         for (int j = 0; j < aarg2->size(); j++)
00261           (*aarg2)[j]->sub((*arg1var)[i], (*newVar)[i]);
00262 
00263       ListObj* app = new ListObj;
00264       for (int i = 0; i < newVar->size(); i++)  app->append((*newVar)[i]);
00265       for (int i = 0; i < vars->size(); i++)    app->append((*vars)[i]);
00266       
00267       newVar->clearList();
00268       delete newVar;
00269       ListObj* ret = toCNF(aarg2, app, domain, vtMap, hasExist);
00270       delete aarg2; delete app; delete p1;
00271       return ret;
00272     }
00273 
00274     if (strcmp(opp, "EXIST")==0)
00275     {
00276       hasExist = true;
00277       const ListObj* a2 = arg2(p1); // formula
00278       const ListObj* a1 = arg1(p1); // variables
00279 
00280         // without a domain, there are no constants to ground an existentially
00281         // quantified clause, so we must skolemize
00282       if (domain == NULL)
00283       {
00284         ListObj* sk = skolemize(a2, a1, vars);
00285         ListObj* c  = toCNF(sk, vars, domain, vtMap, hasExist);
00286         delete sk; delete p1;
00287         return c;
00288       }
00289         // get the variable names
00290       Array<string> varNames;
00291       for (int i = 0; i < a1->size(); i++)
00292         varNames.append((*a1)[i]->getStr());
00293 
00294       ArraysAccessor<int> arrAccessor;
00295       for (int i = 0; i < varNames.size(); i++)
00296       {        
00297         VarTypeMap::const_iterator mit = vtMap->find(varNames[i]);
00298         assert(mit != vtMap->end());
00299         int typeId = (*mit).second;
00300         assert(typeId > 0);
00301         const Array<int>* constArr = domain->getConstantsByType(typeId);
00302         if (constArr->size() == 0)
00303         {
00304           cout << "You must declare constants for type " 
00305                << domain->getTypeName(typeId) 
00306                << " in order to ground the variable " << varNames[i] << endl;
00307           exit(-1);
00308         }
00309         arrAccessor.appendArray(constArr);
00310       }
00311 
00312       if (varNames.size()==0){cout<<"ERROR: EXIST has no vars."<<endl;exit(-1);}
00313 
00314       ListObj* newFormula = new ListObj;
00315       newFormula->append("v");
00316       Array<int> constIds;
00317       while (arrAccessor.getNextCombination(constIds))
00318       {
00319         ListObj* replacedFormula = new ListObj(a2);
00320 
00321         assert(constIds.size() == varNames.size());
00322         for (int i = 0; i < varNames.size(); i++)
00323         {
00324           const char* constName = domain->getConstantName(constIds[i]);
00325           replace(replacedFormula, varNames[i].c_str(), constName, domain);
00326         }
00327         newFormula->append(replacedFormula);
00328       }
00329       //newFormula->print(cout); cout << endl;
00330 
00331       delete p1;
00332       ListObj* c  = toCNF(newFormula, vars, domain, vtMap, hasExist);
00333 
00334       delete newFormula; 
00335       return c;
00336     }
00337 
00338     return p1;
00339   }
00340 
00341 
00342   void replaceAsterisk(const Array<bool>& bArr, int& idx)
00343   {
00344     if (!isStr())
00345     {
00346       const char* opp = op(this)->str_;
00347 
00348       if (strcmp(opp, "*")==0)
00349       {
00350         assert(size()==2);
00351           // if false, replace the * with !, 
00352           // else set (*this) to be the formula without the !
00353         if (!bArr[idx]) 
00354           (*this)[0]->setStrIfStr("!");
00355         else            
00356         { 
00357           ListObj* unNegatedFormula = new ListObj((*this)[1]); 
00358           assert(!unNegatedFormula->isStr());
00359           deleteAndClear();
00360           for (int i = 0; i < unNegatedFormula->size(); i++)
00361             append((*unNegatedFormula)[i]);
00362           unNegatedFormula->clear();
00363           delete unNegatedFormula;
00364         }
00365         idx++;
00366         if (idx == bArr.size()) return;
00367       }
00368 
00369       for (int i = 0; i < size(); i++)
00370       {
00371         (*this)[i]->replaceAsterisk(bArr, idx);
00372         if (idx == bArr.size()) return;
00373       }
00374     }
00375   }
00376 
00377 
00378     // removes $ and .10 from $x.10
00379   void cleanUpVars()
00380   {
00381     if (isStr())
00382     {
00383       if (str_[0] != '$') return;
00384       char* dot = strrchr(str_, '.'); 
00385       if (dot==NULL) return; // dealing with skolem constant of function
00386       int numChar = dot-str_-1;
00387       char* tmp = new char[numChar+1];
00388       strncpy(tmp, str_+1, numChar);
00389       tmp[numChar] = '\0';
00390       delete [] str_;
00391       str_ = tmp;
00392     }
00393     else
00394       for (int i = 0; i < list_.size(); i++)
00395         list_[i]->cleanUpVars(); 
00396   }
00397 
00398 
00399   void removeRedundantPredicates()
00400   {
00401     const char* opp = op(this)->str_;
00402 
00403     if (strcmp(opp,"^")==0)
00404     {
00405       for (int i = 1; i < size(); i++) // for each clause
00406         removeRedundantPredicates((*this)[i]);      
00407     }
00408     else
00409       removeRedundantPredicates(this);
00410   }
00411 
00412 
00413   void removeRedundantClauses()
00414   {
00415     //for each clause, remove redundant predicates
00416     //for each clause
00417     //  compare it to every other clause c
00418     //  if it contains c, remove it from *this
00419 
00420     const char* opp = op(this)->str_;
00421 
00422     if (strcmp(opp,"^")==0)
00423     {
00424       for (int i = 1; i < size(); i++) // for each clause
00425         removeRedundantPredicates((*this)[i]);
00426       
00427       Array<ListObj*> clauses, redundantClauses;
00428       for (int i = 1; i < size(); i++)
00429       {
00430         bool keep = true;
00431         for (int j = 1; j < size(); j++)
00432         {
00433           if (i==j) continue;
00434           if (subsetOf((*this)[j],(*this)[i])) 
00435             if ((*this)[i]->size() != (*this)[j]->size() || i < j) 
00436             { keep = false; break; }
00437         }
00438       if (keep) clauses.append((*this)[i]);
00439       else      redundantClauses.append((*this)[i]);
00440       }
00441 
00442       ListObj* andOper = (*this)[0];
00443       assert(strcmp(andOper->str_,"^")==0);
00444         //delete the operator and redundant clauses
00445       for (int i = 0; i < redundantClauses.size(); i++)
00446         delete redundantClauses[i];
00447       clear();
00448       append(andOper);
00449       for (int i = 0; i < clauses.size(); i++) append(clauses[i]);
00450     }
00451     else
00452       removeRedundantPredicates(this);
00453   }
00454 
00455 
00456   static void replace(const ListObj* const & p, const char* const & varName,
00457                       const char* const& constName, const Domain* const& domain)
00458   {
00459     const char* opp = op(p)->str_;
00460     
00461       //if there is variable of the same name that is existentially/universally
00462       //in an inner scope, then return;
00463     if (strcmp(opp, "EXIST")==0 || strcmp(opp, "FORALL")==0)
00464       if (containsVarName((*p)[1], varName)) return;
00465 
00466       // if we are currently looking at a predicate or a function
00467     const bool isPredFunc = (   domain->isPredicate(opp) 
00468                              || domain->isFunction(opp));
00469 
00470     for (int i = 1; i < p->size(); i++)
00471     {
00472         // if we are currently looking at a predicate/function 
00473         // AND the param is a possible var
00474       if (isPredFunc && (*p)[i]->isStr())
00475       {
00476           //if we found the variable
00477         if (strcmp((*p)[i]->getStr(), varName)==0)
00478           (*p)[i]->setStrIfStr(constName);
00479       }
00480       else
00481         replace((*p)[i], varName, constName, domain);
00482     }
00483   }
00484 
00485 
00486   void replace(const char* const & oldop, const char* const & newop)
00487   {
00488     for (int i = 0; i < size(); i++)
00489     {
00490       if (strcmp((*this)[i]->getStr(), oldop)==0)
00491         (*this)[i]->setStrIfStr(newop);
00492       else
00493         (*this)[i]->replace(oldop, newop);
00494     }
00495   }
00496 
00497   
00498   bool hasOrOp()
00499   {
00500     if (!isList()) return false;
00501     return (strcmp(op(this)->str_,"v")==0);
00502   }
00503 
00504   
00505   bool hasAndOp()
00506   {
00507     if (!isList()) return false;
00508     return (strcmp(op(this)->str_,"^")==0);
00509   }
00510 
00511 
00512  private:
00513   static bool same(const ListObj* const & lo1, const ListObj* const & lo2)
00514   {
00515     if (lo1->isStr() && lo2->isStr()) 
00516     {
00517       if (strcmp(lo1->str_, lo2->str_)==0) return true;
00518       return false;
00519     }
00520 
00521     if (lo1->isList() && lo2->isList())
00522     {
00523       if (lo1->size() == lo2->size())
00524       {
00525         for (int i = 0; i < lo1->size(); i++)
00526           if (!same((*lo1)[i],(*lo2)[i])) return false;
00527         return true;
00528       }
00529       return false;        
00530     }
00531     return false;
00532   }
00533 
00534 
00535   void sub(const ListObj* const & oldlo, const ListObj* const & newlo)
00536   {
00537     if (isStr()) 
00538     {
00539       if (same(this, oldlo))
00540       {
00541         if (newlo->isStr()) 
00542         {
00543           delete [] str_;
00544           str_ = new char[strlen(newlo->str_)+1];
00545           strcpy(str_, newlo->str_);
00546         }
00547         else
00548         {
00549           delete [] str_;
00550           str_ = new char[1];
00551           str_[0] = '\0';
00552           list_.deleteItemsAndClear();
00553 
00554           for (int i = 0; i < newlo->size(); i++)
00555             list_.append(new ListObj((*newlo)[i]));
00556         }
00557       }
00558       return;
00559     }
00560     
00561     for (int i = 0; i < list_.size(); i++)
00562     {
00563       if (same(list_[i],oldlo)) {delete list_[i]; list_[i]=new ListObj(newlo); }
00564       else                       list_[i]->sub(oldlo, newlo);
00565     }
00566   }
00567 
00568 
00569   static const ListObj* op(const ListObj* const & exp)
00570   {
00571     assert(exp->isList());
00572     if (exp->size() == 0) return exp;
00573     return (*exp)[0];
00574   }
00575 
00576 
00577   static const ListObj* arg1(const ListObj* const & exp)
00578   { 
00579     if (exp->isList() && exp->size() > 1) return (*exp)[1];
00580     else                                  return null_;
00581   }
00582   
00583 
00584   static const ListObj* arg2(const ListObj* const & exp)  
00585   { 
00586     if (exp->isList() && exp->size() > 2) return (*exp)[2];
00587     else                                  return null_;
00588   }
00589   
00590 
00591 
00592   static bool isConnective(const char* const & c)
00593   {
00594     if (strcmp(c, "^")==0 || strcmp(c, "v")==0 || strcmp(c, "!")==0 || 
00595         strcmp(c, "=>")==0 || strcmp(c, "<=>")==0 )
00596       return true;
00597     return false;
00598   }
00599 
00600 
00601   static bool isQuantifier(const char* const & q)
00602   {
00603     if (strcmp(q, "FORALL")==0 || strcmp(q, "EXIST")==0)
00604       return true;
00605     return false;
00606   }
00607   
00608 
00609     // An atomic clause has no connectives or quantifiers.
00610   static bool isAtomicClause(const ListObj* const & sentence)
00611   {
00612       //op(sentence) is a temporary object. Assigning opp as in 
00613       //"const char* opp = op(sentence).str_" cause opp to be mangled.
00614     const char* opp = op(sentence)->str_;
00615     if (!isConnective(opp) && !isQuantifier(opp)) return true;
00616     return false;      
00617   }
00618 
00619 
00620   static bool isNegatedClause(const ListObj* const & sentence)
00621   {
00622     if (strcmp(op(sentence)->str_, "!")==0) return true;
00623     return false;
00624   }
00625 
00626 
00627   static bool isLiteralClause(const ListObj* const & sentence)
00628   {
00629     if (isAtomicClause(sentence) || (isNegatedClause(sentence) 
00630                                      && isAtomicClause(arg1(sentence))))
00631       return true;
00632     return false;
00633   }
00634 
00635 
00636   static ListObj* eliminateImplication(const ListObj* const & p)
00637   {
00638     if (isLiteralClause(p)) return new ListObj(p);
00639 
00640     const char* opp = op(p)->str_;
00641 
00642     if (strcmp(opp, "=>")==0)
00643     {
00644       ListObj* n1 = new ListObj; 
00645       n1->append("!"); n1->append(new ListObj(arg1(p)));
00646       ListObj* n = new ListObj; 
00647       n->append("v"); n->append(new ListObj(arg2(p))); n->append(n1);
00648       return n;
00649     }
00650     else
00651     if (strcmp(opp, "<=>")==0)
00652     {        
00653       ListObj* n1a = new ListObj;
00654       n1a->append("!"); n1a->append(new ListObj(arg1(p)));
00655       ListObj* na = new ListObj; 
00656       na->append("v"); na->append(n1a); na->append(new ListObj(arg2(p)));
00657 
00658       ListObj* n1b = new ListObj; 
00659       n1b->append("!"); n1b->append(new ListObj(arg2(p)));
00660       ListObj* nb = new ListObj; 
00661       nb->append("v"); nb->append(new ListObj(arg1(p)));
00662       nb->append(n1b); 
00663       
00664       ListObj* n = new ListObj; n->append("^"); n->append(nb); n->append(na);
00665       return n;
00666     }
00667     else
00668     {
00669       ListObj* n = new ListObj; n->append(opp);
00670       for (int i = 1; i < p->size(); i++) // for each arg
00671         n->append(eliminateImplication((*p)[i]));
00672       return n;
00673     }
00674   }
00675 
00676 
00677   static ListObj* moveNotInwards(const ListObj* const & p)
00678   {
00679     const char* opp = op(p)->str_;
00680 
00681     if (strcmp(opp, "!")==0) return new ListObj((*p)[1]);
00682 
00683     if (strcmp(opp, "^")==0)
00684     {
00685       ListObj* n = NULL;
00686       int numDisj = 0;
00687       ListObj* firstDisj = NULL;
00688 
00689       for (int i = 1; i < p->size(); i++) //for each arg
00690       {
00691         numDisj++;
00692         if (numDisj == 1) { firstDisj = moveNotInwards((*p)[i]); continue; }
00693         else 
00694         if (numDisj == 2) {n=new ListObj; n->append("v"); n->append(firstDisj);}
00695         n->append(moveNotInwards((*p)[i]));
00696       }
00697       if (numDisj == 1) return firstDisj;
00698       return n;
00699     }
00700 
00701     if (strcmp(opp, "v")==0)
00702     {
00703       ListObj* n = NULL;
00704       int numConj = 0;
00705       ListObj* firstConj = NULL;
00706       
00707       for (int i = 1; i < p->size(); i++) //for each arg
00708       {
00709         numConj++;
00710         if (numConj == 1) { firstConj = moveNotInwards((*p)[i]); continue; }
00711         else 
00712         if (numConj == 2) { n=new ListObj; n->append("^");n->append(firstConj);}
00713         n->append(moveNotInwards((*p)[i]));
00714       }
00715 
00716       if (numConj == 1) return firstConj;     
00717       return n;
00718     }
00719 
00720     if (strcmp(opp, "FORALL")==0)
00721     {
00722       ListObj* n = new ListObj;
00723       n->append("EXIST"); 
00724       n->append(new ListObj((*p)[1]));
00725       n->append(moveNotInwards((*p)[2]));
00726       return n;
00727     }
00728 
00729     if (strcmp(opp, "EXIST")==0)
00730     {
00731       ListObj* n = new ListObj;
00732       n->append("FORALL");
00733       n->append(new ListObj((*p)[1]));
00734       n->append(moveNotInwards((*p)[2]));
00735       return n;
00736     }    
00737 
00738     ListObj* n = new ListObj; n->append("!");  n->append(new ListObj(p));
00739     return n;
00740   }
00741 
00742 
00743   static ListObj* disjunctionAndAppend(const ListObj* const & p1, 
00744                                        const ListObj* const & p2)
00745   {
00746     bool p1IsDisjunc = (strcmp(op(p1)->str_, "v")==0);
00747     int ibeg = (p1IsDisjunc) ? 1 : 0;
00748     int iend = (p1IsDisjunc) ? p1->size() : 1;
00749 
00750     bool p2IsDisjunc = (strcmp(op(p2)->str_, "v")==0);
00751     int jbeg = (p2IsDisjunc) ? 1 : 0;
00752     int jend = (p2IsDisjunc) ? p2->size() : 1;
00753 
00754     ListObj* n = new ListObj();
00755     if (p1->size()+p2->size() > 1) n->append("v");
00756 
00757     for (int i = ibeg; i < iend; i++)
00758     {
00759       if (p1IsDisjunc) n->append(new ListObj((*p1)[i]));
00760       else             n->append(new ListObj(p1));
00761     }
00762 
00763     for (int j = jbeg; j < jend; j++)  
00764     {
00765       if (p2IsDisjunc) n->append(new ListObj((*p2)[j]));
00766       else             n->append(new ListObj(p2));
00767     }
00768     return n;
00769   }
00770 
00771 
00772   static ListObj* mergeDisjuncts(const ListObj* const & ddisjuncts, 
00773                                  const int& numDisj)
00774   {
00775     assert(ddisjuncts->size() >= 1);    
00776     if (numDisj == 1) return new ListObj((*ddisjuncts)[ ddisjuncts->size()-1 ]);
00777   
00778     ListObj* y = mergeDisjuncts(ddisjuncts, numDisj-1);
00779     ListObj* x = new ListObj((*ddisjuncts)[ ddisjuncts->size()-numDisj ]);
00780     int numConj = 0;
00781     ListObj* result = NULL;
00782     ListObj* firstConj = NULL;
00783     ListObj* yj, * xi;
00784 
00785     bool yIsConj = strcmp(op(y)->str_, "^")==0;
00786     int jbeg = (yIsConj) ? 1 : 0;
00787     int jmax = (yIsConj) ? y->size() : 1;
00788 
00789     bool xIsConj = strcmp(op(x)->str_, "^")==0;
00790     int xbeg = (xIsConj) ? 1 : 0;
00791     int xmax = (xIsConj) ? x->size() : 1;
00792 
00793     for (int j = jbeg; j < jmax; j++)
00794     {
00795       if (yIsConj) yj = (*y)[j];
00796       else         yj = y;
00797 
00798       for (int i = xbeg; i < xmax; i++)
00799       {
00800         if (xIsConj) xi = (*x)[i];
00801         else         xi = x;
00802 
00803         numConj++;
00804         if (numConj == 1) 
00805         { 
00806           firstConj = disjunctionAndAppend(xi, yj); 
00807           continue; 
00808         }
00809         else
00810         if (numConj == 2) 
00811         { 
00812           result = new ListObj(); 
00813           result->append("^"); 
00814           result->append(firstConj);
00815         }
00816 
00817         result->append(disjunctionAndAppend(xi, yj));
00818       }
00819     }
00820 
00821     delete y; delete x;
00822     if (numConj == 1) return firstConj;
00823     return result;
00824   }
00825 
00826 
00827   static bool isVariable(const ListObj* const & x) 
00828   {
00829     if (strlen(x->str_) == 0) return false;
00830     return ((x->str_)[0] == '$'); 
00831   }
00832 
00833 
00834   static ListObj* newVariable(const ListObj* const & var)
00835   {
00836     assert(var->isStr());
00837     string s;
00838     if (!isVariable(var)) s.append("$");
00839     char buf[128];
00840     sprintf(buf, "%d", ++newVarCounter_);
00841     s.append(var->str_).append(".").append(buf);
00842     return new ListObj(s.c_str());
00843   }
00844 
00845 
00846   static ListObj* skolemConstant(const ListObj* const & name)
00847   {
00848     assert(name->isStr());
00849     char buf[1024];
00850     sprintf(buf, "$%s_%d", name->str_, ++newVarCounter_);
00851     return new ListObj(buf);
00852   }
00853   
00854     //only used in skolemize()
00855   static ListObj* cons(ListObj* const & p1, const ListObj* const & p2)
00856   {
00857     assert(p2->isList());
00858     ListObj* n = new ListObj;
00859     n->append(p1);
00860     for (int i = 0; i < p2->size(); i++) 
00861       n->append(new ListObj((*p2)[i]));
00862     return n;
00863   }
00864 
00865 
00866   static ListObj* skolemize(const ListObj* const & p, 
00867                             const ListObj* const & vars, 
00868                             const ListObj* const & outsideVars)
00869   {
00870     ListObj* pcopy = new ListObj(p);
00871     
00872     ListObj* skolemSym = new ListObj; //skolem constants or functions
00873     if (outsideVars->size() == 0)
00874     {
00875       for (int i = 0; i < vars->size(); i++) 
00876         skolemSym->append(skolemConstant((*vars)[i]));
00877     }
00878     else
00879     {
00880       for (int i = 0; i < vars->size(); i++) 
00881         skolemSym->append( cons(skolemConstant((*vars)[i]),outsideVars) );
00882     }
00883     assert(skolemSym->size() == vars->size());
00884     
00885     for (int i = 0; i < pcopy->size(); i++)
00886       for (int j = 0; j < skolemSym->size(); j++)
00887         (*pcopy)[i]->sub((*vars)[j], (*skolemSym)[j]);
00888 
00889     delete skolemSym;
00890 
00891     return pcopy;
00892   }
00893 
00894 
00895   static bool containsVarName(const ListObj* const & vars, 
00896                               const char* const & varName)
00897   {
00898     for (int i = 0; i < vars->size(); i++)
00899       if (strcmp((*vars)[i]->getStr(), varName)==0) return true;
00900     return false;
00901   }
00902 
00903 
00904     // remove redundant predicates from a clause with two or more predicates
00905   static void removeRedundantPredicates(ListObj* const & p)
00906   {
00907     const char* opp = op(p)->str_;
00908 
00909       // if not a clause with two or more predicates
00910     if (strcmp(opp,"v")!=0) return; 
00911 
00912     Array<ListObj*> preds, redundantPreds;   
00913     for (int i = 1; i < p->size(); i++)
00914     {
00915       bool unique = true;
00916       for (int j = i+1; j < p->size(); j++)
00917         if (same((*p)[i],(*p)[j])) { unique = false; break; }
00918       if (unique) preds.append((*p)[i]);
00919       else        redundantPreds.append((*p)[i]);
00920     }
00921     
00922     ListObj* orOper = (*p)[0];
00923     assert(strcmp(orOper->str_,"v")==0);
00924     for (int i = 0; i < redundantPreds.size(); i++) 
00925       delete redundantPreds[i];
00926     p->clear();
00927     p->append(orOper);
00928     for (int i = 0; i < preds.size(); i++) p->append(preds[i]);
00929   }
00930 
00931 
00932   static bool subsetOf(const ListObj* const & p, const ListObj* const & q)
00933   {
00934     if (p->size() > q->size()) return false;
00935     for (int i = 0; i < p->size(); i++)
00936     {
00937       bool sameAsOneElt = false;
00938       for (int j = 0; j < q->size(); j++)
00939         if (same((*p)[i],(*q)[j])) { sameAsOneElt = true; break; }
00940       if (!sameAsOneElt) return false;
00941     }
00942     return true;
00943   }
00944 
00945 
00946  private:
00947     // If the formula is (v (P x) (Q y)), 
00948     // list_[0]: is a ListObj with str_ == "v"
00949     // list_[1]: is a ListObj lo1 s.t lo1.list_[0].str_ == "P", 
00950     //                                lo1.list_[1].str_ == "x"
00951 
00952   Array<ListObj*> list_;
00953 
00954   char* str_;
00955 
00956   static int newVarCounter_;
00957   static ListObj* null_;
00958 };
00959 
00960 
00961 inline
00962 ostream& operator<<(ostream& out, const ListObj& p) { return p.print(out); }
00963 
00964 
00965 #endif

Generated on Tue Jan 16 05:30:05 2007 for Alchemy by  doxygen 1.5.1