vampire-sys 0.5.2

Low-level FFI bindings to the Vampire theorem prover (use the 'vampire' crate instead)
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
/*
 * This file is part of the source code of the software program
 * Vampire. It is protected by applicable
 * copyright laws.
 *
 * This source code is distributed under the licence found here
 * https://vprover.github.io/license.html
 * and in the source directory
 */
/**
 * @file Term.hpp
 * Defines class Term (also serving as term arguments)
 *
 * The way terms are laid out in memory is partly historical and certainly non-trivial.
 * Here are a few salient points to help you navigate:
 * - a "Term" represents a function (unsigned, see Kernel::Signature) applied to some number of arguments
 * - usually Terms are "perfectly shared" (see Indexing::TermSharing)
 * - the arguments are "TermList"s, i.e. a variable or a Term*
 * - TermList is a tagged union that relies on Term* being aligned (!) to achieve pointer tagging
 * - TermTag::REF == 0 because this does not change the value of an aligned Term*
 * - the arguments of a Term are laid out in reverse order (!)
 * - the last argument (i.e. the closest to the Term) is a sentinel with TermTag::FUN
 *   and some metadata about the enclosing Term
 *
 * @since 18/04/2006 Bellevue
 * @since 06/05/2007 Manchester, changed into a single class instead of three
 */

#ifndef __Term__
#define __Term__

#include "Forwards.hpp"
#include "Debug/Assertion.hpp"

#include "Lib/BitUtils.hpp"
#include "Lib/Metaiterators.hpp"
#include "Lib/Comparison.hpp"
#include "Lib/Reflection.hpp"
#include "Lib/Stack.hpp"
#include "Lib/Hash.hpp"
#include "Lib/Coproduct.hpp"
#include "Lib/Recycled.hpp"

// the number of bits used for "TermList::_info::distinctVars"
#define TERM_DIST_VAR_BITS 19
// maximum number that fits in a TERM_DIST_VAR_BITS-bit unsigned integer
#define TERM_DIST_VAR_UNKNOWN ((1 << TERM_DIST_VAR_BITS)-1)

namespace Kernel {
  std::ostream& operator<<(std::ostream& out, Term const& self);
  std::ostream& operator<<(std::ostream& out, TermList const& self);
  std::ostream& operator<<(std::ostream& out, Literal const& self);
  bool operator<(TermList const&,TermList const&);

using namespace Lib;

/** Tag denoting the kind of this term
 * @since 19/02/2008 Manchester, moved outside of the Term class
 */
enum TermTag {
  /** reference to another term */
  REF = 0u,
  /** ordinary variable */
  ORD_VAR = 1u,
  /** (function) symbol */
  FUN = 2u,
  /** special variable */
  SPEC_VAR = 3u,
};
// number of bits occupied by a TermTag
const unsigned TERM_TAG_BITS = 2;
static_assert(SPEC_VAR < 1 << TERM_TAG_BITS, "TermTag must fit within TERM_TAG_BITS");

enum ArgumentOrderVals {
  /**
   * Values representing order of arguments in equality,
   * to be stores in the term sharing structure.
   *
   * The important thing is that the UNKNOWN value is
   * equal to 0, as this will be the default value inside
   * the term objects
   *
   * Values of elements must be equal to values of corresponding elements
   * in the @c Result enum, so that one can convert between the
   * enums using static_cast.
   */
  AO_UNKNOWN=0,
  AO_GREATER=1,
  AO_LESS=2,
  AO_EQUAL=3,
  AO_INCOMPARABLE=4,
};
const unsigned ARGUMENT_ORDER_BITS = 3;
static_assert(AO_INCOMPARABLE < 1 << ARGUMENT_ORDER_BITS, "ArgumentOrderVals must fit within ARGUMENT_ORDER_BITS");

inline std::ostream& operator<<(std::ostream& out, ArgumentOrderVals const& self)
{
  switch(self) {
    case AO_UNKNOWN: return out << "UNKNOWN";
    case AO_GREATER: return out << "GREATER";
    case AO_LESS: return out << "LESS";
    case AO_EQUAL: return out << "EQUAL";
    case AO_INCOMPARABLE: return out << "INCOMPARABLE";
  }
  ASSERTION_VIOLATION
}

enum class TermKind : unsigned {
  LITERAL,
  TERM,
  SORT,
};

/* a function symbol of a composite term. in addition to the function symbol id (the functor in vampire terminology) we store what kind of term (i.e. term, literal or sort) it is. */
struct SymbolId {
  unsigned functor;
  TermKind kind;
  auto asTuple() const { return std::tie(functor, kind); }
  IMPL_COMPARISONS_FROM_TUPLE(SymbolId);
};

struct VarNumber {
  unsigned number;
  bool special;
  auto asTuple() const { return std::tie(number, special); }
  IMPL_COMPARISONS_FROM_TUPLE(VarNumber);
};

enum class Proxy {
  AND,
  OR,
  IMP,
  FORALL,
  EXISTS,
  IFF,
  XOR,
  NOT,
  PI,
  SIGMA,
  EQUALS,
  NOT_PROXY
};

/**
 * Class containing either a pointer to a compound term or
 * a variable number or a functor.
 */
class TermList {
public:
  /* default constructor, satisfying isEmpty() */
  TermList() : _content(FUN) {}
  /** creates a term list containing a pointer to a term */
  explicit TermList(const Term* t) : _content(0) {
    // NB we also zero-initialise _content so that the spare bits are zero on 32-bit platforms
    // dead-store eliminated on 64-bit
    _setTerm(t);
    ASS_EQ(tag(), REF);
  }
  /** creates a term list containing a variable. If @b special is true, then the variable
   * will be "special". Special variables are also variables, with a difference that a
   * special variables and ordinary variables have an empty intersection */
  TermList(unsigned var, bool special)
  {
    if (special) {
      makeSpecialVar(var);
    }
    else {
      makeVar(var);
    }
  }

