GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/sep/theory_sep.h Lines: 18 32 56.3 %
Date: 2021-05-22 Branches: 21 102 20.6 %

Line Exec Source
1
/******************************************************************************
2
 * Top contributors (to current version):
3
 *   Andrew Reynolds, Tim King, Haniel Barbosa
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
 * Theory of separation logic.
14
 */
15
16
#include "cvc5_private.h"
17
18
#ifndef CVC5__THEORY__SEP__THEORY_SEP_H
19
#define CVC5__THEORY__SEP__THEORY_SEP_H
20
21
#include "context/cdhashmap.h"
22
#include "context/cdhashset.h"
23
#include "context/cdlist.h"
24
#include "context/cdqueue.h"
25
#include "theory/decision_strategy.h"
26
#include "theory/inference_manager_buffered.h"
27
#include "theory/sep/theory_sep_rewriter.h"
28
#include "theory/theory.h"
29
#include "theory/theory_state.h"
30
#include "theory/uf/equality_engine.h"
31
#include "util/statistics_stats.h"
32
33
namespace cvc5 {
34
namespace theory {
35
36
class TheoryModel;
37
38
namespace sep {
39
40
class TheorySep : public Theory {
41
  typedef context::CDList<Node> NodeList;
42
  typedef context::CDHashSet<Node> NodeSet;
43
  typedef context::CDHashMap<Node, Node> NodeNodeMap;
44
45
  /////////////////////////////////////////////////////////////////////////////
46
  // MISC
47
  /////////////////////////////////////////////////////////////////////////////
48
49
 private:
50
  /** all lemmas sent */
51
  NodeSet d_lemmas_produced_c;
52
53
  /** True node for predicates = true */
54
  Node d_true;
55
56
  /** True node for predicates = false */
57
  Node d_false;
58
59
  //whether bounds have been initialized
60
  bool d_bounds_init;
61
62
  TheorySepRewriter d_rewriter;
63
  /** A (default) theory state object */
64
  TheoryState d_state;
65
  /** A buffered inference manager */
66
  InferenceManagerBuffered d_im;
67
68
  Node mkAnd( std::vector< TNode >& assumptions );
69
70
  int processAssertion(
71
      Node n,
72
      std::map<int, std::map<Node, int> >& visited,
73
      std::map<int, std::map<Node, std::vector<Node> > >& references,
74
      std::map<int, std::map<Node, bool> >& references_strict,
75
      bool pol,
76
      bool hasPol,
77
      bool underSpatial);
78
79
 public:
80
  TheorySep(context::Context* c,
81
            context::UserContext* u,
82
            OutputChannel& out,
83
            Valuation valuation,
84
            const LogicInfo& logicInfo,
85
            ProofNodeManager* pnm = nullptr);
86
  ~TheorySep();
87
88
  /**
89
   * Declare heap. For smt2 inputs, this is called when the command
90
   * (declare-heap (locT datat)) is invoked by the user. This sets locT as the
91
   * location type and dataT is the data type for the heap. This command can be
92
   * executed once only, and must be invoked before solving separation logic
93
   * inputs.
94
   */
95
  void declareSepHeap(TypeNode locT, TypeNode dataT) override;
96
97
  //--------------------------------- initialization
98
  /** get the official theory rewriter of this theory */
99
  TheoryRewriter* getTheoryRewriter() override;
100
  /** get the proof checker of this theory */
101
  ProofRuleChecker* getProofChecker() override;
102
  /**
103
   * Returns true if we need an equality engine. If so, we initialize the
104
   * information regarding how it should be setup. For details, see the
105
   * documentation in Theory::needsEqualityEngine.
106
   */
107
  bool needsEqualityEngine(EeSetupInfo& esi) override;
108
  /** finish initialization */
109
  void finishInit() override;
110
  //--------------------------------- end initialization
111
  /** preregister term */
112
  void preRegisterTerm(TNode n) override;
113
114
  std::string identify() const override { return std::string("TheorySep"); }
115
116
  /////////////////////////////////////////////////////////////////////////////
117
  // PREPROCESSING
118
  /////////////////////////////////////////////////////////////////////////////
119
120
 public:
121
  void ppNotifyAssertions(const std::vector<Node>& assertions) override;
122
  /////////////////////////////////////////////////////////////////////////////
123
  // T-PROPAGATION / REGISTRATION
124
  /////////////////////////////////////////////////////////////////////////////
125
126
 private:
127
  /** Should be called to propagate the literal.  */
128
  bool propagateLit(TNode literal);
129
  /** Conflict when merging constants */
130
  void conflict(TNode a, TNode b);
131
132
 public:
133
  TrustNode explain(TNode n) override;
134
135
 public:
136
  void computeCareGraph() override;
137
138
  /////////////////////////////////////////////////////////////////////////////
139
  // MODEL GENERATION
140
  /////////////////////////////////////////////////////////////////////////////
141
142
 public:
143
  void postProcessModel(TheoryModel* m) override;
144
145
  /////////////////////////////////////////////////////////////////////////////
146
  // NOTIFICATIONS
147
  /////////////////////////////////////////////////////////////////////////////
148
149
 public:
150
151
  void presolve() override;
152
9454
  void shutdown() override {}
153
154
  /////////////////////////////////////////////////////////////////////////////
155
  // MAIN SOLVER
156
  /////////////////////////////////////////////////////////////////////////////
157
158
  //--------------------------------- standard check
159
  /** Do we need a check call at last call effort? */
160
  bool needsCheckLastEffort() override;
161
  /** Post-check, called after the fact queue of the theory is processed. */
162
  void postCheck(Effort level) override;
163
  /** Pre-notify fact, return true if processed. */
164
  bool preNotifyFact(TNode atom,
165
                     bool pol,
166
                     TNode fact,
167
                     bool isPrereg,
168
                     bool isInternal) override;
169
  /** Notify fact */
170
  void notifyFact(TNode atom, bool pol, TNode fact, bool isInternal) override;
171
  //--------------------------------- end standard check
172
173
 private:
174
  /** Ensures that the reduction has been added for the given fact */
175
  void reduceFact(TNode atom, bool polarity, TNode fact);
176
  /** Is spatial kind? */
177
  bool isSpatialKind(Kind k) const;
178
  // NotifyClass: template helper class for d_equalityEngine - handles
179
  // call-back from congruence closure module
180
9460
  class NotifyClass : public eq::EqualityEngineNotify
181
  {
182
    TheorySep& d_sep;
183
184
   public:
185
9460
    NotifyClass(TheorySep& sep) : d_sep(sep) {}
186
187
    bool eqNotifyTriggerPredicate(TNode predicate, bool value) override
188
    {
189
      Debug("sep::propagate")
190
          << "NotifyClass::eqNotifyTriggerPredicate(" << predicate << ", "
191
          << (value ? "true" : "false") << ")" << std::endl;
192
      Assert(predicate.getKind() == kind::EQUAL);
193
      // Just forward to sep
194
      if (value)
195
      {
196
        return d_sep.propagateLit(predicate);
197
      }
198
      return d_sep.propagateLit(predicate.notNode());
199
    }
200
3765
    bool eqNotifyTriggerTermEquality(TheoryId tag,
201
                                     TNode t1,
202
                                     TNode t2,
203
                                     bool value) override
204
    {
205
7530
      Debug("sep::propagate")
206
3765
          << "NotifyClass::eqNotifyTriggerTermEquality(" << t1 << ", " << t2
207
3765
          << ", " << (value ? "true" : "false") << ")" << std::endl;
208
3765
      if (value)
209
      {
210
        // Propagate equality between shared terms
211
1205
        return d_sep.propagateLit(t1.eqNode(t2));
212
      }
213
2560
      return d_sep.propagateLit(t1.eqNode(t2).notNode());
214
    }
215
216
    void eqNotifyConstantTermMerge(TNode t1, TNode t2) override
217
    {
218
      Debug("sep::propagate") << "NotifyClass::eqNotifyConstantTermMerge(" << t1
219
                              << ", " << t2 << ")" << std::endl;
220
      d_sep.conflict(t1, t2);
221
    }
222
223
3411
    void eqNotifyNewClass(TNode t) override {}
224
4832
    void eqNotifyMerge(TNode t1, TNode t2) override
225
    {
226
4832
      d_sep.eqNotifyMerge(t1, t2);
227
4832
    }
228
2560
    void eqNotifyDisequal(TNode t1, TNode t2, TNode reason) override {}
229
  };
230
231
  /** The notify class for d_equalityEngine */
232
  NotifyClass d_notify;
233
234
  /** list of all refinement lemms */
235
  std::map< Node, std::map< Node, std::vector< Node > > > d_refinement_lem;
236
237
  //cache for positive polarity start reduction
238
  NodeSet d_reduce;
239
  std::map< Node, std::map< Node, Node > > d_red_conc;
240
  std::map< Node, std::map< Node, Node > > d_neg_guard;
241
  std::vector< Node > d_neg_guards;
242
  /** a (singleton) decision strategy for each negative guard. */
243
  std::map<Node, std::unique_ptr<DecisionStrategySingleton> >
244
      d_neg_guard_strategy;
245
  std::map< Node, Node > d_guard_to_assertion;
246
  NodeList d_spatial_assertions;
247
248
  //data,ref type (globally fixed)
249
  TypeNode d_type_ref;
250
  TypeNode d_type_data;
251
  //currently fix one data type for each location type, throw error if using more than one
252
  std::map< TypeNode, TypeNode > d_loc_to_data_type;
253
  //information about types
254
  std::map< TypeNode, Node > d_base_label;
255
  std::map< TypeNode, Node > d_nil_ref;
256
  //reference bound
257
  std::map< TypeNode, Node > d_reference_bound;
258
  std::map< TypeNode, Node > d_reference_bound_max;
259
  std::map< TypeNode, std::vector< Node > > d_type_references;
260
  //kind of bound for reference types
261
  enum {
262
    bound_strict,
263
    bound_default,
264
    bound_invalid,
265
  };
266
  std::map< TypeNode, unsigned > d_bound_kind;
267
268
  std::map< TypeNode, std::vector< Node > > d_type_references_card;
269
  std::map< Node, unsigned > d_type_ref_card_id;
270
  std::map< TypeNode, std::vector< Node > > d_type_references_all;
271
  std::map< TypeNode, unsigned > d_card_max;
272
  //for empty argument
273
  std::map< TypeNode, Node > d_emp_arg;
274
  //map from ( atom, label, child index ) -> label
275
  std::map< Node, std::map< Node, std::map< int, Node > > > d_label_map;
276
  std::map< Node, Node > d_label_map_parent;
277
278
  //term model
279
  std::map< Node, Node > d_tmodel;
280
  std::map< Node, Node > d_pto_model;
281
282
  class HeapAssertInfo {
283
  public:
284
    HeapAssertInfo( context::Context* c );
285
293
    ~HeapAssertInfo(){}
286
    context::CDO< Node > d_pto;
287
    context::CDO< bool > d_has_neg_pto;
288
  };
289
  std::map< Node, HeapAssertInfo * > d_eqc_info;
290
  HeapAssertInfo * getOrMakeEqcInfo( Node n, bool doMake = false );
291
292
  //get global reference/data type
293
  TypeNode getReferenceType( Node n );
294
  TypeNode getDataType( Node n );
295
  /**
296
   * Register reference data types for atom. Calls the method below for
297
   * the appropriate types.
298
   */
299
  void registerRefDataTypesAtom(Node atom);
300
  /**
301
   * This is called either when:
302
   * (A) a declare-heap command is issued with tn1/tn2, and atom is null, or
303
   * (B) an atom specifying the heap type tn1/tn2 is registered to this theory.
304
   * We set the heap type if we are are case (A), and check whether the
305
   * heap type is consistent in the case of (B).
306
   */
307
  void registerRefDataTypes(TypeNode tn1, TypeNode tn2, Node atom);
308
  //get location/data type
309
  //get the base label for the spatial assertion
310
  Node getBaseLabel( TypeNode tn );
311
  Node getNilRef( TypeNode tn );
312
  void setNilRef( TypeNode tn, Node n );
313
  Node getLabel( Node atom, int child, Node lbl );
314
  Node applyLabel( Node n, Node lbl, std::map< Node, Node >& visited );
315
  void getLabelChildren( Node atom, Node lbl, std::vector< Node >& children, std::vector< Node >& labels );
316
317
397
  class HeapInfo {
318
  public:
319
397
    HeapInfo() : d_computed(false) {}
320
    //information about the model
321
    bool d_computed;
322
    std::vector< Node > d_heap_locs;
323
    std::vector< Node > d_heap_locs_model;
324
    //get value
325
    Node getValue( TypeNode tn );
326
  };
327
  //heap info ( label -> HeapInfo )
328
  std::map< Node, HeapInfo > d_label_model;
329
  // loc -> { data_1, ..., data_n } where (not (pto loc data_1))...(not (pto loc data_n))).
330
  std::map< Node, std::vector< Node > > d_heap_locs_nptos;
331
332
  void debugPrintHeap( HeapInfo& heap, const char * c );
333
  void validatePto( HeapAssertInfo * ei, Node ei_n );
334
  void addPto( HeapAssertInfo * ei, Node ei_n, Node p, bool polarity );
335
  void mergePto( Node p1, Node p2 );
336
  void computeLabelModel( Node lbl );
337
  Node instantiateLabel(Node n,
338
                        Node o_lbl,
339
                        Node lbl,
340
                        Node lbl_v,
341
                        std::map<Node, Node>& visited,
342
                        std::map<Node, Node>& pto_model,
343
                        TypeNode rtn,
344
                        std::map<Node, bool>& active_lbl,
345
                        unsigned ind = 0);
346
  void setInactiveAssertionRec( Node fact, std::map< Node, std::vector< Node > >& lbl_to_assertions, std::map< Node, bool >& assert_active );
347
348
  Node mkUnion( TypeNode tn, std::vector< Node >& locs );
349
350
 private:
351
  Node getRepresentative( Node t );
352
  bool hasTerm( Node a );
353
  bool areEqual( Node a, Node b );
354
  bool areDisequal( Node a, Node b );
355
  void eqNotifyMerge(TNode t1, TNode t2);
356
357
  void sendLemma( std::vector< Node >& ant, Node conc, InferenceId id, bool infer = false );
358
  void doPending();
359
360
 public:
361
362
  void initializeBounds();
363
};/* class TheorySep */
364
365
}  // namespace sep
366
}  // namespace theory
367
}  // namespace cvc5
368
369
#endif /* CVC5__THEORY__SEP__THEORY_SEP_H */