python-sat 1.8.dev19__tar.gz → 1.8.dev20__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 (98) hide show
  1. {python_sat-1.8.dev19/python_sat.egg-info → python_sat-1.8.dev20}/PKG-INFO +1 -1
  2. {python_sat-1.8.dev19 → python_sat-1.8.dev20}/pysat/__init__.py +1 -1
  3. {python_sat-1.8.dev19 → python_sat-1.8.dev20}/pysat/_fileio.py +30 -14
  4. {python_sat-1.8.dev19 → python_sat-1.8.dev20}/pysat/formula.py +123 -92
  5. {python_sat-1.8.dev19 → python_sat-1.8.dev20/python_sat.egg-info}/PKG-INFO +1 -1
  6. {python_sat-1.8.dev19 → python_sat-1.8.dev20}/LICENSE.txt +0 -0
  7. {python_sat-1.8.dev19 → python_sat-1.8.dev20}/MANIFEST.in +0 -0
  8. {python_sat-1.8.dev19 → python_sat-1.8.dev20}/README.rst +0 -0
  9. {python_sat-1.8.dev19 → python_sat-1.8.dev20}/allies/__init__.py +0 -0
  10. {python_sat-1.8.dev19 → python_sat-1.8.dev20}/allies/approxmc.py +0 -0
  11. {python_sat-1.8.dev19 → python_sat-1.8.dev20}/allies/unigen.py +0 -0
  12. {python_sat-1.8.dev19 → python_sat-1.8.dev20}/cardenc/bitwise.hh +0 -0
  13. {python_sat-1.8.dev19 → python_sat-1.8.dev20}/cardenc/card.hh +0 -0
  14. {python_sat-1.8.dev19 → python_sat-1.8.dev20}/cardenc/clset.hh +0 -0
  15. {python_sat-1.8.dev19 → python_sat-1.8.dev20}/cardenc/common.hh +0 -0
  16. {python_sat-1.8.dev19 → python_sat-1.8.dev20}/cardenc/itot.hh +0 -0
  17. {python_sat-1.8.dev19 → python_sat-1.8.dev20}/cardenc/ladder.hh +0 -0
  18. {python_sat-1.8.dev19 → python_sat-1.8.dev20}/cardenc/mto.hh +0 -0
  19. {python_sat-1.8.dev19 → python_sat-1.8.dev20}/cardenc/pairwise.hh +0 -0
  20. {python_sat-1.8.dev19 → python_sat-1.8.dev20}/cardenc/ptypes.hh +0 -0
  21. {python_sat-1.8.dev19 → python_sat-1.8.dev20}/cardenc/pycard.cc +0 -0
  22. {python_sat-1.8.dev19 → python_sat-1.8.dev20}/cardenc/seqcounter.hh +0 -0
  23. {python_sat-1.8.dev19 → python_sat-1.8.dev20}/cardenc/sortcard.hh +0 -0
  24. {python_sat-1.8.dev19 → python_sat-1.8.dev20}/cardenc/utils.hh +0 -0
  25. {python_sat-1.8.dev19 → python_sat-1.8.dev20}/examples/__init__.py +0 -0
  26. {python_sat-1.8.dev19 → python_sat-1.8.dev20}/examples/bica.py +0 -0
  27. {python_sat-1.8.dev19 → python_sat-1.8.dev20}/examples/fm.py +0 -0
  28. {python_sat-1.8.dev19 → python_sat-1.8.dev20}/examples/genhard.py +0 -0
  29. {python_sat-1.8.dev19 → python_sat-1.8.dev20}/examples/hitman.py +0 -0
  30. {python_sat-1.8.dev19 → python_sat-1.8.dev20}/examples/lbx.py +0 -0
  31. {python_sat-1.8.dev19 → python_sat-1.8.dev20}/examples/lsu.py +0 -0
  32. {python_sat-1.8.dev19 → python_sat-1.8.dev20}/examples/mcsls.py +0 -0
  33. {python_sat-1.8.dev19 → python_sat-1.8.dev20}/examples/models.py +0 -0
  34. {python_sat-1.8.dev19 → python_sat-1.8.dev20}/examples/musx.py +0 -0
  35. {python_sat-1.8.dev19 → python_sat-1.8.dev20}/examples/optux.py +0 -0
  36. {python_sat-1.8.dev19 → python_sat-1.8.dev20}/examples/primer.py +0 -0
  37. {python_sat-1.8.dev19 → python_sat-1.8.dev20}/examples/rc2.py +0 -0
  38. {python_sat-1.8.dev19 → python_sat-1.8.dev20}/examples/usage.py +0 -0
  39. {python_sat-1.8.dev19 → python_sat-1.8.dev20}/pysat/_utils.py +0 -0
  40. {python_sat-1.8.dev19 → python_sat-1.8.dev20}/pysat/card.py +0 -0
  41. {python_sat-1.8.dev19 → python_sat-1.8.dev20}/pysat/engines.py +0 -0
  42. {python_sat-1.8.dev19 → python_sat-1.8.dev20}/pysat/pb.py +0 -0
  43. {python_sat-1.8.dev19 → python_sat-1.8.dev20}/pysat/process.py +0 -0
  44. {python_sat-1.8.dev19 → python_sat-1.8.dev20}/pysat/solvers.py +0 -0
  45. {python_sat-1.8.dev19 → python_sat-1.8.dev20}/python_sat.egg-info/SOURCES.txt +0 -0
  46. {python_sat-1.8.dev19 → python_sat-1.8.dev20}/python_sat.egg-info/dependency_links.txt +0 -0
  47. {python_sat-1.8.dev19 → python_sat-1.8.dev20}/python_sat.egg-info/requires.txt +0 -0
  48. {python_sat-1.8.dev19 → python_sat-1.8.dev20}/python_sat.egg-info/top_level.txt +0 -0
  49. {python_sat-1.8.dev19 → python_sat-1.8.dev20}/requirements.txt +0 -0
  50. {python_sat-1.8.dev19 → python_sat-1.8.dev20}/setup.cfg +0 -0
  51. {python_sat-1.8.dev19 → python_sat-1.8.dev20}/setup.py +0 -0
  52. {python_sat-1.8.dev19 → python_sat-1.8.dev20}/solvers/cadical103.tar.gz +0 -0
  53. {python_sat-1.8.dev19 → python_sat-1.8.dev20}/solvers/cadical153.tar.gz +0 -0
  54. {python_sat-1.8.dev19 → python_sat-1.8.dev20}/solvers/cadical170.tar.gz +0 -0
  55. {python_sat-1.8.dev19 → python_sat-1.8.dev20}/solvers/cadical195.tar.gz +0 -0
  56. {python_sat-1.8.dev19 → python_sat-1.8.dev20}/solvers/glucose30.tar.gz +0 -0
  57. {python_sat-1.8.dev19 → python_sat-1.8.dev20}/solvers/glucose41.tar.gz +0 -0
  58. {python_sat-1.8.dev19 → python_sat-1.8.dev20}/solvers/glucose421.tar.gz +0 -0
  59. {python_sat-1.8.dev19 → python_sat-1.8.dev20}/solvers/lingeling.tar.gz +0 -0
  60. {python_sat-1.8.dev19 → python_sat-1.8.dev20}/solvers/maplechrono.zip +0 -0
  61. {python_sat-1.8.dev19 → python_sat-1.8.dev20}/solvers/maplecm.zip +0 -0
  62. {python_sat-1.8.dev19 → python_sat-1.8.dev20}/solvers/maplesat.zip +0 -0
  63. {python_sat-1.8.dev19 → python_sat-1.8.dev20}/solvers/mergesat3.tar.gz +0 -0
  64. {python_sat-1.8.dev19 → python_sat-1.8.dev20}/solvers/minicard.tar.gz +0 -0
  65. {python_sat-1.8.dev19 → python_sat-1.8.dev20}/solvers/minisat22.tar.gz +0 -0
  66. {python_sat-1.8.dev19 → python_sat-1.8.dev20}/solvers/minisatgh.zip +0 -0
  67. {python_sat-1.8.dev19 → python_sat-1.8.dev20}/solvers/patches/cadical103.patch +0 -0
  68. {python_sat-1.8.dev19 → python_sat-1.8.dev20}/solvers/patches/cadical153.patch +0 -0
  69. {python_sat-1.8.dev19 → python_sat-1.8.dev20}/solvers/patches/cadical195.patch +0 -0
  70. {python_sat-1.8.dev19 → python_sat-1.8.dev20}/solvers/patches/glucose30.patch +0 -0
  71. {python_sat-1.8.dev19 → python_sat-1.8.dev20}/solvers/patches/glucose41.patch +0 -0
  72. {python_sat-1.8.dev19 → python_sat-1.8.dev20}/solvers/patches/glucose421.patch +0 -0
  73. {python_sat-1.8.dev19 → python_sat-1.8.dev20}/solvers/patches/gluecard30.patch +0 -0
  74. {python_sat-1.8.dev19 → python_sat-1.8.dev20}/solvers/patches/gluecard41.patch +0 -0
  75. {python_sat-1.8.dev19 → python_sat-1.8.dev20}/solvers/patches/lingeling.patch +0 -0
  76. {python_sat-1.8.dev19 → python_sat-1.8.dev20}/solvers/patches/maplechrono.patch +0 -0
  77. {python_sat-1.8.dev19 → python_sat-1.8.dev20}/solvers/patches/maplecm.patch +0 -0
  78. {python_sat-1.8.dev19 → python_sat-1.8.dev20}/solvers/patches/maplesat.patch +0 -0
  79. {python_sat-1.8.dev19 → python_sat-1.8.dev20}/solvers/patches/mergesat3.patch +0 -0
  80. {python_sat-1.8.dev19 → python_sat-1.8.dev20}/solvers/patches/minicard.patch +0 -0
  81. {python_sat-1.8.dev19 → python_sat-1.8.dev20}/solvers/patches/minisat22.patch +0 -0
  82. {python_sat-1.8.dev19 → python_sat-1.8.dev20}/solvers/patches/minisatgh.patch +0 -0
  83. {python_sat-1.8.dev19 → python_sat-1.8.dev20}/solvers/prepare.py +0 -0
  84. {python_sat-1.8.dev19 → python_sat-1.8.dev20}/solvers/pysolvers.cc +0 -0
  85. {python_sat-1.8.dev19 → python_sat-1.8.dev20}/tests/test_accum_stats.py +0 -0
  86. {python_sat-1.8.dev19 → python_sat-1.8.dev20}/tests/test_atmost.py +0 -0
  87. {python_sat-1.8.dev19 → python_sat-1.8.dev20}/tests/test_atmost1.py +0 -0
  88. {python_sat-1.8.dev19 → python_sat-1.8.dev20}/tests/test_atmostk.py +0 -0
  89. {python_sat-1.8.dev19 → python_sat-1.8.dev20}/tests/test_boolengine.py +0 -0
  90. {python_sat-1.8.dev19 → python_sat-1.8.dev20}/tests/test_clausification.py +0 -0
  91. {python_sat-1.8.dev19 → python_sat-1.8.dev20}/tests/test_cnf.py +0 -0
  92. {python_sat-1.8.dev19 → python_sat-1.8.dev20}/tests/test_equals1.py +0 -0
  93. {python_sat-1.8.dev19 → python_sat-1.8.dev20}/tests/test_formula_unique.py +0 -0
  94. {python_sat-1.8.dev19 → python_sat-1.8.dev20}/tests/test_process.py +0 -0
  95. {python_sat-1.8.dev19 → python_sat-1.8.dev20}/tests/test_propagate.py +0 -0
  96. {python_sat-1.8.dev19 → python_sat-1.8.dev20}/tests/test_unique_model.py +0 -0
  97. {python_sat-1.8.dev19 → python_sat-1.8.dev20}/tests/test_unique_mus.py +0 -0
  98. {python_sat-1.8.dev19 → python_sat-1.8.dev20}/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.dev19