  /** the tag */
  inline TermTag tag() const { return static_cast<TermTag>(_tag()); }
  /** the term list is empty */
  inline bool isEmpty() const
  { return tag() == FUN; }
  /** the term list is non-empty */
  inline bool isNonEmpty() const
  { return tag() != FUN; }
  /** next term in this list */
  inline TermList* next()
  { return this-1; }
  /** next term in this list */
  inline const TermList* next() const
  { return this-1; }
  /** the term contains a variable as its head */
  inline bool isVar() const { return tag() == ORD_VAR || tag() == SPEC_VAR; }
  /** the term contains an ordinary variable as its head */
  inline bool isOrdinaryVar() const { return tag() == ORD_VAR; }
  /** the term contains a special variable as its head */
  inline bool isSpecialVar() const { return tag() == SPEC_VAR; }

  /** return the variable number */
  inline unsigned var() const
  { ASS(isVar()); return _content / 4; }
  /** the term contains reference to Term class */
  inline bool isTerm() const
  { return tag() == REF; }
  inline const Term* term() const
  { ASS(isTerm()); return _term(); }
  inline Term* term()
  { ASS(isTerm()); return _term(); }
  /** True of the terms have the same content. Useful for comparing
   * arguments of shared terms. */
  inline bool sameContent(const TermList* t) const
  { return _content == t->_content ; }
  inline bool sameContent(const TermList& t) const
  { return sameContent(&t); }
  /** return the content, useful for e.g., term argument comparison */
  inline uint64_t content() const { return _content; }
  /** set the content manually - hazardous, such terms should then only be used as integers */
  void setContent(uint64_t content) { _content = content; }
  /** default hash is to hash the content */
  unsigned defaultHash() const { return DefaultHash::hash(content()); }
  unsigned defaultHash2() const { return content(); }

  std::string toString(bool needsPar = false) const;

  friend std::ostream& operator<<(std::ostream& out, Kernel::TermList const& tl);
  /** make the term into an ordinary variable with a given number */
  inline void makeVar(unsigned vnumber)
  { _content = vnumber * 4 + ORD_VAR; }
  /** make the term into a special variable with a given number */
  inline void makeSpecialVar(unsigned vnumber)
  { _content = vnumber * 4 + SPEC_VAR; }
  /** create an term empty (so that isEmpty() returns true)
   *  (can just be the default constructor now)
   */
  inline static TermList empty()
  { return TermList(); }

  /** the top of a term is either a function symbol or a variable id. this class is model this */
  class Top {
    using Inner = Coproduct<VarNumber, SymbolId>;
    Inner _inner;
    
    Top(Inner self) : _inner(self) {}
  public:
    static Top var    (unsigned v, bool special) { return Top(Inner(VarNumber {v, special})); }
    // static Top functor(unsigned f) { return Top(Inner::variant<FUN>(f)); }
    template<class T>
    static Top functor(T const* t) { return Top(Inner(SymbolId{ t->functor(), t->kind(), })); }
    Option<VarNumber> var()     const { return _inner.as<VarNumber>().toOwned(); }
    Option<SymbolId> functor() const { return _inner.as<SymbolId>().toOwned(); }
    Lib::Comparison compare(Top const& other) const 
    { return _inner.compare(other._inner); }
    IMPL_COMPARISONS_FROM_COMPARE(Top);
    friend bool operator==(Top const& l, Top const& r) { return l._inner == r._inner; }
    friend bool operator!=(Top const& l, Top const& r) { return      !(l == r);       }
    void output(std::ostream& out) const;

    friend std::ostream& operator<<(std::ostream& out, Kernel::TermList::Top const& self)
    { self.output(out); return out; }
  };

  /* returns the Top of a function (a variable id, or a function symbol depending on whether the term is a variable or a complex term) */
  Top top() const
  { return isTerm() ? TermList::Top::functor(term()) 
                    : TermList::Top::var(var(), isSpecialVar());            }

  /** make the term into a reference */
  inline void setTerm(Term* t) {
    // NB we also zero-initialise _content so that the spare bits are zero on 32-bit platforms
    // dead-store eliminated on 64-bit
    _content = 0;
    _setTerm(t);
    ASS_EQ(tag(), REF);
  }
  static bool sameTop(TermList ss, TermList tt);
  static bool sameTopFunctor(TermList ss, TermList tt);
  static bool equals(TermList t1, TermList t2);
  static bool allShared(TermList* args);
  static TermList var(unsigned var, bool special = false) { return TermList(var, special); }
  /** if not var, the inner term must be shared */
  unsigned weight() const;
  /** returns true if this termList is wrapping a higher-order "arrow" sort */
  bool isArrowSort();
  bool isBoolSort();
  bool isArraySort();
  bool isTupleSort();
  bool containsSubterm(TermList v) const;
  bool containsAllVariablesOf(TermList t) const;
  bool ground() const;
  bool isSafe() const;

  /* Higher-order terms */
  bool isApplication() const;
  bool isLambdaTerm() const;
  bool isRedex() const;
  bool isProxy(Proxy proxy) const;
  bool isChoice() const;

  Option<unsigned> deBruijnIndex() const;
  TermList lhs() const;
  TermList rhs() const;
  TermList lambdaBody() const;
  TermList head() const;
  std::pair<TermList, TermList> asPair();
  TermList domain();
  TermList result();
  TermList replaceSubterm(TermList what, TermList by, bool liftFreeIndices = false) const;
  /* End higher-order terms */

#if VDEBUG
  void assertValid() const;
#endif

  inline bool operator==(const TermList& t) const
  { return _content==t._content; }
  inline bool operator!=(const TermList& t) const
  { return _content!=t._content; }

  friend bool operator<(const TermList& lhs, const TermList& rhs);

private:
  std::string asArgsToString() const;

