########################################
# The contents of this file are subject to the MLX PUBLIC LICENSE version
# 1.0 (the "License"); you may not use this file except in
# compliance with the License.
# 
# Software distributed under the License is distributed on an "AS IS"
# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.  See
# the License for the specific language governing rights and limitations
# under the License.
# 
# The Original Source Code is "compClust", released 2003 September 03.
# 
# The Original Source Code was developed by the California Institute of
# Technology (Caltech).  Portions created by Caltech are Copyright (C)
# 2002-2003 California Institute of Technology. All Rights Reserved.
########################################
#
#        Author: Diane Trout
# Last Modified: $Date: 2004/04/02 00:39:55 $
#

"""Collection of functions to help process NaN's within python.
"""
import sre
# since win32 doesn't support float("NaN") we need to define
# the constants here.
inf = 1e300*1e300
nan = inf-inf
nan_pattern = sre.compile("\s*nan\s*", sre.IGNORECASE)

def nanfloat(v):
  """Convert a string to float, properly handling NaNs"""
  if nan_pattern.match(v):
    return nan
  else:
    return float(v)


if nan == 0:
  # on broken systems currently appears to be linux
  def isNaN(v):
    """Determine if a value is a nan """
    return v == 1 and v == 0

  def isnotNaN(v):
    """Determine if a value is not a nan"""
    return not (v == 1 and v == 0)
else:
  # reasonable systems
  def isNaN(v):
    """Determine if a value is a nan """
    return not (v == v)

  def isnotNaN(v):
    """Determine if a value is not a nan"""
    return (v == v)


def isNaNinSequence(t):
  """boolean = isNaNinSequence( sequence_type )

  Given a list of numeric values determine if there is a NaN
  in the sequence.
  """
  return reduce(lambda x,y: x+y, map(isNaN, t))

def isnotNaNinSequence(t):
  """boolean = isnotNaNNaNinSequence( sequence_type )

  Given a list of numeric values determine if there are no NaNs
  in the sequence.
  """
  return not reduce(lambda x,y: x+y, map(isNaN, t))

def removeNaNsFromSequence(list):
  """list = removeNaNsFromSequence(list)

  Given a sequence, remove any NaNs present.
  """
  return filter(isnotNaN, list)
    
def removeSequencesWithNaNs(list):
  """list = removeSequencesWithNaNs(list)

  Given a sequence of sequences shallowly test the subsequence to see if it
  contains a NaN, if it does, remove that subsequence from the containing
  sequence.
  """
  return filter(isnotNaNinSequence, list)
  
