GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/quantifiers/sygus/template_infer.cpp Lines: 94 96 97.9 %
Date: 2021-11-05 Branches: 234 522 44.8 %

Line Exec Source
1
/******************************************************************************
2
 * Top contributors (to current version):
3
 *   Andrew Reynolds, Mathias Preiner, Aina Niemetz
4
 *
5
 * This file is part of the cvc5 project.
6
 *
7
 * Copyright (c) 2009-2021 by the authors listed in the file AUTHORS
8
 * in the top-level source directory and their institutional affiliations.
9
 * All rights reserved.  See the file COPYING in the top-level source
10
 * directory for licensing information.
11
 * ****************************************************************************
12
 *
13
 * Utility for processing single invocation synthesis conjectures.
14
 */
15
#include "theory/quantifiers/sygus/template_infer.h"
16
17
#include "expr/skolem_manager.h"
18
#include "options/quantifiers_options.h"
19
#include "theory/quantifiers/sygus/sygus_grammar_cons.h"
20
#include "theory/quantifiers/sygus/sygus_utils.h"
21
#include "theory/quantifiers/term_util.h"
22
23
using namespace cvc5::kind;
24
25
namespace cvc5 {
26
namespace theory {
27
namespace quantifiers {
28
29
542
void SygusTemplateInfer::initialize(Node q)
30
{
31
542
  Assert(d_quant.isNull());
32
542
  Assert(q.getKind() == FORALL);
33
542
  d_quant = q;
34
  // We are processing without single invocation techniques, now check if
35
  // we should fix an invariant template (post-condition strengthening or
36
  // pre-condition weakening).
37
542
  options::SygusInvTemplMode tmode = options::sygusInvTemplMode();
38
542
  if (tmode != options::SygusInvTemplMode::NONE)
39
  {
40
    // currently only works for single predicate synthesis
41
486
    if (q[0].getNumChildren() > 1 || !q[0][0].getType().isPredicate())
42
    {
43
365
      tmode = options::SygusInvTemplMode::NONE;
44
    }
45
121
    else if (!options::sygusInvTemplWhenSyntax())
46
    {
47
      // only use invariant templates if no syntactic restrictions
48
121
      if (CegGrammarConstructor::hasSyntaxRestrictions(q))
49
      {
50
65
        tmode = options::SygusInvTemplMode::NONE;
51
      }
52
    }
53
  }
54
55
542
  if (tmode == options::SygusInvTemplMode::NONE)
56
  {
57
    // not processing invariant templates
58
982
    return;
59
  }
60
61
102
  Node qq;
62
56
  if (q[1].getKind() == NOT && q[1][0].getKind() == FORALL)
63
  {
64
48
    qq = q[1][0][1];
65
  }
66
  else
67
  {
68
8
    qq = TermUtil::simpleNegate(q[1]);
69
  }
70
56
  if (qq.isConst())
71
  {
72
    // trivial, do not use transition inference
73
2
    return;
74
  }
75
76
  // if we are doing invariant templates, then construct the template
77
54
  Trace("sygus-si") << "- Do transition inference..." << std::endl;
78
54
  d_ti.process(qq, q[0][0]);
79
54
  Trace("cegqi-inv") << std::endl;
80
100
  Node prog = d_ti.getFunction();
81
54
  if (!d_ti.isComplete())
82
  {
83
    // the invariant could not be inferred
84
8
    return;
85
  }
86
46
  Assert(prog == q[0][0]);
87
46
  NodeManager* nm = NodeManager::currentNM();
88
46
  SkolemManager* sm = nm->getSkolemManager();
89
  // map the program back via non-single invocation map
90
92
  std::vector<Node> prog_templ_vars;
91
46
  d_ti.getVariables(prog_templ_vars);
92
46
  d_trans_pre[prog] = d_ti.getPreCondition();
93
46
  d_trans_post[prog] = d_ti.getPostCondition();
94
46
  Trace("cegqi-inv") << "   precondition : " << d_trans_pre[prog] << std::endl;
95
46
  Trace("cegqi-inv") << "  postcondition : " << d_trans_post[prog] << std::endl;
96
97
  // construct template argument
98
92
  TypeNode atn = prog.getType();
99
46
  if (atn.isFunction())
100
  {
101
46
    atn = atn.getRangeType();
102
  }
103
46
  d_templ_arg[prog] = sm->mkDummySkolem("I", atn);
104
105
  // construct template
106
92
  Node templ;
107
46
  if (options::sygusInvAutoUnfold())
108
  {
109
46
    if (d_ti.isComplete())
110
    {
111
92
      Trace("cegqi-inv-auto-unfold")
112
46
          << "Automatic deterministic unfolding... " << std::endl;
113
      // auto-unfold
114
92
      DetTrace dt;
115
46
      int init_dt = d_ti.initializeTrace(dt);
116
46
      if (init_dt == 0)
117
      {
118
10
        Trace("cegqi-inv-auto-unfold") << "  Init : ";
119
10
        dt.print("cegqi-inv-auto-unfold");
120
10
        Trace("cegqi-inv-auto-unfold") << std::endl;
121
10
        unsigned counter = 0;
122
10
        unsigned status = 0;
123
1068
        while (counter < 100 && status == 0)
124
        {
125
529
          status = d_ti.incrementTrace(dt);
126
529
          counter++;
127
529
          Trace("cegqi-inv-auto-unfold") << "  #" << counter << " : ";
128
529
          dt.print("cegqi-inv-auto-unfold");
129
1058
          Trace("cegqi-inv-auto-unfold")
130
529
              << "...status = " << status << std::endl;
131
        }
132
10
        if (status == 1)
133
        {
134
          // we have a trivial invariant
135
5
          templ = d_ti.constructFormulaTrace(dt);
136
10
          Trace("cegqi-inv") << "By finite deterministic terminating trace, a "
137
5
                                "solution invariant is : "
138
5
                             << std::endl;
139
5
          Trace("cegqi-inv") << "   " << templ << std::endl;
140
          // this should be unnecessary
141
5
          templ = nm->mkNode(AND, templ, d_templ_arg[prog]);
142
        }
143
      }
144
      else
145
      {
146
36
        Trace("cegqi-inv-auto-unfold") << "...failed initialize." << std::endl;
147
      }
148
    }
149
  }
150
92
  Trace("cegqi-inv") << "Make the template... " << tmode << " " << templ
151
46
                     << std::endl;
152
46
  if (templ.isNull())
153
  {
154
41
    if (tmode == options::SygusInvTemplMode::PRE)
155
    {
156
      templ = nm->mkNode(OR, d_trans_pre[prog], d_templ_arg[prog]);
157
    }
158
    else
159
    {
160
41
      Assert(tmode == options::SygusInvTemplMode::POST);
161
41
      templ = nm->mkNode(AND, d_trans_post[prog], d_templ_arg[prog]);
162
    }
163
  }
164
92
  Trace("cegqi-inv") << "       template (pre-substitution) : " << templ
165
46
                     << std::endl;
166
46
  Assert(!templ.isNull());
167
168
  // get the variables
169
92
  Node sfvl = SygusUtils::getSygusArgumentListForSynthFun(prog);
170
46
  if (!sfvl.isNull())
171
  {
172
92
    std::vector<Node> prog_vars(sfvl.begin(), sfvl.end());
173
    // subsitute the template arguments
174
92
    Trace("cegqi-inv") << "vars : " << prog_templ_vars << " " << prog_vars
175
46
                       << std::endl;
176
46
    Assert(prog_templ_vars.size() == prog_vars.size());
177
46
    templ = templ.substitute(prog_templ_vars.begin(),
178
                             prog_templ_vars.end(),
179
                             prog_vars.begin(),
180
                             prog_vars.end());
181
  }
182
46
  Trace("cegqi-inv") << "       template : " << templ << std::endl;
183
46
  d_templ[prog] = templ;
184
}
185
186
3098
Node SygusTemplateInfer::getTemplate(Node prog) const
187
{
188
3098
  std::map<Node, Node>::const_iterator tmpl = d_templ.find(prog);
189
3098
  if (tmpl != d_templ.end())
190
  {
191
63
    return tmpl->second;
192
  }
193
3035
  return Node::null();
194
}
195
196
63
Node SygusTemplateInfer::getTemplateArg(Node prog) const
197
{
198
63
  std::map<Node, Node>::const_iterator tmpla = d_templ_arg.find(prog);
199
63
  if (tmpla != d_templ_arg.end())
200
  {
201
63
    return tmpla->second;
202
  }
203
  return Node::null();
204
}
205
206
}  // namespace quantifiers
207
}  // namespace theory
208
31125
}  // namespace cvc5