3
+ Version: 1.8.dev20
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
@@ -10,7 +10,7 @@
10
10
 
11
11
  # current version
12
12
  #==============================================================================
13
- VERSION = (1, 8, 'dev', 19)
13
+ VERSION = (1, 8, 'dev', 20)
14
14
 
15
15
 
16
16
  # PEP440 Format
@@ -22,11 +22,12 @@
22
22
  Module description
23
23
  ==================
24
24
 
25
- This simple module provides a basic interface to input/output operations on
26
- files. Its key design feature is the ability to work with both uncompressed
27
- and compressed files through a unified interface, thus, making it easier
28
- for a user to deal with various types of compressed files. The compression
29
- types supported include gzip, bzip2, and lzma (xz).
25
+ This simple module provides a basic interface to input/output operations
26
+ on files. Its key design feature is the ability to work with both
27
+ uncompressed and compressed files through a unified interface, thus,
28
+ making it easier for a user to deal with various types of compressed
29
+ files. The compression types supported include gzip, bzip2, lzma (xz), and
30
+ zstandard (zstd).
30
31
 
31
32
  The module is supposed to be mainly used by :mod:`pysat.formula`.
32
33
 
@@ -66,6 +67,13 @@ except ImportError:
66
67
  except ImportError: # for Python2 without lzma
