[ prog / sol / mona ]

prog


e and the Stern-Brocot tree

28 2021-02-24 00:31

[2/2]

class ListGroup (Group):
   @ classmethod
   def kind (cls):
      return "list"

   def __init__ (self, groups):
      self.groups = groups

   def eval (self, ctx, stackpos):
      MC    = ctx ["matrixclass"]
      stack = ctx ["stack"      ]
      gs    = self.groups
      count = len (gs)

      if count < 1:
         MC.copyinto (MC.I, stack [stackpos])
         return

      if count == 1:
         gs [0].eval (ctx, stackpos)
         return

      div, mod = divmod (count - 1, 2)

      if mod:
         now   = stackpos + 1
         other = stackpos
      else:
         now   = stackpos
         other = stackpos + 1

      Stack.ensure (stack, stackpos + 3, MC)
      factor  = stackpos + 2
      mfactor = stack [factor]
      mnow    = stack [now   ]
      mother  = stack [other ]
      gs [0].eval (ctx, now)
      mul     = MC.mul
      gspos   = 1

      for k in range (div):
         gs [gspos    ].eval (ctx, factor)
         mul (mnow,   mfactor, mother)
         gs [gspos + 1].eval (ctx, factor)
         mul (mother, mfactor, mnow)
         gspos += 2

      if mod:
         gs [gspos].eval (ctx, factor)
         mul (mnow, mfactor, mother)


class ExpoGroup (Group):
   @ classmethod
   def kind (cls):
      return "expo"

   def __init__ (self, base, expo, *, alwaysevalbase = False):
      self.base           = base
      self.expo           = expo
      self.alwaysevalbase = alwaysevalbase

   def eval (self, ctx, stackpos):
      MC     = ctx ["matrixclass"]
      stack  = ctx ["stack"      ]
      base   = self.base
      expo   = self.expo
      always = self.alwaysevalbase

      if (expo < 1) and not always:
         MC.copyinto (MC.I, stack [stackpos])
         return

      Stack.ensure (stack, stackpos + 2, MC)
      base.eval (ctx, stackpos)
      Expo.bits (stack [stackpos], expo, stack, stackpos + 1, MC)
      MC.copyinto (stack [stackpos + 1], stack [stackpos])


class Spec:
   @ classmethod
   def kind (cls):
      pass

   @ classmethod
   def targetfloat (cls):
      pass


class StarSpec (Spec):
   @ classmethod
   def kind (cls):
      return "star"

   def __init__ (self, group):
      self.group = group


class Compiler:
   @ staticmethod
   def fixedlimit (spec, limit):
      what = spec.kind ()
      ret  = getattr (Compiler, "fixedlimit_" + what) (spec, limit)
      return ret

   @ staticmethod
   def fixedlimit_star (spec, limit):
      if limit < 1:
         return {
            "group": EmptyGroup (),
            "count": 0,
         }

      g    = spec.group
      what = g.kind ()

      if what != "fixed":
         raise ValueError (what)

      fs    = g.fixedstr
      fslen = len (fs)

      if fslen < 1:
         raise ValueError (fslen)

      div, mod = divmod (limit, fslen)

      if mod:
         h = ListGroup ([
            ExpoGroup (g, div),
            FixedGroup (fs [:mod])])
      else:
         h = ExpoGroup (g, div)

      return {
         "group": h,
         "count": limit,
      }


class Specs:
   class Phi (StarSpec):
      @ classmethod
      def targetfloat (cls):
         return (1 + math.sqrt (5)) / 2

      def __init__ (self):
         StarSpec.__init__ (self, FixedGroup ("RL"))

   class Sqrt2 (StarSpec):
      @ classmethod
      def targetfloat (cls):
         return math.sqrt (2)

      def __init__ (self):
         StarSpec.__init__ (self, FixedGroup ("RLLR"))

   class Sqrt3 (StarSpec):
      @ classmethod
      def targetfloat (cls):
         return math.sqrt (3)

      def __init__ (self):
         StarSpec.__init__ (self, FixedGroup ("RLR"))

   class Sqrt5 (StarSpec):
      @ classmethod
      def targetfloat (cls):
         return math.sqrt (5)

      def __init__ (self):
         StarSpec.__init__ (self, FixedGroup ("RRLLLLRR"))

   class Sqrt7 (StarSpec):
      @ classmethod
      def targetfloat (cls):
         return math.sqrt (7)

      def __init__ (self):
         StarSpec.__init__ (self, FixedGroup ("RRLRLRR"))


def work_speclimit (spec, limit):
   log    = print
   M      = Matrix
   C      = Compiler
   slots  = 2
   mstack = Stack.alloc (slots, M)
   target = spec.targetfloat ()
   ctx    = {
      "matrixclass": M,
      "stack":       mstack,
   }

   log ("target {:.15f}".format (target))

   ret   = C.fixedlimit (spec, limit)
   group = ret ["group"]
   group.eval (ctx, 1)
   M.mul (M.S, mstack [1], mstack [0])
   a, b  = M.pair (mstack [0])

   log ("result {:.15f}".format (a / b))
   log ("{:d}".format (a))
   log ("{:d}".format (b))
   log ("stack {:d}".format (len (mstack)))
54


VIP:

do not edit these