Add oracle engine to quantifiers engine (#8589)
authorAndrew Reynolds <andrew.j.reynolds@gmail.com>
Mon, 11 Apr 2022 21:06:10 +0000 (16:06 -0500)
committerGitHub <noreply@github.com>
Mon, 11 Apr 2022 21:06:10 +0000 (16:06 -0500)
This class is the subsolver of quantifiers engine for handling oracles in SMTO. The implementation of this class will be added in followup PRs.

It also contains a utility method for constructing oracle interfaces.

src/CMakeLists.txt
src/options/quantifiers_options.toml
src/theory/quantifiers/oracle_engine.cpp [new file with mode: 0644]
src/theory/quantifiers/oracle_engine.h [new file with mode: 0644]
src/theory/quantifiers/quantifiers_modules.cpp
src/theory/quantifiers/quantifiers_modules.h
src/theory/quantifiers_engine.cpp
src/theory/quantifiers_engine.h

index 60627c4e8688ce76eaee47b26dc493a167a97e05..d9d185480262c72164627ad2c02bc3c80298070e 100644 (file)
@@ -827,6 +827,8 @@ libcvc5_add_sources(
   theory/quantifiers/lazy_trie.h
   theory/quantifiers/master_eq_notify.cpp
   theory/quantifiers/master_eq_notify.h
+  theory/quantifiers/oracle_engine.cpp
+  theory/quantifiers/oracle_engine.h
   theory/quantifiers/proof_checker.cpp
   theory/quantifiers/proof_checker.h
   theory/quantifiers/quant_bound_inference.cpp
index 199445117342bff401211e651640b17e6b1c5cda..bbd26f702c466c7ed23bdf0842864d0b3e41bca9 100644 (file)
@@ -559,6 +559,14 @@ name   = "Quantifiers"
   default    = "true"
   help       = "pool-based instantiation: instantiate with ground terms occurring in user-specified pools"
 
+[[option]]
+  name       = "oracles"
+  category   = "expert"
+  long       = "oracles"
+  type       = "bool"
+  default    = "false"
+  help       = "Enable interface to external oracles"
+
 ### Finite model finding options
 
 [[option]]
diff --git a/src/theory/quantifiers/oracle_engine.cpp b/src/theory/quantifiers/oracle_engine.cpp
new file mode 100644 (file)
index 0000000..19cec1d
--- /dev/null
@@ -0,0 +1,136 @@
+/******************************************************************************
+ * Top contributors (to current version):
+ *   Andrew Reynolds
+ *
+ * This file is part of the cvc5 project.
+ *
+ * Copyright (c) 2009-2021 by the authors listed in the file AUTHORS
+ * in the top-level source directory and their institutional affiliations.
+ * All rights reserved.  See the file COPYING in the top-level source
+ * directory for licensing information.
+ * ****************************************************************************
+ *
+ * Oracle engine
+ */
+
+#include "theory/quantifiers/oracle_engine.h"
+
+#include "expr/attribute.h"
+#include "expr/skolem_manager.h"
+#include "options/quantifiers_options.h"
+#include "theory/quantifiers/first_order_model.h"
+#include "theory/quantifiers/quantifiers_attributes.h"
+#include "theory/quantifiers/quantifiers_inference_manager.h"
+#include "theory/quantifiers/quantifiers_registry.h"
+#include "theory/quantifiers/term_registry.h"
+#include "theory/quantifiers/term_tuple_enumerator.h"
+
+using namespace cvc5::internal::kind;
+using namespace cvc5::context;
+
+namespace cvc5::internal {
+namespace theory {
+namespace quantifiers {
+
+/** Attribute true for input variables */
+struct OracleInputVarAttributeId
+{
+};
+typedef expr::Attribute<OracleInputVarAttributeId, bool>
+    OracleInputVarAttribute;
+/** Attribute true for output variables */
+struct OracleOutputVarAttributeId
+{
+};
+typedef expr::Attribute<OracleOutputVarAttributeId, bool>
+    OracleOutputVarAttribute;
+
+OracleEngine::OracleEngine(Env& env,
+                           QuantifiersState& qs,
+                           QuantifiersInferenceManager& qim,
+                           QuantifiersRegistry& qr,
+                           TermRegistry& tr)
+    : QuantifiersModule(env, qs, qim, qr, tr), d_oracleFuns(userContext())
+{
+}
+
+void OracleEngine::presolve() {}
+
+bool OracleEngine::needsCheck(Theory::Effort e)
+{
+  return e == Theory::Effort::EFFORT_LAST_CALL;
+}
+
+// the model is built at this effort level
+OracleEngine::QEffort OracleEngine::needsModel(Theory::Effort e)
+{
+  return QEFFORT_MODEL;
+}
+
+void OracleEngine::reset_round(Theory::Effort e) {}
+
+void OracleEngine::registerQuantifier(Node q) {}
+
+void OracleEngine::check(Theory::Effort e, QEffort quant_e) {}
+
+bool OracleEngine::checkCompleteFor(Node q) { return false; }
+
+void OracleEngine::checkOwnership(Node q) {}
+
+std::string OracleEngine::identify() const
+{
+  return std::string("OracleEngine");
+}
+
+void OracleEngine::declareOracleFun(Node f, const std::string& binName)
+{
+  OracleInterfaceAttribute oia;
+  f.setAttribute(oia, binName);
+  d_oracleFuns.push_back(f);
+}
+
+std::vector<Node> OracleEngine::getOracleFuns() const
+{
+  std::vector<Node> ofuns;
+  for (const Node& f : d_oracleFuns)
+  {
+    ofuns.push_back(f);
+  }
+  return ofuns;
+}
+
+Node OracleEngine::mkOracleInterface(const std::vector<Node>& inputs,
+                                     const std::vector<Node>& outputs,
+                                     Node assume,
+                                     Node constraint,
+                                     const std::string& binName)
+{
+  Assert(!assume.isNull());
+  Assert(!constraint.isNull());
+  NodeManager* nm = NodeManager::currentNM();
+  SkolemManager* sm = nm->getSkolemManager();
+  OracleInterfaceAttribute oia;
+  Node oiVar = sm->mkDummySkolem("oracle-interface", nm->booleanType());
+  oiVar.setAttribute(oia, binName);
+  Node ipl = nm->mkNode(INST_PATTERN_LIST, nm->mkNode(INST_ATTRIBUTE, oiVar));
+  std::vector<Node> vars;
+  OracleInputVarAttribute oiva;
+  for (Node v : inputs)
+  {
+    v.setAttribute(oiva, true);
+    vars.push_back(v);
+  }
+  OracleOutputVarAttribute oova;
+  for (Node v : outputs)
+  {
+    v.setAttribute(oova, true);
+    vars.push_back(v);
+  }
+  Node bvl = nm->mkNode(BOUND_VAR_LIST, vars);
+  Node body = nm->mkNode(ORACLE_FORMULA_GEN, assume, constraint);
+  return nm->mkNode(FORALL, bvl, body, ipl);
+}
+
+}  // namespace quantifiers
+}  // namespace theory
+}  // namespace cvc5::internal
diff --git a/src/theory/quantifiers/oracle_engine.h b/src/theory/quantifiers/oracle_engine.h
new file mode 100644 (file)
index 0000000..7b12e29
--- /dev/null
@@ -0,0 +1,101 @@
+/******************************************************************************
+ * Top contributors (to current version):
+ *   Andrew Reynolds, Elizabeth Polgreen
+ *
+ * This file is part of the cvc5 project.
+ *
+ * Copyright (c) 2009-2021 by the authors listed in the file AUTHORS
+ * in the top-level source directory and their institutional affiliations.
+ * All rights reserved.  See the file COPYING in the top-level source
+ * directory for licensing information.
+ * ****************************************************************************
+ *
+ * Oracle engine for SMTO
+ */
+
+#include "cvc5_private.h"
+
+#ifndef CVC5__THEORY__QUANTIFIERS__ORACLE_ENGINE_H
+#define CVC5__THEORY__QUANTIFIERS__ORACLE_ENGINE_H
+
+#include "theory/quantifiers/quant_module.h"
+
+namespace cvc5::internal {
+namespace theory {
+namespace quantifiers {
+
+/**
+ * Oracle engine
+ *
+ * This class manages the list of declared oracle functions and asserted
+ * oracle interfaces.
+ *
+ * For SMT modulo oracles (SMTO) queries, this class is responsible for
+ * invoking oracles, as specified by oracle interface quantifiers (see
+ * OracleInterfaceAttribute), until all oracle functions have consistent
+ * definitions with respect to the current model.
+ *
+ * In detail, an oracle function f has a consistent definition with respect to
+ * the current model M if all invocations f(t) in assertions are such that
+ * we have invoked its associated oracle on t^M and that invocation returned
+ * the value f(t)^M. This module is complete for oracle interface quantifiers
+ * if their associated oracle function has a consistent definition.
+ *
+ * For details, see Polgreen et al VMCAI 2022.
+ */
+class OracleEngine : public QuantifiersModule
+{
+ public:
+  OracleEngine(Env& env,
+               QuantifiersState& qs,
+               QuantifiersInferenceManager& qim,
+               QuantifiersRegistry& qr,
+               TermRegistry& tr);
+  ~OracleEngine() {}
+  /** Presolve */
+  void presolve() override;
+  /** Needs check. */
+  bool needsCheck(Theory::Effort e) override;
+  /** Needs model. */
+  QEffort needsModel(Theory::Effort e) override;
+  /** Reset round. */
+  void reset_round(Theory::Effort e) override;
+  /** Register quantified formula q */
+  void registerQuantifier(Node q) override;
+  /** Check.
+   * Adds instantiations for all currently asserted
+   * quantified formulas via calls to process(...)
+   */
+  void check(Theory::Effort e, QEffort quant_e) override;
+  /**
+   * Check was complete for quantified formula q, return true if we can say
+   * "sat" provided that q is currently asserted.
+   */
+  bool checkCompleteFor(Node q) override;
+  /** check ownership */
+  void checkOwnership(Node q) override;
+  /** Identify. */
+  std::string identify() const override;
+
+  /** Declare oracle fun */
+  void declareOracleFun(Node f, const std::string& binName);
+  /** Get the list of all declared oracle functions */
+  std::vector<Node> getOracleFuns() const;
+
+  /** Make an oracle interface quantifier */
+  static Node mkOracleInterface(const std::vector<Node>& inputs,
+                                const std::vector<Node>& outputs,
+                                Node assume,
+                                Node constraint,
+                                const std::string& binName);
+
+ private:
+  /** The oracle functions (user-context dependent) */
+  context::CDList<Node> d_oracleFuns;
+};
+
+}  // namespace quantifiers
+}  // namespace theory
+}  // namespace cvc5::internal
+
+#endif
index b6ba8620104ce5d5aec47f61cb5b76e33ff66ee6..2432182142c155efb399f1e3ea91d8e14655aaf2 100644 (file)
@@ -117,6 +117,11 @@ void QuantifiersModules::initialize(Env& env,
     d_sygus_inst.reset(new SygusInst(env, qs, qim, qr, tr));
     modules.push_back(d_sygus_inst.get());
   }
+  if (options.quantifiers.oracles)
+  {
+    d_oracleEngine.reset(new OracleEngine(env, qs, qim, qr, tr));
+    modules.push_back(d_oracleEngine.get());
+  }
 }
 
 }  // namespace quantifiers