67
68
  lzma_present = False
68
69
 
70
+ zstd_present = True
71
+ try:
72
+ from compression import zstd
73
+ except ImportError: # zstandard is introduced in Python 3.14
74
+ zstd_present = False
75
+
76
+
69
77
 
70
78
  #
71
79
  #==============================================================================
@@ -75,9 +83,10 @@ class FileObject(object):
75
83
  open files creating standard file pointers and closing them. The class
76
84
  is used when opening DIMACS files for reading and writing. Supports
77
85
  both uncompressed and compressed files. Compression algorithms
78
- supported are ``gzip``, ``bzip2``, and ``lzma``. Algorithm ``lzma`` can
79
- be used in Python 3 by default and also in Python 2 if the
80
- ``backports.lzma`` package is installed.
86
+ supported are ``gzip``, ``bzip2``, ``lzma``, and ``zstd``. Algorithm
87
+ ``lzma`` can be used in Python 3 by default and also in Python 2 if
88
+ the ``backports.lzma`` package is installed. Algorithm ``zstandard``
89
+ can be used in Python 3.14 and later.
81
90
 
82
91
  Note that the class opens a file in text mode.
83
92
 
@@ -90,8 +99,9 @@ class FileObject(object):
90
99
  :type compression: str
91
100
 
92
101
  Compression type can be ``None``, ``'gzip'``, ``'bzip2'``, ``'lzma'``,
