GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/sets/theory_sets_type_rules.cpp Lines: 161 205 78.5 %
Date: 2021-05-22 Branches: 280 1074 26.1 %

Line Exec Source
1
/******************************************************************************
2
 * Top contributors (to current version):
3
 *   Andrew Reynolds, Kshitij Bansal, Mudathir Mohamed
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
 * Sets theory type rules.
14
 */
15
16
#include "theory/sets/theory_sets_type_rules.h"
17
18
#include <climits>
19
#include <sstream>
20
21
#include "theory/sets/normal_form.h"
22
23
namespace cvc5 {
24
namespace theory {
25
namespace sets {
26
27
7346
TypeNode SetsBinaryOperatorTypeRule::computeType(NodeManager* nodeManager,
28
                                                 TNode n,
29
                                                 bool check)
30
{
31
7346
  Assert(n.getKind() == kind::UNION || n.getKind() == kind::INTERSECTION
32
         || n.getKind() == kind::SETMINUS);
33
7346
  TypeNode setType = n[0].getType(check);
34
7346
  if (check)
35
  {
36
7346
    if (!setType.isSet())
37
    {
38
      throw TypeCheckingExceptionPrivate(
39
          n, "operator expects a set, first argument is not");
40
    }
41
14692
    TypeNode secondSetType = n[1].getType(check);
42
7346
    if (secondSetType != setType)
43
    {
44
4
      std::stringstream ss;
45
2
      ss << "Operator " << n.getKind()
46
2
         << " expects two sets of the same type. Found types '" << setType
47
2
         << "' and '" << secondSetType << "'.";
48
2
      throw TypeCheckingExceptionPrivate(n, ss.str());
49
    }
50
  }
51
7344
  return setType;
52
}
53
54
4208
bool SetsBinaryOperatorTypeRule::computeIsConst(NodeManager* nodeManager,
55
                                                TNode n)
56
{
57
  // only UNION has a const rule in kinds.
58
  // INTERSECTION and SETMINUS are not used in the canonical representation of
59
  // sets and therefore they do not have const rules in kinds
60
4208
  Assert(n.getKind() == kind::UNION);
61
4208
  return NormalForm::checkNormalConstant(n);
62
}
63
64
364
TypeNode SubsetTypeRule::computeType(NodeManager* nodeManager,
65
                                     TNode n,
66
                                     bool check)
67
{
68
364
  Assert(n.getKind() == kind::SUBSET);
69
728
  TypeNode setType = n[0].getType(check);
70
364
  if (check)
71
  {
72
364
    if (!setType.isSet())
73
    {
74
      throw TypeCheckingExceptionPrivate(n, "set subset operating on non-set");
75
    }
76
728
    TypeNode secondSetType = n[1].getType(check);
77
364
    if (secondSetType != setType)
78
    {
79
      if (!setType.isComparableTo(secondSetType))
80
      {
81
        throw TypeCheckingExceptionPrivate(
82
            n, "set subset operating on sets of different types");
83
      }
84
    }
85
  }
86
728
  return nodeManager->booleanType();
87
}
88
89
23333
TypeNode MemberTypeRule::computeType(NodeManager* nodeManager,
90
                                     TNode n,
91
                                     bool check)
92
{
93
23333
  Assert(n.getKind() == kind::MEMBER);
94
46666
  TypeNode setType = n[1].getType(check);
95
23333
  if (check)
96
  {
97
23333
    if (!setType.isSet())
98
    {
99
      throw TypeCheckingExceptionPrivate(
100
          n, "checking for membership in a non-set");
101
    }
102
46666
    TypeNode elementType = n[0].getType(check);
103
    // e.g. (member 1 (singleton 1.0)) is true whereas
104
    // (member 1.0 (singleton 1)) throws a typing error
105
23333
    if (!elementType.isSubtypeOf(setType.getSetElementType()))
106
    {
107
      std::stringstream ss;
108
      ss << "member operating on sets of different types:\n"
109
         << "child type:  " << elementType << "\n"
110
         << "not subtype: " << setType.getSetElementType() << "\n"
111
         << "in term : " << n;
112
      throw TypeCheckingExceptionPrivate(n, ss.str());
113
    }
114
  }
115
46666
  return nodeManager->booleanType();
116
}
117
118
3427
TypeNode SingletonTypeRule::computeType(NodeManager* nodeManager,
119
                                        TNode n,
120
                                        bool check)
121
{
122
3427
  Assert(n.getKind() == kind::SINGLETON && n.hasOperator()
123
         && n.getOperator().getKind() == kind::SINGLETON_OP);
124
125
6854
  SingletonOp op = n.getOperator().getConst<SingletonOp>();
126
6854
  TypeNode type1 = op.getType();
127
3427
  if (check)
128
  {
129
6854
    TypeNode type2 = n[0].getType(check);
130
6854
    TypeNode leastCommonType = TypeNode::leastCommonTypeNode(type1, type2);
131
    // the type of the element should be a subtype of the type of the operator
132
    // e.g. (singleton (singleton_op Real) 1) where 1 is an Int
133
3427
    if (leastCommonType.isNull() || leastCommonType != type1)
134
    {
135
      std::stringstream ss;
136
      ss << "The type '" << type2 << "' of the element is not a subtype of '"
137
         << type1 << "' in term : " << n;
138
      throw TypeCheckingExceptionPrivate(n, ss.str());
139
    }
140
  }
141
6854
  return nodeManager->mkSetType(type1);
142
}
143
144
3054
bool SingletonTypeRule::computeIsConst(NodeManager* nodeManager, TNode n)
145
{
146
3054
  Assert(n.getKind() == kind::SINGLETON);
147
3054
  return n[0].isConst();
148
}
149
150
1816
TypeNode EmptySetTypeRule::computeType(NodeManager* nodeManager,
151
                                       TNode n,
152
                                       bool check)
153
{
154
1816
  Assert(n.getKind() == kind::EMPTYSET);
155
3632
  EmptySet emptySet = n.getConst<EmptySet>();
156
3632
  return emptySet.getType();
157
}
158
159
2638
TypeNode CardTypeRule::computeType(NodeManager* nodeManager,
160
                                   TNode n,
161
                                   bool check)
162
{
163
2638
  Assert(n.getKind() == kind::CARD);
164
5276
  TypeNode setType = n[0].getType(check);
165
2638
  if (check)
166
  {
167
2638
    if (!setType.isSet())
168
    {
169
      throw TypeCheckingExceptionPrivate(
170
          n, "cardinality operates on a set, non-set object found");
171
    }
172
  }
173
5276
  return nodeManager->integerType();
174
}
175
176
23
TypeNode ComplementTypeRule::computeType(NodeManager* nodeManager,
177
                                         TNode n,
178
                                         bool check)
179
{
180
23
  Assert(n.getKind() == kind::COMPLEMENT);
181
23
  TypeNode setType = n[0].getType(check);
182
23
  if (check)
183
  {
184
23
    if (!setType.isSet())
185
    {
186
      throw TypeCheckingExceptionPrivate(
187
          n, "COMPLEMENT operates on a set, non-set object found");
188
    }
189
  }
190
23
  return setType;
191
}
192
193
134
TypeNode UniverseSetTypeRule::computeType(NodeManager* nodeManager,
194
                                          TNode n,
195
                                          bool check)
196
{
197
134
  Assert(n.getKind() == kind::UNIVERSE_SET);
198
  // for nullary operators, we only computeType for check=true, since they are
199
  // given TypeAttr() on creation
200
134
  Assert(check);
201
134
  TypeNode setType = n.getType();
202
134
  if (!setType.isSet())
203
  {
204
    throw TypeCheckingExceptionPrivate(n,
205
                                       "Non-set type found for universe set");
206
  }
207
134
  return setType;
208
}
209
210
53
TypeNode ComprehensionTypeRule::computeType(NodeManager* nodeManager,
211
                                            TNode n,
212
                                            bool check)
213
{
214
53
  Assert(n.getKind() == kind::COMPREHENSION);
215
53
  if (check)
216
  {
217
53
    if (n[0].getType(check) != nodeManager->boundVarListType())
218
    {
219
      throw TypeCheckingExceptionPrivate(
220
          n, "first argument of set comprehension is not bound var list");
221
    }
222
53
    if (n[1].getType(check) != nodeManager->booleanType())
223
    {
224
      throw TypeCheckingExceptionPrivate(
225
          n, "body of set comprehension is not boolean");
226
    }
227
  }
228
53
  return nodeManager->mkSetType(n[2].getType(check));
229
}
230
231
18
TypeNode ChooseTypeRule::computeType(NodeManager* nodeManager,
232
                                     TNode n,
233
                                     bool check)
234
{
235
18
  Assert(n.getKind() == kind::CHOOSE);
236
36
  TypeNode setType = n[0].getType(check);
237
18
  if (check)
238
  {
239
18
    if (!setType.isSet())
240
    {
241
      throw TypeCheckingExceptionPrivate(
242
          n, "CHOOSE operator expects a set, a non-set is found");
243
    }
244
  }
245
36
  return setType.getSetElementType();
246
}
247
248
29
TypeNode IsSingletonTypeRule::computeType(NodeManager* nodeManager,
249
                                          TNode n,
250
                                          bool check)
251
{
252
29
  Assert(n.getKind() == kind::IS_SINGLETON);
253
58
  TypeNode setType = n[0].getType(check);
254
29
  if (check)
255
  {
256
29
    if (!setType.isSet())
257
    {
258
      throw TypeCheckingExceptionPrivate(
259
          n, "IS_SINGLETON operator expects a set, a non-set is found");
260
    }
261
  }
262
58
  return nodeManager->booleanType();
263
}
264
265
31
TypeNode InsertTypeRule::computeType(NodeManager* nodeManager,
266
                                     TNode n,
267
                                     bool check)
268
{
269
31
  Assert(n.getKind() == kind::INSERT);
270
31
  size_t numChildren = n.getNumChildren();
271
31
  Assert(numChildren >= 2);
272
31
  TypeNode setType = n[numChildren - 1].getType(check);
273
31
  if (check)
274
  {
275
31
    if (!setType.isSet())
276
    {
277
      throw TypeCheckingExceptionPrivate(n, "inserting into a non-set");
278
    }
279
110
    for (size_t i = 0; i < numChildren - 1; ++i)
280
    {
281
158
      TypeNode elementType = n[i].getType(check);
282
79
      if (elementType != setType.getSetElementType())
283
      {
284
        throw TypeCheckingExceptionPrivate(
285
            n,
286
            "type of element should be same as element type of set being "
287
            "inserted into");
288
      }
289
    }
290
  }
291
31
  return setType;
292
}
293
294
365
TypeNode RelBinaryOperatorTypeRule::computeType(NodeManager* nodeManager,
295
                                                TNode n,
296
                                                bool check)
297
{
298
365
  Assert(n.getKind() == kind::PRODUCT || n.getKind() == kind::JOIN);
299
300
730
  TypeNode firstRelType = n[0].getType(check);
301
730
  TypeNode secondRelType = n[1].getType(check);
302
365
  TypeNode resultType = firstRelType;
303
304
365
  if (!firstRelType.isSet() || !secondRelType.isSet())
305
  {
306
    throw TypeCheckingExceptionPrivate(
307
        n, " Relational operator operates on non-sets");
308
  }
309
365
  if (!firstRelType[0].isTuple() || !secondRelType[0].isTuple())
310
  {
311
    throw TypeCheckingExceptionPrivate(
312
        n, " Relational operator operates on non-relations (sets of tuples)");
313
  }
314
315
730
  std::vector<TypeNode> newTupleTypes;
316
730
  std::vector<TypeNode> firstTupleTypes = firstRelType[0].getTupleTypes();
317
730
  std::vector<TypeNode> secondTupleTypes = secondRelType[0].getTupleTypes();
318
319
  // JOIN is not allowed to apply on two unary sets
320
365
  if (n.getKind() == kind::JOIN)
321
  {
322
318
    if ((firstTupleTypes.size() == 1) && (secondTupleTypes.size() == 1))
323
    {
324
      throw TypeCheckingExceptionPrivate(
325
          n, " Join operates on two unary relations");
326
    }
327
318
    else if (firstTupleTypes.back() != secondTupleTypes.front())
328
    {
329
      throw TypeCheckingExceptionPrivate(
330
          n, " Join operates on two non-joinable relations");
331
    }
332
954
    newTupleTypes.insert(newTupleTypes.end(),
333
                         firstTupleTypes.begin(),
334
1272
                         firstTupleTypes.end() - 1);
335
954
    newTupleTypes.insert(newTupleTypes.end(),
336
636
                         secondTupleTypes.begin() + 1,
337
1272
                         secondTupleTypes.end());
338
  }
339
47
  else if (n.getKind() == kind::PRODUCT)
340
  {
341
47
    newTupleTypes.insert(
342
94
        newTupleTypes.end(), firstTupleTypes.begin(), firstTupleTypes.end());
343
47
    newTupleTypes.insert(
344
94
        newTupleTypes.end(), secondTupleTypes.begin(), secondTupleTypes.end());
345
  }
346
365
  resultType = nodeManager->mkSetType(nodeManager->mkTupleType(newTupleTypes));
347
348
730
  return resultType;
349
}
350
351
119
TypeNode RelTransposeTypeRule::computeType(NodeManager* nodeManager,
352
                                           TNode n,
353
                                           bool check)
354
{
355
119
  Assert(n.getKind() == kind::TRANSPOSE);
356
238
  TypeNode setType = n[0].getType(check);
357
119
  if (check && (!setType.isSet() || !setType.getSetElementType().isTuple()))
358
  {
359
    throw TypeCheckingExceptionPrivate(
360
        n, "relation transpose operates on non-relation");
361
  }
362
238
  std::vector<TypeNode> tupleTypes = setType[0].getTupleTypes();
363
119
  std::reverse(tupleTypes.begin(), tupleTypes.end());
364
238
  return nodeManager->mkSetType(nodeManager->mkTupleType(tupleTypes));
365
}
366
367
44
TypeNode RelTransClosureTypeRule::computeType(NodeManager* nodeManager,
368
                                              TNode n,
369
                                              bool check)
370
{
371
44
  Assert(n.getKind() == kind::TCLOSURE);
372
44
  TypeNode setType = n[0].getType(check);
373
44
  if (check)
374
  {
375
44
    if (!setType.isSet() || !setType.getSetElementType().isTuple())
376
    {
377
      throw TypeCheckingExceptionPrivate(
378
          n, " transitive closure operates on non-relation");
379
    }
380
88
    std::vector<TypeNode> tupleTypes = setType[0].getTupleTypes();
381
44
    if (tupleTypes.size() != 2)
382
    {
383
      throw TypeCheckingExceptionPrivate(
384
          n, " transitive closure operates on non-binary relations");
385
    }
386
44
    if (tupleTypes[0] != tupleTypes[1])
387
    {
388
      throw TypeCheckingExceptionPrivate(
389
          n,
390
          " transitive closure operates on non-homogeneous binary relations");
391
    }
392
  }
393
44
  return setType;
394
}
395
396
38
TypeNode JoinImageTypeRule::computeType(NodeManager* nodeManager,
397
                                        TNode n,
398
                                        bool check)
399
{
400
38
  Assert(n.getKind() == kind::JOIN_IMAGE);
401
402
76
  TypeNode firstRelType = n[0].getType(check);
403
404
38
  if (!firstRelType.isSet())
405
  {
406
    throw TypeCheckingExceptionPrivate(
407
        n, " JoinImage operator operates on non-relations");
408
  }
409
38
  if (!firstRelType[0].isTuple())
410
  {
411
    throw TypeCheckingExceptionPrivate(
412
        n, " JoinImage operator operates on non-relations (sets of tuples)");
413
  }
414
415
76
  std::vector<TypeNode> tupleTypes = firstRelType[0].getTupleTypes();
416
38
  if (tupleTypes.size() != 2)
417
  {
418
    throw TypeCheckingExceptionPrivate(
419
        n, " JoinImage operates on a non-binary relation");
420
  }
421
76
  TypeNode valType = n[1].getType(check);
422
38
  if (valType != nodeManager->integerType())
423
  {
424
    throw TypeCheckingExceptionPrivate(
425
        n, " JoinImage cardinality constraint must be integer");
426
  }
427
76
  std::vector<TypeNode> newTupleTypes;
428
38
  newTupleTypes.push_back(tupleTypes[0]);
429
76
  return nodeManager->mkSetType(nodeManager->mkTupleType(newTupleTypes));
430
}
431
432
9
TypeNode RelIdenTypeRule::computeType(NodeManager* nodeManager,
433
                                      TNode n,
434
                                      bool check)
435
{
436
9
  Assert(n.getKind() == kind::IDEN);
437
18
  TypeNode setType = n[0].getType(check);
438
9
  if (check)
439
  {
440
9
    if (!setType.isSet() && !setType.getSetElementType().isTuple())
441
    {
442
      throw TypeCheckingExceptionPrivate(n,
443
                                         " Identity operates on non-relation");
444
    }
445
9
    if (setType[0].getTupleTypes().size() != 1)
446
    {
447
      throw TypeCheckingExceptionPrivate(
448
          n, " Identity operates on non-unary relations");
449
    }
450
  }
451
18
  std::vector<TypeNode> tupleTypes = setType[0].getTupleTypes();
452
9
  tupleTypes.push_back(tupleTypes[0]);
453
18
  return nodeManager->mkSetType(nodeManager->mkTupleType(tupleTypes));
454
}
455
456
Cardinality SetsProperties::computeCardinality(TypeNode type)
457
{
458
  Assert(type.getKind() == kind::SET_TYPE);
459
  Cardinality elementCard = 2;
460
  elementCard ^= type[0].getCardinality();
461
  return elementCard;
462
}
463
464
bool SetsProperties::isWellFounded(TypeNode type)
465
{
466
  return type[0].isWellFounded();
467
}
468
469
6
Node SetsProperties::mkGroundTerm(TypeNode type)
470
{
471
6
  Assert(type.isSet());
472
6
  return NodeManager::currentNM()->mkConst(EmptySet(type));
473
}
474
475
}  // namespace sets
476
}  // namespace theory
477
28194
}  // namespace cvc5