python-sat 1.8.dev18__tar.gz → 1.8.dev19__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (99) hide show
  1. {python-sat-1.8.dev18/python_sat.egg-info → python_sat-1.8.dev19}/PKG-INFO +1 -1
  2. {python-sat-1.8.dev18 → python_sat-1.8.dev19}/examples/bica.py +5 -5
  3. {python-sat-1.8.dev18 → python_sat-1.8.dev19}/pysat/__init__.py +1 -1
  4. {python-sat-1.8.dev18 → python_sat-1.8.dev19}/pysat/formula.py +78 -74
  5. {python-sat-1.8.dev18 → python_sat-1.8.dev19/python_sat.egg-info}/PKG-INFO +1 -1
  6. python_sat-1.8.dev19/tests/test_formula_unique.py +101 -0
  7. python-sat-1.8.dev18/tests/test_formula_unique.py +0 -38
  8. {python-sat-1.8.dev18 → python_sat-1.8.dev19}/LICENSE.txt +0 -0
  9. {python-sat-1.8.dev18 → python_sat-1.8.dev19}/MANIFEST.in +0 -0
  10. {python-sat-1.8.dev18 → python_sat-1.8.dev19}/README.rst +0 -0
  11. {python-sat-1.8.dev18 → python_sat-1.8.dev19}/allies/__init__.py +0 -0
  12. {python-sat-1.8.dev18 → python_sat-1.8.dev19}/allies/approxmc.py +0 -0
  13. {python-sat-1.8.dev18 → python_sat-1.8.dev19}/allies/unigen.py +0 -0
  14. {python-sat-1.8.dev18 → python_sat-1.8.dev19}/cardenc/bitwise.hh +0 -0
  15. {python-sat-1.8.dev18 → python_sat-1.8.dev19}/cardenc/card.hh +0 -0
  16. {python-sat-1.8.dev18 → python_sat-1.8.dev19}/cardenc/clset.hh +0 -0
  17. {python-sat-1.8.dev18 → python_sat-1.8.dev19}/cardenc/common.hh +0 -0
  18. {python-sat-1.8.dev18 → python_sat-1.8.dev19}/cardenc/itot.hh +0 -0
  19. {python-sat-1.8.dev18 → python_sat-1.8.dev19}/cardenc/ladder.hh +0 -0
  20. {python-sat-1.8.dev18 → python_sat-1.8.dev19}/cardenc/mto.hh +0 -0
  21. {python-sat-1.8.dev18 → python_sat-1.8.dev19}/cardenc/pairwise.hh +0 -0
  22. {python-sat-1.8.dev18 → python_sat-1.8.dev19}/cardenc/ptypes.hh +0 -0
  23. {python-sat-1.8.dev18 → python_sat-1.8.dev19}/cardenc/pycard.cc +0 -0
  24. {python-sat-1.8.dev18 → python_sat-1.8.dev19}/cardenc/seqcounter.hh +0 -0
  25. {python-sat-1.8.dev18 → python_sat-1.8.dev19}/cardenc/sortcard.hh +0 -0
  26. {python-sat-1.8.dev18 → python_sat-1.8.dev19}/cardenc/utils.hh +0 -0
  27. {python-sat-1.8.dev18 → python_sat-1.8.dev19}/examples/__init__.py +0 -0
  28. {python-sat-1.8.dev18 → python_sat-1.8.dev19}/examples/fm.py +0 -0
  29. {python-sat-1.8.dev18 → python_sat-1.8.dev19}/examples/genhard.py +0 -0
  30. {python-sat-1.8.dev18 → python_sat-1.8.dev19}/examples/hitman.py +0 -0
  31. {python-sat-1.8.dev18 → python_sat-1.8.dev19}/examples/lbx.py +0 -0
  32. {python-sat-1.8.dev18 → python_sat-1.8.dev19}/examples/lsu.py +0 -0
  33. {python-sat-1.8.dev18 → python_sat-1.8.dev19}/examples/mcsls.py +0 -0
  34. {python-sat-1.8.dev18 → python_sat-1.8.dev19}/examples/models.py +0 -0
  35. {python-sat-1.8.dev18 → python_sat-1.8.dev19}/examples/musx.py +0 -0
  36. {python-sat-1.8.dev18 → python_sat-1.8.dev19}/examples/optux.py +0 -0
  37. {python-sat-1.8.dev18 → python_sat-1.8.dev19}/examples/primer.py +0 -0
  38. {python-sat-1.8.dev18 → python_sat-1.8.dev19}/examples/rc2.py +0 -0
  39. {python-sat-1.8.dev18 → python_sat-1.8.dev19}/examples/usage.py +0 -0
  40. {python-sat-1.8.dev18 → python_sat-1.8.dev19}/pysat/_fileio.py +0 -0
  41. {python-sat-1.8.dev18 → python_sat-1.8.dev19}/pysat/_utils.py +0 -0
  42. {python-sat-1.8.dev18 → python_sat-1.8.dev19}/pysat/card.py +0 -0
  43. {python-sat-1.8.dev18 → python_sat-1.8.dev19}/pysat/engines.py +0 -0
  44. {python-sat-1.8.dev18 → python_sat-1.8.dev19}/pysat/pb.py +0 -0
  45. {python-sat-1.8.dev18 → python_sat-1.8.dev19}/pysat/process.py +0 -0
  46. {python-sat-1.8.dev18 → python_sat-1.8.dev19}/pysat/solvers.py +0 -0
  47. {python-sat-1.8.dev18 → python_sat-1.8.dev19}/python_sat.egg-info/SOURCES.txt +0 -0
  48. {python-sat-1.8.dev18 → python_sat-1.8.dev19}/python_sat.egg-info/dependency_links.txt +0 -0
  49. {python-sat-1.8.dev18 → python_sat-1.8.dev19}/python_sat.egg-info/requires.txt +0 -0
  50. {python-sat-1.8.dev18 → python_sat-1.8.dev19}/python_sat.egg-info/top_level.txt +0 -0
  51. {python-sat-1.8.dev18 → python_sat-1.8.dev19}/requirements.txt +0 -0
  52. {python-sat-1.8.dev18 → python_sat-1.8.dev19}/setup.cfg +0 -0
  53. {python-sat-1.8.dev18 → python_sat-1.8.dev19}/setup.py +0 -0
  54. {python-sat-1.8.dev18 → python_sat-1.8.dev19}/solvers/cadical103.tar.gz +0 -0
  55. {python-sat-1.8.dev18 → python_sat-1.8.dev19}/solvers/cadical153.tar.gz +0 -0
  56. {python-sat-1.8.dev18 → python_sat-1.8.dev19}/solvers/cadical170.tar.gz +0 -0
  57. {python-sat-1.8.dev18 → python_sat-1.8.dev19}/solvers/cadical195.tar.gz +0 -0
  58. {python-sat-1.8.dev18 → python_sat-1.8.dev19}/solvers/glucose30.tar.gz +0 -0
  59. {python-sat-1.8.dev18 → python_sat-1.8.dev19}/solvers/glucose41.tar.gz +0 -0
  60. {python-sat-1.8.dev18 → python_sat-1.8.dev19}/solvers/glucose421.tar.gz +0 -0
  61. {python-sat-1.8.dev18 → python_sat-1.8.dev19}/solvers/lingeling.tar.gz +0 -0
  62. {python-sat-1.8.dev18 → python_sat-1.8.dev19}/solvers/maplechrono.zip +0 -0
  63. {python-sat-1.8.dev18 → python_sat-1.8.dev19}/solvers/maplecm.zip +0 -0
  64. {python-sat-1.8.dev18 → python_sat-1.8.dev19}/solvers/maplesat.zip +0 -0
  65. {python-sat-1.8.dev18 → python_sat-1.8.dev19}/solvers/mergesat3.tar.gz +0 -0
  66. {python-sat-1.8.dev18 → python_sat-1.8.dev19}/solvers/minicard.tar.gz +0 -0
  67. {python-sat-1.8.dev18 → python_sat-1.8.dev19}/solvers/minisat22.tar.gz +0 -0
  68. {python-sat-1.8.dev18 → python_sat-1.8.dev19}/solvers/minisatgh.zip +0 -0
  69. {python-sat-1.8.dev18 → python_sat-1.8.dev19}/solvers/patches/cadical103.patch +0 -0
  70. {python-sat-1.8.dev18 → python_sat-1.8.dev19}/solvers/patches/cadical153.patch +0 -0
  71. {python-sat-1.8.dev18 → python_sat-1.8.dev19}/solvers/patches/cadical195.patch +0 -0
  72. {python-sat-1.8.dev18 → python_sat-1.8.dev19}/solvers/patches/glucose30.patch +0 -0
  73. {python-sat-1.8.dev18 → python_sat-1.8.dev19}/solvers/patches/glucose41.patch +0 -0
  74. {python-sat-1.8.dev18 → python_sat-1.8.dev19}/solvers/patches/glucose421.patch +0 -0
  75. {python-sat-1.8.dev18 → python_sat-1.8.dev19}/solvers/patches/gluecard30.patch +0 -0
  76. {python-sat-1.8.dev18 → python_sat-1.8.dev19}/solvers/patches/gluecard41.patch +0 -0
  77. {python-sat-1.8.dev18 → python_sat-1.8.dev19}/solvers/patches/lingeling.patch +0 -0
  78. {python-sat-1.8.dev18 → python_sat-1.8.dev19}/solvers/patches/maplechrono.patch +0 -0
  79. {python-sat-1.8.dev18 → python_sat-1.8.dev19}/solvers/patches/maplecm.patch +0 -0
  80. {python-sat-1.8.dev18 → python_sat-1.8.dev19}/solvers/patches/maplesat.patch +0 -0
  81. {python-sat-1.8.dev18 → python_sat-1.8.dev19}/solvers/patches/mergesat3.patch +0 -0
  82. {python-sat-1.8.dev18 → python_sat-1.8.dev19}/solvers/patches/minicard.patch +0 -0
  83. {python-sat-1.8.dev18 → python_sat-1.8.dev19}/solvers/patches/minisat22.patch +0 -0
  84. {python-sat-1.8.dev18 → python_sat-1.8.dev19}/solvers/patches/minisatgh.patch +0 -0
  85. {python-sat-1.8.dev18 → python_sat-1.8.dev19}/solvers/prepare.py +0 -0
  86. {python-sat-1.8.dev18 → python_sat-1.8.dev19}/solvers/pysolvers.cc +0 -0
  87. {python-sat-1.8.dev18 → python_sat-1.8.dev19}/tests/test_accum_stats.py +0 -0
  88. {python-sat-1.8.dev18 → python_sat-1.8.dev19}/tests/test_atmost.py +0 -0
  89. {python-sat-1.8.dev18 → python_sat-1.8.dev19}/tests/test_atmost1.py +0 -0
  90. {python-sat-1.8.dev18 → python_sat-1.8.dev19}/tests/test_atmostk.py +0 -0
  91. {python-sat-1.8.dev18 → python_sat-1.8.dev19}/tests/test_boolengine.py +0 -0
  92. {python-sat-1.8.dev18 → python_sat-1.8.dev19}/tests/test_clausification.py +0 -0
  93. {python-sat-1.8.dev18 → python_sat-1.8.dev19}/tests/test_cnf.py +0 -0
  94. {python-sat-1.8.dev18 → python_sat-1.8.dev19}/tests/test_equals1.py +0 -0
  95. {python-sat-1.8.dev18 → python_sat-1.8.dev19}/tests/test_process.py +0 -0
  96. {python-sat-1.8.dev18 → python_sat-1.8.dev19}/tests/test_propagate.py +0 -0
  97. {python-sat-1.8.dev18 → python_sat-1.8.dev19}/tests/test_unique_model.py +0 -0
  98. {python-sat-1.8.dev18 → python_sat-1.8.dev19}/tests/test_unique_mus.py +0 -0
  99. {python-sat-1.8.dev18 → python_sat-1.8.dev19}/tests/test_warmstart.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: python-sat