93
- as well as ``'use_ext'``. If ``'use_ext'`` is specified, compression
94
- algorithm is defined by the extension of the given file name.
102
+ ``'zstd'``, as well as ``'use_ext'``. If ``'use_ext'`` is specified,
103
+ compression algorithm is defined by the extension of the given file
104
+ name.
95
105
  """
96
106
 
97
107
  def __init__(self, name, mode='r', compression=None):
@@ -109,9 +119,9 @@ class FileObject(object):
109
119
 
110
120
  def open(self, name, mode='r', compression=None):
111
121
  """
112
- Open a file pointer. Note that a file is *always* opened in text
113
- mode. The method inherits its input parameters from the constructor
114
- of :class:`FileObject`.
122
+ Open a file pointer. Note that a file is *always* opened in
123
+ text mode. The method inherits its input parameters from the
124
+ constructor of :class:`FileObject`.
115
125
  """
116
126
 
117
127
  if compression == 'use_ext':
@@ -138,11 +148,15 @@ class FileObject(object):
138
148
  self.fp = codecs.getreader('ascii')(self.fp_extra)
139
149
  else: # mode == 'w'
140
150
  self.fp = codecs.getwriter('ascii')(self.fp_extra)
141
- else: # self.ctype == 'lzma'
151
+ elif self.ctype == 'lzma':
142
152
  # LZMA is available in Python 2 only if backports.lzma is installed
143
153
  # Python 3 supports it by default
144
154
  assert lzma_present, 'LZMA compression is unavailable.'
145
155
  self.fp = lzma.open(name, mode=mode + 't')
156
+ else: # self.ctype == 'zstd'
157
+ # Zstandard is available only in Python 3.14 and later
158
+ assert zstd_present, 'Zstandard compression is unavailable.'
159
+ self.fp = zstd.open(name, mode=mode + 't')
146
160
 
147
161
  def close(self):
148
162
  """
@@ -175,6 +189,8 @@ class FileObject(object):
175
189
  self.ctype = 'bzip2'
176
190
  elif ext in ('.xz', '.lzma'):
