python-sat 1.9.dev2__cp39-cp39-win_amd64.whl → 1.9.dev4__cp39-cp39-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.
Files changed (28) hide show
  1. pycard.cp39-win_amd64.pyd +0 -0
  2. pyformula.cp39-win_amd64.pyd +0 -0
  3. pysat/__init__.py +1 -1
  4. pysat/_fileio.py +15 -0
  5. pysat/examples/rc2.py +50 -23
  6. pysat/formula.py +84 -3
  7. pysat/integer.py +906 -245
  8. pysat/solvers.py +1898 -760
  9. pysolvers.cp39-win_amd64.pyd +0 -0
  10. {python_sat-1.9.dev2.data → python_sat-1.9.dev4.data}/scripts/rc2.py +50 -23
  11. {python_sat-1.9.dev2.dist-info → python_sat-1.9.dev4.dist-info}/METADATA +1 -1
  12. {python_sat-1.9.dev2.dist-info → python_sat-1.9.dev4.dist-info}/RECORD +28 -27
  13. {python_sat-1.9.dev2.dist-info → python_sat-1.9.dev4.dist-info}/WHEEL +1 -1
  14. {python_sat-1.9.dev2.dist-info → python_sat-1.9.dev4.dist-info}/top_level.txt +1 -0
  15. {python_sat-1.9.dev2.data → python_sat-1.9.dev4.data}/scripts/approxmc.py +0 -0
  16. {python_sat-1.9.dev2.data → python_sat-1.9.dev4.data}/scripts/bbscan.py +0 -0
  17. {python_sat-1.9.dev2.data → python_sat-1.9.dev4.data}/scripts/bica.py +0 -0
  18. {python_sat-1.9.dev2.data → python_sat-1.9.dev4.data}/scripts/fm.py +0 -0
  19. {python_sat-1.9.dev2.data → python_sat-1.9.dev4.data}/scripts/genhard.py +0 -0
  20. {python_sat-1.9.dev2.data → python_sat-1.9.dev4.data}/scripts/lbx.py +0 -0
  21. {python_sat-1.9.dev2.data → python_sat-1.9.dev4.data}/scripts/lsu.py +0 -0
  22. {python_sat-1.9.dev2.data → python_sat-1.9.dev4.data}/scripts/mcsls.py +0 -0
  23. {python_sat-1.9.dev2.data → python_sat-1.9.dev4.data}/scripts/models.py +0 -0
  24. {python_sat-1.9.dev2.data → python_sat-1.9.dev4.data}/scripts/musx.py +0 -0
  25. {python_sat-1.9.dev2.data → python_sat-1.9.dev4.data}/scripts/optux.py +0 -0
  26. {python_sat-1.9.dev2.data → python_sat-1.9.dev4.data}/scripts/primer.py +0 -0
  27. {python_sat-1.9.dev2.data → python_sat-1.9.dev4.data}/scripts/unigen.py +0 -0
  28. {python_sat-1.9.dev2.dist-info → python_sat-1.9.dev4.dist-info}/licenses/LICENSE.txt +0 -0
pycard.cp39-win_amd64.pyd CHANGED
Binary file
Binary file
pysat/__init__.py CHANGED
@@ -10,7 +10,7 @@
10
10
 
11
11
  # current version
12
12
  #==============================================================================
13
- VERSION = (1, 9, 'dev', 2)
13
+ VERSION = (1, 9, 'dev', 4)
14
14
 
15
15
 
16
16
  # PEP440 Format
pysat/_fileio.py CHANGED
@@ -74,6 +74,21 @@ except ImportError: # zstandard is introduced in Python 3.14
74
74
  zstd_present = False
75
75
 
76
76
 
77
+ #
78
+ #==============================================================================
79
+ def read_all_text(fp):
80
+ """
81
+ Read the entire contents of a file-like object and normalize the
82
+ result to text.
83
+ """
84
+
85
+ data = fp.read()
86
+
87
+ if isinstance(data, bytes):
88
+ return data.decode('utf-8')
89
+
90
+ return data
91
+
77
92
 
