import sys
sys.dont_write_bytecode=True
from about import *

###############################
class Row(Charmed):
  "Information about decisions, objectives."
  id = -1
  def __init__(i,t,cells):
    i.id = Row.id = Row.id + 1
    i.cells, i.t = cells,t
    i.theScore=None
  def score(i):
    if i.theScore == None:
      i.theScore = fromhell(i.cells,i.t)
    return i.theScore
  def approx(i):
    out = i.cells[:]
    for h in i.t.nums:
      out[h.pos] = approx(h.bins(),out[h.pos])
    return out
 
def fromhell(cells,t): 
  "Sum of the distance from hell on all objectives."
  s = 0.0
  less, more = t.less, t.more
  for h in less:
    x= h.norm(cells[h.pos])
    s += (1-x)
  for h in more: 
    x= h.norm(cells[h.pos])
    s += x
  return  s/ (len(less)+len(more) + 1/The.math.inf)

class Table(Charmed):
  "Storage for what we know about Rows."
  id = -1
  def __init__(i,spec=[],keeping=True):
    i.id = Table.id = Table.id+1
    i.more, i.less, i.klass, i.nums = [] ,[], [], []
    i.syms, i.rows, i.columns       = [], [], []
    i.dep , i.indep, i._at          = [], [], {}
    i.keeping = keeping
    if spec: 
      i.header(spec)
  def at(i,x): return i._at[x]
  def centroid(i): 
    return [h.centroid() for h in i.columns]
  def clone(i,lstOfCells=[],keeping=True): 
    t = Table(spec=i.spec(), keeping=keeping)
    for cells in lstOfCells: t.seen(cells) 
    return t
  def discretize(i,rnn=True):    
    def sym(x): 
      return x.translate(None,The.read.num)
    t = Table(spec = [sym(h.name) for h in i.columns])
    for row in i.rows:
        t.seen(row.approx())
    return t 
  def spec(i)   : return [x.name for x in i.columns]
  def nump(i,x) : return x in [The.read.less,
                         The.read.more,The.read.num]
  def add(i,txt,head):
    r = The.read
    if   txt[0] == r.more  : also = i.more 
    elif txt[0] == r.less  : also = i.less
    elif txt[0] == r.klass : also = i.klass
    elif txt[0] == r.num   : also = i.nums
    else:                    also = i.syms
    i.columns += [head]
    head.pos   = i._at[txt] = len(i.columns) -1
    txt1 = ''.join([y.strip(The.read.chars) 
                    for y in txt])
    i._at[txt1] = head.pos
    also    += [head]
    i.indep  = i.nums + i.syms
    i.dep    = i.more + i.less + i.klass
  def has(i,*things):
    for thing in things: i.add(thing.name,thing)
  def header(i,spec): # e.g. Num(name=fred,min=
    for m,txt in enumerate(spec):
      head = Num if i.nump(txt[0]) else Sym
      i.add(txt, head(name=txt))
  def __repr__(i):
    return 'Table(%g,%g)' % (i.id,len(i.rows)) 
  def seen(i,cells):
    row = [None] * len(i.columns)
    for head in i.columns:
      cell = cells[head.pos]
      if cell != The.read.ignore:
        cell = head.seen(cell)
      row[head.pos] = cell
    if i.keeping: 
      i.rows += [Row(cells=row,t=i)]
