LCOV - code coverage report
Current view: top level - buildbot/coverage/build/src/theory/quantifiers/sygus - sygus_abduct.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 86 88 97.7 %
Date: 2026-05-05 10:35:20 Functions: 1 2 50.0 %
Branches: 67 110 60.9 %

           Branch data     Line data    Source code
       1                 :            : /******************************************************************************
       2                 :            :  * This file is part of the cvc5 project.
       3                 :            :  *
       4                 :            :  * Copyright (c) 2009-2026 by the authors listed in the file AUTHORS
       5                 :            :  * in the top-level source directory and their institutional affiliations.
       6                 :            :  * All rights reserved.  See the file COPYING in the top-level source
       7                 :            :  * directory for licensing information.
       8                 :            :  * ****************************************************************************
       9                 :            :  *
      10                 :            :  * Implementation of sygus abduction utility, which transforms an arbitrary
      11                 :            :  * input into an abduction problem.
      12                 :            :  */
      13                 :            : 
      14                 :            : #include "theory/quantifiers/sygus/sygus_abduct.h"
      15                 :            : 
      16                 :            : #include <sstream>
      17                 :            : 
      18                 :            : #include "expr/dtype.h"
      19                 :            : #include "expr/node_algorithm.h"
      20                 :            : #include "expr/skolem_manager.h"
      21                 :            : #include "theory/datatypes/sygus_datatype_utils.h"
      22                 :            : #include "theory/quantifiers/quantifiers_attributes.h"
      23                 :            : #include "theory/quantifiers/quantifiers_rewriter.h"
      24                 :            : #include "theory/quantifiers/sygus/sygus_utils.h"
      25                 :            : #include "theory/quantifiers/term_util.h"
      26                 :            : 
      27                 :            : using namespace std;
      28                 :            : using namespace cvc5::internal::kind;
      29                 :            : 
      30                 :            : namespace cvc5::internal {
      31                 :            : namespace theory {
      32                 :            : namespace quantifiers {
      33                 :            : 
      34                 :          0 : SygusAbduct::SygusAbduct() {}
      35                 :            : 
      36                 :        416 : Node SygusAbduct::mkAbductionConjecture(NodeManager* nm,
      37                 :            :                                         const std::string& name,
      38                 :            :                                         const std::vector<Node>& asserts,
      39                 :            :                                         const std::vector<Node>& axioms,
      40                 :            :                                         TypeNode abdGType)
      41                 :            : {
      42                 :        416 :   std::unordered_set<Node> symset;
      43         [ +  + ]:       1363 :   for (size_t i = 0, size = asserts.size(); i < size; i++)
      44                 :            :   {
      45                 :        947 :     expr::getSymbols(asserts[i], symset);
      46                 :            :   }
      47         [ +  - ]:        832 :   Trace("sygus-abduct-debug")
      48                 :        416 :       << "...finish, got " << symset.size() << " symbols." << std::endl;
      49                 :            : 
      50         [ +  - ]:        416 :   Trace("sygus-abduct-debug") << "Setup symbols..." << std::endl;
      51                 :        416 :   std::vector<Node> syms;
      52                 :        416 :   std::vector<Node> vars;
      53                 :        416 :   std::vector<Node> varlist;
      54                 :        416 :   std::vector<TypeNode> varlistTypes;
      55         [ +  + ]:       1173 :   for (const Node& s : symset)
      56                 :            :   {
      57                 :        757 :     TypeNode tn = s.getType();
      58         [ +  + ]:       1508 :     if (tn.isDatatypeConstructor() || tn.isDatatypeSelector()
      59 [ +  + ][ +  + ]:       1508 :         || tn.isDatatypeTester() || tn.isDatatypeUpdater())
         [ -  + ][ +  + ]
      60                 :            :     {
      61                 :            :       // datatype symbols should be considered interpreted symbols here, not
      62                 :            :       // (higher-order) variables.
      63                 :         12 :       continue;
      64                 :            :     }
      65                 :            :     // Notice that we allow for non-first class (e.g. function) variables here.
      66                 :            :     // This is applicable to the case where we are doing get-abduct in a logic
      67                 :            :     // with UF.
      68                 :        745 :     std::stringstream ss;
      69                 :        745 :     ss << s;
      70                 :        745 :     Node var = NodeManager::mkBoundVar(tn);
      71                 :        745 :     syms.push_back(s);
      72                 :        745 :     vars.push_back(var);
      73                 :        745 :     Node vlv = NodeManager::mkBoundVar(ss.str(), tn);
      74                 :        745 :     varlist.push_back(vlv);
      75                 :        745 :     varlistTypes.push_back(tn);
      76                 :            :     // set that this variable encodes the term s
      77                 :            :     SygusVarToTermAttribute sta;
      78                 :        745 :     vlv.setAttribute(sta, s);
      79         [ +  + ]:        757 :   }
      80         [ +  - ]:        416 :   Trace("sygus-abduct-debug") << "...finish" << std::endl;
      81                 :            : 
      82         [ +  - ]:        416 :   Trace("sygus-abduct-debug") << "Make abduction predicate..." << std::endl;
      83                 :            :   // make the abduction predicate to synthesize
      84                 :        416 :   TypeNode abdType = varlistTypes.empty() ? nm->booleanType()
      85         [ +  + ]:        416 :                                           : nm->mkPredicateType(varlistTypes);
      86                 :        832 :   Node abd = NodeManager::mkBoundVar(name.c_str(), abdType);
      87         [ +  - ]:        416 :   Trace("sygus-abduct-debug") << "...finish" << std::endl;
      88                 :            : 
      89                 :            :   // the sygus variable list
      90                 :        416 :   Node abvl;
      91                 :            :   // if provided, we will associate the provide sygus datatype type with the
      92                 :            :   // function-to-synthesize. However, we must convert it so that its
      93                 :            :   // free symbols are universally quantified.
      94         [ +  + ]:        416 :   if (!abdGType.isNull())
      95                 :            :   {
      96 [ +  - ][ +  - ]:        183 :     Assert(abdGType.isDatatype() && abdGType.getDType().isSygus());
         [ -  + ][ -  + ]
                 [ -  - ]
      97         [ +  - ]:        183 :     Trace("sygus-abduct-debug") << "Process abduction type:" << std::endl;
      98 [ +  - ][ -  + ]:        183 :     Trace("sygus-abduct-debug") << abdGType.getDType().getName() << std::endl;
                 [ -  - ]
      99                 :            : 
     100                 :            :     // substitute the free symbols of the grammar with variables corresponding
     101                 :            :     // to the formal argument list of the new sygus datatype type.
     102                 :            :     TypeNode abdGTypeS = datatypes::utils::substituteAndGeneralizeSygusType(
     103                 :        183 :         abdGType, syms, varlist);
     104                 :            : 
     105 [ +  - ][ +  - ]:        183 :     Assert(abdGTypeS.isDatatype() && abdGTypeS.getDType().isSygus());
         [ -  + ][ -  + ]
                 [ -  - ]
     106                 :            : 
     107         [ +  - ]:        366 :     Trace("sygus-abduct-debug")
     108                 :        183 :         << "Make sygus grammar attribute..." << std::endl;
     109                 :            :     // Set the sygus grammar attribute to indicate that abdGTypeS encodes the
     110                 :            :     // grammar for abd.
     111                 :        183 :     SygusUtils::setSygusType(abd, abdGTypeS);
     112         [ +  - ]:        183 :     Trace("sygus-abduct-debug") << "Finished setting up grammar." << std::endl;
     113                 :            : 
     114                 :            :     // use the bound variable list from the new substituted grammar type
     115                 :        183 :     const DType& agtsd = abdGTypeS.getDType();
     116                 :        183 :     abvl = agtsd.getSygusVarList();
     117 [ +  - ][ +  - ]:        183 :     Assert(!abvl.isNull() && abvl.getKind() == Kind::BOUND_VAR_LIST);
         [ -  + ][ -  + ]
                 [ -  - ]
     118                 :        183 :   }
     119         [ +  + ]:        233 :   else if (!varlist.empty())
     120                 :            :   {
     121                 :            :     // the bound variable list of the abduct-to-synthesize is determined by
     122                 :            :     // the variable list above
     123                 :        223 :     abvl = nm->mkNode(Kind::BOUND_VAR_LIST, varlist);
     124                 :            :     // We do not set a grammar type for abd (SygusSynthGrammarAttribute).
     125                 :            :     // Its grammar will be constructed internally in the default way
     126                 :            :   }
     127                 :            : 
     128         [ +  - ]:        416 :   Trace("sygus-abduct-debug") << "Make abduction predicate app..." << std::endl;
     129                 :        416 :   std::vector<Node> achildren;
     130                 :        416 :   achildren.push_back(abd);
     131                 :        416 :   achildren.insert(achildren.end(), vars.begin(), vars.end());
     132         [ +  + ]:        416 :   Node abdApp = vars.empty() ? abd : nm->mkNode(Kind::APPLY_UF, achildren);
     133         [ +  - ]:        416 :   Trace("sygus-abduct-debug") << "...finish" << std::endl;
     134                 :            : 
     135         [ +  - ]:        416 :   Trace("sygus-abduct-debug") << "Set attributes..." << std::endl;
     136                 :            :   // set the sygus bound variable list
     137                 :        416 :   SygusUtils::setSygusArgumentList(abd, abvl);
     138         [ +  - ]:        416 :   Trace("sygus-abduct-debug") << "...finish" << std::endl;
     139                 :            : 
     140         [ +  - ]:        416 :   Trace("sygus-abduct-debug") << "Make conjecture body..." << std::endl;
     141                 :            :   Node input =
     142         [ +  + ]:        416 :       asserts.size() == 1 ? asserts[0] : nm->mkNode(Kind::AND, asserts);
     143                 :        416 :   input = input.substitute(syms.begin(), syms.end(), vars.begin(), vars.end());
     144                 :            :   // A(x) => ~input( x )
     145 [ +  + ][ -  - ]:       1248 :   input = nm->mkNode(Kind::OR, {abdApp.negate(), input.negate()});
     146         [ +  - ]:        416 :   Trace("sygus-abduct-debug") << "...finish" << std::endl;
     147                 :            : 
     148         [ +  - ]:        416 :   Trace("sygus-abduct-debug") << "Make conjecture..." << std::endl;
     149                 :        416 :   Node res = input.negate();
     150         [ +  + ]:        416 :   if (!vars.empty())
     151                 :            :   {
     152                 :        406 :     Node bvl = nm->mkNode(Kind::BOUND_VAR_LIST, vars);
     153                 :            :     // exists x. ~( A( x ) => ~input( x ) )
     154                 :        406 :     res = nm->mkNode(Kind::EXISTS, bvl, res);
     155                 :        406 :   }
     156                 :            :   // sygus attribute
     157                 :            :   Node aconj =
     158                 :        416 :       axioms.size() == 0
     159                 :          0 :           ? nm->mkConst(true)
     160 [ +  + ][ +  + ]:        416 :           : (axioms.size() == 1 ? axioms[0] : nm->mkNode(Kind::AND, axioms));
     161                 :        416 :   aconj = aconj.substitute(syms.begin(), syms.end(), vars.begin(), vars.end());
     162         [ +  - ]:        416 :   Trace("sygus-abduct") << "---> Assumptions: " << aconj << std::endl;
     163                 :        832 :   Node sc = nm->mkNode(Kind::AND, aconj, abdApp);
     164         [ +  + ]:        416 :   if (!vars.empty())
     165                 :            :   {
     166                 :        406 :     Node vbvl = nm->mkNode(Kind::BOUND_VAR_LIST, vars);
     167                 :        406 :     sc = nm->mkNode(Kind::EXISTS, vbvl, sc);
     168                 :        406 :   }
     169                 :        832 :   Node sygusScVar = NodeManager::mkDummySkolem("sygus_sc", nm->booleanType());
     170                 :        416 :   sygusScVar.setAttribute(theory::SygusSideConditionAttribute(), sc);
     171                 :        416 :   Node instAttr = nm->mkNode(Kind::INST_ATTRIBUTE, sygusScVar);
     172                 :            :   // build in the side condition
     173                 :            :   //   exists x. A( x ) ^ input_axioms( x )
     174                 :            :   // as an additional annotation on the sygus conjecture. In other words,
     175                 :            :   // the abducts A we procedure must be consistent with our axioms.
     176                 :            : 
     177                 :            :   // forall A. exists x. ~( A( x ) => ~input( x ) )
     178                 :       1248 :   res = SygusUtils::mkSygusConjecture(nm, {abd}, res, {instAttr});
     179         [ +  - ]:        416 :   Trace("sygus-abduct-debug") << "...finish" << std::endl;
     180                 :            : 
     181         [ +  - ]:        416 :   Trace("sygus-abduct") << "Generate: " << res << std::endl;
     182                 :            : 
     183                 :        832 :   return res;
     184                 :        416 : }
     185                 :            : 
     186                 :            : }  // namespace quantifiers
     187                 :            : }  // namespace theory
     188                 :            : }  // namespace cvc5::internal

Generated by: LCOV version 1.14