78
93
  #
79
94
  #==============================================================================
pysat/examples/rc2.py CHANGED
@@ -131,6 +131,7 @@
131
131
  #
132
132
  #==============================================================================
133
133
  from __future__ import print_function
134
+ import bisect
134
135
  import collections
135
136
  import getopt
136
137
  import itertools
@@ -810,8 +811,8 @@ class RC2(object):
810
811
  handled by calling :func:`process_am1`.
811
812
  """
812
813
 
813
- # literal connections
814
- conns = collections.defaultdict(lambda: set([]))
814
+ # literal connections and selectors conflicting on their own
815
+ conns = collections.defaultdict(list)
815
816
  confl = []
816
817
 
817
818
  # prepare connections
@@ -819,26 +820,29 @@ class RC2(object):
819
820
  st, props = self.oracle.propagate(assumptions=[l1], phase_saving=2)
820
821
  if st:
821
822
  for l2 in props:
822
- if -l2 in self.sels_set:
823
- conns[l1].add(-l2)
824
- conns[-l2].add(l1)
823
+ l2 = -l2
824
+ if l2 in self.sels_set:
825
+ conns[l1].append(l2)
826
+ conns[l2].append(l1)
825
827
  else:
826
828
  # propagating this literal results in a conflict
827
829
  confl.append(l1)
828
830
 
829
- if confl: # filtering out unnecessary connections
830
- ccopy = {}
831
- confl = set(confl)
831
+ # sort (in-place) and deduplicate adjacency lists
832
+ for l in list(conns):
833
+ neigh = conns[l]
834
+ if neigh:
835
+ neigh.sort()
832
836
 
833
- for l in conns:
834
- if l not in confl:
835
- cc = conns[l].difference(confl)
836
- if cc:
837
- ccopy[l] = cc
837
+ j = 1
838
+ for i in range(1, len(neigh)):
839
+ if neigh[i] != neigh[j - 1]:
840
+ neigh[j] = neigh[i]
841
+ j += 1
838
842
 
839
- conns = ccopy
840
- confl = list(confl)
843
+ del neigh[j:]
841
844
 
845
+ if confl:
842
846
  # processing unit size cores
843
847
  for l in confl:
844
848
  self.core, self.minw = [l], self.wght[l]
@@ -849,24 +853,47 @@ class RC2(object):
849
853
  print('c unit cores found: {0}; cost: {1}'.format(len(confl),
850
854
  self.cost))
851
855
 
856
+ # the following graph manipulation requires
857
+ # fast membership checks for confl; making it a set
858
+ confl = set(confl)
859
+
860
+ # current degrees in the remaining graph;
861
+ # literals disconnected after removing conflicts are ignored
862
+ degree, lits = {}, set()
863
+ for l in conns:
864
+ if l not in confl:
865
+ d = sum(1 for l2 in conns[l] if l2 not in confl)
866
+ if d:
867
+ degree[l] = d
868
+ lits.add(l)
869
+
870
+ # detect AM1s on the original formula with conflicting selectors
871
+ # filtered out, similarly to the previous implementation
852
872
  nof_am1 = 0
853
873
  len_am1 = []
854
- lits = set(conns.keys())
874
+
855
875
  while lits:
856
- am1 = [min(lits, key=lambda l: len(conns[l]))]
876
+ am1 = [min(lits, key=lambda l: degree[l])]
857
877
 
858
- for l in sorted(conns[am1[0]], key=lambda l: len(conns[l])):
878
+ for l in sorted(conns[am1[0]], key=lambda l: degree.get(l, 0)):
859
879
  if l in lits:
860
880
  for l_added in am1[1:]:
861
- if l_added not in conns[l]:
881
+ # adjacency lists are sorted, so we use
882
+ # binary search for clique membership tests
883
+ i = bisect.bisect_left(conns[l], l_added)
884
+ if i == len(conns[l]) or conns[l][i] != l_added:
862
885
  break
863
886
  else:
864
887
  am1.append(l)
865
888
 
866
- # updating remaining lits and connections
867
- lits.difference_update(set(am1))
868
- for l in conns:
869
- conns[l] = conns[l].difference(set(am1))
889
+ # updating remaining literals and their degrees
890
+ am1_set = set(am1)
891
+ lits.difference_update(am1_set)
892
+
893
+ for l in am1:
894
+ for l2 in conns.get(l, []):
895
+ if l2 in lits:
896
+ degree[l2] -= 1
870
897
 
871
898
  if len(am1) > 1:
872
899
  # treat the new atmost1 relation
pysat/formula.py CHANGED
@@ -271,7 +271,7 @@ import decimal
271
271
  from enum import Enum
272
272
  import itertools
273
273
  import os
274
- from pysat._fileio import FileObject
274
+ from pysat._fileio import FileObject, read_all_text
275
275
  import sys
276
276
 
277
277
  # checking whether or not py-aiger-cnf is available and working as expected
@@ -281,6 +281,13 @@ try:
281
281
  except ImportError:
282
282
  aiger_present = False
283
283
 
284
+ # checking whether or not native formula parser is available
285
+ pyformula_present = True
286
+ try:
287
+ import pyformula
288
+ except ImportError:
289
+ pyformula_present = False
290
+
284
291
  try: # for Python2
285
292
  from cStringIO import StringIO
286
293
  except ImportError: # for Python3
@@ -3286,6 +3293,11 @@ class CNF(Formula, object):
3286
3293
  ... cnf2 = CNF(from_fp=fp)
3287
3294
  """