177
191
  self.ctype = 'lzma'
192
+ elif ext == 'zst':
193
+ self.ctype = 'zstd'
178
194
  else:
179
195
  self.ctype = None
180
196
 
@@ -1170,7 +1170,7 @@ class Formula(object):
1170
1170
  self.clausify()
1171
1171
 
1172
1172
  # then recursively iterate through the clauses
1173
- for cl in self._iter(outermost=True):
1173
+ for cl in self._iter({}, outermost=True):
1174
1174
  if PYSAT_TRUE.name not in cl:
1175
1175
  yield [l for l in cl if l != PYSAT_FALSE.name]
1176
1176
 
@@ -1421,16 +1421,19 @@ class Atom(Formula):
1421
1421
  self.encoded = [] # always empty
1422
1422
  self.object = None
1423
1423
 
1424
- def _iter(self, outermost=False):
1424
+ def _iter(self, seen, outermost=False):
1425
1425
  """
1426
1426
  Internal iterator over the clauses. Does nothing as there are no
1427
1427
  clauses to iterate through.
1428
1428
  """
1429
1429
 
1430
- if outermost:
1431
- yield from self.clauses
1432
- else:
1433
- yield from self.encoded
1430
+ if not self in seen:
1431
+ seen[self] = True
1432
+
1433
+ if outermost:
1434
+ yield from self.clauses
1435
+ else:
1436
+ yield from self.encoded
1434
1437
 
1435
1438
  def _clausify(self, name_required=True):
1436
1439
  """
@@ -1602,20 +1605,23 @@ class And(Formula):
1602
1605
  self.encoded = []
1603
1606
  self.subformulas = []
1604
1607
 
1605
- def _iter(self, outermost=False):
1608
+ def _iter(self, seen, outermost=False):
1606
1609
  """
1607
1610
  Internal iterator over the clauses. First, iterates through the
1608
1611
  clauses of the subformulas followed by the formula's own clauses.
1609
1612
  """
1610
1613
 
1611
- for sub in self.subformulas:
1612
- for cl in sub._iter():
1613
- yield cl
1614
+ if not self in seen:
1615
+ seen[self] = True
1614
1616
 
1615
- if outermost:
1616
- yield from self.clauses
1617
- else:
1618
- yield from self.encoded
1617
+ for sub in self.subformulas:
1618
+ for cl in sub._iter(seen):
1619
+ yield cl
1620
+
1621
+ if outermost:
1622
+ yield from self.clauses
1623
+ else:
1624
+ yield from self.encoded
1619
1625
 
1620
1626
  def simplified(self, assumptions=[]):
1621
1627
  """
@@ -1835,20 +1841,23 @@ class Or(Formula):
1835
1841
  self.encoded = []
1836
1842
  self.subformulas = []
1837
1843
 
1838
- def _iter(self, outermost=False):
1844
+ def _iter(self, seen, outermost=False):
1839
1845
  """
1840
1846
  Internal iterator over the clauses. First, iterates through the
1841
1847
  clauses of the subformulas followed by the formula's own clauses.
1842
1848
  """
1843
1849
 
1844
- for sub in self.subformulas:
1845
- for cl in sub._iter():
1846
- yield cl
1850
+ if not self in seen:
1851
+ seen[self] = True
1847
1852
 
1848
- if outermost:
1849
- yield from self.clauses
1850
- else:
1851
- yield from self.encoded
1853
+ for sub in self.subformulas:
1854
+ for cl in sub._iter(seen):
1855
+ yield cl
1856
+
1857
+ if outermost:
1858
+ yield from self.clauses
1859
+ else:
1860
+ yield from self.encoded
1852
1861
 
1853
1862
  def simplified(self, assumptions=[]):
1854
1863
  """
@@ -2031,18 +2040,21 @@ class Neg(Formula):
2031
2040
  self.encoded = []
2032
2041
  self.subformula = None
2033
2042
 
2034
- def _iter(self, outermost=False):
2043
+ def _iter(self, seen, outermost=False):
2035
2044
  """
2036
2045
  Recursive iterator through the clauses.
