[ prog / sol / mona ]

prog


[challenge] Try to rewrite SICP [urgent]

12 2022-08-19 03:39

Upgrade of >>11 to adaptive sliding window predictor, still alpha. The adapt parameter controls how many window sizes are considered, starting from the full window.

import collections as co
import sys


class Oracle:
   def __init__ (self, source):
      with open (source, "r") as f:
         text = f.read ()

      self.text = text

   def length (self):
      return len (self.text)

   def guess (self, index, char):
      c = self.text [index]
      return True if c == char else c


class Acolyte:
   def __init__ (self, oracle):
      self.oracle = oracle
      self.index  = 0
      self.score  = 0

   def length (self):
      return self.oracle.length ()

   def guess (self, char):
      index    = self.index
      prophecy = self.oracle.guess (index, char)

      if prophecy is True:
         self.score += 1

      self.index = index + 1
      return prophecy

   def status (self):
      length = self.oracle.length ()
      index  = self.index
      score  = self.score

      return "{}={} {}={} {}={:.6f} {}={} {}={:.6f}".format (
         "length", length,
         "index",  index,
         "cover",  index / length,
         "score",  score,
         "ratio",  score / index if index else 0)


class Temple:
   def __init__ (self, argv):
      pass

   def preach (self, acolyte):
      pass


class TempleOfSpace (Temple):
   def preach (self, acolyte):
      guess = acolyte.guess

      for k in range (acolyte.length ()):
         guess (' ')


class TempleOfSlidingWindow (Temple):
   def __init__ (self, argv):
      self.window = int (argv [0])

   def preach (self, acolyte):
      window  = self.window
      length  = acolyte.length ()
      if length < window: return
      guess   = acolyte.guess
      predict = {}

      start = ' '
      key   = ''.join (
         map (lambda charguess: charguess [0] if charguess [1] is True else charguess [1],
         map (lambda k: (start, guess (start)),
         range (window))))

      for k in range (window, length):
         counts = predict.get (key)

         if counts is None:
            gu  = guess (start)
            ch  = start if gu is True else gu
            predict [key] = co.Counter ([ch])
            key = key [1:] + ch
         else:
            pred = counts.most_common (1) [0] [0]
            gu   = guess (pred)
            ch   = pred if gu is True else gu
            counts [ch] += 1
            key = key [1:] + ch

      print ("{}={}".format (
         "predict", len (predict)))


class TempleOfAdaptiveSW (Temple):
   def __init__ (self, argv):
      self.window = int (argv [0])
      self.adapt  = int (argv [1])

   def preach (self, acolyte):
      window  = self.window
      adapt   = self.adapt
      length  = acolyte.length ()
      if length < window: return
      guess   = acolyte.guess
      ranada  = range (adapt)
      predict = [{} for k in ranada]

      start  = ' '
      key    = ''.join (
         map (lambda charguess: charguess [0] if charguess [1] is True else charguess [1],
         map (lambda k: (start, guess (start)),
         range (window))))
      keys   = [key [k:] for k in ranada]
      counts = [None] * adapt

      for j in range (window, length):
         pred = start
         most = 0

         for k in ranada:
            countsk    = predict [k].get (keys [k])
            counts [k] = countsk
            if countsk is not None:
               chark, mostk = countsk.most_common (1) [0]
               if mostk > most:
                  most = mostk
                  pred = chark

         gu   = guess (pred)
         char = pred if gu is True else gu

         for k in ranada:
            keysk   = keys   [k]
            countsk = counts [k]

            if countsk is None:
               predict [k] [keysk] = co.Counter ([char])
            else:
               countsk [char] += 1

            keys [k] = keysk [1:] + char

      print ("{}={}={}".format (
         "predict",
         sum (len (p) for p in predict),
         [len (p) for p in predict]))


def work_temple (src, templar, rest):
   temple  = globals () ["TempleOf" + templar] (rest)
   oracle  = Oracle (src)
   acolyte = Acolyte (oracle)
   temple.preach (acolyte)
   print (acolyte.status ())

def main_temple (argv):
   src    = argv [0]
   temple = argv [1]
   rest   = argv [2:]
   work_temple (src, temple, rest)


def main ():
   globals () ["main_" + sys.argv [1]] (sys.argv [2:])

if __name__ == "__main__": main ()
14


VIP:

do not edit these