3
- Version: 1.8.dev18
3
+ Version: 1.8.dev19
4
4
  Summary: A Python library for prototyping with SAT oracles
5
5
  Home-page: https://github.com/pysathq/pysat
6
6
  Author: Alexey Ignatiev, Joao Marques-Silva, Antonio Morgado
@@ -51,7 +51,7 @@
51
51
  navigation to determine the Southern Celestial Pole.)
52
52
 
53
53
  .. [1] Alexey Ignatiev, Alessandro Previti, Joao Marques-Silva.
54
- *SAT-Based Formula Simplification*. SAT 2015. pp.287-298
54
+ *SAT-Based Formula Simplification*. SAT 2015. pp. 287-298
55
55
 
56
56
  .. [2] Willard V. Quine. *The Problem of Simplifying Truth Functions*.
57
57
  American Mathematical Monthly 59(8). 1952. pp. 521-531
@@ -262,10 +262,10 @@ class Bica:
262
262
 
263
263
  """
264
264
 
265
- def __init__(self, formula, negated=None, target='cnf', psolver='g3',
265
+ def __init__(self, formula, negated=None, target='cnf', psolver='cd19',
266
266
  padapt=False, pdcalls=False, pexhaust=False, pminz=False,
267
267
  ppuresat=False, psearch='lin', punsorted=False, ptrim=False,
268
- osolver='g3', oadapt=False, odcalls=False, oexhaust=False,
268
+ osolver='mgh', oadapt=False, odcalls=False, oexhaust=False,
269
269
  ominz=False, onodisj=False, opuresat=False, ounsorted=False,
270
270
  otrim=False, weighted=False, verbose=0):
271
271
  """
@@ -538,7 +538,7 @@ def parse_options():
538
538
  ominz = False
539
539
  nodisj = False
540
540
  psolver = 'cd19'
541
- osolver = 'cd19'
541
+ osolver = 'mgh'
542
542
  ppuresat = False
543
543
  opuresat = False
544
544
  punsorted = False
@@ -638,7 +638,7 @@ def usage():
638
638
  print(' -s, --psolver SAT solver to use [Primer]')
639
639
  print(' Available values: cd, cd15, cd19, g3, g41, g42, lgl, mcb, mcm, mpl, m22, mc, mg3, mgh (default = cd19)')
640
640
  print(' -S, --osolver SAT solver to use [OptUx]')
641
- print(' Available values: cd, cd15, cd19, g3, g41, g42, lgl, mcb, mcm, mpl, m22, mc, mg3, mgh (default = cd19)')
641
+ print(' Available values: cd, cd15, cd19, g3, g41, g42, lgl, mcb, mcm, mpl, m22, mc, mg3, mgh (default = mgh)')
642
642
  print(' -t, --ptrim=<int> How many times to trim unsatisfiable cores [Primer]')
643
643
  print(' Available values: [0 .. INT_MAX] (default = 0)')
644
644
  print(' -T, --otrim=<int> How many times to trim unsatisfiable cores [OptUx]')