  /*
   * the actual content of a TermList, defined as a bitfield
   * 1. a Term *
   * 2. metadata (see below) such that _tag() is the lowest two bits of (1)
   * 3. "other", rarely used and handled specially
   * metadata used to be defined as this bitfield:
   */
#if 0
  struct {
    /** a TermTag indicating what is stored here */
    unsigned tag : 2;
    /** polarity, used only for literals */
    unsigned polarity : 1;
    /** true if commutative/symmetric */
    unsigned commutative : 1;
    /** true if shared */
    unsigned shared : 1;
    /** true if literal */
    unsigned literal : 1;
    /** true if atomic sort */
    unsigned sort : 1;
    /** true if term contains at least one term var */
    unsigned hasTermVar : 1;
    /** Ordering comparison result for commutative term arguments, one of
     * 0 (unknown) 1 (less), 2 (equal), 3 (greater), 4 (incomparable)
     * @see Term::ArgumentOrder */
    unsigned order : 3;
    /** Number of distinct variables in the term, equal
     * to TERM_DIST_VAR_UNKNOWN if the number has not been
     * computed yet. */

    mutable unsigned distinctVars : TERM_DIST_VAR_BITS;
    /** term id hiding in this _info */
    // this should not be removed without care,
    // otherwise the bitfield layout might shift, resulting in broken pointer tagging
    unsigned id : 32;
    } _info;
#endif
  // but it was *not* portable because the layout of the bitfield is not guaranteed - see BitUtils.hpp
  // (and this *did* bite us on PowerPC somehow)

  uint64_t _content;
  BITFIELD(64,
    BITFIELD_MEMBER(uint32_t, _id, _setId, 32,
    BITFIELD_MEMBER(uint32_t, _distinctVars, _setDistinctVars, TERM_DIST_VAR_BITS,
    BITFIELD_MEMBER(unsigned, _order, _setOrder, ARGUMENT_ORDER_BITS,
    BITFIELD_MEMBER(bool, _hasLambda, _setHasLambda, 1,
    BITFIELD_MEMBER(bool, _hasRedex, _setHasRedex, 1,
    BITFIELD_MEMBER(bool, _hasDeBruijnIndex, _setHasDeBruijnIndex, 1,
    BITFIELD_MEMBER(bool, _hasTermVar, _setHasTermVar, 1,
    BITFIELD_MEMBER(bool, _sort, _setSort, 1,
    BITFIELD_MEMBER(bool, _literal, _setLiteral, 1,
    BITFIELD_MEMBER(bool, _shared, _setShared, 1,
    BITFIELD_MEMBER(bool, _polarity, _setPolarity, 1,
    BITFIELD_MEMBER(unsigned, _tag, _setTag, TERM_TAG_BITS,
    END_BITFIELD
  )))))))))))))
  BITFIELD_PTR_GET(Term, _term, 0)
  BITFIELD_PTR_SET(Term, _setTerm, 0)

  static_assert(sizeof(void *) <= sizeof(uint64_t), "must be able to fit a pointer into a 64-bit integer");

  friend class Indexing::TermSharing;
  friend class Term;
  friend class Literal;
  friend class AtomicSort;
}; // class TermList
static_assert(sizeof(TermList) == 8, "size of TermList must be exactly 64 bits");

//special functor values
enum class SpecialFunctor {
  ITE,
  LET,
  FORMULA,
  LAMBDA,
  MATCH, // <- keep this one the last, or modify SPECIAL_FUNCTOR_LAST accordingly
};
static constexpr SpecialFunctor SPECIAL_FUNCTOR_LAST = SpecialFunctor::MATCH;
std::ostream& operator<<(std::ostream& out, SpecialFunctor const& self);

/**
 * Class to represent terms and lists of terms.
 * @since 19/02/2008 Manchester, changed to use class TermList
 */
class alignas(8) Term
{
public:

  static constexpr unsigned SPECIAL_FUNCTOR_LOWER_BOUND  =  std::numeric_limits<unsigned>::max() - unsigned(SPECIAL_FUNCTOR_LAST);
  static SpecialFunctor toSpecialFunctor(unsigned f) {
    ASS_GE(f, SPECIAL_FUNCTOR_LOWER_BOUND);
    unsigned result = std::numeric_limits<unsigned>::max() - f;
    ASS_LE(result, unsigned(SPECIAL_FUNCTOR_LAST))
    return SpecialFunctor(result);
  }
  static unsigned toNormalFunctor(SpecialFunctor f) 
  { return std::numeric_limits<unsigned>::max() - static_cast<unsigned>(f); }

  class SpecialTermData
  {
    friend class Term;
  private:
    union {
      struct {
        Formula * condition;
        TermList sort;
      } _iteData;
      struct {
        Formula* binding;
        TermList sort;
      } _letData;
      struct {
        Formula * formula;
      } _formulaData;
      struct {
        TermList lambdaExp;
        VList* _vars;
        SList* _sorts;  
        TermList sort; 
        TermList expSort;//TODO is this needed?
      } _lambdaData;
      struct {
        TermList sort;
        TermList matchedSort;
      } _matchData;
    };
    /** Return pointer to the term to which this object is attached */
    const Term* getTerm() const { return reinterpret_cast<const Term*>(this+1); }
  public:
    SpecialFunctor specialFunctor() const
    { return getTerm()->specialFunctor(); }

