import sys
sys.dont_write_bytecode=True # no .pyc files
from the import *
from about import *
from lib import *

class Nums(AutoDict):
  def __init__(i):
    AutoDict.__init__(i,Num)

stop=StopIteration 

class Control:
  def __init__(i,
               iter=range(0,100),
               epsilon= 0.005,
               also=None,
               era= 100,
               cohen=The.math.cohen,
               haltOn=None,
               cmp=lambda old, new: new - old):
    i.iter=iter
    i.era = era
    i.epsilon = epsilon
    i.all = Nums()
    i.now = Nums()
    i.also = also
    i.cohen = cohen
    i.haltOn = haltOn
    i.cmp = cmp
  def thisEra(i,tick):
    return int(tick/i.era)*i.era
  def small(i,where) : 
    if not where in i.all: 1/0
    return i.all[where].s*i.cohen
  def enough(i,where,when) :
    if (where,when) in i.now: 
      val  = i.now[(where,when)].mu
      return val > (1 - i.epsilon)
    else:
      return False
  def done(i,when):
    where = i.haltOn
    if where:
      if i.enough(where,when) or \
            not i.improving(where,when): 
        return True
    return False
  def improving(i,where,when):
    before = when - i.era
    if (where,before) in i.now and \
       (where,when) in i.now:
      new = i.now[(where,when)]
      old = i.now[(where,before)]
      return i.cmp(old.mu,new.mu) > i.small(where)
    return False
  def seen(i,tick,**d):
    when = i.thisEra(tick)
    for where,what in d.items():
      i.seen1(when,what,where)
  def seen1(i,when,what,where):
    if i.also: 
      i.also.seen1(when,what,where)
    i.all[where].seen(what)
    i.now[(where, when)].seen(what)
  def loop(i):
    before = 0
    for tick in i.iter:
      now = i.thisEra(tick)
      if before and now != before:
        if i.done(before):
          break
      before = now
      yield tick
      
 
def controlled(control,lo,hi,
           key  =lambda z:'%10s' %  z,
           value=lambda z: '%2d' %  z
           ):
    d = control.now
    wheres= {}
    whens = {}
    for where,when in d.keys():
      wheres[where] = 1
      whens[ when ] = 1
    wheres = sorted(wheres.keys())
    whens  = sorted(whens.keys())
    for where in wheres:
      print '\n------|',str(where),\
            '|----------------------------------\n'
      for when in whens:
        if (where,when) in d:
          all = d[(where,when)].cached()
          s   = "?"
          if len(all) > 5:
            s=   xtile(all,show = value,
                     lo=lo,hi=hi)
          print '%10s' % key(when),\
              '[%5s]' % len(all), s
        
"""
### xtile: Pretty Print  Distributions

The function _xtile_ takes a list of (possibly) unsorted numbers and
presents them as a horizontal xtile chart (in ascii format). The default
is a contracted _quintile_ that shows the 10,30,50,70,90 breaks in the
data (but this can be changed- see the optional flags of the function).

"""
def xtile(lst,lo=0,hi=100,width=50,
             chops=[0.1 ,0.3,0.5,0.7,0.9],
             marks=["-" ," "," ","-"," "],
             bar="|",star="*",show= lambda s:" %3.0f" % s):
  def pos(p)   : return ordered[int(len(lst)*p)]
  def place(x) : 
    tmp= int(width*float((x - lo))/(hi - lo))
    if tmp == width: tmp += -1
    return tmp
  def pretty(lst) : 
    return ', '.join([show(x) for x in lst])
  ordered = sorted(lst)
  lo      = min(lo,ordered[0])
  hi      = max(hi,ordered[-1])
  what    = [pos(p)   for p in chops]
  where   = [place(n) for n in  what]
  out     = [" "] * width
  for one,two in pairs(where):
    for i in range(one,two): 
      out[i] = marks[0]
    marks = marks[1:]
  out[int(width/2)]    = bar
  loc = place(pos(0.5)) 
  #print loc, len(out)
  out[loc] = star 
  return ''.join(out) +  "," +  pretty(what)

def _tileX() :
  import random
  random.seed(1)
  nums = [random.random()**2 for _ in range(100)]
  print xtile(nums,lo=0,hi=1.0,width=25,show= lambda s:" %3.2f" % s)


#c = Control(haltOn='a',era=200,hi=1000,val='%5.2f')
#for x in c:
# c.seen(x,f(x**0.25),'a')
def _control():
  def f(t): return 1.0/(1 + e**(-1*t))
  c =  Control(range(0,100))
  for x in c.loop():
    c.seens(x/20,seen=f(x**0.1))
    print x
  controlled(c,0,1,
             value=lambda s: '%4.2f' % s)


