python-sat 0.1.8.dev10__cp310-cp310-win_amd64.whl → 1.8.dev26__cp310-cp310-win_amd64.whl

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.

Potentially problematic release.


This version of python-sat might be problematic. Click here for more details.

Files changed (45) hide show
  1. pycard.cp310-win_amd64.pyd +0 -0
  2. pysat/__init__.py +4 -4
  3. pysat/_fileio.py +30 -14
  4. pysat/allies/approxmc.py +22 -22
  5. pysat/allies/unigen.py +435 -0
  6. pysat/card.py +13 -12
  7. pysat/engines.py +1302 -0
  8. pysat/examples/bbscan.py +663 -0
  9. pysat/examples/bica.py +691 -0
  10. pysat/examples/fm.py +12 -8
  11. pysat/examples/genhard.py +24 -23
  12. pysat/examples/hitman.py +53 -37
  13. pysat/examples/lbx.py +56 -15
  14. pysat/examples/lsu.py +28 -14
  15. pysat/examples/mcsls.py +53 -15
  16. pysat/examples/models.py +6 -4
  17. pysat/examples/musx.py +15 -7
  18. pysat/examples/optux.py +71 -32
  19. pysat/examples/primer.py +620 -0
  20. pysat/examples/rc2.py +268 -69
  21. pysat/formula.py +3241 -229
  22. pysat/pb.py +85 -37
  23. pysat/process.py +16 -2
  24. pysat/solvers.py +2119 -724
  25. pysolvers.cp310-win_amd64.pyd +0 -0
  26. {python_sat-0.1.8.dev10.data → python_sat-1.8.dev26.data}/scripts/approxmc.py +22 -22
  27. python_sat-1.8.dev26.data/scripts/bbscan.py +663 -0
  28. python_sat-1.8.dev26.data/scripts/bica.py +691 -0
  29. {python_sat-0.1.8.dev10.data → python_sat-1.8.dev26.data}/scripts/fm.py +12 -8
  30. {python_sat-0.1.8.dev10.data → python_sat-1.8.dev26.data}/scripts/genhard.py +24 -23
  31. {python_sat-0.1.8.dev10.data → python_sat-1.8.dev26.data}/scripts/lbx.py +56 -15
  32. {python_sat-0.1.8.dev10.data → python_sat-1.8.dev26.data}/scripts/lsu.py +28 -14
  33. {python_sat-0.1.8.dev10.data → python_sat-1.8.dev26.data}/scripts/mcsls.py +53 -15
  34. {python_sat-0.1.8.dev10.data → python_sat-1.8.dev26.data}/scripts/models.py +6 -4
  35. {python_sat-0.1.8.dev10.data → python_sat-1.8.dev26.data}/scripts/musx.py +15 -7
  36. {python_sat-0.1.8.dev10.data → python_sat-1.8.dev26.data}/scripts/optux.py +71 -32
  37. python_sat-1.8.dev26.data/scripts/primer.py +620 -0
  38. {python_sat-0.1.8.dev10.data → python_sat-1.8.dev26.data}/scripts/rc2.py +268 -69
  39. python_sat-1.8.dev26.data/scripts/unigen.py +435 -0
  40. {python_sat-0.1.8.dev10.dist-info → python_sat-1.8.dev26.dist-info}/METADATA +19 -5
  41. python_sat-1.8.dev26.dist-info/RECORD +48 -0
  42. {python_sat-0.1.8.dev10.dist-info → python_sat-1.8.dev26.dist-info}/WHEEL +1 -1
  43. python_sat-0.1.8.dev10.dist-info/RECORD +0 -39
  44. {python_sat-0.1.8.dev10.dist-info → python_sat-1.8.dev26.dist-info/licenses}/LICENSE.txt +0 -0
  45. {python_sat-0.1.8.dev10.dist-info → python_sat-1.8.dev26.dist-info}/top_level.txt +0 -0
@@ -99,7 +99,7 @@
99
99
  from __future__ import print_function
100
100
  import getopt
101
101
  import os
102
- from pysat.formula import CNFPlus, WCNFPlus
102
+ from pysat.formula import CNFPlus, WCNFPlus, CNF
103
103
  from pysat.solvers import Solver, SolverNames
104
104
  import re
