#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Copyright (C) 2013, Wolfgang Scherer, <Wolfgang.Scherer at gmx.de>
#
# This file is part of DOGgy Style Programming.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>,
# or write to Wolfgang Scherer, <Wolfgang.Scherer at gmx.de>
"""\
satoku.py - SAT problem utilities
====== ====================
usage: satoku.py [OPTIONS] [filename]
or import satoku
====== ====================
Options
=======
===================== ==================================================
-s, --sort sort clause vectors (default for --matrix)
--no-sort do not sort clause vectors (default for --beautify)
--minimize minimize clauses (remove redundancies, resolve clauses)
--flatten expand each clause, converting a AND/OR/AND problem
to a flat AND/OR problem.
--expand create full problem expansion (implies --sort)
--split split clause vectors into single-literal clauses
(implied by --matrix)
-c, --conflicts maximize conflicts (implies --split, default for --matrix)
--no-conflicts do not maximize conflicts (default for --beautify)
--fast-conflicts maximize conflicts, fast conjunction cover
(implies --conflicts)
--full-conflicts maximize conflicts, full conjunction cover
(implies --conflicts)
--keep-min-problem keep minimal problem when maximizing conflicts
(auto-detected by --fast-conflicts,
--full_conflicts)
-x, --xor create XOR problem
--no-xor do not create XOR problem (default for --beautify)
-h, --header append HEADER (default)
--no-header do not append HEADER
-f, --footer append FOOTER (default)
--no-footer do not append FOOTER
-b, --beautify beautify clause vectors
-a, --annotate annotate clause vectors (AND/OR)
-m, --matrix create matrix (default)
--from-matrix parse matrix (implies `--matrix`)
--quick-convert dump Satoku Matrix after parsing and applying
conversions (implies `--matrix`,
`--no-update`)
-v, --variables map variables (default).
With `--from-matrix`, it means that last
region consists of mapped variables.
--no-variables do not map variables
--strip-variables dump Satoku Matrix without variables
-u, --update update state rows (default)
--no-update do not update state rows (disables several
removal/solver options)
--immediate-zeroes immediately follow zero updates (default)
--delay-zeroes delay zero updates
--drop-1-states delete 1-state cell-matrix rows after
requirement update (default for `--update`)
--keep-1-states do not delete 1-state cell-matrix rows after
requirement update (default without
`--update`)
--keep-2-states keep non-variable 2-state cell-matrix rows
after requirement update (default)
--drop-2-states remove non-variable 2-state cell-matrix rows
after requirement update (usually used with
`--update`, `--variables`)
--drop-killed delete killed state rows (default)
--keep-killed do not delete killed state rows
-r, --redundant remove redundant cell-matrix rows (default)
--no-redundant do not remove redundant cell-matrix rows
--no-bin-conflicts do not combine binary conflict cell states (default)
--bin-conflicts combine binary conflict cell states (default)
--no-reduce-cells do not reduce cells (default)
--reduce-cells reduce cells (implies `--bin-conflicts`)
--strictly-less reduction must be strictly less space
--allow-equal reduction may use equal amount of space
--drop-uncombined drop uncombined cell states (default)
--keep-uncombined keep uncombined cell states
--no-minor-ccrs do not check minor conflict cell rows (default).
--check-minor-ccrs check minor conflict cell rows.
Max. 2 possible states + min. 1 impossible state.
Possibly re-triggers `--reduce-cells`.
-q, --quiet suppress warnings
-v, --verbose verbose test output
-d, --debug[=NUM] show debug information
-h, --help display this help message
--template list show available templates.
--eide[=COMM] Emacs IDE template list (implies --template list).
--template[=NAME] extract named template to standard
output. Default NAME is ``-``.
--extract[=DIR] extract adhoc files to directory DIR (default: ``.``)
--explode[=DIR] explode script with adhoc in directory DIR
(default ``__adhoc__``)
--implode implode script with adhoc
-t, --test run doc tests
===================== ==================================================
**Obsolete Options**:
===================== ==================================================
--drop-snf-conflicts remove 2-states (deprecated, use `--drop-2-states`)
===================== ==================================================
Module
======
See :class:`SatokuMatrix` for examples.
Exports
-------
>>> for ex in __all__:
... printf(sformat('from {0} import {1}', __name__, ex))
from satoku import SatokuError
from satoku import SatokuUnsatisfied
from satoku import SatokuSatisfied
from satoku import SatokuDone
from satoku import ClauseVector
from satoku import Clause
from satoku import OrClause
from satoku import AndClause
from satoku import Problem
from satoku import SelRow
from satoku import SMRegion
from satoku import SMRegionIterator
from satoku import SMClause
from satoku import SMStats
from satoku import SatokuMatrix
from satoku import LoopMark
from satoku import parse_clauses_
from satoku import clean_clauses
from satoku import parse_clauses
from satoku import permute_cols
from satoku import dump_regions
.. _END_OF_HELP_satoku:
"""
# --------------------------------------------------
# |||:sec:||| COMPATIBILITY
# --------------------------------------------------
import sys
# (progn (forward-line 1) (snip-insert "py.b.printf" t t "py") (insert "\n"))
# adapted from http://www.daniweb.com/software-development/python/code/217214
try:
printf = eval("print") # python 3.0 case
except SyntaxError:
printf_dict = dict()
try:
exec("from __future__ import print_function\nprintf=print", printf_dict)
printf = printf_dict["printf"] # 2.6 case
except SyntaxError:
def printf(*args, **kwd): # 2.4, 2.5, define our own Print function
fout = kwd.get("file", sys.stdout)
w = fout.write
if args:
w(str(args[0]))
sep = kwd.get("sep", " ")
for a in args[1:]:
w(sep)
w(str(a))
w(kwd.get("end", "\n"))
del printf_dict
# (progn (forward-line 1) (snip-insert "py.b.sformat" t t "py") (insert "\n"))
try:
('{0}').format(0)
def sformat (fmtspec, *args, **kwargs):
return fmtspec.format(*args, **kwargs)
except AttributeError:
try:
import stringformat
def sformat (fmtspec, *args, **kwargs):
return stringformat.FormattableString(fmtspec).format(
*args, **kwargs)
except ImportError:
printf('error: stringformat missing. Try `easy_install stringformat`.', file=sys.stderr)
# (progn (forward-line 1) (snip-insert "py.b.isstring" t t "python") (insert "\n"))
try:
from ws_seq_type import isstring, issequence, sequence_type, UCHAR_FMT
except ImportError:
# (progn (forward-line 1) (snip-insert "py.f.isstring" t t "py") (insert "\n"))
exec('''
def isstring(obj):
return isinstance(obj, basestring)
'''.strip())
try:
isstring("")
UCHAR_FMT = 'u"{0}u{1:04x}"'
except NameError:
def isstring(obj):
return isinstance(obj, str) or isinstance(obj, bytes)
UCHAR_FMT = '"{0}u{1:04x}"'
# (progn (forward-line 1) (snip-insert "py.f.issequence" t t "py") (insert "\n"))
def issequence(arg, or_dict=False, or_seq=True): # ||:fnc:||
if not isstring(arg):
if hasattr(arg, 'items'):
return or_dict
if hasattr(arg, '__getitem__'):
return True
if hasattr(arg, '__iter__'):
return or_seq
return False
# (progn (forward-line 1) (snip-insert-mode "py.f.sequence_type" t) (insert "\n"))
_st_strg = (True, False, False, False)
_st_list = (False, True, False, False)
_st_dict = (False, False, True, False)
_st_seq = (False, False, False, True)
_st_none = (False, False, False, False)
def sequence_type(value): # ||:fnc:||
if isstring(value):
return _st_strg
if hasattr(value, 'items'):
return _st_dict
if hasattr(value, '__getitem__'):
return _st_list
if hasattr(value, '__iter__'):
return _st_seq
return _st_none
# (progn (forward-line 1) (snip-insert-mode "py.f.uchar" t) (insert "\n"))
def uchar(num):
'''Make UNICODE character.'''
return eval(sformat(UCHAR_FMT,'\\', num))
# (progn (forward-line 1) (snip-insert "py.b.dict.items" t t "py") (insert "\n"))
try:
getattr(dict(), 'iteritems')
except AttributeError:
ditems = lambda d: getattr(d, 'items')()
dkeys = lambda d: getattr(d, 'keys')()
dvalues = lambda d: getattr(d, 'values')()
else:
ditems = lambda d: getattr(d, 'iteritems')()
dkeys = lambda d: getattr(d, 'iterkeys')()
dvalues = lambda d: getattr(d, 'itervalues')()
# (progn (forward-line 1) (snip-insert "py.b.xrange" t t "py") (insert "\n"))
try:
xrange(0)
except NameError:
xrange = range
import os
import re
# --------------------------------------------------
# |||:sec:||| CONFIGURATION
# --------------------------------------------------
__all__ = []
# (progn (forward-line 1) (snip-insert "py_b.dbg_def" t t "python") (insert ""))
dbg_comm = ((('dbg_comm' in globals()) and (globals()['dbg_comm'])) or ('// '))
dbg_twid = ((('dbg_twid' in globals()) and (globals()['dbg_twid'])) or (9))
dbg_fwid = ((('dbg_fwid' in globals()) and (globals()['dbg_fwid'])) or (25))
# (progn (forward-line 1) (snip-insert "py_main-pyramid-activate" t t "py") (insert ""))
# (progn (forward-line 1) (snip-insert "py_b.canonize_module" t t "python") (insert ""))
def _canonize_module_(module_or_name, full=None):
"""Set module's ``_is_main_`` flag/register module under canonical
name.
:param full: if not True, only set ``_is_main_`` flag.
Otherwise, register module under canonical name.
This is useful, for e.g. consistent _pyjsmo_class resolution.
.. note:: After full canonization, the idiom ``if __name__ ==
'__main__: ...'`` no longer works. Use ``if _is_main_: ...``
instead.
"""
if isstring(module_or_name):
module = sys.modules[module_or_name]
else:
module = module_or_name
# flag for __main__
_is_main_ = (module.__name__ == '__main__')
if not hasattr(module, '_is_main_'):
module._is_main_ = _is_main_
if not full:
return _is_main_
# module file name -> canonical name
try:
mfile = module.__file__
except AttributeError:
return
canon_name_ = mfile
canon_name_ = os.path.basename(canon_name_)
canon_name_, _ext = os.path.splitext(canon_name_)
# adhoc compiliation xx_.py -> xx.py
if canon_name_.endswith('_') and not canon_name_.endswith('__'):
canon_name_ = canon_name_[:-1]
# find parent module |:check:| distutils/pkg_resources?
mdir = os.path.abspath(os.path.dirname(mfile))
mparts = []
while mdir and os.path.exists(os.path.join(mdir, '__init__.py')):
mdir, pfx = os.path.split(mdir)
mparts.insert(0, pfx)
parent = '.'.join(mparts)
mparts.append(canon_name_)
canon_name = '.'.join(mparts)
if module.__name__ != canon_name:
if parent:
# fix parent module
exec('import ' + parent)
if parent in (sys.modules):
setattr(sys.modules[parent], canon_name_, module)
sys.modules[canon_name] = module
module.__name__ = canon_name
return _is_main_
_canonize_module_(__name__, __name__ == '__main__')
# (progn (forward-line 1) (snip-insert "py.b.strings" t t "py") (insert "\n"))
# (progn (forward-line 1) (snip-insert "py.f.strclean" t t "py") (insert "\n"))
# (progn (forward-line 1) (snip-insert "py.f.issequence" t t "py") (insert "\n"))
# (progn (forward-line 1) (snip-insert "py_b.logging" t t "python") (insert ""))
# (progn (forward-line 1) (snip-insert "py.b.ordereddict" t t "py") (insert "\n"))
# (progn (forward-line 1) (snip-insert "py.b.dbg.setup" t t "py") (insert "\n"))
# (progn (forward-line 1) (snip-insert "py.main.project.libdir" t t "py") (insert "\n"))
# (progn (forward-line 1) (snip-insert "py.main.sql.alchemy" t t "py") (insert "\n"))
# (progn (forward-line 1) (snip-insert "py.main.sql.ws" t t "py") (insert "\n"))
# @:adhoc_run_time:@
#import adhoc # @:adhoc:@
# (progn (forward-line 1) (snip-insert "py.b.posix" t t "py") (insert "\n"))
# (progn (forward-line 1) (snip-insert "py.b.os.system.sh" t t "py") (insert "\n"))
# (progn (forward-line 1) (snip-insert "py.b.prog.path" t t "py") (insert "\n"))
# (progn (forward-line 1) (snip-insert "py.b.line.loop" t t "py") (insert "\n"))
# (progn (forward-line 1) (snip-insert "py_wsrfid.pylons_imports" t t "python") (insert ""))
# (progn (forward-line 1) (snip-insert "py_main.wsgi_get_app" t t "python") (insert ""))
try:
from cStringIO import StringIO as BytesIO, StringIO
except ImportError:
try:
from StringIO import StringIO as BytesIO, StringIO
except ImportError:
from io import BytesIO, StringIO
import weakref
import copy
import pyjsmo
import pyjsmo.formatv
import pyjsmo.table
from pyjsmo import PyJsMo, OrderedDict
try:
from PIL import Image, ImageDraw, ImageColor
have_pil = True
except ImportError:
have_pil = False
# --------------------------------------------------
# |||:sec:||| VARIABLES
# --------------------------------------------------
IMG_WIDTH = 1024
IMG_HEIGHT = 1024
PIX_WIDTH_MAX = 10
if have_pil:
PIX_COLORS = (
ImageColor.getrgb('#ff8888'),
ImageColor.getrgb('#6666ff'),
ImageColor.getrgb('#ffffff'),
)
BACKGROUND_COLOR = ImageColor.getrgb('#ffffff')
FRAME_COLOR_INNER = ImageColor.getrgb('#cccccc')
FRAME_COLOR_OUTER = ImageColor.getrgb('#000000')
TRUTH_VALUES = ['0', '1', '_']
TRUTH_VALUES_NEG = [ 1, 0, -1 ]
TRUTH_VALUES_ID = ['*', '1', '_']
CLAUSE_TYPES = ('AND', 'OR')
TEST_PROBLEM = '''
// Problem:
// ((a ∧ d) ∨ (¬a ∧ b) ∨ (¬a ∧ ¬b ∧ c)) ∧
// ( a ∨ ¬b ∨ c) ∧
// (¬a ∨ b ∨ ¬c) ∧
// ( b ∨ ¬c ∨ d) ∧
// (¬c ∨ d ∨ e) ∧
// (¬b ∨ (b ∧ d) ∨ (b ∧ ¬d ∧ ¬e))
[[ 1 - - 0 - ]
[ 0 1 - - - ]
[ 0 0 1 - - ]]
[ 1 0 1 - - ]
[ 0 1 0 - - ]
// comment
// comment
- 1 0 1
- - 0 1 1
[ - 0 - - -
- 1 - 1 -
- 1 - 0 0 ]
// comment
'''
TEST_PROBLEM_REGIONS = ''.join((
TEST_PROBLEM,
"""
//r: 3 2 1 5 9 10
""")).strip()
TEST_PROBLEM_NOCFL = TEST_PROBLEM.replace('0', '1')
SM_INFO = "// |:info:| move point inside and press `C-u M-x satoku-mode RET'"
HEADER = """
// |:sec:|
""".strip()
FOOTER = """
// (let (e) (forward-line 1) (setq e (point)) (forward-line -1) (delete-region (point) (- e 1)) (delete-blank-lines) (delete-region (point) (point-max)) (snip-insert "fca_footer" t t "fca") (insert ""))
// --------------------------------------------------
// |:sec:| EOF
// --------------------------------------------------
// :ide""" """-menu: Emacs IDE Main Menu - Buffer @BUFFER@
// . M-x `eIDE-menu' ()(eIDE-menu "z")
//
// Local""" """ Variables:
// mode: text
// snip-mode: fca
// comment-start: "// "
// comment-start-skip: "// *"
// truncate-lines: t
// End:
""".strip()
# --------------------------------------------------
# |||:sec:||| EXCEPTIONS
# --------------------------------------------------
__all__.append('SatokuError')
[docs]class SatokuError(Exception): # ||:cls:||
"""
"""
__all__.append('SatokuUnsatisfied')
[docs]class SatokuUnsatisfied(SatokuError): # ||:cls:||
"""
"""
__all__.append('SatokuSatisfied')
[docs]class SatokuSatisfied(SatokuError): # ||:cls:||
"""
"""
__all__.append('SatokuDone')
[docs]class SatokuDone(SatokuError): # ||:cls:||
"""
"""
# --------------------------------------------------
# |||:sec:||| CLASSES
# --------------------------------------------------
__all__.append('ClauseVector')
[docs]class ClauseVector(list): # ||:cls:||
"""
>>> cv = ClauseVector(' [ 0 - - 1 - 0 ] // comment')
>>> printf(''.join((str(cv), cv.comment)))
0 _ _ 1 _ 0 // comment
>>> printf(cv.split())
[ 0 _ _ _ _ _ ]
[ _ _ _ 1 _ _ ]
[ _ _ _ _ _ 0 ]
.. \\|:here:|
"""
_verbose = False
_verbose = True # |:debug:|
def __str__(self): # |:mth:|
"""
:returns: string representation
"""
return ' '.join(map(lambda e: TRUTH_VALUES[e], self))
def __setitem__(self, indx, value): # |:mth:|
"""
"""
if indx >= len(self):
super(ClauseVector, self).extend([-1 for i in xrange((indx + 1) - len(self))])
if value >= 0:
if self[indx] < 0:
used_cols = self.used_cols
#sort = used_cols and used_cols[-1] > indx
used_cols.append(indx)
#if sort: # |:check:| keep cv.used_cols sorted?
# used_cols[:] = sorted(used_cols)
up_check = False
else:
up_check = (self[indx] >= 0)
super(ClauseVector, self).__setitem__(indx, value)
if up_check:
self.update_cols()
def __init__(self, *args, **kwargs): # |:mth:|
self.indx = 0
self.comment = ''
self.used_cols = []
line = None
if args:
arg0 = args[0]
if isstring(arg0):
line = arg0
args = ()
elif isinstance(arg0, self.__class__):
self.indx = arg0.indx
self.comment = arg0.comment
super(ClauseVector, self).__init__(*args, **kwargs)
if line:
self.parse_string(line)
else:
self.update_cols()
# --------------------------------------------------
# ||:sec:|| Internal Functions
# --------------------------------------------------
[docs] def update_cols(self): # |:mth:|
"""
:returns: self for chaining.
"""
used_cols = []
self.used_cols = used_cols
for indx, literal in enumerate(self):
if literal >= 0:
used_cols.append(indx)
return self
# --------------------------------------------------
# ||:sec:|| Parameters
# --------------------------------------------------
[docs] def key(self): # |:mth:|
"""
:returns: sort key
"""
return sformat('{0:05d}|{1}', 99999 - len(self.used_cols), str(self))
[docs] def max_used(self): # |:mth:|
"""
:returns: len(self.used_cols)
"""
return len(self.used_cols)
[docs] def max_width(self): # |:mth:|
"""
:returns: len(self)
"""
return len(self)
[docs] def max_depth(self): # |:mth:|
"""
:returns: 0
"""
return 0
[docs] def has_one(self): # |:mth:|
"""
:returns: True, if vector contains an unnegated
variable. False otherwise.
..
"""
for col in self.used_cols:
if self[col] == 1:
return True
return False
[docs] def has_zero(self): # |:mth:|
"""
:returns: True, if vector has a negated variable. False
otherwise.
..
"""
for col in self.used_cols:
if self[col] == 0:
return True
return False
# --------------------------------------------------
# ||:sec:|| Operators
# --------------------------------------------------
[docs] def can_fold(self): # |:mth:|
"""
:returns: True, if clause vector can fold. I.e., its used column count is 1.
"""
return len(self.used_cols) == 1
[docs] def conflicts_with(self, other): # |:mth:|
"""
:returns: True, if self conflicts with other.
"""
slen = len(self)
olen = len(other)
for indx in self.used_cols:
if indx >= olen:
continue
break # |:check:| keep cv.used_cols sorted?
val = other[indx]
if val >= 0 and val != self[indx]:
return True
return False
[docs] def equals(self, other): # |:mth:|
"""
:returns: True, if self is equal to other.
>>> cv = ClauseVector('[ - 0 1 ]')
>>> ccv = ClauseVector('[ 1 0 1 ]')
>>> cv.equals(ccv)
False
>>> ccv = ClauseVector('[ 1 ]')
>>> cv.equals(ccv)
False
>>> cv = ccv
>>> ccv = ClauseVector('[ 1 0 1 ]')
>>> cv.equals(ccv)
False
>>> cv = ccv
>>> cv.equals(ccv)
True
"""
if not isinstance(other, ClauseVector):
return False
if len(self.used_cols) != len(other.used_cols):
return False
olen = len(other)
for col in self.used_cols:
if col >= olen:
return False
if self[col] != other[col]:
return False
return True
[docs] def contains(self, other): # |:mth:|
"""
:returns: True, if self contains other.
>>> cv = ClauseVector('[ - 0 1 ]')
>>> ccv = ClauseVector('[ 1 0 1 ]')
>>> cv.contains(ccv)
True
>>> ccv = ClauseVector('[ 1 ]')
>>> cv.contains(ccv)
False
>>> cv = ccv
>>> ccv = ClauseVector('[ 1 0 1 ]')
>>> cv.contains(ccv)
True
"""
if not isinstance(other, ClauseVector):
return False
if len(self.used_cols) > len(other.used_cols):
return False
olen = len(other)
for col in self.used_cols:
if col >= olen:
return False
if self[col] != other[col]:
return False
return True
[docs] def sdiff(self, other): # |:mth:|
"""Single difference column.
:returns: (single difference column, shorter, longer) or (-1, shorter, longer).
>>> cv = ClauseVector('[ - 0 0 ]')
>>> ccv = ClauseVector('[ 1 ]')
>>> cv.sdiff(ccv)
(-1, [1], [-1, 0, 0])
>>> ccv = ClauseVector( '[ 1 0 1 ]')
>>> cv.sdiff(ccv)
(2, [-1, 0, 0], [1, 0, 1])
>>> ccv.sdiff(cv)
(2, [-1, 0, 0], [1, 0, 1])
>>> cv = ClauseVector( '[ 1 1 1 ]')
>>> cv.sdiff(ccv)
(1, [1, 1, 1], [1, 0, 1])
>>> cv = ClauseVector( '[ 1 1 1 ]')
>>> ccv = ClauseVector('[ 0 0 1 ]')
>>> cv.sdiff(ccv)
(-1, [1, 1, 1], [0, 0, 1])
>>> cv = ClauseVector( '[ 1 1 1 - ]')
>>> ccv = ClauseVector('[ - 0 1 0 ]')
>>> cv.sdiff(ccv)
(-1, [1, 1, 1, -1], [-1, 0, 1, 0])
>>> cv = ClauseVector( '[ 1 0 - 1 ]')
>>> ccv = ClauseVector('[ - 1 0 - ]')
>>> cv.sdiff(ccv)
(-1, [-1, 1, 0, -1], [1, 0, -1, 1])
"""
# - 0 0
# 1 0 1
# ^
# - 0 0
# 1 0 1
# ^
sulen = len(self.used_cols)
oulen = len(other.used_cols)
if sulen > oulen:
longer = self
shorter = other
else:
shorter = self
longer = other
llen = len(longer)
sdiff_col = -1
for col in shorter.used_cols:
sval = shorter[col]
if col >= llen:
lval = -1
else:
lval = longer[col]
if lval != sval:
if sdiff_col >= 0 or lval < 0 or sval < 0:
sdiff_col = -1
break
sdiff_col = col
return (sdiff_col, shorter, longer)
# --------------------------------------------------
# ||:sec:|| Functions
# --------------------------------------------------
[docs] def copy(self): # |:mth:|
"""
:returns: copy
"""
return copy.deepcopy(self)
[docs] def set_width(self, width=-1): # |:mth:|
"""Set width.
:returns: self for chaining.
"""
if len(self) < width:
self.extend([-1 for i in xrange(width - len(self))])
return self
[docs] def index(self): # |:mth:|
"""Index members.
:returns: self for chaining.
"""
return self
[docs] def annotate(self, clause_types=None): # |:mth:|
"""Index members.
:returns: self for chaining.
"""
if clause_types is None:
clause_types = CLAUSE_TYPES
self.comment = ''.join((' // ', clause_types[0]))
return self
[docs] def sort(self): # |:mth:|
"""
:returns: self for chaining.
"""
return self
[docs] def sort_by_index(self): # |:mth:|
"""
:returns: self for chaining.
"""
return self
[docs] def negate(self): # |:mth:|
"""
:returns: self for chaining
"""
for col in self.used_cols:
self[col] = TRUTH_VALUES_NEG[self[col]]
return self
[docs] def fold(self): # |:mth:|
"""
:returns: ClauseVector.
"""
return self
[docs] def split(self): # |:mth:|
"""
:returns: Clause.
"""
clause = Clause()
clause.indx = self.indx
width = len(self)
tcv = ClauseVector()
tcv.set_width(width)
for indx, col in enumerate(self.used_cols):
lcv = ClauseVector(tcv)
lcv.indx = indx
lcv[col] = self[col]
clause.append(lcv)
return clause
[docs] def remove_redundant(self): # |:mth:|
"""
:returns: self for chaining.
"""
return self
[docs] def max_conflicts(self): # |:mth:|
"""Maximize conflicts.
:returns: maximized clause.
::
(l0 | l1 | l2 ) = ( l0 | (!l0 & l1) | (!l0 & !l1 & l2))
[ 1 1 1 ] = [[ 1 _ _ ] [[ 1 _ _ ]
[ _ 1 _ ] = [ 0 1 _ ]
[ _ _ 1 ]] [ 0 0 1 ]]
"""
clause = Clause()
clause.indx = self.indx
self.indx = 0
clause.append(self)
return clause.max_conflicts()
[docs] def max_max_conflicts(self, full=None): # |:mth:|
"""Maximize conflicts including AND.
:returns: maximized clause.
"""
clause = Clause()
clause.indx = self.indx
self.indx = 0
clause.append(self)
return clause.max_max_conflicts(full=full)
[docs] def xor_conflicts(self): # |:mth:|
"""XOR conflicts.
:returns: clause with XOR conflicts.
::
(l0 | l1 | l2 ) = ( l0 | (!l0 & l1) | (!l0 & !l1 & l2))
[ 1 1 1 ] = [[ 1 _ _ ] [[ 1 _ _ ]
[ _ 1 _ ] = [ 0 1 _ ]
[ _ _ 1 ]] [ 0 0 1 ]]
"""
clause = Clause()
clause.indx = self.indx
self.indx = 0
clause.append(self)
return clause.xor_conflicts()
# --------------------------------------------------
# ||:sec:|| Parsing
# --------------------------------------------------
[docs] def parse_string(self, string): # |:mth:|
"""
:returns: self for chaining.
"""
parts = re.split('\\s*//\\s*', string)
parts.append(None)
if parts[1]:
self.comment = ''.join((' // ', parts[1]))
else:
self.comment = ''
string = parts[0].replace('[', '').replace(']', '').strip()
self.extend(map(lambda e: (not(e == '0' or e == '1') and -1) or int(e), re.split('\\s', string)))
self.update_cols()
return self
# (progn (forward-line -1) (insert "\n") (snip-insert "py.s.meth" t t "py") (backward-symbol-tag 1 "fillme" "::"))
# (progn (forward-line -2) (insert "\n") (snip-insert "py.s.property" t t "py") (backward-symbol-tag 1 "fillme" "::"))
__all__.append('Clause')
[docs]class Clause(list): # ||:cls:||
"""Clause of clause vectors.
:param progress: progress output (keyword only!)
>>> cl = Clause('1 - 0 - 0').fold().split()
>>> printf(cl)
[ 1 _ _ _ _ ]
[ _ _ 0 _ _ ]
[ _ _ _ _ 0 ]
.. \\|:here:|
"""
def __str__(self): # |:mth:|
"""
:returns: string representation
"""
clstrs = []
for cl in self:
cllines = str(cl).splitlines()
if len(cllines) > 1:
pre_sep = sformat('[{0}\n ', cl.comment)
post_sep = '\n]'
else:
pre_sep = '[ '
post_sep = ''.join((' ]', cl.comment))
clstr = ''.join((pre_sep, '\n '.join(cllines), post_sep ))
clstrs.append(clstr)
return '\n'.join(clstrs)
def __init__(self, *args, **kwargs): # |:mth:|
if args:
cv = args[0]
args = ()
else:
cv = None
self.indx = 0
self.max_vectors = 0
self.comment = ''
self._pyjsmo_x_progress = kwargs.pop('progress', None)
super(Clause, self).__init__(*args, **kwargs)
if cv:
self.add_cv(cv)
# --------------------------------------------------
# ||:sec:|| Progress
# --------------------------------------------------
_pyjsmo_x_progress = None
[docs] def progress(self, message, **kwargs): # |:mth:|
"""
:returns: self for chaining.
"""
if self._pyjsmo_x_progress:
self._pyjsmo_x_progress.step(message, **kwargs)
return self
# --------------------------------------------------
# ||:sec:|| Internal
# --------------------------------------------------
[docs] def add_cv(self, cv): # |:mth:|
"""Add copy of clause vector.
:returns: self for chaining.
"""
cv = ClauseVector(cv)
self.append(cv)
return self
# --------------------------------------------------
# ||:sec:|| Parameters
# --------------------------------------------------
[docs] def key(self): # |:mth:|
"""
:returns: sort key
"""
for cv in self:
return cv.key()
val = TRUTH_VALUES[-1]
return sformat('{0:5d}|{1}', 99999 - 0, val)
[docs] def max_used(self): # |:mth:|
"""
:returns: max number of used columns in sub-clauses/vectors
"""
used = 0
for sub in self:
sub_used = sub.max_used()
if used < sub_used:
used = sub_used
return used
[docs] def max_width(self): # |:mth:|
"""
:returns: max width of sub-clauses/vectors
"""
width = 0
for sub in self:
sub_width = sub.max_width()
if width < sub_width:
width = sub_width
return width
[docs] def max_depth(self): # |:mth:|
"""
:returns: max depth of sub-clauses/vectors
>>> pr = Problem()
>>> printf(pr.max_depth())
0
>>> pr = Problem('[ 1 1 _ _ _ _ ] [ _ _ 1 1 _ _ ] [ _ _ _ _ 1 1 ]')
>>> printf(pr.max_depth())
1
>>> pr = Problem('[[ 1 1 _ _ _ _ ] [ _ _ 1 1 _ _ ] [ _ _ _ _ 1 1 ]]')
>>> printf(pr.max_depth())
2
>>> pr = Problem('[[ 1 1 _ _ _ _ ] [ _ _ 1 1 _ _ ] [ _ _ _ _ 1 1 ] [[ 1 1 _ _ _ _ ] [ _ _ 1 1 _ _ ] [ _ _ _ _ 1 1 ]]]')
>>> printf(pr.max_depth())
3
"""
depth = 0
for sub in self:
sub_depth = sub.max_depth() + 1
if depth < sub_depth:
depth = sub_depth
return depth
[docs] def has_one(self): # |:mth:|
"""
:returns: True, if any sub-clause/vector has an unnegated
variable. False otherwise.
..
"""
for member in self:
if member.has_one():
return True
return False
[docs] def has_zero(self): # |:mth:|
"""
:returns: True, if any sub-clause/vector has a negated
variable. False otherwise.
..
"""
for member in self:
if member.has_zero():
return True
return False
# --------------------------------------------------
# ||:sec:|| Operators
# --------------------------------------------------
[docs] def can_fold(self): # |:mth:|
"""
:returns: True, if clause vector can fold. I.e., its used column count is 1.
"""
return True
[docs] def conflicts_with(self, other): # |:mth:|
"""
:returns: True, if self conflicts with other.
"""
return False
[docs] def equals(self, other): # |:mth:|
"""
:returns: True, if self contains other.
"""
return False
[docs] def contains(self, other): # |:mth:|
"""
:returns: True, if self contains other.
"""
return False
# --------------------------------------------------
# ||:sec:|| Functions
# --------------------------------------------------
[docs] def copy(self): # |:mth:|
"""
:returns: copy
"""
return copy.deepcopy(self)
[docs] def set_width(self, width=-1): # |:mth:|
"""Set width.
:returns: self for chaining.
:param width: if < 0, set width to :meth:`max_width`.
"""
if width < 0:
width = self.max_width()
for cv in self:
cv.set_width(width)
return self
[docs] def index(self): # |:mth:|
"""Index members.
:returns: self for chaining.
"""
for indx, member in enumerate(self):
member.indx = indx
member.index()
return self
[docs] def annotate(self, clause_types=None): # |:mth:|
"""Index members.
:returns: self for chaining.
"""
if clause_types is None:
clause_types = CLAUSE_TYPES
self.comment = ''.join((' // ', clause_types[0]))
clause_types = list(reversed(clause_types))
for cl in self:
cl.annotate(clause_types)
return self
[docs] def sort(self): # |:mth:|
"""
:returns: self for chaining.
"""
self[:] = sorted([member.sort() for member in self], key=lambda e: e.sort().key())
return self
[docs] def sort_by_index(self): # |:mth:|
"""
:returns: self for chaining.
"""
self[:] = sorted([member.sort_by_index() for member in self], key=lambda e: e.indx)
return self
[docs] def negate(self): # |:mth:|
"""
:returns: self for chaining
"""
for cv in self:
cv.negate()
return self
[docs] def fold(self): # |:mth:|
"""
:returns: folded ClauseVector.
"""
if len(self) == 1 and isinstance(self[0], ClauseVector):
fcv = self[0]
fcv.indx = self.indx
return fcv
can_fold = True
fcv = ClauseVector()
fcv.indx = self.indx
for indx, cl in enumerate(self):
fcl = cl.fold()
self[indx] = fcl
if not isinstance(fcl, ClauseVector):
can_fold = False
elif can_fold:
can_fold = fcl.can_fold()
if can_fold:
fcv.set_width(fcl.max_width())
for indx in fcl.used_cols:
fcv[indx] = fcl[indx]
if can_fold:
return fcv
return self
[docs] def split(self): # |:mth:|
"""
:returns: self for chaining.
"""
return self
[docs] def remove_duplicates(self, sort=None): # |:mth:|
"""Remove duplicate clauses in place.
:returns: self for chaining.
:param sort: if True, also sort clause.
>>> cl = Problem('[ 1 - 0 1 ][ 1 0 1 ][ 0 1 ][ 1 0 1 ][ - - 0 1 ][ 1 - 0 0 ]')
>>> printf(cl)
[ 1 _ 0 1 ]
[ 1 0 1 ]
[ 0 1 ]
[ 1 0 1 ]
[ _ _ 0 1 ]
[ 1 _ 0 0 ]
>>> printf(cl.remove_duplicates())
[ 1 _ 0 1 ]
[ 0 1 ]
[ 1 0 1 ]
[ _ _ 0 1 ]
[ 1 _ 0 0 ]
"""
spr = self.copy()
if not sort:
spr.index()
spr.sort()
rr_clauses = []
while spr:
cv = spr.pop()
if isinstance(cv, ClauseVector):
next_spr = Clause()
for comp_cv in spr:
if cv.equals(comp_cv):
continue
next_spr.append(comp_cv)
spr = next_spr
else:
cv.remove_duplicates()
rr_clauses.append(cv)
self[:] = rr_clauses
if not sort:
self.sort_by_index()
return self
[docs] def remove_redundant(self, sort=None): # |:mth:|
"""Remove redundant clauses in place.
:returns: self for chaining.
:param sort: if True, also sort clause.
>>> cl = Problem('[ 1 - 0 1 ][ 1 0 1 ][ 0 1 ][ 1 0 1 ][ - - 0 1 ][ 1 - 0 0 ]')
>>> printf(cl)
[ 1 _ 0 1 ]
[ 1 0 1 ]
[ 0 1 ]
[ 1 0 1 ]
[ _ _ 0 1 ]
[ 1 _ 0 0 ]
>>> printf(cl.remove_redundant())
[ 0 1 ]
[ 1 0 1 ]
[ _ _ 0 1 ]
[ 1 _ 0 0 ]
"""
spr = self.copy()
if not sort:
spr.index()
spr.sort()
rr_clauses = []
while spr:
cv = spr.pop()
if isinstance(cv, ClauseVector):
next_spr = Clause()
for comp_cv in spr:
if cv.contains(comp_cv):
continue
next_spr.append(comp_cv)
spr = next_spr
else:
cv.remove_redundant()
rr_clauses.append(cv)
self[:] = rr_clauses
if not sort:
self.sort_by_index()
return self
[docs] def minimize_(self): # |:mth:|
"""Minimize in place.
:returns: number of minimized clauses.
"""
m_debug = False # |:debug:|
minimized = 0
min_clauses = []
spr = self
while spr:
cv = spr.pop()
if isinstance(cv, ClauseVector):
next_spr = Clause()
for comp_cv in spr:
if isinstance(comp_cv, ClauseVector):
sdiff_col, shorter, longer = cv.sdiff(comp_cv)
if sdiff_col >= 0:
if len(longer.used_cols) == 1:
raise SatokuUnsatisfied(sformat(
'UNSAT: while minimizing {0} [ {1} ], {2} [ {3} ]',
shorter.indx, shorter, longer.indx, longer))
longer[sdiff_col] = -1
minimized += 1
m_debug and printe(sformat(
"{0}{3:^{1}} {4:<{2}s}: ]{5!s}[",
dbg_comm, dbg_twid, dbg_fwid, ':DBG:', 'minimized', (minimized, sdiff_col, shorter, longer)))
if longer.contains(shorter):
cv = longer
continue
next_spr.append(comp_cv)
spr = next_spr
else:
cv.minimize()
min_clauses.append(cv)
self[:] = min_clauses
return minimized
[docs] def minimize(self, sort=None): # |:mth:|
"""Minimize in place.
:returns: self for chaining.
:param sort: if True, also sort clause.
>>> cl = Problem('[ _ 1 _ 1 1 ][ 1 - 0 1 ][ 1 0 1 ][ 0 0 ][ 1 0 1 ][ - - 0 1 ][ 1 - 0 0 ][ - - 1 1 ]')
>>> printf(cl)
[ _ 1 _ 1 1 ]
[ 1 _ 0 1 ]
[ 1 0 1 ]
[ 0 0 ]
[ 1 0 1 ]
[ _ _ 0 1 ]
[ 1 _ 0 0 ]
[ _ _ 1 1 ]
>>> printf(cl.copy().remove_redundant())
[ _ 1 _ 1 1 ]
[ 0 0 ]
[ 1 0 1 ]
[ _ _ 0 1 ]
[ 1 _ 0 0 ]
[ _ _ 1 1 ]
>>> printf(cl.minimize())
[ 0 0 ]
[ _ 0 1 ]
[ 1 _ 0 _ ]
[ _ _ _ 1 ]
>>> cl = Problem('[ 0 0 0 ][ 0 0 1 ][ 0 1 0 ][ 0 1 1 ][ 1 0 0 ][ 1 0 1 ][ 1 1 0 ][ 1 1 1 ]')
>>> printf(cl)
[ 0 0 0 ]
[ 0 0 1 ]
[ 0 1 0 ]
[ 0 1 1 ]
[ 1 0 0 ]
[ 1 0 1 ]
[ 1 1 0 ]
[ 1 1 1 ]
>>> printf(cl.copy().remove_redundant())
[ 0 0 0 ]
[ 0 0 1 ]
[ 0 1 0 ]
[ 0 1 1 ]
[ 1 0 0 ]
[ 1 0 1 ]
[ 1 1 0 ]
[ 1 1 1 ]
>>> printf(cl.minimize()) #doctest: +ELLIPSIS
Traceback (most recent call last):
...
SatokuUnsatisfied: UNSAT: while minimizing 4 [ _ 0 _ ], 6 [ _ 1 _ ]
"""
m_debug = False # |:debug:|
if not sort:
self.index()
pass_ = 0
minimized = 1
while minimized:
if m_debug:
printe(sformat('{0}----------', dbg_comm))
printe(sformat(
"{0}{3:^{1}} {4:<{2}s}: ]{5!s}[",
dbg_comm, dbg_twid, dbg_fwid, ':DBG:', 'pass', pass_))
printe(self)
printe(sformat('{0}----------', dbg_comm))
self.remove_redundant(True)
if m_debug:
printe(self)
printe(sformat('{0}----------', dbg_comm))
minimized = self.minimize_()
pass_ += 1
if not sort:
self.sort_by_index()
return self
[docs] def remove_redundant_min(self, sort=None): # |:mth:|
"""Remove redundant minimal clauses in place.
:returns: self for chaining.
:param sort: if True, also sort clause.
Keep longest clause vectors.
>>> cl = Problem('[ 1 - 0 1 ][ 1 0 1 ][ 0 1 ][ 1 0 1 ][ - - 0 1 ][ 1 - 0 0 ]')
>>> printf(cl)
[ 1 _ 0 1 ]
[ 1 0 1 ]
[ 0 1 ]
[ 1 0 1 ]
[ _ _ 0 1 ]
[ 1 _ 0 0 ]
>>> printf(cl.remove_redundant_min())
[ 1 _ 0 1 ]
[ 1 0 1 ]
[ 0 1 ]
[ 1 _ 0 0 ]
"""
spr = self.copy()
if not sort:
spr.index()
spr.sort()
spr[:] = reversed(spr)
rr_clauses = []
while spr:
cv = spr.pop()
if isinstance(cv, ClauseVector):
next_spr = Clause()
for comp_cv in spr:
if comp_cv.contains(cv):
continue
next_spr.append(comp_cv)
spr = next_spr
else:
cv.remove_redundant_min()
rr_clauses.append(cv)
self[:] = rr_clauses
if not sort:
self.sort_by_index()
else:
self.sort()
return self
[docs] def expand(self): # |:mth:|
"""Expand clause vectors in place.
:returns: distributive expansion of clause vectors. (AND(OR()) -> OR(AND()), OR(AND()) -> AND(OR()))
>>> cl = Problem('[[1 0 - - - - ][ - - 1 0 - - ][ - - - - 1 0 ]]')[0]
>>> printf(cl)
[ 1 0 _ _ _ _ ]
[ _ _ 1 0 _ _ ]
[ _ _ _ _ 1 0 ]
>>> exp = cl.expand()
>>> printf(exp)
[ 1 _ 1 _ 1 _ ]
[ 1 _ 1 _ _ 0 ]
[ 1 _ _ 0 1 _ ]
[ 1 _ _ 0 _ 0 ]
[ _ 0 1 _ 1 _ ]
[ _ 0 1 _ _ 0 ]
[ _ 0 _ 0 1 _ ]
[ _ 0 _ 0 _ 0 ]
>>> cl = Problem('[1 0 1 ]').split()[0]
>>> printf(cl)
[ 1 _ _ ]
[ _ 0 _ ]
[ _ _ 1 ]
>>> exp = cl.expand()
>>> printf(exp)
[ 1 0 1 ]
>>> cl = Problem('[[ 1 _ _ ][ 0 0 _ ][ 0 1 1 ]]').split()[0]
>>> printf(cl)
[ 1 _ _ ]
[ 0 0 _ ]
[ 0 1 1 ]
>>> exp = cl.expand()
>>> printf(exp)
[ 1 0 1 ]
>>> exp = exp.expand()
>>> printf(exp)
[ 1 _ _ ]
[ _ 0 _ ]
[ _ _ 1 ]
"""
exp_result = Clause()
max_vectors = 0
step = 0
for cv in self:
clause = cv.split()
# |:info:| could use cv.max_conflicts(), but it only slows
# down expansion without decreasing the maximum
# number of intermediate vectors.
# clause = cv.max_conflicts()
if not exp_result:
exp_result.extend(clause)
else:
next_exp_result = Clause()
for crcv in exp_result:
for subcv in clause:
ncrcv = crcv.copy()
for col in subcv.used_cols:
if ncrcv.conflicts_with(subcv):
continue
ncrcv[col] = subcv[col]
next_exp_result.append(ncrcv)
exp_result = next_exp_result
exp_result.minimize()
vector_ct = len(exp_result)
if max_vectors < vector_ct:
max_vectors = vector_ct
if _verbose:
self.progress(sformat('exp {0:4d} {1}', step, vector_ct))
step += 1
self[:] = exp_result
self.max_vectors = max_vectors
if _verbose:
self.progress('max vectors', info=max_vectors)
return self
[docs] def max_conflicts(self): # |:mth:|
"""Maximize conflicts.
:returns: maximized clause.
::
(l0 | l1 | l2 ) = ( l0 | (!l0 & l1) | (!l0 & !l1 & l2))
[ 1 1 1 ] = [[ 1 _ _ ] [[ 1 _ _ ]
[ _ 1 _ ] = [ 0 1 _ ]
[ _ _ 1 ]] [ 0 0 1 ]]
"""
can_maximize = len(self) > 0
if not can_maximize:
return self
if len(self) == 1 and isinstance(self[0], ClauseVector):
fcv = self.pop(0)
self.extend(fcv.split())
else:
for cv in self:
if not isinstance(cv, ClauseVector):
can_maximize = False
break
if len(cv.used_cols) != 1:
can_maximize = False
break
if can_maximize:
max_cvs = []
neg_cv = ClauseVector()
for cv in self:
# drop clause vectors, which conflict
if cv.conflicts_with(neg_cv):
continue
neg_col = cv.used_cols[0]
for col in neg_cv.used_cols:
cv[col] = neg_cv[col]
neg_cv[neg_col] = TRUTH_VALUES_NEG[cv[neg_col]]
max_cvs.append(cv)
self[:] = max_cvs
return self
[docs] def max_max_conflicts(self, full=None): # |:mth:|
"""Maximize conflicts including clauses.
:returns: maximized clause.
::
(l0 | l1 | l2 ) = ( l0 | (!l0 & l1) | (!l0 & !l1 & l2))
[ 1 1 1 ] = [[ 1 _ _ ] [[ 1 _ _ ]
[ _ 1 _ ] = [ 0 1 _ ]
[ _ _ 1 ]] [ 0 0 1 ]]
::
((l0 & l1) | (l2 & l3) | (l4 & l5))
= ((l0 & l1) |
(!l0 & l2 & l3) | (!l1 & l2 & l3) |
(!l0 & !l2 & l4 & l5) | (!l1 & !l2 & l4 & l5) |
(!l0 & !l3 & l4 & l5) | (!l1 & !l3 & l4 & l5))
[
[ 1 1 _ _ _ _ ]
[ _ _ 1 1 _ _ ]
[ _ _ _ _ 1 1 ]
]
=>
[
[ 1 1 _ _ _ _ ]
[ 0 _ 1 1 _ _ ]
[ _ 0 1 1 _ _ ]
[ 0 _ 0 _ 1 1 ]
[ 0 _ _ 0 1 1 ]
[ _ 0 0 _ 1 1 ]
[ _ 0 _ 0 1 1 ]
]
>>> pr = Problem('[ 1 1 1 ] [0 _ 1 1 ]')
>>> ign = pr.max_max_conflicts()
>>> printf(pr)
[
[ 1 _ _ ]
[ 0 1 _ ]
[ 0 0 1 ]
]
[
[ 0 _ _ _ ]
[ 1 _ 1 _ ]
[ 1 _ 0 1 ]
]
>>> pr = Problem('[[ 1 1 _ _ _ _ ] [ _ _ 1 1 _ _ ] [ _ _ _ _ 1 1 ]]')
>>> printf(pr)
[
[ 1 1 _ _ _ _ ]
[ _ _ 1 1 _ _ ]
[ _ _ _ _ 1 1 ]
]
>>> ign = pr.max_max_conflicts()
>>> printf(pr)
[
[ 1 1 _ _ _ _ ]
[ 0 _ 1 1 _ _ ]
[ _ 0 1 1 _ _ ]
[ 0 _ 0 _ 1 1 ]
[ 0 _ _ 0 1 1 ]
[ _ 0 0 _ 1 1 ]
[ _ 0 _ 0 1 1 ]
]
>>> pr = Problem('[[ 1 1 _ _ _ _ ] [ _ _ 1 1 _ _ ] [ _ _ _ _ 1 1 ]]')
>>> ign = pr.max_max_conflicts(full=True)
>>> printf(pr)
[
[ 1 1 _ _ _ _ ]
[ 0 0 1 1 _ _ ]
[ 0 1 1 1 _ _ ]
[ 1 0 1 1 _ _ ]
[ 0 0 0 0 1 1 ]
[ 0 0 0 1 1 1 ]
[ 0 0 1 0 1 1 ]
[ 0 1 0 0 1 1 ]
[ 0 1 0 1 1 1 ]
[ 0 1 1 0 1 1 ]
[ 1 0 0 0 1 1 ]
[ 1 0 0 1 1 1 ]
[ 1 0 1 0 1 1 ]
]
>>> pr = Problem('[[ 1 1 _ _ ] [ _ 1 1 _ ] [ _ _ 1 1 ]]')
>>> ign = pr.max_max_conflicts()
>>> printf(pr)
[
[ 1 1 _ _ ]
[ 0 1 1 _ ]
[ 0 0 1 1 ]
[ _ 0 1 1 ]
]
.. \\|:todo:| fix overlapping clauses
>>> pr = Problem('[[ 1 1 _ _ ] [ _ 0 1 _ ] [ _ 0 _ _ 1 ]]').set_width()
>>> printf(pr)
[
[ 1 1 _ _ _ ]
[ _ 0 1 _ _ ]
[ _ 0 _ _ 1 ]
]
| Conflicting negations: duplicate
| Conflicting merges: drop
| keep longest!
>>> mpr = pr.copy().max_max_conflicts()
>>> printf(mpr)
[
[ 1 1 _ _ _ ]
[ 0 0 1 _ _ ]
[ _ 0 1 _ _ ]
[ 0 0 0 _ 1 ]
[ _ 0 _ _ 1 ]
[ _ 0 0 _ 1 ]
]
old::
[
[ 1 1 _ _ _ ]
[ 0 0 1 _ _ ]
[ _ 0 1 _ _ ]
[ 0 0 0 _ 1 ]
[ _ 0 0 _ 1 ]
]
::
----------
[ 1 1 _ _ _ _ ]
[ 0 _ _ _ _ _ ]
[ _ 0 _ _ _ _ ]
----------
[ _ 0 1 _ _ _ ]
[ _ 1 _ _ _ _ ]
[ _ _ 0 _ _ _ ]
----------
[ _ 0 _ _ 1 _ ]
[ _ 1 _ _ _ _ ]
[ _ _ _ _ 0 _ ]
::
----------
[ 1 1 _ _ _ _ ]
[ 0 _ _ _ _ _ ]
[ _ 0 _ _ _ _ ]
----------
[ 0 0 1 _ _ _ ]
[ _ 0 1 _ _ _ ]
[ 0 1 _ _ _ _ ]
[ 0 _ 0 _ _ _ ]
[ _ 0 _ _ _ _ ]
[ _ 1 _ _ _ _ ]
[ _ 0 0 _ _ _ ]
----------
[ 0 0 0 _ 1 _ ]
[ _ 0 _ _ 1 _ ]
[ _ 0 0 _ 1 _ ]
>>> mpr = pr.copy().max_max_conflicts(full=True)
>>> printf(mpr)
[
[ 1 1 _ _ _ ]
[ 0 0 1 _ _ ]
[ 1 0 1 _ _ ]
[ 0 0 1 _ 1 ]
[ 0 0 0 _ 1 ]
[ 1 0 0 _ 1 ]
[ 1 0 1 _ 1 ]
]
old::
[
[ 1 1 _ _ _ ]
[ 0 0 1 _ _ ]
[ 1 0 1 _ _ ]
]
::
----------
[ 1 1 _ _ _ _ ]
[ 0 0 _ _ _ _ ]
[ 0 1 _ _ _ _ ]
[ 1 0 _ _ _ _ ]
----------
[ _ 0 1 _ _ _ ]
[ 0 0 1 _ _ _ ]
[ 1 0 1 _ _ _ ]
[ 0 0 0 _ _ _ ]
[ 0 0 1 _ _ _ ]
[ 0 1 1 _ _ _ ]
[ 0 0 1 _ _ _ ]
[ 0 1 0 _ _ _ ]
[ 0 0 0 _ _ _ ]
[ 0 1 1 _ _ _ ]
[ 0 0 1 _ _ _ ]
[ 0 1 1 _ _ _ ]
[ 1 0 0 _ _ _ ]
[ 1 0 1 _ _ _ ]
[ 1 0 1 _ _ _ ]
[ 1 1 1 _ _ _ ]
=>
[ 0 0 0 _ _ _ ]
[ 0 0 1 _ _ _ ]
[ 0 1 0 _ _ _ ]
[ 0 1 1 _ _ _ ]
[ 1 0 0 _ _ _ ]
[ 1 0 1 _ _ _ ]
[ 1 1 1 _ _ _ ]
----------
[ _ 0 _ _ 1 _ ]
[ 0 0 0 _ 1 _ ]
[ 0 0 1 _ 1 _ ]
[ 1 0 0 _ 1 _ ]
[ 1 0 1 _ 1 _ ]
"""
can_maximize = len(self) > 0
if not can_maximize:
return self
if len(self) == 1 and isinstance(self[0], ClauseVector):
fcv = self.pop(0)
self.extend(fcv.split())
else:
max_depth = self.max_depth()
can_maximize = max_depth < 2
if can_maximize:
max_cvs = []
neg_cv = ClauseVector()
neg_cvs = [neg_cv]
for cv in self:
if not isinstance(cv, ClauseVector):
raise SatokuError(sformat('cannot maximize type {0}', type(cv)))
for neg_cv in neg_cvs:
# drop clause vectors, which conflict
if cv.conflicts_with(neg_cv):
continue
mcv = ClauseVector(cv)
for col in neg_cv.used_cols:
mcv[col] = neg_cv[col]
max_cvs.append(mcv)
if full:
# full
cur_neg_cvs = list(filter(lambda pcv: cv.conflicts_with(pcv), permute_cols(cv.used_cols)))
else:
# fast
cur_neg_cvs = []
for neg_col in cv.used_cols:
neg_cv = ClauseVector()
neg_cv[neg_col] = TRUTH_VALUES_NEG[cv[neg_col]]
cur_neg_cvs.append(neg_cv)
next_neg_cvs = []
for neg_cv in neg_cvs:
for cur_neg_cv in cur_neg_cvs:
next_neg_cv = ClauseVector(neg_cv)
next_neg_cvs_local = [next_neg_cv]
for neg_col in cur_neg_cv.used_cols:
next_next_neg_cvs_local = []
for next_neg_cv in next_neg_cvs_local:
if len(next_neg_cv) > neg_col and next_neg_cv[neg_col] >= 0:
next_next_neg_cvs_local.append(ClauseVector(next_neg_cv))
next_neg_cv[neg_col] = cur_neg_cv[neg_col]
next_next_neg_cvs_local.append(next_neg_cv)
next_neg_cvs_local = next_next_neg_cvs_local
next_neg_cvs.extend(next_neg_cvs_local)
neg_cvs = next_neg_cvs
self[:] = max_cvs
self.remove_duplicates()
#self.remove_redundant()
#self.remove_redundant_min()
return self
[docs] def xor_conflicts(self): # |:mth:|
"""XOR conflicts.
:returns: XOR clause.
::
(l0 | l1 | l2 ) = ( l0 | (!l0 & l1) | (!l0 & !l1 & l2))
[ 1 1 1 ] = [[ 1 _ _ ] [[ 1 _ _ ]
[ _ 1 _ ] = [ 0 1 _ ]
[ _ _ 1 ]] [ 0 0 1 ]]
"""
can_maximize = len(self) > 0
if not can_maximize:
return self
if len(self) == 1 and isinstance(self[0], ClauseVector):
fcv = self.pop(0)
self.extend(fcv.split())
else:
for cv in self:
if not isinstance(cv, ClauseVector):
can_maximize = False
break
if len(cv.used_cols) != 1:
can_maximize = False
break
if can_maximize:
xor_cvs = []
std_cv = ClauseVector()
neg_cv = ClauseVector()
for cv in self:
# drop clause vectors, which conflict
if cv.conflicts_with(std_cv):
continue
# drop clause vectors, which conflict
if cv.conflicts_with(neg_cv):
continue
col = cv.used_cols[0]
std_cv[col] = cv[col]
neg_cv[col] = TRUTH_VALUES_NEG[cv[col]]
for cv in self:
for col in neg_cv.used_cols:
if cv[col] == -1:
cv[col] = neg_cv[col]
xor_cvs.append(cv)
xor_cvs.append(std_cv)
self[:] = xor_cvs
return self
# (progn (forward-line -1) (insert "\n") (snip-insert "py.s.meth" t t "py") (backward-symbol-tag 1 "fillme" "::"))
# (progn (forward-line -2) (insert "\n") (snip-insert "py.s.property" t t "py") (backward-symbol-tag 1 "fillme" "::"))
__all__.append('OrClause')
[docs]class OrClause(Clause): # ||:cls:||
"""
"""
def __init__(self, *args, **kwargs): # |:mth:|
super(OrClause, self).__init__(*args, **kwargs)
# (progn (forward-line -1) (insert "\n") (snip-insert "py.s.meth" t t "py") (backward-symbol-tag 1 "fillme" "::"))
# (progn (forward-line -2) (insert "\n") (snip-insert "py.s.property" t t "py") (backward-symbol-tag 1 "fillme" "::"))
__all__.append('AndClause')
[docs]class AndClause(Clause): # ||:cls:||
"""
"""
def __init__(self, *args, **kwargs): # |:mth:|
super(AndClause, self).__init__(*args, **kwargs)
# (progn (forward-line -1) (insert "\n") (snip-insert "py.s.meth" t t "py") (backward-symbol-tag 1 "fillme" "::"))
# (progn (forward-line -2) (insert "\n") (snip-insert "py.s.property" t t "py") (backward-symbol-tag 1 "fillme" "::"))
__all__.append('Problem')
[docs]class Problem(AndClause): # ||:cls:||
"""
>>> pr = Problem(TEST_PROBLEM)
>>> printf(pr)
[
[ 1 _ _ 0 _ ]
[ 0 1 _ _ _ ]
[ 0 0 1 _ _ ]
]
[ 1 0 1 _ _ ]
[ 0 1 0 _ _ ]
[ _ 1 0 1 ]
[ _ _ 0 1 1 ]
[
[ _ 0 _ _ _ ]
[ _ 1 _ 1 _ ]
[ _ 1 _ 0 0 ]
]
>>> printf(pr.split())
[
[ 1 _ _ 0 _ ]
[ 0 1 _ _ _ ]
[ 0 0 1 _ _ ]
]
[
[ 1 _ _ _ _ ]
[ _ 0 _ _ _ ]
[ _ _ 1 _ _ ]
]
[
[ 0 _ _ _ _ ]
[ _ 1 _ _ _ ]
[ _ _ 0 _ _ ]
]
[
[ _ 1 _ _ ]
[ _ _ 0 _ ]
[ _ _ _ 1 ]
]
[
[ _ _ 0 _ _ ]
[ _ _ _ 1 _ ]
[ _ _ _ _ 1 ]
]
[
[ _ 0 _ _ _ ]
[ _ 1 _ 1 _ ]
[ _ 1 _ 0 0 ]
]
>>> printf(pr.split())
[
[ 1 _ _ 0 _ ]
[ 0 1 _ _ _ ]
[ 0 0 1 _ _ ]
]
[
[ 1 _ _ _ _ ]
[ _ 0 _ _ _ ]
[ _ _ 1 _ _ ]
]
[
[ 0 _ _ _ _ ]
[ _ 1 _ _ _ ]
[ _ _ 0 _ _ ]
]
[
[ _ 1 _ _ ]
[ _ _ 0 _ ]
[ _ _ _ 1 ]
]
[
[ _ _ 0 _ _ ]
[ _ _ _ 1 _ ]
[ _ _ _ _ 1 ]
]
[
[ _ 0 _ _ _ ]
[ _ 1 _ 1 _ ]
[ _ 1 _ 0 0 ]
]
>>> printf(pr.max_conflicts())
[
[ 1 _ _ 0 _ ]
[ 0 1 _ _ _ ]
[ 0 0 1 _ _ ]
]
[
[ 1 _ _ _ _ ]
[ 0 0 _ _ _ ]
[ 0 1 1 _ _ ]
]
[
[ 0 _ _ _ _ ]
[ 1 1 _ _ _ ]
[ 1 0 0 _ _ ]
]
[
[ _ 1 _ _ ]
[ _ 0 0 _ ]
[ _ 0 1 1 ]
]
[
[ _ _ 0 _ _ ]
[ _ _ 1 1 _ ]
[ _ _ 1 0 1 ]
]
[
[ _ 0 _ _ _ ]
[ _ 1 _ 1 _ ]
[ _ 1 _ 0 0 ]
]
>>> printf(pr.split())
[
[ 1 _ _ 0 _ ]
[ 0 1 _ _ _ ]
[ 0 0 1 _ _ ]
]
[
[ 1 _ _ _ _ ]
[ 0 0 _ _ _ ]
[ 0 1 1 _ _ ]
]
[
[ 0 _ _ _ _ ]
[ 1 1 _ _ _ ]
[ 1 0 0 _ _ ]
]
[
[ _ 1 _ _ ]
[ _ 0 0 _ ]
[ _ 0 1 1 ]
]
[
[ _ _ 0 _ _ ]
[ _ _ 1 1 _ ]
[ _ _ 1 0 1 ]
]
[
[ _ 0 _ _ _ ]
[ _ 1 _ 1 _ ]
[ _ 1 _ 0 0 ]
]
>>> printf(pr.max_conflicts())
[
[ 1 _ _ 0 _ ]
[ 0 1 _ _ _ ]
[ 0 0 1 _ _ ]
]
[
[ 1 _ _ _ _ ]
[ 0 0 _ _ _ ]
[ 0 1 1 _ _ ]
]
[
[ 0 _ _ _ _ ]
[ 1 1 _ _ _ ]
[ 1 0 0 _ _ ]
]
[
[ _ 1 _ _ ]
[ _ 0 0 _ ]
[ _ 0 1 1 ]
]
[
[ _ _ 0 _ _ ]
[ _ _ 1 1 _ ]
[ _ _ 1 0 1 ]
]
[
[ _ 0 _ _ _ ]
[ _ 1 _ 1 _ ]
[ _ 1 _ 0 0 ]
]
.. \\|:here:|
"""
def __str__(self): # |:mth:||:todo:| fix indentation.
"""
:returns: string representation
"""
max_depth = self.max_depth()
clstrs = []
for cl in self:
cldepth = cl.max_depth()
cllines = str(cl).splitlines()
if len(cllines) > 1:
pre_sep = sformat('[{0}\n ', cl.comment)
post_sep = '\n]'
else:
pre_sep = '[ '
post_sep = ''.join((' ]', cl.comment))
cldepth += 1
clstr = ''.join((pre_sep, '\n '.join(cllines), post_sep))
indent = ' ' * ((max_depth - cldepth) * 2)
if False:
sep = ''.join(('\n', indent))
clstrs.append(''.join((indent, sep.join(clstr.splitlines()))))
else:
clstrs.append(clstr)
return '\n'.join(clstrs)
def __init__(self, *args, **kwargs): # |:mth:|
if args and isstring(args[0]):
string = args[0]
args = ()
else:
string = None
self.commands = []
super(Problem, self).__init__(*args, **kwargs)
if string:
self.parse_string(string)
[docs] def fold(self): # |:mth:|
"""
:returns: self for chaining.
"""
for indx, cl in enumerate(self):
self[indx] = cl.fold()
return self
[docs] def split(self): # |:mth:|
"""
:returns: self for chaining.
"""
for indx, cl in enumerate(self):
self[indx] = cl.split()
return self
[docs] def flatten(self): # |:mth:|
"""Flatten problem in place.
:returns: distributive expansion of each clause. (OR(AND()) -> AND(OR()))
>>> pr = Problem('[[1 0 - - - - ][ - - 1 0 - - ][ - - - - 1 0 ]] [[1 1 - - - - ][ - 0 1 - - - ][ - 0 - - 1 - ]]')
>>> cpr = pr.copy().flatten()
>>> printf(pr)
[
[ 1 0 _ _ _ _ ]
[ _ _ 1 0 _ _ ]
[ _ _ _ _ 1 0 ]
]
[
[ 1 1 _ _ _ _ ]
[ _ 0 1 _ _ _ ]
[ _ 0 _ _ 1 _ ]
]
>>> printf(cpr)
[ 1 _ 1 _ _ 0 ]
[ 1 _ _ 0 1 _ ]
[ 1 _ _ 0 _ 0 ]
[ _ 0 1 _ _ 0 ]
[ _ 0 _ 0 1 _ ]
[ _ 0 _ 0 _ 0 ]
[ 1 0 _ _ _ _ ]
[ _ _ 1 _ 1 _ ]
>>> pr = Problem('[ 1 _ 1 _ _ 0 ][ 1 _ _ 0 1 _ ][ 1 0 _ _ _ _ ][ 1 _ _ 0 _ 0 ]')
>>> cpr = pr.copy().flatten()
>>> printf(pr)
[ 1 _ 1 _ _ 0 ]
[ 1 _ _ 0 1 _ ]
[ 1 0 _ _ _ _ ]
[ 1 _ _ 0 _ 0 ]
>>> printf(cpr)
[ 1 _ 1 _ _ 0 ]
[ 1 _ _ 0 1 _ ]
[ 1 0 _ _ _ _ ]
[ 1 _ _ 0 _ 0 ]
>>> rpr = cpr.copy().remove_redundant()
>>> printf(rpr)
[ 1 _ 1 _ _ 0 ]
[ 1 _ _ 0 1 _ ]
[ 1 0 _ _ _ _ ]
[ 1 _ _ 0 _ 0 ]
>>> mpr = cpr.copy().minimize()
>>> printf(mpr)
[ 1 _ 1 _ _ 0 ]
[ 1 _ _ 0 1 _ ]
[ 1 0 _ _ _ _ ]
[ 1 _ _ 0 _ 0 ]
>>> fpr = cpr.copy().flatten()
>>> printf(fpr)
[ 1 _ 1 _ _ 0 ]
[ 1 _ _ 0 1 _ ]
[ 1 0 _ _ _ _ ]
[ 1 _ _ 0 _ 0 ]
>>> ccpr = cpr.copy().expand()
>>> printf(ccpr)
[ 1 _ _ _ _ _ ]
[ _ 0 1 0 _ _ ]
[ _ 0 _ 0 _ 0 ]
[ _ 0 _ _ 1 0 ]
>>> cccpr = ccpr.copy().expand()
>>> printf(cccpr)
[ 1 _ 1 _ _ 0 ]
[ 1 _ _ 0 _ 0 ]
[ 1 _ _ 0 1 _ ]
[ 1 0 _ _ _ _ ]
>>> pr = Problem('[[1 0 - - - - ][ - - 1 0 - - ][ - - - - 1 0 ]] [[1 1 - - - - ][ - 0 1 - - - ][ - 0 - - 1 - ]]')
>>> printf(pr)
[
[ 1 0 _ _ _ _ ]
[ _ _ 1 0 _ _ ]
[ _ _ _ _ 1 0 ]
]
[
[ 1 1 _ _ _ _ ]
[ _ 0 1 _ _ _ ]
[ _ 0 _ _ 1 _ ]
]
>>> mpr = pr.max_max_conflicts(full=True)
>>> printf(mpr)
[
[ 1 0 _ _ _ _ ]
[ 0 0 1 0 _ _ ]
[ 0 1 1 0 _ _ ]
[ 1 1 1 0 _ _ ]
[ 0 0 0 0 1 0 ]
[ 0 0 0 1 1 0 ]
[ 0 0 1 1 1 0 ]
[ 0 1 0 0 1 0 ]
[ 0 1 0 1 1 0 ]
[ 0 1 1 1 1 0 ]
[ 1 1 0 0 1 0 ]
[ 1 1 0 1 1 0 ]
[ 1 1 1 1 1 0 ]
]
[
[ 1 1 _ _ _ _ ]
[ 0 0 1 _ _ _ ]
[ 1 0 1 _ _ _ ]
[ 0 0 1 _ 1 _ ]
[ 0 0 0 _ 1 _ ]
[ 1 0 0 _ 1 _ ]
[ 1 0 1 _ 1 _ ]
]
>>> min_pr = mpr.minimize().sort()
>>> printf(min_pr)
[
[ 1 0 _ _ _ _ ]
[ _ _ 1 0 _ _ ]
[ _ _ _ _ 1 0 ]
]
[
[ 1 1 _ _ _ _ ]
[ _ 0 1 _ _ _ ]
[ _ 0 _ _ 1 _ ]
]
>>> cpr = min_pr.copy().flatten()
>>> printf(cpr)
[ 1 _ 1 _ _ 0 ]
[ 1 _ _ 0 1 _ ]
[ 1 _ _ 0 _ 0 ]
[ _ 0 1 _ _ 0 ]
[ _ 0 _ 0 1 _ ]
[ _ 0 _ 0 _ 0 ]
[ 1 0 _ _ _ _ ]
[ _ _ 1 _ 1 _ ]
>>> cpr = mpr.copy().flatten()
>>> printf(cpr)
[ 1 _ 1 _ _ 0 ]
[ 1 _ _ 0 1 _ ]
[ 1 _ _ 0 _ 0 ]
[ _ 0 1 _ _ 0 ]
[ _ 0 _ 0 1 _ ]
[ _ 0 _ 0 _ 0 ]
[ 1 0 _ _ _ _ ]
[ _ _ 1 _ 1 _ ]
>>> max_pr = cpr.copy().max_max_conflicts(full=True)
>>> printf(max_pr)
[
[ 1 _ _ _ _ _ ]
[ 0 _ 1 _ _ _ ]
[ 0 _ 0 _ _ 0 ]
]
[
[ 1 _ _ _ _ _ ]
[ 0 _ _ 0 _ _ ]
[ 0 _ _ 1 1 _ ]
]
[
[ 1 _ _ _ _ _ ]
[ 0 _ _ 0 _ _ ]
[ 0 _ _ 1 _ 0 ]
]
[
[ _ 0 _ _ _ _ ]
[ _ 1 1 _ _ _ ]
[ _ 1 0 _ _ 0 ]
]
[
[ _ 0 _ _ _ _ ]
[ _ 1 _ 0 _ _ ]
[ _ 1 _ 1 1 _ ]
]
[
[ _ 0 _ _ _ _ ]
[ _ 1 _ 0 _ _ ]
[ _ 1 _ 1 _ 0 ]
]
[
[ 1 _ _ _ _ _ ]
[ 0 0 _ _ _ _ ]
]
[
[ _ _ 1 _ _ _ ]
[ _ _ 0 _ 1 _ ]
]
>>> fpr = max_pr.copy().flatten()
>>> printf(fpr)
[ 1 _ 1 _ _ 0 ]
[ 1 _ _ 0 1 _ ]
[ 1 _ _ 0 _ 0 ]
[ _ 0 1 _ _ 0 ]
[ _ 0 _ 0 1 _ ]
[ _ 0 _ 0 _ 0 ]
[ 1 0 _ _ _ _ ]
[ _ _ 1 _ 1 _ ]
>>> min_pr = fpr.copy().minimize().sort()
>>> printf(min_pr)
[ 1 _ 1 _ _ 0 ]
[ 1 _ _ 0 1 _ ]
[ 1 _ _ 0 _ 0 ]
[ _ 0 1 _ _ 0 ]
[ _ 0 _ 0 1 _ ]
[ _ 0 _ 0 _ 0 ]
[ 1 0 _ _ _ _ ]
[ _ _ 1 _ 1 _ ]
>>> sol_pr = min_pr.copy().expand().sort()
>>> printf(sol_pr)
[ 1 0 1 _ _ _ ]
[ 1 0 _ _ 1 _ ]
[ 1 _ 1 0 _ _ ]
[ 1 _ _ _ 1 0 ]
[ _ 0 1 0 _ _ ]
[ _ 0 _ _ 1 0 ]
>>> cmp_pr = sol_pr.copy().expand().sort()
>>> printf(cmp_pr)
[ 1 _ 1 _ _ 0 ]
[ 1 _ _ 0 1 _ ]
[ 1 _ _ 0 _ 0 ]
[ _ 0 1 _ _ 0 ]
[ _ 0 _ 0 1 _ ]
[ _ 0 _ 0 _ 0 ]
[ 1 0 _ _ _ _ ]
[ _ _ 1 _ 1 _ ]
"""
cpr = Problem()
epr = self.copy().split()
for clause in epr:
if isinstance(clause, ClauseVector):
cpl = [clause]
else:
cpl = clause.expand()
cpr.extend(cpl)
cpr.minimize()
self[:] = cpr
return self
def max_conflicts(self): # |:mth:|
"""Maximize conflicts.
::
(l0 | l1 | l2 ) = ( l0 | (!l0 & l1) | (!l0 & !l1 & l2))
[ 1 1 1 ] = [[ 1 _ _ ] [[ 1 _ _ ]
[ _ 1 _ ] = [ 0 1 _ ]
[ _ _ 1 ]] [ 0 0 1 ]]
:returns: self for chaining.
"""
for indx, cl in enumerate(self):
self[indx] = cl.max_conflicts()
return self
[docs] def max_max_conflicts(self, full=None): # |:mth:|
"""Maximize conflicts in place.
::
(l0 | l1 | l2 ) = ( l0 | (!l0 & l1) | (!l0 & !l1 & l2))
[ 1 1 1 ] = [[ 1 _ _ ] [[ 1 _ _ ]
[ _ 1 _ ] = [ 0 1 _ ]
[ _ _ 1 ]] [ 0 0 1 ]]
:returns: self for chaining.
"""
for indx, cl in enumerate(self):
self[indx] = cl.max_max_conflicts(full=full)
return self
[docs] def xor_conflicts(self): # |:mth:|
"""Xorimize conflicts.
::
(l0 | l1 | l2 ) = ( l0 | (!l0 & l1) | (!l0 & !l1 & l2))
[ 1 1 1 ] = [[ 1 _ _ ] [[ 1 _ _ ]
[ _ 1 _ ] = [ 0 1 _ ]
[ _ _ 1 ]] [ 0 0 1 ]]
:returns: self for chaining.
"""
for indx, cl in enumerate(self):
self[indx] = cl.xor_conflicts()
return self
[docs] def max_conflicts(self): # |:mth:|
"""Maximize conflicts.
::
(l0 | l1 | l2 ) = ( l0 | (!l0 & l1) | (!l0 & !l1 & l2))
[ 1 1 1 ] = [[ 1 _ _ ] [[ 1 _ _ ]
[ _ 1 _ ] = [ 0 1 _ ]
[ _ _ 1 ]] [ 0 0 1 ]]
:returns: self for chaining.
"""
for indx, cl in enumerate(self):
self[indx] = cl.max_conflicts()
return self
[docs] def parse_string(self, string): # |:mth:|
"""
:returns: self for chaining.
"""
if self:
width = len(self[0])
else:
width = 0
clauses, commands = parse_clauses(string)
self.extend(clauses)
self.commands = commands
return self
[docs] def parse_file(self, filename=None): # |:mth:|
"""
:returns: self for chaining.
"""
do_close = True
if not filename or filename == '-':
do_close = False
in_fh = sys.stdin
else:
in_fh = open(filename, 'r')
self.parse_string(in_fh.read())
if do_close:
in_fh.close()
return self
# (progn (forward-line -1) (insert "\n") (snip-insert "py.s.meth" t t "py") (backward-symbol-tag 1 "fillme" "::"))
# (progn (forward-line -2) (insert "\n") (snip-insert "py.s.property" t t "py") (backward-symbol-tag 1 "fillme" "::"))
__all__.append('SelRow')
[docs]class SelRow(bytearray): # ||:cls:||
"""
:param size: initial size of row (keyword only).
..
>>> d = SelRow()
.. \\|:here:|
"""
def __init__(self, *args, **kwargs): # |:mth:|
size = kwargs.pop('size', 0)
if size is None:
size = 0
super(SelRow, self).__init__(*args, **kwargs)
if size:
self.expand(size)
[docs] def expand(self, size): # |:mth:|
"""
:returns: self for chaining.
"""
self.extend([2 for i in xrange(size)])
[docs] def fix_ones(self, matrix): # |:mth:|
"""
Fix hard ones in row.
"""
clause_count = len(matrix.clauses)
for sf in xrange(clause_count):
soft_count, hard_count, soft_ones, hard_ones = matrix.one_count(self, sf)
if soft_count == 1:
ci = matrix.clause_offsets[sf]
ri = ci + soft_ones[0]
self[ri] = 1
return self
[docs] def dump(self, matrix, indx, regions=None): # |:mth:|
"""
:returns: string representation.
"""
regions = matrix.get_dump_regions(regions)
if not regions:
printe('// warning: SelRow: regions is empty')
return
segments = []
cseq_indx = 0
for region in regions:
if region.size == 0:
continue
segments.append('|')
for ccsm in matrix.clauses[region.ofs:region.ofs+region.size]:
segment = ['']
if indx == ccsm.indx:
trans = TRUTH_VALUES_ID
else:
trans = TRUTH_VALUES
ofs = ccsm.ofs
for si in xrange(ccsm.size):
segment.append(trans[self[ofs+si]])
segment.append('|')
segments.append(' '.join(segment))
cseq_indx += 1
return ''.join(segments)
# (progn (forward-line -1) (insert "\n") (snip-insert "py.s.meth" t t "py") (backward-symbol-tag 1 "fillme" "::"))
# (progn (forward-line -2) (insert "\n") (snip-insert "py.s.property" t t "py") (backward-symbol-tag 1 "fillme" "::"))
__all__.append('SMRegion')
[docs]class SMRegion(PyJsMo): # ||:cls:||
"""Satoku matrix region.
:param ofs: is the clause number offset, where the region starts.
:param size: is the clause count inside the region.
..
>>> d = SMRegion()
.. >>> printf(d.definitionv())
.. \\|:here:|
"""
_pyjsmo_versions = [
(1, {'bases': [0],
'order': ['ofs', 'size'],
'defaults': pyjsmo.OrderedDict((
('ofs', 0),
('size', 0),
)),
'amap': [],
'expand': None,
}),
]
def __init__(self, ofs=None, size=None, **kwargs): # |:mth:|
if ofs is None:
ofs = 0
self.ofs = ofs
if size is None:
size = 0
self.size = size
super(SMRegion, self).__init__(**kwargs)
__all__.append('SMRegionIterator')
[docs]class SMRegionIterator(PyJsMo): # ||:cls:||
"""Region iterator supporting dynamic changes to regions.
>>> riter = SMRegionIterator(SMRegion(2, 4), SMRegion(8, 3), SMRegion(11, 2))
>>> [indx for indx in riter]
[2, 3, 4, 5, 8, 9, 10, 11, 12]
>>> [indx for indx in riter]
[]
>>> [indx for indx in riter.at(6)]
[8, 9, 10, 11, 12]
>>> for indx in riter.at(4): break
>>> indx
4
>>> riter.offset
5
>>> riter.regions[0].size -= 2
Now, the region does no longer support offset 5:
>>> for indx in riter: break
>>> indx
8
"""
regions = []
rindx = 0
offset = 0
def __iter__(self): # |:mth:|
# does not reset, otherwise at() would not work
#self.reset()
return self
def __next__(self): # |:mth:|
rindx = self.rindx
if rindx >= len(self.regions):
raise StopIteration
# readjust, since region might have changed
offset = self.adjust_offset(self.offset)
if offset is None:
raise StopIteration
next_offset = self.adjust_offset(offset + 1)
self.offset = next_offset
return offset
next = __next__
def adjust_offset(self, offset): # |:mth:|
rindx = self.rindx
while True:
if rindx >= len(self.regions):
return None
region = self.regions[rindx]
if offset < region.ofs:
offset = region.ofs
if offset < region.ofs + region.size:
return offset
if offset >= region.ofs + region.size:
rindx += 1
self.rindx = rindx
def at(self, offset): # |:mth:|
self.rindx = 0
self.offset = self.adjust_offset(offset)
return self
def reset(self): # |:mth:|
return self.at(0)
def __init__(self, *regions): # |:mth:|
if len(regions) == 1 and issequence(regions[0]):
regions = regions[0]
if not regions:
regions = [SMRegion(0, 0)]
self.regions = sorted(regions, key=lambda r: r.ofs)
self.reset()
def _get_region(self): # |:mth:|
r"""Programmatic property."""
rindx = self.rindx
if rindx >= len(self.regions):
region = None
else:
region = self.regions[rindx]
return region
region = property(_get_region, None, None, _get_region.__doc__)
# (progn (forward-line -1) (insert "\n") (snip-insert "py.s.meth" t t "py") (backward-symbol-tag 1 "fillme" "::"))
# (progn (forward-line -2) (insert "\n") (snip-insert "py.s.property" t t "py") (backward-symbol-tag 1 "fillme" "::"))
__all__.append('SMClause')
[docs]class SMClause(PyJsMo): # ||:cls:||
"""Satoku matrix clause.
..
>>> d = SMClause()
.. >>> printf(d.definitionv())
.. \\|:here:|
"""
_pyjsmo_versions = [
(1, {'bases': [0],
'order': ['indx', 'ofs', 'size', 'deleted'],
'defaults': pyjsmo.OrderedDict((
('indx', 0),
('ofs', 0),
('size', 0),
)),
'amap': [],
'expand': None,
}),
]
_pyjsmo_x_matrix = None
def _get_matrix(self): # |:mth:|
"""Weak reference."""
value = self._pyjsmo_x_matrix
if value is not None:
value = value()
return value
def _set_matrix(self, value): # |:mth:|
if value is not None:
value = weakref.ref(value)
self._pyjsmo_x_matrix = value
matrix = property(_get_matrix, _set_matrix, None, _get_matrix.__doc__)
_pyjsmo_x_clause = None
def _get_clause(self): # |:mth:|
"""Weak reference."""
value = self._pyjsmo_x_clause
if value is not None:
value = value()
return value
def _set_clause(self, value): # |:mth:|
if value is not None:
value = weakref.ref(value)
self._pyjsmo_x_clause = value
clause = property(_get_clause, _set_clause, None, _get_clause.__doc__)
def __init__(self, indx=None, ofs=None, clause=None, matrix=None, size=None, **kwargs): # |:mth:|
if matrix:
if indx is None:
if matrix.clauses:
indx = len(matrix.clauses)
if ofs is None:
ofs = matrix.size
self.indx = indx or 0
self.ofs = ofs
self.clause = clause
self.matrix = matrix
if clause:
self.size = len(clause)
else:
if size is None:
size = 0
self.size = size
super(SMClause, self).__init__(**kwargs)
[docs] def next_ofs(self): # |:mth:|
"""
:returns: self for chaining.
"""
return self.ofs + self.size
def adjust_row_range(self, si, sj, sx): # |:mth:|
row_count = sx - sj
if self.size - row_count < 2:
row_count = self.size - 2
sx = sj + row_count
return si, sj, sx
def repr(self, with_ofs=None): # |:mth:|
if with_ofs:
fmt = 's_i({0:>5d})<{1:>3d}>@{2:>6d}'
else:
fmt = 's_i({0:>5d})<{1:>3d}>'
return sformat(fmt, self.indx, self.size, self.ofs)
# (progn (forward-line -1) (insert "\n") (snip-insert "py.s.meth" t t "py") (backward-symbol-tag 1 "fillme" "::"))
# (progn (forward-line -2) (insert "\n") (snip-insert "py.s.property" t t "py") (backward-symbol-tag 1 "fillme" "::"))
# (progn (forward-line -3) (insert "\n") (snip-insert "py.s.property.weakref" t t "py"))
__all__.append('SMStats')
[docs]class SMStats(PyJsMo): # ||:cls:||
"""
>>> sms = SMStats()
>>> printf(sms)
{
"satisfiable": true,
"init_clauses": 0,
"init_variables": 0,
"init_synthesized": 0,
"init_rows": 0,
"clauses": 0,
"variables": 0,
"synthesized": 0,
"rows": 0,
"cells": 0,
"clauses_deleted": 0,
"rows_deleted": 0,
"row_kills": 0,
"duplicate_kills": 0,
"zero_changes": 0,
"soft_changes": 0,
"zero_update_passes": 0,
"row_update_passes": 0,
"superset_update_passes": 0,
"zero_updates": 0,
"row_updates": 0,
"superset_updates": 0,
"max_zero_updates": 0,
"max_row_updates": 0,
"max_superset_updates": 0,
"pending_zero_updates": 0,
"pending_row_updates": 0,
"pending_superset_updates": 0,
"row_checks": 0,
"row_merges": 0,
"state_combines": 0,
"cell_combines": 0,
"message": ""
}
..
.. >>> printf(str(sms.definitionv()))
.. \\|:here:|
"""
_pyjsmo_versions = [
(1, {'bases': [0],
'order': [],
'order': ['satisfiable',
'init_clauses', 'init_variables', 'init_synthesized', 'init_rows',
'clauses', 'variables', 'synthesized', 'rows', 'cells',
'clauses_deleted', 'rows_deleted', 'row_kills', 'duplicate_kills', 'zero_changes', 'soft_changes',
'zero_update_passes', 'row_update_passes', 'superset_update_passes',
'zero_updates', 'row_updates', 'superset_updates',
'max_zero_updates', 'max_row_updates', 'max_superset_updates',
'pending_zero_updates', 'pending_row_updates', 'pending_superset_updates',
'row_checks', 'row_merges', 'state_combines', 'cell_combines',
'message'],
'defaults': pyjsmo.OrderedDict((
('satisfiable', True),
('init_clauses', 0),
('init_variables', 0),
('init_synthesized', 0),
('init_rows', 0),
('clauses', 0),
('variables', 0),
('synthesized', 0),
('clauses_deleted', 0),
('rows_deleted', 0),
('rows', 0),
('cells', 0),
('row_kills', 0),
('duplicate_kills', 0),
('zero_changes', 0),
('soft_changes', 0),
('zero_update_passes', 0),
('row_update_passes', 0),
('superset_update_passes', 0),
('zero_updates', 0),
('row_updates', 0),
('superset_updates', 0),
('max_zero_updates', 0),
('max_row_updates', 0),
('max_superset_updates', 0),
('pending_zero_updates', 0),
('pending_row_updates', 0),
('pending_superset_updates', 0),
('row_checks', 0),
('row_merges', 0),
('state_combines', 0),
('cell_combines', 0),
('message', ''),
)),
'amap': [],
'expand': None,
}),
]
def __init__(self, *args, **kwargs): # |:mth:|
super(SMStats, self).__init__(*args, **kwargs)
# (progn (forward-line -1) (insert "\n") (snip-insert "py.s.meth" t t "py") (backward-symbol-tag 1 "fillme" "::"))
# (progn (forward-line -2) (insert "\n") (snip-insert "py.s.property" t t "py") (backward-symbol-tag 1 "fillme" "::"))
__all__.append('SatokuMatrix')
[docs]class SatokuMatrix(PyJsMo): # ||:cls:||
"""Satoku Matrix.
:param problem: problem to be mapped. Default: self.problem.
:param with_variables: also map variables. Default: do not map
variables.
:param no_conflicts: do not map conflicts. Default: map
conflicts.
:param delay_zero_updates: delay mirror cell zero changes
conflicts. Default: set mirrored zero changes immediately.
>>> pr = Problem(TEST_PROBLEM_NOCFL).split()
>>> sm = SatokuMatrix(None)
.. >>> printf(sm.definitionv())
**Map Problem Without Variables**
>>> ign = sm.map_problem(pr, with_variables=False, no_conflicts=True)
**Check Regions**
>>> printf(dump_regions(sm.regions))
r0: 0, 6 / r1: 6, 0 / r2: 6, 0
>>> region = sm.regions[-3] # the one before variables
>>> region2 = sm.add_region(at=-2) # add before variables
>>> region.size -= 1
>>> region2.ofs -= 1
>>> region2.size += 1
>>> printf(dump_regions(sm.regions))
r0: 0, 5 / r1: 5, 1 / r2: 6, 0 / r3: 6, 0
**Manually Set Conflicts**
.. \\|:here:|
>>> ign = sm.zero_change(1, 1, 0, 2)
>>> ign = sm.zero_change(2, 0, 0, 1, True)
>>> ign = sm.dump(immediate=True)
// | || P || | || _ _ _ | _ _ _ | _ _ _ | _ _ _ | _ _ _ || _ _ _ |
// +-------+-----++-+-++-------+-------+-------+-------+-------++-------+
// +-------+-----++-+-++-------+-------+-------+-------+-------++-------+
// | 0 | 0 || | || 1 * * | _ _ _ | _ _ _ | _ _ _ | _ _ _ || _ _ _ |
// | | 1 || | || * 1 * | _ _ _ | 0 _ _ | _ _ _ | _ _ _ || _ _ _ |
// | | 2 || | || * * 1 | _ _ _ | _ _ _ | _ _ _ | _ _ _ || _ _ _ |
// +-------+-----++-+-++-------+-------+-------+-------+-------++-------+
// | 1 | 0 || | || _ _ _ | 1 * * | _ _ _ | _ _ _ | _ _ _ || _ _ _ |
// | | 1 || | || _ _ 0 | * 1 * | _ _ _ | _ _ _ | _ _ _ || _ _ _ |
// | | 2 || | || _ _ _ | * * 1 | _ _ _ | _ _ _ | _ _ _ || _ _ _ |
// +-------+-----++-+-++-------+-------+-------+-------+-------++-------+
// | 2 | 0 || | || _ 0 _ | _ _ _ | 1 * * | _ _ _ | _ _ _ || _ _ _ |
// | | 1 || | || _ _ _ | _ _ _ | * 1 * | _ _ _ | _ _ _ || _ _ _ |
// | | 2 || | || _ _ _ | _ _ _ | * * 1 | _ _ _ | _ _ _ || _ _ _ |
// +-------+-----++-+-++-------+-------+-------+-------+-------++-------+
// | 3 | 0 || | || _ _ _ | _ _ _ | _ _ _ | 1 * * | _ _ _ || _ _ _ |
// | | 1 || | || _ _ _ | _ _ _ | _ _ _ | * 1 * | _ _ _ || _ _ _ |
// | | 2 || | || _ _ _ | _ _ _ | _ _ _ | * * 1 | _ _ _ || _ _ _ |
// +-------+-----++-+-++-------+-------+-------+-------+-------++-------+
// | 4 | 0 || | || _ _ _ | _ _ _ | _ _ _ | _ _ _ | 1 * * || _ _ _ |
// | | 1 || | || _ _ _ | _ _ _ | _ _ _ | _ _ _ | * 1 * || _ _ _ |
// | | 2 || | || _ _ _ | _ _ _ | _ _ _ | _ _ _ | * * 1 || _ _ _ |
// +-------+-----++-+-++-------+-------+-------+-------+-------++-------+
// +-------+-----++-+-++-------+-------+-------+-------+-------++-------+
// | 5 | 0 || | || _ _ _ | _ _ _ | _ _ _ | _ _ _ | _ _ _ || 1 * * |
// | | 1 || | || _ _ _ | _ _ _ | _ _ _ | _ _ _ | _ _ _ || * 1 * |
// | | 2 || | || _ _ _ | _ _ _ | _ _ _ | _ _ _ | _ _ _ || * * 1 |
// +-------+-----++-+-++-------+-------+-------+-------+-------++-------+
**Update Pending Zero Changes**
>>> ign = sm.update_zeroes()
>>> ign = sm.dump(immediate=True)
// | || P || | || _ _ _ | _ _ _ | _ _ _ | _ _ _ | _ _ _ || _ _ _ |
// +-------+-----++-+-++-------+-------+-------+-------+-------++-------+
// +-------+-----++-+-++-------+-------+-------+-------+-------++-------+
// | 0 | 0 || | || 1 * * | _ _ _ | _ _ _ | _ _ _ | _ _ _ || _ _ _ |
// | | 1 || | || * 1 * | _ _ _ | 0 _ _ | _ _ _ | _ _ _ || _ _ _ |
// | | 2 || | || * * 1 | _ 0 _ | _ _ _ | _ _ _ | _ _ _ || _ _ _ |
// +-------+-----++-+-++-------+-------+-------+-------+-------++-------+
// | 1 | 0 || | || _ _ _ | 1 * * | _ _ _ | _ _ _ | _ _ _ || _ _ _ |
// | | 1 || | || _ _ 0 | * 1 * | _ _ _ | _ _ _ | _ _ _ || _ _ _ |
// | | 2 || | || _ _ _ | * * 1 | _ _ _ | _ _ _ | _ _ _ || _ _ _ |
// +-------+-----++-+-++-------+-------+-------+-------+-------++-------+
// | 2 | 0 || | || _ 0 _ | _ _ _ | 1 * * | _ _ _ | _ _ _ || _ _ _ |
// | | 1 || | || _ _ _ | _ _ _ | * 1 * | _ _ _ | _ _ _ || _ _ _ |
// | | 2 || | || _ _ _ | _ _ _ | * * 1 | _ _ _ | _ _ _ || _ _ _ |
// +-------+-----++-+-++-------+-------+-------+-------+-------++-------+
// | 3 | 0 || | || _ _ _ | _ _ _ | _ _ _ | 1 * * | _ _ _ || _ _ _ |
// | | 1 || | || _ _ _ | _ _ _ | _ _ _ | * 1 * | _ _ _ || _ _ _ |
// | | 2 || | || _ _ _ | _ _ _ | _ _ _ | * * 1 | _ _ _ || _ _ _ |
// +-------+-----++-+-++-------+-------+-------+-------+-------++-------+
// | 4 | 0 || | || _ _ _ | _ _ _ | _ _ _ | _ _ _ | 1 * * || _ _ _ |
// | | 1 || | || _ _ _ | _ _ _ | _ _ _ | _ _ _ | * 1 * || _ _ _ |
// | | 2 || | || _ _ _ | _ _ _ | _ _ _ | _ _ _ | * * 1 || _ _ _ |
// +-------+-----++-+-++-------+-------+-------+-------+-------++-------+
// +-------+-----++-+-++-------+-------+-------+-------+-------++-------+
// | 5 | 0 || | || _ _ _ | _ _ _ | _ _ _ | _ _ _ | _ _ _ || 1 * * |
// | | 1 || | || _ _ _ | _ _ _ | _ _ _ | _ _ _ | _ _ _ || * 1 * |
// | | 2 || | || _ _ _ | _ _ _ | _ _ _ | _ _ _ | _ _ _ || * * 1 |
// +-------+-----++-+-++-------+-------+-------+-------+-------++-------+
**Slowly Kill Row s[2, 0]**
>>> ign = sm.zero_change(2, 0, 0, 0)
>>> ign = sm.zero_change(2, 0, 0, 2)
>>> ign = sm.update_zeroes()
>>> ign = sm.dump(immediate=True)
// | || P || | || _ _ _ | _ _ _ | 0 _ _ | _ _ _ | _ _ _ || _ _ _ |
// +-------+-----++-+-++-------+-------+-------+-------+-------++-------+
// +-------+-----++-+-++-------+-------+-------+-------+-------++-------+
// | 0 | 0 || | || 1 * * | _ _ _ | 0 _ _ | _ _ _ | _ _ _ || _ _ _ |
// | | 1 || | || * 1 * | _ _ _ | 0 _ _ | _ _ _ | _ _ _ || _ _ _ |
// | | 2 || | || * * 1 | _ 0 _ | 0 _ _ | _ _ _ | _ _ _ || _ _ _ |
// +-------+-----++-+-++-------+-------+-------+-------+-------++-------+
// | 1 | 0 || | || _ _ _ | 1 * * | 0 _ _ | _ _ _ | _ _ _ || _ _ _ |
// | | 1 || | || _ _ 0 | * 1 * | 0 _ _ | _ _ _ | _ _ _ || _ _ _ |
// | | 2 || | || _ _ _ | * * 1 | 0 _ _ | _ _ _ | _ _ _ || _ _ _ |
// +-------+-----++-+-++-------+-------+-------+-------+-------++-------+
// | 2 | 0 || | || 0 0 0 | 0 0 0 | 1 * * | 0 0 0 | 0 0 0 || 0 0 0 |
// | | 1 || | || _ _ _ | _ _ _ | * 1 * | _ _ _ | _ _ _ || _ _ _ |
// | | 2 || | || _ _ _ | _ _ _ | * * 1 | _ _ _ | _ _ _ || _ _ _ |
// +-------+-----++-+-++-------+-------+-------+-------+-------++-------+
// | 3 | 0 || | || _ _ _ | _ _ _ | 0 _ _ | 1 * * | _ _ _ || _ _ _ |
// | | 1 || | || _ _ _ | _ _ _ | 0 _ _ | * 1 * | _ _ _ || _ _ _ |
// | | 2 || | || _ _ _ | _ _ _ | 0 _ _ | * * 1 | _ _ _ || _ _ _ |
// +-------+-----++-+-++-------+-------+-------+-------+-------++-------+
// | 4 | 0 || | || _ _ _ | _ _ _ | 0 _ _ | _ _ _ | 1 * * || _ _ _ |
// | | 1 || | || _ _ _ | _ _ _ | 0 _ _ | _ _ _ | * 1 * || _ _ _ |
// | | 2 || | || _ _ _ | _ _ _ | 0 _ _ | _ _ _ | * * 1 || _ _ _ |
// +-------+-----++-+-++-------+-------+-------+-------+-------++-------+
// +-------+-----++-+-++-------+-------+-------+-------+-------++-------+
// | 5 | 0 || | || _ _ _ | _ _ _ | 0 _ _ | _ _ _ | _ _ _ || 1 * * |
// | | 1 || | || _ _ _ | _ _ _ | 0 _ _ | _ _ _ | _ _ _ || * 1 * |
// | | 2 || | || _ _ _ | _ _ _ | 0 _ _ | _ _ _ | _ _ _ || * * 1 |
// +-------+-----++-+-++-------+-------+-------+-------+-------++-------+
**Make Problem Unsatisfiable**
>>> ign = sm.kill_row(2, 1)
>>> ign = sm.kill_row(2, 2) #doctest: +ELLIPSIS
Traceback (most recent call last):
...
SatokuUnsatisfied: UNSAT s(2, 2)
>>> ign = sm.dump(immediate=True)
// | || X || | || _ _ _ | _ _ _ | 0 0 0 | _ _ _ | _ _ _ || _ _ _ |
// +-------+-----++-+-++-------+-------+-------+-------+-------++-------+
// +-------+-----++-+-++-------+-------+-------+-------+-------++-------+
// | 0 | 0 || | || 1 * * | _ _ _ | 0 0 0 | _ _ _ | _ _ _ || _ _ _ |
// | | 1 || | || * 1 * | _ _ _ | 0 0 0 | _ _ _ | _ _ _ || _ _ _ |
// | | 2 || | || * * 1 | _ 0 _ | 0 0 0 | _ _ _ | _ _ _ || _ _ _ |
// +-------+-----++-+-++-------+-------+-------+-------+-------++-------+
// | 1 | 0 || | || _ _ _ | 1 * * | 0 0 0 | _ _ _ | _ _ _ || _ _ _ |
// | | 1 || | || _ _ 0 | * 1 * | 0 0 0 | _ _ _ | _ _ _ || _ _ _ |
// | | 2 || | || _ _ _ | * * 1 | 0 0 0 | _ _ _ | _ _ _ || _ _ _ |
// +-------+-----++-+-++-------+-------+-------+-------+-------++-------+
// | 2 | 0 || | || 0 0 0 | 0 0 0 | 1 * * | 0 0 0 | 0 0 0 || 0 0 0 |
// | | 1 || | || 0 0 0 | 0 0 0 | * 1 * | 0 0 0 | 0 0 0 || 0 0 0 |
// | | 2 || | || 0 0 0 | 0 0 0 | * * 1 | 0 0 0 | 0 0 0 || 0 0 0 |
// +-------+-----++-+-++-------+-------+-------+-------+-------++-------+
// | 3 | 0 || | || _ _ _ | _ _ _ | 0 0 0 | 1 * * | _ _ _ || _ _ _ |
// | | 1 || | || _ _ _ | _ _ _ | 0 0 0 | * 1 * | _ _ _ || _ _ _ |
// | | 2 || | || _ _ _ | _ _ _ | 0 0 0 | * * 1 | _ _ _ || _ _ _ |
// +-------+-----++-+-++-------+-------+-------+-------+-------++-------+
// | 4 | 0 || | || _ _ _ | _ _ _ | 0 0 0 | _ _ _ | 1 * * || _ _ _ |
// | | 1 || | || _ _ _ | _ _ _ | 0 0 0 | _ _ _ | * 1 * || _ _ _ |
// | | 2 || | || _ _ _ | _ _ _ | 0 0 0 | _ _ _ | * * 1 || _ _ _ |
// +-------+-----++-+-++-------+-------+-------+-------+-------++-------+
// +-------+-----++-+-++-------+-------+-------+-------+-------++-------+
// | 5 | 0 || | || _ _ _ | _ _ _ | 0 0 0 | _ _ _ | _ _ _ || 1 * * |
// | | 1 || | || _ _ _ | _ _ _ | 0 0 0 | _ _ _ | _ _ _ || * 1 * |
// | | 2 || | || _ _ _ | _ _ _ | 0 0 0 | _ _ _ | _ _ _ || * * 1 |
// +-------+-----++-+-++-------+-------+-------+-------+-------++-------+
**Problem With Variables**
Problem::
((a ∧ d) ∨ (¬a ∧ b) ∨ (¬a ∧ ¬b ∧ c)) ∧
( a ∨ ¬b ∨ c) ∧
(¬a ∨ b ∨ ¬c) ∧
( b ∨ ¬c ∨ d) ∧
(¬c ∨ d ∨ e) ∧
(¬b ∨ (b ∧ d) ∨ (b ∧ ¬d ∧ ¬e))
>>> pr = Problem(TEST_PROBLEM).split()
>>> printf(str(pr) + '\\n a b c d e')
[
[ 1 _ _ 0 _ ]
[ 0 1 _ _ _ ]
[ 0 0 1 _ _ ]
]
[
[ 1 _ _ _ _ ]
[ _ 0 _ _ _ ]
[ _ _ 1 _ _ ]
]
[
[ 0 _ _ _ _ ]
[ _ 1 _ _ _ ]
[ _ _ 0 _ _ ]
]
[
[ _ 1 _ _ ]
[ _ _ 0 _ ]
[ _ _ _ 1 ]
]
[
[ _ _ 0 _ _ ]
[ _ _ _ 1 _ ]
[ _ _ _ _ 1 ]
]
[
[ _ 0 _ _ _ ]
[ _ 1 _ 1 _ ]
[ _ 1 _ 0 0 ]
]
a b c d e
**Map Problem**
>>> sm = SatokuMatrix(None)
>>> ign = sm.map_problem(pr, with_variables=True)
.. \\|:here:|
>>> ign = sm.dump(immediate=True)
// | || P || | || _ _ _ | _ _ _ | _ _ _ | _ _ _ | _ _ _ | _ _ _ || _ _ | _ _ | _ _ | _ _ | _ _ |
// +-------+-----++-+-++-------+-------+-------+-------+-------+-------++-----+-----+-----+-----+-----+
// +-------+-----++-+-++-------+-------+-------+-------+-------+-------++-----+-----+-----+-----+-----+
// | 0 | 0 || | || 1 * * | _ _ _ | 0 _ _ | _ _ 0 | _ 0 _ | _ 0 _ || _ 0 | _ _ | _ _ | 0 _ | _ _ |
// | | 1 || | || * 1 * | 0 0 _ | _ _ _ | _ _ _ | _ _ _ | 0 _ _ || 0 _ | _ 0 | _ _ | _ _ | _ _ |
// | | 2 || | || * * 1 | 0 _ _ | _ 0 0 | 0 0 _ | 0 _ _ | _ 0 0 || 0 _ | 0 _ | _ 0 | _ _ | _ _ |
// +-------+-----++-+-++-------+-------+-------+-------+-------+-------++-----+-----+-----+-----+-----+
// | 1 | 0 || | || _ 0 0 | 1 * * | 0 _ _ | _ _ _ | _ _ _ | _ _ _ || _ 0 | _ _ | _ _ | _ _ | _ _ |
// | | 1 || | || _ 0 _ | * 1 * | _ 0 _ | 0 _ _ | _ _ _ | _ 0 0 || _ _ | 0 _ | _ _ | _ _ | _ _ |
// | | 2 || | || _ _ _ | * * 1 | _ _ 0 | _ 0 _ | 0 _ _ | _ _ _ || _ _ | _ _ | _ 0 | _ _ | _ _ |
// +-------+-----++-+-++-------+-------+-------+-------+-------+-------++-----+-----+-----+-----+-----+
// | 2 | 0 || | || 0 _ _ | 0 _ _ | 1 * * | _ _ _ | _ _ _ | _ _ _ || 0 _ | _ _ | _ _ | _ _ | _ _ |
// | | 1 || | || _ _ 0 | _ 0 _ | * 1 * | _ _ _ | _ _ _ | 0 _ _ || _ _ | _ 0 | _ _ | _ _ | _ _ |
// | | 2 || | || _ _ 0 | _ _ 0 | * * 1 | _ _ _ | _ _ _ | _ _ _ || _ _ | _ _ | 0 _ | _ _ | _ _ |
// +-------+-----++-+-++-------+-------+-------+-------+-------+-------++-----+-----+-----+-----+-----+
// | 3 | 0 || | || _ _ 0 | _ 0 _ | _ _ _ | 1 * * | _ _ _ | 0 _ _ || _ _ | _ 0 | _ _ | _ _ | _ _ |
// | | 1 || | || _ _ 0 | _ _ 0 | _ _ _ | * 1 * | _ _ _ | _ _ _ || _ _ | _ _ | 0 _ | _ _ | _ _ |
// | | 2 || | || 0 _ _ | _ _ _ | _ _ _ | * * 1 | _ _ _ | _ _ 0 || _ _ | _ _ | _ _ | _ 0 | _ _ |
// +-------+-----++-+-++-------+-------+-------+-------+-------+-------++-----+-----+-----+-----+-----+
// | 4 | 0 || | || _ _ 0 | _ _ 0 | _ _ _ | _ _ _ | 1 * * | _ _ _ || _ _ | _ _ | 0 _ | _ _ | _ _ |
// | | 1 || | || 0 _ _ | _ _ _ | _ _ _ | _ _ _ | * 1 * | _ _ 0 || _ _ | _ _ | _ _ | _ 0 | _ _ |
// | | 2 || | || _ _ _ | _ _ _ | _ _ _ | _ _ _ | * * 1 | _ _ 0 || _ _ | _ _ | _ _ | _ _ | _ 0 |
// +-------+-----++-+-++-------+-------+-------+-------+-------+-------++-----+-----+-----+-----+-----+
// | 5 | 0 || | || _ 0 _ | _ _ _ | _ 0 _ | 0 _ _ | _ _ _ | 1 * * || _ _ | 0 _ | _ _ | _ _ | _ _ |
// | | 1 || | || 0 _ 0 | _ 0 _ | _ _ _ | _ _ _ | _ _ _ | * 1 * || _ _ | _ 0 | _ _ | _ 0 | _ _ |
// | | 2 || | || _ _ 0 | _ 0 _ | _ _ _ | _ _ 0 | _ 0 0 | * * 1 || _ _ | _ 0 | _ _ | 0 _ | 0 _ |
// +-------+-----++-+-++-------+-------+-------+-------+-------+-------++-----+-----+-----+-----+-----+
// +-------+-----++-+-++-------+-------+-------+-------+-------+-------++-----+-----+-----+-----+-----+
// | 6 | 0 || | || _ 0 0 | _ _ _ | 0 _ _ | _ _ _ | _ _ _ | _ _ _ || 1 * | _ _ | _ _ | _ _ | _ _ |
// | | 1 || | || 0 _ _ | 0 _ _ | _ _ _ | _ _ _ | _ _ _ | _ _ _ || * 1 | _ _ | _ _ | _ _ | _ _ |
// +-------+-----++-+-++-------+-------+-------+-------+-------+-------++-----+-----+-----+-----+-----+
// | 7 | 0 || | || _ _ 0 | _ 0 _ | _ _ _ | _ _ _ | _ _ _ | 0 _ _ || _ _ | 1 * | _ _ | _ _ | _ _ |
// | | 1 || | || _ 0 _ | _ _ _ | _ 0 _ | 0 _ _ | _ _ _ | _ 0 0 || _ _ | * 1 | _ _ | _ _ | _ _ |
// +-------+-----++-+-++-------+-------+-------+-------+-------+-------++-----+-----+-----+-----+-----+
// | 8 | 0 || | || _ _ _ | _ _ _ | _ _ 0 | _ 0 _ | 0 _ _ | _ _ _ || _ _ | _ _ | 1 * | _ _ | _ _ |
// | | 1 || | || _ _ 0 | _ _ 0 | _ _ _ | _ _ _ | _ _ _ | _ _ _ || _ _ | _ _ | * 1 | _ _ | _ _ |
// +-------+-----++-+-++-------+-------+-------+-------+-------+-------++-----+-----+-----+-----+-----+
// | 9 | 0 || | || 0 _ _ | _ _ _ | _ _ _ | _ _ _ | _ _ _ | _ _ 0 || _ _ | _ _ | _ _ | 1 * | _ _ |
// | | 1 || | || _ _ _ | _ _ _ | _ _ _ | _ _ 0 | _ 0 _ | _ 0 _ || _ _ | _ _ | _ _ | * 1 | _ _ |
// +-------+-----++-+-++-------+-------+-------+-------+-------+-------++-----+-----+-----+-----+-----+
// | 10 | 0 || | || _ _ _ | _ _ _ | _ _ _ | _ _ _ | _ _ _ | _ _ 0 || _ _ | _ _ | _ _ | _ _ | 1 * |
// | | 1 || | || _ _ _ | _ _ _ | _ _ _ | _ _ _ | _ _ 0 | _ _ _ || _ _ | _ _ | _ _ | _ _ | * 1 |
// +-------+-----++-+-++-------+-------+-------+-------+-------+-------++-----+-----+-----+-----+-----+
>>> printf(sm.dump_stats())
// ======================== ====
// Satoku Statistics
// ======================== ====
// satisfiable True
// init clauses 6
// init variables 5
// init synthesized 0
// init rows 28
// clauses 6
// variables 5
// synthesized 0
// rows 28
// cells 784
// clauses deleted 0
// rows deleted 0
// row kills 0
// duplicate kills 0
// zero changes 106
// soft changes 0
// zero update passes 0
// row update passes 0
// superset update passes 0
// zero updates 0
// row updates 0
// superset updates 0
// max zero updates 0
// max row updates 0
// max superset updates 0
// pending zero updates 0
// pending row updates 20
// pending superset updates 0
// row checks 0
// row merges 0
// state combines 0
// cell combines 0
// message
// ======================== ====
**Update Rows**
>>> ign = sm.update_zeroes()
>>> ign = sm.update_rows()
.. \\|:here:|
>>> ign = sm.dump(immediate=True)
// | || P || | || _ _ _ | _ _ _ | _ _ _ | _ _ _ | _ _ _ | _ _ _ || _ _ | _ _ | _ _ | _ _ | _ _ |
// +-------+-----++-+-++-------+-------+-------+-------+-------+-------++-----+-----+-----+-----+-----+
// +-------+-----++-+-++-------+-------+-------+-------+-------+-------++-----+-----+-----+-----+-----+
// | 0 | 0 || | || 1 * * | _ _ _ | 0 _ _ | _ _ 0 | _ 0 _ | _ 0 _ || 1 0 | _ _ | _ _ | 0 1 | _ _ |
// | | 1 || | || * 1 * | 0 0 1 | _ _ 0 | _ 0 _ | 0 _ _ | 0 1 0 || 0 1 | 1 0 | 1 0 | 1 0 | _ _ |
// | | 2 || | || * * 1 | 0 _ _ | 1 0 0 | 0 0 1 | 0 _ _ | 1 0 0 || 0 1 | 0 1 | 1 0 | 1 0 | _ _ |
// +-------+-----++-+-++-------+-------+-------+-------+-------+-------++-----+-----+-----+-----+-----+
// | 1 | 0 || | || 1 0 0 | 1 * * | 0 _ _ | _ _ 0 | _ 0 _ | _ 0 _ || 1 0 | _ _ | _ _ | 0 1 | _ _ |
// | | 1 || | || _ 0 _ | * 1 * | _ 0 _ | 0 _ _ | _ _ _ | 1 0 0 || _ _ | 0 1 | _ _ | _ _ | _ _ |
// | | 2 || | || _ _ _ | * * 1 | _ _ 0 | _ 0 _ | 0 _ _ | _ _ 0 || _ _ | _ _ | 1 0 | _ _ | _ _ |
// +-------+-----++-+-++-------+-------+-------+-------+-------+-------++-----+-----+-----+-----+-----+
// | 2 | 0 || | || 0 _ _ | 0 _ _ | 1 * * | _ 0 _ | 0 _ _ | _ _ 0 || 0 1 | _ _ | 1 0 | 1 0 | _ _ |
// | | 1 || | || _ _ 0 | _ 0 _ | * 1 * | _ _ _ | _ _ _ | 0 _ _ || _ _ | 1 0 | _ _ | _ _ | _ _ |
// | | 2 || | || 1 0 0 | _ _ 0 | * * 1 | _ _ 0 | _ 0 _ | _ 0 _ || 1 0 | _ _ | 0 1 | 0 1 | _ _ |
// +-------+-----++-+-++-------+-------+-------+-------+-------+-------++-----+-----+-----+-----+-----+
// | 3 | 0 || | || _ _ 0 | _ 0 _ | _ _ _ | 1 * * | _ _ _ | 0 _ _ || _ _ | 1 0 | _ _ | _ _ | _ _ |
// | | 1 || | || 1 0 0 | _ _ 0 | 0 _ _ | * 1 * | _ 0 _ | _ 0 _ || 1 0 | _ _ | 0 1 | 0 1 | _ _ |
// | | 2 || | || 0 _ _ | 0 _ _ | _ _ 0 | * * 1 | 0 _ _ | _ _ 0 || 0 1 | _ _ | 1 0 | 1 0 | _ _ |
// +-------+-----++-+-++-------+-------+-------+-------+-------+-------++-----+-----+-----+-----+-----+
// | 4 | 0 || | || 1 0 0 | _ _ 0 | 0 _ _ | _ _ 0 | 1 * * | _ 0 _ || 1 0 | _ _ | 0 1 | 0 1 | _ _ |
// | | 1 || | || 0 _ _ | 0 _ _ | _ _ 0 | _ 0 _ | * 1 * | _ _ 0 || 0 1 | _ _ | 1 0 | 1 0 | _ _ |
// | | 2 || | || _ _ _ | _ _ _ | _ _ _ | _ _ _ | * * 1 | _ _ 0 || _ _ | _ _ | _ _ | _ _ | 1 0 |
// +-------+-----++-+-++-------+-------+-------+-------+-------+-------++-----+-----+-----+-----+-----+
// | 5 | 0 || | || _ 0 _ | _ _ _ | _ 0 _ | 0 _ _ | _ _ _ | 1 * * || _ _ | 0 1 | _ _ | _ _ | _ _ |
// | | 1 || | || 0 1 0 | 0 0 1 | _ _ 0 | _ 0 _ | 0 _ _ | * 1 * || 0 1 | 1 0 | 1 0 | 1 0 | _ _ |
// | | 2 || | || 1 0 0 | 1 0 0 | 0 _ _ | _ _ 0 | 1 0 0 | * * 1 || 1 0 | 1 0 | 0 1 | 0 1 | 0 1 |
// +-------+-----++-+-++-------+-------+-------+-------+-------+-------++-----+-----+-----+-----+-----+
// +-------+-----++-+-++-------+-------+-------+-------+-------+-------++-----+-----+-----+-----+-----+
// | 6 | 0 || | || 1 0 0 | _ _ _ | 0 _ _ | _ _ 0 | _ 0 _ | _ 0 _ || 1 * | _ _ | _ _ | 0 1 | _ _ |
// | | 1 || | || 0 _ _ | 0 _ _ | _ _ 0 | _ 0 _ | 0 _ _ | _ _ 0 || * 1 | _ _ | 1 0 | 1 0 | _ _ |
// +-------+-----++-+-++-------+-------+-------+-------+-------+-------++-----+-----+-----+-----+-----+
// | 7 | 0 || | || _ _ 0 | _ 0 _ | _ _ _ | _ _ _ | _ _ _ | 0 _ _ || _ _ | 1 * | _ _ | _ _ | _ _ |
// | | 1 || | || _ 0 _ | _ _ _ | _ 0 _ | 0 _ _ | _ _ _ | 1 0 0 || _ _ | * 1 | _ _ | _ _ | _ _ |
// +-------+-----++-+-++-------+-------+-------+-------+-------+-------++-----+-----+-----+-----+-----+
// | 8 | 0 || | || _ _ _ | _ _ _ | _ _ 0 | _ 0 _ | 0 _ _ | _ _ 0 || _ _ | _ _ | 1 * | _ _ | _ _ |
// | | 1 || | || 1 0 0 | _ _ 0 | 0 _ _ | _ _ 0 | _ 0 _ | _ 0 _ || 1 0 | _ _ | * 1 | 0 1 | _ _ |
// +-------+-----++-+-++-------+-------+-------+-------+-------+-------++-----+-----+-----+-----+-----+
// | 9 | 0 || | || 0 _ _ | 0 _ _ | _ _ 0 | _ 0 _ | 0 _ _ | _ _ 0 || 0 1 | _ _ | 1 0 | 1 * | _ _ |
// | | 1 || | || 1 0 0 | _ _ _ | 0 _ _ | _ _ 0 | _ 0 _ | _ 0 _ || 1 0 | _ _ | _ _ | * 1 | _ _ |
// +-------+-----++-+-++-------+-------+-------+-------+-------+-------++-----+-----+-----+-----+-----+
// | 10 | 0 || | || _ _ _ | _ _ _ | _ _ _ | _ _ _ | _ _ _ | _ _ 0 || _ _ | _ _ | _ _ | _ _ | 1 * |
// | | 1 || | || _ _ _ | _ _ _ | _ _ _ | _ _ _ | _ _ 0 | _ _ _ || _ _ | _ _ | _ _ | _ _ | * 1 |
// +-------+-----++-+-++-------+-------+-------+-------+-------+-------++-----+-----+-----+-----+-----+
>>> printf(sm.dump_stats())
// ======================== ====
// Satoku Statistics
// ======================== ====
// satisfiable True
// init clauses 6
// init variables 5
// init synthesized 0
// init rows 28
// clauses 6
// variables 5
// synthesized 0
// rows 28
// cells 784
// clauses deleted 0
// rows deleted 0
// row kills 0
// duplicate kills 0
// zero changes 190
// soft changes 47
// zero update passes 0
// row update passes 4
// superset update passes 3
// zero updates 0
// row updates 53
// superset updates 19
// max zero updates 0
// max row updates 20
// max superset updates 16
// pending zero updates 0
// pending row updates 0
// pending superset updates 0
// row checks 107
// row merges 97
// state combines 0
// cell combines 0
// message
// ======================== ====
.. \\|:here:|
**Maximize Conflicts**
>>> pr = Problem(TEST_PROBLEM).max_conflicts()
>>> printf(str(pr) + '\\n a b c d e')
[
[ 1 _ _ 0 _ ]
[ 0 1 _ _ _ ]
[ 0 0 1 _ _ ]
]
[
[ 1 _ _ _ _ ]
[ 0 0 _ _ _ ]
[ 0 1 1 _ _ ]
]
[
[ 0 _ _ _ _ ]
[ 1 1 _ _ _ ]
[ 1 0 0 _ _ ]
]
[
[ _ 1 _ _ ]
[ _ 0 0 _ ]
[ _ 0 1 1 ]
]
[
[ _ _ 0 _ _ ]
[ _ _ 1 1 _ ]
[ _ _ 1 0 1 ]
]
[
[ _ 0 _ _ _ ]
[ _ 1 _ 1 _ ]
[ _ 1 _ 0 0 ]
]
a b c d e
>>> sm = SatokuMatrix(None)
>>> ign = sm.map_problem(pr, with_variables=True)
>>> ign = sm.update_rows()
>>> sm.dump_bound()
.. >>> sm.dump_minor_ccrs()
>>> ign = sm.dump(immediate=True)
// | || P || | || _ _ _ | _ _ _ | _ _ _ | _ _ _ | _ _ 0 | _ _ _ || _ _ | _ _ | _ _ | _ _ | _ _ |
// +-------+-----++-+-++-------+-------+-------+-------+-------+-------++-----+-----+-----+-----+-----+
// +-------+-----++-+-++-------+-------+-------+-------+-------+-------++-----+-----+-----+-----+-----+
// | 0 | 0 || | || 1 * * | 1 0 0 | 0 _ _ | _ _ 0 | 1 0 0 | _ 0 _ || 1 0 | _ _ | 0 1 | 0 1 | _ _ |
// | | 1 || | || * 1 * | 0 0 1 | 1 0 0 | 1 0 0 | 0 1 0 | 0 1 0 || 0 1 | 1 0 | 1 0 | 1 0 | _ _ |
// | | 2 || | || * * 1 | 0 1 0 | 1 0 0 | 0 0 1 | 0 1 0 | 1 0 0 || 0 1 | 0 1 | 1 0 | 1 0 | _ _ |
// +-------+-----++-+-++-------+-------+-------+-------+-------+-------++-----+-----+-----+-----+-----+
// | 1 | 0 || | || 1 0 0 | 1 * * | 0 _ _ | _ _ 0 | 1 0 0 | _ 0 _ || 1 0 | _ _ | 0 1 | 0 1 | _ _ |
// | | 1 || | || 0 0 1 | * 1 * | 1 0 0 | 0 0 1 | 0 1 0 | 1 0 0 || 0 1 | 0 1 | 1 0 | 1 0 | _ _ |
// | | 2 || | || 0 1 0 | * * 1 | 1 0 0 | 1 0 0 | 0 1 0 | 0 1 0 || 0 1 | 1 0 | 1 0 | 1 0 | _ _ |
// +-------+-----++-+-++-------+-------+-------+-------+-------+-------++-----+-----+-----+-----+-----+
// | 2 | 0 || | || 0 _ _ | 0 _ _ | 1 * * | _ 0 _ | 0 1 0 | _ _ 0 || 0 1 | _ _ | 1 0 | 1 0 | _ _ |
// | | 1 || | || 1 0 0 | 1 0 0 | * 1 * | 1 0 0 | 1 0 0 | 0 0 1 || 1 0 | 1 0 | 0 1 | 0 1 | 0 1 |
// | | 2 || | || 1 0 0 | 1 0 0 | * * 1 | 0 1 0 | 1 0 0 | 1 0 0 || 1 0 | 0 1 | 0 1 | 0 1 | _ _ |
// +-------+-----++-+-++-------+-------+-------+-------+-------+-------++-----+-----+-----+-----+-----+
// | 3 | 0 || | || _ _ 0 | _ 0 _ | _ _ 0 | 1 * * | _ _ 0 | 0 _ _ || _ _ | 1 0 | _ _ | _ _ | _ _ |
// | | 1 || | || 1 0 0 | 1 0 0 | 0 0 1 | * 1 * | 1 0 0 | 1 0 0 || 1 0 | 0 1 | 0 1 | 0 1 | _ _ |
// | | 2 || | || 0 0 1 | 0 1 0 | 1 0 0 | * * 1 | 0 1 0 | 1 0 0 || 0 1 | 0 1 | 1 0 | 1 0 | _ _ |
// +-------+-----++-+-++-------+-------+-------+-------+-------+-------++-----+-----+-----+-----+-----+
// | 4 | 0 || | || 1 0 0 | 1 0 0 | 0 _ _ | _ _ 0 | 1 * * | _ 0 _ || 1 0 | _ _ | 0 1 | 0 1 | _ _ |
// | | 1 || | || 0 _ _ | 0 _ _ | 1 0 0 | _ 0 _ | * 1 * | _ _ 0 || 0 1 | _ _ | 1 0 | 1 0 | _ _ |
// | | 2 || | || 0 0 0 | 0 0 0 | 0 0 0 | 0 0 0 | * * 1 | 0 0 0 || 0 0 | 0 0 | 0 0 | 0 0 | 0 0 |
// +-------+-----++-+-++-------+-------+-------+-------+-------+-------++-----+-----+-----+-----+-----+
// | 5 | 0 || | || _ 0 _ | _ _ 0 | _ 0 _ | 0 _ _ | _ _ 0 | 1 * * || _ _ | 0 1 | _ _ | _ _ | _ _ |
// | | 1 || | || 0 1 0 | 0 0 1 | 1 0 0 | 1 0 0 | 0 1 0 | * 1 * || 0 1 | 1 0 | 1 0 | 1 0 | _ _ |
// | | 2 || | || 1 0 0 | 1 0 0 | 0 1 0 | 1 0 0 | 1 0 0 | * * 1 || 1 0 | 1 0 | 0 1 | 0 1 | 0 1 |
// +-------+-----++-+-++-------+-------+-------+-------+-------+-------++-----+-----+-----+-----+-----+
// +-------+-----++-+-++-------+-------+-------+-------+-------+-------++-----+-----+-----+-----+-----+
// | 6 | 0 || | || 1 0 0 | 1 0 0 | 0 _ _ | _ _ 0 | 1 0 0 | _ 0 _ || 1 * | _ _ | 0 1 | 0 1 | _ _ |
// | | 1 || | || 0 _ _ | 0 _ _ | 1 0 0 | _ 0 _ | 0 1 0 | _ _ 0 || * 1 | _ _ | 1 0 | 1 0 | _ _ |
// +-------+-----++-+-++-------+-------+-------+-------+-------+-------++-----+-----+-----+-----+-----+
// | 7 | 0 || | || _ _ 0 | _ 0 _ | _ _ 0 | 1 0 0 | _ _ 0 | 0 _ _ || _ _ | 1 * | _ _ | _ _ | _ _ |
// | | 1 || | || _ 0 _ | _ _ 0 | _ 0 _ | 0 _ _ | _ _ 0 | 1 0 0 || _ _ | * 1 | _ _ | _ _ | _ _ |
// +-------+-----++-+-++-------+-------+-------+-------+-------+-------++-----+-----+-----+-----+-----+
// | 8 | 0 || | || 0 _ _ | 0 _ _ | 1 0 0 | _ 0 _ | 0 1 0 | _ _ 0 || 0 1 | _ _ | 1 * | 1 0 | _ _ |
// | | 1 || | || 1 0 0 | 1 0 0 | 0 _ _ | _ _ 0 | 1 0 0 | _ 0 _ || 1 0 | _ _ | * 1 | 0 1 | _ _ |
// +-------+-----++-+-++-------+-------+-------+-------+-------+-------++-----+-----+-----+-----+-----+
// | 9 | 0 || | || 0 _ _ | 0 _ _ | 1 0 0 | _ 0 _ | 0 1 0 | _ _ 0 || 0 1 | _ _ | 1 0 | 1 * | _ _ |
// | | 1 || | || 1 0 0 | 1 0 0 | 0 _ _ | _ _ 0 | 1 0 0 | _ 0 _ || 1 0 | _ _ | 0 1 | * 1 | _ _ |
// +-------+-----++-+-++-------+-------+-------+-------+-------+-------++-----+-----+-----+-----+-----+
// | 10 | 0 || | || _ _ _ | _ _ _ | _ 0 _ | _ _ _ | _ _ 0 | _ _ 0 || _ _ | _ _ | _ _ | _ _ | 1 * |
// | | 1 || | || _ _ _ | _ _ _ | _ _ _ | _ _ _ | _ _ 0 | _ _ _ || _ _ | _ _ | _ _ | _ _ | * 1 |
// +-------+-----++-+-++-------+-------+-------+-------+-------+-------++-----+-----+-----+-----+-----+
>>> printf(sm.dump_stats())
// ======================== ====
// Satoku Statistics
// ======================== ====
// satisfiable True
// init clauses 6
// init variables 5
// init synthesized 0
// init rows 28
// clauses 6
// variables 5
// synthesized 0
// rows 28
// cells 784
// clauses deleted 0
// rows deleted 0
// row kills 1
// duplicate kills 0
// zero changes 308
// soft changes 91
// zero update passes 0
// row update passes 3
// superset update passes 2
// zero updates 0
// row updates 63
// superset updates 22
// max zero updates 0
// max row updates 23
// max superset updates 18
// pending zero updates 0
// pending row updates 0
// pending superset updates 0
// row checks 127
// row merges 129
// state combines 0
// cell combines 0
// message
// ======================== ====
.. \\|:here:|
**Delete Redundant Clauses**
>>> ign = sm.delete_redundant_clauses(strictly_inside=False)
>>> ign = sm.dump(immediate=True)
// | || P || | || _ _ _ | _ _ _ | _ _ _ | _ _ _ || _ _ | _ _ | _ _ | _ _ | _ _ |
// +-------+-----++-+-++-------+-------+-------+-------++-----+-----+-----+-----+-----+
// +-------+-----++-+-++-------+-------+-------+-------++-----+-----+-----+-----+-----+
// | 0 | 0 || | || 1 * * | 0 _ _ | _ _ 0 | _ 0 _ || 1 0 | _ _ | 0 1 | 0 1 | _ _ |
// | | 1 || | || * 1 * | 1 0 0 | 0 0 1 | 1 0 0 || 0 1 | 0 1 | 1 0 | 1 0 | _ _ |
// | | 2 || | || * * 1 | 1 0 0 | 1 0 0 | 0 1 0 || 0 1 | 1 0 | 1 0 | 1 0 | _ _ |
// +-------+-----++-+-++-------+-------+-------+-------++-----+-----+-----+-----+-----+
// | 1 | 0 || | || 0 _ _ | 1 * * | _ 0 _ | _ _ 0 || 0 1 | _ _ | 1 0 | 1 0 | _ _ |
// | | 1 || | || 1 0 0 | * 1 * | 1 0 0 | 0 0 1 || 1 0 | 1 0 | 0 1 | 0 1 | 0 1 |
// | | 2 || | || 1 0 0 | * * 1 | 0 1 0 | 1 0 0 || 1 0 | 0 1 | 0 1 | 0 1 | _ _ |
// +-------+-----++-+-++-------+-------+-------+-------++-----+-----+-----+-----+-----+
// | 2 | 0 || | || _ 0 _ | _ _ 0 | 1 * * | 0 _ _ || _ _ | 1 0 | _ _ | _ _ | _ _ |
// | | 1 || | || 1 0 0 | 0 0 1 | * 1 * | 1 0 0 || 1 0 | 0 1 | 0 1 | 0 1 | _ _ |
// | | 2 || | || 0 1 0 | 1 0 0 | * * 1 | 1 0 0 || 0 1 | 0 1 | 1 0 | 1 0 | _ _ |
// +-------+-----++-+-++-------+-------+-------+-------++-----+-----+-----+-----+-----+
// | 3 | 0 || | || _ _ 0 | _ 0 _ | 0 _ _ | 1 * * || _ _ | 0 1 | _ _ | _ _ | _ _ |
// | | 1 || | || 0 0 1 | 1 0 0 | 1 0 0 | * 1 * || 0 1 | 1 0 | 1 0 | 1 0 | _ _ |
// | | 2 || | || 1 0 0 | 0 1 0 | 1 0 0 | * * 1 || 1 0 | 1 0 | 0 1 | 0 1 | 0 1 |
// +-------+-----++-+-++-------+-------+-------+-------++-----+-----+-----+-----+-----+
// +-------+-----++-+-++-------+-------+-------+-------++-----+-----+-----+-----+-----+
// | 4 | 0 || | || 1 0 0 | 0 _ _ | _ _ 0 | _ 0 _ || 1 * | _ _ | 0 1 | 0 1 | _ _ |
// | | 1 || | || 0 _ _ | 1 0 0 | _ 0 _ | _ _ 0 || * 1 | _ _ | 1 0 | 1 0 | _ _ |
// +-------+-----++-+-++-------+-------+-------+-------++-----+-----+-----+-----+-----+
// | 5 | 0 || | || _ 0 _ | _ _ 0 | 1 0 0 | 0 _ _ || _ _ | 1 * | _ _ | _ _ | _ _ |
// | | 1 || | || _ _ 0 | _ 0 _ | 0 _ _ | 1 0 0 || _ _ | * 1 | _ _ | _ _ | _ _ |
// +-------+-----++-+-++-------+-------+-------+-------++-----+-----+-----+-----+-----+
// | 6 | 0 || | || 0 _ _ | 1 0 0 | _ 0 _ | _ _ 0 || 0 1 | _ _ | 1 * | 1 0 | _ _ |
// | | 1 || | || 1 0 0 | 0 _ _ | _ _ 0 | _ 0 _ || 1 0 | _ _ | * 1 | 0 1 | _ _ |
// +-------+-----++-+-++-------+-------+-------+-------++-----+-----+-----+-----+-----+
// | 7 | 0 || | || 0 _ _ | 1 0 0 | _ 0 _ | _ _ 0 || 0 1 | _ _ | 1 0 | 1 * | _ _ |
// | | 1 || | || 1 0 0 | 0 _ _ | _ _ 0 | _ 0 _ || 1 0 | _ _ | 0 1 | * 1 | _ _ |
// +-------+-----++-+-++-------+-------+-------+-------++-----+-----+-----+-----+-----+
// | 8 | 0 || | || _ _ _ | _ 0 _ | _ _ _ | _ _ 0 || _ _ | _ _ | _ _ | _ _ | 1 * |
// | | 1 || | || _ _ _ | _ _ _ | _ _ _ | _ _ _ || _ _ | _ _ | _ _ | _ _ | * 1 |
// +-------+-----++-+-++-------+-------+-------+-------++-----+-----+-----+-----+-----+
>>> printf(sm.dump_stats())
// ======================== ====
// Satoku Statistics
// ======================== ====
// satisfiable True
// init clauses 6
// init variables 5
// init synthesized 0
// init rows 28
// clauses 4
// variables 5
// synthesized 0
// rows 22
// cells 484
// clauses deleted 2
// rows deleted 0
// row kills 1
// duplicate kills 0
// zero changes 308
// soft changes 91
// zero update passes 0
// row update passes 3
// superset update passes 2
// zero updates 0
// row updates 63
// superset updates 22
// max zero updates 0
// max row updates 23
// max superset updates 18
// pending zero updates 0
// pending row updates 0
// pending superset updates 0
// row checks 127
// row merges 129
// state combines 0
// cell combines 0
// message
// ======================== ====
**Extract solutions**
Get row with longest variable binding s[1,1]::
// | | 1 || | || 1 0 0 | * 1 * | 1 0 0 | 0 0 1 || 1 0 | 1 0 | 0 1 | 0 1 | 0 1 |
Disable row::
// | || P || | || _ _ _ | _ 0 _ | _ _ _ | _ _ 0 || _ _ | _ _ | _ _ | _ _ | _ _ |
// +-------+-----++-+-++-------+-------+-------+-------++-----+-----+-----+-----+-----+
// +-------+-----++-+-++-------+-------+-------+-------++-----+-----+-----+-----+-----+
// | 0 | 0 || | || 1 * * | 0 0 1 | 0 1 0 | 1 0 0 || 1 0 | 0 1 | 0 1 | 0 1 | _ _ |
// | | 1 || | || * 1 * | 1 0 0 | 0 0 1 | 1 0 0 || 0 1 | 0 1 | 1 0 | 1 0 | _ _ |
// | | 2 || | || * * 1 | 1 0 0 | 1 0 0 | 0 1 0 || 0 1 | 1 0 | 1 0 | 1 0 | _ _ |
// +-------+-----++-+-++-------+-------+-------+-------++-----+-----+-----+-----+-----+
// | 1 | 0 || | || 0 _ _ | 1 * * | _ 0 _ | _ _ 0 || 0 1 | _ _ | 1 0 | 1 0 | _ _ |
// | | 1 || | || 0 0 0 | * 1 * | 0 0 0 | 0 0 0 || 0 0 | 0 0 | 0 0 | 0 0 | 0 0 |
// | | 2 || | || 1 0 0 | * * 1 | 0 1 0 | 1 0 0 || 1 0 | 0 1 | 0 1 | 0 1 | _ _ |
// +-------+-----++-+-++-------+-------+-------+-------++-----+-----+-----+-----+-----+
// | 2 | 0 || | || 0 0 1 | 1 0 0 | 1 * * | 0 1 0 || 0 1 | 1 0 | 1 0 | 1 0 | _ _ |
// | | 1 || | || 1 0 0 | 0 0 1 | * 1 * | 1 0 0 || 1 0 | 0 1 | 0 1 | 0 1 | _ _ |
// | | 2 || | || 0 1 0 | 1 0 0 | * * 1 | 1 0 0 || 0 1 | 0 1 | 1 0 | 1 0 | _ _ |
// +-------+-----++-+-++-------+-------+-------+-------++-----+-----+-----+-----+-----+
// | 3 | 0 || | || _ _ 0 | _ 0 _ | 0 _ _ | 1 * * || _ _ | 0 1 | _ _ | _ _ | _ _ |
// | | 1 || | || 0 0 1 | 1 0 0 | 1 0 0 | * 1 * || 0 1 | 1 0 | 1 0 | 1 0 | _ _ |
// | | 2 || | || 0 0 0 | 0 0 0 | 0 0 0 | * * 1 || 0 0 | 0 0 | 0 0 | 0 0 | 0 0 |
// +-------+-----++-+-++-------+-------+-------+-------++-----+-----+-----+-----+-----+
// +-------+-----++-+-++-------+-------+-------+-------++-----+-----+-----+-----+-----+
// | 4 | 0 || | || 1 0 0 | 0 0 1 | 0 1 0 | 1 0 0 || 1 * | 0 1 | 0 1 | 0 1 | _ _ |
// | | 1 || | || 0 _ _ | 1 0 0 | _ 0 _ | _ _ 0 || * 1 | _ _ | 1 0 | 1 0 | _ _ |
// +-------+-----++-+-++-------+-------+-------+-------++-----+-----+-----+-----+-----+
// | 5 | 0 || | || 0 0 1 | 1 0 0 | 1 0 0 | 0 1 0 || 0 1 | 1 * | 1 0 | 1 0 | _ _ |
// | | 1 || | || _ _ 0 | _ 0 _ | 0 _ _ | 1 0 0 || _ _ | * 1 | _ _ | _ _ | _ _ |
// +-------+-----++-+-++-------+-------+-------+-------++-----+-----+-----+-----+-----+
// | 6 | 0 || | || 0 _ _ | 1 0 0 | _ 0 _ | _ _ 0 || 0 1 | _ _ | 1 * | 1 0 | _ _ |
// | | 1 || | || 1 0 0 | 0 0 1 | 0 1 0 | 1 0 0 || 1 0 | 0 1 | * 1 | 0 1 | _ _ |
// +-------+-----++-+-++-------+-------+-------+-------++-----+-----+-----+-----+-----+
// | 7 | 0 || | || 0 _ _ | 1 0 0 | _ 0 _ | _ _ 0 || 0 1 | _ _ | 1 0 | 1 * | _ _ |
// | | 1 || | || 1 0 0 | 0 0 1 | 0 1 0 | 1 0 0 || 1 0 | 0 1 | 0 1 | * 1 | _ _ |
// +-------+-----++-+-++-------+-------+-------+-------++-----+-----+-----+-----+-----+
// | 8 | 0 || | || _ _ _ | _ 0 _ | _ _ _ | _ _ 0 || _ _ | _ _ | _ _ | _ _ | 1 * |
// | | 1 || | || _ _ _ | _ 0 _ | _ _ _ | _ _ 0 || _ _ | _ _ | _ _ | _ _ | * 1 |
// +-------+-----++-+-++-------+-------+-------+-------++-----+-----+-----+-----+-----+
Get row with longest variable binding s[0,0]::
// | 0 | 0 || | || 1 * * | 0 0 1 | 0 1 0 | 1 0 0 || 1 0 | 0 1 | 0 1 | 0 1 | _ _ |
Disable row::
// | || P || | || 0 _ _ | _ 0 0 | _ 0 _ | _ _ 0 || 0 _ | _ _ | _ 0 | _ 0 | _ _ |
// +-------+-----++-+-++-------+-------+-------+-------++-----+-----+-----+-----+-----+
// +-------+-----++-+-++-------+-------+-------+-------++-----+-----+-----+-----+-----+
// | 0 | 0 || | || 1 * * | 0 0 0 | 0 0 0 | 0 0 0 || 0 0 | 0 0 | 0 0 | 0 0 | 0 0 |
// | | 1 || | || * 1 * | 1 0 0 | 0 0 1 | 1 0 0 || 0 1 | 0 1 | 1 0 | 1 0 | _ _ |
// | | 2 || | || * * 1 | 1 0 0 | 1 0 0 | 0 1 0 || 0 1 | 1 0 | 1 0 | 1 0 | _ _ |
// +-------+-----++-+-++-------+-------+-------+-------++-----+-----+-----+-----+-----+
// | 1 | 0 || | || 0 _ _ | 1 * * | _ 0 _ | _ _ 0 || 0 1 | _ _ | 1 0 | 1 0 | _ _ |
// | | 1 || | || 0 0 0 | * 1 * | 0 0 0 | 0 0 0 || 0 0 | 0 0 | 0 0 | 0 0 | 0 0 |
// | | 2 || | || 0 0 0 | * * 1 | 0 0 0 | 0 0 0 || 0 0 | 0 0 | 0 0 | 0 0 | 0 0 |
// +-------+-----++-+-++-------+-------+-------+-------++-----+-----+-----+-----+-----+
// | 2 | 0 || | || 0 0 1 | 1 0 0 | 1 * * | 0 1 0 || 0 1 | 1 0 | 1 0 | 1 0 | _ _ |
// | | 1 || | || 0 0 0 | 0 0 0 | * 1 * | 0 0 0 || 0 0 | 0 0 | 0 0 | 0 0 | 0 0 |
// | | 2 || | || 0 1 0 | 1 0 0 | * * 1 | 1 0 0 || 0 1 | 0 1 | 1 0 | 1 0 | _ _ |
// +-------+-----++-+-++-------+-------+-------+-------++-----+-----+-----+-----+-----+
// | 3 | 0 || | || 0 1 0 | 1 0 0 | 0 0 1 | 1 * * || 0 1 | 0 1 | 1 0 | 1 0 | _ _ |
// | | 1 || | || 0 0 1 | 1 0 0 | 1 0 0 | * 1 * || 0 1 | 1 0 | 1 0 | 1 0 | _ _ |
// | | 2 || | || 0 0 0 | 0 0 0 | 0 0 0 | * * 1 || 0 0 | 0 0 | 0 0 | 0 0 | 0 0 |
// +-------+-----++-+-++-------+-------+-------+-------++-----+-----+-----+-----+-----+
// +-------+-----++-+-++-------+-------+-------+-------++-----+-----+-----+-----+-----+
// | 4 | 0 || | || 0 0 0 | 0 0 0 | 0 0 0 | 0 0 0 || 1 * | 0 0 | 0 0 | 0 0 | 0 0 |
// | | 1 || | || 0 _ _ | 1 0 0 | _ 0 _ | _ _ 0 || * 1 | _ _ | 1 0 | 1 0 | _ _ |
// +-------+-----++-+-++-------+-------+-------+-------++-----+-----+-----+-----+-----+
// | 5 | 0 || | || 0 0 1 | 1 0 0 | 1 0 0 | 0 1 0 || 0 1 | 1 * | 1 0 | 1 0 | _ _ |
// | | 1 || | || 0 1 0 | 1 0 0 | 0 0 1 | 1 0 0 || 0 1 | * 1 | 1 0 | 1 0 | _ _ |
// +-------+-----++-+-++-------+-------+-------+-------++-----+-----+-----+-----+-----+
// | 6 | 0 || | || 0 _ _ | 1 0 0 | _ 0 _ | _ _ 0 || 0 1 | _ _ | 1 * | 1 0 | _ _ |
// | | 1 || | || 0 0 0 | 0 0 0 | 0 0 0 | 0 0 0 || 0 0 | 0 0 | * 1 | 0 0 | 0 0 |
// +-------+-----++-+-++-------+-------+-------+-------++-----+-----+-----+-----+-----+
// | 7 | 0 || | || 0 _ _ | 1 0 0 | _ 0 _ | _ _ 0 || 0 1 | _ _ | 1 0 | 1 * | _ _ |
// | | 1 || | || 0 0 0 | 0 0 0 | 0 0 0 | 0 0 0 || 0 0 | 0 0 | 0 0 | * 1 | 0 0 |
// +-------+-----++-+-++-------+-------+-------+-------++-----+-----+-----+-----+-----+
// | 8 | 0 || | || 0 _ _ | 1 0 0 | _ 0 _ | _ _ 0 || 0 1 | _ _ | 1 0 | 1 0 | 1 * |
// | | 1 || | || 0 _ _ | 1 0 0 | _ 0 _ | _ _ 0 || 0 1 | _ _ | 1 0 | 1 0 | * 1 |
// +-------+-----++-+-++-------+-------+-------+-------++-----+-----+-----+-----+-----+
Get row with longest variable binding s[0,1]::
// | | 1 || | || * 1 * | 1 0 0 | 0 0 1 | 1 0 0 || 0 1 | 0 1 | 1 0 | 1 0 | _ _ |
Disable row::
// | || P || | || 0 0 _ | _ 0 0 | _ 0 0 | 0 _ 0 || 0 _ | _ 0 | _ 0 | _ 0 | _ _ |
// +-------+-----++-+-++-------+-------+-------+-------++-----+-----+-----+-----+-----+
// +-------+-----++-+-++-------+-------+-------+-------++-----+-----+-----+-----+-----+
// | 0 | 0 || | || 1 * * | 0 0 0 | 0 0 0 | 0 0 0 || 0 0 | 0 0 | 0 0 | 0 0 | 0 0 |
// | | 1 || | || * 1 * | 0 0 0 | 0 0 0 | 0 0 0 || 0 0 | 0 0 | 0 0 | 0 0 | 0 0 |
// | | 2 || | || * * 1 | 1 0 0 | 1 0 0 | 0 1 0 || 0 1 | 1 0 | 1 0 | 1 0 | _ _ |
// +-------+-----++-+-++-------+-------+-------+-------++-----+-----+-----+-----+-----+
// | 1 | 0 || | || 0 0 1 | 1 * * | 1 0 0 | 0 1 0 || 0 1 | 1 0 | 1 0 | 1 0 | _ _ |
// | | 1 || | || 0 0 0 | * 1 * | 0 0 0 | 0 0 0 || 0 0 | 0 0 | 0 0 | 0 0 | 0 0 |
// | | 2 || | || 0 0 0 | * * 1 | 0 0 0 | 0 0 0 || 0 0 | 0 0 | 0 0 | 0 0 | 0 0 |
// +-------+-----++-+-++-------+-------+-------+-------++-----+-----+-----+-----+-----+
// | 2 | 0 || | || 0 0 1 | 1 0 0 | 1 * * | 0 1 0 || 0 1 | 1 0 | 1 0 | 1 0 | _ _ |
// | | 1 || | || 0 0 0 | 0 0 0 | * 1 * | 0 0 0 || 0 0 | 0 0 | 0 0 | 0 0 | 0 0 |
// | | 2 || | || 0 0 0 | 0 0 0 | * * 1 | 0 0 0 || 0 0 | 0 0 | 0 0 | 0 0 | 0 0 |
// +-------+-----++-+-++-------+-------+-------+-------++-----+-----+-----+-----+-----+
// | 3 | 0 || | || 0 0 0 | 0 0 0 | 0 0 0 | 1 * * || 0 0 | 0 0 | 0 0 | 0 0 | 0 0 |
// | | 1 || | || 0 0 1 | 1 0 0 | 1 0 0 | * 1 * || 0 1 | 1 0 | 1 0 | 1 0 | _ _ |
// | | 2 || | || 0 0 0 | 0 0 0 | 0 0 0 | * * 1 || 0 0 | 0 0 | 0 0 | 0 0 | 0 0 |
// +-------+-----++-+-++-------+-------+-------+-------++-----+-----+-----+-----+-----+
// +-------+-----++-+-++-------+-------+-------+-------++-----+-----+-----+-----+-----+
// | 4 | 0 || | || 0 0 0 | 0 0 0 | 0 0 0 | 0 0 0 || 1 * | 0 0 | 0 0 | 0 0 | 0 0 |
// | | 1 || | || 0 0 1 | 1 0 0 | 1 0 0 | 0 1 0 || * 1 | 1 0 | 1 0 | 1 0 | _ _ |
// +-------+-----++-+-++-------+-------+-------+-------++-----+-----+-----+-----+-----+
// | 5 | 0 || | || 0 0 1 | 1 0 0 | 1 0 0 | 0 1 0 || 0 1 | 1 * | 1 0 | 1 0 | _ _ |
// | | 1 || | || 0 0 0 | 0 0 0 | 0 0 0 | 0 0 0 || 0 0 | * 1 | 0 0 | 0 0 | 0 0 |
// +-------+-----++-+-++-------+-------+-------+-------++-----+-----+-----+-----+-----+
// | 6 | 0 || | || 0 0 1 | 1 0 0 | 1 0 0 | 0 1 0 || 0 1 | 1 0 | 1 * | 1 0 | _ _ |
// | | 1 || | || 0 0 0 | 0 0 0 | 0 0 0 | 0 0 0 || 0 0 | 0 0 | * 1 | 0 0 | 0 0 |
// +-------+-----++-+-++-------+-------+-------+-------++-----+-----+-----+-----+-----+
// | 7 | 0 || | || 0 0 1 | 1 0 0 | 1 0 0 | 0 1 0 || 0 1 | 1 0 | 1 0 | 1 * | _ _ |
// | | 1 || | || 0 0 0 | 0 0 0 | 0 0 0 | 0 0 0 || 0 0 | 0 0 | 0 0 | * 1 | 0 0 |
// +-------+-----++-+-++-------+-------+-------+-------++-----+-----+-----+-----+-----+
// | 8 | 0 || | || 0 0 1 | 1 0 0 | 1 0 0 | 0 1 0 || 0 1 | 1 0 | 1 0 | 1 0 | 1 * |
// | | 1 || | || 0 0 1 | 1 0 0 | 1 0 0 | 0 1 0 || 0 1 | 1 0 | 1 0 | 1 0 | * 1 |
// +-------+-----++-+-++-------+-------+-------+-------++-----+-----+-----+-----+-----+
Get row with longest variable binding s[0,2]::
// | | 2 || | || * * 1 | 1 0 0 | 1 0 0 | 0 1 0 || 0 1 | 1 0 | 1 0 | 1 0 | _ _ |
Disable row::
// | || P || | || 0 0 0 | 0 0 0 | 0 0 0 | 0 0 0 || 0 0 | 0 0 | 0 0 | 0 0 | _ _ |
// +-------+-----++-+-++-------+-------+-------+-------++-----+-----+-----+-----+-----+
// +-------+-----++-+-++-------+-------+-------+-------++-----+-----+-----+-----+-----+
// | 0 | 0 || | || 1 * * | 0 0 0 | 0 0 0 | 0 0 0 || 0 0 | 0 0 | 0 0 | 0 0 | 0 0 |
// | | 1 || | || * 1 * | 0 0 0 | 0 0 0 | 0 0 0 || 0 0 | 0 0 | 0 0 | 0 0 | 0 0 |
// | | 2 || | || * * 1 | 0 0 0 | 0 0 0 | 0 0 0 || 0 0 | 0 0 | 0 0 | 0 0 | 0 0 |
// +-------+-----++-+-++-------+-------+-------+-------++-----+-----+-----+-----+-----+
// | 1 | 0 || | || 0 0 0 | 1 * * | 0 0 0 | 0 0 0 || 0 0 | 0 0 | 0 0 | 0 0 | 0 0 |
// | | 1 || | || 0 0 0 | * 1 * | 0 0 0 | 0 0 0 || 0 0 | 0 0 | 0 0 | 0 0 | 0 0 |
// | | 2 || | || 0 0 0 | * * 1 | 0 0 0 | 0 0 0 || 0 0 | 0 0 | 0 0 | 0 0 | 0 0 |
// +-------+-----++-+-++-------+-------+-------+-------++-----+-----+-----+-----+-----+
// | 2 | 0 || | || 0 0 0 | 0 0 0 | 1 * * | 0 0 0 || 0 0 | 0 0 | 0 0 | 0 0 | 0 0 |
// | | 1 || | || 0 0 0 | 0 0 0 | * 1 * | 0 0 0 || 0 0 | 0 0 | 0 0 | 0 0 | 0 0 |
// | | 2 || | || 0 0 0 | 0 0 0 | * * 1 | 0 0 0 || 0 0 | 0 0 | 0 0 | 0 0 | 0 0 |
// +-------+-----++-+-++-------+-------+-------+-------++-----+-----+-----+-----+-----+
// | 3 | 0 || | || 0 0 0 | 0 0 0 | 0 0 0 | 1 * * || 0 0 | 0 0 | 0 0 | 0 0 | 0 0 |
// | | 1 || | || 0 0 0 | 0 0 0 | 0 0 0 | * 1 * || 0 0 | 0 0 | 0 0 | 0 0 | 0 0 |
// | | 2 || | || 0 0 0 | 0 0 0 | 0 0 0 | * * 1 || 0 0 | 0 0 | 0 0 | 0 0 | 0 0 |
// +-------+-----++-+-++-------+-------+-------+-------++-----+-----+-----+-----+-----+
// +-------+-----++-+-++-------+-------+-------+-------++-----+-----+-----+-----+-----+
// | 4 | 0 || | || 0 0 0 | 0 0 0 | 0 0 0 | 0 0 0 || 1 * | 0 0 | 0 0 | 0 0 | 0 0 |
// | | 1 || | || 0 0 0 | 0 0 0 | 0 0 0 | 0 0 0 || * 1 | 0 0 | 0 0 | 0 0 | 0 0 |
// +-------+-----++-+-++-------+-------+-------+-------++-----+-----+-----+-----+-----+
// | 5 | 0 || | || 0 0 0 | 0 0 0 | 0 0 0 | 0 0 0 || 0 0 | 1 * | 0 0 | 0 0 | 0 0 |
// | | 1 || | || 0 0 0 | 0 0 0 | 0 0 0 | 0 0 0 || 0 0 | * 1 | 0 0 | 0 0 | 0 0 |
// +-------+-----++-+-++-------+-------+-------+-------++-----+-----+-----+-----+-----+
// | 6 | 0 || | || 0 0 0 | 0 0 0 | 0 0 0 | 0 0 0 || 0 0 | 0 0 | 1 * | 0 0 | 0 0 |
// | | 1 || | || 0 0 0 | 0 0 0 | 0 0 0 | 0 0 0 || 0 0 | 0 0 | * 1 | 0 0 | 0 0 |
// +-------+-----++-+-++-------+-------+-------+-------++-----+-----+-----+-----+-----+
// | 7 | 0 || | || 0 0 0 | 0 0 0 | 0 0 0 | 0 0 0 || 0 0 | 0 0 | 0 0 | 1 * | 0 0 |
// | | 1 || | || 0 0 0 | 0 0 0 | 0 0 0 | 0 0 0 || 0 0 | 0 0 | 0 0 | * 1 | 0 0 |
// +-------+-----++-+-++-------+-------+-------+-------++-----+-----+-----+-----+-----+
// | 8 | 0 || | || 0 0 0 | 0 0 0 | 0 0 0 | 0 0 0 || 0 0 | 0 0 | 0 0 | 0 0 | 1 * |
// | | 1 || | || 0 0 0 | 0 0 0 | 0 0 0 | 0 0 0 || 0 0 | 0 0 | 0 0 | 0 0 | * 1 |
// +-------+-----++-+-++-------+-------+-------+-------++-----+-----+-----+-----+-----+
Solutions (DNF clause vectors)::
[ 1 1 0 0 0 ]
[ 1 0 0 0 _ ]
[ 0 0 1 1 _ ]
[ 0 1 1 1 _ ]
a b c d e
Original Problem::
[ [ 1 _ _ 0 _ ]
[ 0 1 _ _ _ ]
[ 0 0 1 _ _ ] ]
[ [ 1 _ _ _ _ ]
[ _ 0 _ _ _ ]
[ _ _ 1 _ _ ] ]
[ [ 0 _ _ _ _ ]
[ _ 1 _ _ _ ]
[ _ _ 0 _ _ ] ]
[ [ _ 1 _ _ ]
[ _ _ 0 _ ]
[ _ _ _ 1 ] ]
[ [ _ _ 0 _ _ ]
[ _ _ _ 1 _ ]
[ _ _ _ _ 1 ] ]
[ [ _ 0 _ _ _ ]
[ _ 1 _ 1 _ ]
[ _ 1 _ 0 0 ] ]
a b c d e
.. >>> printf(sm)
.. \\|:here:|
"""
_pyjsmo_versions = [
(1, {'bases': [0],
'order': ['satisfiable', 'size', 'row_status',
'regions', 'clauses', 'variables', 'synthesized', 'rows',
'clause_offsets', 'clause_sizes',
'row_clause_map', 'row_literal_map',
'zero_updates',
'row_update_flags', 'row_updates',
'superset_update_flags', 'superset_updates',
'stats',
'opt_strip_variables'],
'defaults': pyjsmo.OrderedDict((
('satisfiable', True),
('size', 0),
('row_status', None),
('regions', []),
('clauses', []),
('variables', None),
('synthesized', None),
('rows', []),
('clause_offsets', []),
('clause_sizes', []),
('row_clause_map', []),
('row_literal_map', []),
('zero_updates', []),
('row_update_flags', []),
('row_updates', []),
('superset_update_flags', []),
('superset_updates', []),
('opt_strip_variables', None),
)),
'amap': [],
'expand': None,
}),
]
_pyjsmo_x_problem = None
_pyjsmo_x_progress = None
def _get_problem(self): # |:mth:|
"""Weak reference."""
value = self._pyjsmo_x_problem
if value is not None:
value = value()
return value
def _set_problem(self, value): # |:mth:|
if value is not None:
value = weakref.ref(value)
self._pyjsmo_x_problem = value
problem = property(_get_problem, _set_problem, None, _get_problem.__doc__)
def __init__(self, problem=None, with_variables=None, no_conflicts=None, delay_zero_updates=None, progress=None, **kwargs): # |:mth:|
super(SatokuMatrix, self).__init__(**kwargs)
self._pyjsmo_x_progress = progress
self._pjsmo_x_variables = []
self.row_status = SelRow()
self.stats = SMStats()
self.synthesized = SMRegion()
self.variables = SMRegion()
region = SMRegion()
self.regions.append(region)
self.map_problem(problem=problem, with_variables=with_variables, no_conflicts=no_conflicts, delay_zero_updates=delay_zero_updates)
def copy(self): # |:mth:|
sm = self.__class__()
for attr in self._pyjsmo_order:
setattr(sm, attr, copy.deepcopy(getattr(self, attr)))
sm.problem = self.problem
sm._pyjsmo_x_progress = self._pyjsmo_x_progress
return sm
# --------------------------------------------------
# ||:sec:|| Progress
# --------------------------------------------------
[docs] def progress(self, message, **kwargs): # |:mth:|
"""
:returns: self for chaining.
"""
if self._pyjsmo_x_progress:
self._pyjsmo_x_progress.step(message, **kwargs)
return self
# --------------------------------------------------
# ||:sec:|| Cell Segment Analysis
# --------------------------------------------------
[docs] def selection_request_(self, row, ci, size): # |:mth:|
"""
:returns: offset for selection request (soft one) or -1
"""
sel_req_ofs = -1
for csi in xrange(size):
if (row[ci + csi] > 1):
if sel_req_ofs >= 0:
return -1
sel_req_ofs = csi
return sel_req_ofs
[docs] def selection_request(self, row, sf): # |:mth:|
"""
:returns: offset for selection request (soft one) or -1
"""
size = self.clause_sizes[sf]
ci = self.clause_offsets[sf]
return self.selection_request_(row, ci, size)
[docs] def required_selection_(self, row, ci, size): # |:mth:|
"""
:returns: offset for required selection (hard one) or -1
"""
sel_req_ofs = -1
for csi in xrange(size):
if (row[ci + csi] == 1):
if sel_req_ofs >= 0:
return -1
sel_req_ofs = csi
return sel_req_ofs
[docs] def required_selection(self, row, sf): # |:mth:|
"""
:returns: offset for required selection (hard one) or -1
"""
size = self.clause_sizes[sf]
ci = self.clause_offsets[sf]
return self.required_selection_(row, ci, size)
[docs] def one_count_quick(self, row, sf): # |:mth:|
"""
:returns: one counts (soft, hard)
"""
soft_count = 0
hard_count = 0
size = self.clause_sizes[sf]
ci = self.clause_offsets[sf]
for csi in xrange(size):
value = row[ci + csi]
if (value > 0):
if (value > 1):
soft_count += 1
else:
hard_count += 1
False and printe(sformat( # |:debug:|
"{0}{3:^{1}} {4:<{2}s}: >{5!s}<",
dbg_comm, dbg_twid, dbg_fwid, ':DBG:', 'ones', (soft_count, hard_count)))
return soft_count, hard_count
[docs] def one_count(self, row, sf): # |:mth:|
"""
:returns: soft_count, hard_count, soft_ones, hard_ones
"""
soft_count = 0
hard_count = 0
soft_ones = []
hard_ones = []
size = self.clause_sizes[sf]
ci = self.clause_offsets[sf]
for csi in xrange(size):
value = row[ci + csi]
if (value > 0):
if (value > 1):
soft_count += 1
soft_ones.append(csi)
else:
hard_count += 1
hard_ones.append(csi)
False and printe(sformat( # |:debug:|
"{0}{3:^{1}} {4:<{2}s}: >{5!s}<",
dbg_comm, dbg_twid, dbg_fwid, ':DBG:', 'ones', (soft_count, hard_count, soft_ones, hard_ones)))
return soft_count, hard_count, soft_ones, hard_ones
[docs] def is_bound_(self, row, astate_ofs, size): # |:mth:|
"""
:returns: (True, ofs), if there is at most a single one (hard or soft) in the segment.
"""
nz_count = 0
nz_sh = -1
for sh in xrange(size):
if (row[astate_ofs + sh] > 0):
nz_count += 1
nz_sh = sh
return nz_count < 2, nz_sh
[docs] def is_bound(self, row, sg): # |:mth:|
"""
:returns: (True, ofs), if there is at most a single one (hard or soft) in the segment.
"""
size = self.clause_sizes[sg]
astate_ofs = self.clause_offsets[sg]
return self.is_bound_(row, astate_ofs, size)
[docs] def next_bound(self, si=None, sg=None, vert_regions=None, horz_regions=None, strictly_inside=None): # |:mth:|
"""
:returns: [si, sg] for next fully bound CCSM.
"""
if vert_regions is None:
vert_regions = [_r for _r in self.regions if _r != self.variables]
if horz_regions is None:
if strictly_inside:
horz_regions = vert_regions
else:
horz_regions = [_r for _r in self.regions]
if si is None:
si = 0
if sg is None:
sg = 0
if strictly_inside is None:
strictly_inside = True
# |:obsolete:|
# vert_limit = region.ofs + region.size
# if strictly_inside:
# horz_limit = vert_limit
# else:
# horz_limit = len(clauses)
# if si < region.ofs:
# si = region.ofs
# if sg < region.ofs:
# sg = region.ofs
rows = self.rows
clauses = self.clauses
riter_vert = SMRegionIterator(vert_regions)
riter_horz = SMRegionIterator(horz_regions)
for _si in riter_vert.at(si):
csm = clauses[_si]
si = csm.indx
ri = csm.ofs
vsize = csm.size
for _sg in riter_horz.at(sg):
ccsm = clauses[_sg]
sg = ccsm.indx
if si == sg:
continue
hofs = ccsm.ofs
hsize = ccsm.size
is_bound = True
one_ofs_counts = [0 for i in xrange(hsize)]
for vofs in xrange(vsize):
is_bound, one_ofs = self.is_bound_(rows[ri + vofs], hofs, hsize)
if not is_bound:
break
if one_ofs >= 0:
one_ofs_counts[one_ofs] += 1
if is_bound:
for one_ofs_count in one_ofs_counts:
if one_ofs_count > 1:
is_bound = False
break
if is_bound:
return (si, sg)
sg = 0
return (-1, -1)
[docs] def dump_bound(self, regions=None): # |:mth:|
"""
:returns: dump all bound clause conflict sub-matrixes.
"""
if regions is None:
regions = [_r for _r in self.regions if _r != self.variables]
si, sg = (0, -1)
while True:
si, sg = self.next_bound(si, sg+1, regions)
if si < 0:
break
printe(sformat(
"{0}{3:^{1}} {4:<{2}s}: ]{5!s}[",
dbg_comm, dbg_twid, dbg_fwid, ':DBG:', 'bound', (si, sg)))
# --------------------------------------------------
# ||:sec:|| Next minor conflict cell row
# --------------------------------------------------
#
# Only 2 assignable positions left, but not unrestricted.
#
# Restricted cell row cr_i,j,g with 2 possible states s_i,j,g,e
# s_i,j,g,f where all other states s_i,j,g,x with x != e,f are
# impossible.
[docs] def is_minor_ccr_(self, row, astate_ofs, size): # |:mth:|
"""Is this row section a minor conflict cell row.
:returns: (True, ofs, ofs), if there is at least one
impossible state and at most two possible states in the
segment.
"""
z_count = 0
nz_count = 0
nz_sh = []
if size > 2:
for sh in xrange(size):
if (row[astate_ofs + sh] > 0):
nz_count += 1
if nz_count > 2:
break
nz_sh.append(sh)
else:
z_count += 1
if nz_count != 2 or not z_count:
return False, 0, 0
return True, nz_sh[0], nz_sh[1]
[docs] def is_minor_ccr(self, row, sg): # |:mth:|
"""Is this a minor conflict cell row.
:returns: (True, ofs, ofs), if there is at least one
impossible state and at most two possible states in the
segment.
"""
size = self.clause_sizes[sg]
astate_ofs = self.clause_offsets[sg]
return self.is_minor_ccr_(row, astate_ofs, size)
[docs] def minor_ccr_default_param(self, vert_regions=None, horz_regions=None, min_height=None): # |:mth:|
"""
:returns: (vert_regions, horz_regions, min_height)
"""
if min_height is None:
min_height = 3
if vert_regions is None:
if min_height > 2:
vert_regions = [_r for _r in self.regions if _r != self.variables]
else:
vert_regions = list(self.regions)
if horz_regions is None:
horz_regions = vert_regions
return (vert_regions, horz_regions, min_height)
[docs] def next_minor_ccr(self, si=None, sj=None, sg=None, vert_regions=None, horz_regions=None, min_height=None): # |:mth:|
"""
:returns: [si, sj, sg, one_sh_0, one_sh_1] for next fully minor_ccr CCSM.
"""
vert_regions, horz_regions, min_height = self.minor_ccr_default_param(
vert_regions, horz_regions, min_height)
min_width = 3
if si is None:
si = 0
if sj is None:
sj = 0
if sg is None:
sg = 0
rows = self.rows
clauses = self.clauses
riter_vert = SMRegionIterator(vert_regions)
riter_horz = SMRegionIterator(horz_regions)
one_sh_0 = 0
one_sh_1 = 0
for _si in riter_vert.at(si):
csm = clauses[_si]
si = csm.indx
row_ofs = csm.ofs
height = csm.size
if height < min_height:
continue
while sj < height:
for _sg in riter_horz.at(sg):
ccsm = clauses[_sg]
sg = ccsm.indx
if si == sg:
continue
astate_ofs = ccsm.ofs
width = ccsm.size
if width < min_width:
continue
is_minor_ccr, one_sh_0, one_sh_1 = self.is_minor_ccr_(
rows[row_ofs + sj], astate_ofs, width)
if is_minor_ccr:
return (si, sj, sg, one_sh_0, one_sh_1)
sg = 0
sj += 1
sj = 0
return (-1, -1, -1, one_sh_0, one_sh_1)
[docs] def dump_minor_ccrs(self, vert_regions=None, horz_regions=None, min_height=None): # |:mth:|
"""
:returns: dump all minor_ccr clause conflict sub-matrixes.
"""
vert_regions, horz_regions, min_height = self.minor_ccr_default_param(
vert_regions, horz_regions, min_height)
si, sj, sg = (0, 0, -1)
while True:
si, sj, sg, one_sh_0, one_sh_1 = self.next_minor_ccr(
si, sj, sg+1, vert_regions, horz_regions, min_height)
if si < 0:
break
printe(sformat(
"// "":DBG: {1:<{0}s}: ]{2!s}[", dbg_fwid, "minor_ccr",
(si, sj, sg, one_sh_0, one_sh_1)))
[docs] def check_minor_ccrs(self, vert_regions=None, horz_regions=None, min_height=None): # |:mth:|
r"""
:returns: number of rows killed
"""
vert_regions, horz_regions, min_height = self.minor_ccr_default_param(
vert_regions, horz_regions, min_height)
init_row_kills = self.stats.row_kills
si, sj, sg = (0, 0, -1)
while True:
si, sj, sg, one_sh_0, one_sh_1 = self.next_minor_ccr(si, sj, sg+1, vert_regions, horz_regions, min_height)
if si < 0:
break
ccell = self.combine_states(si, sj, sg, one_sh_0)
self.delete_clause(ccell.indx)
return self.stats.row_kills - init_row_kills
# --------------------------------------------------
# ||:sec:|| Cell Rows
# --------------------------------------------------
[docs] def cell_rows_(self, this, that, normalized=None): # |:mth:|
r"""
:returns:
"""
ri = this.ofs
ci = that.ofs
cwid = that.size
if normalized:
cr_cell_rows = [
bytearray(((_b and 1) or 0
for _b in
self.rows[this.ofs + sj][ci:ci+cwid]))
for sj in range(this.size)]
else:
cr_cell_rows = [
self.rows[this.ofs + sj][ci:ci+cwid]
for sj in range(this.size)]
return cr_cell_rows
[docs] def cell_rows(self, si, sg, normalized=None): # |:mth:|
r"""
:returns:
"""
this = self.clauses[si]
that = self.clauses[sg]
return self.cell_rows_(this, that, normalized)
# --------------------------------------------------
# ||:sec:|| Zero Change
# --------------------------------------------------
[docs] def fmt_state_row_abs(self, si, sj, ri=None): # |:mth:|
"""Format state row reference.
:returns: formatted state row reference
:param ri: if negative, do not add absolute reference. if
None, calculate absolute row index.
"""
if (len(self.clauses) / 10000 >= 1):
indx_width = 7
else:
indx_width = 4
if (self.size / 10000 >= 1):
rindx_width = 7
else:
rindx_width = 4
if ri is None:
ri = self.clause_offsets[si] + sj
if ri < 0:
fmt = 's_ij({1:{0}d},{2:{0}d})'
else:
fmt = 's_ij({1:{0}d},{2:{0}d}) r({4:{3}d})'
return sformat(fmt, indx_width, si, sj, 7, ri)
[docs] def fmt_state_row(self, si, sj): # |:mth:|
"""Format state row reference.
:returns: formatted state row reference
"""
return self.fmt_state_row_abs(si, sj, -1)
[docs] def fmt_cell_row_abs(self, si, sj, sg, dump=None, ri=None, ci=None): # |:mth:|
"""Format cell row reference.
:returns: formatted cell row reference
:param dump: if True, dump the cell row contents.
:param ri: if negative, do not add absolute reference. if
None, calculate absolute row index.
:param ci: if None or negative, calculate absolute column index.
"""
if (len(self.clauses) / 10000 >= 1):
indx_width = 7
else:
indx_width = 4
if (self.size / 10000 >= 1):
rindx_width = 7
else:
rindx_width = 4
_ri = ri
if ri is None or ri < 0:
_ri = self.clause_offsets[si] + sj
_ci = ci
if ci is None or ci < 0:
_ci = self.clause_offsets[sg]
if dump:
cr_dump = ' '.join(((_c and '1') or '0' for _c in self.rows[_ri][_ci:_ci+self.clauses[sg].size]))
if ri < 0:
fmt = 's_ijg({1:{0}d},{2:{0}d},{3:{0}d})<{7:3d}>'
else:
fmt = 's_ijg({1:{0}d},{2:{0}d},{3:{0}d}) r({5:{4}d},{6:{4}d})<{7:3d}>'
if dump:
fmt += ' [{8}]'
return sformat(fmt, indx_width, si, sj, sg, rindx_width, _ri, _ci, self.clauses[sg].size, cr_dump)
[docs] def fmt_cell_row(self, si, sj, sg, dump=None): # |:mth:|
"""Format cell row reference.
:returns: formatted cell row reference
"""
return self.fmt_cell_row_abs(si, sj, sg, dump, -1, -1)
[docs] def kill_row(self, si, sj): # |:mth:|
"""
:returns: self for chaining.
"""
stats = self.stats
ri = self.clause_offsets[si] + sj
if not self.row_status[ri]:
stats.duplicate_kills += 1
return self
stats.row_kills += 1
#_debug and printe(sformat("// "":KIL: {1:<{0}s}: ]{2!s}[", dbg_fwid, "row", self.fmt_state_row_abs(si, sj, ri)))
self.row_status[ri] = 0
soft_count, hard_count = self.one_count_quick(self.row_status, si)
row = self.rows[ri]
if (soft_count + hard_count) == 0:
self.satisfiable = False
# quick zero fill for visual aesthetics
size = self.size
for ci in xrange(size):
if ci == ri:
continue
row[ci] = 0
for cii, crow in enumerate(self.rows):
if cii == ri:
continue
crow[ri] = 0
stats.message = sformat('UNSAT s({0}, {1})', si, sj)
raise SatokuUnsatisfied(stats.message)
# suppress new superset update requests
superset_update_flags = self.superset_update_flags
self.superset_update_flags = [1 for i in xrange(self.size)]
for ccsm in self.clauses:
sg = ccsm.indx
if si == sg:
# do not change idendity clause segment
continue
ofs = ccsm.ofs
for sh in xrange(ccsm.size):
ci = ofs + sh
if row[ci] != 0:
stats.zero_changes += 1
row[ci] = 0
self.zero_change_(sg, sh, si, sj, ci, ri, True)
self.superset_update_flags = superset_update_flags
return self
[docs] def zero_change_(self, si, sj, sg, sh, ri, ci, immediate=None): # |:mth:|
"""
:returns: killed, changed.
"""
killed = False
changed = False
if self.row_status[ri] == 0:
return killed, changed
rows = self.rows
row = rows[ri]
if row[ci] != 0:
stats = self.stats
stats.zero_changes += 1
changed = True
row[ci] = 0
soft_count, hard_count = self.one_count_quick(row, sg)
# check for killed row
killed = (soft_count + hard_count) == 0
if killed:
self.kill_row(si, sj)
return killed, changed
if soft_count == 1:
self.row_update_request(si, sj)
else:
self.superset_update_request(si, sj)
if rows[ci][ri] != 0:
if immediate:
return self.zero_change_(sg, sh, si, sj, ci, ri)
else:
if self.row_status[ci] != 0:
# check for killed row
soft_count, hard_count = self.one_count_quick(rows[ci], si)
mkilled = (soft_count + hard_count) == 1
if mkilled:
self.kill_row(sg, sh)
else:
self.zero_updates.append((sg, sh, si, sj, ci, ri))
return killed, changed
[docs] def zero_change(self, si, sj, sg, sh, immediate=None): # |:mth:|
"""
:returns: self for chaining.
"""
ri = self.clause_offsets[si] + sj
ci = self.clause_offsets[sg] + sh
return self.zero_change_(si, sj, sg, sh, ri, ci, immediate)
[docs] def update_zeroes(self): # |:mth:|
"""
:returns: self for chaining.
"""
zero_updates = self.zero_updates
if not zero_updates:
return self
stats = self.stats
stats.zero_update_passes += 1
zc_count = len(zero_updates)
stats.zero_updates += zc_count
if stats.max_zero_updates < zc_count:
stats.max_zero_updates = zc_count
self.zero_updates = []
for zc in zero_updates:
self.zero_change_(*zc)
return self
# --------------------------------------------------
# ||:sec:|| Updates
# --------------------------------------------------
[docs] def row_update_request(self, si, sj): # |:mth:|
"""
:returns: self for chaining.
"""
ri = self.clause_offsets[si] + sj
if not self.row_status[ri]:
return self
ru_flags = self.row_update_flags
if ru_flags[ri]:
return self
ru_flags[ri] = 1
self.row_updates.append((si, sj))
return self
[docs] def update_row(self, si, sj): # |:mth:|
"""
:returns: row_changed
"""
stats = self.stats
row_changed = False
ri = self.clause_offsets[si] + sj
ru_flags = self.row_update_flags
if not self.row_status[ri]:
ru_flags[ri] = 0
return row_changed
if not ru_flags[ri]:
return row_changed
row_size = self.size
rows = self.rows
row = rows[ri]
show_details = False
updated = True
while updated:
updated = False
stats.row_checks += 1
for ccsm in self.clauses:
sf = ccsm.indx
if sf == si:
# do not change idendity clause segment
continue
sg = self.selection_request(row, sf)
if sg >= 0:
stats.row_merges += 1
rq_ri = ccsm.ofs + sg
rq_row = rows[rq_ri]
msg_merge_rows = sformat('s[{0:4d},{1:3d}] <- s[{2:4d},{3:3d}]', si, sj, sf, sg)
values = []
for ci in xrange(row_size):
# +==========+=============+===============+
# | row[ci] | rq_row[ci] | row[ci]' |
# +==========+=============+===============+
# | row[ci] <= rq_row[ci] | row[ci] |
# +----------+-------------+---------------+
# | 2 | 1 | 1 |
# +----------+-------------+---------------+
# | 1,2 | 0 | zero_change() |
# +==========+=============+===============+
if rq_row[ci] < row[ci]:
show_details and values.append(sformat("{0:3d}: {1!s} <- {2!s}", ci, row[ci], rq_row[ci]))
if rq_row[ci] == 0:
rq_sf = self.row_clause_map[ci]
rq_sg = self.row_literal_map[ci]
if rq_sf == si:
printe('// |:WRN:| update_row: 0 in identity segment s{0} when merging {1}',
[rq_sf, rq_sg], msg_merge_rows)
continue
killed, changed = self.zero_change_(si, sj, rq_sf, rq_sg, ri, ci, True)
if killed:
row_changed = False
ru_flags[ri] = 0
return row_changed
row_changed = row_changed | changed
updated = True
else:
row[ci] = rq_row[ci]
updated = True
if show_details:
hl()
printe(sformat(
"{0}{3:^{1}} {4:<{2}s}: {5!s} {6!s}",
dbg_comm, dbg_twid, dbg_fwid, ':MRG:', 'row', msg_merge_rows, values))
ru_flags[ri] = 0
return row_changed
[docs] def update_rows(self): # |:mth:|
"""
:returns: self for chaining
"""
stats = self.stats
self.update_zeroes()
while self.row_updates:
stats.row_update_passes += 1
row_updates = self.row_updates
self.row_updates = []
ru_count = len(row_updates)
stats.row_updates += ru_count
if stats.max_row_updates < ru_count:
stats.max_row_updates = ru_count
for req in row_updates:
changed = self.update_row(*req)
if changed:
self.superset_update_request(*req)
self.update_zeroes()
self.update_supersets()
return self
[docs] def superset_update_request(self, si, sj): # |:mth:|
"""
:returns: self for chaining.
"""
ri = self.clause_offsets[si] + sj
if not self.row_status[ri]:
return self
if self.row_update_flags[ri]:
return self
ru_flags = self.superset_update_flags
if ru_flags[ri]:
return self
ru_flags[ri] = 1
self.superset_updates.append((si, sj))
return self
[docs] def update_superset_rows(self, si, sj): # |:mth:|
"""
:returns: self for chaining
"""
stats = self.stats
ci = self.clause_offsets[si] + sj
su_flags = self.superset_update_flags
if not self.row_status[ci]:
su_flags[ci] = 0
return self
if not su_flags[ci]:
return self
for ri, row in enumerate(self.rows):
if ri == ci:
continue
if row[ci] == 1:
row[ci] = 2
stats.soft_changes += 1
sf = self.row_clause_map[ri]
sg = self.row_literal_map[ri]
self.row_update_request(sf, sg)
su_flags[ci] = 0
return self
[docs] def update_supersets(self): # |:mth:|
"""
:returns: self for chaining
"""
superset_updates = self.superset_updates
if not superset_updates:
return self
stats = self.stats
stats.superset_update_passes += 1
su_count = len(superset_updates)
stats.superset_updates += su_count
if stats.max_superset_updates < su_count:
stats.max_superset_updates = su_count
self.superset_updates = []
for req in superset_updates:
self.update_superset_rows(*req)
return self
# --------------------------------------------------
# ||:sec:|| Regions, Clauses, Variables, Problem
# --------------------------------------------------
[docs] def add_region(self, ofs=None, size=None, at=None): # |:mth:|
"""
:returns: new region.
"""
if ofs is None:
ofs = len(self.clauses)
region = SMRegion(ofs, size)
if at is not None:
self.regions.insert(at, region)
else:
self.regions.append(region)
return region
[docs] def set_region(self, ofs, size=None, keep_empty=None): # |:mth:|
"""Set a region.
:returns: self for chaining.
>>> pr = Problem(TEST_PROBLEM)
>>> sm = SatokuMatrix(None)
>>> ign = sm.map_problem(pr, with_variables=True)
>>> ign = sm.update_rows()
>>> ign = sm.dump(immediate=True)
// | || P || | || _ _ _ | _ _ _ | _ _ _ | _ _ _ | _ _ _ | _ _ _ || _ _ | _ _ | _ _ | _ _ | _ _ |
// +-------+-----++-+-++-------+-------+-------+-------+-------+-------++-----+-----+-----+-----+-----+
// +-------+-----++-+-++-------+-------+-------+-------+-------+-------++-----+-----+-----+-----+-----+
// | 0 | 0 || | || 1 * * | _ _ _ | 0 _ _ | _ _ 0 | _ 0 _ | _ 0 _ || 1 0 | _ _ | _ _ | 0 1 | _ _ |
// | | 1 || | || * 1 * | 0 0 1 | _ _ 0 | _ 0 _ | 0 _ _ | 0 1 0 || 0 1 | 1 0 | 1 0 | 1 0 | _ _ |
// | | 2 || | || * * 1 | 0 _ _ | 1 0 0 | 0 0 1 | 0 _ _ | 1 0 0 || 0 1 | 0 1 | 1 0 | 1 0 | _ _ |
// +-------+-----++-+-++-------+-------+-------+-------+-------+-------++-----+-----+-----+-----+-----+
// | 1 | 0 || | || 1 0 0 | 1 * * | 0 _ _ | _ _ 0 | _ 0 _ | _ 0 _ || 1 0 | _ _ | _ _ | 0 1 | _ _ |
// | | 1 || | || _ 0 _ | * 1 * | _ 0 _ | 0 _ _ | _ _ _ | 1 0 0 || _ _ | 0 1 | _ _ | _ _ | _ _ |
// | | 2 || | || _ _ _ | * * 1 | _ _ 0 | _ 0 _ | 0 _ _ | _ _ 0 || _ _ | _ _ | 1 0 | _ _ | _ _ |
// +-------+-----++-+-++-------+-------+-------+-------+-------+-------++-----+-----+-----+-----+-----+
// | 2 | 0 || | || 0 _ _ | 0 _ _ | 1 * * | _ 0 _ | 0 _ _ | _ _ 0 || 0 1 | _ _ | 1 0 | 1 0 | _ _ |
// | | 1 || | || _ _ 0 | _ 0 _ | * 1 * | _ _ _ | _ _ _ | 0 _ _ || _ _ | 1 0 | _ _ | _ _ | _ _ |
// | | 2 || | || 1 0 0 | _ _ 0 | * * 1 | _ _ 0 | _ 0 _ | _ 0 _ || 1 0 | _ _ | 0 1 | 0 1 | _ _ |
// +-------+-----++-+-++-------+-------+-------+-------+-------+-------++-----+-----+-----+-----+-----+
// | 3 | 0 || | || _ _ 0 | _ 0 _ | _ _ _ | 1 * * | _ _ _ | 0 _ _ || _ _ | 1 0 | _ _ | _ _ | _ _ |
// | | 1 || | || 1 0 0 | _ _ 0 | 0 _ _ | * 1 * | _ 0 _ | _ 0 _ || 1 0 | _ _ | 0 1 | 0 1 | _ _ |
// | | 2 || | || 0 _ _ | 0 _ _ | _ _ 0 | * * 1 | 0 _ _ | _ _ 0 || 0 1 | _ _ | 1 0 | 1 0 | _ _ |
// +-------+-----++-+-++-------+-------+-------+-------+-------+-------++-----+-----+-----+-----+-----+
// | 4 | 0 || | || 1 0 0 | _ _ 0 | 0 _ _ | _ _ 0 | 1 * * | _ 0 _ || 1 0 | _ _ | 0 1 | 0 1 | _ _ |
// | | 1 || | || 0 _ _ | 0 _ _ | _ _ 0 | _ 0 _ | * 1 * | _ _ 0 || 0 1 | _ _ | 1 0 | 1 0 | _ _ |
// | | 2 || | || _ _ _ | _ _ _ | _ _ _ | _ _ _ | * * 1 | _ _ 0 || _ _ | _ _ | _ _ | _ _ | 1 0 |
// +-------+-----++-+-++-------+-------+-------+-------+-------+-------++-----+-----+-----+-----+-----+
// | 5 | 0 || | || _ 0 _ | _ _ _ | _ 0 _ | 0 _ _ | _ _ _ | 1 * * || _ _ | 0 1 | _ _ | _ _ | _ _ |
// | | 1 || | || 0 1 0 | 0 0 1 | _ _ 0 | _ 0 _ | 0 _ _ | * 1 * || 0 1 | 1 0 | 1 0 | 1 0 | _ _ |
// | | 2 || | || 1 0 0 | 1 0 0 | 0 _ _ | _ _ 0 | 1 0 0 | * * 1 || 1 0 | 1 0 | 0 1 | 0 1 | 0 1 |
// +-------+-----++-+-++-------+-------+-------+-------+-------+-------++-----+-----+-----+-----+-----+
// +-------+-----++-+-++-------+-------+-------+-------+-------+-------++-----+-----+-----+-----+-----+
// | 6 | 0 || | || 1 0 0 | _ _ _ | 0 _ _ | _ _ 0 | _ 0 _ | _ 0 _ || 1 * | _ _ | _ _ | 0 1 | _ _ |
// | | 1 || | || 0 _ _ | 0 _ _ | _ _ 0 | _ 0 _ | 0 _ _ | _ _ 0 || * 1 | _ _ | 1 0 | 1 0 | _ _ |
// +-------+-----++-+-++-------+-------+-------+-------+-------+-------++-----+-----+-----+-----+-----+
// | 7 | 0 || | || _ _ 0 | _ 0 _ | _ _ _ | _ _ _ | _ _ _ | 0 _ _ || _ _ | 1 * | _ _ | _ _ | _ _ |
// | | 1 || | || _ 0 _ | _ _ _ | _ 0 _ | 0 _ _ | _ _ _ | 1 0 0 || _ _ | * 1 | _ _ | _ _ | _ _ |
// +-------+-----++-+-++-------+-------+-------+-------+-------+-------++-----+-----+-----+-----+-----+
// | 8 | 0 || | || _ _ _ | _ _ _ | _ _ 0 | _ 0 _ | 0 _ _ | _ _ 0 || _ _ | _ _ | 1 * | _ _ | _ _ |
// | | 1 || | || 1 0 0 | _ _ 0 | 0 _ _ | _ _ 0 | _ 0 _ | _ 0 _ || 1 0 | _ _ | * 1 | 0 1 | _ _ |
// +-------+-----++-+-++-------+-------+-------+-------+-------+-------++-----+-----+-----+-----+-----+
// | 9 | 0 || | || 0 _ _ | 0 _ _ | _ _ 0 | _ 0 _ | 0 _ _ | _ _ 0 || 0 1 | _ _ | 1 0 | 1 * | _ _ |
// | | 1 || | || 1 0 0 | _ _ _ | 0 _ _ | _ _ 0 | _ 0 _ | _ 0 _ || 1 0 | _ _ | _ _ | * 1 | _ _ |
// +-------+-----++-+-++-------+-------+-------+-------+-------+-------++-----+-----+-----+-----+-----+
// | 10 | 0 || | || _ _ _ | _ _ _ | _ _ _ | _ _ _ | _ _ _ | _ _ 0 || _ _ | _ _ | _ _ | _ _ | 1 * |
// | | 1 || | || _ _ _ | _ _ _ | _ _ _ | _ _ _ | _ _ 0 | _ _ _ || _ _ | _ _ | _ _ | _ _ | * 1 |
// +-------+-----++-+-++-------+-------+-------+-------+-------+-------++-----+-----+-----+-----+-----+
>>> ign = sm.set_region(4, 4)
>>> printf(dump_regions(sm.regions))
r0: 0, 4 / r1: 4, 4 / r2: 8, 3 / r3: 11, 0
>>> ign = sm.dump(immediate=True)
// | || P || | || _ _ _ | _ _ _ | _ _ _ | _ _ _ || _ _ _ | _ _ _ | _ _ | _ _ || _ _ | _ _ | _ _ |
// +-------+-----++-+-++-------+-------+-------+-------++-------+-------+-----+-----++-----+-----+-----+
// +-------+-----++-+-++-------+-------+-------+-------++-------+-------+-----+-----++-----+-----+-----+
// | 0 | 0 || | || 1 * * | _ _ _ | 0 _ _ | _ _ 0 || _ 0 _ | _ 0 _ | 1 0 | _ _ || _ _ | 0 1 | _ _ |
// | | 1 || | || * 1 * | 0 0 1 | _ _ 0 | _ 0 _ || 0 _ _ | 0 1 0 | 0 1 | 1 0 || 1 0 | 1 0 | _ _ |
// | | 2 || | || * * 1 | 0 _ _ | 1 0 0 | 0 0 1 || 0 _ _ | 1 0 0 | 0 1 | 0 1 || 1 0 | 1 0 | _ _ |
// +-------+-----++-+-++-------+-------+-------+-------++-------+-------+-----+-----++-----+-----+-----+
// | 1 | 0 || | || 1 0 0 | 1 * * | 0 _ _ | _ _ 0 || _ 0 _ | _ 0 _ | 1 0 | _ _ || _ _ | 0 1 | _ _ |
// | | 1 || | || _ 0 _ | * 1 * | _ 0 _ | 0 _ _ || _ _ _ | 1 0 0 | _ _ | 0 1 || _ _ | _ _ | _ _ |
// | | 2 || | || _ _ _ | * * 1 | _ _ 0 | _ 0 _ || 0 _ _ | _ _ 0 | _ _ | _ _ || 1 0 | _ _ | _ _ |
// +-------+-----++-+-++-------+-------+-------+-------++-------+-------+-----+-----++-----+-----+-----+
// | 2 | 0 || | || 0 _ _ | 0 _ _ | 1 * * | _ 0 _ || 0 _ _ | _ _ 0 | 0 1 | _ _ || 1 0 | 1 0 | _ _ |
// | | 1 || | || _ _ 0 | _ 0 _ | * 1 * | _ _ _ || _ _ _ | 0 _ _ | _ _ | 1 0 || _ _ | _ _ | _ _ |
// | | 2 || | || 1 0 0 | _ _ 0 | * * 1 | _ _ 0 || _ 0 _ | _ 0 _ | 1 0 | _ _ || 0 1 | 0 1 | _ _ |
// +-------+-----++-+-++-------+-------+-------+-------++-------+-------+-----+-----++-----+-----+-----+
// | 3 | 0 || | || _ _ 0 | _ 0 _ | _ _ _ | 1 * * || _ _ _ | 0 _ _ | _ _ | 1 0 || _ _ | _ _ | _ _ |
// | | 1 || | || 1 0 0 | _ _ 0 | 0 _ _ | * 1 * || _ 0 _ | _ 0 _ | 1 0 | _ _ || 0 1 | 0 1 | _ _ |
// | | 2 || | || 0 _ _ | 0 _ _ | _ _ 0 | * * 1 || 0 _ _ | _ _ 0 | 0 1 | _ _ || 1 0 | 1 0 | _ _ |
// +-------+-----++-+-++-------+-------+-------+-------++-------+-------+-----+-----++-----+-----+-----+
// +-------+-----++-+-++-------+-------+-------+-------++-------+-------+-----+-----++-----+-----+-----+
// | 4 | 0 || | || 1 0 0 | _ _ 0 | 0 _ _ | _ _ 0 || 1 * * | _ 0 _ | 1 0 | _ _ || 0 1 | 0 1 | _ _ |
// | | 1 || | || 0 _ _ | 0 _ _ | _ _ 0 | _ 0 _ || * 1 * | _ _ 0 | 0 1 | _ _ || 1 0 | 1 0 | _ _ |
// | | 2 || | || _ _ _ | _ _ _ | _ _ _ | _ _ _ || * * 1 | _ _ 0 | _ _ | _ _ || _ _ | _ _ | 1 0 |
// +-------+-----++-+-++-------+-------+-------+-------++-------+-------+-----+-----++-----+-----+-----+
// | 5 | 0 || | || _ 0 _ | _ _ _ | _ 0 _ | 0 _ _ || _ _ _ | 1 * * | _ _ | 0 1 || _ _ | _ _ | _ _ |
// | | 1 || | || 0 1 0 | 0 0 1 | _ _ 0 | _ 0 _ || 0 _ _ | * 1 * | 0 1 | 1 0 || 1 0 | 1 0 | _ _ |
// | | 2 || | || 1 0 0 | 1 0 0 | 0 _ _ | _ _ 0 || 1 0 0 | * * 1 | 1 0 | 1 0 || 0 1 | 0 1 | 0 1 |
// +-------+-----++-+-++-------+-------+-------+-------++-------+-------+-----+-----++-----+-----+-----+
// | 6 | 0 || | || 1 0 0 | _ _ _ | 0 _ _ | _ _ 0 || _ 0 _ | _ 0 _ | 1 * | _ _ || _ _ | 0 1 | _ _ |
// | | 1 || | || 0 _ _ | 0 _ _ | _ _ 0 | _ 0 _ || 0 _ _ | _ _ 0 | * 1 | _ _ || 1 0 | 1 0 | _ _ |
// +-------+-----++-+-++-------+-------+-------+-------++-------+-------+-----+-----++-----+-----+-----+
// | 7 | 0 || | || _ _ 0 | _ 0 _ | _ _ _ | _ _ _ || _ _ _ | 0 _ _ | _ _ | 1 * || _ _ | _ _ | _ _ |
// | | 1 || | || _ 0 _ | _ _ _ | _ 0 _ | 0 _ _ || _ _ _ | 1 0 0 | _ _ | * 1 || _ _ | _ _ | _ _ |
// +-------+-----++-+-++-------+-------+-------+-------++-------+-------+-----+-----++-----+-----+-----+
// +-------+-----++-+-++-------+-------+-------+-------++-------+-------+-----+-----++-----+-----+-----+
// | 8 | 0 || | || _ _ _ | _ _ _ | _ _ 0 | _ 0 _ || 0 _ _ | _ _ 0 | _ _ | _ _ || 1 * | _ _ | _ _ |
// | | 1 || | || 1 0 0 | _ _ 0 | 0 _ _ | _ _ 0 || _ 0 _ | _ 0 _ | 1 0 | _ _ || * 1 | 0 1 | _ _ |
// +-------+-----++-+-++-------+-------+-------+-------++-------+-------+-----+-----++-----+-----+-----+
// | 9 | 0 || | || 0 _ _ | 0 _ _ | _ _ 0 | _ 0 _ || 0 _ _ | _ _ 0 | 0 1 | _ _ || 1 0 | 1 * | _ _ |
// | | 1 || | || 1 0 0 | _ _ _ | 0 _ _ | _ _ 0 || _ 0 _ | _ 0 _ | 1 0 | _ _ || _ _ | * 1 | _ _ |
// +-------+-----++-+-++-------+-------+-------+-------++-------+-------+-----+-----++-----+-----+-----+
// | 10 | 0 || | || _ _ _ | _ _ _ | _ _ _ | _ _ _ || _ _ _ | _ _ 0 | _ _ | _ _ || _ _ | _ _ | 1 * |
// | | 1 || | || _ _ _ | _ _ _ | _ _ _ | _ _ _ || _ _ 0 | _ _ _ | _ _ | _ _ || _ _ | _ _ | * 1 |
// +-------+-----++-+-++-------+-------+-------+-------++-------+-------+-----+-----++-----+-----+-----+
>>> ign = sm.set_region(4, 4)
>>> printf(dump_regions(sm.regions))
r0: 0, 4 / r1: 4, 4 / r2: 8, 3 / r3: 11, 0
>>> ign = sm.set_region(4, 7)
>>> printf(dump_regions(sm.regions))
r0: 0, 4 / r1: 4, 7 / r2: 11, 0 / r3: 11, 0
>>> ign = sm.set_region(4, 4)
>>> printf(dump_regions(sm.regions))
r0: 0, 4 / r1: 4, 4 / r2: 8, 3 / r3: 11, 0 / r4: 11, 0
>>> ign = sm.set_region(0, 10)
>>> printf(dump_regions(sm.regions))
r0: 0, 10 / r1: 10, 1 / r2: 11, 0 / r3: 11, 0
>>> ign = sm.set_region(0, 11)
>>> printf(dump_regions(sm.regions))
r0: 0, 11 / r1: 11, 0 / r2: 11, 0
>>> ign = sm.set_region(0, 9)
>>> printf(dump_regions(sm.regions))
r0: 0, 9 / r1: 9, 2 / r2: 11, 0 / r3: 11, 0
>>> ign = sm.set_region(4, 4)
>>> printf(dump_regions(sm.regions))
r0: 0, 4 / r1: 4, 4 / r2: 8, 1 / r3: 9, 2 / r4: 11, 0 / r5: 11, 0
>>> ign = sm.set_region(6, 2)
>>> printf(dump_regions(sm.regions))
r0: 0, 4 / r1: 4, 2 / r2: 6, 2 / r3: 8, 1 / r4: 9, 2 / r5: 11, 0 / r6: 11, 0
>>> ign = sm.set_region(4, 4)
>>> printf(dump_regions(sm.regions))
r0: 0, 4 / r1: 4, 4 / r2: 8, 1 / r3: 9, 2 / r4: 11, 0 / r5: 11, 0
>>> ign = sm.set_region(0, 10)
>>> printf(dump_regions(sm.regions))
r0: 0, 10 / r1: 10, 1 / r2: 11, 0 / r3: 11, 0
>>> ign = sm.set_region(4, 20)
>>> printf(dump_regions(sm.regions))
r0: 0, 4 / r1: 4, 7 / r2: 11, 0 / r3: 11, 0
>>> ign = sm.dump(immediate=True)
// | || P || | || _ _ _ | _ _ _ | _ _ _ | _ _ _ || _ _ _ | _ _ _ | _ _ | _ _ | _ _ | _ _ | _ _ |
// +-------+-----++-+-++-------+-------+-------+-------++-------+-------+-----+-----+-----+-----+-----+
// +-------+-----++-+-++-------+-------+-------+-------++-------+-------+-----+-----+-----+-----+-----+
// | 0 | 0 || | || 1 * * | _ _ _ | 0 _ _ | _ _ 0 || _ 0 _ | _ 0 _ | 1 0 | _ _ | _ _ | 0 1 | _ _ |
// | | 1 || | || * 1 * | 0 0 1 | _ _ 0 | _ 0 _ || 0 _ _ | 0 1 0 | 0 1 | 1 0 | 1 0 | 1 0 | _ _ |
// | | 2 || | || * * 1 | 0 _ _ | 1 0 0 | 0 0 1 || 0 _ _ | 1 0 0 | 0 1 | 0 1 | 1 0 | 1 0 | _ _ |
// +-------+-----++-+-++-------+-------+-------+-------++-------+-------+-----+-----+-----+-----+-----+
// | 1 | 0 || | || 1 0 0 | 1 * * | 0 _ _ | _ _ 0 || _ 0 _ | _ 0 _ | 1 0 | _ _ | _ _ | 0 1 | _ _ |
// | | 1 || | || _ 0 _ | * 1 * | _ 0 _ | 0 _ _ || _ _ _ | 1 0 0 | _ _ | 0 1 | _ _ | _ _ | _ _ |
// | | 2 || | || _ _ _ | * * 1 | _ _ 0 | _ 0 _ || 0 _ _ | _ _ 0 | _ _ | _ _ | 1 0 | _ _ | _ _ |
// +-------+-----++-+-++-------+-------+-------+-------++-------+-------+-----+-----+-----+-----+-----+
// | 2 | 0 || | || 0 _ _ | 0 _ _ | 1 * * | _ 0 _ || 0 _ _ | _ _ 0 | 0 1 | _ _ | 1 0 | 1 0 | _ _ |
// | | 1 || | || _ _ 0 | _ 0 _ | * 1 * | _ _ _ || _ _ _ | 0 _ _ | _ _ | 1 0 | _ _ | _ _ | _ _ |
// | | 2 || | || 1 0 0 | _ _ 0 | * * 1 | _ _ 0 || _ 0 _ | _ 0 _ | 1 0 | _ _ | 0 1 | 0 1 | _ _ |
// +-------+-----++-+-++-------+-------+-------+-------++-------+-------+-----+-----+-----+-----+-----+
// | 3 | 0 || | || _ _ 0 | _ 0 _ | _ _ _ | 1 * * || _ _ _ | 0 _ _ | _ _ | 1 0 | _ _ | _ _ | _ _ |
// | | 1 || | || 1 0 0 | _ _ 0 | 0 _ _ | * 1 * || _ 0 _ | _ 0 _ | 1 0 | _ _ | 0 1 | 0 1 | _ _ |
// | | 2 || | || 0 _ _ | 0 _ _ | _ _ 0 | * * 1 || 0 _ _ | _ _ 0 | 0 1 | _ _ | 1 0 | 1 0 | _ _ |
// +-------+-----++-+-++-------+-------+-------+-------++-------+-------+-----+-----+-----+-----+-----+
// +-------+-----++-+-++-------+-------+-------+-------++-------+-------+-----+-----+-----+-----+-----+
// | 4 | 0 || | || 1 0 0 | _ _ 0 | 0 _ _ | _ _ 0 || 1 * * | _ 0 _ | 1 0 | _ _ | 0 1 | 0 1 | _ _ |
// | | 1 || | || 0 _ _ | 0 _ _ | _ _ 0 | _ 0 _ || * 1 * | _ _ 0 | 0 1 | _ _ | 1 0 | 1 0 | _ _ |
// | | 2 || | || _ _ _ | _ _ _ | _ _ _ | _ _ _ || * * 1 | _ _ 0 | _ _ | _ _ | _ _ | _ _ | 1 0 |
// +-------+-----++-+-++-------+-------+-------+-------++-------+-------+-----+-----+-----+-----+-----+
// | 5 | 0 || | || _ 0 _ | _ _ _ | _ 0 _ | 0 _ _ || _ _ _ | 1 * * | _ _ | 0 1 | _ _ | _ _ | _ _ |
// | | 1 || | || 0 1 0 | 0 0 1 | _ _ 0 | _ 0 _ || 0 _ _ | * 1 * | 0 1 | 1 0 | 1 0 | 1 0 | _ _ |
// | | 2 || | || 1 0 0 | 1 0 0 | 0 _ _ | _ _ 0 || 1 0 0 | * * 1 | 1 0 | 1 0 | 0 1 | 0 1 | 0 1 |
// +-------+-----++-+-++-------+-------+-------+-------++-------+-------+-----+-----+-----+-----+-----+
// | 6 | 0 || | || 1 0 0 | _ _ _ | 0 _ _ | _ _ 0 || _ 0 _ | _ 0 _ | 1 * | _ _ | _ _ | 0 1 | _ _ |
// | | 1 || | || 0 _ _ | 0 _ _ | _ _ 0 | _ 0 _ || 0 _ _ | _ _ 0 | * 1 | _ _ | 1 0 | 1 0 | _ _ |
// +-------+-----++-+-++-------+-------+-------+-------++-------+-------+-----+-----+-----+-----+-----+
// | 7 | 0 || | || _ _ 0 | _ 0 _ | _ _ _ | _ _ _ || _ _ _ | 0 _ _ | _ _ | 1 * | _ _ | _ _ | _ _ |
// | | 1 || | || _ 0 _ | _ _ _ | _ 0 _ | 0 _ _ || _ _ _ | 1 0 0 | _ _ | * 1 | _ _ | _ _ | _ _ |
// +-------+-----++-+-++-------+-------+-------+-------++-------+-------+-----+-----+-----+-----+-----+
// | 8 | 0 || | || _ _ _ | _ _ _ | _ _ 0 | _ 0 _ || 0 _ _ | _ _ 0 | _ _ | _ _ | 1 * | _ _ | _ _ |
// | | 1 || | || 1 0 0 | _ _ 0 | 0 _ _ | _ _ 0 || _ 0 _ | _ 0 _ | 1 0 | _ _ | * 1 | 0 1 | _ _ |
// +-------+-----++-+-++-------+-------+-------+-------++-------+-------+-----+-----+-----+-----+-----+
// | 9 | 0 || | || 0 _ _ | 0 _ _ | _ _ 0 | _ 0 _ || 0 _ _ | _ _ 0 | 0 1 | _ _ | 1 0 | 1 * | _ _ |
// | | 1 || | || 1 0 0 | _ _ _ | 0 _ _ | _ _ 0 || _ 0 _ | _ 0 _ | 1 0 | _ _ | _ _ | * 1 | _ _ |
// +-------+-----++-+-++-------+-------+-------+-------++-------+-------+-----+-----+-----+-----+-----+
// | 10 | 0 || | || _ _ _ | _ _ _ | _ _ _ | _ _ _ || _ _ _ | _ _ 0 | _ _ | _ _ | _ _ | _ _ | 1 * |
// | | 1 || | || _ _ _ | _ _ _ | _ _ _ | _ _ _ || _ _ 0 | _ _ _ | _ _ | _ _ | _ _ | _ _ | * 1 |
// +-------+-----++-+-++-------+-------+-------+-------++-------+-------+-----+-----+-----+-----+-----+
"""
# drop, if region is out of bounds or empty
climit = len(self.clauses)
if ofs < 0 or ofs >= climit:
return self
if ofs + size > climit:
size = climit - ofs
if not size:
return self
region = SMRegion(ofs, size)
ofs = region.ofs
size = region.size
limit = ofs + size
# |:here:|
regions = self.regions
nregions = []
for indx, xregion in enumerate(regions):
if limit < 0:
# finished with region manipulation
nregions.extend(regions[indx:])
break
if xregion.ofs <= ofs:
xlimit = xregion.ofs + xregion.size
if xlimit <= ofs:
# region entirely below new region
nregions.append(xregion)
continue
xregion.size = ofs - xregion.ofs
if xregion.ofs == ofs:
xregion.size = size
region = xregion
else:
nregions.append(xregion)
nregions.append(region)
if limit < xlimit:
# fill up to next region
nregions.append(SMRegion(limit, xlimit - limit))
if limit <= xlimit:
limit = -1 # done
continue
if xregion.ofs == limit:
nregions.append(xregion)
limit = -1 # done
continue
# xregion must be partially covered by new region
if xregion.ofs > limit:
raise SatokuError(sformat('set_region: xregion.ofs: {0} limit: {1}', xregion.ofs, limit))
if xregion.ofs + size == limit:
# still covered by new region, but next region is above
limit = -1
if xregion.ofs + size <= limit:
# still covered by new region
xregion.ofs = limit
xregion.size = 0
nregions.append(xregion)
continue
xregion.size -= limit - xregion.ofs
xregion.ofs = limit
if xregion.size > 0:
limit = -1 # done
else:
xregion.size = 0
nregions.append(xregion)
if not keep_empty:
sys_regions = (self.variables, self.synthesized)
nregions = [_r for _r in nregions if _r.size or _r in sys_regions]
self.regions = nregions
return self
[docs] def rebuild_clauses_and_maps(self, reason=None): # |:mth:|
"""Rebuild clauses and clause maps."""
# rebuild clauses + clause maps
clauses = self.clauses
ofs = 0
clause_offsets = []
clause_sizes = []
row_clause_map = []
row_literal_map = []
self.clause_offsets = clause_offsets
self.clause_sizes = clause_sizes
self.row_clause_map = row_clause_map
self.row_literal_map = row_literal_map
for indx, csm in enumerate(clauses):
csm.indx = indx
csm.ofs = ofs
cell_size = csm.size
clause_offsets.append(ofs)
clause_sizes.append(cell_size)
row_clause_map.extend([indx for i in xrange(cell_size)])
row_literal_map.extend([i for i in xrange(cell_size)])
ofs += cell_size
if cell_size < 2:
pass
#raise ValueError(sformat('state[{0}] size ({1}) < 2 {2}', indx, cell_size, reason or ''))
[docs] def delete_rows(self, si, sj, sx): # |:mth:|
"""Delete rows from a clause.
:returns: self for chaining.
:param si: cell index
:param sj: start row offset.
:param sx: end row offset.
>>> pr = Problem()
>>> cv = ClauseVector('1 1 1')
>>> pr.extend([cv.copy() for i in xrange(2 + 3)])
>>> cv = ClauseVector('1 1 1 1')
>>> pr.extend([cv.copy() for i in xrange(5)])
>>> cv = ClauseVector('1 1 1 1 1 1')
>>> pr.extend([cv.copy() for i in xrange(2)])
>>> sm = SatokuMatrix(pr)
>>> ign = sm.set_region(0, 2)
>>> ign = sm.set_region(2, 3)
>>> ign = sm.set_region(5, 5)
>>> ign = sm.set_region(10, 2)
>>> printf(dump_regions(sm.regions))
r0: 0, 2 / r1: 2, 3 / r2: 5, 5 / r3: 10, 2 / r4: 12, 0 / r5: 12, 0
>>> ign = sm.zero_change(0, 0, 1, 0, immediate=None)
>>> ign = sm.zero_change(0, 1, 2, 1, immediate=None)
>>> ign = sm.zero_change(0, 2, 3, 2, immediate=None)
>>> ign = sm.zero_change(1, 0, 2, 0, immediate=None)
>>> ign = sm.zero_change(1, 1, 3, 1, immediate=None)
>>> ign = sm.zero_change(1, 2, 4, 2, immediate=None)
>>> ign = sm.delete_rows( 0, 0, 1)
>>> ign = sm.delete_rows( 1, 0, 1)
>>> ign = sm.delete_rows(10, 0, 1)
>>> smt = sm.copy()
>>> ign = smt.dump(immediate=True)
// | || P || | || _ _ | _ _ || _ _ _ | _ _ _ | _ _ _ || _ _ _ _ | _ _ _ _ | _ _ _ _ | _ _ _ _ | _ _ _ _ || _ _ _ _ _ | _ _ _ _ _ _ |
// +-------+-----++-+-++-----+-----++-------+-------+-------++---------+---------+---------+---------+---------++-----------+-------------+
// +-------+-----++-+-++-----+-----++-------+-------+-------++---------+---------+---------+---------+---------++-----------+-------------+
// | 0 | 0 || | || 1 * | _ _ || _ 0 _ | _ _ _ | _ _ _ || _ _ _ _ | _ _ _ _ | _ _ _ _ | _ _ _ _ | _ _ _ _ || _ _ _ _ _ | _ _ _ _ _ _ |
// | | 1 || | || * 1 | _ _ || _ _ _ | _ _ 0 | _ _ _ || _ _ _ _ | _ _ _ _ | _ _ _ _ | _ _ _ _ | _ _ _ _ || _ _ _ _ _ | _ _ _ _ _ _ |
// +-------+-----++-+-++-----+-----++-------+-------+-------++---------+---------+---------+---------+---------++-----------+-------------+
// | 1 | 0 || | || _ _ | 1 * || _ _ _ | _ 0 _ | _ _ _ || _ _ _ _ | _ _ _ _ | _ _ _ _ | _ _ _ _ | _ _ _ _ || _ _ _ _ _ | _ _ _ _ _ _ |
// | | 1 || | || _ _ | * 1 || _ _ _ | _ _ _ | _ _ 0 || _ _ _ _ | _ _ _ _ | _ _ _ _ | _ _ _ _ | _ _ _ _ || _ _ _ _ _ | _ _ _ _ _ _ |
// +-------+-----++-+-++-----+-----++-------+-------+-------++---------+---------+---------+---------+---------++-----------+-------------+
// +-------+-----++-+-++-----+-----++-------+-------+-------++---------+---------+---------+---------+---------++-----------+-------------+
// | 2 | 0 || | || _ _ | _ _ || 1 * * | _ _ _ | _ _ _ || _ _ _ _ | _ _ _ _ | _ _ _ _ | _ _ _ _ | _ _ _ _ || _ _ _ _ _ | _ _ _ _ _ _ |
// | | 1 || | || _ _ | _ _ || * 1 * | _ _ _ | _ _ _ || _ _ _ _ | _ _ _ _ | _ _ _ _ | _ _ _ _ | _ _ _ _ || _ _ _ _ _ | _ _ _ _ _ _ |
// | | 2 || | || _ _ | _ _ || * * 1 | _ _ _ | _ _ _ || _ _ _ _ | _ _ _ _ | _ _ _ _ | _ _ _ _ | _ _ _ _ || _ _ _ _ _ | _ _ _ _ _ _ |
// +-------+-----++-+-++-----+-----++-------+-------+-------++---------+---------+---------+---------+---------++-----------+-------------+
// | 3 | 0 || | || _ _ | _ _ || _ _ _ | 1 * * | _ _ _ || _ _ _ _ | _ _ _ _ | _ _ _ _ | _ _ _ _ | _ _ _ _ || _ _ _ _ _ | _ _ _ _ _ _ |
// | | 1 || | || _ _ | _ _ || _ _ _ | * 1 * | _ _ _ || _ _ _ _ | _ _ _ _ | _ _ _ _ | _ _ _ _ | _ _ _ _ || _ _ _ _ _ | _ _ _ _ _ _ |
// | | 2 || | || _ _ | _ _ || _ _ _ | * * 1 | _ _ _ || _ _ _ _ | _ _ _ _ | _ _ _ _ | _ _ _ _ | _ _ _ _ || _ _ _ _ _ | _ _ _ _ _ _ |
// +-------+-----++-+-++-----+-----++-------+-------+-------++---------+---------+---------+---------+---------++-----------+-------------+
// | 4 | 0 || | || _ _ | _ _ || _ _ _ | _ _ _ | 1 * * || _ _ _ _ | _ _ _ _ | _ _ _ _ | _ _ _ _ | _ _ _ _ || _ _ _ _ _ | _ _ _ _ _ _ |
// | | 1 || | || _ _ | _ _ || _ _ _ | _ _ _ | * 1 * || _ _ _ _ | _ _ _ _ | _ _ _ _ | _ _ _ _ | _ _ _ _ || _ _ _ _ _ | _ _ _ _ _ _ |
// | | 2 || | || _ _ | _ _ || _ _ _ | _ _ _ | * * 1 || _ _ _ _ | _ _ _ _ | _ _ _ _ | _ _ _ _ | _ _ _ _ || _ _ _ _ _ | _ _ _ _ _ _ |
// +-------+-----++-+-++-----+-----++-------+-------+-------++---------+---------+---------+---------+---------++-----------+-------------+
// +-------+-----++-+-++-----+-----++-------+-------+-------++---------+---------+---------+---------+---------++-----------+-------------+
// | 5 | 0 || | || _ _ | _ _ || _ _ _ | _ _ _ | _ _ _ || 1 * * * | _ _ _ _ | _ _ _ _ | _ _ _ _ | _ _ _ _ || _ _ _ _ _ | _ _ _ _ _ _ |
// | | 1 || | || _ _ | _ _ || _ _ _ | _ _ _ | _ _ _ || * 1 * * | _ _ _ _ | _ _ _ _ | _ _ _ _ | _ _ _ _ || _ _ _ _ _ | _ _ _ _ _ _ |
// | | 2 || | || _ _ | _ _ || _ _ _ | _ _ _ | _ _ _ || * * 1 * | _ _ _ _ | _ _ _ _ | _ _ _ _ | _ _ _ _ || _ _ _ _ _ | _ _ _ _ _ _ |
// | | 3 || | || _ _ | _ _ || _ _ _ | _ _ _ | _ _ _ || * * * 1 | _ _ _ _ | _ _ _ _ | _ _ _ _ | _ _ _ _ || _ _ _ _ _ | _ _ _ _ _ _ |
// +-------+-----++-+-++-----+-----++-------+-------+-------++---------+---------+---------+---------+---------++-----------+-------------+
// | 6 | 0 || | || _ _ | _ _ || _ _ _ | _ _ _ | _ _ _ || _ _ _ _ | 1 * * * | _ _ _ _ | _ _ _ _ | _ _ _ _ || _ _ _ _ _ | _ _ _ _ _ _ |
// | | 1 || | || _ _ | _ _ || _ _ _ | _ _ _ | _ _ _ || _ _ _ _ | * 1 * * | _ _ _ _ | _ _ _ _ | _ _ _ _ || _ _ _ _ _ | _ _ _ _ _ _ |
// | | 2 || | || _ _ | _ _ || _ _ _ | _ _ _ | _ _ _ || _ _ _ _ | * * 1 * | _ _ _ _ | _ _ _ _ | _ _ _ _ || _ _ _ _ _ | _ _ _ _ _ _ |
// | | 3 || | || _ _ | _ _ || _ _ _ | _ _ _ | _ _ _ || _ _ _ _ | * * * 1 | _ _ _ _ | _ _ _ _ | _ _ _ _ || _ _ _ _ _ | _ _ _ _ _ _ |
// +-------+-----++-+-++-----+-----++-------+-------+-------++---------+---------+---------+---------+---------++-----------+-------------+
// | 7 | 0 || | || _ _ | _ _ || _ _ _ | _ _ _ | _ _ _ || _ _ _ _ | _ _ _ _ | 1 * * * | _ _ _ _ | _ _ _ _ || _ _ _ _ _ | _ _ _ _ _ _ |
// | | 1 || | || _ _ | _ _ || _ _ _ | _ _ _ | _ _ _ || _ _ _ _ | _ _ _ _ | * 1 * * | _ _ _ _ | _ _ _ _ || _ _ _ _ _ | _ _ _ _ _ _ |
// | | 2 || | || _ _ | _ _ || _ _ _ | _ _ _ | _ _ _ || _ _ _ _ | _ _ _ _ | * * 1 * | _ _ _ _ | _ _ _ _ || _ _ _ _ _ | _ _ _ _ _ _ |
// | | 3 || | || _ _ | _ _ || _ _ _ | _ _ _ | _ _ _ || _ _ _ _ | _ _ _ _ | * * * 1 | _ _ _ _ | _ _ _ _ || _ _ _ _ _ | _ _ _ _ _ _ |
// +-------+-----++-+-++-----+-----++-------+-------+-------++---------+---------+---------+---------+---------++-----------+-------------+
// | 8 | 0 || | || _ _ | _ _ || _ _ _ | _ _ _ | _ _ _ || _ _ _ _ | _ _ _ _ | _ _ _ _ | 1 * * * | _ _ _ _ || _ _ _ _ _ | _ _ _ _ _ _ |
// | | 1 || | || _ _ | _ _ || _ _ _ | _ _ _ | _ _ _ || _ _ _ _ | _ _ _ _ | _ _ _ _ | * 1 * * | _ _ _ _ || _ _ _ _ _ | _ _ _ _ _ _ |
// | | 2 || | || _ _ | _ _ || _ _ _ | _ _ _ | _ _ _ || _ _ _ _ | _ _ _ _ | _ _ _ _ | * * 1 * | _ _ _ _ || _ _ _ _ _ | _ _ _ _ _ _ |
// | | 3 || | || _ _ | _ _ || _ _ _ | _ _ _ | _ _ _ || _ _ _ _ | _ _ _ _ | _ _ _ _ | * * * 1 | _ _ _ _ || _ _ _ _ _ | _ _ _ _ _ _ |
// +-------+-----++-+-++-----+-----++-------+-------+-------++---------+---------+---------+---------+---------++-----------+-------------+
// | 9 | 0 || | || _ _ | _ _ || _ _ _ | _ _ _ | _ _ _ || _ _ _ _ | _ _ _ _ | _ _ _ _ | _ _ _ _ | 1 * * * || _ _ _ _ _ | _ _ _ _ _ _ |
// | | 1 || | || _ _ | _ _ || _ _ _ | _ _ _ | _ _ _ || _ _ _ _ | _ _ _ _ | _ _ _ _ | _ _ _ _ | * 1 * * || _ _ _ _ _ | _ _ _ _ _ _ |
// | | 2 || | || _ _ | _ _ || _ _ _ | _ _ _ | _ _ _ || _ _ _ _ | _ _ _ _ | _ _ _ _ | _ _ _ _ | * * 1 * || _ _ _ _ _ | _ _ _ _ _ _ |
// | | 3 || | || _ _ | _ _ || _ _ _ | _ _ _ | _ _ _ || _ _ _ _ | _ _ _ _ | _ _ _ _ | _ _ _ _ | * * * 1 || _ _ _ _ _ | _ _ _ _ _ _ |
// +-------+-----++-+-++-----+-----++-------+-------+-------++---------+---------+---------+---------+---------++-----------+-------------+
// +-------+-----++-+-++-----+-----++-------+-------+-------++---------+---------+---------+---------+---------++-----------+-------------+
// | 10 | 0 || | || _ _ | _ _ || _ _ _ | _ _ _ | _ _ _ || _ _ _ _ | _ _ _ _ | _ _ _ _ | _ _ _ _ | _ _ _ _ || 1 * * * * | _ _ _ _ _ _ |
// | | 1 || | || _ _ | _ _ || _ _ _ | _ _ _ | _ _ _ || _ _ _ _ | _ _ _ _ | _ _ _ _ | _ _ _ _ | _ _ _ _ || * 1 * * * | _ _ _ _ _ _ |
// | | 2 || | || _ _ | _ _ || _ _ _ | _ _ _ | _ _ _ || _ _ _ _ | _ _ _ _ | _ _ _ _ | _ _ _ _ | _ _ _ _ || * * 1 * * | _ _ _ _ _ _ |
// | | 3 || | || _ _ | _ _ || _ _ _ | _ _ _ | _ _ _ || _ _ _ _ | _ _ _ _ | _ _ _ _ | _ _ _ _ | _ _ _ _ || * * * 1 * | _ _ _ _ _ _ |
// | | 4 || | || _ _ | _ _ || _ _ _ | _ _ _ | _ _ _ || _ _ _ _ | _ _ _ _ | _ _ _ _ | _ _ _ _ | _ _ _ _ || * * * * 1 | _ _ _ _ _ _ |
// +-------+-----++-+-++-----+-----++-------+-------+-------++---------+---------+---------+---------+---------++-----------+-------------+
// | 11 | 0 || | || _ _ | _ _ || _ _ _ | _ _ _ | _ _ _ || _ _ _ _ | _ _ _ _ | _ _ _ _ | _ _ _ _ | _ _ _ _ || _ _ _ _ _ | 1 * * * * * |
// | | 1 || | || _ _ | _ _ || _ _ _ | _ _ _ | _ _ _ || _ _ _ _ | _ _ _ _ | _ _ _ _ | _ _ _ _ | _ _ _ _ || _ _ _ _ _ | * 1 * * * * |
// | | 2 || | || _ _ | _ _ || _ _ _ | _ _ _ | _ _ _ || _ _ _ _ | _ _ _ _ | _ _ _ _ | _ _ _ _ | _ _ _ _ || _ _ _ _ _ | * * 1 * * * |
// | | 3 || | || _ _ | _ _ || _ _ _ | _ _ _ | _ _ _ || _ _ _ _ | _ _ _ _ | _ _ _ _ | _ _ _ _ | _ _ _ _ || _ _ _ _ _ | * * * 1 * * |
// | | 4 || | || _ _ | _ _ || _ _ _ | _ _ _ | _ _ _ || _ _ _ _ | _ _ _ _ | _ _ _ _ | _ _ _ _ | _ _ _ _ || _ _ _ _ _ | * * * * 1 * |
// | | 5 || | || _ _ | _ _ || _ _ _ | _ _ _ | _ _ _ || _ _ _ _ | _ _ _ _ | _ _ _ _ | _ _ _ _ | _ _ _ _ || _ _ _ _ _ | * * * * * 1 |
// +-------+-----++-+-++-----+-----++-------+-------+-------++---------+---------+---------+---------+---------++-----------+-------------+
- case 1: zero line at beginning of 2-state
>>> ign = smt.kill_row(0, 0)
- case 2: zero line at end of 2-state
>>> ign = smt.kill_row(1, 1)
- case 3: 2 zero lines at beginning of 3-state
>>> ign = smt.kill_row(2, 0)
>>> ign = smt.kill_row(2, 1)
- case 4: 2 zero lines at end of 3-state
>>> ign = smt.kill_row(3, 1)
>>> ign = smt.kill_row(3, 2)
- case 5: 1 zero lines at beg. of 3-state, 1 zero lines at end of 3-state
>>> ign = smt.kill_row(4, 0)
>>> ign = smt.kill_row(4, 2)
- case 6: 2 zero lines at beginning of 4-state
>>> ign = smt.kill_row(5, 0)
>>> ign = smt.kill_row(5, 1)
- case 7: 2 zero lines at end of 4-state
>>> ign = smt.kill_row(6, 2)
>>> ign = smt.kill_row(6, 3)
- case 8: 2 zero lines in the middle of 4-state
>>> ign = smt.kill_row(7, 1)
>>> ign = smt.kill_row(7, 2)
- case 9: 2 zero lines at beginning of 4-state, 1 at end
>>> ign = smt.kill_row(8, 0)
>>> ign = smt.kill_row(8, 1)
>>> ign = smt.kill_row(8, 3)
- case 10: 2 zero lines at end of 4-state, 1 at beg.
>>> ign = smt.kill_row(9, 0)
>>> ign = smt.kill_row(9, 2)
>>> ign = smt.kill_row(9, 3)
- case 11: 2 zero lines at beginning of 5-state + 2 at end
>>> ign = smt.kill_row(10, 0)
>>> ign = smt.kill_row(10, 1)
>>> ign = smt.kill_row(10, 3)
>>> ign = smt.kill_row(10, 4)
- case 12: 2 zero lines at beginning of 6-state + 2 at end
>>> ign = smt.kill_row(11, 0)
>>> ign = smt.kill_row(11, 1)
>>> ign = smt.kill_row(11, 4)
>>> ign = smt.kill_row(11, 5)
>>> ign = smt.dump(immediate=True)
// | || P || | || 0 1 | 1 0 || 0 0 1 | 1 0 0 | 0 1 0 || 0 0 _ _ | _ _ 0 0 | _ 0 0 _ | 0 0 1 0 | 0 1 0 0 || 0 0 1 0 0 | 0 0 _ _ 0 0 |
// +-------+-----++-+-++-----+-----++-------+-------+-------++---------+---------+---------+---------+---------++-----------+-------------+
// +-------+-----++-+-++-----+-----++-------+-------+-------++---------+---------+---------+---------+---------++-----------+-------------+
// | 0 | 0 || | || 1 * | 0 0 || 0 0 0 | 0 0 0 | 0 0 0 || 0 0 0 0 | 0 0 0 0 | 0 0 0 0 | 0 0 0 0 | 0 0 0 0 || 0 0 0 0 0 | 0 0 0 0 0 0 |
// | | 1 || | || * 1 | _ 0 || 0 0 _ | _ 0 0 | 0 _ 0 || 0 0 _ _ | _ _ 0 0 | _ 0 0 _ | 0 0 _ 0 | 0 _ 0 0 || 0 0 _ 0 0 | 0 0 _ _ 0 0 |
// +-------+-----++-+-++-----+-----++-------+-------+-------++---------+---------+---------+---------+---------++-----------+-------------+
// | 1 | 0 || | || 0 _ | 1 * || 0 0 _ | _ 0 0 | 0 _ 0 || 0 0 _ _ | _ _ 0 0 | _ 0 0 _ | 0 0 _ 0 | 0 _ 0 0 || 0 0 _ 0 0 | 0 0 _ _ 0 0 |
// | | 1 || | || 0 0 | * 1 || 0 0 0 | 0 0 0 | 0 0 0 || 0 0 0 0 | 0 0 0 0 | 0 0 0 0 | 0 0 0 0 | 0 0 0 0 || 0 0 0 0 0 | 0 0 0 0 0 0 |
// +-------+-----++-+-++-----+-----++-------+-------+-------++---------+---------+---------+---------+---------++-----------+-------------+
// +-------+-----++-+-++-----+-----++-------+-------+-------++---------+---------+---------+---------+---------++-----------+-------------+
// | 2 | 0 || | || 0 0 | 0 0 || 1 * * | 0 0 0 | 0 0 0 || 0 0 0 0 | 0 0 0 0 | 0 0 0 0 | 0 0 0 0 | 0 0 0 0 || 0 0 0 0 0 | 0 0 0 0 0 0 |
// | | 1 || | || 0 0 | 0 0 || * 1 * | 0 0 0 | 0 0 0 || 0 0 0 0 | 0 0 0 0 | 0 0 0 0 | 0 0 0 0 | 0 0 0 0 || 0 0 0 0 0 | 0 0 0 0 0 0 |
// | | 2 || | || 0 _ | _ 0 || * * 1 | _ 0 0 | 0 _ 0 || 0 0 _ _ | _ _ 0 0 | _ 0 0 _ | 0 0 _ 0 | 0 _ 0 0 || 0 0 _ 0 0 | 0 0 _ _ 0 0 |
// +-------+-----++-+-++-----+-----++-------+-------+-------++---------+---------+---------+---------+---------++-----------+-------------+
// | 3 | 0 || | || 0 _ | _ 0 || 0 0 _ | 1 * * | 0 _ 0 || 0 0 _ _ | _ _ 0 0 | _ 0 0 _ | 0 0 _ 0 | 0 _ 0 0 || 0 0 _ 0 0 | 0 0 _ _ 0 0 |
// | | 1 || | || 0 0 | 0 0 || 0 0 0 | * 1 * | 0 0 0 || 0 0 0 0 | 0 0 0 0 | 0 0 0 0 | 0 0 0 0 | 0 0 0 0 || 0 0 0 0 0 | 0 0 0 0 0 0 |
// | | 2 || | || 0 0 | 0 0 || 0 0 0 | * * 1 | 0 0 0 || 0 0 0 0 | 0 0 0 0 | 0 0 0 0 | 0 0 0 0 | 0 0 0 0 || 0 0 0 0 0 | 0 0 0 0 0 0 |
// +-------+-----++-+-++-----+-----++-------+-------+-------++---------+---------+---------+---------+---------++-----------+-------------+
// | 4 | 0 || | || 0 0 | 0 0 || 0 0 0 | 0 0 0 | 1 * * || 0 0 0 0 | 0 0 0 0 | 0 0 0 0 | 0 0 0 0 | 0 0 0 0 || 0 0 0 0 0 | 0 0 0 0 0 0 |
// | | 1 || | || 0 _ | _ 0 || 0 0 _ | _ 0 0 | * 1 * || 0 0 _ _ | _ _ 0 0 | _ 0 0 _ | 0 0 _ 0 | 0 _ 0 0 || 0 0 _ 0 0 | 0 0 _ _ 0 0 |
// | | 2 || | || 0 0 | 0 0 || 0 0 0 | 0 0 0 | * * 1 || 0 0 0 0 | 0 0 0 0 | 0 0 0 0 | 0 0 0 0 | 0 0 0 0 || 0 0 0 0 0 | 0 0 0 0 0 0 |
// +-------+-----++-+-++-----+-----++-------+-------+-------++---------+---------+---------+---------+---------++-----------+-------------+
// +-------+-----++-+-++-----+-----++-------+-------+-------++---------+---------+---------+---------+---------++-----------+-------------+
// | 5 | 0 || | || 0 0 | 0 0 || 0 0 0 | 0 0 0 | 0 0 0 || 1 * * * | 0 0 0 0 | 0 0 0 0 | 0 0 0 0 | 0 0 0 0 || 0 0 0 0 0 | 0 0 0 0 0 0 |
// | | 1 || | || 0 0 | 0 0 || 0 0 0 | 0 0 0 | 0 0 0 || * 1 * * | 0 0 0 0 | 0 0 0 0 | 0 0 0 0 | 0 0 0 0 || 0 0 0 0 0 | 0 0 0 0 0 0 |
// | | 2 || | || 0 _ | _ 0 || 0 0 _ | _ 0 0 | 0 _ 0 || * * 1 * | _ _ 0 0 | _ 0 0 _ | 0 0 _ 0 | 0 _ 0 0 || 0 0 _ 0 0 | 0 0 _ _ 0 0 |
// | | 3 || | || 0 _ | _ 0 || 0 0 _ | _ 0 0 | 0 _ 0 || * * * 1 | _ _ 0 0 | _ 0 0 _ | 0 0 _ 0 | 0 _ 0 0 || 0 0 _ 0 0 | 0 0 _ _ 0 0 |
// +-------+-----++-+-++-----+-----++-------+-------+-------++---------+---------+---------+---------+---------++-----------+-------------+
// | 6 | 0 || | || 0 _ | _ 0 || 0 0 _ | _ 0 0 | 0 _ 0 || 0 0 _ _ | 1 * * * | _ 0 0 _ | 0 0 _ 0 | 0 _ 0 0 || 0 0 _ 0 0 | 0 0 _ _ 0 0 |
// | | 1 || | || 0 _ | _ 0 || 0 0 _ | _ 0 0 | 0 _ 0 || 0 0 _ _ | * 1 * * | _ 0 0 _ | 0 0 _ 0 | 0 _ 0 0 || 0 0 _ 0 0 | 0 0 _ _ 0 0 |
// | | 2 || | || 0 0 | 0 0 || 0 0 0 | 0 0 0 | 0 0 0 || 0 0 0 0 | * * 1 * | 0 0 0 0 | 0 0 0 0 | 0 0 0 0 || 0 0 0 0 0 | 0 0 0 0 0 0 |
// | | 3 || | || 0 0 | 0 0 || 0 0 0 | 0 0 0 | 0 0 0 || 0 0 0 0 | * * * 1 | 0 0 0 0 | 0 0 0 0 | 0 0 0 0 || 0 0 0 0 0 | 0 0 0 0 0 0 |
// +-------+-----++-+-++-----+-----++-------+-------+-------++---------+---------+---------+---------+---------++-----------+-------------+
// | 7 | 0 || | || 0 _ | _ 0 || 0 0 _ | _ 0 0 | 0 _ 0 || 0 0 _ _ | _ _ 0 0 | 1 * * * | 0 0 _ 0 | 0 _ 0 0 || 0 0 _ 0 0 | 0 0 _ _ 0 0 |
// | | 1 || | || 0 0 | 0 0 || 0 0 0 | 0 0 0 | 0 0 0 || 0 0 0 0 | 0 0 0 0 | * 1 * * | 0 0 0 0 | 0 0 0 0 || 0 0 0 0 0 | 0 0 0 0 0 0 |
// | | 2 || | || 0 0 | 0 0 || 0 0 0 | 0 0 0 | 0 0 0 || 0 0 0 0 | 0 0 0 0 | * * 1 * | 0 0 0 0 | 0 0 0 0 || 0 0 0 0 0 | 0 0 0 0 0 0 |
// | | 3 || | || 0 _ | _ 0 || 0 0 _ | _ 0 0 | 0 _ 0 || 0 0 _ _ | _ _ 0 0 | * * * 1 | 0 0 _ 0 | 0 _ 0 0 || 0 0 _ 0 0 | 0 0 _ _ 0 0 |
// +-------+-----++-+-++-----+-----++-------+-------+-------++---------+---------+---------+---------+---------++-----------+-------------+
// | 8 | 0 || | || 0 0 | 0 0 || 0 0 0 | 0 0 0 | 0 0 0 || 0 0 0 0 | 0 0 0 0 | 0 0 0 0 | 1 * * * | 0 0 0 0 || 0 0 0 0 0 | 0 0 0 0 0 0 |
// | | 1 || | || 0 0 | 0 0 || 0 0 0 | 0 0 0 | 0 0 0 || 0 0 0 0 | 0 0 0 0 | 0 0 0 0 | * 1 * * | 0 0 0 0 || 0 0 0 0 0 | 0 0 0 0 0 0 |
// | | 2 || | || 0 _ | _ 0 || 0 0 _ | _ 0 0 | 0 _ 0 || 0 0 _ _ | _ _ 0 0 | _ 0 0 _ | * * 1 * | 0 _ 0 0 || 0 0 _ 0 0 | 0 0 _ _ 0 0 |
// | | 3 || | || 0 0 | 0 0 || 0 0 0 | 0 0 0 | 0 0 0 || 0 0 0 0 | 0 0 0 0 | 0 0 0 0 | * * * 1 | 0 0 0 0 || 0 0 0 0 0 | 0 0 0 0 0 0 |
// +-------+-----++-+-++-----+-----++-------+-------+-------++---------+---------+---------+---------+---------++-----------+-------------+
// | 9 | 0 || | || 0 0 | 0 0 || 0 0 0 | 0 0 0 | 0 0 0 || 0 0 0 0 | 0 0 0 0 | 0 0 0 0 | 0 0 0 0 | 1 * * * || 0 0 0 0 0 | 0 0 0 0 0 0 |
// | | 1 || | || 0 _ | _ 0 || 0 0 _ | _ 0 0 | 0 _ 0 || 0 0 _ _ | _ _ 0 0 | _ 0 0 _ | 0 0 _ 0 | * 1 * * || 0 0 _ 0 0 | 0 0 _ _ 0 0 |
// | | 2 || | || 0 0 | 0 0 || 0 0 0 | 0 0 0 | 0 0 0 || 0 0 0 0 | 0 0 0 0 | 0 0 0 0 | 0 0 0 0 | * * 1 * || 0 0 0 0 0 | 0 0 0 0 0 0 |
// | | 3 || | || 0 0 | 0 0 || 0 0 0 | 0 0 0 | 0 0 0 || 0 0 0 0 | 0 0 0 0 | 0 0 0 0 | 0 0 0 0 | * * * 1 || 0 0 0 0 0 | 0 0 0 0 0 0 |
// +-------+-----++-+-++-----+-----++-------+-------+-------++---------+---------+---------+---------+---------++-----------+-------------+
// +-------+-----++-+-++-----+-----++-------+-------+-------++---------+---------+---------+---------+---------++-----------+-------------+
// | 10 | 0 || | || 0 0 | 0 0 || 0 0 0 | 0 0 0 | 0 0 0 || 0 0 0 0 | 0 0 0 0 | 0 0 0 0 | 0 0 0 0 | 0 0 0 0 || 1 * * * * | 0 0 0 0 0 0 |
// | | 1 || | || 0 0 | 0 0 || 0 0 0 | 0 0 0 | 0 0 0 || 0 0 0 0 | 0 0 0 0 | 0 0 0 0 | 0 0 0 0 | 0 0 0 0 || * 1 * * * | 0 0 0 0 0 0 |
// | | 2 || | || 0 _ | _ 0 || 0 0 _ | _ 0 0 | 0 _ 0 || 0 0 _ _ | _ _ 0 0 | _ 0 0 _ | 0 0 _ 0 | 0 _ 0 0 || * * 1 * * | 0 0 _ _ 0 0 |
// | | 3 || | || 0 0 | 0 0 || 0 0 0 | 0 0 0 | 0 0 0 || 0 0 0 0 | 0 0 0 0 | 0 0 0 0 | 0 0 0 0 | 0 0 0 0 || * * * 1 * | 0 0 0 0 0 0 |
// | | 4 || | || 0 0 | 0 0 || 0 0 0 | 0 0 0 | 0 0 0 || 0 0 0 0 | 0 0 0 0 | 0 0 0 0 | 0 0 0 0 | 0 0 0 0 || * * * * 1 | 0 0 0 0 0 0 |
// +-------+-----++-+-++-----+-----++-------+-------+-------++---------+---------+---------+---------+---------++-----------+-------------+
// | 11 | 0 || | || 0 0 | 0 0 || 0 0 0 | 0 0 0 | 0 0 0 || 0 0 0 0 | 0 0 0 0 | 0 0 0 0 | 0 0 0 0 | 0 0 0 0 || 0 0 0 0 0 | 1 * * * * * |
// | | 1 || | || 0 0 | 0 0 || 0 0 0 | 0 0 0 | 0 0 0 || 0 0 0 0 | 0 0 0 0 | 0 0 0 0 | 0 0 0 0 | 0 0 0 0 || 0 0 0 0 0 | * 1 * * * * |
// | | 2 || | || 0 _ | _ 0 || 0 0 _ | _ 0 0 | 0 _ 0 || 0 0 _ _ | _ _ 0 0 | _ 0 0 _ | 0 0 _ 0 | 0 _ 0 0 || 0 0 _ 0 0 | * * 1 * * * |
// | | 3 || | || 0 _ | _ 0 || 0 0 _ | _ 0 0 | 0 _ 0 || 0 0 _ _ | _ _ 0 0 | _ 0 0 _ | 0 0 _ 0 | 0 _ 0 0 || 0 0 _ 0 0 | * * * 1 * * |
// | | 4 || | || 0 0 | 0 0 || 0 0 0 | 0 0 0 | 0 0 0 || 0 0 0 0 | 0 0 0 0 | 0 0 0 0 | 0 0 0 0 | 0 0 0 0 || 0 0 0 0 0 | * * * * 1 * |
// | | 5 || | || 0 0 | 0 0 || 0 0 0 | 0 0 0 | 0 0 0 || 0 0 0 0 | 0 0 0 0 | 0 0 0 0 | 0 0 0 0 | 0 0 0 0 || 0 0 0 0 0 | * * * * * 1 |
// +-------+-----++-+-++-----+-----++-------+-------+-------++---------+---------+---------+---------+---------++-----------+-------------+
>>> ign = smt.delete_killed_rows()
>>> ign = smt.dump(immediate=True)
// | || P || | || 0 1 | 1 0 || 0 1 | 1 0 | 0 1 || _ _ | _ _ | _ _ | 0 1 | 0 1 || 0 1 | _ _ |
// +-------+-----++-+-++-----+-----++-----+-----+-----++-----+-----+-----+-----+-----++-----+-----+
// +-------+-----++-+-++-----+-----++-----+-----+-----++-----+-----+-----+-----+-----++-----+-----+
// | 0 | 0 || | || 1 * | 0 0 || 0 0 | 0 0 | 0 0 || 0 0 | 0 0 | 0 0 | 0 0 | 0 0 || 0 0 | 0 0 |
// | | 1 || | || * 1 | _ 0 || 0 _ | _ 0 | 0 _ || _ _ | _ _ | _ _ | 0 _ | 0 _ || 0 _ | _ _ |
// +-------+-----++-+-++-----+-----++-----+-----+-----++-----+-----+-----+-----+-----++-----+-----+
// | 1 | 0 || | || 0 _ | 1 * || 0 _ | _ 0 | 0 _ || _ _ | _ _ | _ _ | 0 _ | 0 _ || 0 _ | _ _ |
// | | 1 || | || 0 0 | * 1 || 0 0 | 0 0 | 0 0 || 0 0 | 0 0 | 0 0 | 0 0 | 0 0 || 0 0 | 0 0 |
// +-------+-----++-+-++-----+-----++-----+-----+-----++-----+-----+-----+-----+-----++-----+-----+
// +-------+-----++-+-++-----+-----++-----+-----+-----++-----+-----+-----+-----+-----++-----+-----+
// | 2 | 0 || | || 0 0 | 0 0 || 1 * | 0 0 | 0 0 || 0 0 | 0 0 | 0 0 | 0 0 | 0 0 || 0 0 | 0 0 |
// | | 1 || | || 0 _ | _ 0 || * 1 | _ 0 | 0 _ || _ _ | _ _ | _ _ | 0 _ | 0 _ || 0 _ | _ _ |
// +-------+-----++-+-++-----+-----++-----+-----+-----++-----+-----+-----+-----+-----++-----+-----+
// | 3 | 0 || | || 0 _ | _ 0 || 0 _ | 1 * | 0 _ || _ _ | _ _ | _ _ | 0 _ | 0 _ || 0 _ | _ _ |
// | | 1 || | || 0 0 | 0 0 || 0 0 | * 1 | 0 0 || 0 0 | 0 0 | 0 0 | 0 0 | 0 0 || 0 0 | 0 0 |
// +-------+-----++-+-++-----+-----++-----+-----+-----++-----+-----+-----+-----+-----++-----+-----+
// | 4 | 0 || | || 0 0 | 0 0 || 0 0 | 0 0 | 1 * || 0 0 | 0 0 | 0 0 | 0 0 | 0 0 || 0 0 | 0 0 |
// | | 1 || | || 0 _ | _ 0 || 0 _ | _ 0 | * 1 || _ _ | _ _ | _ _ | 0 _ | 0 _ || 0 _ | _ _ |
// +-------+-----++-+-++-----+-----++-----+-----+-----++-----+-----+-----+-----+-----++-----+-----+
// +-------+-----++-+-++-----+-----++-----+-----+-----++-----+-----+-----+-----+-----++-----+-----+
// | 5 | 0 || | || 0 _ | _ 0 || 0 _ | _ 0 | 0 _ || 1 * | _ _ | _ _ | 0 _ | 0 _ || 0 _ | _ _ |
// | | 1 || | || 0 _ | _ 0 || 0 _ | _ 0 | 0 _ || * 1 | _ _ | _ _ | 0 _ | 0 _ || 0 _ | _ _ |
// +-------+-----++-+-++-----+-----++-----+-----+-----++-----+-----+-----+-----+-----++-----+-----+
// | 6 | 0 || | || 0 _ | _ 0 || 0 _ | _ 0 | 0 _ || _ _ | 1 * | _ _ | 0 _ | 0 _ || 0 _ | _ _ |
// | | 1 || | || 0 _ | _ 0 || 0 _ | _ 0 | 0 _ || _ _ | * 1 | _ _ | 0 _ | 0 _ || 0 _ | _ _ |
// +-------+-----++-+-++-----+-----++-----+-----+-----++-----+-----+-----+-----+-----++-----+-----+
// | 7 | 0 || | || 0 _ | _ 0 || 0 _ | _ 0 | 0 _ || _ _ | _ _ | 1 * | 0 _ | 0 _ || 0 _ | _ _ |
// | | 1 || | || 0 _ | _ 0 || 0 _ | _ 0 | 0 _ || _ _ | _ _ | * 1 | 0 _ | 0 _ || 0 _ | _ _ |
// +-------+-----++-+-++-----+-----++-----+-----+-----++-----+-----+-----+-----+-----++-----+-----+
// | 8 | 0 || | || 0 0 | 0 0 || 0 0 | 0 0 | 0 0 || 0 0 | 0 0 | 0 0 | 1 * | 0 0 || 0 0 | 0 0 |
// | | 1 || | || 0 _ | _ 0 || 0 _ | _ 0 | 0 _ || _ _ | _ _ | _ _ | * 1 | 0 _ || 0 _ | _ _ |
// +-------+-----++-+-++-----+-----++-----+-----+-----++-----+-----+-----+-----+-----++-----+-----+
// | 9 | 0 || | || 0 0 | 0 0 || 0 0 | 0 0 | 0 0 || 0 0 | 0 0 | 0 0 | 0 0 | 1 * || 0 0 | 0 0 |
// | | 1 || | || 0 _ | _ 0 || 0 _ | _ 0 | 0 _ || _ _ | _ _ | _ _ | 0 _ | * 1 || 0 _ | _ _ |
// +-------+-----++-+-++-----+-----++-----+-----+-----++-----+-----+-----+-----+-----++-----+-----+
// +-------+-----++-+-++-----+-----++-----+-----+-----++-----+-----+-----+-----+-----++-----+-----+
// | 10 | 0 || | || 0 0 | 0 0 || 0 0 | 0 0 | 0 0 || 0 0 | 0 0 | 0 0 | 0 0 | 0 0 || 1 * | 0 0 |
// | | 1 || | || 0 _ | _ 0 || 0 _ | _ 0 | 0 _ || _ _ | _ _ | _ _ | 0 _ | 0 _ || * 1 | _ _ |
// +-------+-----++-+-++-----+-----++-----+-----+-----++-----+-----+-----+-----+-----++-----+-----+
// | 11 | 0 || | || 0 _ | _ 0 || 0 _ | _ 0 | 0 _ || _ _ | _ _ | _ _ | 0 _ | 0 _ || 0 _ | 1 * |
// | | 1 || | || 0 _ | _ 0 || 0 _ | _ 0 | 0 _ || _ _ | _ _ | _ _ | 0 _ | 0 _ || 0 _ | * 1 |
// +-------+-----++-+-++-----+-----++-----+-----+-----++-----+-----+-----+-----+-----++-----+-----+
>>> printf(dump_regions(sm.regions))
r0: 0, 2 / r1: 2, 3 / r2: 5, 5 / r3: 10, 2 / r4: 12, 0 / r5: 12, 0
"""
clause = self.clauses[si]
start = sj
end = sx
if clause.size < 3:
# nothing to delete
return self
if start < 0:
printe(sformat(
'{0} :WRN: delete_rows: start < 0 ({1})',
dbg_comm, start))
start = 0
if start > clause.size:
printe(sformat(
'{0} :WRN: delete_rows: start > clause.size ({1} >= {2})',
dbg_comm, start, clause.size))
start = clause.size
if end > clause.size:
printe(sformat(
'{0} :WRN: delete_rows: end > clause.size ({1} >= {2})',
dbg_comm, end, clause.size))
end = clause.size
if end < start:
printe(sformat(
'{0} :WRN: delete_rows: end < start ({1} < {2})',
dbg_comm, end, start))
end = start
row_count = end - start
if clause.size - row_count < 2:
printe(sformat(
'{0} :WRN: delete_rows: row count > max. row count ({1} > {2})',
dbg_comm, row_count, clause.size - 2))
row_count = clause.size - 2
end = start + row_count
if row_count <= 0:
# nothing to delete
return self
start_row = clause.ofs + start
end_row = start_row + row_count
clause.size -= row_count
# remove vertical part from rows
for row in self.rows:
#printe(sformat("// "":DBG: {1:<{0}s}: ]{2!s}[", dbg_fwid, "row", (row)))
del(row[start_row:end_row])
# remove vertical part from row_status, update_flags
del(self.row_status[start_row:end_row])
del(self.row_update_flags[start_row:end_row])
del(self.superset_update_flags[start_row:end_row])
# remove horizontal rows
del(self.rows[start_row:end_row])
# adjust size
self.size -= row_count
self.rebuild_clauses_and_maps(sformat(
'delete_rows({0},{1},{2}): ofs: {3}, size: {4}, start: {5}, end {6}, count (7)',
si, sj, sx, clause.ofs, clause.size, start, end, row_count))
stats = self.stats
stats.rows_deleted += row_count
# ||||:here:||||
return self
[docs] def delete_clauses(self, start, end): # |:mth:|
"""Delete a region of clauses.
:returns: self for chaining.
:param start: start clause index.
:param end: end clause index.
>>> pr = Problem()
>>> cv = ClauseVector('1 1')
>>> pr.extend([cv.copy() for i in xrange( 5 + 3 + 2 + 5 + 0)])
>>> sm = SatokuMatrix(pr)
>>> ign = sm.set_region(0, 5)
>>> ign = sm.set_region(5, 3)
>>> ign = sm.set_region(8, 2)
>>> ign = sm.set_region(10, 5)
>>> ign = sm.add_region(at=-2)
>>> printf(dump_regions(sm.regions))
r0: 0, 5 / r1: 5, 3 / r2: 8, 2 / r3: 10, 5 / r4: 15, 0 / r5: 15, 0 / r6: 15, 0
>>> ign = sm.dump(immediate=True)
// | || P || | || _ _ | _ _ | _ _ | _ _ | _ _ || _ _ | _ _ | _ _ || _ _ | _ _ || _ _ | _ _ | _ _ | _ _ | _ _ |
// +-------+-----++-+-++-----+-----+-----+-----+-----++-----+-----+-----++-----+-----++-----+-----+-----+-----+-----+
// +-------+-----++-+-++-----+-----+-----+-----+-----++-----+-----+-----++-----+-----++-----+-----+-----+-----+-----+
// | 0 | 0 || | || 1 * | _ _ | _ _ | _ _ | _ _ || _ _ | _ _ | _ _ || _ _ | _ _ || _ _ | _ _ | _ _ | _ _ | _ _ |
// | | 1 || | || * 1 | _ _ | _ _ | _ _ | _ _ || _ _ | _ _ | _ _ || _ _ | _ _ || _ _ | _ _ | _ _ | _ _ | _ _ |
// +-------+-----++-+-++-----+-----+-----+-----+-----++-----+-----+-----++-----+-----++-----+-----+-----+-----+-----+
// | 1 | 0 || | || _ _ | 1 * | _ _ | _ _ | _ _ || _ _ | _ _ | _ _ || _ _ | _ _ || _ _ | _ _ | _ _ | _ _ | _ _ |
// | | 1 || | || _ _ | * 1 | _ _ | _ _ | _ _ || _ _ | _ _ | _ _ || _ _ | _ _ || _ _ | _ _ | _ _ | _ _ | _ _ |
// +-------+-----++-+-++-----+-----+-----+-----+-----++-----+-----+-----++-----+-----++-----+-----+-----+-----+-----+
// | 2 | 0 || | || _ _ | _ _ | 1 * | _ _ | _ _ || _ _ | _ _ | _ _ || _ _ | _ _ || _ _ | _ _ | _ _ | _ _ | _ _ |
// | | 1 || | || _ _ | _ _ | * 1 | _ _ | _ _ || _ _ | _ _ | _ _ || _ _ | _ _ || _ _ | _ _ | _ _ | _ _ | _ _ |
// +-------+-----++-+-++-----+-----+-----+-----+-----++-----+-----+-----++-----+-----++-----+-----+-----+-----+-----+
// | 3 | 0 || | || _ _ | _ _ | _ _ | 1 * | _ _ || _ _ | _ _ | _ _ || _ _ | _ _ || _ _ | _ _ | _ _ | _ _ | _ _ |
// | | 1 || | || _ _ | _ _ | _ _ | * 1 | _ _ || _ _ | _ _ | _ _ || _ _ | _ _ || _ _ | _ _ | _ _ | _ _ | _ _ |
// +-------+-----++-+-++-----+-----+-----+-----+-----++-----+-----+-----++-----+-----++-----+-----+-----+-----+-----+
// | 4 | 0 || | || _ _ | _ _ | _ _ | _ _ | 1 * || _ _ | _ _ | _ _ || _ _ | _ _ || _ _ | _ _ | _ _ | _ _ | _ _ |
// | | 1 || | || _ _ | _ _ | _ _ | _ _ | * 1 || _ _ | _ _ | _ _ || _ _ | _ _ || _ _ | _ _ | _ _ | _ _ | _ _ |
// +-------+-----++-+-++-----+-----+-----+-----+-----++-----+-----+-----++-----+-----++-----+-----+-----+-----+-----+
// +-------+-----++-+-++-----+-----+-----+-----+-----++-----+-----+-----++-----+-----++-----+-----+-----+-----+-----+
// | 5 | 0 || | || _ _ | _ _ | _ _ | _ _ | _ _ || 1 * | _ _ | _ _ || _ _ | _ _ || _ _ | _ _ | _ _ | _ _ | _ _ |
// | | 1 || | || _ _ | _ _ | _ _ | _ _ | _ _ || * 1 | _ _ | _ _ || _ _ | _ _ || _ _ | _ _ | _ _ | _ _ | _ _ |
// +-------+-----++-+-++-----+-----+-----+-----+-----++-----+-----+-----++-----+-----++-----+-----+-----+-----+-----+
// | 6 | 0 || | || _ _ | _ _ | _ _ | _ _ | _ _ || _ _ | 1 * | _ _ || _ _ | _ _ || _ _ | _ _ | _ _ | _ _ | _ _ |
// | | 1 || | || _ _ | _ _ | _ _ | _ _ | _ _ || _ _ | * 1 | _ _ || _ _ | _ _ || _ _ | _ _ | _ _ | _ _ | _ _ |
// +-------+-----++-+-++-----+-----+-----+-----+-----++-----+-----+-----++-----+-----++-----+-----+-----+-----+-----+
// | 7 | 0 || | || _ _ | _ _ | _ _ | _ _ | _ _ || _ _ | _ _ | 1 * || _ _ | _ _ || _ _ | _ _ | _ _ | _ _ | _ _ |
// | | 1 || | || _ _ | _ _ | _ _ | _ _ | _ _ || _ _ | _ _ | * 1 || _ _ | _ _ || _ _ | _ _ | _ _ | _ _ | _ _ |
// +-------+-----++-+-++-----+-----+-----+-----+-----++-----+-----+-----++-----+-----++-----+-----+-----+-----+-----+
// +-------+-----++-+-++-----+-----+-----+-----+-----++-----+-----+-----++-----+-----++-----+-----+-----+-----+-----+
// | 8 | 0 || | || _ _ | _ _ | _ _ | _ _ | _ _ || _ _ | _ _ | _ _ || 1 * | _ _ || _ _ | _ _ | _ _ | _ _ | _ _ |
// | | 1 || | || _ _ | _ _ | _ _ | _ _ | _ _ || _ _ | _ _ | _ _ || * 1 | _ _ || _ _ | _ _ | _ _ | _ _ | _ _ |
// +-------+-----++-+-++-----+-----+-----+-----+-----++-----+-----+-----++-----+-----++-----+-----+-----+-----+-----+
// | 9 | 0 || | || _ _ | _ _ | _ _ | _ _ | _ _ || _ _ | _ _ | _ _ || _ _ | 1 * || _ _ | _ _ | _ _ | _ _ | _ _ |
// | | 1 || | || _ _ | _ _ | _ _ | _ _ | _ _ || _ _ | _ _ | _ _ || _ _ | * 1 || _ _ | _ _ | _ _ | _ _ | _ _ |
// +-------+-----++-+-++-----+-----+-----+-----+-----++-----+-----+-----++-----+-----++-----+-----+-----+-----+-----+
// +-------+-----++-+-++-----+-----+-----+-----+-----++-----+-----+-----++-----+-----++-----+-----+-----+-----+-----+
// | 10 | 0 || | || _ _ | _ _ | _ _ | _ _ | _ _ || _ _ | _ _ | _ _ || _ _ | _ _ || 1 * | _ _ | _ _ | _ _ | _ _ |
// | | 1 || | || _ _ | _ _ | _ _ | _ _ | _ _ || _ _ | _ _ | _ _ || _ _ | _ _ || * 1 | _ _ | _ _ | _ _ | _ _ |
// +-------+-----++-+-++-----+-----+-----+-----+-----++-----+-----+-----++-----+-----++-----+-----+-----+-----+-----+
// | 11 | 0 || | || _ _ | _ _ | _ _ | _ _ | _ _ || _ _ | _ _ | _ _ || _ _ | _ _ || _ _ | 1 * | _ _ | _ _ | _ _ |
// | | 1 || | || _ _ | _ _ | _ _ | _ _ | _ _ || _ _ | _ _ | _ _ || _ _ | _ _ || _ _ | * 1 | _ _ | _ _ | _ _ |
// +-------+-----++-+-++-----+-----+-----+-----+-----++-----+-----+-----++-----+-----++-----+-----+-----+-----+-----+
// | 12 | 0 || | || _ _ | _ _ | _ _ | _ _ | _ _ || _ _ | _ _ | _ _ || _ _ | _ _ || _ _ | _ _ | 1 * | _ _ | _ _ |
// | | 1 || | || _ _ | _ _ | _ _ | _ _ | _ _ || _ _ | _ _ | _ _ || _ _ | _ _ || _ _ | _ _ | * 1 | _ _ | _ _ |
// +-------+-----++-+-++-----+-----+-----+-----+-----++-----+-----+-----++-----+-----++-----+-----+-----+-----+-----+
// | 13 | 0 || | || _ _ | _ _ | _ _ | _ _ | _ _ || _ _ | _ _ | _ _ || _ _ | _ _ || _ _ | _ _ | _ _ | 1 * | _ _ |
// | | 1 || | || _ _ | _ _ | _ _ | _ _ | _ _ || _ _ | _ _ | _ _ || _ _ | _ _ || _ _ | _ _ | _ _ | * 1 | _ _ |
// +-------+-----++-+-++-----+-----+-----+-----+-----++-----+-----+-----++-----+-----++-----+-----+-----+-----+-----+
// | 14 | 0 || | || _ _ | _ _ | _ _ | _ _ | _ _ || _ _ | _ _ | _ _ || _ _ | _ _ || _ _ | _ _ | _ _ | _ _ | 1 * |
// | | 1 || | || _ _ | _ _ | _ _ | _ _ | _ _ || _ _ | _ _ | _ _ || _ _ | _ _ || _ _ | _ _ | _ _ | _ _ | * 1 |
// +-------+-----++-+-++-----+-----+-----+-----+-----++-----+-----+-----++-----+-----++-----+-----+-----+-----+-----+
Verify Matrix Copy
>>> smt = sm.copy()
>>> printf(dump_regions(smt.regions))
r0: 0, 5 / r1: 5, 3 / r2: 8, 2 / r3: 10, 5 / r4: 15, 0 / r5: 15, 0 / r6: 15, 0
Case 1: start < 0, end < 0
>>> smt = sm.copy().delete_clauses(-1, -5)
>>> printf(dump_regions(smt.regions))
r0: 0, 5 / r1: 5, 3 / r2: 8, 2 / r3: 10, 5 / r4: 15, 0 / r5: 15, 0 / r6: 15, 0
Case 2: start > len(clauses), end > len(clauses)
>>> smt = sm.copy().delete_clauses(18, 20)
>>> printf(dump_regions(smt.regions))
r0: 0, 5 / r1: 5, 3 / r2: 8, 2 / r3: 10, 5 / r4: 15, 0 / r5: 15, 0 / r6: 15, 0
Case 3: begin inside clause, end inside different clause, intermediate clauses covered
>>> smt = sm.copy().delete_clauses(6, 11)
>>> printf(dump_regions(smt.regions))
r0: 0, 5 / r1: 5, 1 / r2: 6, 4 / r3: 10, 0 / r4: 10, 0 / r5: 10, 0
>>> ign = smt.dump(immediate=True)
// | || P || | || _ _ | _ _ | _ _ | _ _ | _ _ || _ _ || _ _ | _ _ | _ _ | _ _ |
// +-------+-----++-+-++-----+-----+-----+-----+-----++-----++-----+-----+-----+-----+
// +-------+-----++-+-++-----+-----+-----+-----+-----++-----++-----+-----+-----+-----+
// | 0 | 0 || | || 1 * | _ _ | _ _ | _ _ | _ _ || _ _ || _ _ | _ _ | _ _ | _ _ |
// | | 1 || | || * 1 | _ _ | _ _ | _ _ | _ _ || _ _ || _ _ | _ _ | _ _ | _ _ |
// +-------+-----++-+-++-----+-----+-----+-----+-----++-----++-----+-----+-----+-----+
// | 1 | 0 || | || _ _ | 1 * | _ _ | _ _ | _ _ || _ _ || _ _ | _ _ | _ _ | _ _ |
// | | 1 || | || _ _ | * 1 | _ _ | _ _ | _ _ || _ _ || _ _ | _ _ | _ _ | _ _ |
// +-------+-----++-+-++-----+-----+-----+-----+-----++-----++-----+-----+-----+-----+
// | 2 | 0 || | || _ _ | _ _ | 1 * | _ _ | _ _ || _ _ || _ _ | _ _ | _ _ | _ _ |
// | | 1 || | || _ _ | _ _ | * 1 | _ _ | _ _ || _ _ || _ _ | _ _ | _ _ | _ _ |
// +-------+-----++-+-++-----+-----+-----+-----+-----++-----++-----+-----+-----+-----+
// | 3 | 0 || | || _ _ | _ _ | _ _ | 1 * | _ _ || _ _ || _ _ | _ _ | _ _ | _ _ |
// | | 1 || | || _ _ | _ _ | _ _ | * 1 | _ _ || _ _ || _ _ | _ _ | _ _ | _ _ |
// +-------+-----++-+-++-----+-----+-----+-----+-----++-----++-----+-----+-----+-----+
// | 4 | 0 || | || _ _ | _ _ | _ _ | _ _ | 1 * || _ _ || _ _ | _ _ | _ _ | _ _ |
// | | 1 || | || _ _ | _ _ | _ _ | _ _ | * 1 || _ _ || _ _ | _ _ | _ _ | _ _ |
// +-------+-----++-+-++-----+-----+-----+-----+-----++-----++-----+-----+-----+-----+
// +-------+-----++-+-++-----+-----+-----+-----+-----++-----++-----+-----+-----+-----+
// | 5 | 0 || | || _ _ | _ _ | _ _ | _ _ | _ _ || 1 * || _ _ | _ _ | _ _ | _ _ |
// | | 1 || | || _ _ | _ _ | _ _ | _ _ | _ _ || * 1 || _ _ | _ _ | _ _ | _ _ |
// +-------+-----++-+-++-----+-----+-----+-----+-----++-----++-----+-----+-----+-----+
// +-------+-----++-+-++-----+-----+-----+-----+-----++-----++-----+-----+-----+-----+
// | 6 | 0 || | || _ _ | _ _ | _ _ | _ _ | _ _ || _ _ || 1 * | _ _ | _ _ | _ _ |
// | | 1 || | || _ _ | _ _ | _ _ | _ _ | _ _ || _ _ || * 1 | _ _ | _ _ | _ _ |
// +-------+-----++-+-++-----+-----+-----+-----+-----++-----++-----+-----+-----+-----+
// | 7 | 0 || | || _ _ | _ _ | _ _ | _ _ | _ _ || _ _ || _ _ | 1 * | _ _ | _ _ |
// | | 1 || | || _ _ | _ _ | _ _ | _ _ | _ _ || _ _ || _ _ | * 1 | _ _ | _ _ |
// +-------+-----++-+-++-----+-----+-----+-----+-----++-----++-----+-----+-----+-----+
// | 8 | 0 || | || _ _ | _ _ | _ _ | _ _ | _ _ || _ _ || _ _ | _ _ | 1 * | _ _ |
// | | 1 || | || _ _ | _ _ | _ _ | _ _ | _ _ || _ _ || _ _ | _ _ | * 1 | _ _ |
// +-------+-----++-+-++-----+-----+-----+-----+-----++-----++-----+-----+-----+-----+
// | 9 | 0 || | || _ _ | _ _ | _ _ | _ _ | _ _ || _ _ || _ _ | _ _ | _ _ | 1 * |
// | | 1 || | || _ _ | _ _ | _ _ | _ _ | _ _ || _ _ || _ _ | _ _ | _ _ | * 1 |
// +-------+-----++-+-++-----+-----+-----+-----+-----++-----++-----+-----+-----+-----+
Case 4: begin inside clause, end inside different clause, no intermediate clauses
>>> smt = sm.copy().delete_clauses(7, 9)
>>> printf(dump_regions(smt.regions))
r0: 0, 5 / r1: 5, 2 / r2: 7, 1 / r3: 8, 5 / r4: 13, 0 / r5: 13, 0 / r6: 13, 0
Case 5: begin inside clause, end at end of same clause
>>> smt = sm.copy().delete_clauses(7, 8)
>>> printf(dump_regions(smt.regions))
r0: 0, 5 / r1: 5, 2 / r2: 7, 2 / r3: 9, 5 / r4: 14, 0 / r5: 14, 0 / r6: 14, 0
Case 6: begin at start of clause, end inside same clause
>>> smt = sm.copy().delete_clauses(8, 9)
>>> printf(dump_regions(smt.regions))
r0: 0, 5 / r1: 5, 3 / r2: 8, 1 / r3: 9, 5 / r4: 14, 0 / r5: 14, 0 / r6: 14, 0
Case 7: begin at start of clause, end at end of same clause
>>> smt = sm.copy().delete_clauses(5, 8)
>>> printf(dump_regions(smt.regions))
r0: 0, 5 / r1: 5, 2 / r2: 7, 5 / r3: 12, 0 / r4: 12, 0 / r5: 12, 0
::
| 0 <- 5 -> | 5 <- 3 -> | 8 <- 2 -> | 10 <- 5 -> | 15 <- 0 -> | 15
6 11
7 9
7 8
8 9
5 8
>>> smt = sm.copy().delete_clauses(8, 10)
>>> printf(dump_regions(smt.regions))
r0: 0, 5 / r1: 5, 3 / r2: 8, 5 / r3: 13, 0 / r4: 13, 0 / r5: 13, 0
.. >>> ign = smt.dump(immediate=True)
"""
start_ = start
end_ = end
clauses = self.clauses
clause_ct = len(clauses)
if start < 0:
printe(sformat(
'{0} :WRN: delete_clauses: start < 0 ({1})',
dbg_comm, start))
start = 0
if start > clause_ct:
printe(sformat(
'{0} :WRN: delete_clauses: start > len(clauses) ({1} >= {2})',
dbg_comm, start, clause_ct))
start = clause_ct
if end > clause_ct:
printe(sformat(
'{0} :WRN: delete_clauses: end > len(clauses) ({1} >= {2})',
dbg_comm, end, clause_ct))
end = clause_ct
if end < start:
printe(sformat(
'{0} :WRN: delete_clauses: end < start ({1} < {2})',
dbg_comm, end, start))
end = start
csm_count = end - start
if csm_count <= 0:
# nothing to delete
return self
# check dor double deletion
for clause in clauses[start:end]:
if clause.deleted:
raise SatokuUnsatisfied(sformat("// ||"":ERR:|| error: double deletion of clause {0}", clause.repr()))
clause.deleted = True
csm_first = clauses[start]
csm_last = clauses[end-1]
cell_start = csm_first.ofs
cell_size = (csm_last.ofs + csm_last.size) - cell_start
cell_end = cell_start + cell_size
# remove vertical part from rows
for row in self.rows:
del(row[cell_start:cell_end])
# remove vertical part from row_status, update_flags
del(self.row_status[cell_start:cell_end])
del(self.row_update_flags[cell_start:cell_end])
del(self.superset_update_flags[cell_start:cell_end])
# remove horizontal rows
del(self.rows[cell_start:cell_end])
# adjust size
self.size -= cell_size
sys_regions = (self.variables, self.synthesized)
# adjust regions
nregions = []
for region in self.regions:
region_start = region.ofs
region_end = region_start + region.size
# drop covered regions
if (region_start >= start and region_end <= end):
region.size = 0
region.ofs = start
if region in sys_regions:
nregions.append(region)
continue
if region_start <= start:
# region starts before or at deletion range
if region_end > start:
# region ends inside or after deletion range
if region_end <= end:
# region ends inside or at end of deletion range
region.size -= (region_end - start)
else:
# region ends after deletion range
region.size -= (end - start)
if not region.size:
region.size = 0
region.ofs = start
if region in sys_regions:
nregions.append(region)
# drop empty regions
continue
else:
# region ends before or at deletion range
pass
else:
# region starts inside or after deletion range
if region_start < end:
# region starts inside deletion range
region.ofs -= (region_start - start)
region.size -= (end - region_start)
if not region.size:
region.size = 0
region.ofs = start
if region in sys_regions:
nregions.append(region)
# drop empty regions
continue
else:
# region starts after deletion range
region.ofs -= (end -start)
nregions.append(region)
self.regions = nregions
# remove clauses
del(clauses[start:end])
self.rebuild_clauses_and_maps(sformat(
'delete_clauses({0},{1}): first: {2}, last: {3}, start: {4}, end {5}, count (6)',
start_, end_, csm_first, csm_last, cell_start, cell_end, cell_size))
stats = self.stats
stats.clauses_deleted += csm_count
# ||||:here:||||
return self
[docs] def delete_clause(self, si): # |:mth:|
"""
:returns: self for chaining.
"""
return self.delete_clauses(si, si+1)
[docs] def delete_single_clues(self): # |:mth:|
"""
:returns: self for chaining.
"""
delete_plan = []
regions = [_r for _r in self.regions if _r != self.variables]
riter = SMRegionIterator(regions)
for csm in (self.clauses[indx] for indx in riter):
if csm.size == 1:
delete_plan.append(csm)
for csm in reversed(delete_plan):
self.delete_clause(csm.indx)
return self
[docs] def delete_2_state_cell_rows(self): # |:mth:|
"""
:returns: self for chaining.
"""
delete_plan = []
regions = [_r for _r in self.regions if _r != self.variables]
riter = SMRegionIterator(regions)
for csm in (self.clauses[indx] for indx in riter):
if csm.size == 2:
#printe(sformat("// "":DBG: {1:<{0}s}: ]{2!s}[", dbg_fwid, "csm", (csm)))
#printe(sformat("// "":DBG: {1:<{0}s}: ]{2!s}[", dbg_fwid, "cv_clause", (cv_clause)))
delete_plan.append(csm)
for csm in reversed(delete_plan):
self.delete_clause(csm.indx)
return self
[docs] def delete_killed_rows(self): # |:mth:|
"""
:returns: self for chaining.
"""
row_status = self.row_status
regions = [_r for _r in self.regions if _r != self.variables]
riter = SMRegionIterator(regions)
for csm in (self.clauses[indx] for indx in riter):
si = csm.indx
if csm.size < 3:
continue
sx = -1
last_status = 1
delete_ranges = []
for sj in reversed(range(csm.size)):
if not row_status[csm.ofs + sj]:
if not last_status:
continue
sx = sj + 1
last_status = 0
else:
if not last_status:
self.delete_rows(*csm.adjust_row_range(si, sj + 1, sx))
last_status = 1
if csm.size < 3:
break
if not last_status:
self.delete_rows(*csm.adjust_row_range(si, sj, sx))
[docs] def delete_redundant_clauses(self, vert_regions=None, horz_regions=None, strictly_inside=None): # |:mth:|
"""
:returns: self for chaining.
"""
if vert_regions is None:
vert_regions = [_r for _r in self.regions if _r != self.variables]
if horz_regions is None:
horz_regions = [_r for _r in self.regions]
si, sf = (0, 0)
while True:
si, sf = self.next_bound(si, 0, vert_regions, horz_regions, strictly_inside=strictly_inside)
if si < 0:
break
riter = SMRegionIterator(vert_regions)
region = riter.at(si).region
size = region.size
self.delete_clause(si)
if region.size == size:
region.size -= 1
return self
[docs] def add_clause(self, clause): # |:mth:|
"""
:returns: self for chaining.
"""
if isinstance(clause, SMClause):
csm = clause
else:
csm = SMClause(len(self.clauses), self.size, clause, self)
self.clauses.append(csm)
indx = csm.indx
ofs = csm.ofs
size = csm.size
self.size += size
self.regions[-1].size += 1
self.row_status.expand(size)
self.clause_offsets.append(ofs)
self.clause_sizes.append(size)
self.row_clause_map.extend([indx for i in xrange(size)])
self.row_literal_map.extend([i for i in xrange(size)])
update_flags = [0 for i in xrange(size)]
self.row_update_flags.extend(update_flags)
self.superset_update_flags.extend(update_flags)
rows = self.rows
for row in rows:
row.expand(size)
row_size = self.size
for indx in xrange(size):
row = SelRow(size=row_size)
rows.append(row)
if True:
for ci in xrange(size):
if ci == indx:
row[ofs+ci] = 1
else:
row[ofs+ci] = 0
return self
[docs] def add_variables(self, problem=None): # |:mth:|
"""
:returns: self for chaining.
"""
if problem is None:
problem = self.problem
vcount = problem.max_width()
for vi in xrange(vcount):
csm = Clause()
vcv1 = ClauseVector()
vcv1.set_width(vcount)
vcv1[vi] = 1
csm.append(vcv1)
vcv0 = ClauseVector()
vcv0.set_width(vcount)
vcv0[vi] = 0
csm.append(vcv0)
self.add_clause(csm)
# reference the variable clauses
self._pjsmo_x_variables.append(csm)
return self
[docs] def clear_superset_updates(self): # |:mth:|
"""Clear superset updates.
:returns: self for chaining.
"""
self.superset_update_flags = [0 for i in xrange(self.size)]
self.superset_updates = []
return self
[docs] def map_conflicts(self, delay_zero_updates=None): # |:mth:|
"""Map clause conflicts.
:returns: self for chaining.
:param delay_zero_updates: delay mirror cell zero changes
conflicts. Default: set mirrored zero changes immediately.
"""
immediate = not delay_zero_updates
clauses = self.clauses
count = len(clauses)
for csm in clauses:
if not csm.clause:
continue
si = csm.indx
for sj in xrange(csm.size):
cv = csm.clause[sj]
for sf in xrange(csm.indx + 1, count):
ccsm = clauses[sf]
for sg in xrange(ccsm.size):
if not ccsm.clause:
continue
ccv = ccsm.clause[sg]
cfl = cv.conflicts_with(ccv)
False and cfl and printe(sformat( # |:debug:|
"{0}{3:^{1}} {4:<{2}s}: ]{5!s}\n{6!s}[",
dbg_comm, dbg_twid, dbg_fwid, ':DBG:', 'matrix cell',
((si, sj), (sf, sg), cfl),
'\n'.join((str(cv), str(ccv)))
))
if cfl:
self.zero_change(si, sj, sf, sg, immediate)
# superset updates are not necessary at this point
self.clear_superset_updates()
return self
[docs] def eval_problem_commands(self, commands): # |:mth:|
"""
"""
for command, args in commands:
if command == 'r':
ofs = 0
if isstring(args):
sizes = (int(_s) for _s in args.strip().split())
else:
sizes = args
for size in sizes:
self.set_region(ofs, size)
ofs += size
[docs] def map_problem(self, problem=None, with_variables=None, no_conflicts=None, delay_zero_updates=None): # |:mth:|
"""Map a problem into satoku matrix.
:returns: self for chaining.
:param problem: problem to be mapped. Default: self.problem.
:param with_variables: also map variables. Default: do not map
variables.
:param no_conflicts: do not map conflicts. Default: map
conflicts.
:param delay_zero_updates: delay mirror cell zero changes
conflicts. Default: set mirrored zero changes immediately.
>>> pr = Problem(TEST_PROBLEM)
>>> sm = SatokuMatrix(pr, delay_zero_updates=True)
>>> ign = sm.dump(immediate=True)
// | || P || | || _ _ _ | _ _ _ | _ _ _ | _ _ _ | _ _ _ | _ _ _ |
// +-------+-----++-+-++-------+-------+-------+-------+-------+-------+
// +-------+-----++-+-++-------+-------+-------+-------+-------+-------+
// | 0 | 0 || | || 1 * * | _ _ _ | 0 _ _ | _ _ 0 | _ 0 _ | _ 0 _ |
// | | 1 || | || * 1 * | 0 0 _ | _ _ _ | _ _ _ | _ _ _ | 0 _ _ |
// | | 2 || | || * * 1 | 0 _ _ | _ 0 0 | 0 0 _ | 0 _ _ | _ 0 0 |
// +-------+-----++-+-++-------+-------+-------+-------+-------+-------+
// | 1 | 0 || | || _ _ _ | 1 * * | 0 _ _ | _ _ _ | _ _ _ | _ _ _ |
// | | 1 || | || _ _ _ | * 1 * | _ 0 _ | 0 _ _ | _ _ _ | _ 0 0 |
// | | 2 || | || _ _ _ | * * 1 | _ _ 0 | _ 0 _ | 0 _ _ | _ _ _ |
// +-------+-----++-+-++-------+-------+-------+-------+-------+-------+
// | 2 | 0 || | || _ _ _ | _ _ _ | 1 * * | _ _ _ | _ _ _ | _ _ _ |
// | | 1 || | || _ _ _ | _ _ _ | * 1 * | _ _ _ | _ _ _ | 0 _ _ |
// | | 2 || | || _ _ _ | _ _ _ | * * 1 | _ _ _ | _ _ _ | _ _ _ |
// +-------+-----++-+-++-------+-------+-------+-------+-------+-------+
// | 3 | 0 || | || _ _ _ | _ _ _ | _ _ _ | 1 * * | _ _ _ | 0 _ _ |
// | | 1 || | || _ _ _ | _ _ _ | _ _ _ | * 1 * | _ _ _ | _ _ _ |
// | | 2 || | || _ _ _ | _ _ _ | _ _ _ | * * 1 | _ _ _ | _ _ 0 |
// +-------+-----++-+-++-------+-------+-------+-------+-------+-------+
// | 4 | 0 || | || _ _ _ | _ _ _ | _ _ _ | _ _ _ | 1 * * | _ _ _ |
// | | 1 || | || _ _ _ | _ _ _ | _ _ _ | _ _ _ | * 1 * | _ _ 0 |
// | | 2 || | || _ _ _ | _ _ _ | _ _ _ | _ _ _ | * * 1 | _ _ 0 |
// +-------+-----++-+-++-------+-------+-------+-------+-------+-------+
// | 5 | 0 || | || _ _ _ | _ _ _ | _ _ _ | _ _ _ | _ _ _ | 1 * * |
// | | 1 || | || _ _ _ | _ _ _ | _ _ _ | _ _ _ | _ _ _ | * 1 * |
// | | 2 || | || _ _ _ | _ _ _ | _ _ _ | _ _ _ | _ _ _ | * * 1 |
// +-------+-----++-+-++-------+-------+-------+-------+-------+-------+
>>> printf(sm.dump_stats())
// ======================== ====
// Satoku Statistics
// ======================== ====
// satisfiable True
// init clauses 6
// init variables 0
// init synthesized 0
// init rows 18
// clauses 6
// variables 0
// synthesized 0
// rows 18
// cells 324
// clauses deleted 0
// rows deleted 0
// row kills 0
// duplicate kills 0
// zero changes 28
// soft changes 0
// zero update passes 0
// row update passes 0
// superset update passes 0
// zero updates 0
// row updates 0
// superset updates 0
// max zero updates 0
// max row updates 0
// max superset updates 0
// pending zero updates 28
// pending row updates 3
// pending superset updates 0
// row checks 0
// row merges 0
// state combines 0
// cell combines 0
// message
// ======================== ====
>>> ign = sm.update_zeroes()
>>> ign = sm.clear_superset_updates()
>>> ign = sm.dump(immediate=True)
// | || P || | || _ _ _ | _ _ _ | _ _ _ | _ _ _ | _ _ _ | _ _ _ |
// +-------+-----++-+-++-------+-------+-------+-------+-------+-------+
// +-------+-----++-+-++-------+-------+-------+-------+-------+-------+
// | 0 | 0 || | || 1 * * | _ _ _ | 0 _ _ | _ _ 0 | _ 0 _ | _ 0 _ |
// | | 1 || | || * 1 * | 0 0 _ | _ _ _ | _ _ _ | _ _ _ | 0 _ _ |
// | | 2 || | || * * 1 | 0 _ _ | _ 0 0 | 0 0 _ | 0 _ _ | _ 0 0 |
// +-------+-----++-+-++-------+-------+-------+-------+-------+-------+
// | 1 | 0 || | || _ 0 0 | 1 * * | 0 _ _ | _ _ _ | _ _ _ | _ _ _ |
// | | 1 || | || _ 0 _ | * 1 * | _ 0 _ | 0 _ _ | _ _ _ | _ 0 0 |
// | | 2 || | || _ _ _ | * * 1 | _ _ 0 | _ 0 _ | 0 _ _ | _ _ _ |
// +-------+-----++-+-++-------+-------+-------+-------+-------+-------+
// | 2 | 0 || | || 0 _ _ | 0 _ _ | 1 * * | _ _ _ | _ _ _ | _ _ _ |
// | | 1 || | || _ _ 0 | _ 0 _ | * 1 * | _ _ _ | _ _ _ | 0 _ _ |
// | | 2 || | || _ _ 0 | _ _ 0 | * * 1 | _ _ _ | _ _ _ | _ _ _ |
// +-------+-----++-+-++-------+-------+-------+-------+-------+-------+
// | 3 | 0 || | || _ _ 0 | _ 0 _ | _ _ _ | 1 * * | _ _ _ | 0 _ _ |
// | | 1 || | || _ _ 0 | _ _ 0 | _ _ _ | * 1 * | _ _ _ | _ _ _ |
// | | 2 || | || 0 _ _ | _ _ _ | _ _ _ | * * 1 | _ _ _ | _ _ 0 |
// +-------+-----++-+-++-------+-------+-------+-------+-------+-------+
// | 4 | 0 || | || _ _ 0 | _ _ 0 | _ _ _ | _ _ _ | 1 * * | _ _ _ |
// | | 1 || | || 0 _ _ | _ _ _ | _ _ _ | _ _ _ | * 1 * | _ _ 0 |
// | | 2 || | || _ _ _ | _ _ _ | _ _ _ | _ _ _ | * * 1 | _ _ 0 |
// +-------+-----++-+-++-------+-------+-------+-------+-------+-------+
// | 5 | 0 || | || _ 0 _ | _ _ _ | _ 0 _ | 0 _ _ | _ _ _ | 1 * * |
// | | 1 || | || 0 _ 0 | _ 0 _ | _ _ _ | _ _ _ | _ _ _ | * 1 * |
// | | 2 || | || _ _ 0 | _ 0 _ | _ _ _ | _ _ 0 | _ 0 0 | * * 1 |
// +-------+-----++-+-++-------+-------+-------+-------+-------+-------+
>>> printf(sm.dump_stats())
// ======================== ====
// Satoku Statistics
// ======================== ====
// satisfiable True
// init clauses 6
// init variables 0
// init synthesized 0
// init rows 18
// clauses 6
// variables 0
// synthesized 0
// rows 18
// cells 324
// clauses deleted 0
// rows deleted 0
// row kills 0
// duplicate kills 0
// zero changes 56
// soft changes 0
// zero update passes 1
// row update passes 0
// superset update passes 0
// zero updates 28
// row updates 0
// superset updates 0
// max zero updates 28
// max row updates 0
// max superset updates 0
// pending zero updates 0
// pending row updates 6
// pending superset updates 0
// row checks 0
// row merges 0
// state combines 0
// cell combines 0
// message
// ======================== ====
>>> pr = Problem(TEST_PROBLEM_REGIONS)
>>> sm = SatokuMatrix(pr, with_variables=True)
>>> ign = sm.update_rows()
>>> pr.commands
[('r', '3 2 1 5 9 10')]
>>> ign = sm.dump(immediate=True)
// | || P || | || _ _ _ | _ _ _ | _ _ _ || _ _ _ | _ _ _ || _ _ _ || _ _ | _ _ | _ _ | _ _ | _ _ |
// +-------+-----++-+-++-------+-------+-------++-------+-------++-------++-----+-----+-----+-----+-----+
// +-------+-----++-+-++-------+-------+-------++-------+-------++-------++-----+-----+-----+-----+-----+
// | 0 | 0 || | || 1 * * | _ _ _ | 0 _ _ || _ _ 0 | _ 0 _ || _ 0 _ || 1 0 | _ _ | _ _ | 0 1 | _ _ |
// | | 1 || | || * 1 * | 0 0 1 | _ _ 0 || _ 0 _ | 0 _ _ || 0 1 0 || 0 1 | 1 0 | 1 0 | 1 0 | _ _ |
// | | 2 || | || * * 1 | 0 _ _ | 1 0 0 || 0 0 1 | 0 _ _ || 1 0 0 || 0 1 | 0 1 | 1 0 | 1 0 | _ _ |
// +-------+-----++-+-++-------+-------+-------++-------+-------++-------++-----+-----+-----+-----+-----+
// | 1 | 0 || | || 1 0 0 | 1 * * | 0 _ _ || _ _ 0 | _ 0 _ || _ 0 _ || 1 0 | _ _ | _ _ | 0 1 | _ _ |
// | | 1 || | || _ 0 _ | * 1 * | _ 0 _ || 0 _ _ | _ _ _ || 1 0 0 || _ _ | 0 1 | _ _ | _ _ | _ _ |
// | | 2 || | || _ _ _ | * * 1 | _ _ 0 || _ 0 _ | 0 _ _ || _ _ 0 || _ _ | _ _ | 1 0 | _ _ | _ _ |
// +-------+-----++-+-++-------+-------+-------++-------+-------++-------++-----+-----+-----+-----+-----+
// | 2 | 0 || | || 0 _ _ | 0 _ _ | 1 * * || _ 0 _ | 0 _ _ || _ _ 0 || 0 1 | _ _ | 1 0 | 1 0 | _ _ |
// | | 1 || | || _ _ 0 | _ 0 _ | * 1 * || _ _ _ | _ _ _ || 0 _ _ || _ _ | 1 0 | _ _ | _ _ | _ _ |
// | | 2 || | || 1 0 0 | _ _ 0 | * * 1 || _ _ 0 | _ 0 _ || _ 0 _ || 1 0 | _ _ | 0 1 | 0 1 | _ _ |
// +-------+-----++-+-++-------+-------+-------++-------+-------++-------++-----+-----+-----+-----+-----+
// +-------+-----++-+-++-------+-------+-------++-------+-------++-------++-----+-----+-----+-----+-----+
// | 3 | 0 || | || _ _ 0 | _ 0 _ | _ _ _ || 1 * * | _ _ _ || 0 _ _ || _ _ | 1 0 | _ _ | _ _ | _ _ |
// | | 1 || | || 1 0 0 | _ _ 0 | 0 _ _ || * 1 * | _ 0 _ || _ 0 _ || 1 0 | _ _ | 0 1 | 0 1 | _ _ |
// | | 2 || | || 0 _ _ | 0 _ _ | _ _ 0 || * * 1 | 0 _ _ || _ _ 0 || 0 1 | _ _ | 1 0 | 1 0 | _ _ |
// +-------+-----++-+-++-------+-------+-------++-------+-------++-------++-----+-----+-----+-----+-----+
// | 4 | 0 || | || 1 0 0 | _ _ 0 | 0 _ _ || _ _ 0 | 1 * * || _ 0 _ || 1 0 | _ _ | 0 1 | 0 1 | _ _ |
// | | 1 || | || 0 _ _ | 0 _ _ | _ _ 0 || _ 0 _ | * 1 * || _ _ 0 || 0 1 | _ _ | 1 0 | 1 0 | _ _ |
// | | 2 || | || _ _ _ | _ _ _ | _ _ _ || _ _ _ | * * 1 || _ _ 0 || _ _ | _ _ | _ _ | _ _ | 1 0 |
// +-------+-----++-+-++-------+-------+-------++-------+-------++-------++-----+-----+-----+-----+-----+
// +-------+-----++-+-++-------+-------+-------++-------+-------++-------++-----+-----+-----+-----+-----+
// | 5 | 0 || | || _ 0 _ | _ _ _ | _ 0 _ || 0 _ _ | _ _ _ || 1 * * || _ _ | 0 1 | _ _ | _ _ | _ _ |
// | | 1 || | || 0 1 0 | 0 0 1 | _ _ 0 || _ 0 _ | 0 _ _ || * 1 * || 0 1 | 1 0 | 1 0 | 1 0 | _ _ |
// | | 2 || | || 1 0 0 | 1 0 0 | 0 _ _ || _ _ 0 | 1 0 0 || * * 1 || 1 0 | 1 0 | 0 1 | 0 1 | 0 1 |
// +-------+-----++-+-++-------+-------+-------++-------+-------++-------++-----+-----+-----+-----+-----+
// +-------+-----++-+-++-------+-------+-------++-------+-------++-------++-----+-----+-----+-----+-----+
// | 6 | 0 || | || 1 0 0 | _ _ _ | 0 _ _ || _ _ 0 | _ 0 _ || _ 0 _ || 1 * | _ _ | _ _ | 0 1 | _ _ |
// | | 1 || | || 0 _ _ | 0 _ _ | _ _ 0 || _ 0 _ | 0 _ _ || _ _ 0 || * 1 | _ _ | 1 0 | 1 0 | _ _ |
// +-------+-----++-+-++-------+-------+-------++-------+-------++-------++-----+-----+-----+-----+-----+
// | 7 | 0 || | || _ _ 0 | _ 0 _ | _ _ _ || _ _ _ | _ _ _ || 0 _ _ || _ _ | 1 * | _ _ | _ _ | _ _ |
// | | 1 || | || _ 0 _ | _ _ _ | _ 0 _ || 0 _ _ | _ _ _ || 1 0 0 || _ _ | * 1 | _ _ | _ _ | _ _ |
// +-------+-----++-+-++-------+-------+-------++-------+-------++-------++-----+-----+-----+-----+-----+
// | 8 | 0 || | || _ _ _ | _ _ _ | _ _ 0 || _ 0 _ | 0 _ _ || _ _ 0 || _ _ | _ _ | 1 * | _ _ | _ _ |
// | | 1 || | || 1 0 0 | _ _ 0 | 0 _ _ || _ _ 0 | _ 0 _ || _ 0 _ || 1 0 | _ _ | * 1 | 0 1 | _ _ |
// +-------+-----++-+-++-------+-------+-------++-------+-------++-------++-----+-----+-----+-----+-----+
// | 9 | 0 || | || 0 _ _ | 0 _ _ | _ _ 0 || _ 0 _ | 0 _ _ || _ _ 0 || 0 1 | _ _ | 1 0 | 1 * | _ _ |
// | | 1 || | || 1 0 0 | _ _ _ | 0 _ _ || _ _ 0 | _ 0 _ || _ 0 _ || 1 0 | _ _ | _ _ | * 1 | _ _ |
// +-------+-----++-+-++-------+-------+-------++-------+-------++-------++-----+-----+-----+-----+-----+
// | 10 | 0 || | || _ _ _ | _ _ _ | _ _ _ || _ _ _ | _ _ _ || _ _ 0 || _ _ | _ _ | _ _ | _ _ | 1 * |
// | | 1 || | || _ _ _ | _ _ _ | _ _ _ || _ _ _ | _ _ 0 || _ _ _ || _ _ | _ _ | _ _ | _ _ | * 1 |
// +-------+-----++-+-++-------+-------+-------++-------+-------++-------++-----+-----+-----+-----+-----+
>>> ign = sm.dump(immediate=True, regions=[_r for _i, _r in enumerate(sm.regions) if _i not in (1,)])
// | || P || | || _ _ _ | _ _ _ | _ _ _ || _ _ _ || _ _ | _ _ | _ _ | _ _ | _ _ |
// +-------+-----++-+-++-------+-------+-------++-------++-----+-----+-----+-----+-----+
// +-------+-----++-+-++-------+-------+-------++-------++-----+-----+-----+-----+-----+
// | 0 | 0 || | || 1 * * | _ _ _ | 0 _ _ || _ 0 _ || 1 0 | _ _ | _ _ | 0 1 | _ _ |
// | | 1 || | || * 1 * | 0 0 1 | _ _ 0 || 0 1 0 || 0 1 | 1 0 | 1 0 | 1 0 | _ _ |
// | | 2 || | || * * 1 | 0 _ _ | 1 0 0 || 1 0 0 || 0 1 | 0 1 | 1 0 | 1 0 | _ _ |
// +-------+-----++-+-++-------+-------+-------++-------++-----+-----+-----+-----+-----+
// | 1 | 0 || | || 1 0 0 | 1 * * | 0 _ _ || _ 0 _ || 1 0 | _ _ | _ _ | 0 1 | _ _ |
// | | 1 || | || _ 0 _ | * 1 * | _ 0 _ || 1 0 0 || _ _ | 0 1 | _ _ | _ _ | _ _ |
// | | 2 || | || _ _ _ | * * 1 | _ _ 0 || _ _ 0 || _ _ | _ _ | 1 0 | _ _ | _ _ |
// +-------+-----++-+-++-------+-------+-------++-------++-----+-----+-----+-----+-----+
// | 2 | 0 || | || 0 _ _ | 0 _ _ | 1 * * || _ _ 0 || 0 1 | _ _ | 1 0 | 1 0 | _ _ |
// | | 1 || | || _ _ 0 | _ 0 _ | * 1 * || 0 _ _ || _ _ | 1 0 | _ _ | _ _ | _ _ |
// | | 2 || | || 1 0 0 | _ _ 0 | * * 1 || _ 0 _ || 1 0 | _ _ | 0 1 | 0 1 | _ _ |
// +-------+-----++-+-++-------+-------+-------++-------++-----+-----+-----+-----+-----+
// +-------+-----++-+-++-------+-------+-------++-------++-----+-----+-----+-----+-----+
// | 3 | 0 || | || _ 0 _ | _ _ _ | _ 0 _ || 1 * * || _ _ | 0 1 | _ _ | _ _ | _ _ |
// | | 1 || | || 0 1 0 | 0 0 1 | _ _ 0 || * 1 * || 0 1 | 1 0 | 1 0 | 1 0 | _ _ |
// | | 2 || | || 1 0 0 | 1 0 0 | 0 _ _ || * * 1 || 1 0 | 1 0 | 0 1 | 0 1 | 0 1 |
// +-------+-----++-+-++-------+-------+-------++-------++-----+-----+-----+-----+-----+
// +-------+-----++-+-++-------+-------+-------++-------++-----+-----+-----+-----+-----+
// | 4 | 0 || | || 1 0 0 | _ _ _ | 0 _ _ || _ 0 _ || 1 * | _ _ | _ _ | 0 1 | _ _ |
// | | 1 || | || 0 _ _ | 0 _ _ | _ _ 0 || _ _ 0 || * 1 | _ _ | 1 0 | 1 0 | _ _ |
// +-------+-----++-+-++-------+-------+-------++-------++-----+-----+-----+-----+-----+
// | 5 | 0 || | || _ _ 0 | _ 0 _ | _ _ _ || 0 _ _ || _ _ | 1 * | _ _ | _ _ | _ _ |
// | | 1 || | || _ 0 _ | _ _ _ | _ 0 _ || 1 0 0 || _ _ | * 1 | _ _ | _ _ | _ _ |
// +-------+-----++-+-++-------+-------+-------++-------++-----+-----+-----+-----+-----+
// | 6 | 0 || | || _ _ _ | _ _ _ | _ _ 0 || _ _ 0 || _ _ | _ _ | 1 * | _ _ | _ _ |
// | | 1 || | || 1 0 0 | _ _ 0 | 0 _ _ || _ 0 _ || 1 0 | _ _ | * 1 | 0 1 | _ _ |
// +-------+-----++-+-++-------+-------+-------++-------++-----+-----+-----+-----+-----+
// | 7 | 0 || | || 0 _ _ | 0 _ _ | _ _ 0 || _ _ 0 || 0 1 | _ _ | 1 0 | 1 * | _ _ |
// | | 1 || | || 1 0 0 | _ _ _ | 0 _ _ || _ 0 _ || 1 0 | _ _ | _ _ | * 1 | _ _ |
// +-------+-----++-+-++-------+-------+-------++-------++-----+-----+-----+-----+-----+
// | 8 | 0 || | || _ _ _ | _ _ _ | _ _ _ || _ _ 0 || _ _ | _ _ | _ _ | _ _ | 1 * |
// | | 1 || | || _ _ _ | _ _ _ | _ _ _ || _ _ _ || _ _ | _ _ | _ _ | _ _ | * 1 |
// +-------+-----++-+-++-------+-------+-------++-------++-----+-----+-----+-----+-----+
.. \\||||:here:||||
"""
mapped = self.problem
if problem is None:
problem = mapped
else:
if mapped:
raise(SatokuError('problem already mapped'))
problem.split()
self.problem = problem
if problem is None:
return self
for csm in problem:
self.add_clause(csm)
self.progress('add clauses')
self.add_region()
self.variables = self.regions[-1]
if with_variables:
self.add_variables(problem)
self.progress('add variables')
self.add_region()
self.synthesized = self.regions[-1]
stats = self.stats
stats.init_variables = self.variables.size
stats.init_synthesized = self.synthesized.size
stats.init_clauses = len(self.clauses) - stats.init_variables -stats.init_synthesized
stats.init_rows = self.size
self.eval_problem_commands(problem.commands)
if no_conflicts:
return self
self.map_conflicts(delay_zero_updates)
self.progress('map conflicts')
return self
[docs] def parse_file(self, filename=None, has_variables=None, delay_zero_updates=None): # |:mth:|
"""
:returns: self for chaining.
"""
do_close = True
if not filename or filename == '-':
do_close = False
in_fh = sys.stdin
else:
in_fh = open(filename, 'r')
immediate = not delay_zero_updates
full_status_rx = '^(// [|] *[|][|] *[SPX] [|][|][ 0-9]+[|][ 0-9]+[|][|] . . .*[|][|])( [0-1] [0-1] [|])*(\\s)$'
# covers both `sol-matrix` and `satokdu.py`
status_rx = re.compile('// [|] *[|][|] *[SPX] [|][|][ 0-9]+[|][ 0-9]+[|][|]\\s*')
region_split_rx = re.compile('\\s*[|][|]\\s*')
cell_row_split_rx = re.compile('\\s*[|]\\s*')
truth_value_map = dict()
truth_value_map.update(((_s, 0) for _s in ('0', '*')))
truth_value_map.update(((_s, 1) for _s in ('1', '_')))
in_problem = False
line_prefix_width = 0
line_width = 0
row_indx = 0
def parse_regions(line_in):
regions = []
cell_rows = []
for _reg in re.split(region_split_rx, line_in):
_reg_crs = [[truth_value_map[_s] for _s in _cr.split()]
for _cr in re.split(cell_row_split_rx, _reg)]
regions.append(_reg_crs)
cell_rows.extend(_reg_crs)
return regions, cell_rows
for indx, line in enumerate(in_fh):
if in_problem:
if row_indx >= self.size:
# done
break
row_in = line[line_prefix_width:line_prefix_width + line_width]
if row_in.startswith('-'):
continue
cell_row_regions, cell_rows = parse_regions(row_in)
if _debug and False:
printe(sformat("// "":DBG: {1:<{0}s}: ]{2!s}[", dbg_fwid, "row_in", (row_in)))
printe(sformat("// "":DBG: {1:<{0}s}: ]{2!s}[", dbg_fwid, "cell_row_regions", (cell_row_regions)))
printe(sformat("// "":DBG: {1:<{0}s}: ]{2!s}[", dbg_fwid, "cell_rows", (cell_rows)))
si = self.row_clause_map[row_indx]
sj = self.row_literal_map[row_indx]
for sg, cell_row in enumerate(cell_rows):
for sh, value in enumerate(cell_row):
#printe(sformat("// "":DBG: {1:<{0}s}: ]{2!s}[", dbg_fwid, "zero_change", (si, sj, sg, sh)))
if not value:
self.zero_change(si, sj, sg, sh, immediate)
row_indx += 1
continue
mo = re.match(status_rx, line)
if mo:
in_problem = True
line_prefix_width = mo.end(0)
# |:todo:| parse status line and set up clauses
status_in = line[line_prefix_width:]
mo = re.search('.*[|]( [0*1_])+', status_in)
if mo:
line_width = mo.end(0)
status_in = status_in[:line_width]
#_debug and printe(sformat("// "":DBG: {1:<{0}s}: ]{2!s}[", dbg_fwid, "status_in", (status_in)))
region_sizes = []
cell_row_regions, cell_rows = parse_regions(status_in)
for rindx, region_cell_rows in enumerate(cell_row_regions):
region_sizes.append(len(region_cell_rows))
for cell_row in region_cell_rows:
csm = SMClause(len(self.clauses), self.size, None, self, len(cell_row))
self.add_clause(csm)
self.progress('add clauses')
self.eval_problem_commands([('r', region_sizes)])
self.progress('set regions')
if has_variables or has_variables is None:
clauses = self.clauses
failed = ' (fail)'
for region in reversed(self.regions):
ofs = region.ofs
failed = ' (good)'
for indx in range(region.size):
if clauses[ofs + indx].size != 2:
failed = ' (fail)'
break
if failed == ' (good)':
self.variables = region
break
if failed != ' (good)':
self.add_region()
self.variables = self.regions[-1]
self.add_region()
self.synthesized = self.regions[-1]
else:
if self.variables == self.regions[-1]:
self.add_region()
self.synthesized = self.regions[-1]
self.progress('set variables' + failed)
else:
self.add_region()
self.variables = self.regions[-1]
self.add_region()
self.synthesized = self.regions[-1]
stats = self.stats
stats.init_variables = self.variables.size
stats.init_synthesized = self.synthesized.size
stats.init_clauses = len(self.clauses) - stats.init_variables - stats.init_synthesized
stats.init_rows = self.size
# ||||||:here:||||||
self.progress('map conflicts')
if do_close:
in_fh.close()
return self
# --------------------------------------------------
# ||:sec:|| States
# --------------------------------------------------
[docs] def combine_states_(self, this, sj, that, sh): # |:mth:|
r"""
:returns: combined cell
"""
combined_cell = SMClause(matrix=self, size=3)
self.add_clause(combined_cell)
si = combined_cell.indx
sg0 = this.indx
sg1 = that.indx
for sh0 in range(this.size):
if sh0 == sj:
continue
self.zero_change(si, 0, sg0, sh0, True)
self.zero_change(si, 1, sg0, sh0, True)
for sh1 in range(that.size):
if sh1 == sh:
self.zero_change(si, 1, sg1, sh1, True)
continue
self.zero_change(si, 0, sg1, sh1, True)
# update trigger, before last row is completed
self.update_rows()
self.zero_change(si, 2, sg0, sj, True)
self.update_rows()
self.stats.state_combines += 1
return combined_cell
[docs] def combine_states(self, si, sj, sg, sh): # |:mth:|
r"""
:returns: combined cell
"""
this = self.clauses[si]
that = self.clauses[sg]
return self.combine_states_(this, sj, that, sh)
# --------------------------------------------------
# ||:sec:|| Combine Cells
# --------------------------------------------------
[docs] def combine_cells_(self, this, that, keep_uncombined=None, template_only=None, relaxed=None): # |:mth:|
r"""
:returns: combined cell
:param this: :class:`SMClause` instance.
:param that: :class:`SMClause` instance or None. If None, a
single clause is copied or moved.
"""
single_clause = this.indx == that.indx
if single_clause:
raise SatokuUnsatisfied(sformat("// ||"":ERR:|| error: illegal single clause combination {0} X {1}", this.repr(), that.repr()))
if that is None:
that = this
single_clause = True
cr_cell_rows = self.cell_rows_(this, that, True)
combined_size = sum([sum(_cr) for _cr in cr_cell_rows])
combined_size = 0
is_bound = True
for cr in cr_cell_rows:
cr_sum = sum(cr)
combined_size += cr_sum
if cr_sum > 1:
is_bound = False
def cell_dump(cell_rows):
return ' '.join(('[' + ' '.join((str(_c) for _c in _cr)) + ']' for _cr in cell_rows))
if combined_size < 2:
if not relaxed:
printe(sformat("// |"":WRN:| warning: illegal combined size {0} for {1} X {2} {3}", combined_size, this.repr(), that.repr(), cell_dump(cr_cell_rows)))
return None
if is_bound:
if not relaxed:
printe(sformat("// |"":WRN:| warning: fully bound CFRs (redundant) for {1} X {2} {3}", combined_size, this.repr(), that.repr(), cell_dump(cr_cell_rows)))
return None
if _debug:
printe(sformat(
"// "":CXC: {1:<{0}s}: ]{2!s}[", dbg_fwid, "combine cells", sformat('{0} X {1} {2}', this.repr(), that.repr(), cell_dump(cr_cell_rows))))
combined_cell = SMClause(matrix=self, size=combined_size)
self.add_clause(combined_cell)
# |:info:||:check:||:todo:| this is necessary, since sometimes
# a false negative (UNSAT) is reported. It seems to be
# sufficient to trigger an update right before the last
# combination is filled in (see below).
#
# For examples see
# - zz-www.sudokuwiki.org-0156-base
# - zz-www.sudokuwiki.org-0164-base
single_step_update = _debug and not template_only
single_step_update = not template_only
single_step_update = False
si = combined_cell.indx
sj = 0
update_trigger = combined_cell.size - 1
combined_sum = 0
for this_sj, cr_cell_row in enumerate(cr_cell_rows):
sg0 = this.indx
sg1 = that.indx
for that_sj, can_combine in enumerate(cr_cell_row):
if not can_combine:
continue
combined_sum += 1
# |:info:||:check:||:todo:| this seems to be
# sufficient to prevent the false UNSAT report.
if not single_step_update and not template_only and combined_sum == update_trigger:
if _debug:
printe(sformat("// "":PRC: update trigger{0}", ""))
self.update_rows()
if not self.row_status[combined_cell.ofs + sj]:
# killed by single step
if not relaxed:
printe(sformat("// "":DBG: combined cell already killed: s_ij({0}, {0})", si, sj))
continue
if not self.row_status[this.ofs + this_sj]:
# killed by single step
if not relaxed:
printe(sformat("// "":DBG: source cell row 0 already killed: s_ij({0}, {0})", sg0, this_sj))
self.kill_row(si, sj)
continue
if not self.row_status[that.ofs + that_sj]:
# killed by single step
if not relaxed:
printe(sformat("// "":DBG: source cell row 1 already killed: s_ij({0}, {0})", sg1, that_sj))
self.kill_row(si, sj)
continue
# request cell 1, row this_sj
for sh in range(this.size):
if sh == this_sj:
continue
self.zero_change(si, sj, sg0, sh,True)
# request cell 2, row that_sj
for sh in range(that.size):
if sh == that_sj:
continue
self.zero_change(si, sj, sg1, sh,True)
if single_step_update:
if _debug:
printe(sformat(
"// "":cXc: {1:<{0}s}: ]{2!s}[", dbg_fwid, "combine cell rows",
sformat('{0} X {1}',
self.fmt_cell_row(si,sj,sg0, True),
self.fmt_cell_row(si,sj,sg1, True))))
self.update_rows()
sj += 1
if not template_only:
if not single_step_update:
self.update_rows()
if not keep_uncombined:
self.delete_clause(this.indx)
if not single_clause:
self.delete_clause(that.indx)
self.stats.cell_combines += 1
return combined_cell
[docs] def combine_cells(self, si, sg, keep_uncombined=None, template_only=None, relaxed=None): # |:mth:|
r"""
:returns: combined cell
"""
this = self.clauses[si]
that = self.clauses[sg]
return self.combine_cells_(this, that, keep_uncombined, template_only, relaxed)
[docs] def find_bin_conflicts(self, vert_regions=None, horz_regions=None, full=None): # |:mth:|
r"""
:returns: list of cell index tuples (this, that)
"""
if vert_regions is None:
vert_regions = [_r for _r in self.regions if _r != self.variables]
if horz_regions is None:
horz_regions = vert_regions
combine_plan = []
marked = [0 for _i in range(len(self.clauses))]
vert_riter = SMRegionIterator(vert_regions)
horz_riter = SMRegionIterator(horz_regions)
for mtx_row in (self.clauses[indx] for indx in vert_riter):
si = mtx_row.indx
ri = mtx_row.ofs
if mtx_row.size < 3:
continue
# only first combination found
if not full and marked[si]:
continue
# |:todo:||:check:| is the area correct?
for cr_cell in (self.clauses[indx] for indx in horz_riter.at(si+1)):
sg = cr_cell.indx
ci = cr_cell.ofs
cwid = cr_cell.size
if cwid < 3 :
continue
# only first combination found
if not full and marked[sg]:
continue
# |:here:| for each cell row
is_bin_conflict = True
bc_ocr = None # conflict row with exactly 1 zero
bi_ocr = None # inverse conflict row with exactly 1 one
bc_count = 0
bi_count = 0
for sj, ocr in enumerate(self.cell_rows_(mtx_row, cr_cell, True)):
ones = sum(ocr)
if not sj:
bc_ocr = bytearray()
bi_ocr = bytearray()
zeroes = 0
ones = 0
for state in ocr:
if state == 0:
istate = 1
zeroes += 1
else:
istate = 0
ones += 1
bi_ocr.append(istate)
if zeroes == 1:
bc_ocr = ocr
bc_count += 1
elif ones == 1:
bc_ocr = bi_ocr
bi_ocr = ocr
bi_count += 1
else:
is_bin_conflict = False
break
continue
if ocr == bc_ocr:
bc_count += 1;
if bc_count > 1:
is_bin_conflict = False
break
elif ocr == bi_ocr:
bi_count += 1;
else:
is_bin_conflict = False
break
if bc_count != 1 or bi_count != mtx_row.size - 1:
is_bin_conflict = False
continue
marked[si] += 1
marked[sg] += 1
combine_plan.append((mtx_row, cr_cell))
if not full:
break
return combine_plan
[docs] def combine_bin_conflicts(self, vert_regions=None, horz_regions=None, full=None, keep_uncombined=None): # |:mth:|
r"""
:returns: number of cells combined
"""
combine_plan = self.find_bin_conflicts(
vert_regions, horz_regions, full=full)
uncombined = 0
if combine_plan:
for this, that in combine_plan:
cc = self.combine_cells_(this, that, keep_uncombined, relaxed=not _debug)
if cc is None:
uncombined += 1
return len(combine_plan) - uncombined
[docs] def find_reducable_cells(self, vert_regions=None, horz_regions=None, allow_equal=None, full=None): # |:mth:|
r"""
:returns: list of cell index tuples (this, that)
"""
if vert_regions is None:
vert_regions = [_r for _r in self.regions if _r != self.variables]
if horz_regions is None:
horz_regions = vert_regions
combine_plan = self.find_bin_conflicts(
vert_regions, horz_regions, full=full)
marked = [0 for _i in range(len(self.clauses))]
for this, that in combine_plan:
marked[this.indx] = 1
marked[that.indx] = 1
vert_riter = SMRegionIterator(vert_regions)
horz_riter = SMRegionIterator(horz_regions)
for mtx_row in (self.clauses[indx] for indx in vert_riter):
si = mtx_row.indx
ri = mtx_row.ofs
if mtx_row.size < 3:
continue
# only first combination found
if not full and marked[si]:
continue
# |:todo:||:check:| is the area correct?
for cr_cell in (self.clauses[indx] for indx in horz_riter.at(si+1)):
sg = cr_cell.indx
ci = cr_cell.ofs
cwid = cr_cell.size
if cwid < 3 :
continue
# only first combination found
if not full and marked[sg]:
continue
# |:here:| for each cell row
is_reducable = True
ones = sum([sum(_cr) for _cr in self.cell_rows_(mtx_row, cr_cell, True)])
limit = mtx_row.size + cr_cell.size
if allow_equal:
limit += 1
if ones < 4: # |:check:| what combines to 3? 3 x 3 => redundant
continue
if ones >= limit:
continue
marked[si] += 1
marked[sg] += 1
combine_plan.append((mtx_row, cr_cell))
if not full:
break
return combine_plan
[docs] def combine_reducable_cells(self, vert_regions=None, horz_regions=None, allow_equal=None, full=None, keep_uncombined=None): # |:mth:|
r"""
:returns: number of cells combined
"""
combine_plan = self.find_reducable_cells(
vert_regions, horz_regions, allow_equal=allow_equal, full=full)
uncombined = 0
if combine_plan:
for this, that in combine_plan:
template_only = False
if _debug:
stop_at = (-1, -1)
#stop_at = (16, 44)
template_only = this.indx == stop_at[0] and that.indx == stop_at[1]
which = sformat('{0} X {1}', this.repr(), that.repr())
cc = self.combine_cells_(this, that, keep_uncombined, template_only, relaxed=not _debug)
if cc is None:
uncombined += 1
if template_only:
self.opt_strip_variables = True
raise SatokuUnsatisfied(sformat('combine {0}', which))
return len(combine_plan) - uncombined
# --------------------------------------------------
# ||:sec:|| Output
# --------------------------------------------------
[docs] def dump_stats(self): # |:mth:|
"""
:returns: string representation.
"""
stats = self.stats
size = self.size
stats.satisfiable = self.satisfiable
stats.variables = self.variables.size
stats.synthesized = self.synthesized.size
stats.clauses = len(self.clauses) - stats.variables - stats.synthesized
stats.rows = size
stats.cells = size * size
stats.pending_zero_updates = len(self.zero_updates)
stats.pending_row_updates = len(self.row_updates)
stats.pending_superset_updates = len(self.superset_updates)
#help(pyjsmo.formatv.format_dict_as_text_table)
#stats_table = pyjsmo.formatv.format_dict_as_text_table(stats, sorted_=False, pretty=True)
stats_table = pyjsmo.table.TableMW(80)
stats_table.append(rows=[(k.replace('_', ' '), v) for k, v in ditems(stats)])
for row in stats_table.body:
row[1].align = '>'
stats_table.append(head=[['Satoku Statistics']])
head_col = stats_table.head[0][0]
head_col.span = 2
head_col.align = '^'
return re.sub('^(?m)', '// ', stats_table.output())
def sep_line(self, cindx_width, lindx_width, regions=None): # |:mth:|
regions = self.get_dump_regions(regions)
if not regions:
printe('// warning: SatokuMatrix.sep_line: regions is empty')
return
cindx_line = ''.join(['-' for i in xrange(cindx_width)])
lindx_line = ''.join(['-' for i in xrange(lindx_width)])
line = [sformat('// +-{0}-+-{1}-++-+-+', cindx_line, lindx_line)]
segments = []
cseq_indx = 0
for region in regions:
if region.size == 0:
continue
segments.append('+')
for ccsm in self.clauses[region.ofs:region.ofs+region.size]:
segment = ['']
for si in xrange(ccsm.size):
segment.append('-')
segment.append('+')
segments.append('-'.join(segment))
cseq_indx += 1
line.append(''.join(segments))
return ''.join(line)
def get_dump_regions(self, regions=None): # |:mth:|
if regions is None:
if self.opt_strip_variables:
regions = [_r for _r in self.regions if _r != self.variables]
else:
regions = list(self.regions)
return regions
[docs] def dump(self, immediate=False, regions=None, **kwargs): # |:mth:|
"""
:returns: string representation, if immediate is False, self otherwise.
"""
regions = self.get_dump_regions(regions)
if not regions:
printe('// warning: SatokuMatrix.dump: regions is empty')
return
cindx_width = 5
lindx_width = 3
lines = []
if immediate:
def line_out(line): # |:fnc:|
printf(line, **kwargs)
else:
def line_out(line): # |:fnc:|
lines.append(line)
sep_line = self.sep_line(cindx_width, lindx_width, regions)
if self.satisfiable:
status_mark = 'P'
else:
status_mark = 'X'
line = [sformat('// | {1:>{0}s} || {3:>{2}s} || | |', cindx_width, '', lindx_width-1, status_mark)]
self.row_status.fix_ones(self)
line.append(self.row_status.dump(self, -1, regions))
line_out(''.join(line))
line_out(sep_line)
rows = self.rows
cseq_indx = 0
for region in regions:
if region.size == 0:
continue
line_out(sep_line)
for csm in self.clauses[region.ofs:region.ofs+region.size]:
for ri in xrange(csm.size):
if ri == 0:
line = [sformat('// | {1:>{0}d} | {3:>{2}d} || | |', cindx_width, cseq_indx, lindx_width, ri)]
else:
line = [sformat('// | {1:>{0}s} | {3:>{2}d} || | |', cindx_width, '', lindx_width, ri)]
line.append(rows[csm.ofs+ri].dump(self, csm.indx, regions))
line_out(''.join(line))
line_out(sep_line)
cseq_indx += 1
if immediate:
return self
return '\n'.join(lines)
[docs] def image(self, output=None, format_=None, no_save=None, width=None, height=None): # |:mth:|
"""
:returns: PIL image.
>>> pr = Problem(TEST_PROBLEM)
>>> sm = SatokuMatrix(pr)
>>> ign = sm.update_rows()
.. >>> ign = sm.dump(immediate=True)
>>> sm.image(None, 'PPM') #doctest: +ELLIPSIS
P6
199 199
255
...
"""
if not have_pil:
raise SatokuError('matrix.image: sorry, PIL not available')
dump_it = False
need_format = False
if output is None or output == '-':
dump_it = True
output = BytesIO()
need_format = True
if format_ is None and need_format:
format_ = 'PNG'
if width is None:
width = IMG_WIDTH
if height is None:
height = IMG_HEIGHT
frame_width = 1
pix_width = 1
# remove empty trailing regions
regions = list(self.regions)
last_region = SMRegion()
while regions and regions[-1].size == 0:
last_region = regions.pop()
if not regions:
regions.append(last_region)
region_ct = len(regions)
calc_pix_row_width = lambda : ( # |:fnc:|
self.size * (pix_width + frame_width)
+ frame_width
+ (region_ct-1) * 2 * frame_width )
cl_ct = len(self.clauses)
pix_row_width = calc_pix_row_width()
while pix_width < PIX_WIDTH_MAX and pix_row_width < width:
pix_width += 1
pix_row_width = calc_pix_row_width()
if pix_row_width > width and pix_width > 1:
pix_width -= 1
pix_row_width = calc_pix_row_width()
use_width = pix_row_width
use_height = height
if use_width <= height:
use_height = use_width
# |:todo:| cannot deal with cut-offs, yet
use_height = use_width
im = Image.new("RGB", (use_width, use_height), "white")
pix = im.load()
if False:
printe(sformat(
"{0}{3:^{1}} {4:<{2}s}: ]{5!s}[",
dbg_comm, dbg_twid, dbg_fwid, ':DBG:', 'pix_width', pix_width))
printe(sformat(
"{0}{3:^{1}} {4:<{2}s}: ]{5!s}[",
dbg_comm, dbg_twid, dbg_fwid, ':DBG:', 'frame_width', frame_width))
printe(sformat(
"{0}{3:^{1}} {4:<{2}s}: ]{5!s}[",
dbg_comm, dbg_twid, dbg_fwid, ':DBG:', 'self.size', self.size))
printe(sformat(
"{0}{3:^{1}} {4:<{2}s}: ]{5!s}[",
dbg_comm, dbg_twid, dbg_fwid, ':DBG:', 'cl_ct', cl_ct))
printe(sformat(
"{0}{3:^{1}} {4:<{2}s}: ]{5!s}[",
dbg_comm, dbg_twid, dbg_fwid, ':DBG:', 'pix_row_width', pix_row_width))
printe(sformat(
"{0}{3:^{1}} {4:<{2}s}: ]{5!s}[",
dbg_comm, dbg_twid, dbg_fwid, ':DBG:', 'use_width', use_width))
printe(sformat(
"{0}{3:^{1}} {4:<{2}s}: ]{5!s}[",
dbg_comm, dbg_twid, dbg_fwid, ':DBG:', 'use_height', use_height))
hrule_outer = []
hrule_inner = []
inner_regions = list(regions)
inner_region = inner_regions.pop(0)
inner_rg_limit = inner_region.size
hrule_outer.append(FRAME_COLOR_OUTER)
hrule_inner.append(FRAME_COLOR_OUTER)
for ccsm in self.clauses:
ccsm_indx = ccsm.indx
pix_size = ccsm.size * (pix_width + frame_width)
if inner_rg_limit > 0 and inner_rg_limit <= ccsm_indx:
hrule_outer.append(BACKGROUND_COLOR)
hrule_outer.append(FRAME_COLOR_OUTER)
hrule_inner.append(BACKGROUND_COLOR)
hrule_inner.append(FRAME_COLOR_OUTER)
if not inner_regions:
inner_rg_limit = -1
else:
inner_region = inner_regions.pop(0)
inner_rg_limit += inner_region.size
hrule_outer.extend([FRAME_COLOR_OUTER for i in xrange(pix_size)])
hrule_inner.extend([FRAME_COLOR_INNER for i in xrange(pix_size)])
hrule_inner[-1] = FRAME_COLOR_OUTER
i_ri = 0
def draw_hrule(i_ri, hrule, frame_width=1): # |:fnc:|
# image, pix_row_width, frame_width, FRAME_COLOR
ri = 0
ci = 0
try:
for ri in xrange(frame_width):
use_ri = i_ri + ri
for ci, color in enumerate(hrule):
pix[ci, use_ri] = color
except IndexError:
(t, e, tb) = sys.exc_info()
import traceback
printe(''.join(traceback.format_tb(tb)), end='')
printe(sformat('{0}: {1}. i_ri: {2}, ri: {3}, ci: {4}',
t.__name__, e, i_ri, ri, ci))
del(tb)
raise
return i_ri + frame_width
def draw_row(i_ri, pix_row): # |:fnc:|
for ri in xrange(pix_width):
use_ri = i_ri + ri
for ci, color in enumerate(pix_row):
pix[ci, use_ri] = color
i_ri += pix_width
return i_ri
outer_regions = list(regions)
outer_region = outer_regions.pop(0)
outer_rg_limit = outer_region.size
i_ri = draw_hrule(i_ri, hrule_outer, frame_width)
for csm in self.clauses:
csm_indx = csm.indx
row_ofs = csm.ofs
row_count = csm.size
if outer_rg_limit > 0 and outer_rg_limit <= csm_indx:
i_ri += 1
i_ri = draw_hrule(i_ri, hrule_outer, frame_width)
if not outer_regions:
outer_rg_limit = -1
else:
outer_region = outer_regions.pop(0)
outer_rg_limit += outer_region.size
for ri in xrange(row_count):
inner_regions = list(regions)
inner_region = inner_regions.pop(0)
inner_rg_limit = inner_region.size
row = self.rows[row_ofs + ri]
pix_row = []
pix_row.extend([FRAME_COLOR_OUTER for i in xrange(frame_width)])
for ccsm in self.clauses:
ccsm_indx = ccsm.indx
astate_ofs = ccsm.ofs
col_count = ccsm.size
if inner_rg_limit > 0 and inner_rg_limit <= ccsm_indx:
pix_row.extend([BACKGROUND_COLOR for i in xrange(frame_width)])
pix_row.extend([FRAME_COLOR_OUTER for i in xrange(frame_width)])
if not inner_regions:
inner_rg_limit = -1
else:
inner_region = inner_regions.pop(0)
inner_rg_limit += inner_region.size
for ci in xrange(col_count):
color = PIX_COLORS[row[astate_ofs + ci]]
pix_row.extend([color for i in xrange(pix_width)])
pix_row.extend([FRAME_COLOR_INNER for i in xrange(frame_width)])
for i in xrange(frame_width):
pix_row[-(1 + i)] = FRAME_COLOR_OUTER
i_ri = draw_row(i_ri, pix_row)
i_ri = draw_hrule(i_ri, hrule_inner, frame_width)
i_ri = draw_hrule(i_ri-1, hrule_outer, frame_width)
if not no_save:
im.save(output, format_)
if dump_it:
sys.stdout.write(output.getvalue())
return im
# (progn (forward-line -1) (insert "\n") (snip-insert "py.s.meth" t t "py") (backward-symbol-tag 1 "fillme" "::"))
# (progn (forward-line -2) (insert "\n") (snip-insert "py.s.property" t t "py") (backward-symbol-tag 1 "fillme" "::"))
# (progn (forward-line -3) (insert "\n") (snip-insert "py.s.property.weakref" t t "py"))
__all__.append('LoopMark')
[docs]class LoopMark(object): # ||:cls:||
r"""
"""
beg = '/'
stp = '|'
end = '\\'
mark = beg
def __init__(self, *args, **kwargs): # |:mth:|
super(LoopMark, self).__init__(*args, **kwargs)
self.reset()
def __call__(self): # |:mth:|
mark = self.mark
self.mark = self.stp
return mark
def reset(self): # |:mth:|
self.mark = self.beg
return self.mark
def stop(self): # |:mth:|
self.reset()
return self.end
# (progn (forward-line -1) (insert "\n") (snip-insert "py.s.meth" t t "py") (backward-symbol-tag 1 "fillme" "::"))
# (progn (forward-line -2) (insert "\n") (snip-insert "py.s.property" t t "py") (backward-symbol-tag 1 "fillme" "::"))
# (progn (forward-line -1) (insert "\n") (snip-insert "py.s.class" t t "py") (backward-symbol-tag 1 "fillme" "::"))
# --------------------------------------------------
# |||:sec:||| FUNCTIONS
# --------------------------------------------------
__all__.append('parse_clauses_')
[docs]def parse_clauses_(string): # ||:fnc:||
"""
>>> parse_clauses(TEST_PROBLEM)
([[[1, -1, -1, 0, -1], [0, 1, -1, -1, -1], [0, 0, 1, -1, -1]], [1, 0, 1, -1, -1], [0, 1, 0, -1, -1], [-1, 1, 0, 1], [-1, -1, 0, 1, 1], [[-1, 0, -1, -1, -1], [-1, 1, -1, 1, -1], [-1, 1, -1, 0, 0]]], [])
>>> parse_clauses(TEST_PROBLEM_NOCFL)
([[[1, -1, -1, 1, -1], [1, 1, -1, -1, -1], [1, 1, 1, -1, -1]], [1, 1, 1, -1, -1], [1, 1, 1, -1, -1], [-1, 1, 1, 1], [-1, -1, 1, 1, 1], [[-1, 1, -1, -1, -1], [-1, 1, -1, 1, -1], [-1, 1, -1, 1, 1]]], [])
>>> parse_clauses(TEST_PROBLEM_REGIONS)
([[[1, -1, -1, 0, -1], [0, 1, -1, -1, -1], [0, 0, 1, -1, -1]], [1, 0, 1, -1, -1], [0, 1, 0, -1, -1], [-1, 1, 0, 1], [-1, -1, 0, 1, 1], [[-1, 0, -1, -1, -1], [-1, 1, -1, 1, -1], [-1, 1, -1, 0, 0]]], [('r', '3 2 1 5 9 10')])
:returns: list of parsed clauses.
"""
clauses = []
while string:
mo = re.search('[][]', string)
if mo:
sep = mo.group(0)
sub_clauses, sub_string = parse_clauses_(string[0:mo.start()].strip())
clauses.extend(sub_clauses)
if sep == '[':
cl = Clause()
sub_clauses, string = parse_clauses_(string[mo.end():].lstrip())
cl.extend(sub_clauses)
clauses.append(cl.fold())
continue
return clauses, string[mo.end():].lstrip()
else:
for line in string.strip().splitlines():
clauses.append(ClauseVector(line))
string = ''
break
return clauses, string
__all__.append('clean_clauses')
[docs]def clean_clauses(string): # ||:fnc:||
"""
>>> printf(clean_clauses(TEST_PROBLEM))
[[ 1 - - 0 - ]
[ 0 1 - - - ]
[ 0 0 1 - - ]]
[ 1 0 1 - - ]
[ 0 1 0 - - ]
- 1 0 1
- - 0 1 1
[ - 0 - - -
- 1 - 1 -
- 1 - 0 0 ]
:returns: list of parsed clauses.
"""
lines = []
for line in string.splitlines():
line = line.lstrip()
if not line:
continue
if line.startswith('//'):
continue
line = re.sub('//.*$', '', line).strip()
lines.append(line)
string = '\n'.join(lines).strip()
return string
__all__.append('parse_clauses')
[docs]def parse_clauses(string): # ||:fnc:||
"""
:returns: list of parsed clauses.
"""
commands = []
cstring = string
while cstring:
mo = re.search('^//(:?)([lr])(:?)(.*)(?mi)', cstring)
if mo:
if not mo.group(1) and not mo.group(3):
cstring = cstring[mo.end(0):]
continue
command = mo.group(0)
commands.append((mo.group(2).lower(), mo.group(4).strip()))
cstring = cstring[mo.end(0):]
else:
break
string = clean_clauses(string)
clauses, string = parse_clauses_(string)
return clauses, commands
__all__.append('permute_cols')
[docs]def permute_cols(used_cols): # ||:fnc:||
"""
:returns: clause with permuted columns.
>>> printf(permute_cols([0, 2, 3]))
[ 0 _ 0 0 ]
[ 0 _ 0 1 ]
[ 0 _ 1 0 ]
[ 0 _ 1 1 ]
[ 1 _ 0 0 ]
[ 1 _ 0 1 ]
[ 1 _ 1 0 ]
[ 1 _ 1 1 ]
"""
permutations = Clause()
cv = ClauseVector()
cur_cvs = [cv]
for col in used_cols:
next_cvs = []
for cur_cv in cur_cvs:
cv = ClauseVector(cur_cv)
cv[col] = 0
next_cvs.append(cv)
cv = ClauseVector(cur_cv)
cv[col] = 1
next_cvs.append(cv)
cur_cvs = next_cvs
permutations.extend(cur_cvs)
return permutations
# (progn (forward-line -1) (insert "\n") (snip-insert "py.s.func" t t "py") (backward-symbol-tag 1 "fillme" "::"))
# (progn (forward-line 1) (snip-insert "py_wsrfid.module_route" t t "py") (insert ""))
# --------------------------------------------------
# |||:sec:||| UTILITIES
# --------------------------------------------------
__all__.append('dump_regions')
[docs]def dump_regions(regions, start=None): # ||:fnc:||
r"""
:returns: string repr of regions
"""
if start is None:
start = 0
return ' / '.join((': '.join(('r' + str(start + _i), ', '.join((str(_v) for _k, _v in ditems(_r))))) for _i, _r in enumerate(regions)))
# (progn (forward-line -1) (insert "\n") (snip-insert "py.s.func" t t "py") (backward-symbol-tag 1 "fillme" "::"))
# (progn (forward-line 1) (snip-insert "py.wsrfid.dispatch.request" t t "py") (insert ""))
# (progn (forward-line 1) (snip-insert "py_f.findfile" t t "py") (insert ""))
# (progn (forward-line 1) (snip-insert "py.c.placeholder.template" t t "py") (insert "\n"))
# (progn (forward-line 1) (snip-insert "py.c.key.hash.ordered.dict" t t "py") (insert "\n"))
# (progn (forward-line 1) (snip-insert "py.c.progress" t t "py") (insert "\n"))
# --------------------------------------------------
# |||:sec:||| PROGRESS
# --------------------------------------------------
import datetime
class Progress: # ||:cls:||
"""Report progress time and duration.
>>> prg = Progress(quiet=True)
>>> prg.step('Hello World', file=sys.stdout)
>>> prg.quiet = False
>>> prg.stop(file=sys.stdout) #doctest: +ELLIPSIS
// |:TIM:| end : [...-...-... ...:...:...] step: [...:...:...] total: [...:...:...]
>>> _quiet = False
>>> prg = Progress(comment="// ", quiet=_quiet, file=sys.stderr)
>>> prg.step('Hello World')
>>> prg.stop()
"""
def out(self, string, **kwargs): # |:mth:|
"""print message, if not self.quiet
"""
if self.quiet:
return
kwargs['file'] = kwargs.get('file', self.file)
printf(string, **kwargs)
def __init__(self, comment=None, tag_bars='|', quiet=None, **kwargs): # |:mth:|
now = datetime.datetime.now()
self.start_ = now
self.step_ = now
self.end_ = now
if comment is None:
comment = ((('dbg_comm' in globals()) and (globals()['dbg_comm'])) or ('# '))
self.comment = comment
self.tag_bars = tag_bars
self.quiet = quiet
self.file = kwargs.pop('file', sys.stderr)
self.out(sformat("{0}{2:^{1}} {4:<{3}s}: [{5!s}]",
self.comment,
((('dbg_twid' in globals()) and (globals()['dbg_twid'])) or (9)),
sformat('{0}:TIM:{0}',self.tag_bars),
((('dbg_fwid' in globals()) and (globals()['dbg_fwid'])) or (15)),
'start', self.start_))
def save(self): # |:mth:|
"""Get progress state.
"""
state = (self.step_,)
return state
def restore(self, state=None): # |:mth:|
"""Restore progress state.
:param state: progress state.
"""
if state:
self.step_ = state[0]
return self
def step(self, mark='break', intermediate=None, state=None, info=None, **kwargs): # |:mth:|
"""step message.
:param file: override for output file.
"""
if info:
self.out(sformat("{0}{2:^{1}} {4:<{3}s}: ]{5!s}[",
self.comment,
((('dbg_twid' in globals()) and (globals()['dbg_twid'])) or (9)),
sformat('{0}:INF:{0}',self.tag_bars),
((('dbg_fwid' in globals()) and (globals()['dbg_fwid'])) or (15)),
mark, info
), **kwargs)
return
now = datetime.datetime.now()
self.restore(state)
self.end_ = now
self.out(sformat("{0}{2:^{1}} {4:<{3}s}: [{5!s}] step: [{6}] total: [{7}]",
self.comment,
((('dbg_twid' in globals()) and (globals()['dbg_twid'])) or (9)),
sformat('{0}:TIM:{0}',self.tag_bars),
((('dbg_fwid' in globals()) and (globals()['dbg_fwid'])) or (15)),
mark, self.end_,
(self.end_ - self.step_),
(self.end_ - self.start_),
), **kwargs)
if not intermediate:
self.step_ = now
def stop(self, **kwargs): # |:mth:|
"""stop message.
:param file: override for output file.
"""
self.step('end', **kwargs)
class ProgressNull(object): # ||:cls:||
'''Basic progress counter.
'''
def __call__(self, done=False, *args, **kwargs): # |:mth:|
item_no = self.item_no
if not done:
self.item_no += 1
step = self.step
if step == 1 or (item_no % step) == 0:
self.step_no += 1
return item_no
def __init__(self, length=50, step=1, file=None, **kwargs): # |:mth:|
self.length = length
self.step = step
self.file = kwargs.pop('file', sys.stderr)
self.item_no = 0
self.step_no = 0
class ProgressDot(ProgressNull): # ||:cls:||
'''
Display progress dots.
>>> pd = ProgressDot(5,4)
>>> for s in range(40):
... pd(done=False)
>>> pd(done=True)
>>> pd = ProgressDot(5,4)
>>> for s in range(39):
... pd(done=False)
>>> pd(done=True)
'''
def __call__(self, done=False, *args, **kwargs): # |:mth:|
step_no = self.step_no
item_no = super(ProgressDot, self).__call__(done, *args, **kwargs)
if not done:
if (item_no % (self.step * self.length)) == 0:
if step_no:
printf(file=self.file)
printf(sformat('{0:>3d}: ', item_no), file=self.file, end='')
if self.step_no > step_no:
printf('.', file=self.file, end='')
else:
printf(sformat(' ({0:d})', self.item_no), file=self.file)
# (progn (forward-line 1) (snip-insert "py.f.hl" t t "py") (insert "\n"))
hlr = None
def hlcr(title=None, tag='|||' ':CHP:|||', rule_width=50, **kwargs): # ||:fnc:||
comm = ((('dbg_comm' in globals()) and (globals()['dbg_comm'])) or ('# '))
dstr = []
dstr.append(''.join((comm, '-' * rule_width)))
if title:
dstr.append(sformat('{0}{2:^{1}} {3!s}',
comm, ((('dbg_twid' in globals()) and (globals()['dbg_twid'])) or (9)),
tag, title))
dstr.append(''.join((comm, '-' * rule_width)))
return '\n'.join(dstr)
def hlsr(title=None, tag='||' ':SEC:||', rule_width=35, **kwargs): # |:fnc:|
return hlcr(title, tag, rule_width)
def hlssr(title=None, tag='|' ':INF:|', rule_width=20, **kwargs): # |:fnc:|
return hlcr(title, tag, rule_width)
def hlc(*args, **kwargs): # |:fnc:|
for line in hlcr(*args, **kwargs).splitlines():
printe(line, **kwargs)
def hls(*args, **kwargs): # |:fnc:|
for line in hlsr(*args, **kwargs).splitlines():
printe(line, **kwargs)
def hlss(*args, **kwargs): # |:fnc:|
for line in hlssr(*args, **kwargs).splitlines():
printe(line, **kwargs)
def hl(*args, **kwargs): # |:fnc:|
for line in hlr(*args, **kwargs).splitlines():
printe(line, **kwargs)
def hl_lvl(level=0): # |:fnc:|
global hlr
if level == 0:
hlr = hlssr
elif level == 1:
hlr = hlsr
else:
hlr = hlcr
hl_lvl(0)
# (progn (forward-line 1) (snip-insert "py.f.single.quote" t t "py") (insert "\n"))
# (progn (forward-line 1) (snip-insert "py.f.remove.match" t t "py") (insert "\n"))
# (progn (forward-line 1) (snip-insert "py.f.printenv" t t "py") (insert "\n"))
# (progn (forward-line 1) (snip-insert "py.f.uname-s" t t "py") (insert "\n"))
# (progn (forward-line 1) (snip-insert "py.f.printe" t t "py") (insert ""))
if 'printe' not in globals() or globals().get('_is_main_', (__name__ == '__main__')):
def printe(*args, **kwargs):
kwargs['file'] = kwargs.get('file', sys.stderr)
printf(*args, **kwargs)
printd = printe
printw = printe
printx = printe
# (progn (forward-line 1) (snip-insert "py.f.dbg.squeeze" t t "py") (insert "\n"))
# (progn (forward-line 1) (snip-insert "py.f.dbg.indent" t t "py") (insert "\n"))
def run(parameters, pass_opts): # ||:fnc:||
"""Application runner, when called as __main__."""
# (progn (forward-line 1) (snip-insert "py.bf.sql.ws" t t "py") (insert "\n"))
# (progn (forward-line 1) (snip-insert "py.bf.file.arg.loop" t t "py") (insert "\n"))
# (progn (forward-line 1) (snip-insert "py_wsrfid.wsuvv_run" t t "py") (insert "\n"))
if not parameters.args:
parameters.args.append('-')
filename = parameters.args[0]
prg_quiet = _quiet
opt_quick_convert = parameters.quick_convert
if opt_quick_convert:
parameters.from_matrix = True
parameters.update = False
opt_strip_variables = parameters.strip_variables
opt_from_matrix = parameters.from_matrix
if opt_from_matrix:
parameters.action = 0
action = parameters.action
if action == 0:
# matrix
if parameters.sort is None:
parameters.sort = True
parameters.split = True
if parameters.conflicts is None:
parameters.conflicts = True
elif action == 1:
# beautify
if not prg_quiet:
prg_quiet = not _verbose
if parameters.xor is None:
if parameters.conflicts is None:
if parameters.fast_conflicts or parameters.full_conflicts:
parameters.conflicts = True
pass
prg = Progress(quiet=prg_quiet, tag_bars='')
if parameters.header is None:
parameters.header = True
if parameters.footer is None:
parameters.footer = True
if parameters.expand:
if parameters.flatten is None:
parameters.flatten = True
parameters.flatten = None
if parameters.sort is None:
parameters.sort = True
if parameters.conflicts:
parameters.split = True
if parameters.image:
parameters.footer = False
# |:here:| parse matrix or FCA
problem = Problem()
if not opt_from_matrix:
problem.parse_file(filename)
prg.step('read problem')
if parameters.sort:
problem.sort()
prg.step('sort problem')
if parameters.split:
problem.split()
prg.step('split problem')
re_sort = False
if parameters.minimize:
problem.minimize()
prg.step('minimize P')
re_sort = parameters.sort
if parameters.flatten:
problem.flatten()
prg.step('flatten P')
re_sort = parameters.sort
if parameters.expand:
prg_state = prg.save()
problem.sort()
problem[:] = reversed(problem)
if _verbose:
problem._pyjsmo_x_progress = prg
problem.expand()
problem._pyjsmo_x_progress = None
prg.step('expand P', state=prg_state)
re_sort = parameters.sort
if re_sort:
problem.sort()
prg.step('sort problem')
if parameters.conflicts:
max_max = parameters.fast_conflicts or parameters.full_conflicts
if max_max:
if parameters.keep_min_problem is None:
max_used = problem.max_used()
if max_used > 1:
parameters.keep_min_problem = True
if parameters.keep_min_problem:
min_problem = copy.deepcopy(problem)
if max_max:
problem.max_max_conflicts(full=parameters.full_conflicts)
else:
problem.max_conflicts()
if parameters.keep_min_problem:
min_problem.extend(problem)
problem = min_problem
prg.step('max conflicts')
if parameters.xor:
problem.xor_conflicts()
prg.step('xor_conflicts')
# |:here:|
error = 0
if action == 1: # --beautify
if not parameters.split:
problem.fold()
else:
problem.split()
problem.set_width()
if parameters.annotate:
clause_types = CLAUSE_TYPES
# |:todo:| reverse clause types
problem.annotate(clause_types)
if parameters.header:
printf(HEADER)
printf(sformat(
"{0}{3:^{1}} {4:<{2}s}: ]{5!s}[",
dbg_comm, dbg_twid, dbg_fwid, ':INF:', 'clauses', len(problem)))
printf(sformat(
"{0}{3:^{1}} {4:<{2}s}: ]{5!s}[",
dbg_comm, dbg_twid, dbg_fwid, ':INF:', 'variables', problem.max_width()))
printf(problem)
else: # --matrix
matrix = SatokuMatrix(progress=prg)
matrix.opt_strip_variables = opt_strip_variables
opt_drop_1_states = parameters.drop_1_states
if opt_drop_1_states is None:
opt_drop_1_states = parameters.update
try:
prg_state = prg.save()
if opt_from_matrix:
matrix.parse_file(filename, has_variables=parameters.variables, delay_zero_updates=parameters.delay_zero_updates)
prg.step('parse matrix', state=prg_state)
if not parameters.keep_killed:
prg_state = prg.save()
matrix.delete_killed_rows()
prg.step('drop kill rows', state=prg_state)
else:
matrix.map_problem(problem, with_variables=parameters.variables, delay_zero_updates=parameters.delay_zero_updates)
prg.step('map problem', state=prg_state)
if parameters.update:
prg_state = prg.save()
matrix.update_rows()
prg.step('update rows', state=prg_state)
if opt_drop_1_states:
prg_state = prg.save()
matrix.delete_single_clues()
prg.step('drop 1-states', state=prg_state)
if not parameters.keep_killed:
prg_state = prg.save()
matrix.delete_killed_rows()
prg.step('drop kill rows', state=prg_state)
if parameters.drop_2_states:
if not parameters.variables:
printe(sformat("// |"":WRN:| warning: `--drop-2-states` without `--variables`{0}", ""))
prg_state = prg.save()
matrix.delete_2_state_cell_rows()
prg.step('drop 2-states', state=prg_state)
if parameters.reduce_cells:
parameters.bin_conflicts = False # included as precedence by `--reduce-cells`
if parameters.update:
opt_keep_uncombined = parameters.keep_uncombined
if parameters.redundant:
prg_state = prg.save()
matrix.delete_redundant_clauses(strictly_inside=True)
prg.step('drop redundant', state=prg_state)
# solver loop
prg_state_solver = prg.save()
lmark = LoopMark()
algo_calls = 0
while True:
lmark.reset()
if parameters.reduce_cells:
prg_state = prg.save()
opt_allow_equal = parameters.allow_equal
total_combined = 0
rounds = 0
while True:
combined = matrix.combine_reducable_cells(allow_equal=opt_allow_equal, keep_uncombined=opt_keep_uncombined)
algo_calls += 1
total_combined += combined
rounds += 1
if combined or not total_combined:
prg.step(sformat('{0}reducable cells {1}', lmark(), combined))
if not combined:
break
if not parameters.keep_killed:
matrix.delete_killed_rows()
prg.step(sformat('{0}drop kill rows', lmark()))
if opt_keep_uncombined:
break
if parameters.redundant:
matrix.delete_redundant_clauses(strictly_inside=True)
prg.step(sformat('{0}drop redundant', lmark()))
if total_combined and rounds > 2:
prg.step(sformat('{0}total combined {1}', lmark(), total_combined), state=prg_state)
elif parameters.bin_conflicts:
prg_state = prg.save()
total_combined = 0
rounds = 0
while True:
combined = matrix.combine_bin_conflicts(keep_uncombined=opt_keep_uncombined)
algo_calls += 1
total_combined += combined
rounds += 1
if combined or not total_combined:
prg.step(sformat('{0}bin conflicts {1}', lmark(), combined))
if not combined:
break
if not parameters.keep_killed:
matrix.delete_killed_rows()
prg.step(sformat('{0}drop kill rows', lmark()))
if opt_keep_uncombined:
break
if parameters.redundant:
matrix.delete_redundant_clauses(strictly_inside=True)
prg.step(sformat('{0}drop redundant', lmark()))
if total_combined and rounds > 2:
prg.step(sformat('{0}total combined {1}', lmark(), total_combined), state=prg_state)
total_row_kills = 0
if parameters.check_minor_ccrs:
prg_state = prg.save()
vert_regions, horz_regions, min_height = matrix.minor_ccr_default_param(
#vert_regions, horz_regions, min_height
)
rounds = 0
while True:
row_kills = matrix.check_minor_ccrs(vert_regions, horz_regions, min_height)
algo_calls += 1
total_row_kills += row_kills
rounds += 1
if row_kills or not total_row_kills:
prg.step(sformat('{0}check minor CCRs {1}', lmark(), row_kills))
if not row_kills:
break
if not parameters.keep_killed:
matrix.delete_killed_rows()
prg.step(sformat('{0}drop kill rows', lmark()))
if parameters.redundant and not opt_keep_uncombined:
matrix.delete_redundant_clauses(strictly_inside=True)
prg.step(sformat('{0}drop redundant', lmark()))
if total_row_kills and rounds > 2:
prg.step(sformat('{0}total row_kills {1}', lmark(), total_row_kills), state=prg_state)
if opt_keep_uncombined:
break
if not total_row_kills:
break
if algo_calls:
prg.step(sformat('{0}solver loop', lmark.stop()), state=prg_state_solver)
except SatokuUnsatisfied:
(t, e, tb) = sys.exc_info()
printe(sformat('// {0}', e))
printf(sformat('// {0}', e))
del(tb)
except SatokuSatisfied:
pass
except SatokuDone:
pass
if parameters.image:
matrix.image(parameters.image)
else:
prg_state = prg.save()
if parameters.header:
printf(HEADER)
regions = None
matrix.dump(immediate=True, regions=regions)
printf(SM_INFO)
if not _quiet:
printf(matrix.dump_stats())
prg.step('processed', intermediate=True, file=sys.stdout, state=prg_state)
error = (not matrix.satisfiable and 1) or 0
if parameters.footer:
fh = os.popen("snr --mode fca '^fca_footer$' 2>/dev/null", 'r')
footer = fh.read().strip()
fh.close()
if not footer:
footer = FOOTER
printf()
printf(footer)
prg.stop()
return error
# |:here:|
pass
# --------------------------------------------------
# |||:sec:||| MAIN
# --------------------------------------------------
_quiet = False
_verbose = False
_debug = False
# (progn (forward-line 1) (snip-insert "py.f.setdefaultencoding" t t "py") (insert "\n"))
file_encoding_is_clean = False
def setdefaultencoding(encoding=None, quiet=False):
if file_encoding_is_clean:
return
if encoding is None:
encoding='utf-8'
try:
isinstance('', basestring)
if not hasattr(sys, '_setdefaultencoding'):
if not quiet:
printf('''\
Add this to /etc/python2.x/sitecustomize.py,
or put it in local sitecustomize.py and adjust PYTHONPATH=".:${PYTHONPATH}"::
try:
import sys
setattr(sys, '_setdefaultencoding', getattr(sys, 'setdefaultencoding'))
except AttributeError:
pass
Running with reload(sys) hack ...
''', file=sys.stderr)
reload(sys)
setattr(sys, '_setdefaultencoding',
getattr(sys, 'setdefaultencoding'))
sys._setdefaultencoding(encoding)
except NameError:
# python3 already has utf-8 default encoding ;-)
pass
def main(argv): # ||:fnc:||
global _quiet, _debug, _verbose
global RtAdHoc, AdHoc
_parameters = None
_pass_opts = []
try:
import argparse
except ImportError:
printe('error: argparse missing. Try `easy_install argparse`.')
sys.exit(1)
parser = argparse.ArgumentParser(add_help=False)
# parser.add_argument('--sum', dest='accumulate', action='store_const',
# const=sum, default=max,
# help='sum the integers (default: find the max)')
# |:opt:| add options
parser.add_argument(
'-s', '--sort', action='store_true',
default=None, dest='sort', help='sort clause vectors (default for --matrix)')
parser.add_argument(
'--no-sort', action='store_false',
default=None, dest='sort', help='do not sort clause vectors (default for --beautify)')
parser.add_argument(
'--minimize', action='store_true',
default=None, help='minimize clauses')
parser.add_argument(
'--flatten', action='store_true',
default=None, help='expand each clause, converting a AND/OR/AND problem to a flat AND/OR problem')
parser.add_argument(
'--expand', action='store_true',
default=None, help='create full problem expansion (implies --sort)')
parser.add_argument(
'--split', action='store_true',
default=None, help='split clause vectors into single-literal clauses (implied by --matrix)')
parser.add_argument(
'-c', '--conflicts', action='store_true',
default=None, dest='conflicts', help='maximize conflicts, single variable (implies --split, default for --matrix)')
parser.add_argument(
'--no-conflicts', action='store_false',
default=None, dest='conflicts', help='do not maximize conflicts (default for --beautify)')
parser.add_argument(
'--fast-conflicts', action='store_true',
default=None, help='maximize conflicts, fast conjunction cover (implies --conflicts)')
parser.add_argument(
'--full-conflicts', action='store_true',
default=None, help='maximize conflicts, full conjunction cover (implies --conflicts)')
parser.add_argument(
'--keep-min-problem', action='store_true',
default=None, help='keep minimal problem when maximizing conflicts (auto-detected by --fast-conflicts, --full_conflicts)')
parser.add_argument(
'-x', '--xor', action='store_true',
default=None, dest='xor', help='create XOR problem')
parser.add_argument(
'--no-xor', action='store_false',
default=None, dest='xor', help='do not create XOR problem (default for --beautify)')
parser.add_argument(
'-h', '--header', action='store_true',
default=None, dest='header', help='append HEADER (default)')
parser.add_argument(
'--no-header', action='store_false',
default=None, dest='header', help='do not append HEADER')
parser.add_argument(
'-f', '--footer', action='store_true',
default=None, dest='footer', help='append FOOTER (default)')
parser.add_argument(
'--no-footer', action='store_false',
default=None, dest='footer', help='do not append FOOTER')
parser.add_argument(
'-b', '--beautify', action='store_const', const = 1,
default=0, dest='action', help='beautify clause vectors')
parser.add_argument(
'-a', '--annotate', action='store_true',
default=None, help='annotate clause vectors (AND/OR)')
parser.add_argument(
'-m', '--matrix', action='store_const', const = 0,
default=0, dest='action', help='create matrix (default)')
parser.add_argument(
'--from-matrix', action='store_true',
default=None, help='parse Satoku Matrix (implies `--matrix`)')
parser.add_argument(
'--quick-convert', action='store_true',
default=None, help='dump Satoku Matrix after parsing (implies `--matrix`, `--no-update`)')
parser.add_argument(
'-v', '--variables', action='store_true',
default=True, dest='variables', help='map variables (default)')
parser.add_argument(
'--no-variables', action='store_false',
default=True, dest='variables', help='do not map variables')
parser.add_argument(
'--drop-variables', action='store_true',
default=None, help='delete variables (not implemented |:todo:|)')
parser.add_argument(
'--strip-variables', action='store_true',
default=None, help='dump Satoku Matrix without variables')
parser.add_argument(
'-u', '--update', action='store_true',
default=True, dest='update', help='update rows (default)')
parser.add_argument(
'--no-update', action='store_false',
default=True, dest='update', help='do not update rows')
parser.add_argument(
'--immediate-zeroes', action='store_false',
default=None, dest='delay_zero_updates', help='immediately follow zero updates (default)')
parser.add_argument(
'--delay-zeroes', action='store_true',
default=None, dest='delay_zero_updates', help='delay zero updates')
parser.add_argument(
'-r', '--redundant', action='store_true',
default=True, dest='redundant', help='remove redundant clauses (default)')
parser.add_argument(
'--no-redundant', action='store_false',
default=True, dest='redundant', help='do not remove redundant clauses')
parser.add_argument(
'--no-bin-conflicts', action='store_false',
default=None, dest='bin_conflicts', help='do not combine binary conflict cell states (default)')
parser.add_argument(
'--bin-conflicts', action='store_true',
default=None, dest='bin_conflicts', help='combine binary conflict cell states')
parser.add_argument(
'--no-reduce-cells', action='store_false',
default=None, dest='reduce_cells', help='do not reduce cells (default)')
parser.add_argument(
'--reduce-cells', action='store_true',
default=None, dest='reduce_cells', help='reduce cells')
parser.add_argument(
'--strictly-less', action='store_false',
default=None, dest='allow_equal', help='reduction must be strictly less space')
parser.add_argument(
'--allow-equal', action='store_true',
default=None, dest='allow_equal', help='reduction may use equal amount of space')
parser.add_argument(
'--drop-uncombined', action='store_false',
default=None, dest='keep_uncombined', help='drop uncombined cell states (default)')
parser.add_argument(
'--keep-uncombined', action='store_true',
default=None, dest='keep_uncombined', help='keep uncombined cell states')
parser.add_argument(
'--no-minor-ccrs', action='store_false',
default=None, dest='check_minor_ccrs', help='do not check minor CCRs (default)')
parser.add_argument(
'--check-minor-ccrs', action='store_true',
default=None, dest='check_minor_ccrs', help='check minor CCRs')
parser.add_argument(
'--drop-1-states', action='store_true', dest='drop_1_states',
default=None, help='remove 1-state rows after requirement update (default with `--update`)')
parser.add_argument(
'--keep-1-states', action='store_false', dest='drop_1_states',
default=None, help='keep 1-state rows after requirement update (default without `--update`)')
parser.add_argument(
'--keep-2-states', action='store_false', dest='drop_2_states',
default=None, help='keep 2-state rows after requirement update (default)')
parser.add_argument(
'--drop-2-states', action='store_true', dest='drop_2_states',
default=None, help='remove 2-state rows after requirement update (usually used with `--update`, `--variables`)')
parser.add_argument(
'--drop-snf-conflicts', action='store_true', dest='drop_2_states',
default=False, help='remove 2-state rows (deprecated, use `--drop-2-states`)')
parser.add_argument(
'--drop-killed', action='store_false', dest='keep_killed',
default=False, help='delete killed rows (default)')
parser.add_argument(
'--keep-killed', action='store_true',
default=False, help='do not delete killed rows')
parser.add_argument(
'-i', '--image', nargs='?', action='store', type=str, metavar='NAME',
default = None, const = '-',
help='save image. Default: - (stdout)')
parser.add_argument(
'-q', '--quiet', action='store_const', const=-2,
dest='debug', default=0, help='suppress warnings')
parser.add_argument(
'--verbose', action='store_const', const=-1,
dest='debug', default=0, help='verbose test output')
parser.add_argument(
'-d', '--debug', nargs='?', action='store', type=int, metavar='NUM',
default = 0, const = 1,
help='show debug information')
parser.add_argument(
'-t', '--test', action='store_true',
help='run doc tests')
class AdHocAction(argparse.Action):
def __call__(self, parser, namespace, values, option_string=None):
list(map(lambda opt: setattr(namespace, opt, False),
('implode', 'explode', 'extract', 'template', 'eide')))
setattr(namespace, option_string[2:], True)
setattr(namespace, 'adhoc_arg', values)
parser.add_argument(
'--implode', nargs=0, action=AdHocAction, default=False,
help='implode script with adhoc')
parser.add_argument(
'--explode', nargs='?', action=AdHocAction, type=str, metavar='DIR',
default=False, const='__adhoc__',
help='explode script with adhoc in directory DIR'
' (default: `__adhoc__`)')
parser.add_argument(
'--extract', nargs='?', action=AdHocAction, type=str, metavar='DIR',
default=False, const = '.',
help='extract files to directory DIR (default: `.`)')
parser.add_argument(
'--template', nargs='?', action=AdHocAction, type=str, metavar='NAME',
default=False, const = '-',
help='extract named template to standard output. default NAME is ``-``')
parser.add_argument(
'--eide', nargs='?', action=AdHocAction, type=str, metavar='COMM',
default=False, const = '',
help='Emacs IDE template list (implies --template list).')
parser.add_argument(
'-?', '--help', action='store_true',
help="display this help message")
parser.add_argument(
'--ap-help', action='store_true',
help="internal help message")
parser.add_argument(
'args', nargs='*', metavar='arg',
#'args', nargs='+', metavar='arg',
#type=argparse.FileType('r'), default=sys.stdin,
help='a series of arguments')
#_parameters = parser.parse_args()
(_parameters, _pass_opts) = parser.parse_known_args(argv[1:])
# generate argparse help
if _parameters.ap_help:
parser.print_help()
return 0
# standard help
if _parameters.help:
help_ = re.sub('\n+[.][.] _END_OF_HELP.*(?s)', '', __doc__)
sys.stdout.write(help_ + '\n')
return 0
_debug = _parameters.debug
if _debug > 0:
_verbose = True
_quiet = False
elif _debug < 0:
_verbose = (_debug == -1)
_quiet = not(_verbose)
_debug = 0
_parameters.debug = _debug
_parameters.verbose = _verbose
_parameters.quiet = _quiet
if _debug:
cmd_line = argv
sys.stderr.write(sformat(
"{0}{3:^{1}} {4:<{2}s}: >{5!s}<\n",
((('dbg_comm' in globals()) and (globals()['dbg_comm'])) or ('# ')),
((('dbg_twid' in globals()) and (globals()['dbg_twid'])) or (9)),
((('dbg_fwid' in globals()) and (globals()['dbg_fwid'])) or (15)),
':DBG:', 'cmd_line', cmd_line))
# at least use `quiet` to suppress the setdefaultencoding warning
setdefaultencoding(quiet=_quiet or _parameters.test)
# |:opt:| handle options
# adhoc: implode/explode/extract
adhoc_export = (_parameters.explode or _parameters.extract)
adhoc_op = (
_parameters.implode or adhoc_export
or _parameters.template or _parameters.eide
)
if adhoc_op:
file_ = __file__
source = None
have_adhoc = 'AdHoc' in globals()
have_rt_adhoc = 'RtAdHoc' in globals()
# shall adhoc be imported
if _parameters.implode or not have_rt_adhoc:
# shall this file be compiled
adhoc_compile = not (have_rt_adhoc)
os_path = os.defpath
for pv in ('PATH', 'path'):
try:
os_path = os.environ[pv]
break
except KeyError:
pass
os_path = os_path.split(os.pathsep)
for path_dir in os_path:
if not path_dir:
continue
if path_dir not in sys.path:
sys.path.append(path_dir)
if not have_adhoc:
try:
import adhoc
AdHoc = adhoc.AdHoc
except ImportError:
adhoc_compile = False
try:
from rt_adhoc import RtAdHoc as Adhoc
except ImportError:
pass
else:
adhoc_compile = False
AdHoc = RtAdHoc
AdHoc.quiet = _quiet
AdHoc.verbose = _verbose
AdHoc.debug = _debug
AdHoc.include_path.append(os.path.dirname(file_))
AdHoc.extra_templates = [
]
AdHoc.template_process_hooks = {
}
if _parameters.eide:
AdHoc.tt_ide = True
AdHoc.tt_comment = _parameters.adhoc_arg or ''
AdHoc.tt_prefix = '. (shell-command "'
AdHoc.tt_suffix = '")'
_parameters.template = True
_parameters.adhoc_arg = 'list'
if adhoc_compile:
ah = AdHoc()
source = ah.compileFile(file_)
else:
file_, source = AdHoc.std_source_param(file_)
# implode
if _parameters.implode:
# @:adhoc_enable:@
# if not _quiet:
# map(sys.stderr.write,
# ["warning: ", os.path.basename(file_),
# " already imploded!\n"])
# @:adhoc_enable:@
AdHoc.write_source('-', source)
# explode
elif _parameters.explode:
AdHoc.export_dir = _parameters.adhoc_arg
AdHoc.export(file_, source)
# extract
elif _parameters.extract:
AdHoc.extract_dir = _parameters.adhoc_arg
AdHoc.extract(file_, source)
# template
elif _parameters.template:
template_name = _parameters.adhoc_arg
if not template_name:
template_name = '-'
if template_name == 'list':
sys.stdout.write(
'\n'.join(AdHoc.template_table(file_, source)) + '\n')
else:
template = AdHoc.get_named_template(
template_name, file_, source)
AdHoc.write_source('-', template)
# restore for subsequent calls to main
if not have_adhoc:
del(AdHoc)
return 0
# run doc tests
if _parameters.test:
import doctest
doctest.testmod(verbose = _verbose)
return 0
# |:opt:| handle options
return run(_parameters, _pass_opts)
if globals().get('_is_main_', (__name__ == '__main__')):
#sys.argv.insert(1, '--debug') # |:debug:|
result = main(sys.argv)
sys.exit(result)
# |:here:|
# (progn (forward-line 1) (snip-insert "py.t.ide" t t "py") (insert "\n"))
#
# :ide-menu: Emacs IDE Main Menu - Buffer @BUFFER@
# . M-x `eIDE-menu' (eIDE-menu "z")
# :ide: CSCOPE ON
# . (cscope-minor-mode)
# :ide: CSCOPE OFF
# . (cscope-minor-mode (quote ( nil )))
# :ide: TAGS: forced update
# . (compile (concat "cd /home/ws/project/ws-rfid && make -k FORCED=1 tags"))
# :ide: TAGS: update
# . (compile (concat "cd /home/ws/project/ws-rfid && make -k tags"))
# :ide: +-#+
# . Utilities ()
# :ide: TOC: Generate TOC with py-toc.py
# . (progn (save-buffer) (compile (concat "py-toc.py ./" (file-name-nondirectory (buffer-file-name)) " ")))
# :ide: CMD: Fold region with line continuation
# . (shell-command-on-region (region-beginning) (region-end) "fold --spaces -width 79 | sed 's, $,,;1!s,^, ,;$!s,$,\\\\,'" nil nil nil t)
# :ide: CMD: Fold region and replace with line continuation
# . (shell-command-on-region (region-beginning) (region-end) "fold --spaces --width 79 | sed 's, $,,;1!s,^, ,;$!s,$,\\\\,'" t nil nil t)
# :ide: +-#+
# . Fold ()
# :ide: CMD: Remove 8 spaces and add `>>> ' to region
# . (shell-command-on-region (region-beginning) (region-end) "sed 's,^ ,,;/^[ ]*##/d;/^[ ]*#/{;s,^ *# *,,p;d;};/^[ ]*$/!s,^,>>> ,'" nil nil nil t)
# :ide: CMD: Remove 4 spaces and add `>>> ' to region
# . (shell-command-on-region (region-beginning) (region-end) "sed 's,^ ,,;/^[ ]*##/d;/^[ ]*#/{;s,^ *# *,,p;d;};/^[ ]*$/!s,^,>>> ,'" nil nil nil t)
# :ide: +-#+
# . Doctest ()
# :ide: LINT: Check 80 column width ignoring IDE Menus
# . (let ((args " | /srv/ftp/pub/check-80-col.sh -")) (compile (concat "sed 's,^\\(\\|. \\|.. \\|... \\)\\(:ide\\|[.] \\).*,,' " (buffer-file-name) " " args " | sed 's,^-," (buffer-file-name) ",'")))
# :ide: LINT: Check 80 column width
# . (let ((args "")) (compile (concat "/srv/ftp/pub/check-80-col.sh " (buffer-file-name) " " args)))
# :ide: +-#+
# . Lint Tools ()
# :ide: DELIM: @: SYM :@ @:fillme:@ adhoc tag
# . (symbol-tag-normalize-delimiter (cons (cons nil "@:") (cons ":@" nil)) t)
# :ide: +-#+
# . Delimiters ()
# :ide: COMPILE: Run with --ap-help
# . (progn (save-buffer) (compile (concat "python ./" (file-name-nondirectory (buffer-file-name)) " --ap-help")))
# :ide: COMPILE: Run with --help
# . (progn (save-buffer) (compile (concat "python ./" (file-name-nondirectory (buffer-file-name)) " --help")))
# :ide: COMPILE: Run with --test
# . (progn (save-buffer) (compile (concat "python ./" (file-name-nondirectory (buffer-file-name)) " --test")))
# :ide: COMPILE: Run with --test --verbose
# . (progn (save-buffer) (compile (concat "python ./" (file-name-nondirectory (buffer-file-name)) " --test --verbose")))
# :ide: COMPILE: Run with --debug
# . (progn (save-buffer) (compile (concat "python ./" (file-name-nondirectory (buffer-file-name)) " --debug")))
# :ide: +-#+
# . Compile with standard arguments ()
# :ide: OCCUR-OUTLINE: Python Source Code
# . (x-symbol-tag-occur-outline "sec" '("|||:" ":|||") (cons (cons "^\\([ \t\r]*\\(def\\|class\\)[ ]+\\|[A-Za-z_]?\\)" nil) (cons nil "\\([ \t\r]*(\\|[ \t]*=\\)")))
# :ide: MENU-OUTLINE: Python Source Code
# . (x-eIDE-menu-outline "sec" '("|||:" ":|||") (cons (cons "^\\([ \t\r]*\\(def\\|class\\)[ ]+\\|[A-Za-z_]?\\)" nil) (cons nil "\\([ \t\r]*(\\|[ \t]*=\\)")))
# :ide: +-#+
# . Outline ()
# :ide: INFO: SQLAlchemy - SQL Expression Language - Reference
# . (let ((ref-buffer "*sqa-expr-ref*")) (if (not (get-buffer ref-buffer)) (shell-command (concat "w3m -dump -cols " (number-to-string (1- (window-width))) " 'http://www.sqlalchemy.org/docs/05/reference/sqlalchemy/expressions.html'") ref-buffer) (display-buffer ref-buffer t)))
# :ide: INFO: SQLAlchemy - SQL Expression Language - Tutorial
# . (let ((ref-buffer "*sqa-expr-tutor*")) (if (not (get-buffer ref-buffer)) (shell-command (concat "w3m -dump -cols " (number-to-string (1- (window-width))) " 'http://www.sqlalchemy.org/docs/05/sqlexpression.html'") ref-buffer) (display-buffer ref-buffer t)))
# :ide: INFO: SQLAlchemy - Query
# . (let ((ref-buffer "*sqa-query*")) (if (not (get-buffer ref-buffer)) (shell-command (concat "w3m -dump -cols " (number-to-string (1- (window-width))) " 'http://www.sqlalchemy.org/docs/orm/query.html'") ref-buffer) (display-buffer ref-buffer t)))
# :ide: +-#+
# . SQLAlchemy Reference ()
# :ide: INFO: Python - argparse
# . (let ((ref-buffer "*python-argparse*")) (if (not (get-buffer ref-buffer)) (shell-command (concat "w3m -dump -cols " (number-to-string (1- (window-width))) " 'http://docs.python.org/library/argparse.html'") ref-buffer) (display-buffer ref-buffer t)))
# :ide: INFO: Python Documentation
# . (let ((ref-buffer "*w3m*")) (if (get-buffer ref-buffer) (display-buffer ref-buffer t)) (other-window 1) (w3m-goto-url "http://docs.python.org/index.html" nil nil))
# :ide: INFO: Python Reference
# . (let* ((ref-buffer "*python-ref*") (local "/home/ws/project/ws-util/python/reference/PQR2.7.html") (url (or (and (file-exists-p local) local) "'http://rgruet.free.fr/PQR27/PQR2.7.html'"))) (unless (get-buffer ref-buffer) (get-buffer-create ref-buffer) (with-current-buffer ref-buffer (shell-command (concat "snc txt.py.reference 2>/dev/null") ref-buffer) (goto-char (point-min)) (if (eobp) (shell-command (concat "w3m -dump -cols " (number-to-string (1- (window-width))) " " url) ref-buffer)))) (display-buffer ref-buffer t))
# :ide: +-#+
# . Python Reference ()
# :ide: COMPILE: Run with --eide
# . (progn (save-buffer) (shell-command (concat "python ./" (file-name-nondirectory (buffer-file-name)) " --eide") (concat "*templates: " (file-name-nondirectory (buffer-file-name)) "*")))
# :ide: COMPILE: Run with python3 --test
# . (progn (save-buffer) (compile (concat "python3 ./" (file-name-nondirectory (buffer-file-name)) " --test")))
# :ide: COMPILE: Run with python3 w/o args
# . (progn (save-buffer) (compile (concat "python3 ./" (file-name-nondirectory (buffer-file-name)) " ")))
# :ide: COMPILE: Run with /srv/sw-amt.ws/630-construct-non-identities-000.mtx-3SAT.fca >zz.mtx
# . (progn (save-buffer) (compile (concat "( python ./" (file-name-nondirectory (buffer-file-name)) " --verbose /srv/sw-amt.ws/630-construct-non-identities-000.mtx-3SAT.fca ) >zz.mtx")))
# :ide: COMPILE: Run with --no-conflicts /srv/sw-amt.ws/630-construct-non-identities-000.mtx-3SAT.fca >zz.mtx
# . (progn (save-buffer) (compile (concat "( python ./" (file-name-nondirectory (buffer-file-name)) " --verbose --no-conflicts /srv/sw-amt.ws/630-construct-non-identities-000.mtx-3SAT.fca ) >zz.mtx")))
# :ide: COMPILE: Run with --no-update /srv/sw-amt.ws/630-construct-non-identities-000.mtx-3SAT.fca >zz.mtx
# . (progn (save-buffer) (compile (concat "( python ./" (file-name-nondirectory (buffer-file-name)) " --verbose --no-update /srv/sw-amt.ws/630-construct-non-identities-000.mtx-3SAT.fca ) >zz.mtx")))
# :ide: COMPILE: Run with /srv/sw-amt.ws/630-construct-non-identities-000.mtx-3SAT.fca >zz.mtx
# . (progn (save-buffer) (compile (concat "( python ./" (file-name-nondirectory (buffer-file-name)) " --verbose /srv/sw-amt.ws/630-construct-non-identities-000.mtx-3SAT.fca ) >zz.mtx")))
# :ide: COMPILE: Run with --sort --beautify /srv/sw-amt.ws/630-construct-non-identities-000.mtx-3SAT.fca
# . (progn (save-buffer) (compile (concat "python ./" (file-name-nondirectory (buffer-file-name)) " --sort --beautify /srv/sw-amt.ws/630-construct-non-identities-000.mtx-3SAT.fca")))
# :ide: COMPILE: Run with examples/EXAMPLE-3-AND >zz.mtx
# . (progn (save-buffer) (compile (concat "( python ./" (file-name-nondirectory (buffer-file-name)) " --verbose examples/EXAMPLE-3-AND ) >zz.mtx")))
# :ide: COMPILE: Run with examples/EXAMPLE-3-AND --no-conflicts --image >zz.png
# . (progn (save-buffer) (compile (concat "( python ./" (file-name-nondirectory (buffer-file-name)) " --image --verbose --no-conflicts examples/EXAMPLE-3-AND ) >zz.png")))
# :ide: COMPILE: Run with examples/EXAMPLE-3-AND --no-conflicts
# . (progn (save-buffer) (compile (concat "( python ./" (file-name-nondirectory (buffer-file-name)) " --verbose --no-conflicts examples/EXAMPLE-3-AND )")))
# :ide: COMPILE: Run with examples/EXAMPLE-3-AND --full-conflicts
# . (progn (save-buffer) (compile (concat "( python ./" (file-name-nondirectory (buffer-file-name)) " --verbose --full-conflicts examples/EXAMPLE-3-AND )")))
# :ide: COMPILE: Run with --sort --beautify examples/EXAMPLE-3-AND
# . (progn (save-buffer) (compile (concat "python ./" (file-name-nondirectory (buffer-file-name)) " --sort --beautify examples/EXAMPLE-3-AND")))
# :ide: COMPILE: Run with --sort --beautify examples/ex-xor5-3sat/ex-xor5-3sat-000.fca
# . (progn (save-buffer) (compile (concat "python ./" (file-name-nondirectory (buffer-file-name)) " --sort --beautify examples/ex-xor5-3sat/ex-xor5-3sat-000.fca")))
# :ide: COMPILE: Run with --sort --xor --beautify examples/ex-xor5-3sat/ex-xor5-3sat-000.fca
# . (progn (save-buffer) (compile (concat "python ./" (file-name-nondirectory (buffer-file-name)) " --sort --xor --beautify examples/ex-xor5-3sat/ex-xor5-3sat-000.fca")))
# :ide: COMPILE: Run with --matrix --delay-zeroes --no-sort --drop-2-states --variables --conflicts /srv/sw-amt.ws/satoku/check/unconnected-2states/unconnected-2states.fca
# . (progn (save-buffer) (compile (concat "python ./" (file-name-nondirectory (buffer-file-name)) " --matrix --delay-zeroes --no-sort --drop-2-states --variables --conflicts /srv/sw-amt.ws/satoku/check/unconnected-2states/unconnected-2states.fca")))
# :ide: COMPILE: Run with --matrix --no-sort --drop-2-states --variables --conflicts /srv/sw-amt.ws/satoku/check/unconnected-2states/unconnected-2states.fca
# . (progn (save-buffer) (compile (concat "python ./" (file-name-nondirectory (buffer-file-name)) " --matrix --no-sort --drop-2-states --variables --conflicts /srv/sw-amt.ws/satoku/check/unconnected-2states/unconnected-2states.fca")))
# :ide: COMPILE: Run with --debug --from-matrix --reduce-cells --check-minor-ccrs ../examples/EXAMPLE-3-AND.v.mtx
# . (progn (save-buffer) (compile (concat "python ./" (file-name-nondirectory (buffer-file-name)) " --debug=1 --from-matrix --reduce-cells --check-minor-ccrs ../examples/EXAMPLE-3-AND.v.mtx")))
# :ide: COMPILE: Run with --debug --from-matrix --reduce-cells ../examples/EXAMPLE-3-AND.v.mtx
# . (progn (save-buffer) (compile (concat "python ./" (file-name-nondirectory (buffer-file-name)) " --debug=1 --from-matrix --reduce-cells ../examples/EXAMPLE-3-AND.v.mtx")))
# :ide: COMPILE: Run with --debug --from-matrix ../examples/EXAMPLE-3-AND.v.mtx
# . (progn (save-buffer) (compile (concat "python ./" (file-name-nondirectory (buffer-file-name)) " --debug=1 --from-matrix ../examples/EXAMPLE-3-AND.v.mtx")))
# :ide: COMPILE: Run with --debug --from-matrix --variables --drop-2-states --reduce-cells < ...-sm.x.v-000 (mtx_position) > ...-sm-s.x.v-000 (red_position) ### level-very-deep/zz-www.sudokuwiki.org-0164-base.sdk
# . (let* ((sudoku_dir "/home/ws/develop/Perl/sudoku") (subdir "level-very-deep") (base "zz-www.sudokuwiki.org-0164-base") (work_base (concat sudoku_dir "/" subdir "/" base "/" base))) (save-buffer) (compile (concat "bunzip2 -c " work_base "-000-sm.x.v-000.mtx.bz2 | python ./" (file-name-nondirectory (buffer-file-name)) " --debug=1 --from-matrix --variables --drop-2-states --reduce-cells 2>&1 >" base "-000-sm.s.x.v-001.mtx | tee " base "-000-sm.s.x.v-001-ae.log")))
# :ide: COMPILE: Run with --debug --from-matrix --variables --drop-2-states --reduce-cells --allow-equal < ...-sm.x.v-000 (mtx_position) > ...-sm-s.x.v-000-ae (red_position) ### level-very-deep/zz-www.sudokuwiki.org-0164-base.sdk
# . (let* ((sudoku_dir "/home/ws/develop/Perl/sudoku") (subdir "level-very-deep") (base "zz-www.sudokuwiki.org-0164-base") (work_base (concat sudoku_dir "/" subdir "/" base "/" base))) (save-buffer) (compile (concat "bunzip2 -c " work_base "-000-sm.x.v-000.mtx.bz2 | python ./" (file-name-nondirectory (buffer-file-name)) " --debug=1 --from-matrix --variables --drop-2-states --reduce-cells --allow-equal 2>&1 >" base "-000-sm.s.x.v-001-ae.mtx | tee " base "-000-sm.s.x.v-001-ae.log")))
# :ide: COMPILE: Run with --debug=0 --from-matrix --variables --drop-2-states --reduce-cells --allow-equal < ...-sm.x.v-000 (mtx_position) > ...-sm-s.x.v-000-ae (red_position) ### level-very-deep/zz-www.sudokuwiki.org-0164-base.sdk
# . (let* ((sudoku_dir "/home/ws/develop/Perl/sudoku") (subdir "level-very-deep") (base "zz-www.sudokuwiki.org-0164-base") (work_base (concat sudoku_dir "/" subdir "/" base "/" base))) (save-buffer) (compile (concat "bunzip2 -c " work_base "-000-sm.x.v-000.mtx.bz2 | python ./" (file-name-nondirectory (buffer-file-name)) " --debug=0 --from-matrix --variables --drop-2-states --reduce-cells --allow-equal 2>&1 >" base "-000-sm.s.x.v-001-ae.mtx | tee " base "-000-sm.s.x.v-001-ae.log")))
# :ide: COMPILE: Run with --debug --from-matrix --variables --drop-2-states --reduce-cells --allow-equal < ...-sm.x.v-000 (mtx_position) > ...-sm-s.x.v-000-ae (red_position) ### level-deep/xx-Cheese-check.sdk
# . (let* ((sudoku_dir "/home/ws/develop/Perl/sudoku") (subdir "level-deep") (base "xx-Cheese-check") (work_base (concat sudoku_dir "/" subdir "/" base "/" base))) (save-buffer) (compile (concat "bunzip2 -c " work_base "-000-sm.x.v-000.mtx.bz2 | python ./" (file-name-nondirectory (buffer-file-name)) " --debug=1 --from-matrix --variables --drop-2-states --reduce-cells --allow-equal 2>&1 >" base "-000-sm.s.x.v-001-ae.mtx | tee " base "-000-sm.s.x.v-001-ae.log")))
# :ide: COMPILE: Run with --test
# . (progn (save-buffer) (compile (concat "python ./" (file-name-nondirectory (buffer-file-name)) " --test")))
# :ide: COMPILE: Run with --help
# . (progn (save-buffer) (compile (concat "python ./" (file-name-nondirectory (buffer-file-name)) " --help")))
# :ide: +-#+
# . Compile ()
#
# Local Variables:
# mode: python
# comment-start: "#"
# comment-start-skip: "#+"
# comment-column: 0
# truncate-lines: t
# End: