Add priorities to getNextDecision. Properly handle case for finite types + unbounded...
authorajreynol <andrew.j.reynolds@gmail.com>
Thu, 3 Nov 2016 20:09:12 +0000 (15:09 -0500)
committerajreynol <andrew.j.reynolds@gmail.com>
Thu, 3 Nov 2016 20:09:26 +0000 (15:09 -0500)
25 files changed:
src/theory/arrays/theory_arrays.cpp
src/theory/arrays/theory_arrays.h
src/theory/quantifiers/bounded_integers.cpp
src/theory/quantifiers/bounded_integers.h
src/theory/quantifiers/ce_guided_instantiation.cpp
src/theory/quantifiers/ce_guided_instantiation.h
src/theory/quantifiers/inst_strategy_cbqi.cpp
src/theory/quantifiers/inst_strategy_cbqi.h
src/theory/quantifiers/quant_util.h
src/theory/quantifiers/theory_quantifiers.cpp
src/theory/quantifiers/theory_quantifiers.h
src/theory/quantifiers_engine.cpp
src/theory/quantifiers_engine.h
src/theory/sep/theory_sep.cpp
src/theory/sep/theory_sep.h
src/theory/strings/theory_strings.cpp
src/theory/strings/theory_strings.h
src/theory/theory.h
src/theory/theory_engine.cpp
src/theory/uf/theory_uf.cpp
src/theory/uf/theory_uf.h
src/theory/uf/theory_uf_strong_solver.cpp
src/theory/uf/theory_uf_strong_solver.h
test/regress/regress0/sep/Makefile.am
test/regress/regress0/sep/sep-fmf-priority.smt2 [new file with mode: 0644]

index 28a08630e107f4a0b341db56ab6aa5b808903323..7946fea59c8b9b747928512c63041875f016f847 100644 (file)
@@ -2119,10 +2119,11 @@ void TheoryArrays::queueRowLemma(RowLemmaType lem)
 }
 
 