105
105
  import sys
@@ -116,7 +116,7 @@ class MUSX(object):
116
116
  soft clauses is still unsatisfiable together with the hard clauses.
117
117
 
118
118
  The constructor of :class:`MUSX` objects receives a target
119
- :class:`.WCNF` formula, a SAT solver name, and a verbosity level. Note
119
+ :class:`.CNF` or `.WCNF` formula, a SAT solver name, and a verbosity level. Note
120
120
  that the default SAT solver is MiniSat22 (referred to as ``'m22'``, see
121
121
  :class:`.SolverNames` for details). The default verbosity level is
122
122
  ``1``.
@@ -140,13 +140,21 @@ class MUSX(object):
140
140
  # clause selectors and a mapping from selectors to clause ids
141
141
  self.sels, self.vmap = [], {}
142
142
 
143
+ # to deal with a CNF* formula, we create its weighted version
144
+ if isinstance(formula, CNF):
145
+ formula = formula.weighted()
146
+
143
147
  # constructing the oracle
144
148
  self.oracle = Solver(name=solver, bootstrap_with=formula.hard,
145
149
  use_timer=True)
146
150
 
147
151
  if isinstance(formula, WCNFPlus) and formula.atms:
148
- assert self.oracle.supports_atmost(), \
149
- '{0} does not support native cardinality constraints. Make sure you use the right type of formula.'.format(solver_name)
152
+ # we are using CaDiCaL195 and it can use external linear engine
153
+ if solver in SolverNames.cadical195:
154
+ self.oracle.activate_atmost()
155
+
156
+ assert self.oracle.supports_atmost(), ('{0} does not support native cardinality constraints. Make sure you'
157
+ ' use the right type of formula.').format(solver)
150
158
 
151
159
  for atm in formula.atms:
152
160
  self.oracle.add_atmost(*atm)
@@ -219,7 +227,7 @@ class MUSX(object):
219
227
 
220
228
  Soft clauses are (de)activated using the standard MiniSat-like
221
229
  assumptions interface [2]_. Each soft clause :math:`c` is augmented
