GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/quantifiers/sygus/template_infer.cpp Lines: 94 96 97.9 %
Date: 2021-09-16 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
332
void SygusTemplateInfer::initialize(Node q)
30
{
31
332
  Assert(d_quant.isNull());
32
332
  Assert(q.getKind() == FORALL);
33
332
  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
332
  options::SygusInvTemplMode tmode = options::sygusInvTemplMode();
38
332
  if (tmode != options::SygusInvTemplMode::NONE)
39
  {
40
    // currently only works for single predicate synthesis
41
307
    if (q[0].getNumChildren() > 1 || !q[0][0].getType().isPredicate())
42
    {
43
229
      tmode = options::SygusInvTemplMode::NONE;
44
    }
45
78
    else if (!options::sygusInvTemplWhenSyntax())
46
    {
47
      // only use invariant templates if no syntactic restrictions
48
78
      if (CegGrammarConstructor::hasSyntaxRestrictions(q))
49
      {
50
41
        tmode = options::SygusInvTemplMode::NONE;
51
      }
52
    }
53
  }
54
55
332
  if (tmode == options::SygusInvTemplMode::NONE)
56
  {
57
    // not processing invariant templates
58
596
    return;
59
  }
60
61
68
  Node qq;
62
37
  if (q[1].getKind() == NOT && q[1][0].getKind() == FORALL)
63
  {
64
31
    qq = q[1][0][1];
65
  }
66
  else
67
  {
68
6
    qq = TermUtil::simpleNegate(q[1]);
69
  }
70
37
  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
35
  Trace("sygus-si") << "- Do transition inference..." << std::endl;
78
35
  d_ti.process(qq, q[0][0]);
79
35
  Trace("cegqi-inv") << std::endl;
80
66
  Node prog = d_ti.getFunction();
81
35
  if (!d_ti.isComplete())
82
  {
83
    // the invariant could not be inferred
84
4
    return;
85
  }
86
31
  Assert(prog == q[0][0]);
87
31
  NodeManager* nm = NodeManager::currentNM();
88
31
  SkolemManager* sm = nm->getSkolemManager();
89
  // map the program back via non-single invocation map
90
62
  std::vector<Node> prog_templ_vars;
91
31
  d_ti.getVariables(prog_templ_vars);
92
31
  d_trans_pre[prog] = d_ti.getPreCondition();
93
31
  d_trans_post[prog] = d_ti.getPostCondition();
94
31
  Trace("cegqi-inv") << "   precondition : " << d_trans_pre[prog] << std::endl;
95
31
  Trace("cegqi-inv") << "  postcondition : " << d_trans_post[prog] << std::endl;
96
97
  // construct template argument
98
62
  TypeNode atn = prog.getType();
99
31
  if (atn.isFunction())
100
  {
101
31
    atn = atn.getRangeType();
102
  }
103
31
  d_templ_arg[prog] = sm->mkDummySkolem("I", atn);
104
105
  // construct template
106
62
  Node templ;
107
31
  if (options::sygusInvAutoUnfold())
108
  {
109
31
    if (d_ti.isComplete())
110
    {
111
62
      Trace("cegqi-inv-auto-unfold")
112
31
          << "Automatic deterministic unfolding... " << std::endl;
113
      // auto-unfold
114
62
      DetTrace dt;
115
31
      int init_dt = d_ti.initializeTrace(dt);
116
31
      if (init_dt == 0)
117
      {
118
8
        Trace("cegqi-inv-auto-unfold") << "  Init : ";
119
8
        dt.print("cegqi-inv-auto-unfold");
120
8
        Trace("cegqi-inv-auto-unfold") << std::endl;
121
8
        unsigned counter = 0;
122
8
        unsigned status = 0;
123
856
        while (counter < 100 && status == 0)
124
        {
125
424
          status = d_ti.incrementTrace(dt);
126
424
          counter++;
127
424
          Trace("cegqi-inv-auto-unfold") << "  #" << counter << " : ";
128
424
          dt.print("cegqi-inv-auto-unfold");
129
848
          Trace("cegqi-inv-auto-unfold")
130
424
              << "...status = " << status << std::endl;
131
        }
132
8
        if (status == 1)
133
        {
134
          // we have a trivial invariant
135
4
          templ = d_ti.constructFormulaTrace(dt);
136
8
          Trace("cegqi-inv") << "By finite deterministic terminating trace, a "
137
4
                                "solution invariant is : "
138
4
                             << std::endl;
139
4
          Trace("cegqi-inv") << "   " << templ << std::endl;
140
          // this should be unnecessary
141
4
          templ = nm->mkNode(AND, templ, d_templ_arg[prog]);
142
        }
143
      }
144
      else
145
      {
146
23
        Trace("cegqi-inv-auto-unfold") << "...failed initialize." << std::endl;
147
      }
148
    }
149
  }
150
62
  Trace("cegqi-inv") << "Make the template... " << tmode << " " << templ
151
31
                     << std::endl;
152
31
  if (templ.isNull())
153
  {
154
27
    if (tmode == options::SygusInvTemplMode::PRE)
155
    {
156
      templ = nm->mkNode(OR, d_trans_pre[prog], d_templ_arg[prog]);
157
    }
158
    else
159
    {
160
27
      Assert(tmode == options::SygusInvTemplMode::POST);
161
27
      templ = nm->mkNode(AND, d_trans_post[prog], d_templ_arg[prog]);
162
    }
163
  }
164
62
  Trace("cegqi-inv") << "       template (pre-substitution) : " << templ
165
31
                     << std::endl;
166
31
  Assert(!templ.isNull());
167
168
  // get the variables
169
62
  Node sfvl = SygusUtils::getSygusArgumentListForSynthFun(prog);
170
31
  if (!sfvl.isNull())
171
  {
172
62
    std::vector<Node> prog_vars(sfvl.begin(), sfvl.end());
173
    // subsitute the template arguments
174
62
    Trace("cegqi-inv") << "vars : " << prog_templ_vars << " " << prog_vars
175
31
                       << std::endl;
176
31
    Assert(prog_templ_vars.size() == prog_vars.size());
177
31
    templ = templ.substitute(prog_templ_vars.begin(),
178
                             prog_templ_vars.end(),
179
                             prog_vars.begin(),
180
                             prog_vars.end());
181
  }
182
31
  Trace("cegqi-inv") << "       template : " << templ << std::endl;
183
31
  d_templ[prog] = templ;
184
}
185
186
1852
Node SygusTemplateInfer::getTemplate(Node prog) const
187
{
188
1852
  std::map<Node, Node>::const_iterator tmpl = d_templ.find(prog);
189
1852
  if (tmpl != d_templ.end())
190
  {
191
48
    return tmpl->second;
192
  }
193
1804
  return Node::null();
194
}
195
196
48
Node SygusTemplateInfer::getTemplateArg(Node prog) const
197
{
198
48
  std::map<Node, Node>::const_iterator tmpla = d_templ_arg.find(prog);
199
48
  if (tmpla != d_templ_arg.end())
200
  {
201
48
    return tmpla->second;
202
  }
203
  return Node::null();
204
}
205
206
}  // namespace quantifiers
207
}  // namespace theory
208
29577
}  // namespace cvc5