    Formula* getITECondition() const { ASS_EQ(specialFunctor(), SpecialFunctor::ITE); return _iteData.condition; }
    VList* getLambdaVars() const { ASS_EQ(specialFunctor(), SpecialFunctor::LAMBDA); return _lambdaData._vars; }
    void setLambdaVars(VList* vars) { ASS_EQ(specialFunctor(), SpecialFunctor::LAMBDA); _lambdaData._vars = vars; }
    SList* getLambdaVarSorts() const { ASS_EQ(specialFunctor(), SpecialFunctor::LAMBDA); return _lambdaData._sorts; }
    void setLambdaVarSorts(SList* sorts) { ASS_EQ(specialFunctor(), SpecialFunctor::LAMBDA); _lambdaData._sorts = sorts; }
    TermList getLambdaExp() const { ASS_EQ(specialFunctor(), SpecialFunctor::LAMBDA); return _lambdaData.lambdaExp; }
    void setLambdaExp(TermList exp) { ASS_EQ(specialFunctor(), SpecialFunctor::LAMBDA); _lambdaData.lambdaExp = exp; }
    void setLambdaExpSort(TermList sort) { ASS_EQ(specialFunctor(), SpecialFunctor::LAMBDA); _lambdaData.expSort = sort; }
    void setLambdaSort(TermList sort) { ASS_EQ(specialFunctor(), SpecialFunctor::LAMBDA); _lambdaData.sort = sort; }
    Formula* getLetBinding() const { ASS_EQ(specialFunctor(), SpecialFunctor::LET); return _letData.binding; }
    TermList getLambdaExpSort() const { ASS_EQ(specialFunctor(), SpecialFunctor::LAMBDA); return _lambdaData.expSort; }
    TermList getSort() const {
      switch (specialFunctor()) {
        case SpecialFunctor::ITE:
          return _iteData.sort;
        case SpecialFunctor::LET:
          return _letData.sort;
        case SpecialFunctor::LAMBDA:
          return _lambdaData.sort;
        case SpecialFunctor::MATCH:
          return _matchData.sort;
        default:
          ASSERTION_VIOLATION_REP(specialFunctor());
      }
    }
    Formula* getFormula() const { ASS_EQ(specialFunctor(), SpecialFunctor::FORMULA); return _formulaData.formula; }
    TermList getMatchedSort() const { return _matchData.matchedSort; }
  };


  Term() throw();
  explicit Term(const Term& t) throw();
  static Term* create(unsigned function, unsigned arity, const TermList* args);
  static Term* create(unsigned fn, std::initializer_list<TermList> args);
  static Term* create(unsigned fn, Stack<TermList> const& args) { return Term::create(fn, args.length(), args.begin()); }
  template<class Iter>
  static Term* createFromIter(unsigned fn, Iter args) 
  { 
    Recycled<Stack<TermList>> stack;
    stack->loadFromIterator(args);
    return Term::create(fn, *stack); 
  }
  static Term* create(Term* t,TermList* args);
  static Term* createNonShared(unsigned function, unsigned arity, TermList* arg);
  static Term* createNonShared(Term* t,TermList* args);
  static Term* createNonShared(Term* t);
  static Term* cloneNonShared(Term* t);

  static Term* createConstant(const std::string& name);
  /** Create a new constant and insert in into the sharing structure */
  static Term* createConstant(unsigned symbolNumber) { return create(symbolNumber,0,0); }
  static Term* createITE(Formula * condition, TermList thenBranch, TermList elseBranch, TermList branchSort);
  static Term* createLet(Formula* binding, TermList body, TermList bodySort);
  static Term* createLambda(TermList lambdaExp, VList* vars, SList* sorts, TermList expSort);
  static Term* createFormula(Formula* formula);
  static Term* createMatch(TermList sort, TermList matchedSort, unsigned int arity, TermList* elements);
  static Term* create1(unsigned fn, TermList arg);
  static Term* create2(unsigned fn, TermList arg1, TermList arg2);

  //** fool constants
  static Term* foolTrue();
  static Term* foolFalse();

  /** Reset all static caches (for library use when running multiple proofs) */
  static void resetStaticCaches(); 

  /** Return number of bytes before the start of the term that belong to it */
  size_t getPreDataSize() { return isSpecial() ? sizeof(SpecialTermData) : 0; }

  /** Function or predicate symbol of a term */
  const unsigned functor() const { return _functor; }


  SpecialFunctor specialFunctor() const 
  { return toSpecialFunctor(functor()); }
  std::string toString(bool topLevel = true) const;
  friend std::ostream& operator<<(std::ostream& out, Kernel::Term const& tl);
  static std::string variableToString(unsigned var);
  static std::string variableToString(TermList var);

  /** return the arguments 
   *
   *  WARNING: this function returns a pointer to the first argument
   *  which could be a sort when dealing with a polymorphic problem!
   * 
   *  Use with care! Consider whether the termArgs() function may be more
   *  suited to your needs before using this.
   */
  const TermList* args() const
  { return _args + _arity; }
  /** @see nthArguement(int) */ 
  const TermList* nthArgument(int n) const
  {
    ASS(n >= 0);
    ASS((unsigned)n < _arity);

    return _args + (_arity - n);
  }
  /** return the nth argument (counting from 0) 
   *
   *  Note that the arguments may be sort arguments as well as term arguments.
   *  i.e. nthArgument(n) will return 
   *    - a sort, for 0 <= n < numTypeArguemnts()
   *    - a term, for numTypeArguments() <= n < arity()
   *
   *  If you want to access a specific term or type argument use typeArg(int) or termArg(int) instead.
   */ 
  TermList* nthArgument(int n)
  {
    ASS(n >= 0);
    ASS((unsigned)n < _arity);

    return _args + (_arity - n);
  }

  /** returns the nth term argument. for 0 <= n <= numTermArguments  */
  TermList termArg(unsigned n) const;

  /** returns the nth type argument. for 0 <= n <= numTypeArguments  */
  TermList typeArg(unsigned n) const;

  /**
   * Return the number of type arguments for a polymorphic term (or 0 if monomorphic).
   */
  unsigned numTypeArguments() const;

  /**
   * Return the number of term arguments for a term (equal to _arity if monomorphic).
   */  
  unsigned numTermArguments() const;

  /** Return the 1st term argument for a polymorphic term.
    * Call hasTermArgs before calling this or test the result for
    * non-emptiness
    * In the monomorphic case, the same as args()
    */
  TermList* termArgs();

