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;
    }
}
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++;
    }
}
Exemplo n.º 3
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 );
}
Exemplo n.º 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;
  }
}
Exemplo n.º 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);
  }
}
Exemplo n.º 6
0
map<Enode *, bool> CoreSMTSolver::getBoolModel() {
    map<Enode *, bool> ret;
    for (int i = 0; i < trail.size(); i++) {
        Lit const & l = trail[i];
        Var const v = var(l);
        if (v >= 2) {
            Enode * e = theory_handler->varToEnode(v);
            bool p = value(l) == l_True;
            if (e->isNot()) {
                e = e->get1st();
                p = !p;
            }
            if (e->isVar()) {
                if (sign(l)) {
                    p = !p;
                }
                ret.emplace(e, p);
            }
        }
    }
    return ret;
}
box refine_CE_with_nlopt_core(box counterexample, vector<Enode*> const & opt_ctrs, vector<Enode*> const & side_ctrs) {
    // Plug-in `a` into the constraint and optimize `b` in the counterexample `M` by solving:
    //
    //    ∃ y_opt ∈ I_y. ∀ y ∈ I_y. f(a, y_opt) >= f(a, y) — (2)
    //
    // using local optimizer (i.e. nlopt).
    // Let `M’ = (a, b_opt)` be a model for (2).

    DREAL_LOG_DEBUG << "================================" << endl;
    DREAL_LOG_DEBUG << "  Before Refinement              " << endl;
    DREAL_LOG_DEBUG << "================================" << endl;
    DREAL_LOG_DEBUG << counterexample << endl;
    DREAL_LOG_DEBUG << "================================" << endl;
    static bool initialized = false;
    static vector<double> lb, ub, init;
    init.clear();
    for (Enode * e : counterexample.get_vars()) {
        if (e->isForallVar()) {
            if (!initialized) {
                lb.push_back(e->getDomainLowerBound());
                ub.push_back(e->getDomainUpperBound());
            }
            init.push_back(counterexample[e].mid());
            DREAL_LOG_DEBUG << lb.back() << " <= " << init.back() << " <= " << ub.back() << endl;
        }
    }
    auto const n = init.size();
    static nlopt::opt opt(nlopt::LD_SLSQP, n);
    if (!initialized) {
        opt.set_lower_bounds(lb);
        opt.set_upper_bounds(ub);
        // set tollerance
        // TODO(soonhok): set precision
        // opt.set_xtol_rel(0.0001);
        opt.set_xtol_abs(0.001);
        opt.set_maxtime(0.01);
        initialized = true;
    }

    opt.remove_equality_constraints();
    opt.remove_inequality_constraints();

    // set objective function
    vector<tuple<Enode *, box const &, bool> *> extra_vec;
    Enode * e = opt_ctrs[0];
    bool polarity = false;
    while (e->isNot()) {
        e = e->get1st();
        polarity = !polarity;
    }
    auto extra = new tuple<Enode *, box const &, bool>(e, counterexample, polarity);
    extra_vec.push_back(extra);
    opt.set_min_objective(nlopt_obj, extra);
    opt.add_inequality_constraint(nlopt_side_condition, extra);
    DREAL_LOG_DEBUG << "objective function is added: " << e << endl;

    // set side conditions
    for (Enode * e : side_ctrs) {
        bool polarity = false;
        while (e->isNot()) {
            e = e->get1st();
            polarity = !polarity;
        }
        auto extra = new tuple<Enode *, box const &, bool>(e, counterexample, polarity);
        extra_vec.push_back(extra);
        DREAL_LOG_DEBUG << "refine_counterexample_with_nlopt: Side condition is added: " << e << endl;
        if (e->isEq()) {
            opt.add_equality_constraint(nlopt_side_condition, extra);
        } else if (e->isLt() || e->isLeq() || e->isGt() || e->isGeq()) {
            opt.add_inequality_constraint(nlopt_side_condition, extra);
        }
    }
    try {
        vector<double> output = opt.optimize(init);
        unsigned i = 0;
        for (Enode * e : counterexample.get_vars()) {
            if (e->isForallVar()) {
                counterexample[e] = output[i];
                i++;
            }
        }
    } catch (nlopt::roundoff_limited & e) {
    } catch (std::runtime_error & e) {
        DREAL_LOG_DEBUG << e.what() << endl;
    }

    for (auto extra : extra_vec) {
        delete extra;
    }
    DREAL_LOG_DEBUG << "================================" << endl;
    DREAL_LOG_DEBUG << "  After Refinement              " << endl;
    DREAL_LOG_DEBUG << "================================" << endl;
    DREAL_LOG_DEBUG << counterexample << endl;
    DREAL_LOG_DEBUG << "================================" << endl;
    return counterexample;
}
Exemplo n.º 8
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 );
  }
}
Exemplo n.º 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 ) );
}
Exemplo n.º 10
0
double eval_enode(Enode * const e, unordered_map<Enode*, double> const & var_map) {
    if (e->isVar()) {
        auto const it = var_map.find(e);
        if (it == var_map.cend()) {
            throw runtime_error("variable not found");
        } else {
            // Variable is found in var_map
            return it->second;
        }
    } else if (e->isConstant()) {
        double const v = e->getValue();
        return v;
    } else if (e->isSymb()) {
        throw runtime_error("eval_enode: Symb");
    } else if (e->isNumb()) {
        throw runtime_error("eval_enode: Numb");
    } else if (e->isTerm()) {
        assert(e->getArity() >= 1);
        enodeid_t id = e->getCar()->getId();
        double ret = 0.0;
        Enode * tmp = e;
        switch (id) {
        case ENODE_ID_PLUS:
            ret = eval_enode(tmp->get1st(), var_map);
            tmp = tmp->getCdr()->getCdr();  // e is pointing to the 2nd arg
            while (!tmp->isEnil()) {
                ret = ret + eval_enode(tmp->getCar(), var_map);
                tmp = tmp->getCdr();
            }
            return ret;
        case ENODE_ID_MINUS:
            ret = eval_enode(tmp->get1st(), var_map);
            tmp = tmp->getCdr()->getCdr();  // e is pointing to the 2nd arg
            while (!tmp->isEnil()) {
                ret = ret - eval_enode(tmp->getCar(), var_map);
                tmp = tmp->getCdr();
            }
            return ret;
        case ENODE_ID_UMINUS:
            ret = eval_enode(tmp->get1st(), var_map);
            assert(tmp->getArity() == 1);
            return (- ret);
        case ENODE_ID_TIMES:
            ret = eval_enode(tmp->get1st(), var_map);
            tmp = tmp->getCdr()->getCdr();  // e is pointing to the 2nd arg
            while (!tmp->isEnil()) {
                ret = ret * eval_enode(tmp->getCar(), var_map);
                tmp = tmp->getCdr();
            }
            return ret;
        case ENODE_ID_DIV:
            ret = eval_enode(tmp->get1st(), var_map);
            tmp = tmp->getCdr()->getCdr();  // e is pointing to the 2nd arg
            while (!tmp->isEnil()) {
                ret = ret / eval_enode(tmp->getCar(), var_map);
                tmp = tmp->getCdr();
            }
            return ret;
        case ENODE_ID_ACOS:
            assert(e->getArity() == 1);
            return acos(eval_enode(e->get1st(), var_map));
        case ENODE_ID_ASIN:
            assert(e->getArity() == 1);
            return asin(eval_enode(e->get1st(), var_map));
        case ENODE_ID_ATAN:
            assert(e->getArity() == 1);
            return atan(eval_enode(e->get1st(), var_map));
        case ENODE_ID_ATAN2:
            assert(e->getArity() == 2);
            return atan2(eval_enode(e->get1st(), var_map),
                         eval_enode(e->get2nd(), var_map));
        case ENODE_ID_MIN:
            assert(e->getArity() == 2);
            return fmin(eval_enode(e->get1st(), var_map),
                        eval_enode(e->get2nd(), var_map));
        case ENODE_ID_MAX:
            assert(e->getArity() == 2);
            return fmax(eval_enode(e->get1st(), var_map),
                        eval_enode(e->get2nd(), var_map));
        case ENODE_ID_MATAN:
            assert(e->getArity() == 1);
            throw runtime_error("eval_enode: MATAN");
        case ENODE_ID_SAFESQRT:
            assert(e->getArity() == 1);
            throw runtime_error("eval_enode: SAFESQRT");
        case ENODE_ID_SQRT:
            assert(e->getArity() == 1);
            return sqrt(eval_enode(e->get1st(), var_map));
        case ENODE_ID_EXP:
            assert(e->getArity() == 1);
            return exp(eval_enode(e->get1st(), var_map));
        case ENODE_ID_LOG:
            assert(e->getArity() == 1);
            return log(eval_enode(e->get1st(), var_map));
        case ENODE_ID_POW:
            assert(e->getArity() == 2);
            return pow(eval_enode(e->get1st(), var_map),
                       eval_enode(e->get2nd(), var_map));
        case ENODE_ID_ABS:
            assert(e->getArity() == 1);
            return fabs(eval_enode(e->get1st(), var_map));
        case ENODE_ID_SIN:
            assert(e->getArity() == 1);
            return sin(eval_enode(e->get1st(), var_map));
        case ENODE_ID_COS:
            assert(e->getArity() == 1);
            return cos(eval_enode(e->get1st(), var_map));
        case ENODE_ID_TAN:
            assert(e->getArity() == 1);
            return tan(eval_enode(e->get1st(), var_map));
        case ENODE_ID_SINH:
            assert(e->getArity() == 1);
            return sinh(eval_enode(e->get1st(), var_map));
        case ENODE_ID_COSH:
            assert(e->getArity() == 1);
            return cosh(eval_enode(e->get1st(), var_map));
        case ENODE_ID_TANH:
            assert(e->getArity() == 1);
            return tanh(eval_enode(e->get1st(), var_map));
        default:
            throw runtime_error("eval_enode: Unknown Term");
        }
    } else if (e->isList()) {
        throw runtime_error("eval_enode: List");
    } else if (e->isDef()) {
        throw runtime_error("eval_enode: Def");
    } else if (e->isEnil()) {
        throw runtime_error("eval_enode: Nil");
    } else {
        throw runtime_error("eval_enode: unknown case");
    }
    throw runtime_error("Not implemented yet: eval_enode");
}
Exemplo n.º 11
0
double deriv_enode(Enode * const e, Enode * const v, unordered_map<Enode*, double> const & var_map) {
    if (e == v) {
        return 1.0;
    }
    if (e->isVar()) {
        auto const it = var_map.find(e);
        if (it == var_map.cend()) {
            throw runtime_error("variable not found");
        } else {
            // Variable is found in var_map
            return 0.0;
        }
    } else if (e->isConstant()) {
        return 0.0;
    } else if (e->isSymb()) {
        throw runtime_error("eval_enode: Symb");
    } else if (e->isNumb()) {
        throw runtime_error("eval_enode: Numb");
    } else if (e->isTerm()) {
        assert(e->getArity() >= 1);
        enodeid_t id = e->getCar()->getId();
        double ret = 0.0;
        Enode * tmp = e;
        switch (id) {
        case ENODE_ID_PLUS:
            ret = deriv_enode(tmp->get1st(), v, var_map);
            tmp = tmp->getCdr()->getCdr();  // e is pointing to the 2nd arg
            while (!tmp->isEnil()) {
                ret = ret + deriv_enode(tmp->getCar(), v, var_map);
                tmp = tmp->getCdr();
            }
            return ret;
        case ENODE_ID_MINUS:
            ret = deriv_enode(tmp->get1st(), v, var_map);
            tmp = tmp->getCdr()->getCdr();  // e is pointing to the 2nd arg
            while (!tmp->isEnil()) {
                ret = ret - deriv_enode(tmp->getCar(), v, var_map);
                tmp = tmp->getCdr();
            }
            return ret;
        case ENODE_ID_UMINUS:
            ret = deriv_enode(tmp->get1st(), v, var_map);
            assert(tmp->getArity() == 1);
            return (- ret);
        case ENODE_ID_TIMES: {
            // (f * g)' = f' * g + f * g'
            if (tmp->getArity() != 2) {
                throw runtime_error("deriv_enode: only support arity = 2 case for multiplication");
            }
            double const f = eval_enode(e->get1st(), var_map);
            double const f_ = deriv_enode(e->get1st(), v, var_map);
            double const g = eval_enode(e->get2nd(), var_map);
            double const g_ = deriv_enode(e->get2nd(), v, var_map);
            return f_ * g + f * g_;
        }
        case ENODE_ID_DIV: {
            // (f / g)' = (f' * g - f * g') / g^2
            if (tmp->getArity() != 2) {
                throw runtime_error("deriv_enode: only support arity = 2 case for division");
            }
            double const f = eval_enode(e->get1st(), var_map);
            double const f_ = deriv_enode(e->get1st(), v, var_map);
            double const g = eval_enode(e->get2nd(), var_map);
            double const g_ = deriv_enode(e->get2nd(), v, var_map);
            return (f_ * g - f * g_) / (g * g);
        }
        case ENODE_ID_ACOS: {
            // (acos f)' = -(1 / sqrt(1 - f^2)) f'
            assert(e->getArity() == 1);
            double const f = eval_enode(e->get1st(), var_map);
            double const f_ = deriv_enode(e->get1st(), v, var_map);
            return - (1 / sqrt(1 - f * f)) * f_;
        }
        case ENODE_ID_ASIN: {
            // (asin f)' = (1 / sqrt(1 - f^2)) f'
            assert(e->getArity() == 1);
            double const f = eval_enode(e->get1st(), var_map);
            double const f_ = deriv_enode(e->get1st(), v, var_map);
            return 1 / sqrt(1 - f * f) * f_;
        }
        case ENODE_ID_ATAN: {
            // (atan f)' = (1 / (1 + f^2)) * f'
            assert(e->getArity() == 1);
            double const f = eval_enode(e->get1st(), var_map);
            double const f_ = deriv_enode(e->get1st(), v, var_map);
            return 1 / (1 + f * f) * f_;
        }
        case ENODE_ID_ATAN2: {
            // atan2(x,y)' = -y / (x^2 + y^2) dx + x / (x^2 + y^2) dy
            //             = (-y dx + x dy) / (x^2 + y^2)
            assert(e->getArity() == 2);
            double const f = eval_enode(e->get1st(), var_map);
            double const f_ = deriv_enode(e->get1st(), v, var_map);
            double const g = eval_enode(e->get2nd(), var_map);
            double const g_ = deriv_enode(e->get2nd(), v, var_map);
            return (-g * f_ + f * g_) / (f * f + g * g);
        }
        case ENODE_ID_MIN:
            assert(e->getArity() == 2);
            throw runtime_error("deriv_enode: no support for min");
        case ENODE_ID_MAX:
            assert(e->getArity() == 2);
            throw runtime_error("deriv_enode: no support for max");
        case ENODE_ID_MATAN:
            assert(e->getArity() == 1);
            throw runtime_error("deriv_enode: no support for matan");
        case ENODE_ID_SAFESQRT:
            assert(e->getArity() == 1);
            throw runtime_error("deriv_enode: no support for safesqrt");
        case ENODE_ID_SQRT: {
            // (sqrt(f))' = 1/2 * 1/(sqrt(f)) * f'
            assert(e->getArity() == 1);
            double const f = eval_enode(e->get1st(), var_map);
            double const f_ = deriv_enode(e->get1st(), v, var_map);
            return 0.5 * 1 / sqrt(f) * f_;
        }
        case ENODE_ID_EXP: {
            // (exp f)' = (exp f) * f'
            assert(e->getArity() == 1);
            double const f = eval_enode(e->get1st(), var_map);
            double const f_ = deriv_enode(e->get1st(), v, var_map);
            return exp(f) * f_;
        }
        case ENODE_ID_LOG: {
            // (log f)' = f' / f
            assert(e->getArity() == 1);
            double const f = eval_enode(e->get1st(), var_map);
            double const f_ = deriv_enode(e->get1st(), v, var_map);
            return f_ / f;
        }
        case ENODE_ID_POW: {
            // (f^g)' = f^g (f' * g / f + g' * ln g)
            assert(e->getArity() == 2);
            double const f = eval_enode(e->get1st(), var_map);
            double const f_ = deriv_enode(e->get1st(), v, var_map);
            double const g = eval_enode(e->get2nd(), var_map);
            double const g_ = deriv_enode(e->get2nd(), v, var_map);
            return pow(f, g) * (f_ * g / f + g_ * log(g));
        }
        case ENODE_ID_ABS: {
            assert(e->getArity() == 1);
            double const f = eval_enode(e->get1st(), var_map);
            double const f_ = deriv_enode(e->get1st(), v, var_map);
            if (f > 0) {
                return f_;
            } else {
                return - f_;
            }
        }
        case ENODE_ID_SIN: {
            // (sin f)' = (cos f) * f'
            assert(e->getArity() == 1);
            double const f = eval_enode(e->get1st(), var_map);
            double const f_ = deriv_enode(e->get1st(), v, var_map);
            return cos(f) * f_;
        }
        case ENODE_ID_COS: {
            // (cos f)' = - (sin f) * f'
            assert(e->getArity() == 1);
            double const f = eval_enode(e->get1st(), var_map);
            double const f_ = deriv_enode(e->get1st(), v, var_map);
            return - sin(f) * f_;
        }
        case ENODE_ID_TAN: {
            // (tan f)' = (1 + tan^2 f) * f'
            assert(e->getArity() == 1);
            double const f = eval_enode(e->get1st(), var_map);
            double const f_ = deriv_enode(e->get1st(), v, var_map);
            return (1 + tan(f) * tan(f)) * f_;
        }
        case ENODE_ID_SINH: {
            // (sinh f)' = (e^f + e^(-f))/2 * f'
            //           = cosh(f) * f'
            assert(e->getArity() == 1);
            double const f = eval_enode(e->get1st(), var_map);
            double const f_ = deriv_enode(e->get1st(), v, var_map);
            return cosh(f) * f_;
        }
        case ENODE_ID_COSH: {
            // (cosh f)' = (e^f - e^(-f))/2 * f'
            //           = sinh(f) * f'
            assert(e->getArity() == 1);
            double const f = eval_enode(e->get1st(), var_map);
            double const f_ = deriv_enode(e->get1st(), v, var_map);
            return sinh(f) * f_;
        }
        case ENODE_ID_TANH: {
            // (tanh f)' = (sech^2 f) * f'
            //           = (1 - tanh(f) ^ 2) * f'
            assert(e->getArity() == 1);
            double const f = eval_enode(e->get1st(), var_map);
            double const f_ = deriv_enode(e->get1st(), v, var_map);
            return (1 - tanh(f) * tanh(f)) * f_;
        }
        default:
            throw runtime_error("deriv_enode: Unknown Term");
        }
    } else if (e->isList()) {
        throw runtime_error("deriv_enode: List");
    } else if (e->isDef()) {
        throw runtime_error("deriv_enode: Def");
    } else if (e->isEnil()) {
        throw runtime_error("deriv_enode: Nil");
    } else {
        throw runtime_error("deriv_enode: unknown case");
    }
    throw runtime_error("Not implemented yet: deriv_enode");
}
Exemplo n.º 12
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;
}
Exemplo n.º 13
0
//
// Performs the actual cnfization
//
bool Tseitin::cnfize( Enode * formula, map< enodeid_t, Enode * > & cnf_cache )
{
  (void)cnf_cache;
  assert( formula );
  assert( !formula->isAnd( ) );

  Enode * arg_def = egraph.valDupMap1( formula );
  if ( arg_def != NULL )
  {
    vector< Enode * > clause;
    clause.push_back( arg_def );
#ifdef PRODUCE_PROOF
    if ( config.produce_inter > 0 )
      return solver.addSMTClause( clause, egraph.getIPartitions( formula ) );
#endif
    return solver.addSMTClause( clause );
  }

  vector< Enode * > unprocessed_enodes;       // Stack for unprocessed enodes
  unprocessed_enodes.push_back( formula );    // formula needs to be processed
  //
  // 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 an unprocessed boolean operator
      //
      if ( enode->isBooleanOperator( )
        && egraph.valDupMap1( arg ) == NULL )
      {
        unprocessed_enodes.push_back( arg );
        unprocessed_children = true;
      }
      //
      // If it is an atom (either boolean or theory) just
      // store it in the cache
      //
      else if ( arg->isAtom( ) )
      {
        egraph.storeDupMap1( arg, arg );
      }
    }
    //
    // SKip if unprocessed_children
    //
    if ( unprocessed_children )
      continue;

    unprocessed_enodes.pop_back( );
    Enode * result = NULL;
    //
    // At this point, every child has been processed
    //
    //
    // Do the actual cnfization, according to the node type
    //
    char def_name[ 32 ];

    if ( enode->isLit( ) )
    {
      result = enode;
    }
    else if ( enode->isNot( ) )
    {
      Enode * arg_def = egraph.valDupMap1( enode->get1st( ) );
      assert( arg_def );
      result = egraph.mkNot( egraph.cons( arg_def ) ); // Toggle the literal
    }
    else
    {
      Enode * arg_def = NULL;
      Enode * new_arg_list = egraph.copyEnodeEtypeListWithCache( enode->getCdr( ) );
      //
      // If the enode is not top-level it needs a definition
      //
      if ( formula != enode )
      {
        sprintf( def_name, CNF_STR, formula->getId( ), enode->getId( ) );
        egraph.newSymbol( def_name, sstore.mkBool( ) );
        arg_def = egraph.mkVar( def_name );
#ifdef PRODUCE_PROOF
        if ( config.produce_inter > 0 )
        {
          // Tag Positive and negative literals
          egraph.tagIFormula( arg_def
                            , egraph.getIPartitions( enode ) );
          egraph.tagIFormula( egraph.mkNot( egraph.cons( arg_def ) )
                            , egraph.getIPartitions( enode ) );
        }
#endif
      }
#ifdef PRODUCE_PROOF
      uint64_t partitions = 0;
      if ( config.produce_inter > 0 )
      {
        partitions = egraph.getIPartitions( enode );
        assert( partitions != 0 );
      }
#endif
      //
      // Handle boolean operators
      //
      if ( enode->isAnd( ) )
        cnfizeAnd( new_arg_list, arg_def
#ifdef PRODUCE_PROOF
        , partitions
#endif
        );
      else if ( enode->isOr( ) )
        cnfizeOr( new_arg_list, arg_def
#ifdef PRODUCE_PROOF
        , partitions
#endif
        );
      else if ( enode->isIff( ) )
        cnfizeIff( new_arg_list, arg_def
#ifdef PRODUCE_PROOF
        , partitions
#endif
        );
      else if ( enode->isXor( ) )
        cnfizeXor( new_arg_list, arg_def
#ifdef PRODUCE_PROOF
        , partitions
#endif
        );
      else
      {
        opensmt_error2( "operator not handled ", enode->getCar( ) );
      }

      if ( arg_def != NULL )
        result = arg_def;
    }

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

  if ( formula->isNot( ) )
  {
    // Retrieve definition of argument
    Enode * arg_def = egraph.valDupMap1( formula->get1st( ) );
    assert( arg_def );
    vector< Enode * > clause;
    clause.push_back( toggleLit( arg_def ) );
#ifdef PRODUCE_PROOF
    if ( config.produce_inter > 0 )
      return solver.addSMTClause( clause, egraph.getIPartitions( formula ) );
#endif
    return solver.addSMTClause( clause );
  }

  return true;
}
Exemplo n.º 14
0
// Translate an Enode e into ibex::ExprNode.
// Note: As a side-effect, update var_map : string -> ibex::Variable
// Note: Use subst map (Enode ->ibex::Interval)
ExprNode const * translate_enode_to_exprnode(map<string, Variable const> & var_map, Enode * const e, unordered_map<Enode*, ibex::Interval> const & subst) {
    // TODO(soonhok): for the simple case such as 0 <= x or x <= 10.
    // Handle it as a domain specification instead of constraints.
    if (e->isVar()) {
        auto const subst_it = subst.find(e);
        if (subst_it != subst.cend()) {
            auto const i = subst_it->second;
            return &ExprConstant::new_scalar(i);
        }
        string const & var_name = e->getCar()->getNameFull();
        auto const it = var_map.find(var_name);
        if (it == var_map.cend()) {
            // The variable is new, we need to make one.
            Variable v(var_name.c_str());
            // double const lb = e->getLowerBound();
            // double const ub = e->getUpperBound();
            var_map.emplace(var_name, v);
            return v.symbol;
        } else {
            // Variable is found in var_map
            Variable const & v = it->second;
            return v.symbol;
        }

    } else if (e->isConstant()) {
        double const lb = e->getValueLowerBound();
        double const ub = e->getValueUpperBound();
        return &ExprConstant::new_scalar(ibex::Interval(lb, ub));
    } else if (e->isSymb()) {
        throw logic_error("translateEnodeExprNode: Symb");
    } else if (e->isNumb()) {
        throw logic_error("translateEnodeExprNode: Numb");
    } else if (e->isTerm()) {
        assert(e->getArity() >= 1);
        enodeid_t id = e->getCar()->getId();
        ExprNode const * ret = nullptr;
        Enode * tmp = e;
        switch (id) {
        case ENODE_ID_PLUS:
            ret = translate_enode_to_exprnode(var_map, tmp->get1st(), subst);
            tmp = tmp->getCdr()->getCdr();  // e is pointing to the 2nd arg
            while (!tmp->isEnil()) {
                ret = &(*ret + *translate_enode_to_exprnode(var_map, tmp->getCar(), subst));
                tmp = tmp->getCdr();
            }
            return ret;
        case ENODE_ID_MINUS:
            ret = translate_enode_to_exprnode(var_map, tmp->get1st(), subst);
            tmp = tmp->getCdr()->getCdr();  // e is pointing to the 2nd arg
            while (!tmp->isEnil()) {
                ret = &(*ret - *translate_enode_to_exprnode(var_map, tmp->getCar(), subst));
                tmp = tmp->getCdr();
            }
            return ret;
        case ENODE_ID_UMINUS:
            ret = translate_enode_to_exprnode(var_map, tmp->get1st(), subst);
            assert(tmp->getArity() == 1);
            return &(- *ret);
        case ENODE_ID_TIMES:
            ret = translate_enode_to_exprnode(var_map, tmp->get1st(), subst);
            tmp = tmp->getCdr()->getCdr();  // e is pointing to the 2nd arg
            while (!tmp->isEnil()) {
                ret = &(*ret * *translate_enode_to_exprnode(var_map, tmp->getCar(), subst));
                tmp = tmp->getCdr();
            }
            return ret;
        case ENODE_ID_DIV:
            ret = translate_enode_to_exprnode(var_map, tmp->get1st(), subst);
            tmp = tmp->getCdr()->getCdr();  // e is pointing to the 2nd arg
            while (!tmp->isEnil()) {
                ret = &(*ret / *translate_enode_to_exprnode(var_map, tmp->getCar(), subst));
                tmp = tmp->getCdr();
            }
            return ret;
        case ENODE_ID_ACOS:
            assert(e->getArity() == 1);
            return &acos(*translate_enode_to_exprnode(var_map, e->get1st(), subst));
        case ENODE_ID_ASIN:
            assert(e->getArity() == 1);
            return &asin(*translate_enode_to_exprnode(var_map, e->get1st(), subst));
        case ENODE_ID_ATAN:
            assert(e->getArity() == 1);
            return &atan(*translate_enode_to_exprnode(var_map, e->get1st(), subst));
        case ENODE_ID_ATAN2:
            assert(e->getArity() == 2);
            return &atan2(*translate_enode_to_exprnode(var_map, e->get1st(), subst), *translate_enode_to_exprnode(var_map, e->get2nd(), subst));
        case ENODE_ID_MIN:
            assert(e->getArity() == 2);
            return &min(*translate_enode_to_exprnode(var_map, e->get1st(), subst), *translate_enode_to_exprnode(var_map, e->get2nd(), subst));
        case ENODE_ID_MAX:
            assert(e->getArity() == 2);
            return &max(*translate_enode_to_exprnode(var_map, e->get1st(), subst), *translate_enode_to_exprnode(var_map, e->get2nd(), subst));
        case ENODE_ID_MATAN:
            // TODO(soonhok): MATAN
            throw logic_error("translateEnodeExprNode: MATAN");
        case ENODE_ID_SAFESQRT:
            // TODO(soonhok): SAFESQRT
            throw logic_error("translateEnodeExprNode: SAFESQRT");
        case ENODE_ID_SQRT:
            assert(e->getArity() == 1);
            return &sqrt(*translate_enode_to_exprnode(var_map, e->get1st(), subst));
        case ENODE_ID_EXP:
            assert(e->getArity() == 1);
            return &exp(*translate_enode_to_exprnode(var_map, e->get1st(), subst));
        case ENODE_ID_LOG:
            assert(e->getArity() == 1);
            return &log(*translate_enode_to_exprnode(var_map, e->get1st(), subst));
        case ENODE_ID_POW: {
            assert(e->getArity() == 2);
            bool   is_1st_constant = false;
            bool   is_1st_int      = false;
            bool   is_2nd_constant = false;
            bool   is_2nd_int      = false;
            double dbl_1st = 0.0;
            int    int_1st = 0;
            double dbl_2nd = 0.0;
            int    int_2nd = 0;
            if (e->get1st()->isConstant()) {
                dbl_1st = e->get1st()->getValue();
                is_1st_constant = true;
                double tmp;
                if (modf(dbl_1st, &tmp) == 0.0) {
                    is_1st_int = true;
                    int_1st = static_cast<int>(tmp);
                }
            }
            if (e->get2nd()->isConstant()) {
                dbl_2nd = e->get2nd()->getValue();
                is_2nd_constant = true;
                double tmp;
                if (modf(dbl_2nd, &tmp) == 0.0) {
                    is_2nd_int = true;
                    int_2nd = static_cast<int>(tmp);
                }
            }
            if (is_1st_constant && is_2nd_constant) {
                // Both of them are constant, just compute and return a number
                return &ExprConstant::new_scalar(pow(dbl_1st, dbl_2nd));
            }
            // Now, either of them is non-constant.
            if (is_1st_int) {
                return &pow(int_1st, *translate_enode_to_exprnode(var_map, e->get2nd(), subst));
            }
            if (is_1st_constant) {
                return &pow(dbl_1st, *translate_enode_to_exprnode(var_map, e->get2nd(), subst));
            }
            if (is_2nd_int) {
                return &pow(*translate_enode_to_exprnode(var_map, e->get1st(), subst), int_2nd);
            }
            if (is_2nd_constant) {
                return &pow(*translate_enode_to_exprnode(var_map, e->get1st(), subst), dbl_2nd);
            }
            return &pow(*translate_enode_to_exprnode(var_map, e->get1st(), subst), *translate_enode_to_exprnode(var_map, e->get2nd(), subst));
        }
        case ENODE_ID_ABS:
            assert(e->getArity() == 1);
            return &abs(*translate_enode_to_exprnode(var_map, e->get1st(), subst));
        case ENODE_ID_SIN:
            assert(e->getArity() == 1);
            return &sin(*translate_enode_to_exprnode(var_map, e->get1st(), subst));
        case ENODE_ID_COS:
            assert(e->getArity() == 1);
            return &cos(*translate_enode_to_exprnode(var_map, e->get1st(), subst));
        case ENODE_ID_TAN:
            assert(e->getArity() == 1);
            return &tan(*translate_enode_to_exprnode(var_map, e->get1st(), subst));
        case ENODE_ID_SINH:
            assert(e->getArity() == 1);
            return &sinh(*translate_enode_to_exprnode(var_map, e->get1st(), subst));
        case ENODE_ID_COSH:
            assert(e->getArity() == 1);
            return &cosh(*translate_enode_to_exprnode(var_map, e->get1st(), subst));
        case ENODE_ID_TANH:
            assert(e->getArity() == 1);
            return &tanh(*translate_enode_to_exprnode(var_map, e->get1st(), subst));
        default:
            throw logic_error("translateEnodeExprNode: Unknown Term");
        }
    } else if (e->isList()) {
        throw logic_error("translateEnodeExprNode: List");
    } else if (e->isDef()) {
        throw logic_error("translateEnodeExprNode: Def");
    } else if (e->isEnil()) {
        throw logic_error("translateEnodeExprNode: Nil");
    } else {
        throw logic_error("translateEnodeExprNode: unknown case");
    }
    throw logic_error("Not implemented yet: translateEnodeExprNode");
}