GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/quantifiers/sygus/template_infer.cpp Lines: 95 97 97.9 %
Date: 2021-11-07 Branches: 236 526 44.9 %

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