  /** Return the 1st type argument for a polymorphic term.
    * returns a nullpointer if the term not polymorphic
    * This is technically almost the same thing as calling args(), 
    * but can be used to increase readability of code.
    */
  const TermList* typeArgs() const;

  /** Indexing operator for accessing arguments */
  const TermList operator[](int i) const {
    return *nthArgument(i);
  }
  TermList operator[](int i) {
    return *nthArgument(i);
  }

  /** return the arguments 
   *
   *  WARNING: this function returns a pointer to the first argument
   *  which could be a sort when dealing with a polymorphic problem!
   * 
   *  Use with care! Consider whether the termArgs() function may be more
   *  suited to your needs before using this.
   */  
  TermList* args()
  { return _args + _arity; }


  template<class GetArg>
  static unsigned termHash(unsigned functor, GetArg getArg, unsigned arity) {
    return DefaultHash::hashIter(
        range(0, arity).map([&](auto i) {
          TermList t = getArg(i);
          return DefaultHash::hashBytes(
              reinterpret_cast<const unsigned char*>(&t),
              sizeof(TermList)
              );
          }),
        DefaultHash::hash(functor));
  }

  /**
   * Return the hash function of the top-level of a complex term.
   * @pre The term must be non-variable
   * @since 28/12/2007 Manchester
   */
  unsigned hash() const 
  { return termHash(_functor, [&](auto i) { return *nthArgument(i); }, _arity); }

  /** return the arity */
  unsigned arity() const
  { return _arity; }
  static void* operator new(size_t,unsigned arity,size_t preData=0);
  /** make the term into a symbol term */
  void makeSymbol(unsigned number,unsigned arity)
  {
    _functor = number;
    _arity = arity;
  }
  void destroy();
  void destroyNonShared();
  Term* apply(Substitution& subst);

  /** True iff all immediate arguments are variables */
  bool allArgumentsAreVariables() const
  {
    for(unsigned i = 0; i < arity(); i++)
      if(!nthArgument(i)->isVar())
        return false;

    return true;
  }

  /** True if the term is ground. Only applicable to shared terms */
  bool ground() const
  {
    ASS(_args[0]._shared());
    return numVarOccs() == 0;
  } // ground

  /** True if the term contains a term variable (type variables don't count)
   *  Only applicable to shared terms */
  bool hasTermVar() const
  {
    ASS(shared());
    return _args[0]._hasTermVar();
  } // ground

  /** True if the term is shared */
  bool shared() const
  { return _args[0]._shared(); } // shared

  /** Return the weight. Applicable only to shared terms */
  unsigned weight() const
  {
    ASS(shared());
    return _weight;
  }

  int maxRedLength() const
  {
    ASS(shared());
    return _maxRedLen;    
  }

  int kboWeight(const void* kboInstance) const
  {
    if (_kboEpoch != s_kboEpoch) return -1;
#if VDEBUG
    ASS(_kboInstance && _kboInstance == kboInstance);
#endif
    return _kboWeight;
  }

  void setKboWeight(int w, const void* kboInstance)
  {
#if VDEBUG
    ASS(!_kboInstance || _kboEpoch != s_kboEpoch);
    _kboInstance = kboInstance;
#endif
    _kboWeight = w;
    _kboEpoch = s_kboEpoch;
  }

  /** Invalidate all cached KBO weights across all shared terms.
   * Must be called whenever a new KBO ordering is created (e.g. between proofs)
   * so that stale weights from the previous ordering are not reused. */
  static void invalidateKboWeightCache() { ++s_kboEpoch; }

  /** Mark term as shared */
  void markShared()
  {
    ASS(! shared());
    _args[0]._setShared(true);
  } // markShared

  /** Set term weight */
  void setWeight(unsigned w)
  {
    _weight = w;
  } // setWeight

  /** Set term id */
  void setId(unsigned id);

  /** Set (shared) term's id */
  unsigned getId() const
  {
    ASS(shared());
    return _args[0]._id();
  }
  
  void setMaxRedLen(int rl)
  {
    _maxRedLen = rl;
  } // setWeight

  /** Set the number of variable _occurrences_ */
  void setNumVarOccs(unsigned v)
  {
    if(_isTwoVarEquality) {
      ASS_EQ(v,2);
      return;
    }
    _vars = v;
  } // setVars

  void setHasTermVar(bool b)
  {
    ASS(shared() && !isSort())
    _args[0]._setHasTermVar(b);
  }

  /** Return the number of variable _occurrences_ */
  unsigned numVarOccs() const
  {
    ASS(shared());
    if(_isTwoVarEquality) {
      return _sort.isVar() ? 3 : 2 + _sort.term()->numVarOccs();
    }
    return _vars;
  } // vars()

  /**
   * Return true iff the object is an equality between two variables.
   *
   * This value is set during insertion into the term sharing structure or
   * for terms with special subterms during construction.
   * (I.e. can be used basically anywhere).
   */
  bool isTwoVarEquality() const
  {
    return _isTwoVarEquality;
  }

  const std::string& functionName() const;

  /** True if the term is, in fact, a literal */
  bool isLiteral() const { return _args[0]._literal(); }
  /** True if the term is, in fact, a sort */
  bool isSort() const { return _args[0]._sort(); }
  bool isArrowSort() const;
  TermKind kind() const { return isSort() ? TermKind::SORT 
                               : isLiteral() ? TermKind::LITERAL
                               : TermKind::TERM; }
  /** true if the term is an application */
  bool isApplication() const;
  /** true if the term is a lambda term */
  bool isLambdaTerm() const;
  /** true if the term is a redex */
  bool isRedex() const;
  bool isProxy(Proxy proxy) const;
  bool isChoice() const;

  TermList lambdaBody() const {
    ASS(isLambdaTerm())

    return *nthArgument(2);
  }

  void setHasRedex(bool b) {
    ASS(shared() && !isSort())

    _args[0]._setHasRedex(b);
  }

