"""
Contains a set of functions to be used filterFuction and function vies.  

Each functor should be instantiated with the parameters desired, and then
passed to the view that requires a function.
"""

import MLab
import Numeric

class KineticChangeFilterFunction: 
  """For use with the views.RowFilterFucnction class remove all rows which do
     not show a change in expression of atleast threshold maintained across N
     timepoints"""

  def __init__ (self,threshold, N):
    self.threshold = threshold
    self.n = N
  def __call__(self, ds, row):
    data = ds.getRowData(row)
    # get all consequetive 3 timepoint windows
    windows = apply(zip, tuple([data[i:] for i in range(self.n)]))
    # now compare the window with the largest minimum and the window with the smallest max.
    dif = MLab.max(MLab.min(windows, 1) )- MLab.min(MLab.max(windows,1))
    return(dif>=self.threshold)

class KineticAbsoluteFilterFunction:
  """For use with the views.RowFilterFunction class. 
     Filters out genes vectors which contain no values
     over threshold in atleast N contiguous measurements"""
  def __init__ (self,threshold, N):
    self.threshold = threshold
    self.n = N
  def __call__(self, ds, row):
    data = ds.getRowData(row)
    a =  Numeric.greater(data, self.threshold)
    # this returns a list of which windows of size N in the vector conform to the filter.
    windowTruths = map(MLab.product, apply(zip, tuple([a[i:] for i in range(self.n)])))
    return(listOps.someTrue(windowTruths))

class noiseAddedViewFuction:
  def __init__(self, dataset, sigma):
    import RandomArray
    self.sigma = sigma
    self.noise = RandomArray.normal(0, self.sigma, (dataset.getNumRows(), dataset.getNumCols()))
  def __call__ (self, ds, row):
    return(ds.getRowData(row) + self.noise[row])

class medianNormalizerFunc:
  """
  for use with views.RowFunctionView
  normalize each row by its median unless it is median value is less than threshold
  """
  def __init__(self, threshold):
    self.threshold=threshold
  def __call__(self, ds, row):
    rowData = ds.getRowData(row)
    med = MLab.median(rowData)
    if med > self.threshold:
      return (rowData/med)
    else:
      return rowData

class movingMedianSmoother: 
  """ for use with views.RowFunctionView 'Smooths'
       each datavector by replacing x_i with the median of the window of size w around
       it.   """
  def __init__(self, w):
    self.window=w
  def __call__(self, ds, row):
    w = self.window
    d = ds.getRowData(row)
    return(MLab.median(Numeric.array([d[i:len(d)-(w-i)] for i in range(w)])))