@@ -10,7 +10,7 @@
10
10
 
11
11
  # current version
12
12
  #==============================================================================
13
- VERSION = (1, 8, 'dev', 18)
13
+ VERSION = (1, 8, 'dev', 19)
14
14
 
15
15
 
16
16
  # PEP440 Format
@@ -879,45 +879,26 @@ class Formula(object):
879
879
  if type(collection) in (tuple, list, set):
880
880
  collection = tuple(filter(lambda x: x or x == False, collection))
881
881
 
882
- if len(collection) > 1:
883
- if _hashable(collection):
884
- # it is a hashable iterable; it is better to sort it
885
- items.append((prefix, repr(sorted(collection, key=lambda x: hash(x)))))
882
+ for item in collection:
883
+ if isinstance(item, Iterable):
884
+ items.extend(_flatten(item, prefix=prefix))
886
885
  else:
887
- for i, item in enumerate(collection):
888
- if _hashable(item):
889
- # it is a hashable iterable; it is better to sort it
890
- if isinstance(item, Iterable):
891
- item = sorted(item, key=lambda x: hash(x))
892
-
893
- items.append((prefix, repr(item)))
894
- elif isinstance(item, Iterable):
895
- items.extend(_flatten(item, prefix=prefix))
896
- else:
897
- raise FormulaError('No key can be computed for this formula object')
898
- elif collection:
899
- items.extend(_flatten(collection[0], prefix=prefix))
886
+ items.append((prefix, item))
900
887
 