  /** true if term contains redex */
  bool hasRedex() const {
    ASS(shared())
    return _args[0]._hasRedex();
  }
  /** returns empty option if not a De Bruijn index and index otherwise */
  Option<unsigned> deBruijnIndex() const;

  void setHasDeBruijnIndex(bool b) {
    ASS(shared() && !isSort());
    _args[0]._setHasDeBruijnIndex(b);
  }

  /** returns true if term contains De Bruijn index */
  bool hasDeBruijnIndex() const {
    ASS(shared())

    return _args[0]._hasDeBruijnIndex();
  }

  void setHasLambda(bool b) {
    ASS(shared() && !isSort())

    _args[0]._setHasLambda(b);
  }
  /** true if term contains redex */
  bool hasLambda() const {
    ASS(shared())

    return _args[0]._hasLambda();
  }

  /** Return an index of the argument to which @b arg points */
  unsigned getArgumentIndex(TermList* arg)
  {
    unsigned res=arity()-(arg-_args);
    ASS_L(res,arity());
    return res;
  }

#if VDEBUG
  std::string headerToString() const;
  void assertValid() const;
#endif


  static TermIterator getVariableIterator(TermList tl);

  // the number of _distinct_ variables within the term
  unsigned getDistinctVars()
  {
    if(_args[0]._distinctVars()==TERM_DIST_VAR_UNKNOWN) {
      unsigned res=computeDistinctVars();
      if(res<TERM_DIST_VAR_UNKNOWN) {
        _args[0]._setDistinctVars(res);
      }
      return res;
    } else {
      ASS_L(_args[0]._distinctVars(),0x100000);
      return _args[0]._distinctVars();
    }
  }

  bool couldBeInstanceOf(Term* t)
  {
    ASS(shared());
    ASS(t->shared());
    if(t->functor()!=functor()) {
      return false;
    }
    return true;
  }

  bool containsSubterm(TermList v) const;
  bool containsAllVariablesOf(Term* t);
  size_t countSubtermOccurrences(TermList subterm);

  /** Return true if term has no non-constant functions as subterms */
  bool isShallow() const;

  /** set the colour of the term */
  void setColor(Color color)
  {
    ASS(_color == static_cast<unsigned>(COLOR_TRANSPARENT) || _color == static_cast<unsigned>(color));
    _color = color;
  } // setColor
  /** return the colour of the term */
  Color color() const { return static_cast<Color>(_color); }

  bool skip() const;

  /** Return true if term is an interpreted constant or contains one as its subterm */
  bool hasInterpretedConstants() const { return _hasInterpretedConstants; }
  /** Assign value that will be returned by the hasInterpretedConstants() function */
  void setInterpretedConstantsPresence(bool value) { _hasInterpretedConstants=value; }

  /** Return true if term is either an if-then-else or a let...in expression */
  bool isSpecial() const { return functor() >= SPECIAL_FUNCTOR_LOWER_BOUND; }

  bool isITE()      const { return functor() == toNormalFunctor(SpecialFunctor::ITE); }
  bool isLet()      const { return functor() == toNormalFunctor(SpecialFunctor::LET); }
  bool isFormula()  const { return functor() == toNormalFunctor(SpecialFunctor::FORMULA); }
  bool isLambda()   const { return functor() == toNormalFunctor(SpecialFunctor::LAMBDA); }
  bool isMatch()    const { return functor() == toNormalFunctor(SpecialFunctor::MATCH); }
  bool isBoolean() const;
  bool isSuper() const; 
  
  /** Return pointer to structure containing extra data for special terms such as
   * if-then-else or let...in */
  const SpecialTermData* getSpecialData() const { return const_cast<Term*>(this)->getSpecialData(); }
  /** Return pointer to structure containing extra data for special terms such as
   * if-then-else or let...in */
  SpecialTermData* getSpecialData() {
    ASS(isSpecial());
    return reinterpret_cast<SpecialTermData*>(this)-1;
  }

protected:
  std::string headToString() const;

  unsigned computeDistinctVars() const;

  /**
   * Return argument order value stored in term.
   *
   * The default value (which is returned if no value was set using the
   * @c setArgumentOrder() function) is zero.
   *
   * Currently, this function is used only by @c Ordering::getEqualityArgumentOrder().
   */
  ArgumentOrderVals getArgumentOrderValue() const
  {
    return static_cast<ArgumentOrderVals>(_args[0]._order());
  }

  /**
   * Store argument order value in term.
   *
   * The value must be non-negative and less than 8.
   *
   * Currently, this function is used only by @c Ordering::getEqualityArgumentOrder().
   */
  void setArgumentOrderValue(ArgumentOrderVals val)
  {
    ASS_GE(val,AO_UNKNOWN);
    ASS_LE(val,AO_INCOMPARABLE);

    _args[0]._setOrder(val);
  }

  /** The number of this symbol in a signature */
  unsigned _functor;
  /** Arity of the symbol */
  unsigned _arity : 28;
  /** colour, used in interpolation and symbol elimination */
  unsigned _color : 2;
  /** Equal to 1 if the term/literal contains any interpreted constants */
  unsigned _hasInterpretedConstants : 1;
  /** If true, the object is an equality literal between two variables */
  unsigned _isTwoVarEquality : 1;
  /** Weight of the symbol, i.e. sum of symbol and variable occurrences. */
  unsigned _weight;
  /** Cached weight of the term for KBO, otherwise -1 and invalid. Note that
   * KBO symbol weights are not necessarily 1, so this can differ from @b _weight. */
  int _kboWeight;
  /** Epoch at which _kboWeight was cached. If this differs from s_kboEpoch the
   * cached weight is stale and must be recomputed. Initialized to 0 so it is
   * always stale before any KBO ordering is created (s_kboEpoch starts at 1). */
  unsigned _kboEpoch;
#if VDEBUG
  /** KBO instance that uses the cached value @b _kboWeight. */
  const void* _kboInstance;
#endif
  /** length of maximum reduction length */
  int _maxRedLen;
  union {
    /** If _isTwoVarEquality is false, this value is valid and contains
     * number of occurrences of variables */
    unsigned _vars;
    /** If _isTwoVarEquality is true, this value is valid and contains
     * the sort of the top-level variables */
    TermList _sort;
  };

