Example #1
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 );
}
Example #2
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 );
  }
}
Example #3
0
//
// Sort a term if it commutes.
// The following simplifications implemented
// (should be refactored to separate methods?):
//  - `and':
//    - drop constant true terms
//    - convert an empty `and' to the constant term `true'
//    - convert an `and' containing `false' to a replicate `false'
//  - `or':
//    - drop constant false terms
//    - convert an empty `or' to a replicate `false' term
//    - convert an `or' containing `true' to a replicate `true'
//
//
void Logic::simplify(SymRef& s, vec<PTRef>& args) {
    // First sort it
#ifdef SORT_BOOLEANS
    if (sym_store[s].commutes())
#else
    if (sym_store[s].commutes() && !isAnd(s) && !isOr(s))
#endif
        sort(args, LessThan_PTRef());

    if (!isBooleanOperator(s) && !isEquality(s)) return;

    int dropped_args = 0;
    bool replace = false;
    if (s == getSym_and()) {
        int i, j;
        PTRef p = PTRef_Undef;
        for (i = j = 0; i < args.size(); i++) {
            if (args[i] == getTerm_false()) {
                args.clear();
                s = getSym_false();
#ifdef SIMPLIFY_DEBUG
                cerr << "and  -> false" << endl;
#endif
                return;
            } else if (args[i] != getTerm_true() && args[i] != p) {
                args[j++] = p = args[i];
            } else {
#ifdef SIMPLIFY_DEBUG
                cerr << "and -> drop" << endl;
#endif
            }
        }
        dropped_args = i-j;
        if (dropped_args == args.size()) {
            s = getSym_true();
            args.clear();
#ifdef SIMPLIFY_DEBUG
            cerr << "and -> true" << endl;
#endif
            return;
        } else if (dropped_args == args.size() - 1)
            replace = true;
        else if (dropped_args > 0)
            args.shrink(dropped_args);
    }
    if (s == getSym_or()) {
        int i, j;
        PTRef p = PTRef_Undef;
        for (i = j = 0; i < args.size(); i++) {
            if (args[i] == getTerm_true()) {
                args.clear();
                s = getSym_true();
#ifdef SIMPLIFY_DEBUG
                cerr << "or -> true" << endl;
#endif
                return;
            } else if (args[i] != getTerm_false() && args[i] != p) {
                args[j++] = p = args[i];
            } else {
#ifdef SIMPLIFY_DEBUG
                cerr << "or -> drop" << endl;
#endif
            }
        }
        dropped_args = i-j;
        if (dropped_args == args.size()) {
            s = getSym_false();
            args.clear();
#ifdef SIMPLIFY_DEBUG
            cerr << "or -> false" << endl;
#endif
            return;
        }
        else if (dropped_args == args.size() - 1)
            replace = true;
        else if (dropped_args > 0)
            args.shrink(dropped_args);
    }
    if (isEquality(s)) {
        assert(args.size() == 2);
        if (isBooleanOperator(s) && (args[0] == getTerm_true())) {
            Pterm& t = getPterm(args[1]);
            s = t.symb();
            args.clear();
            for (int i = 0; i < t.size(); i++)
                args.push(t[i]);
#ifdef SIMPLIFY_DEBUG
            cerr << "eq -> second" << endl;
#endif
            return;
        } else if (isBooleanOperator(s) && (args[0] == getTerm_false())) {
            PTRef old = args[1];
            PTRef tr = mkNot(args[1]);
            Pterm& t = getPterm(tr);
            s = t.symb();
            args.clear();
            args.push(old);
#ifdef SIMPLIFY_DEBUG
            cerr << "eq -> not second" << endl;
#endif
            return;
        } else if (isBooleanOperator(s) && (args[1] == getTerm_true())) {
            args.clear();
            Pterm& t = getPterm(args[0]);
            s = t.symb();
            args.clear();
            for (int i = 0; i < t.size(); i++)
                args.push(t[i]);
#ifdef SIMPLIFY_DEBUG
            cerr << "eq -> first" << endl;
#endif
            return;
        } else if (isBooleanOperator(s) && (args[1] == getTerm_false())) {
            PTRef old = args[0];
            PTRef tr = mkNot(args[0]);
            Pterm& t = getPterm(tr);
            s = t.symb();
            args.clear();
            args.push(old);
#ifdef SIMPLIFY_DEBUG
            cerr << "eq -> not first"<< endl;
#endif
            return;
        } else if (args[0] == args[1]) {
            args.clear();
            s = getSym_true();
#ifdef SIMPLIFY_DEBUG
            cerr << "eq -> true" << endl;
#endif
            return;
        } else if (isBooleanOperator(s) && (args[0] == mkNot(args[1]))) {
            args.clear();
            s = getSym_false();
#ifdef SIMPLIFY_DEBUG
            cerr << "eq -> false" << endl;
#endif
            return;
        }
    }
    if (isNot(s)) {
        if (isTrue(args[0])) {
            args.clear();
            s = getSym_false();
#ifdef SIMPLIFY_DEBUG
            cerr << "not -> false" << endl;
#endif
            return;
        }
        if (isFalse(args[0])) {
            args.clear();
            s = getSym_true();
#ifdef SIMPLIFY_DEBUG
            cerr << "not -> true" << endl;
#endif
            return;
        }
    }
    // Others, to be implemented:
    // - distinct
    // - implies
    // - xor
    // - ite
    if (replace) {
        // Return whatever is the sole argument
        Pterm& t = getPterm(args[0]);
        s = t.symb();
        args.clear();
        for (int i = 0; i < t.size(); i++)
            args.push(t[i]);
#ifdef SIMPLIFY_DEBUG
        cerr << " replace" << endl;
#endif
    }
}
Example #4
0
// a != b → R( a, i_{a,b} ) = R( b, i_{a,b} )
void Egraph::ExtAxiom( Enode * a, Enode * b )
{
  assert( isDynamic( a ) );
  assert( isDynamic( b ) );
  Enode * as = dynamicToStatic( a );
  Enode * bs = dynamicToStatic( b );
  assert( isStatic( as ) );
  assert( isStatic( bs ) );

  assert( as->isDTypeArray( ) );
  assert( bs->isDTypeArray( ) );

  // create fresh index i_a,b for pair a,b
  char def_name[ 48 ];
  sprintf( def_name, IND_STR, as->getId( ), bs->getId( ) );
  const unsigned type = DTYPE_ARRAY_INDEX;
  if ( lookupSymbol( def_name ) == NULL )
    newSymbol( def_name, type );
  // Create new variable
  Enode * i = mkVar( def_name );
  // Create two new selections
  Enode * select1  = mkSelect( as, i );
  Enode * select2  = mkSelect( bs, i );
  // Create new literals
  Enode * lit1     = mkEq( cons( as, cons( bs ) ) );
  Enode * lit2_pos = mkEq( cons( select1, cons( select2 ) ) );
  Enode * lit2     = mkNot( cons( lit2_pos ) );
#ifdef PRODUCE_PROOF
  if ( config.gconfig.print_inter > 0 )
  {
    const uint64_t shared = getIPartitions( as ) 
			  & getIPartitions( bs );
    // Mixed can't be one at this point
    assert( shared != 1 );
    // Set AB-mixed partition if no intersection
    if ( shared == 0 )
    {
      setIPartitions( i, 1 );
      setIPartitions( select1, 1 );
      setIPartitions( select2, 1 );
      setIPartitions( lit1, 1 );
      setIPartitions( lit2_pos, 1 );
      setIPartitions( lit2, 1 );
    }
    // Otherwise they share something
    else
    {
      setIPartitions( i, shared );
      setIPartitions( select1, shared );
      setIPartitions( select2, shared );
      setIPartitions( lit1, shared );
      setIPartitions( lit2_pos, shared );
      setIPartitions( lit2, shared );
    }
  }
#endif
  vector< Enode * > v;
  v.push_back( lit1 );
  v.push_back( lit2 );
#ifdef ARR_VERB
  cout << "Axiom Ext ->   " << "( or " << lit1 << " " << lit2 << " )" << endl;
#endif
  splitOnDemand( v, id );

  handleArrayAssertedAtomTerm( select1 );
  handleArrayAssertedAtomTerm( select2 );

  // New contexts to propagate info about new index
  // Given R(a,new) look for all store users W(a,i,e) 
  // and instantiate RoW over R(W(a,i,e),new)
  vector< Enode * > sela;
  vector< Enode * > stoa;
  vector< Enode * > selb;
  vector< Enode * > stob;
  Enode * select3 = NULL;

  // Act over a
  getUsers( a, sela, stoa );
  for( size_t j = 0 ; j < stoa.size( ) ; j++ )
  {
    assert( isDynamic( stoa[ j ] ) );
    Enode * ss = dynamicToStatic( stoa[ j ] );
    assert( isStatic( ss ) );
    // Creation new select for each store user of a
    select3 = mkSelect( ss, i );
    // RoW over new select
    handleArrayAssertedAtomTerm( select3 );
#ifdef PRODUCE_PROOF
    if ( config.gconfig.print_inter > 0 )
    {
      const uint64_t shared = getIPartitions( ss ) 
	                    & getIPartitions( i );
      // Mixed can't be one at this point
      assert( shared != 1 );
      // Set AB-mixed partition if no intersection
      if ( shared == 0 )
	setIPartitions( select3, 1 );
      // Otherwise they share something
      else
	setIPartitions( select3, shared );
    }
#endif
  }

  // Act over b
  getUsers( b, selb, stob );
  for ( size_t j = 0 ; j < stob.size( ) ; j++ )
  {
    assert( isDynamic( stoa[ j ] ) );
    Enode * ss = dynamicToStatic( stob[ j ] );
    assert( isStatic( ss ) );
    // Creation new select for each store user of b
    select3 = mkSelect( ss, i );
#ifdef PRODUCE_PROOF
    if ( config.gconfig.print_inter > 0 )
    {
      const uint64_t shared = getIPartitions( ss ) 
	                    & getIPartitions( i );
      // Mixed can't be one at this point
      assert( shared != 1 );
      // Set AB-mixed partition if no intersection
      if ( shared == 0 )
	setIPartitions( select3, 1 );
      // Otherwise they share something
      else
	setIPartitions( select3, shared );
    }
#endif
    // RoW over new select
    handleArrayAssertedAtomTerm( select3 );
  }
}
Example #5
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->isIff( )
      && !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 );
      
	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 );
	  Enode * lhs = e->get1st( );
	  Enode * rhs = e->get2nd( );
	  Enode * leq = mkLeq( cons( lhs, cons( rhs ) ) );
	  LAExpression b( leq );
	  leq = b.toEnode( *this );
	  Enode * geq = mkGeq( cons( lhs, cons( rhs ) ) );
	  LAExpression c( geq );
	  geq = c.toEnode( *this );
	  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 );
  }

  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;
}