@Override
  public List<Expression<Boolean>> getInterpolants(List<Expression<Boolean>> exprsn) {

    Script s = new de.uni_freiburg.informatik.ultimate.smtinterpol.smtlib2.SMTInterpol();

    SMTInterpolExpressionGenerator gen = new SMTInterpolExpressionGenerator(s);
    ArrayList<String> names = new ArrayList<>();

    s.setOption(":produce-interpolants", true);
    s.setLogic(Logics.QF_LIA);
    int i = 1;
    for (Expression<Boolean> e : exprsn) {
      Term t = gen.generateAssertion(e);
      // System.out.println("T: " + t);
      String name = "phi_" + (i++);
      names.add(name);
      s.assertTerm(s.annotate(t, new Annotation(":named", name)));
    }

    if (s.checkSat() == Script.LBool.UNSAT) {
      Term[] terms = new Term[names.size()];
      i = 0;
      for (String n : names) {
        terms[i++] = s.term(n);
      }

      Term[] interpolants;
      interpolants = s.getInterpolants(terms);
      // System.out.println("I: " + Arrays.toString(interpolants));

      // parse result
      ArrayList<Expression<Boolean>> ret = new ArrayList<>();
      for (Term t : interpolants) {
        // System.out.println(t);
        TermParser parser = new TermParser(t, gen.getVariables());
        Expression<Boolean> interpolant;
        try {
          interpolant = parser.parse();
        } catch (TermParserException ex) {
          logger.severe(ex.getMessage());
          return null;
        }
        ret.add(interpolant);
      }

      return ret;
    }

    return null;
  }
  private Term translate(final Expression exp) {
    if (exp instanceof ArrayAccessExpression) {
      final ArrayAccessExpression arrexp = (ArrayAccessExpression) exp;
      final Expression[] indices = arrexp.getIndices();
      Term result = translate(arrexp.getArray());
      for (int i = 0; i < indices.length; i++) {
        final Term indexiTerm = translate(indices[i]);
        result = mScript.term("select", result, indexiTerm);
      }
      return result;

    } else if (exp instanceof ArrayStoreExpression) {
      final ArrayStoreExpression arrexp = (ArrayStoreExpression) exp;
      final Expression[] indices = arrexp.getIndices();
      assert indices.length > 0;
      // arrayBeforeIndex[i] represents the array, where all indices
      // before the i'th index have already been selected
      final Term[] arrayBeforeIndex = new Term[indices.length];
      final Term[] indexTerm = new Term[indices.length];
      arrayBeforeIndex[0] = translate(arrexp.getArray());
      for (int i = 0; i < indices.length - 1; i++) {
        indexTerm[i] = translate(indices[i]);
        arrayBeforeIndex[i + 1] = mScript.term("select", arrayBeforeIndex[i], indexTerm[i]);
      }
      indexTerm[indices.length - 1] = translate(indices[indices.length - 1]);
      Term result = translate(arrexp.getValue());
      for (int i = indices.length - 1; i >= 0; i--) {
        result = mScript.term("store", arrayBeforeIndex[i], indexTerm[i], result);
      }
      assert (result != null);
      assert resultContainsNoNull(result);
      return result;

    } else if (exp instanceof BinaryExpression) {
      final BinaryExpression binexp = (BinaryExpression) exp;
      final BinaryExpression.Operator op = binexp.getOperator();
      // Sort sort = mSmt2Boogie.getSort(binexp.getLeft().getType());
      if (op == BinaryExpression.Operator.COMPNEQ) {
        final String equalityFuncname =
            mOperationTranslator.opTranslation(
                BinaryExpression.Operator.COMPEQ,
                binexp.getLeft().getType(),
                binexp.getRight().getType());
        final String negationFuncname =
            mOperationTranslator.opTranslation(
                UnaryExpression.Operator.LOGICNEG, PrimitiveType.TYPE_BOOL);
        final BigInteger[] indices = new BigInteger[0];
        return SmtUtils.termWithLocalSimplification(
            mScript,
            negationFuncname,
            indices,
            SmtUtils.termWithLocalSimplification(
                mScript,
                equalityFuncname,
                indices,
                translate(binexp.getLeft()),
                translate(binexp.getRight())));
      } else {
        final String funcname =
            mOperationTranslator.opTranslation(
                op, binexp.getLeft().getType(), binexp.getRight().getType());
        final BigInteger[] indices = null;
        return SmtUtils.termWithLocalSimplification(
            mScript, funcname, indices, translate(binexp.getLeft()), translate(binexp.getRight()));
      }
    } else if (exp instanceof UnaryExpression) {
      final UnaryExpression unexp = (UnaryExpression) exp;
      final UnaryExpression.Operator op = unexp.getOperator();
      if (op == UnaryExpression.Operator.OLD) {
        mOldContextScopeDepth++;
        final Term term = translate(unexp.getExpr());
        mOldContextScopeDepth--;
        return term;
      } else {
        final String funcname = mOperationTranslator.opTranslation(op, unexp.getExpr().getType());
        final BigInteger[] indices = null;
        return SmtUtils.termWithLocalSimplification(
            mScript, funcname, indices, translate(unexp.getExpr()));
      }
    } else if (exp instanceof RealLiteral) {
      final Term result = mOperationTranslator.realTranslation((RealLiteral) exp);
      assert result != null;
      return result;

    } else if (exp instanceof BitvecLiteral) {
      final Term result = mOperationTranslator.bitvecTranslation((BitvecLiteral) exp);
      assert result != null;
      return result;

    } else if (exp instanceof BitVectorAccessExpression) {
      final BigInteger[] indices = new BigInteger[2];
      indices[0] = new BigInteger(Integer.toString(((BitVectorAccessExpression) exp).getEnd() - 1));
      indices[1] = new BigInteger(Integer.toString(((BitVectorAccessExpression) exp).getStart()));

      final Term result =
          mScript.term(
              "extract", indices, null, translate(((BitVectorAccessExpression) exp).getBitvec()));
      assert result != null;
      return result;

    } else if (exp instanceof BooleanLiteral) {
      final Term result = mOperationTranslator.booleanTranslation((BooleanLiteral) exp);
      assert result != null;
      return result;

    } else if (exp instanceof FunctionApplication) {
      final FunctionApplication func = ((FunctionApplication) exp);
      final Term result;
      final Map<String, Expression[]> attributes =
          mBoogie2SmtSymbolTable.getAttributes(func.getIdentifier());
      final String overapproximation =
          Boogie2SmtSymbolTable.checkForAttributeDefinedIdentifier(attributes, s_Overapproximation);
      if (mOverapproximateFunctions || overapproximation != null) {
        final Sort resultSort = mTypeSortTranslator.getSort(exp.getType(), exp);
        final TermVariable auxVar =
            mVariableManager.constructFreshTermVariable(func.getIdentifier(), resultSort);
        mAuxVars.add(auxVar);
        mOverapproximations.put(overapproximation, exp.getLocation());
        result = auxVar;
      } else {
        final BigInteger[] indices = Boogie2SmtSymbolTable.checkForIndices(attributes);
        final IBoogieType[] argumentTypes = new IBoogieType[func.getArguments().length];
        for (int i = 0; i < func.getArguments().length; i++) {
          argumentTypes[i] = func.getArguments()[i].getType();
        }

        final Sort[] params = new Sort[func.getArguments().length];
        for (int i = 0; i < func.getArguments().length; i++) {
          params[i] = mTypeSortTranslator.getSort(func.getArguments()[i].getType(), exp);
        }

        final Term[] parameters = new Term[func.getArguments().length];
        for (int i = 0; i < func.getArguments().length; i++) {
          parameters[i] = translate(func.getArguments()[i]);
        }

        final String funcSymb =
            mOperationTranslator.funcApplication(func.getIdentifier(), argumentTypes);
        if (funcSymb == null) {
          throw new IllegalArgumentException("unknown function" + func.getIdentifier());
        }
        //				result = mScript.term(funcSymb, indices, null, parameters);
        // overkill, this should be called only for bitvector operations.
        result = SmtUtils.termWithLocalSimplification(mScript, funcSymb, indices, parameters);
      }
      return result;
    } else if (exp instanceof IdentifierExpression) {
      final IdentifierExpression var = (IdentifierExpression) exp;
      assert var.getDeclarationInformation() != null : " no declaration information";
      final Term result =
          getSmtIdentifier(
              var.getIdentifier(), var.getDeclarationInformation(), isOldContext(), exp);
      assert result != null;
      return result;

    } else if (exp instanceof IntegerLiteral) {
      final Term result = mOperationTranslator.integerTranslation((IntegerLiteral) exp);
      assert result != null;
      return result;

    } else if (exp instanceof IfThenElseExpression) {
      final IfThenElseExpression ite = (IfThenElseExpression) exp;
      final Term cond = translate(ite.getCondition());
      final Term thenPart = translate(ite.getThenPart());
      final Term elsePart = translate(ite.getElsePart());
      final Term result = Util.ite(mScript, cond, thenPart, elsePart);
      assert result != null;
      return result;

    } else if (exp instanceof QuantifierExpression) {
      // throw new
      // UnsupportedOperationException("QuantifierExpression not implemented yet");
      final QuantifierExpression quant = (QuantifierExpression) exp;
      final String[] typeParams = quant.getTypeParams();
      final VarList[] variables = quant.getParameters();
      int numvars = typeParams.length;
      for (int i = 0; i < variables.length; i++) {
        numvars += variables[i].getIdentifiers().length;
      }
      final TermVariable[] vars = new TermVariable[numvars];
      // TODO is this really unused code
      // HashMap<String,Term> newVars = new HashMap<String, Term>();
      int offset = 0;
      // for (int j = 0; j < typeParams.length; j++) {
      // vars[offset] = mScript.createTermVariable("q" +
      // quoteId(typeParams[j]), intSort);
      // typeStack.push(vars[offset]);
      // offset++;
      // }
      mQuantifiedVariables.beginScope();
      for (int i = 0; i < variables.length; i++) {
        final IBoogieType type = variables[i].getType().getBoogieType();
        final Sort sort = mTypeSortTranslator.getSort(type, exp);
        for (int j = 0; j < variables[i].getIdentifiers().length; j++) {
          final String identifier = variables[i].getIdentifiers()[j];
          final String smtVarName = "q" + Boogie2SMT.quoteId(variables[i].getIdentifiers()[j]);
          vars[offset] = mScript.variable(smtVarName, sort);
          mQuantifiedVariables.put(identifier, vars[offset]);
          offset++;
        }
      }
      final Term form = translate(quant.getSubformula());

      final Attribute[] attrs = quant.getAttributes();
      int numTrigs = 0;
      for (final Attribute a : attrs) {
        if (a instanceof Trigger) {
          numTrigs++;
        }
      }
      final Term[][] triggers = new Term[numTrigs][];
      offset = 0;
      for (final Attribute a : attrs) {
        if (a instanceof Trigger) {
          final Expression[] trigs = ((Trigger) a).getTriggers();
          final Term[] smttrigs = new Term[trigs.length];
          for (int i = 0; i < trigs.length; i++) {
            final Term trig = translate(trigs[i]);
            // if (trig instanceof ITETerm
            // && ((ITETerm)trig).getTrueCase() == ONE
            // && ((ITETerm)trig).getFalseCase() == ZERO)
            // smttrigs[i] = ((ITETerm) trig).getCondition();
            // else
            smttrigs[i] = trig;
          }
          triggers[offset++] = smttrigs;
        }
      }
      // throw new
      // UnsupportedOperationException("QuantifierExpression not implemented yet");
      // identStack.pop();
      // for (int j = 0; j < typeParams.length; j++) {
      // typeStack.pop();
      // }
      mQuantifiedVariables.endScope();

      Term result = null;
      try {
        result =
            quant.isUniversal()
                ? mScript.quantifier(Script.FORALL, vars, form, triggers)
                : mScript.quantifier(Script.EXISTS, vars, form, triggers);
      } catch (final SMTLIBException e) {
        if (e.getMessage().equals("Cannot create quantifier in quantifier-free logic")) {
          Boogie2SMT.reportUnsupportedSyntax(
              exp, "Setting does not support quantifiers", mServices);
          throw e;
        } else {
          throw new AssertionError();
        }
      }
      assert resultContainsNoNull(result);
      return result;
    } else {
      throw new AssertionError("Unsupported expression " + exp);
    }
  }