2037
2046
  """
2038
2047
 
2039
- for cl in self.subformula._iter():
2040
- yield cl
2048
+ if not self in seen:
2049
+ seen[self] = True
2041
2050
 
2042
- if outermost:
2043
- yield from self.clauses
2044
- else:
2045
- yield from self.encoded
2051
+ for cl in self.subformula._iter(seen):
2052
+ yield cl
2053
+
2054
+ if outermost:
2055
+ yield from self.clauses
2056
+ else:
2057
+ yield from self.encoded
2046
2058
 
2047
2059
  def simplified(self, assumptions=[]):
2048
2060
  """
@@ -2198,21 +2210,24 @@ class Implies(Formula):
2198
2210
  self.encoded = []
2199
2211
  self.left = self.right = None
2200
2212
 
2201
- def _iter(self, outermost=False):
2213
+ def _iter(self, seen, outermost=False):
2202
2214
  """
2203
2215
  Clause iterator. Recursively iterates through the clauses of
2204
2216
  ``left`` and ``right`` subformulas followed by own clause
2205
2217
  traversal.
2206
2218
  """
2207
2219
 
2208
- for sub in [self.left, self.right]:
2209
- for cl in sub._iter():
2210
- yield cl
2220
+ if not self in seen:
2221
+ seen[self] = True
2211
2222
 
2212
- if outermost:
2213
- yield from self.clauses
2214
- else:
2215
- yield from self.encoded
2223
+ for sub in [self.left, self.right]:
2224
+ for cl in sub._iter(seen):
2225
+ yield cl
2226
+
2227
+ if outermost:
2228
+ yield from self.clauses
2229
+ else:
2230
+ yield from self.encoded
2216
2231
 
2217
2232
  def simplified(self, assumptions=[]):
2218
2233
  """
@@ -2421,20 +2436,23 @@ class Equals(Formula):
2421
2436
  self.encoded = []
2422
2437
  self.subformulas = []
2423
2438
 
2424
- def _iter(self, outermost=False):
2439
+ def _iter(self, seen, outermost=False):
2425
2440
  """
2426
2441
  Internal iterator over the clauses. First, iterates through the
2427
2442
  clauses of the subformulas followed by the formula's own clauses.
2428
2443
  """
2429
2444
 
2430
- for sub in self.subformulas:
2431
- for cl in sub._iter():
2432
- yield cl
2445
+ if not self in seen:
2446
+ seen[self] = True
2433
2447
 
2434
- if outermost:
2435
- yield from self.clauses
2436
- else:
2437
- yield from self.encoded
2448
+ for sub in self.subformulas:
2449
+ for cl in sub._iter(seen):
2450
+ yield cl
2451
+
2452
+ if outermost:
2453
+ yield from self.clauses
2454
+ else:
2455
+ yield from self.encoded
2438
2456
 
2439
2457
  def simplified(self, assumptions=[]):
2440
2458
  """
@@ -2679,20 +2697,23 @@ class XOr(Formula):
2679
2697
  self.encoded = []
2680
2698
  self.subformulas = []
2681
2699
 
2682
- def _iter(self, outermost=False):
2700
+ def _iter(self, seen, outermost=False):
2683
2701
  """
2684
2702
  Internal iterator over the clauses. First, iterates through the
2685
2703
  clauses of the subformulas followed by the formula's own clauses.
2686
2704
  """
2687
2705
 
2688
- for sub in self.subformulas:
2689
- for cl in sub._iter():
2690
- yield cl
2706
+ if not self in seen:
2707
+ seen[self] = True
2691
2708
 
2692
- if outermost:
2693
- yield from self.clauses
2694
- else:
2695
- yield from self.encoded
2709
+ for sub in self.subformulas:
2710
+ for cl in sub._iter(seen):
2711
+ yield cl
2712
+
2713
+ if outermost:
2714
+ yield from self.clauses
2715
+ else:
2716
+ yield from self.encoded
2696
2717
 
2697
2718
  def simplified(self, assumptions=[]):
2698
2719
  """
@@ -2945,20 +2966,23 @@ class ITE(Formula):
2945
2966
  self.encoded = []
2946
2967
  self.cond = self.cons1 = self.cons2 = None
2947
2968
 
2948
- def _iter(self, outermost=False):
2969
+ def _iter(self, seen, outermost=False):
2949
2970
  """
2950
2971
  Internal iterator over the clauses. First, iterates through the