3288
3295
 
3296
+ if pyformula_present:
3297
+ self.nv, self.clauses, self.comments = pyformula.parse_cnf(
3298
+ read_all_text(file_pointer), comment_lead)
3299
+ return
3300
+
3289
3301
  self.nv = 0
3290
3302
  self.clauses = []
3291
3303
  self.comments = []
@@ -3331,7 +3343,10 @@ class CNF(Formula, object):
3331
3343
  3
3332
3344
  """
3333
3345
 
3334
- self.from_fp(StringIO(string), comment_lead)
3346
+ if pyformula_present:
3347
+ self.nv, self.clauses, self.comments = pyformula.parse_cnf(string, comment_lead)
3348
+ else:
3349
+ self.from_fp(StringIO(string), comment_lead)
3335
3350
 
3336
3351
  def from_clauses(self, clauses, by_ref=False):
3337
3352
  """
@@ -4044,6 +4059,18 @@ class WCNF(object):
4044
4059
  ... cnf2 = WCNF(from_fp=fp)
4045
4060
  """
4046
4061
 
4062
+ if pyformula_present:
4063
+ self.nv, self.hard, self.soft, self.wght, self.topw, self.comments, negs = \
4064
+ pyformula.parse_wcnf(read_all_text(file_pointer), comment_lead)
4065
+
4066
+ if negs:
4067
+ self.normalize_negatives(negs)
4068
+
4069
+ if type(self.topw) == decimal.Decimal and self.topw.is_infinite():
4070
+ self.topw = 1 + sum(self.wght)
4071
+
4072
+ return
4073
+
4047
4074
  def parse_wght(string):
4048
4075
  if string == 'h':
4049
4076
  return None
@@ -4171,7 +4198,17 @@ class WCNF(object):
4171
4198
  3
4172
4199
  """
4173
4200
 