901
888
  # next, checking if it is a dictionary
902
889
  elif isinstance(collection, dict):
903
890
  for key in collection.keys():
904
891
  value = collection[key]
905
892
  new_key = prefix + sep + key if prefix else key
906
- if value and _hashable(value):
907
- # it is a hashable iterable; it is better to sort it
908
- if isinstance(value, Iterable):
909
- value = sorted(value, key=lambda x: hash(x))
910
-
911
- items.append((new_key, repr(value)))
912
- elif isinstance(value, Iterable):
913
- if value:
914
- items.extend(_flatten(value, new_key, sep=sep))
893
+ if isinstance(value, Iterable) and value:
894
+ items.extend(_flatten(value, prefix=new_key, sep=sep))
915
895
  else:
916
- raise FormulaError('No key can be computed for this formula object')
896
+
897
+ items.append((new_key, value))
917
898
 
918
899
  # finally, it is a simple non-empty object
919
900
  elif collection or collection == False:
920
- items.append((prefix, repr(collection)))
901
+ items.append((prefix, collection))
921
902
 
922
903
  return items
923
904
 
@@ -929,46 +910,68 @@ class Formula(object):
929
910
  args[0] = tuple(args[0][1:])
930
911
 
931
912
  # flattening all the inputs
932
- key = _flatten(args) + _flatten(kwargs)
933
-
934
- # we can arguments with but also without keywords:
935
- if len(key) == 2 and key[0][0] == '':
936
- # there are two components in the key and the first one is unnamed
937
- # this can happen for Atom or Neg and it so we name it accordingly
938
- key[0] = ('object' if key[1][1] == repr(FormulaType.ATOM) else 'subformula', key[0][1])
939
- elif len(key) == 3 and key[2][1] == repr(FormulaType.IMPL):
940
- if key[0][0] == '' and key[1][0] == '':
941
- key[0] = ('left', key[0][1])
942
- key[1] = ('right', key[1][1])
943
- elif key[1][0] == 'left':
944
- key[0] = ('right', key[0][1])
945
- elif key[1][0] == 'right':
946
- key[0] = ('left', key[0][1])
947
- elif len(key) == 4 and key[3][1] == repr(FormulaType.ITE):
948
- # dealing with ITE triples - the most complicated case
949
- if key[0][0] == '' and key[1][0] == '' and key[2][0] == '':
950
- key[0] = ('cond', key[0][1])
951
- key[1] = ('cons1', key[1][1])
952
- key[2] = ('cons2', key[2][1])
953
- elif key[0][0] == key[1][0] == '':
954
- if key[2][0] == 'cond':
955
- key[0] = ('cons1', key[0][1])
956
- key[1] = ('cons2', key[1][1])
957
- elif key[2][0] == 'cons1':
958
- key[0] = ('cond', key[0][1])
959
- key[1] = ('cons2', key[1][1])
960
- elif key[2][0] == 'cons2':
961
- key[0] = ('cond', key[0][1])
962
- key[1] = ('cons1', key[1][1])
963
- elif key[0] == '':
964
- if 'cond' not in (key[1][0], key[2][0]):
965
- key[0] = ('cond', key[0][0])
966
- elif 'cons1' not in (key[1][0], key[2][0]):
967
- key[0] = ('cons1', key[0][0])
968
- elif 'cons2' not in (key[1][0], key[2][0]):
969
- key[0] = ('cons2', key[0][0])
970
-
971
- return tuple(sorted(key))
913
+ items = _flatten(args) + _flatten(kwargs)
914
+ ftype, subfs, extra = None, [], []
915
+
916
+ # ignoring everything except subformulas and the type
917
+ for item in items:
918
+ if item[0] == 'type':
919
+ ftype = item
920
+ elif item[0] != 'merge':
921
+ subfs.append(item)
922
+ else:
923
+ extra = [('merge', repr(item[1]))]
924
+
925
+ # the ugly part:
926
+ # reconstructing the key pairs, depending on the type of Formula
927
+ if ftype[1] == FormulaType.ATOM:
928
+ assert len(subfs) == 1, 'A single object is required for an Atom formula'
929
+ subfs[0] = ('object', repr(subfs[0][1]))
930
+ elif ftype[1] == FormulaType.NEG:
931
+ assert len(subfs) == 1, 'A single subformula is required for a Neg formula'
932
+ subfs[0] = ('subformula', id(subfs[0][1]))
933
+ elif ftype[1] == FormulaType.IMPL:
934
+ assert len(subfs) == 2, 'Two subformulas are required for an Implies formula'
935
+ if subfs[0][0] == '' and subfs[1][0] == '':
936
+ subfs[0] = ('left', id(subfs[0][1]))
937
+ subfs[1] = ('right', id(subfs[1][1]))
938
+ elif subfs[1][0] == 'left':
939
+ subfs[0] = ('right', id(subfs[0][1]))
940
+ elif subfs[1][0] == 'right':
941
+ subfs[0] = ('left', id(subfs[0][1]))
942
+ elif ftype[1] == FormulaType.ITE:
943
+ assert len(subfs) == 3, 'Three subformulas are required for an ITE formula'
944
+ if subfs[0][0] == '' and subfs[1][0] == '' and subfs[2][0] == '':
945
+ subfs[0] = ('cond', id(subfs[0][1]))
946
+ subfs[1] = ('cons1', id(subfs[1][1]))
947
+ subfs[2] = ('cons2', id(subfs[2][1]))
948
+ elif subfs[0][0] == subfs[1][0] == '':
949
+ if subfs[2][0] == 'cond':
950
+ subfs[0] = ('cons1', id(subfs[0][1]))
951
+ subfs[1] = ('cons2', id(subfs[1][1]))
952
+ elif subfs[2][0] == 'cons1':
953
+ subfs[0] = ('cond', id(subfs[0][1]))
954
+ subfs[1] = ('cons2', id(subfs[1][1]))
955
+ elif subfs[2][0] == 'cons2':
956
+ subfs[0] = ('cond', id(subfs[0][1]))
957
+ subfs[1] = ('cons1', id(subfs[1][1]))
958
+ elif subfs[0] == '':
959
+ if 'cond' not in (subfs[1][0], subfs[2][0]):
960
+ subfs[0] = ('cond', id(subfs[0][0]))
961
+ elif 'cons1' not in (subfs[1][0], subfs[2][0]):
962
+ subfs[0] = ('cons1', id(subfs[0][0]))
963
+ elif 'cons2' not in (subfs[1][0], subfs[2][0]):
964
+ subfs[0] = ('cons2', id(subfs[0][0]))
965
+ else:
966
+ # these are commutative connectives; we need to sort the arguments
967
+ assert len(subfs) >= 1, 'At least one subformula is required for an And/Equals/Or/XOr formula'
968
+ subfs = sorted(map(lambda p: (p[0], repr(id(p[1]))), subfs))
969
+
970
+ if not extra:
971
+ extra = [('merge', repr(False))]
972
+
973
+ # the key is a string combining all the parts
974
+ return ' '.join([f'{repr(p[0])}:{repr(p[1])}' for p in [ftype] + subfs + extra])
972
975
 