2951
2972
  clauses of the subformulas followed by the formula's own clauses.
2952
2973
  """
2953
2974
 
2954
- for sub in [self.cond, self.cons1, self.cons2]:
2955
- for cl in sub._iter():
2956
- yield cl
2975
+ if not self in seen:
2976
+ seen[self] = True
2957
2977
 
2958
- if outermost:
2959
- yield from self.clauses
2960
- else:
2961
- yield from self.encoded
2978
+ for sub in [self.cond, self.cons1, self.cons2]:
2979
+ for cl in sub._iter(seen):
2980
+ yield cl
2981
+
2982
+ if outermost:
2983
+ yield from self.clauses
2984
+ else:
2985
+ yield from self.encoded
2962
2986
 
2963
2987
  def simplified(self, assumptions=[]):
2964
2988
  """
@@ -3180,7 +3204,7 @@ class CNF(Formula, object):
3180
3204
  Read a CNF formula from a file in the DIMACS format. A file name is
3181
3205
  expected as an argument. A default argument is ``comment_lead`` for
3182
3206
  parsing comment lines. A given file can be compressed by either
3183
- gzip, bzip2, or lzma.
3207
+ gzip, bzip2, lzma, or zstd.
3184
3208
 
3185
3209
  :param fname: name of a file to parse.
3186
3210
  :param comment_lead: a list of characters leading comment lines
@@ -3191,11 +3215,12 @@ class CNF(Formula, object):
3191
3215
  :type compressed_with: str
3192
3216
 
3193
3217
  Note that the ``compressed_with`` parameter can be ``None`` (i.e.
3194
- the file is uncompressed), ``'gzip'``, ``'bzip2'``, ``'lzma'``, or
3195
- ``'use_ext'``. The latter value indicates that compression type
3196
- should be automatically determined based on the file extension.
3197
- Using ``'lzma'`` in Python 2 requires the ``backports.lzma``
3198
- package to be additionally installed.
3218
+ the file is uncompressed), ``'gzip'``, ``'bzip2'``, ``'lzma'``,
3219
+ ``'zstd'``, or ``'use_ext'``. The latter value indicates that
3220
+ compression type should be automatically determined based on the
3221
+ file extension. Using ``'lzma'`` in Python 2 requires the
3222
+ ``backports.lzma`` package to be additionally installed. Using
3223
+ ``'zstd'`` requires Python 3.14.
3199
3224
 
3200
3225
  Usage example:
3201
3226
 
@@ -3413,7 +3438,7 @@ class CNF(Formula, object):
3413
3438
  CNF format. A file name is expected as an argument. Additionally,
3414
3439
  supplementary comment lines can be specified in the ``comments``
3415
3440
  parameter. Also, a file can be compressed using either gzip, bzip2,
3416
- or lzma (xz).
3441
+ lzma (xz), or zstd.
3417
3442
 
3418
3443
  :param fname: a file name where to store the formula.
3419
3444
  :param comments: additional comments to put in the file.
@@ -3425,12 +3450,13 @@ class CNF(Formula, object):
3425
3450
  :type as_dnf: bool
3426
3451
  :type compress_with: str
3427
3452
 
3428
- Note that the ``compress_with`` parameter can be ``None`` (i.e.
3429
- the file is uncompressed), ``'gzip'``, ``'bzip2'``, ``'lzma'``, or
3430
- ``'use_ext'``. The latter value indicates that compression type
3431
- should be automatically determined based on the file extension.
3432
- Using ``'lzma'`` in Python 2 requires the ``backports.lzma``
3433
- package to be additionally installed.
3453
+ Note that the ``compressed_with`` parameter can be ``None`` (i.e.
3454
+ the file is uncompressed), ``'gzip'``, ``'bzip2'``, ``'lzma'``,
3455
+ ``'zstd'``, or ``'use_ext'``. The latter value indicates that
3456
+ compression type should be automatically determined based on the
3457
+ file extension. Using ``'lzma'`` in Python 2 requires the
3458
+ ``backports.lzma`` package to be additionally installed. Using
3459
+ ``'zstd'`` requires Python 3.14.
3434
3460
 
3435
3461
  Example:
3436
3462
 
@@ -3858,16 +3884,19 @@ class CNF(Formula, object):
3858
3884
 