  /** The list of arguments of size type arity + term arity + 1. The first
   *  argument stores the term weight and the mask (the last two bits are 0).
   */
  TermList _args[1];

  friend class TermList;
  friend class Indexing::TermSharing;
  friend class Ordering;

  /** Global KBO epoch counter. Incrementing this invalidates all per-term
   * cached KBO weights, allowing a new ordering to be used without iterating
   * all shared terms. Starts at 1 so _kboEpoch=0 (new terms) is always stale. */
  static unsigned s_kboEpoch;

public:
  /**
   * Iterator returning arguments of a term left-to-right.
   */
  class Iterator
  {
  public:
    DECL_ELEMENT_TYPE(TermList);
    Iterator(const Term* t) : _next(t->args()) {}
    bool hasNext() const { return _next->isNonEmpty(); }
    TermList next()
    {
      ASS(hasNext());
      TermList res = *_next;
      _next = _next->next();
      return res;
    }
  private:
    const TermList* _next;
  }; // Term::Iterator
}; // class Term


/**
 * Class of AtomicSort.
 */
class AtomicSort
  : public Term
{
public:
  AtomicSort();
  explicit AtomicSort(const AtomicSort& t) throw();

  AtomicSort(unsigned functor,unsigned arity) throw()
  {
    _functor = functor;
    _arity = arity;
    _args[0]._setLiteral(false);
    _args[0]._setSort(true);
  }

  static AtomicSort* create(unsigned typeCon, unsigned arity, const TermList* args);
  static AtomicSort* create2(unsigned tc, TermList arg1, TermList arg2);
  static AtomicSort* create(AtomicSort const* t,TermList* args);
  static AtomicSort* createNonShared(AtomicSort const* sort,TermList* args);
  static AtomicSort* createConstant(unsigned typeCon) { return create(typeCon,0,0); }
  static AtomicSort* createConstant(const std::string& name); 

  /** True if the sort is a higher-order arrow sort */
  bool isArrowSort() const;
  /** True if the sort $o */
  bool isBoolSort() const;
  /** true if sort is the sort of an array */
  bool isArraySort() const;
  /** true if sort is the sort of an tuple */
  bool isTupleSort() const;

  const std::string& typeConName() const;  
  
  static TermList arrowSort(const TermStack& domSorts, TermList range);
  static TermList arrowSort(TermList s1, TermList s2);
  static TermList arrowSort(TermList s1, TermList s2, TermList s3);
  static TermList arrowSort(unsigned size, const TermList* types, TermList range);
  static TermList arraySort(TermList indexSort, TermList innerSort);
  static TermList tupleSort(unsigned arity, TermList* sorts);
  static TermList defaultSort();
  static TermList superSort();
  static TermList boolSort();
  static TermList intSort();
  static TermList realSort();
  static TermList rationalSort();

  /** Reset all static caches (for library use when running multiple proofs) */
  static void resetStaticCaches();

private:

  static AtomicSort* createNonShared(unsigned typeCon, unsigned arity, TermList* arg);
  static AtomicSort* createNonSharedConstant(unsigned typeCon) { return createNonShared(typeCon,0,0); }
};

/**
 * Class of literals.
 * @since 06/05/2007 Manchester
 */
class Literal
  : public Term
{
public:
  /** True if equality literal */
  bool isEquality() const
  { return functor() == 0; }

  Literal();
  explicit Literal(const Literal& l) throw();

  /**
   * Create a literal.
   * @since 16/05/2007 Manchester
   */
  Literal(unsigned functor,unsigned arity,bool polarity) throw()
  {
    _functor = functor;
    _arity = arity;
    _args[0]._setPolarity(polarity);
    _args[0]._setSort(false);
    _args[0]._setLiteral(true);
  }

  /**
   * A unique header, 2*p is negative and 2*p+1 if positive where p is
   * the number of the predicate symbol.
   */
  unsigned header() const
  { return 2*_functor + polarity(); }
  /**
   * Header of the complementary literal, 2*p+1 is negative and 2*p
   * if positive where p is the number of the predicate symbol.
   */
  unsigned complementaryHeader() const
  { return 2*_functor + 1 - polarity(); }

  static bool headersMatch(Literal* l1, Literal* l2, bool complementary);
  /** set polarity to true or false */
  void setPolarity(bool positive)
  { _args[0]._setPolarity(positive); }

  TermList eqArgSort() const;
  
  // prevent bugs through implicit bool <-> unsigned conversions
  template<class Iter> static Literal* createFromIter(unsigned predicate, unsigned polarity, Iter iter) = delete;
  template<class Iter> static Literal* createFromIter(    bool predicate, unsigned polarity, Iter iter) = delete;
  template<class Iter> static Literal* createFromIter(    bool predicate,     bool polarity, Iter iter) = delete;

  template<class Iter>
  static Literal* createFromIter(unsigned predicate, bool polarity, Iter iter) {
    RStack<TermList> args;
    while (iter.hasNext()) {
      args->push(iter.next());
    }
    return Literal::create(predicate, args->size(), polarity, args->begin());
  }

  template<class Iter>
  static Literal* createFromIter(Literal* lit, Iter iter) {
    if (lit->isEquality()) {
      return  Literal::createEquality(lit->polarity(), iter.tryNext().unwrap(), iter.tryNext().unwrap(), lit->eqArgSort());
    } else {
      return Literal::createFromIter(lit->functor(), bool(lit->polarity()), std::move(iter));
    }
  }

  static Literal* create(unsigned predicate, unsigned arity, bool polarity, TermList* args);
  static Literal* create(unsigned predicate, bool polarity, std::initializer_list<TermList>);
  static Literal* create(Literal* l,bool polarity);
  static Literal* create(Literal* l,TermList* args);
  static Literal* createEquality(bool polarity, TermList arg1, TermList arg2, TermList sort);
  static Literal* create1(unsigned predicate, bool polarity, TermList arg);
  static Literal* create2(unsigned predicate, bool polarity, TermList arg1, TermList arg2);

  /**
   * Return the hash function of the top-level of a literal.
   * @since 30/03/2008 Flight Murcia-Manchester
   */
  template<bool flip = false>
  unsigned hash() const
  {
    return Literal::literalHash(functor(), polarity() ^ flip,
        [&](auto i) -> TermList const& { return *nthArgument(i); }, arity(),
        someIf(isTwoVarEquality(), [&](){ return twoVarEqSort(); }));
  }

  template<class GetArg>
  static unsigned literalEquals(const Literal* lit, unsigned functor, bool polarity, GetArg getArg, unsigned arity, Option<TermList> twoVarEqSort) {
    if (functor != lit->functor() || polarity != lit->polarity()) return false;

    if (functor == 0) { // i.e., isEquality
      ASS_EQ(arity, 2)
      ASS(rightArgOrder(getArg(0), getArg(1)))
      ASS(rightArgOrder(*lit->nthArgument(0), *lit->nthArgument(1)))

      if (someIf(lit->isTwoVarEquality(), [&](){ return lit->twoVarEqSort(); }) != twoVarEqSort) {
        return false;
      }
      return std::make_tuple(*lit->nthArgument(0), *lit->nthArgument(1)) == std::make_tuple(getArg(0), getArg(1));

    } else {
      ASS(twoVarEqSort.isNone())
      return range(0, arity).all([&](auto i) { return *lit->nthArgument(i) == getArg(i); });
    }
  }

  static bool rightArgOrder(TermList const& lhs, TermList const& rhs);

  template<class GetArg>
  static unsigned literalHash(unsigned functor, bool polarity, GetArg getArg, unsigned arity, Option<TermList> twoVarEqSort) {
    if (functor == 0) { // i.e., isEquality
      ASS_EQ(arity, 2)
      ASS(rightArgOrder(getArg(0), getArg(1)))
      return HashUtils::combine(
          DefaultHash::hash(polarity),
          DefaultHash::hash(functor),
          DefaultHash::hash(twoVarEqSort),
          getArg(0).defaultHash(),
          getArg(1).defaultHash());
    } else {
      ASS(twoVarEqSort.isNone())
      return HashUtils::combine(
          DefaultHash::hash(polarity),
          Term::termHash(functor, getArg, arity));
    }
  }



  static Literal* complementaryLiteral(Literal* l);
  /** If l is positive, return l; otherwise return its complementary literal. */
  static Literal* positiveLiteral(Literal* l) {
    return l->isPositive() ? l : complementaryLiteral(l);
  }

  // destructively swap arguments of an equation
  // the term is assumed to be non-shared
  void argSwap() {
    ASS(isEquality() && !shared());
    ASS(arity() == 2);

    TermList* ts1 = args();
    TermList* ts2 = ts1->next();
    using std::swap;//ADL
    swap(ts1->_content, ts2->_content);
  }

  /** true if positive */
  bool isPositive() const
  {
    return polarity();
  } // isPositive

  /** true if negative */
  bool isNegative() const
  {
    return !polarity();
  } // isNegative

  /** return polarity, 1 if positive and 0 if negative */
  int polarity() const
  {
    return _args[0]._polarity();
  } // polarity

  /**
   * Mark this object as an equality between two variables.
   */
  void markTwoVarEquality()
  {
    ASS(!shared());
    ASS(isEquality());
    ASS(nthArgument(0)->isVar() || !nthArgument(0)->term()->shared());
    ASS(nthArgument(1)->isVar() || !nthArgument(1)->term()->shared());

    _isTwoVarEquality = true;
  }


  /** Return sort of the variables in an equality between two variables.
   * This value is set during insertion into the term sharing structure
   */
  TermList twoVarEqSort() const
  {
    ASS(isTwoVarEquality());

    return _sort;
  }

  /** Assign sort of the variables in an equality between two variables. */
  void setTwoVarEqSort(TermList sort)
  {
    ASS(isTwoVarEquality());

    _sort = sort;
  }

//   /** Applied @b subst to the literal and return the result */
  Literal* apply(Substitution& subst);


  inline bool couldBeInstanceOf(Literal* lit, bool complementary)
  {
    ASS(shared());
    ASS(lit->shared());
    return headersMatch(this, lit, complementary);
  }

  bool isAnswerLiteral() const;

  friend std::ostream& operator<<(std::ostream& out, Kernel::Literal const& tl);
  std::string toString(bool reverseEquality = false) const;

  const std::string& predicateName() const;

private:
  template<class GetArg>
  static Literal* create(unsigned predicate, unsigned arity, bool polarity, GetArg args, Option<TermList> twoVarEqSort = Option<TermList>());
}; // class Literal

// TODO used in some proofExtra output
//      find a better place for this?
bool positionIn(TermList& subterm,TermList* term, std::string& position);
bool positionIn(TermList& subterm,Term* term, std::string& position);

/**
 * Hash used to make hashing over shared terms deterministic.
 */
struct SharedTermHash {
  static bool equals(Term* t1, Term* t2) { return t1==t2; }
  static unsigned hash(Term* t) { return t->getId(); }
};

/** helper lambda that turns a number into a variable */
static const auto unsignedToVarFn = [](unsigned var)
  { return TermList::var(var); };

} // namespace Kernel

template<>
struct std::hash<Kernel::TermList> {
  size_t operator()(Kernel::TermList const& t) const 
  { return t.defaultHash(); }
};

#endif