index c0105359c107e410d2ef72742d0328f5d9e6c44a..599aaece1c28080be59ba2c6041816151c0ee7dd 100644 (file)
@@ -27,6 +27,7 @@
 #include "theory/quantifiers/fmf/model_engine.h"
 #include "theory/quantifiers/inst_strategy_enumerative.h"
 #include "theory/quantifiers/inst_strategy_pool.h"
+#include "theory/quantifiers/oracle_engine.h"
 #include "theory/quantifiers/quant_conflict_find.h"
 #include "theory/quantifiers/quant_split.h"
 #include "theory/quantifiers/sygus/synth_engine.h"
@@ -94,6 +95,8 @@ class QuantifiersModules
   std::unique_ptr<QuantDSplit> d_qsplit;
   /** SyGuS instantiation engine */
   std::unique_ptr<SygusInst> d_sygus_inst;
+  /** Oracle engine */
+  std::unique_ptr<OracleEngine> d_oracleEngine;
 };
 
 }  // namespace quantifiers
index 2e9eb1210a0ebee57e429a41be2cfb0b9c0978d8..0eaea7fe77690bcc19a3b6b8b86ccead2bbe2f3e 100644 (file)
@@ -702,5 +702,24 @@ void QuantifiersEngine::declarePool(Node p, const std::vector<Node>& initValue)
   d_treg.declarePool(p, initValue);
 }
 