3859
3885
  dest |= set(range(1, self.nv + 1))
3860
3886
 
3861
- def _iter(self, outermost=False):
3887
+ def _iter(self, seen, outermost=False):
3862
3888
  """
3863
3889
  This is a copy of :meth:`__iter__`, to be consistent with
3864
3890
  :class:`Formula`.
3865
3891
  """
3866
3892
 
3867
- if outermost:
3868
- yield from self.clauses
3869
- else:
3870
- yield from self.encoded
3893
+ if not self in seen:
3894
+ seen[self] = True
3895
+
3896
+ if outermost:
3897
+ yield from self.clauses
3898
+ else:
3899
+ yield from self.encoded
3871
3900
 
3872
3901
  def simplified(self, assumptions=[]):
3873
3902
  """
@@ -3933,7 +3962,7 @@ class WCNF(object):
3933
3962
  Read a WCNF formula from a file in the DIMACS format. A file name
3934
3963
  is expected as an argument. A default argument is ``comment_lead``
3935
3964
  for parsing comment lines. A given file can be compressed by either
3936
- gzip, bzip2, or lzma.
3965
+ gzip, bzip2, lzma, or zstd.
3937
3966
 
3938
3967
  :param fname: name of a file to parse.
3939
3968
  :param comment_lead: a list of characters leading comment lines
@@ -3944,11 +3973,12 @@ class WCNF(object):
3944
3973
  :type compressed_with: str
3945
3974
 
3946
3975
  Note that the ``compressed_with`` parameter can be ``None`` (i.e.
3947
- the file is uncompressed), ``'gzip'``, ``'bzip2'``, ``'lzma'``, or
3948
- ``'use_ext'``. The latter value indicates that compression type
3949
- should be automatically determined based on the file extension.
3950
- Using ``'lzma'`` in Python 2 requires the ``backports.lzma``
3951
- package to be additionally installed.
3976
+ the file is uncompressed), ``'gzip'``, ``'bzip2'``, ``'lzma'``,
3977
+ ``'zstd'``, or ``'use_ext'``. The latter value indicates that
3978
+ compression type should be automatically determined based on the
3979
+ file extension. Using ``'lzma'`` in Python 2 requires the
3980
+ ``backports.lzma`` package to be additionally installed. Using
3981
+ ``'zstd'`` requires Python 3.14.
3952
3982
 
3953
3983
  Usage example:
3954
3984
 
@@ -4149,7 +4179,7 @@ class WCNF(object):
4149
4179
  CNF format. A file name is expected as an argument. Additionally,
4150
4180
  supplementary comment lines can be specified in the ``comments``
4151
4181
  parameter. Also, a file can be compressed using either gzip, bzip2,
4152
- or lzma (xz).
4182
+ lzma (xz), or zstd.
4153
4183
 
4154
4184
  :param fname: a file name where to store the formula.
4155
4185
  :param comments: additional comments to put in the file.
@@ -4159,12 +4189,13 @@ class WCNF(object):
4159
4189
  :type comments: list(str)
4160
4190
  :type compress_with: str
4161
4191
 
4162
- Note that the ``compress_with`` parameter can be ``None`` (i.e.
4163
- the file is uncompressed), ``'gzip'``, ``'bzip2'``, ``'lzma'``, or
4164
- ``'use_ext'``. The latter value indicates that compression type
4165
- should be automatically determined based on the file extension.
4166
- Using ``'lzma'`` in Python 2 requires the ``backports.lzma``
4167
- package to be additionally installed.
4192
+ Note that the ``compressed_with`` parameter can be ``None`` (i.e.
4193
+ the file is uncompressed), ``'gzip'``, ``'bzip2'``, ``'lzma'``,
4194
+ ``'zstd'``, or ``'use_ext'``. The latter value indicates that
4195
+ compression type should be automatically determined based on the
4196
+ file extension. Using ``'lzma'`` in Python 2 requires the
4197
+ ``backports.lzma`` package to be additionally installed. Using
4198
+ ``'zstd'`` requires Python 3.14.
4168
4199
 
4169
4200
  Example:
4170
4201
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: python-sat
3
- Version: 1.8.dev19
3
+ Version: 1.8.dev20
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
File without changes
File without changes