Source code for satoku

#!/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: