Beispiel #1
0
  //Acceps a query, calls the SAT solver and generates Valid/InValid.
  //if returned 0 then input is INVALID if returned 1 then input is
  //VALID if returned 2 then UNDECIDED
  SOLVER_RETURN_TYPE
  STP::TopLevelSTPAux(SATSolver& NewSolver, const ASTNode& original_input)
  {
    bm->ASTNodeStats("input asserts and query: ", original_input);

    DifficultyScore difficulty;
    if (bm->UserFlags.stats_flag)
            cerr << "Difficulty Initially:" << difficulty.score(original_input) << endl;

    // A heap object so I can easily control its lifetime.
    std::auto_ptr<BVSolver> bvSolver(new BVSolver(bm, simp));
    std::auto_ptr<PropagateEqualities> pe (new PropagateEqualities(simp,bm->defaultNodeFactory,bm));

    ASTNode simplified_solved_InputToSAT = original_input;

    // If the number of array reads is small. We rewrite them through.
    // The bit-vector simplifications are more thorough than the array simplifications. For example,
    // we don't currently do unconstrained elimination on arrays--- but we do for bit-vectors.
    // A better way to do this would be to estimate the number of axioms introduced.
    // TODO: I chose the number of reads we perform this operation at randomly.
    bool removed = false;
    if (((bm->UserFlags.ackermannisation && numberOfReadsLessThan(simplified_solved_InputToSAT,50)) || bm->UserFlags.isSet("upfront-ack", "0"))
        || numberOfReadsLessThan(simplified_solved_InputToSAT,10)
    )
      {
              // If the number of axioms that would be added it small. Remove them.
              bm->UserFlags.ackermannisation = true;
              simplified_solved_InputToSAT = arrayTransformer->TransformFormula_TopLevel(simplified_solved_InputToSAT);
              if (bm->UserFlags.stats_flag)
                cerr << "Have removed array operations" << endl;
              removed = true;
      }

    const bool arrayops = containsArrayOps(simplified_solved_InputToSAT);
    if (removed)
      assert(!arrayops);

    // Run size reducing just once.
    simplified_solved_InputToSAT = sizeReducing(simplified_solved_InputToSAT, bvSolver.get(),pe.get());

    unsigned initial_difficulty_score = difficulty.score(simplified_solved_InputToSAT);

    int bitblasted_difficulty = -1;

    // Fixed point it if it's not too difficult.
    // Currently we discards all the state each time sizeReducing is called,
    // so it's expensive to call.
    if ((!arrayops && initial_difficulty_score < 1000000) || bm->UserFlags.isSet("preserving-fixedpoint", "0"))
           simplified_solved_InputToSAT = callSizeReducing(simplified_solved_InputToSAT, bvSolver.get(),pe.get(), initial_difficulty_score, bitblasted_difficulty);

    if ((!arrayops || bm->UserFlags.isSet("array-difficulty-reversion", "1")))
      {
        initial_difficulty_score = difficulty.score(simplified_solved_InputToSAT);
      }

    if (bitblasted_difficulty != -1 && bm->UserFlags.stats_flag)
      std::cout << "Initial Bitblasted size:" << bitblasted_difficulty << endl;


    if (bm->UserFlags.stats_flag)
      std::cout << "Difficulty After Size reducing:" << initial_difficulty_score << endl;

    // So we can delete the object and release all the hash-buckets storage.
    std::auto_ptr<Revert_to> revert(new Revert_to());

    if ((!arrayops || bm->UserFlags.isSet("array-difficulty-reversion", "1")))
      {
        revert->initialSolverMap.insert(simp->Return_SolverMap()->begin(), simp->Return_SolverMap()->end());
        revert->backup_arrayToIndexToRead.insert(arrayTransformer->arrayToIndexToRead.begin(),arrayTransformer->arrayToIndexToRead.end());
        revert->toRevertTo = simplified_solved_InputToSAT;
      }

    ASTNode inputToSAT;

    //round of substitution, solving, and simplification. ensures that
    //DAG is minimized as much as possibly, and ideally should
    //garuntee that all liketerms in BVPLUSes have been combined.
    bm->SimplifyWrites_InPlace_Flag = false;
    //bm->Begin_RemoveWrites = false;
    //bm->start_abstracting = false;
    bm->TermsAlreadySeenMap_Clear();
    do
      {
        inputToSAT = simplified_solved_InputToSAT;

        if (bm->soft_timeout_expired)
            return SOLVER_TIMEOUT;

        if (bm->UserFlags.optimize_flag)
          {
            simplified_solved_InputToSAT = pe->topLevel(simplified_solved_InputToSAT, arrayTransformer);

            // Imagine:
            // The simplifier simplifies (0 + T) to T
            // Then bvsolve introduces (0 + T)
            // Then CreateSubstitutionMap decides T maps to a constant, but leaving another (0+T).
            // When we go to simplify (0 + T) will still be in the simplify cache, so will be mapped to T.
            // But it shouldn't be T, it should be a constant.
            // Applying the substitution map fixes this case.
            //
            if (simp->hasUnappliedSubstitutions())
              {
                simplified_solved_InputToSAT = simp->applySubstitutionMap(simplified_solved_InputToSAT);
                simp->haveAppliedSubstitutionMap();
              }

            bm->ASTNodeStats(pe_message.c_str(), simplified_solved_InputToSAT);

            simplified_solved_InputToSAT = simp->SimplifyFormula_TopLevel(simplified_solved_InputToSAT, false);

            bm->ASTNodeStats(size_inc_message.c_str(), simplified_solved_InputToSAT);
          }

        if (bm->UserFlags.wordlevel_solve_flag && bm->UserFlags.optimize_flag)
          {
            simplified_solved_InputToSAT = bvSolver->TopLevelBVSolve(simplified_solved_InputToSAT);
            bm->ASTNodeStats(bitvec_message.c_str(), simplified_solved_InputToSAT);
          }
      }
    while (inputToSAT != simplified_solved_InputToSAT);

    if (bm->UserFlags.bitConstantProp_flag)
      {
        bm->GetRunTimes()->start(RunTimes::ConstantBitPropagation);
        simplifier::constantBitP::ConstantBitPropagation cb(simp, bm->defaultNodeFactory, simplified_solved_InputToSAT);
        simplified_solved_InputToSAT = cb.topLevelBothWays(simplified_solved_InputToSAT);

        bm->GetRunTimes()->stop(RunTimes::ConstantBitPropagation);

        if (cb.isUnsatisfiable())
          simplified_solved_InputToSAT = bm->ASTFalse;

        bm->ASTNodeStats(cb_message.c_str(), simplified_solved_InputToSAT);
      }

    if (bm->UserFlags.isSet("use-intervals", "1"))
      {
        EstablishIntervals intervals(*bm);
        simplified_solved_InputToSAT = intervals.topLevel_unsignedIntervals(simplified_solved_InputToSAT);
        bm->ASTNodeStats(int_message.c_str(), simplified_solved_InputToSAT);
      }

    // Find pure literals.
    if (bm->UserFlags.isSet("pure-literals", "1"))
      {
        FindPureLiterals fpl;
        bool changed = fpl.topLevel(simplified_solved_InputToSAT, simp, bm);
        if (changed)
          {
            simplified_solved_InputToSAT = simp->applySubstitutionMap(simplified_solved_InputToSAT);
            simp->haveAppliedSubstitutionMap();
            bm->ASTNodeStats(pl_message.c_str(), simplified_solved_InputToSAT);
          }
      }

    if (bm->soft_timeout_expired)
        return SOLVER_TIMEOUT;

    // Simplify using Ite context
    if (bm->UserFlags.optimize_flag && bm->UserFlags.isSet("ite-context", "0"))
      {
        UseITEContext iteC(bm);
        simplified_solved_InputToSAT = iteC.topLevel(simplified_solved_InputToSAT);
        bm->ASTNodeStats("After ITE Context: ", simplified_solved_InputToSAT);
      }

    if (bm->UserFlags.isSet("aig-core-simplify", "0"))
      {
        AIGSimplifyPropositionalCore aigRR(bm);
        simplified_solved_InputToSAT = aigRR.topLevel(simplified_solved_InputToSAT);
        bm->ASTNodeStats("After AIG Core: ", simplified_solved_InputToSAT);
      }

#if 0
    bm->ASTNodeStats("Before SimplifyWrites_Inplace begins: ", simplified_solved_InputToSAT);

    bm->SimplifyWrites_InPlace_Flag = true;
    bm->Begin_RemoveWrites = false;
    bm->start_abstracting = false;
    bm->TermsAlreadySeenMap_Clear();
    do
      {
        inputToSAT = simplified_solved_InputToSAT;

        if (bm->UserFlags.optimize_flag)
          {
            simplified_solved_InputToSAT = pe->topLevel(simplified_solved_InputToSAT, arrayTransformer);

            if (simp->hasUnappliedSubstitutions())
              {
                simplified_solved_InputToSAT = simp->applySubstitutionMap(simplified_solved_InputToSAT);
                simp->haveAppliedSubstitutionMap();
              }

            bm->ASTNodeStats(pe->message.c_str(), simplified_solved_InputToSAT);

            simplified_solved_InputToSAT = simp->SimplifyFormula_TopLevel(simplified_solved_InputToSAT, false);
            bm->ASTNodeStats("after simplification: ", simplified_solved_InputToSAT);


            if (bm->UserFlags.isSet("always-true", "0"))
              {
                SimplifyingNodeFactory nf(*(bm->hashingNodeFactory), *bm);
                AlwaysTrue always (simp,bm,&nf);
                simplified_solved_InputToSAT = always.topLevel(simplified_solved_InputToSAT);
                bm->ASTNodeStats("After removing always true: ", simplified_solved_InputToSAT);
              }
          }

        // The word level solver uses the simplifier to apply the rewrites it makes,
        // without optimisations enabled. It will enter infinite loops on some input.
        // Instead it could use the apply function of the substitution map, but it
        // doesn't yet...
        if (bm->UserFlags.wordlevel_solve_flag && bm->UserFlags.optimize_flag)
          {
            simplified_solved_InputToSAT = bvSolver->TopLevelBVSolve(simplified_solved_InputToSAT);
            bm->ASTNodeStats("after solving: ", simplified_solved_InputToSAT);
          }
      }
    while (inputToSAT != simplified_solved_InputToSAT);

    bm->ASTNodeStats("After SimplifyWrites_Inplace: ", simplified_solved_InputToSAT);
#endif

    if (bm->UserFlags.isSet("enable-unconstrained", "1"))
      {
        // Remove unconstrained.
        RemoveUnconstrained r(*bm);
        simplified_solved_InputToSAT = r.topLevel(simplified_solved_InputToSAT, simp);
        bm->ASTNodeStats(uc_message.c_str(), simplified_solved_InputToSAT);
      }

    bm->TermsAlreadySeenMap_Clear();

    //bm->start_abstracting = false;
    bm->SimplifyWrites_InPlace_Flag = false;
    //bm->Begin_RemoveWrites = false;

    long final_difficulty_score = difficulty.score(simplified_solved_InputToSAT);

    bool worse= false;
    if (final_difficulty_score > 1.1 * initial_difficulty_score)
        worse = true;

    // It's of course very wasteful to do this! Later I'll make it reuse the work..
    // We bit-blast again, in order to throw it away, so that we can measure whether
    // the number of AIG nodes is smaller. The difficulty score is sometimes completely
    // wrong, the sage-app7 are the motivating examples. The other way to improve it would
    // be to fix the difficulty scorer!
    if (!worse && (bitblasted_difficulty != -1))
     {
        BBNodeManagerAIG bbnm;
        BitBlaster<BBNodeAIG, BBNodeManagerAIG> bb(&bbnm, simp, bm->defaultNodeFactory , &(bm->UserFlags));
        bb.BBForm(simplified_solved_InputToSAT);
        int newBB=  bbnm.totalNumberOfNodes();
        if (bm->UserFlags.stats_flag)
          cerr << "Final BB Size:" << newBB << endl;

        if (bitblasted_difficulty < newBB)
          worse = true;
    }


    if (bm->UserFlags.stats_flag)
      {
        cerr << "Initial Difficulty Score:" << initial_difficulty_score << endl;
        cerr << "Final Difficulty Score:" << final_difficulty_score << endl;
      }

    bool optimize_enabled = bm->UserFlags.optimize_flag;
    if (worse &&
       (!arrayops || bm->UserFlags.isSet("array-difficulty-reversion", "1")) &&
       bm->UserFlags.isSet("difficulty-reversion", "1"))
      {
        // If the simplified problem is harder, than the
        // initial problem we revert back to the initial
        // problem.

        if (bm->UserFlags.stats_flag)
          cerr << "simplification made the problem harder, reverting." << endl;
        simplified_solved_InputToSAT = revert->toRevertTo;

        // I do this to clear the substitution/solver map.
        // Not sure what would happen if it contained simplifications
        // that haven't been applied.
        simp->ClearAllTables();

        simp->Return_SolverMap()->insert(revert->initialSolverMap.begin(), revert->initialSolverMap.end());
        revert->initialSolverMap.clear();

        // Copy back what we knew about arrays at the start..
        arrayTransformer->arrayToIndexToRead.clear();
        arrayTransformer->arrayToIndexToRead.insert(revert->backup_arrayToIndexToRead.begin(), revert->backup_arrayToIndexToRead.end());

        // The arrayTransformer calls simplify. We don't want
        // it to put back in all the bad simplifications.
        bm->UserFlags.optimize_flag = false;
      }
    revert.reset(NULL);

    simplified_solved_InputToSAT = arrayTransformer->TransformFormula_TopLevel(simplified_solved_InputToSAT);
    bm->ASTNodeStats("after transformation: ", simplified_solved_InputToSAT);
    bm->TermsAlreadySeenMap_Clear();

    bm->UserFlags.optimize_flag = optimize_enabled;

    SOLVER_RETURN_TYPE res;
    if (!bm->UserFlags.ackermannisation)
      {
        bm->counterexample_checking_during_refinement = true;
      }

    // We are about to solve. Clear out all the memory associated with caches
    // that we won't need again.
    simp->ClearCaches();
    simp->haveAppliedSubstitutionMap();
    bm->ClearAllTables();

    // Deleting it clears out all the buckets associated with hashmaps etc. too.
    bvSolver.reset(NULL);
    pe.reset(NULL);


    if (bm->UserFlags.stats_flag)
      simp->printCacheStatus();

    const bool maybeRefinement = arrayops && !bm->UserFlags.ackermannisation;

    simplifier::constantBitP::ConstantBitPropagation* cb = NULL;
    std::auto_ptr<simplifier::constantBitP::ConstantBitPropagation> cleaner;

    if (bm->UserFlags.bitConstantProp_flag)
      {
        bm->GetRunTimes()->start(RunTimes::ConstantBitPropagation);
        cb = new simplifier::constantBitP::ConstantBitPropagation(simp, bm->defaultNodeFactory,
            simplified_solved_InputToSAT);
        cleaner.reset(cb);
        bm->GetRunTimes()->stop(RunTimes::ConstantBitPropagation);

        bm->ASTNodeStats(cb_message.c_str(), simplified_solved_InputToSAT);

        if (cb->isUnsatisfiable())
          simplified_solved_InputToSAT = bm->ASTFalse;
      }

    ToSATAIG toSATAIG(bm, cb, arrayTransformer);

    ToSATBase* satBase = bm->UserFlags.isSet("traditional-cnf", "0") ? tosat : &toSATAIG;

    if (bm->soft_timeout_expired)
        return SOLVER_TIMEOUT;

    // If it doesn't contain array operations, use ABC's CNF generation.
    res = Ctr_Example->CallSAT_ResultCheck(NewSolver, simplified_solved_InputToSAT, original_input, satBase,
        maybeRefinement);

    if (bm->soft_timeout_expired)
      {
        if (toSATAIG.cbIsDestructed())
          cleaner.release();

        return SOLVER_TIMEOUT;
      }
    if (SOLVER_UNDECIDED != res)
      {
        // If the aig converter knows that it is never going to be called again,
        // it deletes the constant bit stuff before calling the SAT solver.
        if (toSATAIG.cbIsDestructed())
          cleaner.release();

        CountersAndStats("print_func_stats", bm);
        return res;
      }

    assert(arrayops); // should only go to abstraction refinement if there are array ops.
    assert(!bm->UserFlags.ackermannisation); // Refinement must be enabled too.
    assert (bm->UserFlags.solver_to_use != UserDefinedFlags::MINISAT_PROPAGATORS); // The array solver shouldn't have returned undecided..

    res = Ctr_Example->SATBased_ArrayReadRefinement(NewSolver, simplified_solved_InputToSAT, original_input, satBase);
    if (SOLVER_UNDECIDED != res)
      {
        if (toSATAIG.cbIsDestructed())
          cleaner.release();

        CountersAndStats("print_func_stats", bm);
        return res;
      }

    #if 0
    res = Ctr_Example->SATBased_ArrayWriteRefinement(NewSolver, original_input, satBase);
    if (SOLVER_UNDECIDED != res)
      {
        if (toSATAIG.cbIsDestructed())
          cleaner.release();

        CountersAndStats("print_func_stats", bm);
        return res;
      }

    res = Ctr_Example->SATBased_ArrayReadRefinement(NewSolver, simplified_solved_InputToSAT, original_input, satBase);
    if (SOLVER_UNDECIDED != res)
      {
        if (toSATAIG.cbIsDestructed())
          cleaner.release();

        CountersAndStats("print_func_stats", bm);
        return res;
      }
    #endif

    FatalError("TopLevelSTPAux: reached the end without proper conclusion:"
      "either a divide by zero in the input or a bug in STP");
    //bogus return to make the compiler shut up
    return SOLVER_ERROR;


  } //End of TopLevelSTPAux
  //Acceps a query, calls the SAT solver and generates Valid/InValid.
  //if returned 0 then input is INVALID if returned 1 then input is
  //VALID if returned 2 then UNDECIDED
  SOLVER_RETURN_TYPE
  STP::TopLevelSTPAux(SATSolver& NewSolver, const ASTNode& modified_input, const ASTNode& original_input)
  {

    ASTNode inputToSAT = modified_input;
    ASTNode orig_input = original_input;
    bm->ASTNodeStats("input asserts and query: ", inputToSAT);

    ASTNode simplified_solved_InputToSAT = inputToSAT;
    const bool arrayops = containsArrayOps(original_input);

    DifficultyScore difficulty;
    if (bm->UserFlags.stats_flag)
      cerr << "Difficulty Initially:" << difficulty.score(original_input) << endl;

    // A heap object so I can easily control its lifetime.
    BVSolver* bvSolver = new BVSolver(bm, simp);

    simplified_solved_InputToSAT = sizeReducing(inputToSAT, bvSolver);

    unsigned initial_difficulty_score = difficulty.score(simplified_solved_InputToSAT);

    // Fixed point it if it's not too difficult.
    // Currently we discards all the state each time sizeReducing is called,
    // so it's expensive to call.
    if (!arrayops && initial_difficulty_score < 1000000)
      {
        simplified_solved_InputToSAT = callSizeReducing(simplified_solved_InputToSAT, bvSolver, initial_difficulty_score);
        initial_difficulty_score = difficulty.score(simplified_solved_InputToSAT);
      }

    if (bm->UserFlags.stats_flag)
      cout << "Difficulty After Size reducing:" << initial_difficulty_score << endl;

    // Copy the solver map incase we need to revert.
    ASTNodeMap initialSolverMap;
    ASTNode toRevertTo;
    if (!arrayops) // we don't revert for Array problems yet, so don't copy it.
      {
        initialSolverMap.insert(simp->Return_SolverMap()->begin(), simp->Return_SolverMap()->end());
        toRevertTo = simplified_solved_InputToSAT;
      }

    //round of substitution, solving, and simplification. ensures that
    //DAG is minimized as much as possibly, and ideally should
    //garuntee that all liketerms in BVPLUSes have been combined.
    bm->SimplifyWrites_InPlace_Flag = false;
    bm->Begin_RemoveWrites = false;
    bm->start_abstracting = false;
    bm->TermsAlreadySeenMap_Clear();
    do
      {
        inputToSAT = simplified_solved_InputToSAT;

        if (bm->UserFlags.optimize_flag)
          {
            simplified_solved_InputToSAT = simp->CreateSubstitutionMap(simplified_solved_InputToSAT, arrayTransformer);

            // Imagine:
            // The simplifier simplifies (0 + T) to T
            // Then bvsolve introduces (0 + T)
            // Then CreateSubstitutionMap decides T maps to a constant, but leaving another (0+T).
            // When we go to simplify (0 + T) will still be in the simplify cache, so will be mapped to T.
            // But it shouldn't be T, it should be a constant.
            // Applying the substitution map fixes this case.
            //
            if (simp->hasUnappliedSubstitutions())
              {
                simplified_solved_InputToSAT = simp->applySubstitutionMap(simplified_solved_InputToSAT);
                simp->haveAppliedSubstitutionMap();
              }

            bm->ASTNodeStats("after pure substitution: ", simplified_solved_InputToSAT);

            simplified_solved_InputToSAT = simp->SimplifyFormula_TopLevel(simplified_solved_InputToSAT, false);

            bm->ASTNodeStats("after simplification: ", simplified_solved_InputToSAT);
          }

        if (bm->UserFlags.wordlevel_solve_flag && bm->UserFlags.optimize_flag)
          {
            simplified_solved_InputToSAT = bvSolver->TopLevelBVSolve(simplified_solved_InputToSAT);
            bm->ASTNodeStats("after solving: ", simplified_solved_InputToSAT);
          }
      }
    while (inputToSAT != simplified_solved_InputToSAT);

    if (bm->UserFlags.bitConstantProp_flag)
      {
        bm->GetRunTimes()->start(RunTimes::ConstantBitPropagation);
        SimplifyingNodeFactory nf(*(bm->hashingNodeFactory), *bm);
        simplifier::constantBitP::ConstantBitPropagation cb(simp, &nf, simplified_solved_InputToSAT);
        simplified_solved_InputToSAT = cb.topLevelBothWays(simplified_solved_InputToSAT);

        bm->GetRunTimes()->stop(RunTimes::ConstantBitPropagation);

        if (cb.isUnsatisfiable())
          simplified_solved_InputToSAT = bm->ASTFalse;

        bm->ASTNodeStats("After Constant Bit Propagation begins: ", simplified_solved_InputToSAT);
      }

    if (bm->UserFlags.isSet("use-intervals", "1"))
      {
        EstablishIntervals intervals(*bm);
        simplified_solved_InputToSAT = intervals.topLevel_unsignedIntervals(simplified_solved_InputToSAT);
        bm->ASTNodeStats("After Establishing Intervals: ", simplified_solved_InputToSAT);
      }

    // Find pure literals.
    if (bm->UserFlags.isSet("pure-literals", "1"))
      {
        FindPureLiterals fpl;
        bool changed = fpl.topLevel(simplified_solved_InputToSAT, simp, bm);
        if (changed)
          {
            simplified_solved_InputToSAT = simp->applySubstitutionMap(simplified_solved_InputToSAT);
            simp->haveAppliedSubstitutionMap();
            bm->ASTNodeStats("After Pure Literals: ", simplified_solved_InputToSAT);
          }
      }

    // Simplify using Ite context
    if (bm->UserFlags.optimize_flag && bm->UserFlags.isSet("ite-context", "0"))
      {
        UseITEContext iteC(bm);
        simplified_solved_InputToSAT = iteC.topLevel(simplified_solved_InputToSAT);
        bm->ASTNodeStats("After ITE Context: ", simplified_solved_InputToSAT);
      }

    if (bm->UserFlags.isSet("aig-core-simplify", "0"))
      {
        AIGSimplifyPropositionalCore aigRR(bm);
        simplified_solved_InputToSAT = aigRR.topLevel(simplified_solved_InputToSAT);
        bm->ASTNodeStats("After AIG Core: ", simplified_solved_InputToSAT);
      }

    bm->ASTNodeStats("Before SimplifyWrites_Inplace begins: ", simplified_solved_InputToSAT);

    bm->SimplifyWrites_InPlace_Flag = true;
    bm->Begin_RemoveWrites = false;
    bm->start_abstracting = false;
    bm->TermsAlreadySeenMap_Clear();
    do
      {
        inputToSAT = simplified_solved_InputToSAT;

        if (bm->UserFlags.optimize_flag)
          {
            simplified_solved_InputToSAT = simp->CreateSubstitutionMap(simplified_solved_InputToSAT, arrayTransformer);

            if (simp->hasUnappliedSubstitutions())
              {
                simplified_solved_InputToSAT = simp->applySubstitutionMap(simplified_solved_InputToSAT);
                simp->haveAppliedSubstitutionMap();
              }

            bm->ASTNodeStats("after pure substitution: ", simplified_solved_InputToSAT);

            simplified_solved_InputToSAT = simp->SimplifyFormula_TopLevel(simplified_solved_InputToSAT, false);
            bm->ASTNodeStats("after simplification: ", simplified_solved_InputToSAT);


            if (bm->UserFlags.isSet("always-true", "0"))
              {
                SimplifyingNodeFactory nf(*(bm->hashingNodeFactory), *bm);
                AlwaysTrue always (simp,bm,&nf);
                simplified_solved_InputToSAT = always.topLevel(simplified_solved_InputToSAT);
                bm->ASTNodeStats("After removing always true: ", simplified_solved_InputToSAT);
              }
          }

        // The word level solver uses the simplifier to apply the rewrites it makes,
        // without optimisations enabled. It will enter infinite loops on some input.
        // Instead it could use the apply function of the substitution map, but it
        // doesn't yet...
        if (bm->UserFlags.wordlevel_solve_flag && bm->UserFlags.optimize_flag)
          {
            simplified_solved_InputToSAT = bvSolver->TopLevelBVSolve(simplified_solved_InputToSAT);
            bm->ASTNodeStats("after solving: ", simplified_solved_InputToSAT);
          }
      }
    while (inputToSAT != simplified_solved_InputToSAT);

    bm->ASTNodeStats("After SimplifyWrites_Inplace: ", simplified_solved_InputToSAT);

    if (bm->UserFlags.isSet("enable-unconstrained", "1"))
      {
        // Remove unconstrained.
        RemoveUnconstrained r(*bm);
        simplified_solved_InputToSAT = r.topLevel(simplified_solved_InputToSAT, simp);
        bm->ASTNodeStats("After Unconstrained Remove begins: ", simplified_solved_InputToSAT);
      }

    bm->TermsAlreadySeenMap_Clear();

    bm->start_abstracting = false;
    bm->SimplifyWrites_InPlace_Flag = false;
    bm->Begin_RemoveWrites = false;

    long final_difficulty_score = difficulty.score(simplified_solved_InputToSAT);
    if (bm->UserFlags.stats_flag)
      {
        cerr << "Initial Difficulty Score:" << initial_difficulty_score << endl;
        cerr << "Final Difficulty Score:" << final_difficulty_score << endl;
      }

    bool optimize_enabled = bm->UserFlags.optimize_flag;
    if (final_difficulty_score > 1.1 * initial_difficulty_score && !arrayops && bm->UserFlags.isSet(
        "difficulty-reversion", "1"))
      {
        // If the simplified problem is harder, than the
        // initial problem we revert back to the initial
        // problem.

        if (bm->UserFlags.stats_flag)
          cerr << "simplification made the problem harder, reverting." << endl;
        simplified_solved_InputToSAT = toRevertTo;

        // I do this to clear the substitution/solver map.
        // Not sure what would happen if it contained simplifications
        // that haven't been applied.
        simp->ClearAllTables();

        simp->Return_SolverMap()->insert(initialSolverMap.begin(), initialSolverMap.end());
        initialSolverMap.clear();

        // The arrayTransformer calls simplify. We don't want
        // it to put back in all the bad simplifications.
        bm->UserFlags.optimize_flag = false;
      }

    simplified_solved_InputToSAT = arrayTransformer->TransformFormula_TopLevel(simplified_solved_InputToSAT);
    bm->ASTNodeStats("after transformation: ", simplified_solved_InputToSAT);
    bm->TermsAlreadySeenMap_Clear();

    bm->UserFlags.optimize_flag = optimize_enabled;

    SOLVER_RETURN_TYPE res;
    if (bm->UserFlags.arrayread_refinement_flag)
      {
        bm->counterexample_checking_during_refinement = true;
      }

    // We are about to solve. Clear out all the memory associated with caches
    // that we won't need again.
    simp->ClearCaches();
    simp->haveAppliedSubstitutionMap();
    bm->ClearAllTables();

    // Deleting it clears out all the buckets associated with hashmaps etc. too.
    delete bvSolver;
    bvSolver = NULL;

    if (bm->UserFlags.stats_flag)
      simp->printCacheStatus();

    const bool maybeRefinement = arrayops && bm->UserFlags.arrayread_refinement_flag;

    simplifier::constantBitP::ConstantBitPropagation* cb = NULL;
    std::auto_ptr<simplifier::constantBitP::ConstantBitPropagation> cleaner;

    if (bm->UserFlags.bitConstantProp_flag)
      {
        bm->ASTNodeStats("Before Constant Bit Propagation begins: ", simplified_solved_InputToSAT);

        bm->GetRunTimes()->start(RunTimes::ConstantBitPropagation);
        cb = new simplifier::constantBitP::ConstantBitPropagation(simp, bm->defaultNodeFactory,
            simplified_solved_InputToSAT);
        cleaner.reset(cb);
        bm->GetRunTimes()->stop(RunTimes::ConstantBitPropagation);

        if (cb->isUnsatisfiable())
          simplified_solved_InputToSAT = bm->ASTFalse;
      }

    ToSATAIG toSATAIG(bm, cb);
    toSATAIG.setArrayTransformer(arrayTransformer);

    ToSATBase* satBase = bm->UserFlags.isSet("traditional-cnf", "0") ? tosat : ((ToSAT*) &toSATAIG) ;

    // If it doesn't contain array operations, use ABC's CNF generation.
    res = Ctr_Example->CallSAT_ResultCheck(NewSolver, simplified_solved_InputToSAT, orig_input, satBase,
        maybeRefinement);

    if (SOLVER_UNDECIDED != res)
      {
        // If the aig converter knows that it is never going to be called again,
        // it deletes the constant bit stuff before calling the SAT solver.
        if (toSATAIG.cbIsDestructed())
          cleaner.release();

        CountersAndStats("print_func_stats", bm);
        return res;
      }

    assert(arrayops); // should only go to abstraction refinement if there are array ops.
    assert(bm->UserFlags.arrayread_refinement_flag); // Refinement must be enabled too.

    // Unfortunately how I implemented the incremental CNF generator in ABC means that
    // cryptominisat and simplifying minisat may simplify away variables that we later need.

    res = Ctr_Example->SATBased_ArrayReadRefinement(NewSolver, simplified_solved_InputToSAT, orig_input, satBase);
    if (SOLVER_UNDECIDED != res)
      {
        if (toSATAIG.cbIsDestructed())
          cleaner.release();

        CountersAndStats("print_func_stats", bm);
        return res;
      }

    res = Ctr_Example->SATBased_ArrayWriteRefinement(NewSolver, orig_input, satBase);
    if (SOLVER_UNDECIDED != res)
      {
        if (toSATAIG.cbIsDestructed())
          cleaner.release();

        CountersAndStats("print_func_stats", bm);
        return res;
      }

    res = Ctr_Example->SATBased_ArrayReadRefinement(NewSolver, simplified_solved_InputToSAT, orig_input, satBase);
    if (SOLVER_UNDECIDED != res)
      {
        if (toSATAIG.cbIsDestructed())
          cleaner.release();

        CountersAndStats("print_func_stats", bm);
        return res;
      }

//    if (!bm->UserFlags.num_absrefine_flag)
      {
        FatalError("TopLevelSTPAux: reached the end without proper conclusion:"
          "either a divide by zero in the input or a bug in STP");
        //bogus return to make the compiler shut up
        return SOLVER_ERROR;
      }
  //  else
      {
       // return res;
      }
  } //End of TopLevelSTPAux