973
976
  def __hash__(self):
974
977
  """
@@ -1126,7 +1129,7 @@ class Formula(object):
1126
1129
  b)``.
1127
1130
  """
1128
1131
 
1129
- return XOr(self, other)
1132
+ return XOr(self, other, merge=True)
1130
1133
 
1131
1134
  def __ixor__(self, other):
1132
1135
  """
@@ -1135,7 +1138,7 @@ class Formula(object):
1135
1138
  ``a`` to a new object ``XOr(a, b)``.
1136
1139
  """
1137
1140
 
1138
- return XOr(self, other)
1141
+ return XOr(self, other, merge=True)
1139
1142
 
1140
1143
  def __iter__(self):
1141
1144
  """
@@ -1547,7 +1550,7 @@ class And(Formula):
1547
1550
  "And[And[Atom('x'), Atom('y')], Atom('z')]"
1548
1551
  >>> repr(a2)
1549
1552
  "And[Atom('x'), Atom('y'), Atom('z')]"
1550
- >>> repr(a2)
1553
+ >>> repr(a3)
1551
1554
  "And[Atom('x'), Atom('y'), Atom('z')]"
1552
1555
  >>>
1553
1556
  >>> id(a1) == id(a2)
@@ -2648,8 +2651,9 @@ class XOr(Formula):
2648
2651
  def __init__(self, *args, **kwargs):
2649
2652
  """
