def normalize(data):
if data is None: return None<EOL>elif pimms.is_array(data, '<STR_LIT>') and not pimms.is_array(data, '<STR_LIT>'):<EOL><INDENT>return {normalize_type_key: [None, '<STR_LIT>'], '<STR_LIT>':np.real(data), '<STR_LIT>': np.imag(data)}<EOL><DEDENT>elif is_set(data):<EOL><INDENT>return {normalize_type_key: [None, '<STR_LIT>'], '<STR_LIT>': normalize(list(data))}<EOL><DEDENT>elif pimms.is_scalar(data, ('<STR_LIT>', '<STR_LIT:string>', '<STR_LIT>', '<STR_LIT:bool>')):<EOL><INDENT>return data<EOL><DEDENT>elif sps.issparse(data):<EOL><INDENT>(i,j,v) = sps.find(data)<EOL>return {normalize_type_key: [None, '<STR_LIT>'],<EOL>'<STR_LIT>':i.tolist(), '<STR_LIT>':j.tolist(), '<STR_LIT>': v.tolist(),<EOL>'<STR_LIT>':data.shape}<EOL><DEDENT>elif pimms.is_map(data):<EOL><INDENT>newdict = {}<EOL>for (k,v) in six.iteritems(data):<EOL><INDENT>if not pimms.is_str(k):<EOL><INDENT>raise ValueError('<STR_LIT>')<EOL><DEDENT>newdict[k] = normalize(v)<EOL><DEDENT>return newdict<EOL><DEDENT>elif pimms.is_array(data, ('<STR_LIT>', '<STR_LIT:string>', '<STR_LIT>', '<STR_LIT:bool>')):<EOL><INDENT>return data.tolist() if pimms.is_nparray(data) else data<EOL><DEDENT>elif data is Ellipsis:<EOL><INDENT>return {normalize_type_key: [None, '<STR_LIT>']}<EOL><DEDENT>elif pimms.is_scalar(data):<EOL><INDENT>try:    m = data.normalize()<EOL>except Exception: raise ValueError('<STR_LIT>' % data)<EOL>if not pimms.is_map(m): raise ValueError('<STR_LIT>' % data)<EOL>m = dict(m)<EOL>tt = type(data)<EOL>m[normalize_type_key] = [tt.__module__, tt.__name__]<EOL>return m<EOL><DEDENT>else:<EOL><INDENT>return [normalize(x) for x in data]<EOL><DEDENT>
normalize(obj) yields a JSON-friendly normalized description of the given object. If the data
  cannot be normalized an error is raised.

Any object that implements a normalize() function can be normalized, so long as the mapping 
object returned by normalize() itself can be normalized. Note that the normalize() function
must return a mapping object.

Objects that can be represented as themselves are returned as themselves. Any other object will
be represented as a map that includes the reserved key '__type__' which will map to a
2-element list [module_name, class_name]; upon denomrlization, the module and class k are looked
up and k.denomalize(data) is called.