+void QuantifiersEngine::declareOracleFun(Node f, const std::string& binName)
+{
+  if (d_qmodules->d_oracleEngine.get() == nullptr)
+  {
+    warning() << "Cannot declare oracle function when oracles are disabled"
+              << std::endl;
+    return;
+  }
+  d_qmodules->d_oracleEngine->declareOracleFun(f, binName);
+}
+std::vector<Node> QuantifiersEngine::getOracleFuns() const
+{
+  if (d_qmodules->d_oracleEngine.get() == nullptr)
+  {
+    return {};
+  }
+  return d_qmodules->d_oracleEngine->getOracleFuns();
+}
+
 }  // namespace theory
 }  // namespace cvc5::internal
index 7574f77ae325cb510f85248ddebae5d1352b5ff9..9da371430e38ddbdaf49bd2b3c5de059e941168d 100644 (file)
@@ -145,6 +145,10 @@ class QuantifiersEngine : protected EnvObj
   bool getSynthSolutions(std::map<Node, std::map<Node, Node> >& sol_map);
   /** Declare pool */
   void declarePool(Node p, const std::vector<Node>& initValue);
+  /** Declare oracle fun */
+  void declareOracleFun(Node f, const std::string& binName);
+  /** Get the list of all declared oracle functions */
+  std::vector<Node> getOracleFuns() const;
   //----------end user interface for instantiations
  private:
   //---------------------- private initialization