4174
- self.from_fp(StringIO(string), comment_lead)
4201
+ if pyformula_present:
4202
+ self.nv, self.hard, self.soft, self.wght, self.topw, self.comments, negs = \
4203
+ pyformula.parse_wcnf(string, comment_lead)
4204
+
4205
+ if negs:
4206
+ self.normalize_negatives(negs)
4207
+
4208
+ if type(self.topw) == decimal.Decimal and self.topw.is_infinite():
4209
+ self.topw = 1 + sum(self.wght)
4210
+ else:
4211
+ self.from_fp(StringIO(string), comment_lead)
4175
4212
 
4176
4213
  def copy(self):
4177
4214
  """
@@ -4668,6 +4705,16 @@ class CNFPlus(CNF, object):
4668
4705
  s = self.to_dimacs().replace('\n', '\\n')
4669
4706
  return f'CNFPlus(from_string=\'{s}\')'
4670
4707
 
4708
+ def from_string(self, string, comment_lead=['c']):
4709
+ """
4710
+ Read a CNF+ formula from a string.
4711
+ """
4712
+
4713
+ if pyformula_present:
4714
+ self.nv, self.clauses, self.atmosts, self.comments = pyformula.parse_cnfplus(string, comment_lead)
4715
+ else:
4716
+ self.from_fp(StringIO(string), comment_lead)
4717
+
4671
4718
  def from_fp(self, file_pointer, comment_lead=['c']):
4672
4719
  """
4673
4720
  Read a CNF+ formula from a file pointer. A file pointer should be
@@ -4693,6 +4740,11 @@ class CNFPlus(CNF, object):
4693
4740
  ... cnf2 = CNFPlus(from_fp=fp)
4694
4741
  """
4695
4742
 
4743
+ if pyformula_present:
4744
+ self.nv, self.clauses, self.atmosts, self.comments = pyformula.parse_cnfplus(
4745
+ read_all_text(file_pointer), comment_lead)
4746
+ return
4747
+
4696
4748
  self.nv = 0
4697
4749
  self.clauses = []
4698
4750
  self.atmosts = []
@@ -5196,6 +5248,23 @@ class WCNFPlus(WCNF, object):
5196
5248
  s = self.to_dimacs().replace('\n', '\\n')
5197
5249
  return f'WCNFPlus(from_string=\'{s}\')'
5198
5250
 
5251
+ def from_string(self, string, comment_lead=['c']):
5252
+ """
5253
+ Read a WCNF+ formula from a string.
5254
+ """
5255
+
5256
+ if pyformula_present:
5257
+ self.nv, self.hard, self.soft, self.wght, self.atms, self.topw, self.comments, negs = \
5258
+ pyformula.parse_wcnfplus(string, comment_lead)
5259
+
5260
+ if negs:
5261
+ self.normalize_negatives(negs)
5262
+
5263
+ if type(self.topw) == decimal.Decimal and self.topw.is_infinite():
5264
+ self.topw = 1 + sum(self.wght)
5265
+ else:
5266
+ self.from_fp(StringIO(string), comment_lead)
5267
+
5199
5268
  def from_fp(self, file_pointer, comment_lead=['c']):
5200
5269
  """
5201
5270
  Read a WCNF+ formula from a file pointer. A file pointer should be
@@ -5221,6 +5290,18 @@ class WCNFPlus(WCNF, object):
5221
5290
  ... cnf2 = WCNFPlus(from_fp=fp)
5222
5291
  """
5223
5292
 
5293
+ if pyformula_present:
5294
+ self.nv, self.hard, self.soft, self.wght, self.atms, self.topw, self.comments, negs = \
5295
+ pyformula.parse_wcnfplus(read_all_text(file_pointer), comment_lead)
5296
+
5297
+ if negs:
5298
+ self.normalize_negatives(negs)
5299
+
5300
+ if type(self.topw) == decimal.Decimal and self.topw.is_infinite():
5301
+ self.topw = 1 + sum(self.wght)
5302
+
5303
+ return
5304
+
5224
5305
  def parse_wght(string):
5225
5306
  if string == 'h':
5226
5307
  return None