Add InferenceId as resources (#6339)
authorGereon Kremer <gereon.kremer@cs.rwth-aachen.de>
Tue, 20 Apr 2021 22:10:17 +0000 (00:10 +0200)
committerGitHub <noreply@github.com>
Tue, 20 Apr 2021 22:10:17 +0000 (22:10 +0000)
This PR extends the resource manager to consider theory::InferenceId a resource we can spend. This should give us a robust way to have the resource limiting cover a lot of theory reasoning. To make use of this, TheoryInferenceManager now spends these resources.
Also, it makes the ResourceManager properly use the options from the Env class.

src/smt/env.cpp
src/smt/env.h
src/smt/smt_engine.cpp
src/theory/theory_inference_manager.cpp
src/util/resource_manager.cpp
src/util/resource_manager.h

index d079682c564fa232f09ab5ba72e4d27c0da421e3..9bb66f649546974afef13ff27caeb77676c39e12 100644 (file)
@@ -31,7 +31,7 @@ using namespace cvc5::smt;
 
 namespace cvc5 {
 
-Env::Env(NodeManager* nm)
+Env::Env(NodeManager* nm, Options* opts)
     : d_context(new context::Context()),
       d_userContext(new context::UserContext()),
       d_nodeManager(nm),
@@ -40,22 +40,18 @@ Env::Env(NodeManager* nm)
       d_dumpManager(new DumpManager(d_userContext.get())),
       d_logic(),
       d_statisticsRegistry(std::make_unique<StatisticsRegistry>()),
-      d_resourceManager(std::make_unique<ResourceManager>(*d_statisticsRegistry, d_options))
+      d_options(),
+      d_resourceManager()
 {
-}
-
-Env::~Env() {}
-
-void Env::setOptions(Options* optr)
-{
-  if (optr != nullptr)
+  if (opts != nullptr)
   {
-    // if we provided a set of options, copy their values to the options
-    // owned by this Env.
-    d_options.copyValues(*optr);
+    d_options.copyValues(*opts);
   }
+  d_resourceManager = std::make_unique<ResourceManager>(*d_statisticsRegistry, d_options);
 }
 
+Env::~Env() {}
+
 void Env::setProofNodeManager(ProofNodeManager* pnm)
 {
   d_proofNodeManager = pnm;
index 09e3238ac8396bd077fb67e28b42afe1c23ebf68..209b6f3e7dcf0ee0ccc05518af7d20bb3e150c7a 100644 (file)
@@ -60,7 +60,7 @@ class Env
   /**
    * Construct an Env with the given node manager.
    */
-  Env(NodeManager* nm);
+  Env(NodeManager* nm, Options* opts);
   /** Destruct the env.  */
   ~Env();
 
@@ -116,8 +116,6 @@ class Env
  private:
   /* Private initialization ------------------------------------------------- */
 
-  /** Set options, which makes a deep copy of optr if non-null */
-  void setOptions(Options* optr = nullptr);
   /** Set the statistics registry */
   void setStatisticsRegistry(StatisticsRegistry* statReg);
   /** Set proof node manager if it exists */
index 122e69488f69843779a91364f419966f19cdba73..3e64c5d23b1159d22289e9fe0b1a053590ab6188 100644 (file)
@@ -83,7 +83,7 @@ using namespace cvc5::theory;
 namespace cvc5 {
 
 SmtEngine::SmtEngine(NodeManager* nm, Options* optr)
-    : d_env(new Env(nm)),
+    : d_env(new Env(nm, optr)),
       d_state(new SmtEngineState(getContext(), getUserContext(), *this)),
       d_absValues(new AbstractValues(getNodeManager())),
       d_asserts(new Assertions(getUserContext(), *d_absValues.get())),
@@ -120,9 +120,6 @@ SmtEngine::SmtEngine(NodeManager* nm, Options* optr)
   // On the other hand, this hack breaks use cases where multiple SmtEngine
   // objects are created by the user.
   d_scope.reset(new SmtScope(this));
-  // Set options in the environment, which makes a deep copy of optr if
-  // non-null. This may throw an options exception.
-  d_env->setOptions(optr);
   // set the options manager
   d_optm.reset(new smt::OptionsManager(&getOptions()));
   // listen to node manager events
index 3bc7351feb2a967ecac432e1acaf2b7e0752f650..ad988e5345b862202b65fe98c8f0d75ae4a0064b 100644 (file)
@@ -15,6 +15,7 @@
 
 #include "theory/theory_inference_manager.h"
 
+#include "smt/smt_engine_scope.h"
 #include "smt/smt_statistics_registry.h"
 #include "theory/output_channel.h"
 #include "theory/rewriter.h"
@@ -118,6 +119,7 @@ void TheoryInferenceManager::conflict(TNode conf, InferenceId id)
 void TheoryInferenceManager::trustedConflict(TrustNode tconf, InferenceId id)
 {
   d_conflictIdStats << id;
+  smt::currentResourceManager()->spendResource(id);
   Trace("im") << "(conflict " << id << " " << tconf.getProven() << ")"
               << std::endl;
   d_theoryState.notifyInConflict();
@@ -250,6 +252,7 @@ bool TheoryInferenceManager::trustedLemma(const TrustNode& tlem,
     }
   }
   d_lemmaIdStats << id;
+  smt::currentResourceManager()->spendResource(id);
   Trace("im") << "(lemma " << id << " " << tlem.getProven() << ")" << std::endl;
   d_numCurrentLemmas++;
   d_out.trustedLemma(tlem, p);
@@ -370,6 +373,7 @@ bool TheoryInferenceManager::processInternalFact(TNode atom,
                                                  ProofGenerator* pg)
 {
   d_factIdStats << iid;
+  smt::currentResourceManager()->spendResource(iid);
   Trace("im") << "(fact " << iid << " " << (pol ? Node(atom) : atom.notNode())
               << ")" << std::endl;
   // make the node corresponding to the explanation
index 40cc415befdedb046be55b8df2c5ddb10360574a..f65f938b5622cd50c5b0cf49fcaaf8d1bc991f3e 100644 (file)
@@ -93,38 +93,29 @@ const char* toString(Resource r)
     default: return "?Resource?";
   }
 }
+std::ostream& operator<<(std::ostream& os, Resource r)
+{
+  return os << toString(r);
+}
 
 struct ResourceManager::Statistics
 {
   ReferenceStat<uint64_t> d_resourceUnitsUsed;
   IntStat d_spendResourceCalls;
-  std::vector<IntStat> d_resourceSteps;
+  HistogramStat<theory::InferenceId> d_inferenceIdSteps;
+  HistogramStat<Resource> d_resourceSteps;
   Statistics(StatisticsRegistry& stats);
-
-  void bump(Resource r, uint64_t amount)
-  {
-    bump_impl(static_cast<std::size_t>(r), amount, d_resourceSteps);
-  }
-
- private:
-  void bump_impl(std::size_t id, uint64_t amount, std::vector<IntStat>& stats)
-  {
-    Assert(stats.size() > id);
-    stats[id] += amount;
-  }
 };
 
 ResourceManager::Statistics::Statistics(StatisticsRegistry& stats)
     : d_resourceUnitsUsed(
         stats.registerReference<uint64_t>("resource::resourceUnitsUsed")),
-      d_spendResourceCalls(stats.registerInt("resource::spendResourceCalls"))
+      d_spendResourceCalls(stats.registerInt("resource::spendResourceCalls")),
+      d_inferenceIdSteps(stats.registerHistogram<theory::InferenceId>(
+          "resource::steps::inference-id")),
+      d_resourceSteps(
+          stats.registerHistogram<Resource>("resource::steps::resource"))
 {
-  for (std::size_t id = 0; id <= resman_detail::ResourceMax; ++id)
-  {
-    Resource r = static_cast<Resource>(id);
-    d_resourceSteps.emplace_back(
-        stats.registerInt("resource::res::" + std::string(toString(r))));
-  }
 }
 
 bool parseOption(const std::string& optarg, std::string& name, uint64_t& weight)
@@ -145,6 +136,7 @@ bool parseOption(const std::string& optarg, std::string& name, uint64_t& weight)
 template <typename T, typename Weights>
 bool setWeight(const std::string& name, uint64_t weight, Weights& weights)
 {
+  using theory::toString;
   for (std::size_t i = 0; i < weights.size(); ++i)
   {
     if (name == toString(static_cast<T>(i)))
@@ -167,6 +159,7 @@ ResourceManager::ResourceManager(StatisticsRegistry& stats, Options& options)
 {
   d_statistics->d_resourceUnitsUsed.set(d_cumulativeResourceUsed);
 
+  d_infidWeights.fill(1);
   d_resourceWeights.fill(1);
   for (const auto& opt :
        options[cvc5::options::resourceWeightHolder__option_t()])
@@ -175,6 +168,8 @@ ResourceManager::ResourceManager(StatisticsRegistry& stats, Options& options)
     uint64_t weight;
     if (parseOption(opt, name, weight))
     {
+      if (setWeight<theory::InferenceId>(name, weight, d_infidWeights))
+        continue;
       if (setWeight<Resource>(name, weight, d_resourceWeights)) continue;
       throw OptionException("Did not recognize resource type " + name);
     }
@@ -225,10 +220,18 @@ void ResourceManager::spendResource(Resource r)
 {
   std::size_t i = static_cast<std::size_t>(r);
   Assert(d_resourceWeights.size() > i);
-  d_statistics->bump(r, d_resourceWeights[i]);
+  d_statistics->d_resourceSteps << r;
   spendResource(d_resourceWeights[i]);
 }
 
+void ResourceManager::spendResource(theory::InferenceId iid)
+{
+  std::size_t i = static_cast<std::size_t>(iid);
+  Assert(d_infidWeights.size() > i);
+  d_statistics->d_inferenceIdSteps << iid;
+  spendResource(d_infidWeights[i]);
+}
+
 void ResourceManager::beginCall()
 {
   d_perCallTimer.set(options::perCallMillisecondLimit());
index 1ed7ee0d97efb536f2a32b07f0693f26457ce00b..2590799fcd80cfeb74e6d275fc20cca9fcadf1be 100644 (file)
@@ -27,6 +27,8 @@
 #include <memory>
 #include <vector>
 
+#include "theory/inference_id.h"
+
 namespace cvc5 {
 
 class Listener;
@@ -93,8 +95,13 @@ enum class Resource
 };
 
 const char* toString(Resource r);
+std::ostream& operator<<(std::ostream& os, Resource r);
 
 namespace resman_detail {
+/** The upper bound of values from the theory::InferenceId enum */
+constexpr std::size_t InferenceIdMax =
+    static_cast<std::size_t>(theory::InferenceId::UNKNOWN);
+/** The upper bound of values from the Resource enum */
 constexpr std::size_t ResourceMax = static_cast<std::size_t>(Resource::Unknown);
 };  // namespace resman_detail
 
@@ -141,6 +148,11 @@ class ResourceManager
    * no remaining resources.
    */
   void spendResource(Resource r);
+  /**
+   * Spends a given resource. Throws an UnsafeInterruptException if there are
+   * no remaining resources.
+   */
+  void spendResource(theory::InferenceId iid);
 
   /**
    * Resets perCall limits to mark the start of a new call,
@@ -183,9 +195,13 @@ class ResourceManager
 
   void spendResource(uint64_t amount);
 
+  /** Weights for InferenceId resources */
+  std::array<uint64_t, resman_detail::InferenceIdMax + 1> d_infidWeights;
+  /** Weights for Resource resources */
   std::array<uint64_t, resman_detail::ResourceMax + 1> d_resourceWeights;
 
   struct Statistics;
+  /** The statistics object */
   std::unique_ptr<Statistics> d_statistics;
 }; /* class ResourceManager */