2650
2653
  Initialiser. Expects a list of arguments signifying the operands
2651
- of the equivalence. Additionally, a user may set a keyword
2652
- argument ``merge=True``, which will enable merging sub-operands.
2654
+ of the exclusive disjunction. Additionally, a user may set a
2655
+ keyword argument ``merge=True``, which will enable merging
2656
+ sub-operands.
2653
2657
  """
2654
2658
 
2655
2659
  super(XOr, self).__init__(type=FormulaType.XOR)
@@ -2663,7 +2667,7 @@ class XOr(Formula):
2663
2667
  self.merged = False
2664
2668
 
2665
2669
  if len(self.subformulas) < 2:
2666
- raise FormulaError('Equivalence requires at least 2 arguments')
2670
+ raise FormulaError('XOr requires at least 2 arguments')
2667
2671
 
2668
2672
  def __del__(self):
2669
2673
  """
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: python-sat
3
- Version: 1.8.dev18
3
+ Version: 1.8.dev19
4
4
  Summary: A Python library for prototyping with SAT oracles
5
5
  Home-page: https://github.com/pysathq/pysat
6
6
  Author: Alexey Ignatiev, Joao Marques-Silva, Antonio Morgado
@@ -0,0 +1,101 @@
1
+ from pysat.formula import *
2
+ from itertools import permutations
3
+
4
+ def test_atom_uniqueness():
5
+ x1, x2 = Atom('x'), Atom(object='x') # same atom
6
+ z = Atom('z') # a different atom
7
+
8
+ assert x1 is x2, 'Atoms should be the same object'
9
+ assert x1 is not z, 'Atoms should be different objects'
10
+
11
+ def test_2and_uniqueness():
12
+ x1, x2 = Atom('x'), Atom('x') # same atom
13
+ y = Atom('y') # a different atom
14
+
15
+ a = And(x1, y)
16
+ b = And(y, x1)
17
+ c = And(x2, y)
18
+ d = And(y, x2)
19
+
20
+ assert id(a) == id(b) == id(c) == id(d), 'All 2-and\'s should be the same object'
21
+
22
+ def test_3and_uniqueness():
23
+ x, y, z = Atom('x'), Atom('y'), Atom('z')
24
+
25
+ a = And(x, y, z)
26
+
27
+ for comb in permutations([x, y, z]):
28
+ assert And(*comb) is a, 'All 3-and\'s should be the same object'
29
+ assert And(comb) is a, 'All 3-and\'s should be the same object'
30
+
31
+ def test_3or_uniqueness():
32
+ x, y, z = Atom('x'), Atom('y'), Atom('z')
33
+
34
+ a = Or(x, y, z)
35
+
36
+ for comb in permutations([x, y, z]):
37
+ assert Or(*comb) is a, 'All 3-and\'s should be the same object'
38
+ assert Or(comb) is a, 'All 3-and\'s should be the same object'
39
+
40
+ def test_impl_uniqueness():
41
+ x, y = Atom('x'), Atom('y')
42
+
43
+ a = x >> y
44
+ b = y >> x
45
+
46
+ a2 = Implies(x, y)
47
+
48
+ assert a is a2, 'Non-unique implication is detected'
49
+ assert a is not b, 'Implication is not commutative'
50
+
51
+ def test_ite_uniqueness():
52
+ x, y, z = Atom('x'), Atom('y'), Atom('z')
53
+
54
+ a = ITE(x, y, z)
55
+
56
+ for comb in permutations([x, y, z]):
57
+ if comb == (x, y, z):
58
+ continue
59
+
60
+ assert ITE(*comb) is not a, 'ITE is not commutative'
61
+
62
+ def test_xor_uniqueness():
63
+ x, y, z = Atom('x'), Atom('y'), Atom('z')
64
+
65
+ a = XOr(x, y, z, merge=True)
66
+ b = XOr(x, y, z, merge=False)
67
+
68
+ for comb in permutations([x, y, z]):
69
+ assert XOr(*comb, merge=True) is a, 'All 3-xor\'s should be the same object'
70
+
71
+ for comb in permutations([x, y, z]):
72
+ assert XOr(*comb, merge=False) is b, 'All 3-xor\'s should be the same object'
73
+ assert XOr(*comb) is b, 'All 3-xor\'s should be the same object'
74
+
75
+ def test_equals_uniqueness():
76
+ x, y, z = Atom('x'), Atom('y'), Atom('z')
77
+
78
+ a = Equals(x, y, z, merge=True)
79
+ b = Equals(x, y, z, merge=False)
80
+
81
+ for comb in permutations([x, y, z]):
82
+ assert Equals(*comb, merge=True) is a, 'All 3-equality\'s should be the same object'
83
+
84
+ for comb in permutations([x, y, z]):
85
+ assert Equals(*comb, merge=False) is b, 'All 3-equality\'s should be the same object'
86
+ assert Equals(*comb) is b, 'All 3-equality\'s should be the same object'
87
+
88
+ def test_complex():
89
+ x, y, z = Atom('x'), Atom('y'), Atom('z')
90
+
91
+ f1 = XOr(x, y, z, merge=False)
92
+ g1 = Or(f1, z, x, merge=True)
93
+ h1 = And(y, g1, x, merge=True)
94
+
95
+ f2 = XOr(z, y, x, merge=False)
96
+ g2 = Or(x, f2, z, merge=True)
97
+ h2 = And(x, g2, y, merge=True)
98
+
99
+ assert f1 is f2, 'Complex uniqueness fail: step 1'
100
+ assert g1 is g2, 'Complex uniqueness fail: step 2'
101
+ assert h1 is h2, 'Complex uniqueness fail: step 3'
@@ -1,38 +0,0 @@
1
- from pysat.formula import *
2
- from itertools import permutations
3
-
4
- def test_atom_uniqueness():
5
- x1, x2 = Atom('x'), Atom('x') # same atom
6
- z = Atom('z') # a different atom
7
-
8
- assert x1 is x2, 'Atoms should be the same object'
9
- assert x1 is not z, 'Atoms should be different objects'
10
-
11
- def test_2and_uniqueness():
12
- x1, x2 = Atom('x'), Atom('x') # same atom
13
- y = Atom('y') # a different atom
14
-
15
- a = And(x1, y)
16
- b = And(y, x1)
17
- c = And(x2, y)
18
- d = And(y, x2)
19
-
20
- assert id(a) == id(b) == id(c) == id(d), 'All 2-and\'s should be the same object'
21
-
22
- def test_3and_uniqueness():
23
- x, y, z = Atom('x'), Atom('y'), Atom('z')
24
-
25
- a = And(x, y, z)
26
-
27
- for comb in permutations([x, y, z]):
28
- assert And(*comb) is a, 'All 3-and\'s should be the same object'
29
- assert And(comb) is a, 'All 3-and\'s should be the same object'
30
-
31
- def test_3or_uniqueness():
32
- x, y, z = Atom('x'), Atom('y'), Atom('z')
33
-
34
- a = Or(x, y, z)
35
-
36
- for comb in permutations([x, y, z]):
37
- assert Or(*comb) is a, 'All 3-and\'s should be the same object'
38
- assert Or(comb) is a, 'All 3-and\'s should be the same object'
File without changes
File without changes