void nlopt_fill_gradient(const double * x, double * grad, void * extra) {
    auto extra_info = static_cast<tuple<Enode *, box const &, bool> *>(extra);
    Enode * e = get<0>(*extra_info);
    box const & b = get<1>(*extra_info);
    bool const polarity = get<2>(*extra_info);
    unordered_map<Enode *, double> var_map;
    unsigned i = 0;
    vector<Enode*> forall_var_vec;
    for (Enode * e : b.get_vars()) {
        if (e->isForallVar()) {
            var_map.emplace(e, x[i]);
            i++;
            forall_var_vec.push_back(e);
        } else {
            var_map.emplace(e, b[e].mid());
        }
    }
    i = 0;
    for (Enode * var : forall_var_vec) {
        double deriv_i = deriv_enode(e->get1st(), var, var_map) - deriv_enode(e->get2nd(), var, var_map);
        if (e->isGt() || e->isGeq()) {
            deriv_i = - deriv_i;
        }
        if (!polarity) {
            deriv_i = - deriv_i;
        }
        grad[i] = deriv_i;
        i++;
    }
}
Beispiel #2
0
// ∀a, i, b, j.	( a = b → i = j → W (a, i, R(b, j)) = a )
void Egraph::WoRAxiom( Enode * wor )
{
  assert( false );
  Enode * a = wor->get1st( );
  Enode * i = wor->get2nd( );
  Enode * worElement = wor->get3rd( );
  Enode * b = worElement->get1st( );
  Enode * j = worElement->get2nd( );

  assert( worElement->isDTypeArrayElement( ) );
  assert( a->isDTypeArray( ) );
  assert( i->isDTypeArrayIndex( ) );
  assert( b->isDTypeArray( ) );
  assert( j->isDTypeArrayIndex( ) );

  // create term W(a,i,R(b,j))
  Enode * select = mkSelect( b, j );
  Enode * store = mkStore(a,i,select);

  // add clause IF a=b THEN IF i=j THEN W(a,i,R(b,j))=a
  // that is (NOT(a=b) OR NOT(i=j) OR W(a,i,R(b,j))=a)
  vector< Enode * > v;
  Enode * lit1 = mkNot(cons(mkEq(cons(a,cons(b)))));
  Enode * lit2 = mkNot(cons(mkEq(cons(i,cons(j)))));
  Enode * lit3 = mkEq(cons(store,cons(a)));

  v.push_back( lit1 );
  v.push_back( lit2 );
  v.push_back( lit3 );
#ifdef ARR_VERB
  cout << "Axiom WoR ->   " << "(or " << lit1 << " " << lit2 << " " << lit3 << " )" << endl;
#endif
  splitOnDemand( v, id );
  handleArrayAssertedAtomTerm( a );
}
double nlopt_eval_enode(const double* x, void * extra) {
    auto extra_info = static_cast<tuple<Enode *, box const &, bool> *>(extra);
    Enode * e = get<0>(*extra_info);
    box const & b = get<1>(*extra_info);
    bool const polarity = get<2>(*extra_info);
    unordered_map<Enode *, double> var_map;
    unsigned i = 0;
    for (Enode * e : b.get_vars()) {
        if (e->isForallVar()) {
            var_map.emplace(e, x[i]);
            i++;
        } else {
            var_map.emplace(e, b[e].mid());
        }
    }
    try {
        double const ret1 = eval_enode(e->get1st(), var_map);
        double const ret2 = eval_enode(e->get2nd(), var_map);
        double ret = 0;
        if (e->isLt() || e->isLeq() || e->isEq()) {
            ret = ret1 - ret2;
        } else if (e->isGt() || e->isGeq()) {
            ret = ret2 - ret1;
        } else if (e->isEq()) {
            throw runtime_error("nlopt_obj: something is wrong.");
        }
        if (!polarity) {
            ret = - ret;
        }
        return ret;
    } catch (exception & e) {
        DREAL_LOG_FATAL << "Exception in nlopt_eval_enode: " << e.what() << endl;
        throw e;
    }
}
Beispiel #4
0
void SimpSMTSolver::getDLVars( Enode * e, bool negate, Enode ** x, Enode ** y )
{
  assert( config.sat_preprocess_theory != 0 );
  assert( e->isLeq( ) );
  Enode * lhs = e->get1st( );
  Enode * rhs = e->get2nd( );
  (void)rhs;
  assert( lhs->isMinus( ) );
  assert( rhs->isConstant( ) || ( rhs->isUminus( ) && rhs->get1st( )->isConstant( ) ) );

  *x = lhs->get1st( );
  *y = lhs->get2nd( );

  if ( negate )
  {
    Enode *tmp = *x;
    *x = *y;
    *y = tmp;
  }
}
Beispiel #5
0
//∀a, i, e, j, f 		i != j → W (W (a, i, e), j, f ) = W (W (a, j, f ), i, e)
void Egraph::WoWNeqAxiom( Enode * wow )
{
  assert( false );
  Enode * wowArray = wow->get1st( );
  Enode * a = wowArray->get1st( );
  Enode * i = wowArray->get2nd( );
  Enode * e = wowArray->get3rd( );
  Enode * j = wow->get2nd( );
  Enode * f = wow->get3rd( );

  assert( wowArray->isDTypeArray( ) );
  assert( a->isDTypeArray( ) );
  assert( i->isDTypeArrayIndex( ) );
  assert( e->isDTypeArrayElement( ) );
  assert( j->isDTypeArrayIndex( ) );
  assert( f->isDTypeArrayElement( ) );

  // Case i, j not coincident
  if( i != j )
  {
    // create term W(W(a,j,f),i,e)
    Enode * store1 = mkStore(a,j,f);
    Enode * store2 = mkStore(store1,i,e);

    // add clause IF i!=j THEN W(W(a,i,e),j,f)=W(W(a,j,f),i,e)
    // that is (i=j OR W(W(a,i,e),j,f)=W(W(a,j,f),i,e))
    vector< Enode * > v;
    Enode * lit1 = mkEq(cons(i,cons(j)));
    Enode * lit2 = mkEq(cons(wow,cons(store2)));

    v.push_back( lit1 );
    v.push_back( lit2 );
#ifdef ARR_VERB
    cout << "Axiom WoW!= ->   " << "(or " << lit1 << " " << lit2 << " )" << endl;
#endif
    splitOnDemand( v, id );
    handleArrayAssertedAtomTerm(store2);
  }
}
Beispiel #6
0
bool CostSolver::assertLitImpl( Enode * e )
{
  assert( e );
  assert( belongsToT( e ) );
  assert( e->hasPolarity() );
  assert( e->getPolarity() != l_Undef );
#if DEBUG
  cout << "ct assert " << (e->getPolarity() == l_True ? "" : "!") << e << endl;
#endif

  assert( !conflict_ );

  Enode * atom = e;
  const bool negated = e->getPolarity() == l_False;

  if ( atom->isCostIncur() )
  {
    assert( nodemap_[ atom ] );
    costfun & fun = *nodemap_[ atom ];
#if DEBUG
    print_status( cout, fun );
#endif
    incurnode * node = incurmap_[ atom ];
    if ( node->prev )
    {
      node->prev->next = node->next;
      assert( node->prev->cost <= node->cost );
    }
    if ( node->next )
    {
      node->next->prev = node->prev;
      assert( node->cost <= node->next->cost );
    }
    else
    {
      fun.unassigned.last = node->prev;
    }
    if ( fun.unassigned.head == node )
    {
      fun.unassigned.head = node->next;
    }
    fun.slack -= node->cost;
    fun.assigned.push_back( node );
    if ( negated )
    {
      undo_ops_.push( undo_op( REMOVE_INCUR_NEG, node ) );
      if ( !fun.lowerbound.empty() &&
           get_bound( fun.lowerbound.top() ) > fun.incurred + fun.slack )
      {
        assert( explanation.empty() );
        conflict_ = atom;
        codomain potential = fun.incurred + fun.slack;
        for ( costfun::nodes_t::iterator it = fun.assigned.begin();
              it != fun.assigned.end();
              ++it )
        {
          incurnode * node = *it;
#if ELIM_REDUNDANT
          if ( node->atom->getPolarity() != l_False )
          {
            continue;
          }
          if ( potential + node->cost < get_bound( fun.lowerbound.top() ) )
          {
            potential += node->cost;
            continue;
          }
#endif
          if ( node->atom->getPolarity() == l_False )
          {
            explanation.push_back( node->atom );
          }
        }
        assert( potential < get_bound( fun.lowerbound.top() ) );
        assert( find( explanation.begin(), explanation.end(), conflict_ ) != explanation.end() );
        explanation.push_back( fun.lowerbound.top() );
#if DEBUG_CONFLICT
            cout << " " << explanation << " : " << fun.slack << endl;
            print_status( cout, fun ); cout << endl;
#endif
#if DEBUG
        cout << "conflict found " << conflict_ << endl;
        print_status( cout, fun );
#endif
#if DEBUG_CHECK_STATUS
        check_status();
#endif
        return false;
      }
    }
    else
    {
      fun.incurred += node->cost;
      undo_ops_.push( undo_op( REMOVE_INCUR_POS, node ) );
      if ( !fun.upperbound.empty() &&
           get_bound( fun.upperbound.top() ) <= fun.incurred )
      {
        conflict_ = atom;
        codomain incurred = fun.incurred;
        for ( costfun::nodes_t::iterator it = fun.assigned.begin();
              it != fun.assigned.end();
              ++it )
        {
          incurnode * node = *it;
#if ELIM_REDUNDANT
          if ( node->atom->getPolarity() != l_True )
          {
            continue;
          }
          if ( incurred - node->cost >= get_bound( fun.upperbound.top() ) )
          {
            incurred -= node->cost;
            continue;
          }
#endif
          if ( node->atom->getPolarity() == l_True )
          {
            explanation.push_back( node->atom );
          }
        }
        assert( incurred >= get_bound( fun.upperbound.top() ) );
        assert( find( explanation.begin(), explanation.end(), conflict_ ) != explanation.end() );
        explanation.push_back( fun.upperbound.top() );
#if DEBUG_CONFLICT
            cout << explanation << " : " << fun.slack << endl;
            print_status( cout, fun ); cout << endl;
#endif
#if DEBUG
        cout << "conflict found " << conflict_ << endl;
        print_status( cout, fun );
#endif
#if DEBUG_CHECK_STATUS
        check_status();
#endif
        return false;
      }
    }
  }
  else if ( atom->isCostBound() )
  {
#if DEBUG
    cout << "ct bound asserted " << atom << endl;
#endif
    assert( nodemap_.find( atom ) != nodemap_.end() );
    costfun & fun = *nodemap_[ atom ];
    Enode * args = atom->getCdr();
    Enode * val = args->getCdr()->getCar();
    assert( val->isConstant() );
#if DEBUG
    cout << atom->get2nd() << endl;
#endif
    const codomain & value = atom->get2nd()->getValue();
    if ( negated )
    {
#if DEBUG
      cout << "ct bound asserted negatively " << atom << endl;
#endif
      if ( ( !fun.lowerbound.empty() &&
             get_bound( fun.lowerbound.top() ) < value ) ||
           fun.lowerbound.empty() )
      {
#if DEBUG
        cout << "ct new lower bound " << atom << endl;
#endif
        fun.lowerbound.push( atom );
        undo_ops_.push( undo_op( REMOVE_LBOUND, &fun ) );
        if ( fun.incurred + fun.slack < get_bound( fun.lowerbound.top() ) )
        {
          conflict_ = atom;
          codomain potential = fun.incurred + fun.slack;
          for ( costfun::nodes_t::iterator it = fun.assigned.begin();
                it != fun.assigned.end();
                ++it )
          {
            incurnode * node = *it;
#if ELIM_REDUNDANT
            if ( node->atom->getPolarity() != l_False )
            {
              continue;
            }
            if ( potential + node->cost < get_bound( fun.lowerbound.top() ) )
            {
              potential += node->cost;
              continue;
            }
#endif
            if ( node->atom->getPolarity() == l_False )
            {
              explanation.push_back( node->atom );
            }
          }
          assert( find( explanation.begin(), explanation.end(), conflict_ ) == explanation.end() );
          explanation.push_back( conflict_ );
          assert( potential < get_bound( fun.lowerbound.top() ) );
          assert( find( explanation.begin(), explanation.end(), conflict_ ) != explanation.end() );
#if DEBUG_CONFLICT
            cout << explanation << " : " << fun.slack << endl;
            print_status( cout, fun ); cout << endl;
#endif
#if DEBUG
          cout << "conflict found " << conflict_ << endl;
          print_status( cout, fun );
#endif
#if DEBUG_CHECK_STATUS
          check_status();
#endif
          return false;
        }
      }
    }
    else
    {
#if DEBUG
      cout << "ct bound asserted positively " << atom << endl;
#endif
      if ( ( !fun.upperbound.empty() &&
             get_bound( fun.upperbound.top() ) > value ) ||
           fun.upperbound.empty() )
      {
#if DEBUG
        cout << "ct new upper bound " << atom << endl;
#endif
        fun.upperbound.push( atom );
        undo_ops_.push( undo_op( REMOVE_UBOUND, &fun ) );
        if ( fun.incurred >= get_bound( fun.upperbound.top() ) )
        {
          conflict_ = atom;
          codomain incurred = fun.incurred;
          for ( costfun::nodes_t::iterator it = fun.assigned.begin();
                it != fun.assigned.end();
                ++it )
          {
            incurnode * node = *it;
#if ELIM_REDUNDANT
            if ( node->atom->getPolarity() != l_True )
            {
              continue;
            }
            if ( incurred - node->cost >= get_bound( fun.upperbound.top() ) )
            {
              incurred -= node->cost;
              continue;
            }
#endif
            if ( node->atom->getPolarity() == l_True )
            {
              explanation.push_back( node->atom );
            }
          }
          assert( find( explanation.begin(), explanation.end(), conflict_ ) == explanation.end() );
          assert( incurred >= get_bound( fun.upperbound.top() ) );
          explanation.push_back( conflict_ );
          assert( find( explanation.begin(), explanation.end(), conflict_ ) != explanation.end() );
#if DEBUG_CONFLICT
            cout << " " << explanation << " : " << fun.slack << endl;
            print_status( cout, fun ); cout << endl;
#endif
#if DEBUG
          cout << "conflict found " << conflict_ << endl;
          print_status( cout, fun );
#endif
#if DEBUG_CHECK_STATUS
          check_status();
#endif
          return false;
        }
      }
    }
    if ( !fun.lowerbound.empty() && !fun.upperbound.empty() &&
         get_bound( fun.lowerbound.top() ) >= get_bound( fun.upperbound.top() ) )
    {
      conflict_ = atom;
      explanation.push_back( fun.lowerbound.top() );
      explanation.push_back( fun.upperbound.top() );
#if DEBUG_CONFLICT
            cout << " " << explanation << " : " << fun.slack << endl;
            print_status( cout, fun ); cout << endl;
#endif
#if DEBUG
      cout << "conflict found " << conflict_ << endl;
      print_status( cout, fun );
#endif
#if DEBUG_CHECK_STATUS
      check_status();
#endif
      return false;
    }
  }
  else
  {
#if DEBUG
    cout << "ct unrecognized " << atom << endl;
#endif
  }

#if 1
  {
    // Deduction
    costfun & fun = *nodemap_[ atom ];
    if ( !fun.upperbound.empty() &&
         fun.lowerbound.empty() &&
         fun.unassigned.last &&
         get_bound( fun.upperbound.top() ) <= fun.unassigned.last->cost + fun.incurred  &&
         !fun.unassigned.last->atom->isDeduced() )
    {
#if DEBUG
      cout << "deducing !" << fun.unassigned.last->atom << endl;
#endif
      fun.unassigned.last->atom->setDeduced( l_False, id );
      deductions.push_back( fun.unassigned.last->atom );
    }
    else if ( !fun.lowerbound.empty() &&
         fun.upperbound.empty() &&
         fun.unassigned.last &&
         get_bound( fun.lowerbound.top() ) > fun.incurred + fun.slack - fun.unassigned.last->cost &&
         !fun.unassigned.last->atom->isDeduced() )
    {
#if DEBUG
      cout << "deducing " << fun.unassigned.last->atom << endl;
#endif
      fun.unassigned.last->atom->setDeduced( l_True, id );
      deductions.push_back( fun.unassigned.last->atom );
    }
    else if ( !fun.upperbound.empty() &&
              !fun.lowerbound.empty() &&
              fun.unassigned.last &&
              get_bound( fun.lowerbound.top() ) +1 == get_bound( fun.upperbound.top() ) )
    {
      if ( fun.unassigned.last->cost == fun.slack &&
           fun.incurred + fun.unassigned.last->cost ==
           get_bound( fun.lowerbound.top() ) &&
           fun.incurred + fun.slack - fun.unassigned.last->cost <
           get_bound( fun.lowerbound.top() ) )
      {
#if DEBUG
      cout << "deducing " << fun.unassigned.last->atom << endl;
      print_status( cout, fun );
#endif
        fun.unassigned.last->atom->setDeduced( l_True, 0 );
        deductions.push_back( fun.unassigned.last->atom );
      }
    }
  }
#endif

#if DEBUG_CHECK_STATUS
  check_status();
#endif
  return true;
}
Beispiel #7
0
// ∀a, i, e, j, f. ( i = j → W ( W ( a, i, e ), j, f ) = W ( a, j, f ) )
void Egraph::WoWEqAxiom( Enode * wow )
{
  assert( false );
  Enode * wowArray = wow->get1st( );
  Enode * a = wowArray->get1st( );
  Enode * i = wowArray->get2nd( );
  Enode * e = wowArray->get3rd( );
  Enode * j = wow->get2nd( );
  Enode * f = wow->get3rd( );

  assert( wowArray->isDTypeArray( ) );
  assert( a->isDTypeArray( ) );
  assert( i->isDTypeArrayIndex( ) );
  assert( e->isDTypeArrayElement( ) );
  assert( j->isDTypeArrayIndex( ) );
  assert( f->isDTypeArrayElement( ) );

  //i,j not coincident
  if( i != j )
  {
    // create term W(a,j,f)
    Enode * store = mkStore( a, j, f );
#ifdef PRODUCE_PROOF
    if ( config.gconfig.print_inter > 0 )
    {
      const uint64_t shared = getIPartitions( a ) 
	                    & getIPartitions( j )
			    & getIPartitions( f );
      // Mixed can't be one at this point
      assert( shared != 1 );
      // Set AB-mixed partition if no intersection
      if ( shared == 0 )
	setIPartitions( store, 1 );
      // Otherwise they share something
      else
	setIPartitions( store, shared );
    }
#endif
    // add clause IF i=j THEN W(W(a,i,e),j,f)=W(a,j,f)
    // that is (NOT(i=j) OR W(W(a,i,e),j,f)=W(a,j,f))
    vector< Enode * > v;
    Enode * lit1_pos = mkEq( cons( i, cons( j ) ) );
    Enode * lit1 = mkNot( cons( lit1_pos ) );
#ifdef PRODUCE_PROOF
    if ( config.gconfig.print_inter > 0 )
    {
      const uint64_t shared = getIPartitions( i ) 
	                    & getIPartitions( j );
      // Mixed can't be one at this point
      assert( shared != 1 );
      // Set AB-mixed partition if no intersection
      if ( shared == 0 )
      {
	setIPartitions( lit1_pos, 1 );
	setIPartitions( lit1, 1 );
      }
      // Otherwise they share something
      else
      {
	setIPartitions( lit1_pos, shared );
	setIPartitions( lit1, shared );
      }
    }
#endif
    Enode * lit2 = mkEq( cons( wow, cons( store ) ) );
#ifdef PRODUCE_PROOF
    if ( config.gconfig.print_inter > 0 )
    {
      const uint64_t shared = getIPartitions( wow ) 
	                    & getIPartitions( store );
      // Mixed can't be one at this point
      assert( shared != 1 );
      // Set AB-mixed partition if no intersection
      if ( shared == 0 )
	setIPartitions( lit2, 1 );
      // Otherwise they share something
      else
	setIPartitions( lit2, shared );
    }
#endif
    v.push_back( lit1 );
    v.push_back( lit2 );
#ifdef ARR_VERB
    cout << "Axiom WoW= ->   " << "(or " << lit1 << " " << lit2 << " )" << endl;
#endif
    splitOnDemand( v, id );
    handleArrayAssertedAtomTerm( store );
  }
}
Beispiel #8
0
void Egraph::handleArrayMerge( Enode * x, Enode * y )
{
  assert( ( x->isDTypeArray( ) && y->isDTypeArray( ) )
       || ( x->isDTypeArrayElement( ) && y->isDTypeArrayElement( ) ) );

  vector< Enode * > xSelUsers, xStoUsers;
  getUsers( x, xSelUsers, xStoUsers );
  vector<Enode * >::iterator xSelUsersIt;
  vector<Enode * >::iterator xStoUsersIt;

  vector< Enode * > ySelUsers, yStoUsers;
  getUsers( y, ySelUsers, yStoUsers );
  vector<Enode * >::iterator ySelUsersIt;
  vector<Enode * >::iterator yStoUsersIt;

#ifdef ARR_VERB_POSTMERGE
  cout << endl << "Getting x and y equivalence class users: " << endl;
  cout << "Equivalence class of x is: " << endl;
  Enode * aux=x;
  do { cout << aux << "   "; aux=aux->getNext(); } while(aux!=x);
  cout << endl << "Here are x class select users: " << endl;
  for ( xSelUsersIt = xSelUsers.begin( ); xSelUsersIt != xSelUsers.end( ); xSelUsersIt++ ) {cout << *xSelUsersIt << "   ";}
  cout << endl << "Here are x class store users: " << endl;
  for ( xStoUsersIt = xStoUsers.begin( ); xStoUsersIt != xStoUsers.end( ); xStoUsersIt++ ) {cout << *xStoUsersIt << "   ";}
  cout << endl << "Equivalence class of y is: " << endl;
  aux=y;
  do { cout << aux << "   "; aux=aux->getNext(); } while(aux!=y);
  cout <<  endl << "Here are y class select users: " << endl;
  for ( ySelUsersIt = ySelUsers.begin( ); ySelUsersIt != ySelUsers.end( ); ySelUsersIt++ ) {cout << *ySelUsersIt << "   ";}
  cout <<  endl << "Here are y class store users: " << endl;
  for ( yStoUsersIt = yStoUsers.begin( ); yStoUsersIt != yStoUsers.end( ); yStoUsersIt++ ) {cout << *yStoUsersIt << "   ";}
  cout << endl << endl;
#endif

  Enode * z, * zIndex;
  // , * zElement, * zArray,

  // TODO join all the cases together for more efficiency

  // NB x,y are elements of equivalence classes X,Y, we need to scan X or Y looking for store terms
  if( y->isDTypeArray() )
  {
    // Case 1: x is b, y is W(a,i,e), exists z as R(b,j)
    // Scan all R(b,j)
    for ( xSelUsersIt = xSelUsers.begin( )
	; xSelUsersIt != xSelUsers.end( )
	; xSelUsersIt++ )
    {
      z = * xSelUsersIt;
      zIndex = z->get2nd( );

      // scan Y looking for store terms
      Enode * YElem = y;
      do
      {
	if( YElem->isStore( ) )
	{
#ifdef ARR_VERB
	  cout << "Arrow down   B: " << x << "   W(A,I,E): " << YElem << "   R(B,J): " << z << endl;
#endif
	  // create new term R(W(a,i,e),j)
	  Enode * s_yelem = dynamicToStatic( YElem );
	  Enode * s_z2nd  = dynamicToStatic( z->get2nd( ) );
	  Enode * select = mkSelect( s_yelem, s_z2nd );
#ifdef PRODUCE_PROOF
	  if ( config.gconfig.print_inter > 0 )
	  {
	    const uint64_t shared = getIPartitions( s_yelem ) 
	                          & getIPartitions( s_z2nd );
	    // Mixed can't be one at this point
	    assert( shared != 1 );
	    // Set AB-mixed partition if no intersection
	    if ( shared == 0 )
	      setIPartitions( select, 1 );
	    // Otherwise they share something
	    else
	      setIPartitions( select, shared );
	  }
#endif
	  handleArrayAssertedAtomTerm( select );
	}

	YElem = YElem->getNext( );
      }
      while ( YElem != y );
    }
    /*// Case 2: x is b, y is W(a,i,e), exists z as W(b,j,f)
    // Scan all W(b,j,f)
    for (xStoUsersIt=xStoUsers.begin(); xStoUsersIt<xStoUsers.end(); xStoUsersIt++)
    {
    z=*xStoUsersIt;
    zElement=z->get3rd();
    zIndex=z->get2nd();

    // create new term W(W(a,i,e),j,f)
    newSto=mkStore(y,zIndex,zElement,present);

    // TODO check if term already seen in a previous assertion on the current path
    // deduce clauses for the new store
    newArrayDed(newSto);
    }*/
  }

  if( x->isDTypeArray() )
  {
    // Case 1 reverse: y is b, x is W(a,i,e), exists z as R(b,j)
    // Scan all R(b,j)
    for ( ySelUsersIt = ySelUsers.begin( )
	; ySelUsersIt != ySelUsers.end( )
	; ySelUsersIt++ )
    {
      z = *ySelUsersIt;
      zIndex = z->get2nd( );

      // scan X looking for store terms
      Enode * XElem = x;
      do
      {
	if( XElem->isStore( ) )
	{

#ifdef ARR_VERB
	  cout << "Arrow down   B: " << XElem << "   W(A,I,E): " << y << "   R(B,J): " << z << endl;
#endif

	  // Create new term R(W(a,i,e),j) from static version
	  Enode * s_xelem = dynamicToStatic( XElem );
	  Enode * s_z2nd = dynamicToStatic( z->get2nd( ) );
	  Enode * select = mkSelect( s_xelem, s_z2nd );
#ifdef PRODUCE_PROOF
	  if ( config.gconfig.print_inter > 0 )
	  {
	    const uint64_t shared = getIPartitions( s_xelem ) 
	                          & getIPartitions( s_z2nd );
	    // Mixed can't be one at this point
	    assert( shared != 1 );
	    // Set AB-mixed partition if no intersection
	    if ( shared == 0 )
	      setIPartitions( select, 1 );
	    // Otherwise they share something
	    else
	      setIPartitions( select, shared );
	  }
#endif
	  handleArrayAssertedAtomTerm( select );
	}

	XElem = XElem->getNext( );
      }
      while ( XElem != x );
    }
    /*// Case 2 reverse: y is a term b of type array, x is a Store W(a,i,e), exists z as W(b,j,f)
    // Scan all W(b,j,f)
    for (yStoUsersIt=yStoUsers.begin(); yStoUsersIt<yStoUsers.end(); yStoUsersIt++)
    {
    z=*yStoUsersIt;
    zElement=z->get3rd();
    zIndex=z->get2nd();

    // create new term W(W(a,i,e),j,f)
    newSto=mkStore(y,zIndex,zElement,present);

    // TODO check if term already seen in a previous assertion on the current path
    // deduce clauses for the new store
    newArrayDed(newSto);
    }*/
  }

  Enode * w;
  if( x->isDTypeArray( ) 
   && y->isDTypeArray( ) )
  {
    //Case 3: x is a term a of type array, y is a term b of type array, exist z as W(a,i,e) and w as R(b,j)
    //scan all W(a,i,e) and R(b,j)
    for ( ySelUsersIt = ySelUsers.begin( )
	; ySelUsersIt < ySelUsers.end( )
	; ySelUsersIt++ )
    {
      for ( xStoUsersIt = xStoUsers.begin( )
	  ; xStoUsersIt < xStoUsers.end( )
	  ; xStoUsersIt++ )
      {
	w = *ySelUsersIt; 
	z = *xStoUsersIt;

#ifdef ARR_VERB
	cout << "Arrow up   A: " << x << "   B: " << y << "   W(A,I,E): " << z << "   R(B,J): " << w << endl;
#endif

	// create new term R(W(a,i,e),j)
	Enode * s_z    = dynamicToStatic( z );
	Enode * s_w2nd = dynamicToStatic( w->get2nd( ) );
	Enode * select = mkSelect( s_z, s_w2nd );
#ifdef PRODUCE_PROOF
	if ( config.gconfig.print_inter > 0 )
	{
	  const uint64_t shared = getIPartitions( s_z ) 
	                        & getIPartitions( s_w2nd );
	  // Mixed can't be one at this point
	  assert( shared != 1 );
	  // Set AB-mixed partition if no intersection
	  if ( shared == 0 )
	    setIPartitions( select, 1 );
	  // Otherwise they share something
	  else
	    setIPartitions( select, shared );
	}
#endif
	handleArrayAssertedAtomTerm( select );
      }
    }
    //Case 3 reverse: y is a term a of type array, x is a term b of type array, exist z as W(a,i,e) and w as R(b,j)
    //scan all W(a,i,e) and R(b,j)
    for ( xSelUsersIt = xSelUsers.begin( )
	; xSelUsersIt < xSelUsers.end( )
	; xSelUsersIt++ )
    {
      for ( yStoUsersIt = yStoUsers.begin( )
	  ; yStoUsersIt < yStoUsers.end( )
	  ; yStoUsersIt++)
      {
	w = *xSelUsersIt; 
	z = *yStoUsersIt;
#ifdef ARR_VERB
	cout << "Arrow up   A: " << x << "   B: " << y << "   W(A,I,E): "<< z << "   R(B,J): " << w << endl;
#endif

	// create new term R(W(a,i,e),j)
	Enode * s_z    = dynamicToStatic( z );
	Enode * s_w2nd = dynamicToStatic( w->get2nd( ) );
	Enode * select = mkSelect( s_z, s_w2nd );
#ifdef PRODUCE_PROOF
	if ( config.gconfig.print_inter > 0 )
	{
	  const uint64_t shared = getIPartitions( s_z ) 
	                        & getIPartitions( s_w2nd );
	  // Mixed can't be one at this point
	  assert( shared != 1 );
	  // Set AB-mixed partition if no intersection
	  if ( shared == 0 )
	    setIPartitions( select, 1 );
	  // Otherwise they share something
	  else
	    setIPartitions( select, shared );
	}
#endif
	handleArrayAssertedAtomTerm( select );
      }
    }
  }

  /*//Case 4: x is a term e of type element, y is a Select R(b,j), exists z as W(a,i,e)
  //scan all W(a,i,e)
  if(y->isSelect())
  {
  for (xStoUsersIt=xStoUsers.begin(); xStoUsersIt<xStoUsers.end(); xStoUsersIt++)
  {
  z=*xStoUsersIt;
  zArray=z->get1st();
  zIndex=z->get2nd();
  // create new term W(a,i,R(b,j))
  newSto=mkStore(zArray,zIndex,y);

  // TODO check if term already seen in a previous assertion on the current path
  // deduce clauses for the new store
  newArrayDed(newSto);
  }
  }
  //Case 4 reverse: y is a term e of type element, x is a Select R(b,j), exists z as W(a,i,e)
  //scan all W(a,i,e)
  if(x->isSelect())
  {
  for (yStoUsersIt=yStoUsers.begin(); yStoUsersIt<yStoUsers.end(); yStoUsersIt++)
  {
  z=*yStoUsersIt;
  zArray=z->get1st();
  zIndex=z->get2nd();
  // create new term W(a,i,R(b,j))
  newSto=mkStore(zArray,zIndex,x);

  // TODO check if term already seen in a previous assertion on the current path
  // deduce clauses for the new store
  newArrayDed(newSto);
  }
  }*/
}
Beispiel #9
0
Enode *
ExpandITEs::doit( Enode * formula )
{
  assert( formula );
  list< Enode * > new_clauses;
  vector< Enode * > unprocessed_enodes;
  egraph.initDupMap1( );

  unprocessed_enodes.push_back( formula );
  //
  // Visit the DAG of the formula from the leaves to the root
  //
  while( !unprocessed_enodes.empty( ) )
  {
    Enode * enode = unprocessed_enodes.back( );
    //
    // Skip if the node has already been processed before
    //
    if ( egraph.valDupMap1( enode ) != NULL )
    {
      unprocessed_enodes.pop_back( );
      continue;
    }

    bool unprocessed_children = false;
    Enode * arg_list;
    for ( arg_list = enode->getCdr( ) ;
          arg_list != egraph.enil ;
          arg_list = arg_list->getCdr( ) )
    {
      Enode * arg = arg_list->getCar( );

      assert( arg->isTerm( ) );
      //
      // Push only if it is unprocessed
      //
      if ( egraph.valDupMap1( arg ) == NULL )
      {
        unprocessed_enodes.push_back( arg );
        unprocessed_children = true;
      }
    }
    //
    // SKip if unprocessed_children
    //
    if ( unprocessed_children )
      continue;

    unprocessed_enodes.pop_back( );
    Enode * result = NULL;
    //
    // At this point, every child has been processed
    //
    char def_name[ 32 ];

    if ( enode->isIte( ) )
    {
      //
      // Retrieve arguments
      //
      Enode * i = egraph.valDupMap1( enode->get1st( ) );
      Enode * t = egraph.valDupMap1( enode->get2nd( ) );
      Enode * e = egraph.valDupMap1( enode->get3rd( ) );
      Enode * not_i = egraph.mkNot( egraph.cons( i ) );
      //
      // Generate variable symbol
      //
      sprintf( def_name, ITE_STR, enode->getId( ) );
      Snode * sort = enode->getLastSort( );
      egraph.newSymbol( def_name, sort );
      //
      // Generate placeholder
      //
      result = egraph.mkVar( def_name );
      //
      // Generate additional clauses
      //
      Enode * eq_then = egraph.mkEq( egraph.cons( result
                                   , egraph.cons( t ) ) );
      Enode * eq_else = egraph.mkEq( egraph.cons( result
                                   , egraph.cons( e ) ) );
      new_clauses.push_back( egraph.mkOr( egraph.cons( not_i
                                        , egraph.cons( eq_then ) ) ) );
      new_clauses.push_back( egraph.mkOr( egraph.cons( i
                                        , egraph.cons( eq_else ) ) ) );
    }
    else
    {
      result = egraph.copyEnodeEtypeTermWithCache( enode );
    }

    assert( result );
    assert( egraph.valDupMap1( enode ) == NULL );
    egraph.storeDupMap1( enode, result );
  }

  Enode * new_formula = egraph.valDupMap1( formula );
  assert( new_formula );
  egraph.doneDupMap1( );

  new_clauses.push_back( new_formula );

  return egraph.mkAnd( egraph.cons( new_clauses ) );
}
Beispiel #10
0
Enode * Egraph::canonizeDTC( Enode * formula, bool split_eqs )
{
  assert( config.sat_lazy_dtc != 0 );
  assert( config.logic == QF_UFLRA
       || config.logic == QF_UFIDL );

  list< Enode * > dtc_axioms;
  vector< Enode * > unprocessed_enodes;
  initDupMap1( );

  unprocessed_enodes.push_back( formula );
  //
  // Visit the DAG of the formula from the leaves to the root
  //
  while( !unprocessed_enodes.empty( ) )
  {
    Enode * enode = unprocessed_enodes.back( );
    //
    // Skip if the node has already been processed before
    //
    if ( valDupMap1( enode ) != NULL )
    {
      unprocessed_enodes.pop_back( );
      continue;
    }

    bool unprocessed_children = false;
    Enode * arg_list;
    for ( arg_list = enode->getCdr( )
        ; arg_list != enil
        ; arg_list = arg_list->getCdr( ) )
    {
      Enode * arg = arg_list->getCar( );
      assert( arg->isTerm( ) );
      //
      // Push only if it is unprocessed
      //
      if ( valDupMap1( arg ) == NULL )
      {
        unprocessed_enodes.push_back( arg );
        unprocessed_children = true;
      }
    }
    //
    // SKip if unprocessed_children
    //
    if ( unprocessed_children )
      continue;

    unprocessed_enodes.pop_back( );
    Enode * result = NULL;
    //
    // Replace arithmetic atoms with canonized version
    //
    if (  enode->isTAtom( )
      && !enode->isUp( ) )
    {
      // No need to do anything if node is purely UF
      if ( isRootUF( enode ) )
      {
        if ( config.verbosity > 2 )
          cerr << "# Egraph::Skipping canonization of " << enode << " as it's root is purely UF" << endl;
        result = enode;
      }
      else
      {
        LAExpression a( enode );
        result = a.toEnode( *this );
#ifdef PRODUCE_PROOF
        const uint64_t partitions = getIPartitions( enode );
        assert( partitions != 0 );
        setIPartitions( result, partitions );
#endif

        if ( split_eqs && result->isEq( ) )
        {
#ifdef PRODUCE_PROOF
          if ( config.produce_inter > 0 )
            opensmt_error2( "can't compute interpolant for equalities at the moment ", enode );
#endif
          LAExpression aa( enode );
          Enode * e = aa.toEnode( *this );
#ifdef PRODUCE_PROOF
          assert( partitions != 0 );
          setIPartitions( e, partitions );
#endif
          Enode * lhs = e->get1st( );
          Enode * rhs = e->get2nd( );
          Enode * leq = mkLeq( cons( lhs, cons( rhs ) ) );
          LAExpression b( leq );
          leq = b.toEnode( *this );
#ifdef PRODUCE_PROOF
          assert( partitions != 0 );
          setIPartitions( leq, partitions );
#endif
          Enode * geq = mkGeq( cons( lhs, cons( rhs ) ) );
          LAExpression c( geq );
          geq = c.toEnode( *this );
#ifdef PRODUCE_PROOF
          assert( partitions != 0 );
          setIPartitions( geq, partitions );
#endif
          Enode * not_e = mkNot( cons( enode ) );
          Enode * not_l = mkNot( cons( leq ) );
          Enode * not_g = mkNot( cons( geq ) );
          // Add clause ( !x=y v x<=y )
          Enode * c1 = mkOr( cons( not_e
                           , cons( leq ) ) );
          // Add clause ( !x=y v x>=y )
          Enode * c2 = mkOr( cons( not_e
                           , cons( geq ) ) );
          // Add clause ( x=y v !x>=y v !x<=y )
          Enode * c3 = mkOr( cons( enode
                           , cons( not_l
                           , cons( not_g ) ) ) );
          // Add conjunction of clauses
          Enode * ax = mkAnd( cons( c1
                            , cons( c2
                            , cons( c3 ) ) ) );

          dtc_axioms.push_back( ax );
          result = enode;
        }
      }
    }
    //
    // If nothing have been done copy and simplify
    //
    if ( result == NULL )
      result = copyEnodeEtypeTermWithCache( enode );

    assert( valDupMap1( enode ) == NULL );
    storeDupMap1( enode, result );
#ifdef PRODUCE_PROOF
    if ( config.produce_inter > 0 )
    {
      // Setting partitions for result
      setIPartitions( result, getIPartitions( enode ) );
      // Setting partitions for negation as well occ if atom
      if ( result->hasSortBool( ) )
      {
        setIPartitions( mkNot( cons( result ) )
                      , getIPartitions( enode ) );
      }
    }
#endif
  }

  Enode * new_formula = valDupMap1( formula );
  assert( new_formula );
  doneDupMap1( );

  if ( !dtc_axioms.empty( ) )
  {
    dtc_axioms.push_back( new_formula );
    new_formula = mkAnd( cons( dtc_axioms ) );
  }

  return new_formula;
}