222
- with a selector literal :math:`s`, e.g. :math:`(c) \gets (c \\vee
230
+ with a selector literal :math:`s`, e.g. :math:`(c) \\gets (c \\vee
223
231
  \\neg{s})`. As a result, clause :math:`c` can be activated by
224
232
  assuming literal :math:`s`. The over-approximation provided as an
225
233
  input is specified as a list of selector literals for clauses in
@@ -308,7 +316,7 @@ def usage():
308
316
  print('Options:')
309
317
  print(' -h, --help')
310
318
  print(' -s, --solver SAT solver to use')
311
- print(' Available values: g3, lgl, mcb, mcm, mpl, m22, mc, mgh (default: m22)')
319
+ print(' Available values: cd15, cd19, g3, lgl, mcb, mcm, mpl, m22, mc, mgh (default: m22)')
312
320
  print(' -v, --verbose Be verbose')
313
321
 
314
322
 
@@ -319,7 +327,7 @@ if __name__ == '__main__':
319
327
 
320
328
  if files:
321
329
  # parsing the input formula
322
- if re.search('\.wcnf[p|+]?(\.(gz|bz2|lzma|xz))?$', files[0]):
330
+ if re.search(r'\.wcnf[p|+]?(\.(gz|bz2|lzma|xz|zst))?$', files[0]):
323
331
  formula = WCNFPlus(from_file=files[0])
324
332
  else: # expecting '*.cnf[,p,+].*'
325
333
  formula = CNFPlus(from_file=files[0]).weighted()
@@ -111,7 +111,8 @@ import os
111
111
  from pysat.examples.hitman import Atom, Hitman
112
112
  from pysat.examples.rc2 import RC2
113
113
  from pysat.formula import CNFPlus, WCNFPlus
114
- from pysat.solvers import Solver
114
+ from pysat.process import Processor
115
+ from pysat.solvers import Solver, SolverNames
115
116
  import re
116
117
  import sys
117
118
 
@@ -130,10 +131,12 @@ class OptUx(object):
130
131
 
131
132
  As a result, OptUx applies exhaustive *disjoint* minimal correction
132
133
  subset (MCS) enumeration [1]_, [2]_, [3]_, [4]_ with the incremental
133
- use of RC2 [5]_ as an underlying MaxSAT solver. Once disjoint MCSes
134
- are enumerated, they are used to bootstrap a hitting set solver. This
135
- implementation uses :class:`.Hitman` as a hitting set solver, which is
136
- again based on RC2.
134
+ use of RC2 [5]_ as an underlying MaxSAT solver. Disjoint MCS
135
+ enumeration is run only if the corresponding input parameter
136
+ ``nodisj`` is set to ``False``. Once disjoint MCSes are enumerated,
137
+ they are used to bootstrap a hitting set solver. This implementation
138
+ uses :class:`.Hitman` as a hitting set solver, which is again based on
139
+ RC2.
137
140
 
138
141
  Note that in the main implicit hitting enumeration loop of the
139
142
  algorithm, OptUx follows Forqes in that it does not reduce correction
@@ -166,6 +169,11 @@ class OptUx(object):
166
169
  support *hard* phase setting, i.e. user preferences will not be
167
170
  overwritten by the *phase saving* heuristic [8]_.
168
171
 
172
+ Additionally, the input formula can be preprocessed before running MUS
173
+ enumeration. This is controlled by the input parameter ``process``
174
+ whose integer value signifies the number of processing rounds to be
175
+ applied. The number of rounds is set to 0 by default.
176
+
169
177
  Finally, one more optional input parameter ``cover`` is to be used
170
178
  when exhaustive enumeration of MUSes is not necessary and the tool can
171
179
  stop as soon as a given formula is covered by the set of currently
@@ -195,6 +203,8 @@ class OptUx(object):
195
203
  :param dcalls: apply clause D oracle calls (for unsorted enumeration only)
196
204
  :param exhaust: do core exhaustion
197
205
  :param minz: do heuristic core reduction
206
+ :param nodisj: do not enumerate disjoint MCSes
207
+ :param process: apply formula preprocessing this many times
198
208
  :param puresat: use pure SAT-based hitting set enumeration
199
209
  :param unsorted: apply unsorted MUS enumeration
200
210
  :param trim: do core trimming at most this number of times
@@ -207,6 +217,8 @@ class OptUx(object):
207
217
  :type dcalls: bool
208
218
  :type exhaust: bool
209
219
  :type minz: bool
220
+ :type nodisj: bool
221
+ :type process: int
210
222
  :type puresat: str
211
223
  :type unsorted: bool
212
224
  :type trim: int
@@ -214,8 +226,8 @@ class OptUx(object):
214
226
  """
215
227
 
216
228
  def __init__(self, formula, solver='g3', adapt=False, cover=None,
217
- dcalls=False, exhaust=False, minz=False, puresat=False,
218
- unsorted=False, trim=False, verbose=0):
229
+ dcalls=False, exhaust=False, minz=False, nodisj=False, process=0,
230
+ puresat=False, unsorted=False, trim=False, verbose=0):
219
231
  """
220
232
  Constructor.
221
233
  """
@@ -243,13 +255,25 @@ class OptUx(object):
243
255
  self._process_soft(formula)
244
256
  self.formula.nv = self.topv
245
257
 
258
+ # applying formula processing (if any)
259
+ if process:
260
+ # the processor is immediately destroyed,
261
+ # as we do not need to restore the models
262
+ with Processor(bootstrap_with=self.formula.hard) as processor:
263
+ proc = processor.process(rounds=process, freeze=self.sels)
264
+ self.formula.hard = proc.clauses
265
+ self.formula.nv = max(self.formula.nv, proc.nv)
266
+
246
267
  # creating an unweighted copy
247
268
  unweighted = self.formula.copy()
248
269
  unweighted.wght = [1 for w in unweighted.wght]
249
270
 
250
- # enumerating disjoint MCSes (including unit-size MCSes)
251
- to_hit, self.units = self._disjoint(unweighted, solver, adapt, exhaust,
252
- minz, trim)
271
+ if not nodisj:
272
+ # enumerating disjoint MCSes (including unit-size MCSes)
273
+ to_hit, self.units = self._disjoint(unweighted, solver, adapt, exhaust,
274
+ minz, trim)
275
+ else:
276
+ to_hit, self.units, self.disj_time = [], [], 0.
253
277
 
254
278
  if self.verbose > 2:
255
279
  print('c mcses: {0} unit, {1} disj'.format(len(self.units),
@@ -286,9 +310,13 @@ class OptUx(object):
286
310
  # SAT oracle bootstrapped with the hard clauses; note that
287
311
  # clauses of the unit-size MCSes are enforced to be enabled
288
312
  self.oracle = Solver(name=solver, bootstrap_with=unweighted.hard +
289
- [[mcs] for mcs in self.units])
313
+ [[mcs] for mcs in self.units], use_timer=True)
290
314
 
291
315
  if unweighted.atms:
316
+ if solver in SolverNames.cadical195:
317
+ # we are using CaDiCaL195 and it can use external linear engine
318
+ self.oracle.activate_atmost()
319
+
292
320
  assert self.oracle.supports_atmost(), \
293
321
  '{0} does not support native cardinality constraints. Make sure you use the right type of formula.'.format(self.solver)
294
322
 
@@ -434,7 +462,7 @@ class OptUx(object):
434
462
  break
435
463
 
436
464
  # extracting the MCS corresponding to the model
437
- falsified = list(filter(lambda l: model[abs(l) - 1] == -l, self.sels))
465
+ falsified = [l for l in self.sels if model[abs(l) - 1] == -l]
438
466
 
439
467
  # unit size or not?
440
468
  if len(falsified) > 1:
@@ -500,7 +528,7 @@ class OptUx(object):
500
528
  # the candidate subset is satisfiable,
501
529
  # thus extracting a correction subset
502
530
  model = self.oracle.get_model()
503
- cs = list(filter(lambda l: model[abs(l) - 1] == -l, self.sels))
531
+ cs = [l for l in self.sels if model[abs(l) - 1] == -l]
504
532
 
505
533
  # hitting the new correction subset
506
534
  self.hitman.hit(cs, weights=self.weights)
@@ -543,10 +571,11 @@ def parse_options():
543
571
  """
544
572
 
545
573
  try:
546
- opts, args = getopt.getopt(sys.argv[1:], 'ac:de:hmp:s:t:uvx',
547
- ['adapt', 'cover=', 'dcalls', 'enum=', 'exhaust', 'help',
548
- 'minimize', 'solver=', 'puresat=', 'unsorted', 'trim=',
549
- 'verbose'])
574
+ opts, args = getopt.getopt(sys.argv[1:], 'ac:de:hmnp:P:s:t:uvx',
575
+ ['adapt', 'cover=', 'dcalls', 'enum=',
576
+ 'exhaust', 'help', 'minimize', 'no-disj',
577
+ 'solver=', 'puresat=', 'process=',
578
+ 'unsorted', 'trim=', 'verbose'])
550
579
  except getopt.GetoptError as err:
551
580
  sys.stderr.write(str(err).capitalize() + '\n')
552
581
  usage()
@@ -557,8 +586,10 @@ def parse_options():
557
586
  dcalls = False
558
587
  exhaust = False
559
588
  minz = False
589
+ no_disj = False
560
590
  to_enum = 1
561
- solver = 'm22'
591
+ solver = 'g3'
592
+ process = 0
562
593
  puresat = False
563
594
  unsorted = False
564
595
  trim = 0
@@ -582,8 +613,12 @@ def parse_options():
582
613
  sys.exit(0)
583
614
  elif opt in ('-m', '--minimize'):
584
615
  minz = True
616
+ elif opt in ('-n', '--no-disj'):
617
+ no_disj = True
585
618
  elif opt in ('-p', '--puresat'):
586
619
  puresat = str(arg)
620
+ elif opt in ('-P', '--process'):
621
+ process = int(arg)
587
622
  elif opt in ('-s', '--solver'):
588
623
  solver = str(arg)
589
624
  elif opt in ('-u', '--unsorted'):
@@ -597,8 +632,8 @@ def parse_options():
597
632
  else:
598
633
  assert False, 'Unhandled option: {0} {1}'.format(opt, arg)
599
634
 
600
- return adapt, cover, dcalls, exhaust, minz, trim, to_enum, solver, \
601
- puresat, unsorted, verbose, args
635
+ return adapt, cover, dcalls, exhaust, minz, no_disj, trim, to_enum, \
636
+ solver, process, puresat, unsorted, verbose, args
602
637
 
603
638
 
604
639
  #
@@ -618,11 +653,14 @@ def usage():
618
653
  print(' Available values: [1 .. INT_MAX], all (default: 1)')
619
654
  print(' -h, --help Show this message')
620
655
  print(' -m, --minimize Use a heuristic unsatisfiable core minimizer')
656
+ print(' -n, --no-disj Do not enumerate disjoint MCSes')
621
657
  print(' -p, --puresat=<string> Use a pure SAT-based hitting set enumerator')
622
- print(' Available values: cd15, lgl, mgh (default = mgh)')
658
+ print(' Available values: cd15, cd19, lgl, mgh (default = mgh)')
623
659
  print(' Requires: unsorted mode, i.e. \'-u\'')
660
+ print(' -P, --process=<int> Number of processing rounds')
661
+ print(' Available values: [0 .. INT_MAX] (default = 0)')
624
662
  print(' -s, --solver SAT solver to use')
625
- print(' Available values: g3, g4, lgl, mcb, mcm, mpl, m22, mc, mgh (default = m22)')
663
+ print(' Available values: cd15, cd19, g3, g4, lgl, mcb, mcm, mpl, m22, mc, mgh (default = g3)')
626
664
  print(' -t, --trim=<int> How many times to trim unsatisfiable cores')
627
665
  print(' Available values: [0 .. INT_MAX] (default = 0)')
628
666
  print(' -u, --unsorted Enumerate MUSes in an unsorted way')
@@ -633,25 +671,26 @@ def usage():
633
671
  #
634
672
  #==============================================================================
635
673
  if __name__ == '__main__':
636
- adapt, cover, dcalls, exhaust, minz, trim, to_enum, solver, puresat, \
637
- unsorted, verbose, files = parse_options()
674
+ adapt, cover, dcalls, exhaust, minz, no_disj, trim, to_enum, solver, \
675
+ process, puresat, unsorted, verbose, files = parse_options()
638
676
 
639
677
  if files:
640
678
  # reading standard CNF, WCNF, or (W)CNF+
641
- if re.search(r'cnf[p|+]?(\.(gz|bz2|lzma|xz))?$', files[0]):
642
- if re.search(r'\.wcnf[p|+]?(\.(gz|bz2|lzma|xz))?$', files[0]):
643
- formula = WCNFPlus(from_file=files[0])
644
- else: # expecting '*.cnf[,p,+].*'
645
- formula = CNFPlus(from_file=files[0]).weighted()
679
+ assert re.search(r'cnf[p|+]?(\.(gz|bz2|lzma|xz|zst))?$', files[0]), 'Unknown input file extension'
680
+ if re.search(r'\.wcnf[p|+]?(\.(gz|bz2|lzma|xz|zst))?$', files[0]):
681
+ formula = WCNFPlus(from_file=files[0])
682
+ else: # expecting '*.cnf[,p,+].*'
683
+ formula = CNFPlus(from_file=files[0]).weighted()
646
684
 
647
685
  if cover: # expecting '*.cnf[,p,+].*' only!
648
- assert re.search(r'cnf[p|+]?(\.(gz|bz2|lzma|xz))?$', cover), 'wrong file for formula to cover'
686
+ assert re.search(r'cnf[p|+]?(\.(gz|bz2|lzma|xz|zst))?$', cover), 'Wrong file for formula to cover'
649
687
  cover = CNFPlus(from_file=cover)
650
688
 
651
689
  # creating an object of OptUx
652
690
  with OptUx(formula, solver=solver, adapt=adapt, cover=cover,
653
- dcalls=dcalls, exhaust=exhaust, minz=minz, puresat=puresat,
654
- unsorted=unsorted, trim=trim, verbose=verbose) as optux:
691
+ dcalls=dcalls, exhaust=exhaust, minz=minz, nodisj=no_disj,
692
+ process=process, puresat=puresat, unsorted=unsorted,
693
+ trim=trim, verbose=verbose) as optux:
655
694
 
656
695
  # iterating over the necessary number of optimal MUSes
657
696
  for i, mus in enumerate(optux.enumerate()):