-Node TheoryArrays::getNextDecisionRequest() {
+Node TheoryArrays::getNextDecisionRequest( unsigned& priority ) {
   if(! d_decisionRequests.empty()) {
     Node n = d_decisionRequests.front();
     d_decisionRequests.pop();
+    priority = 2;
     return n;
   } else {
     return Node::null();
index c1223474c05abf6f643748d42290354049b3e115..77c5928f0d9b06bd2a215ab520a83e0b9e7691c4 100644 (file)
@@ -255,7 +255,7 @@ class TheoryArrays : public Theory {
   private:
   public:
 
-  Node getNextDecisionRequest();
+  Node getNextDecisionRequest( unsigned& priority );
 
   void presolve();
   void shutdown() { }
index 54853ceafa09ebc470d28e1a72f9d4960667b363..dc0019383fdc12e5b6532446e960d7f034c0de3e 100644 (file)
@@ -417,7 +417,7 @@ void BoundedIntegers::assertNode( Node n ) {
   d_assertions[nlit] = n.getKind()!=NOT;
 }
 
-Node BoundedIntegers::getNextDecisionRequest() {
+Node BoundedIntegers::getNextDecisionRequest( unsigned& priority ) {
   Trace("bound-int-dec-debug") << "bi: Get next decision request?" << std::endl;
   for( unsigned i=0; i<d_ranges.size(); i++) {
     Node d = d_rms[d_ranges[i]]->getNextDecisionRequest();
@@ -435,6 +435,7 @@ Node BoundedIntegers::getNextDecisionRequest() {
           i--;
         }
       }else{
+        priority = 1;
         Trace("bound-int-dec") << "Bounded Integers : Decide " << d << std::endl;
         return d;
       }
index c3fb056414b57e32afa42ba675c9313e691868f2..0dfd7eafddaedd8a8a3249b8d66473c62f185bca 100644 (file)
@@ -146,7 +146,7 @@ public:
   void check( Theory::Effort e, unsigned quant_e );
   void registerQuantifier( Node f );
   void assertNode( Node n );
-  Node getNextDecisionRequest();
+  Node getNextDecisionRequest( unsigned& priority );
   bool isBoundVar( Node q, Node v ) { return std::find( d_set[q].begin(), d_set[q].end(), v )!=d_set[q].end(); }
   unsigned getBoundVarType( Node q, Node v );
   unsigned getNumBoundVars( Node q ) { return d_set[q].size(); }
index 54415d974ee0290f2b7ae4e05eb8149186f09eff..ecf4bb74dfe7f848f29b3650692fc47566031098 100644 (file)
@@ -229,6 +229,10 @@ CegInstantiation::CegInstantiation( QuantifiersEngine * qe, context::Context* c
   d_last_inst_si = false;
 }
 
+CegInstantiation::~CegInstantiation(){ 
+  delete d_conj;
+}
+
 bool CegInstantiation::needsCheck( Theory::Effort e ) {
   return e>=Theory::EFFORT_LAST_CALL;
 }
@@ -345,7 +349,7 @@ void CegInstantiation::registerQuantifier( Node q ) {
 void CegInstantiation::assertNode( Node n ) {
 }
 
-Node CegInstantiation::getNextDecisionRequest() {
+Node CegInstantiation::getNextDecisionRequest( unsigned& priority ) {
   //enforce fairness
   if( d_conj->isAssigned() ){
     d_conj->initializeGuard( d_quantEngine );
@@ -363,6 +367,7 @@ Node CegInstantiation::getNextDecisionRequest() {
       bool value;
       if( !d_quantEngine->getValuation().hasSatValue( req_dec[i], value ) ) {
         Trace("cegqi-debug") << "CEGQI : Decide next on : " << req_dec[i] << "..." << std::endl;
+        priority = 0;
         return req_dec[i];
       }else{
         Trace("cegqi-debug2") << "CEGQI : " << req_dec[i] << " already has value " << value << std::endl;
@@ -377,10 +382,12 @@ Node CegInstantiation::getNextDecisionRequest() {
           d_conj->d_curr_lit.set( d_conj->d_curr_lit.get() + 1 );
           lit = d_conj->getLiteral( d_quantEngine, d_conj->d_curr_lit.get() );
           Trace("cegqi-debug") << "CEGQI : Decide on next lit : " << lit << "..." << std::endl;
+          priority = 1;
           return lit;
         }
       }else{
         Trace("cegqi-debug") << "CEGQI : Decide on current lit : " << lit << "..." << std::endl;
+        priority = 1;
         return lit;
       }
     }
index c8b41c035b878ab0e970be3c1b717046d4857811..7f36f4d25bc73240512dc4368e67c4dbe2fca2ec 100644 (file)
@@ -154,6 +154,7 @@ private:
   Node getModelTerm( Node n );
 public:
   CegInstantiation( QuantifiersEngine * qe, context::Context* c );
+  ~CegInstantiation();
 public:
   bool needsCheck( Theory::Effort e );
   unsigned needsModel( Theory::Effort e );
@@ -163,7 +164,7 @@ public:
   void preRegisterQuantifier( Node q );
   void registerQuantifier( Node q );
   void assertNode( Node n );
-  Node getNextDecisionRequest();
+  Node getNextDecisionRequest( unsigned& priority );
   /** Identify this module (for debugging, dynamic configuration, etc..) */
   std::string identify() const { return "CegInstantiation"; }
   /** print solution for synthesis conjectures */
index ac6e1edbe874e11ae551528797bda9029c181b23..895a0c93c50e95a9093f48f95594b9ba16a074ab 100644 (file)
@@ -592,12 +592,13 @@ Node InstStrategyCbqi::getNextDecisionRequestProc( Node q, std::map< Node, bool
   return Node::null(); 
 }
 
-Node InstStrategyCbqi::getNextDecisionRequest(){
+Node InstStrategyCbqi::getNextDecisionRequest( unsigned& priority ){
   std::map< Node, bool > proc;
   for( unsigned i=0; i<d_quantEngine->getModel()->getNumAssertedQuantifiers(); i++ ){
     Node q = d_quantEngine->getModel()->getAssertedQuantifier( i );
     Node d = getNextDecisionRequestProc( q, proc );
     if( !d.isNull() ){
+      priority = 0;
       return d;
     }
   }
index c9f62243fb139998b6f979a2a78852ff3117e914..2cd5f6e1c60be7393800b305a78a3b28c662ddf0 100644 (file)
@@ -107,7 +107,7 @@ public:
   void preRegisterQuantifier( Node q );
   void registerQuantifier( Node q );
   /** get next decision request */
-  Node getNextDecisionRequest();
+  Node getNextDecisionRequest( unsigned& priority );
 };
 
 //generalized counterexample guided quantifier instantiation
index 3ff21aa6e003b4e6f89081638141295a47ed6390..b4264135c12fd3082206caf2ea48f7dac4cc9fa1 100644 (file)
@@ -61,7 +61,7 @@ public:
   virtual void registerQuantifier( Node q ) = 0;
   virtual void assertNode( Node n ) {}
   virtual void propagate( Theory::Effort level ){}
-  virtual Node getNextDecisionRequest() { return TNode::null(); }
+  virtual Node getNextDecisionRequest( unsigned& priority ) { return TNode::null(); }
   /** Identify this module (for debugging, dynamic configuration, etc..) */
   virtual std::string identify() const = 0;
 public:
index e97a76ce6cb596721492192b0352fa3fdef58510..0b4f3c0c7048ccbaedb2ef040c7699451038a390 100644 (file)
@@ -179,8 +179,8 @@ void TheoryQuantifiers::check(Effort e) {
   getQuantifiersEngine()->check( e );
 }
 
-Node TheoryQuantifiers::getNextDecisionRequest(){
-  return getQuantifiersEngine()->getNextDecisionRequest();
+Node TheoryQuantifiers::getNextDecisionRequest( unsigned& priority ){
+  return getQuantifiersEngine()->getNextDecisionRequest( priority );
 }
 
 void TheoryQuantifiers::assertUniversal( Node n ){
index ba5a75d86b63dd3c03b3c28516185951e7851fa9..308514b92f55f313c8006d08510d2467e43eaf21 100644 (file)
@@ -63,7 +63,7 @@ public:
   void presolve();
   void ppNotifyAssertions( std::vector< Node >& assertions );
   void check(Effort e);
-  Node getNextDecisionRequest();
+  Node getNextDecisionRequest( unsigned& priority );
   Node getValue(TNode n);
   void collectModelInfo( TheoryModel* m, bool fullModel );
   void shutdown() { }
index 95b01bc7b03aef4f59145ce4e1a140d7cb5d7836..22bfa948f853d4ace92119c62daf04bd7dbc741d 100644 (file)
@@ -767,14 +767,17 @@ void QuantifiersEngine::propagate( Theory::Effort level ){
   }
 }
 
-Node QuantifiersEngine::getNextDecisionRequest(){
+Node QuantifiersEngine::getNextDecisionRequest( unsigned& priority ){
+  unsigned min_priority;
+  Node dec;  
   for( unsigned i=0; i<d_modules.size(); i++ ){
-    Node n = d_modules[i]->getNextDecisionRequest();
-    if( !n.isNull() ){
-      return n;
+    Node n = d_modules[i]->getNextDecisionRequest( priority );
+    if( !n.isNull() && ( dec.isNull() || priority<min_priority ) ){
+      dec = n;
+      min_priority = priority;
     }
   }
-  return Node::null();
+  return dec;
 }
 
 quantifiers::TermDbSygus* QuantifiersEngine::getTermDatabaseSygus() {
index ff6a8a36cede380e9916863b1740c41abb83477d..fc2b27e020acd03103d6ca6277ead9ee3e594a90 100644 (file)
@@ -294,7 +294,7 @@ public:
   /** propagate */
   void propagate( Theory::Effort level );
   /** get next decision request */
-  Node getNextDecisionRequest();
+  Node getNextDecisionRequest( unsigned& priority );
 private:
   /** reduceQuantifier, return true if reduced */
   bool reduceQuantifier( Node q );
index 426daf622277c477c7d22cdfd5a870481712e519..ea025e3a2a862197e47498d9795a790be640c0dd 100644 (file)
@@ -683,6 +683,7 @@ void TheorySep::check(Effort e) {
                 }else{
                   //this typically should not happen, should never happen for complete base theories
                   Trace("sep-process") << "*** repeated refinement lemma : " << lem << std::endl;
+                  Trace("sep-warn") << "TheorySep : WARNING : repeated refinement lemma : " << lem << "!!!" << std::endl;
                 }
               }
             }else{
@@ -700,6 +701,7 @@ void TheorySep::check(Effort e) {
       //must witness finite data points-to
       for( std::map< TypeNode, Node >::iterator it = d_base_label.begin(); it != d_base_label.end(); ++it ){
         TypeNode data_type = d_loc_to_data_type[it->first];
+        //if the data type is finite
         if( data_type.isInterpretedFinite() ){
           computeLabelModel( it->second );
           Trace("sep-process-debug") << "Check heap data for " << it->first << " -> " << data_type << std::endl;
@@ -708,18 +710,29 @@ void TheorySep::check(Effort e) {
             Node l = d_label_model[it->second].d_heap_locs_model[j][0];
             Trace("sep-process-debug") << "  location : " << l << std::endl;
             if( d_pto_model[l].isNull() ){
-              Node ll = d_tmodel[l];
-              Assert( !ll.isNull() );
-              Trace("sep-process") << "Must witness label : " << ll << ", data type is " << data_type << std::endl;
-              Node dsk = NodeManager::currentNM()->mkSkolem( "dsk", data_type, "pto-data for implicit location" );
-              // if location is in the heap, then something must point to it
-              Node lem = NodeManager::currentNM()->mkNode( kind::IMPLIES, NodeManager::currentNM()->mkNode( kind::MEMBER, ll, it->second ), 
-                                                                          NodeManager::currentNM()->mkNode( kind::SEP_STAR,
-                                                                            NodeManager::currentNM()->mkNode( kind::SEP_PTO, ll, dsk ),
-                                                                            d_true ) );
-              Trace("sep-lemma") << "Sep::Lemma : witness finite data-pto : " << lem << std::endl;
-              d_out->lemma( lem );        
-              addedLemma = true;                                           
+              needAddLemma = true;
+              Node ll;
+              std::map< Node, Node >::iterator itm = d_tmodel.find( l );
+              if( itm!=d_tmodel.end() ) {
+                ll = itm->second;
+              }else{
+                //try to assign arbitrary skolem?
+              }
+              if( !ll.isNull() ){
+                Trace("sep-process") << "Must witness label : " << ll << ", data type is " << data_type << std::endl;
+                Node dsk = NodeManager::currentNM()->mkSkolem( "dsk", data_type, "pto-data for implicit location" );
+                // if location is in the heap, then something must point to it
+                Node lem = NodeManager::currentNM()->mkNode( kind::IMPLIES, NodeManager::currentNM()->mkNode( kind::MEMBER, ll, it->second ), 
+                                                                            NodeManager::currentNM()->mkNode( kind::SEP_STAR,
+                                                                              NodeManager::currentNM()->mkNode( kind::SEP_PTO, ll, dsk ),
+                                                                              d_true ) );
+                Trace("sep-lemma") << "Sep::Lemma : witness finite data-pto : " << lem << std::endl;
+                d_out->lemma( lem );        
+                addedLemma = true;     
+              }else{
+                //This should only happen if we are in an unbounded fragment
+                Trace("sep-warn") << "TheorySep : WARNING : no term corresponding to location " << l << " in heap!!!" << std::endl;
+              }
             }else{
               Trace("sep-process-debug") << "  points-to data witness : " << d_pto_model[l] << std::endl;
             }
@@ -727,7 +740,6 @@ void TheorySep::check(Effort e) {
         }
       }
       if( !addedLemma && needAddLemma ){
-        Trace("sep-process") << "WARNING : could not find sep refinement lemma!!!" << std::endl;
         Assert( false );
         d_out->setIncomplete();
       }
@@ -741,7 +753,7 @@ bool TheorySep::needsCheckLastEffort() {
   return hasFacts();
 }
 
-Node TheorySep::getNextDecisionRequest() {
+Node TheorySep::getNextDecisionRequest( unsigned& priority ) {
   for( unsigned i=0; i<d_neg_guards.size(); i++ ){
     Node g = d_neg_guards[i];
     bool success = true;
@@ -754,6 +766,7 @@ Node TheorySep::getNextDecisionRequest() {
         Node cel = getQuantifiersEngine()->getTermDatabase()->getCounterexampleLiteral( q );
         bool value;
         if( d_valuation.hasSatValue( cel, value ) ){
+          Trace("sep-dec-debug") << "TheorySep::getNextDecisionRequest : dependent guard " << g << " depends on value for guard for quantified formula : " << value << std::endl;
           success = value;
         }else{
           Trace("sep-dec-debug") << "TheorySep::getNextDecisionRequest : wait to decide on " << g << " until " << cel << " is set " << std::endl;
@@ -765,6 +778,7 @@ Node TheorySep::getNextDecisionRequest() {
       bool value;
       if( !d_valuation.hasSatValue( g, value ) ) {
         Trace("sep-dec") << "TheorySep::getNextDecisionRequest : " << g << " (" << i << "/" << d_neg_guards.size() << ")" << std::endl;
+        priority = 0;
         return g;
       }
     }
index a3bb1bd7b5ea6a826b18011e4f262c052a764456..35b7fe5e9593bef079656dbdfc5889b471778ed5 100644 (file)
@@ -118,7 +118,7 @@ class TheorySep : public Theory {
   private:
   public:
 
-  Node getNextDecisionRequest();
+  Node getNextDecisionRequest( unsigned& priority );
 
   void presolve();
   void shutdown() { }
index 5a99f8e30dc234fdd59834d52cc04ae72e829f2d..ade5428cac211bc5a31448ee277439466d939ee5 100644 (file)
@@ -3802,7 +3802,7 @@ void TheoryStrings::printConcat( std::vector< Node >& n, const char * c ) {
 
 //// Finite Model Finding
 
-Node TheoryStrings::getNextDecisionRequest() {
+Node TheoryStrings::getNextDecisionRequest( unsigned& priority ) {
   if( options::stringFMF() && !d_conflict ){
     Node in_var_lsum = d_input_var_lsum.get();
     //Trace("strings-fmf-debug") << "Strings::FMF: Assertion Level = " << d_valuation.getAssertionLevel() << std::endl;
@@ -3852,6 +3852,7 @@ Node TheoryStrings::getNextDecisionRequest() {
         }
         Node lit = d_cardinality_lits[ decideCard ];
         Trace("strings-fmf") << "Strings::FMF: Decide positive on " << lit << std::endl;
+        priority = 1;
         return lit;
       }
     }
index 6665f9e50874eddb32c8b8bfd24953c71327fe13..457afb15a4557fe3efdb955aabe507060240d373 100644 (file)
@@ -502,7 +502,7 @@ private:
   context::CDO< int > d_curr_cardinality;
 public:
   //for finite model finding
-  Node getNextDecisionRequest();
+  Node getNextDecisionRequest( unsigned& priority );
   //ppRewrite
   Node ppRewrite(TNode atom);
 public:
index 28552ed79711bb4582e91d364c589a667fa56db5..ffcec7c0cd130fcdab2b4aa141a76430402fb37d 100644 (file)
@@ -604,8 +604,12 @@ public:
   /**
    * Return a decision request, if the theory has one, or the NULL node
    * otherwise.
+   * If returning non-null node, hould set priority to
+   *                        0 if decision is necessary for model-soundness,
+   *                        1 if decision is necessary for completeness,
+   *                        >1 otherwise.
    */
-  virtual Node getNextDecisionRequest() { return Node(); }
+  virtual Node getNextDecisionRequest( unsigned& priority ) { return Node(); }
 
   /**
    * Statically learn from assertion "in," which has been asserted
index c3e853ec05ffb3f2f3466f56d06ac5ed3cb8e820..9de8fa0ddfdc88a9196ac6c8a32bc12bab59edea 100644 (file)
@@ -739,21 +739,25 @@ void TheoryEngine::propagate(Theory::Effort effort) {
 
 Node TheoryEngine::getNextDecisionRequest() {
   // Definition of the statement that is to be run by every theory
+  unsigned min_priority;
+  Node dec;
 #ifdef CVC4_FOR_EACH_THEORY_STATEMENT
 #undef CVC4_FOR_EACH_THEORY_STATEMENT
 #endif
 #define CVC4_FOR_EACH_THEORY_STATEMENT(THEORY) \
   if (theory::TheoryTraits<THEORY>::hasGetNextDecisionRequest && d_logicInfo.isTheoryEnabled(THEORY)) { \
-    Node n = theoryOf(THEORY)->getNextDecisionRequest(); \
-    if(! n.isNull()) { \
-      return n; \
+    unsigned priority; \
+    Node n = theoryOf(THEORY)->getNextDecisionRequest( priority ); \
+    if(! n.isNull() && ( dec.isNull() || priority<min_priority ) ) { \
+      dec = n; \
+      min_priority = priority; \
     } \
   }
 
   // Request decision from each theory using the statement above
   CVC4_FOR_EACH_THEORY;
 
-  return TNode();
+  return dec;
 }
 
 bool TheoryEngine::properConflict(TNode conflict) const {
index ae935798e64c8695d5e15f732e895afccaeb93cd..4cdc5e240d06116bca35247754f7bef9435f0f4d 100644 (file)
@@ -205,9 +205,9 @@ void TheoryUF::propagate(Effort effort) {
   //}
 }
 
-Node TheoryUF::getNextDecisionRequest(){
+Node TheoryUF::getNextDecisionRequest( unsigned& priority ){
   if (d_thss != NULL && !d_conflict) {
-    return d_thss->getNextDecisionRequest();
+    return d_thss->getNextDecisionRequest( priority );
   }else{
     return Node::null();
   }
index 3a83dececaa0e7c688a90aa39f0922d29b8e5682..0900b4c90d90465138dcf11514f85d459827e616 100644 (file)
@@ -194,7 +194,7 @@ public:
   void computeCareGraph();
 
   void propagate(Effort effort);
-  Node getNextDecisionRequest();
+  Node getNextDecisionRequest( unsigned& priority );
 
   EqualityStatus getEqualityStatus(TNode a, TNode b);
 
index 4713c7dcfd599e15c89d62534e8a65234db322b6..edb92bb1b9d4cd425ac2c5cfc049be74316b9052 100644 (file)
@@ -1962,7 +1962,7 @@ void StrongSolverTheoryUF::propagate( Theory::Effort level ){
 }
 
 /** get next decision request */
-Node StrongSolverTheoryUF::getNextDecisionRequest(){
+Node StrongSolverTheoryUF::getNextDecisionRequest( unsigned& priority ){
   //request the combined cardinality as a decision literal, if not already asserted
   if( options::ufssFairness() ){
     int comCard = 0;
@@ -1972,6 +1972,7 @@ Node StrongSolverTheoryUF::getNextDecisionRequest(){
         com_lit = d_com_card_literal.find( comCard )!=d_com_card_literal.end() ? d_com_card_literal[comCard] : Node::null();
         if( !com_lit.isNull() && d_com_card_assertions.find( com_lit )==d_com_card_assertions.end() ){
           Trace("uf-ss-dec") << "Decide on combined cardinality : " << com_lit << std::endl;
+          priority = 1;
           return com_lit;
         }
         comCard++;
@@ -1984,6 +1985,7 @@ Node StrongSolverTheoryUF::getNextDecisionRequest(){
   for( std::map< TypeNode, SortModel* >::iterator it = d_rep_model.begin(); it != d_rep_model.end(); ++it ){
     Node n = it->second->getNextDecisionRequest();
     if( !n.isNull() ){
+      priority = 1;
       return n;
     }
   }
index 40026522dc687cbb9e401ebefc514202beeadfa1..4130a7d4145fc3cbefa8e44e1e06ef9999dd0fac 100644 (file)
@@ -399,7 +399,7 @@ public:
   /** propagate */
   void propagate( Theory::Effort level );
   /** get next decision request */
-  Node getNextDecisionRequest();
+  Node getNextDecisionRequest( unsigned& priority );
   /** preregister a term */
   void preRegisterTerm( TNode n );
   /** notify restart */
index 203352af3026d9c404211e2b0dc40a4bace16a06..2d35aef512615f5652a5092ec9a1767bf01c49db 100644 (file)
@@ -55,7 +55,8 @@ TESTS =       \
   dup-nemp.smt2 \
   emp2-quant-unsat.smt2 \
   dispose-1.smt2 \
-  finite-witness-sat.smt2
+  finite-witness-sat.smt2 \
+  sep-fmf-priority.smt2
 
 
 FAILING_TESTS =
diff --git a/test/regress/regress0/sep/sep-fmf-priority.smt2 b/test/regress/regress0/sep/sep-fmf-priority.smt2
new file mode 100644 (file)
index 0000000..fe3af1b
--- /dev/null
@@ -0,0 +1,12 @@
+; COMMAND-LINE: --finite-model-find --quant-epr --no-check-models
+; EXPECT: sat
+(set-logic ALL_SUPPORTED)
+
+(declare-sort Loc 0)
+(declare-const l Loc)
+(declare-const x Loc)
+
+(assert (wand (pto x x) false))
+(assert (forall ((x Loc) (y Loc)) (not (pto x y))))
+
+(check-sat)