text: """
  Author(s): Matthew Loper
  
  See LICENCE.txt for licensing and contact information.
  """
  
  
  from . import ch
  import numpy as np
  from os.path import join, split
  from io import StringIO
  import numpy
  import chumpy
  import pickle as pickle
  
  src = ''
  num_passed = 0
  num_not_passed = 0
  which_passed = []
  
  def r(fn_name, args_req, args_opt, nplib=numpy, chlib=chumpy):
      global num_passed, num_not_passed
      result = [None, None]
          
      for lib in [nplib, chlib]:
  
          # if fn_name is 'svd' and lib is chlib:
          #     import pdb; pdb.set_trace()
          if lib is nplib:            
              fn = getattr(lib, fn_name)
          else:
              try:
                  fn = getattr(lib, fn_name)
              except AttributeError:
                  result[0] = 'missing'
                  result[1] = 'missing'
                  num_not_passed += 1
                  continue
          try:
              if isinstance(args_req, dict):
                  _ = fn(**args_req)
              else:
                  _ = fn(*args_req)
              if lib is chlib:
                  result[0] = 'passed'
                  num_passed += 1
                  global which_passed
                  which_passed.append(fn_name)
                  
                  if hasattr(_, 'dterms'):
                      try:
                          _.r
                      
                          try:
                              pickle.dumps(_)
                          except:
                              result[0] += ' (but unpickleable!)'
                      except:
                          import pdb; pdb.set_trace()
                          result[0] += '(but cant get result!)'
          except Exception as e:
              if e is TypeError:
                  import pdb; pdb.set_trace()
              if lib is nplib:
                  import pdb; pdb.set_trace()
              else:
                  num_not_passed += 1
                  # if fn_name == 'rot90':
                  #     import pdb; pdb.set_trace()
              result[0] = e.__class__.__name__
              
          try:
              if isinstance(args_req, dict):
                  fn(**dict(list(args_req.items()) + list(args_opt.items())))
              else:
                  fn(*args_req, **args_opt)
              if lib is chlib:
                  result[1] = 'passed'
          except Exception as e:
              if e is TypeError:
                  import pdb; pdb.set_trace()
              result[1] = e.__class__.__name__
              
      # print '%s: %s, %s' % (fn_name, result[0], result[1])
      
      append(fn_name, result[0], result[1])
      
  def make_row(a, b, c, b_color, c_color):
      global src
      src += '<tr><td>%s</td><td style="background-color:%s">%s</td><td style="background-color:%s">%s</td></tr>' % (a,b_color, b,c_color, c)
      
  def append(a, b, c):
      global src
      b_color = 'white'
      c_color = 'white'
  
      b = b.replace('NotImplementedError', 'not yet implemented')
      c = c.replace('NotImplementedError', 'not yet implemented')
      b = b.replace('WontImplement', "won't implement")
      c = c.replace('WontImplement', "won't implement")
      lookup = {
          'passed': 'lightgreen',
          "won't implement": 'lightgray',
          'untested': 'lightyellow',
          'not yet implemented': 'pink'
      }
      
      b_color = lookup[b] if b in lookup else 'white'
      c_color = lookup[c] if c in lookup else 'white'
  
      print('%s: %s, %s' % (a,b,c))
      make_row(a, b, c, b_color, c_color)
  
  def m(s):
      append(s, 'unknown', 'unknown')
      global num_not_passed
      num_not_passed += 1
  
  def hd3(s):
      global src
      src += '<tr><td colspan=3><h3 style="margin-bottom:0;">%s</h3></td></tr>' % (s,)
  
  def hd2(s):
      global src
      src += '</table><br/><br/><table border=1>'
      src += '<tr><td colspan=3 style="background-color:black;color:white"><h2 style="margin-bottom:0;">%s</h2></td></tr>' % (s,)
      
  def main():
      
      #sample_array
      
      ###############################
      hd2('Array Creation Routines')
      
      hd3('Ones and zeros')
  
      r('empty', {'shape': (2,4,2)}, {'dtype': np.uint8, 'order': 'C'})
      r('empty_like', {'prototype': np.empty((2,4,2))}, {'dtype': np.float64, 'order': 'C'})
      r('eye', {'N': 10}, {'M': 5, 'k': 0, 'dtype': np.float64})
      r('identity', {'n': 10}, {'dtype': np.float64})
      r('ones', {'shape': (2,4,2)}, {'dtype': np.uint8, 'order': 'C'})
      r('ones_like', {'a': np.empty((2,4,2))}, {'dtype': np.float64, 'order': 'C'})
      r('zeros', {'shape': (2,4,2)}, {'dtype': np.uint8, 'order': 'C'})
      r('zeros_like', {'a': np.empty((2,4,2))}, {'dtype': np.float64, 'order': 'C'})
      
      hd3('From existing data')
      r('array', {'object': [1,2,3]}, {'dtype': np.float64, 'order': 'C', 'subok': False, 'ndmin': 2})
      r('asarray', {'a': np.array([1,2,3])}, {'dtype': np.float64, 'order': 'C'})
      r('asanyarray', {'a': np.array([1,2,3])}, {'dtype': np.float64, 'order': 'C'})
      r('ascontiguousarray', {'a': np.array([1,2,3])}, {'dtype': np.float64})
      r('asmatrix', {'data': np.array([1,2,3])}, {'dtype': np.float64})
      r('copy', (np.array([1,2,3]),), {})
      r('frombuffer', {'buffer': np.array([1,2,3])}, {})
      m('fromfile')
      r('fromfunction', {'function': lambda i, j: i + j, 'shape': (3, 3)}, {'dtype': np.float64})
      # function, shape, **kwargs
      # lambda i, j: i + j, (3, 3), dtype=int
      r('fromiter', {'iter': [1,2,3,4], 'dtype': np.float64}, {'count': 2})
      r('fromstring', {'string': '\x01\x02', 'dtype': np.uint8}, {})
      r('loadtxt', {'fname': StringIO("0 1\n2 3")}, {})
  
      hd3('Creating record arrays (wont be implemented)')
      hd3('Creating character arrays (wont be implemented)')
  
      hd3('Numerical ranges')
      r('arange', {'start': 0, 'stop': 10}, {'step': 2, 'dtype': np.float64})
      r('linspace', {'start': 0, 'stop': 10}, {'num': 2, 'endpoint': 10, 'retstep': 1})
      r('logspace', {'start': 0, 'stop': 10}, {'num': 2, 'endpoint': 10, 'base': 1})
      r('meshgrid', ([1,2,3], [4,5,6]), {})
      m('mgrid')
      m('ogrid')
      
      hd3('Building matrices')
      r('diag', {'v': np.arange(9).reshape((3,3))}, {'k': 0})
      r('diagflat', {'v': [[1,2], [3,4]]}, {})
      r('tri', {'N': 3}, {'M': 5, 'k': 2, 'dtype': np.float64})
      r('tril', {'m': [[1,2,3],[4,5,6],[7,8,9],[10,11,12]]}, {'k': -1})
      r('triu', {'m': [[1,2,3],[4,5,6],[7,8,9],[10,11,12]]}, {'k': -1})
      r('vander', {'x': np.array([1, 2, 3, 5])}, {'N': 3})
      
      ###############################
      hd2('Array manipulation routines')
      
      hd3('Basic operations')
      r('copyto', {'dst': np.eye(3), 'src': np.eye(3)}, {})
      
      hd3('Changing array shape')
      r('reshape', {'a': np.eye(3), 'newshape': (9,)}, {'order' : 'C'})
      r('ravel', {'a': np.eye(3)}, {'order' : 'C'})
      m('flat')
      m('flatten')
      
      hd3('Transpose-like operations')
      r('rollaxis', {'a': np.ones((3,4,5,6)), 'axis': 3}, {'start': 0})
      r('swapaxes', {'a': np.array([[1,2,3]]), 'axis1': 0, 'axis2': 1}, {})
      r('transpose', {'a': np.arange(4).reshape((2,2))}, {'axes': (1,0)})
      
      hd3('Changing number of dimensions')
      r('atleast_1d', (np.eye(3),), {})
      r('atleast_2d', (np.eye(3),), {})
      r('atleast_3d', (np.eye(3),), {})
      m('broadcast')
      m('broadcast_arrays')
      r('expand_dims', (np.array([1,2]),2), {})
      r('squeeze', {'a': (np.array([[[1,2,3]]]))}, {})
      
      hd3('Changing kind of array')
      r('asarray', {'a': np.array([1,2,3])}, {'dtype': np.float64, 'order': 'C'})
      r('asanyarray', {'a': np.array([1,2,3])}, {'dtype': np.float64, 'order': 'C'})
      r('asmatrix', {'data': np.array([1,2,3])}, {})
      r('asfarray', {'a': np.array([1,2,3])}, {})
      r('asfortranarray', {'a': np.array([1,2,3])}, {})
      r('asscalar', {'a': np.array([24])}, {})
      r('require', {'a': np.array([24])}, {})
      
      hd3('Joining arrays')
      m('column_stack')
      r('concatenate', ((np.eye(3), np.eye(3)),1), {})
      r('dstack', ((np.eye(3), np.eye(3)),), {})
      r('hstack', ((np.eye(3), np.eye(3)),), {})
      r('vstack', ((np.eye(3), np.eye(3)),), {})
  
      hd3('Splitting arrays')
      m('array_split')
      m('dsplit')
      m('hsplit')
      m('split')
      m('vsplit')
  
      hd3('Tiling arrays')
      r('tile', (np.array([0, 1, 2]),2), {})
      r('repeat', (np.array([[1,2],[3,4]]), 3), {'axis': 1})
  
      hd3('Adding and removing elements')
      m('delete')
      m('insert')
      m('append')
      m('resize')
      m('trim_zeros')
      m('unique')
      
      hd3('Rearranging elements')
      r('fliplr', (np.eye(3),), {})
      r('flipud', (np.eye(3),), {})
      r('reshape', {'a': np.eye(3), 'newshape': (9,)}, {'order' : 'C'})
      r('roll', (np.arange(10), 2), {})
      r('rot90', (np.arange(4).reshape((2,2)),), {})
          
      ###############################
      hd2('Linear algebra (numpy.linalg)')
      
      extra_args = {'nplib': numpy.linalg, 'chlib': ch.linalg}
      
      hd3('Matrix and dot products')
      r('dot', {'a': np.eye(3), 'b': np.eye(3)}, {})
      r('dot', {'a': np.eye(3).ravel(), 'b': np.eye(3).ravel()}, {})
      r('vdot', (np.eye(3).ravel(), np.eye(3).ravel()), {})
      r('inner', (np.eye(3).ravel(), np.eye(3).ravel()), {})
      r('outer', (np.eye(3).ravel(), np.eye(3).ravel()), {})
      r('tensordot', {'a': np.eye(3), 'b': np.eye(3)}, {})
      m('einsum')
      r('matrix_power', {'M': np.eye(3), 'n': 2}, {}, **extra_args)
      r('kron', {'a': np.eye(3), 'b': np.eye(3)}, {})
          
      hd3('Decompositions')
      r('cholesky', {'a': np.eye(3)}, {}, **extra_args)
      r('qr', {'a': np.eye(3)}, {}, **extra_args)
      r('svd', (np.eye(3),), {}, **extra_args)
      
      hd3('Matrix eigenvalues')
      r('eig', (np.eye(3),), {}, **extra_args)
      r('eigh', (np.eye(3),), {}, **extra_args)
      r('eigvals', (np.eye(3),), {}, **extra_args)
      r('eigvalsh', (np.eye(3),), {}, **extra_args)
      
      hd3('Norms and other numbers')
      r('norm', (np.eye(3),), {}, **extra_args)
      r('cond', (np.eye(3),), {}, **extra_args)
      r('det', (np.eye(3),), {}, **extra_args)
      r('slogdet', (np.eye(3),), {}, **extra_args)
      r('trace', (np.eye(3),), {})
      
      hd3('Solving equations and inverting matrices')
      r('solve', (np.eye(3),np.ones(3)), {}, **extra_args)
      r('tensorsolve', (np.eye(3),np.ones(3)), {}, **extra_args)
      r('lstsq', (np.eye(3),np.ones(3)), {}, **extra_args)
      r('inv', (np.eye(3),), {}, **extra_args)
      r('pinv', (np.eye(3),), {}, **extra_args)
      r('tensorinv', (np.eye(4*6).reshape((4,6,8,3)),), {'ind': 2}, **extra_args)
      
      hd2('Mathematical functions')
  
      hd3('Trigonometric functions')
      r('sin', (np.arange(3),), {})
      r('cos', (np.arange(3),), {})
      r('tan', (np.arange(3),), {})
      r('arcsin', (np.arange(3)/3.,), {})
      r('arccos', (np.arange(3)/3.,), {})
      r('arctan', (np.arange(3)/3.,), {})
      r('hypot', (np.arange(3),np.arange(3)), {})
      r('arctan2', (np.arange(3),np.arange(3)), {})
      r('degrees', (np.arange(3),), {})
      r('radians', (np.arange(3),), {})
      r('unwrap', (np.arange(3),), {})
      r('unwrap', (np.arange(3),), {})
      r('deg2rad', (np.arange(3),), {})
      r('rad2deg', (np.arange(3),), {})
      
      hd3('Hyperbolic functions')
      r('sinh', (np.arange(3),), {})
      r('cosh', (np.arange(3),), {})
      r('tanh', (np.arange(3),), {})
      r('arcsinh', (np.arange(3)/9.,), {})
      r('arccosh', (-np.arange(3)/9.,), {})
      r('arctanh', (np.arange(3)/9.,), {})
      
      hd3('Rounding')
      r('around', (np.arange(3),), {})
      r('round_', (np.arange(3),), {})
      r('rint', (np.arange(3),), {})
      r('fix', (np.arange(3),), {})
      r('floor', (np.arange(3),), {})
      r('ceil', (np.arange(3),), {})
      r('trunc', (np.arange(3),), {})
      
      hd3('Sums, products, differences')
      r('prod', (np.arange(3),), {})
      r('sum', (np.arange(3),), {})
      r('nansum', (np.arange(3),), {})
      r('cumprod', (np.arange(3),), {})
      r('cumsum', (np.arange(3),), {})
      r('diff', (np.arange(3),), {})
      r('ediff1d', (np.arange(3),), {})
      r('gradient', (np.arange(3),), {})
      r('cross', (np.arange(3), np.arange(3)), {})
      r('trapz', (np.arange(3),), {})
      
      hd3('Exponents and logarithms')
      r('exp', (np.arange(3),), {})
      r('expm1', (np.arange(3),), {})
      r('exp2', (np.arange(3),), {})
      r('log', (np.arange(3),), {})
      r('log10', (np.arange(3),), {})
      r('log2', (np.arange(3),), {})
      r('log1p', (np.arange(3),), {})
      r('logaddexp', (np.arange(3), np.arange(3)), {})
      r('logaddexp2', (np.arange(3), np.arange(3)), {})
      
      hd3('Other special functions')
      r('i0', (np.arange(3),), {})
      r('sinc', (np.arange(3),), {})
      
      hd3('Floating point routines')
      r('signbit', (np.arange(3),), {})
      r('copysign', (np.arange(3), np.arange(3)), {})
      r('frexp', (np.arange(3),), {})
      r('ldexp', (np.arange(3), np.arange(3)), {})
      
      hd3('Arithmetic operations')
      r('add', (np.arange(3), np.arange(3)), {})
      r('reciprocal', (np.arange(3),), {})
      r('negative', (np.arange(3),), {})
      r('multiply', (np.arange(3), np.arange(3)), {})
      r('divide', (np.arange(3), np.arange(3)), {})
      r('power', (np.arange(3), np.arange(3)), {})
      r('subtract', (np.arange(3), np.arange(3)), {})
      r('true_divide', (np.arange(3), np.arange(3)), {})
      r('floor_divide', (np.arange(3), np.arange(3)), {})
      r('fmod', (np.arange(3), np.arange(3)), {})
      r('mod', (np.arange(3), np.arange(3)), {})
      r('modf', (np.arange(3),), {})
      r('remainder', (np.arange(3), np.arange(3)), {})
      
      hd3('Handling complex numbers')
      m('angle')
      m('real')
      m('imag')
      m('conj')
      
      hd3('Miscellaneous')
      r('convolve', (np.arange(3), np.arange(3)), {})
      r('clip', (np.arange(3), 0, 2), {})
      r('sqrt', (np.arange(3),), {})
      r('square', (np.arange(3),), {})
      r('absolute', (np.arange(3),), {})
      r('fabs', (np.arange(3),), {})
      r('sign', (np.arange(3),), {})
      r('maximum', (np.arange(3), np.arange(3)), {})
      r('minimum', (np.arange(3), np.arange(3)), {})
      r('fmax', (np.arange(3), np.arange(3)), {})
      r('fmin', (np.arange(3), np.arange(3)), {})
      r('nan_to_num', (np.arange(3),), {})
      r('real_if_close', (np.arange(3),), {})
      r('interp', (2.5, [1,2,3], [3,2,0]), {})
      
      extra_args = {'nplib': numpy.random, 'chlib': ch.random}
      
      hd2('Random sampling (numpy.random)')
      hd3('Simple random data')
      r('rand', (3,), {}, **extra_args)
      r('randn', (3,), {}, **extra_args)
      r('randint', (3,), {}, **extra_args)
      r('random_integers', (3,), {}, **extra_args)
      r('random_sample', (3,), {}, **extra_args)
      r('random', (3,), {}, **extra_args)
      r('ranf', (3,), {}, **extra_args)
      r('sample', (3,), {}, **extra_args)
      r('choice', (np.ones(3),), {}, **extra_args)
      r('bytes', (3,), {}, **extra_args)
      
      hd3('Permutations')
      r('shuffle', (np.ones(3),), {}, **extra_args)
      r('permutation', (3,), {}, **extra_args)
      
      hd3('Distributions (these all pass)')
      r('beta', (.5, .5), {}, **extra_args)
      r('binomial', (.5, .5), {}, **extra_args)
      r('chisquare', (.5,), {}, **extra_args)
      r('dirichlet', ((10, 5, 3), 20,), {}, **extra_args)
      r('exponential', [], {}, **extra_args)
      r('f', [1,48,1000], {}, **extra_args)
      r('gamma', [.5], {}, **extra_args)
      make_row('...AND 28 OTHERS...', 'passed', 'passed', 'lightgreen', 'lightgreen')
      
      
      hd3('Random generator')
      r('seed', [], {}, **extra_args)
      r('get_state', [], {}, **extra_args)
      r('set_state', [np.random.get_state()], {}, **extra_args)
      
      ####################################
      hd2('Statistics')
      hd3('Order statistics')
      r('amin', (np.eye(3),),{})
      r('amax', (np.eye(3),),{})
      r('nanmin', (np.eye(3),),{})
      r('nanmax', (np.eye(3),),{})
      r('ptp', (np.eye(3),),{})
      r('percentile', (np.eye(3),50),{})
  
      hd3('Averages and variance')
      r('median', (np.eye(3),),{})
      r('average', (np.eye(3),),{})
      r('mean', (np.eye(3),),{})
      r('std', (np.eye(3),),{})
      r('var', (np.eye(3),),{})
      r('nanmean', (np.eye(3),),{})
      r('nanstd', (np.eye(3),),{})
      r('nanvar', (np.eye(3),),{})
      
  
      hd3('Correlating')
      r('corrcoef', (np.eye(3),),{})
      r('correlate', ([1, 2, 3], [0, 1, 0.5]),{})
      r('cov', (np.eye(3),),{})
      
      hd3('Histograms')
      r('histogram', (np.eye(3),),{})
      r('histogram2d', (np.eye(3).ravel(),np.eye(3).ravel()),{})
      r('histogramdd', (np.eye(3).ravel(),),{})
      r('bincount', (np.asarray(np.eye(3).ravel(), np.uint32),),{})
      r('digitize', (np.array([0.2, 6.4, 3.0, 1.6]), np.array([0.0, 1.0, 2.5, 4.0, 10.0])),{})
      
      ####################################
      hd2('Sorting, searching, and counting')
      
      hd3('Sorting')
      r('sort', (np.array([1,3,1,2.]),), {})
      m('lexsort')
      m('argsort')
      m('msort')
      m('sort_complex')
      m('partition')
      m('argpartition')
      
  # sort(a[, axis, kind, order])    Return a sorted copy of an array.
  # lexsort(keys[, axis])    Perform an indirect sort using a sequence of keys.
  # argsort(a[, axis, kind, order])    Returns the indices that would sort an array.
  # ndarray.sort([axis, kind, order])    Sort an array, in-place.
  # msort(a)    Return a copy of an array sorted along the first axis.
  # sort_complex(a)    Sort a complex array using the real part first, then the imaginary part.
  # partition(a, kth[, axis, kind, order])    Return a partitioned copy of an array.
  # argpartition(a, kth[, axis, kind, order])    Perform an indirect partition along the given axis using the algorithm specified by the kind keyword.
      
      a5 = np.arange(5)
  
      hd3('Searching')
      r('argmax', (a5,), {})
      r('nanargmax', (a5,), {})
      r('argmin', (a5,), {})
      r('nanargmin', (a5,), {})
      r('argwhere', (a5,), {})
      r('nonzero', (a5,), {})
      r('flatnonzero', (a5,), {})
      r('where', (a5>1,), {})
      r('searchsorted', (a5,a5), {})
      r('extract', (lambda x : x > 1, a5), {})
  
  # argmax(a[, axis])    Indices of the maximum values along an axis.
  # nanargmax(a[, axis])    Return the indices of the maximum values in the specified axis ignoring
  # argmin(a[, axis])    Return the indices of the minimum values along an axis.
  # nanargmin(a[, axis])    Return the indices of the minimum values in the specified axis ignoring
  # argwhere(a)    Find the indices of array elements that are non-zero, grouped by element.
  # nonzero(a)    Return the indices of the elements that are non-zero.
  # flatnonzero(a)    Return indices that are non-zero in the flattened version of a.
  # where(condition, [x, y])    Return elements, either from x or y, depending on condition.
  # searchsorted(a, v[, side, sorter])    Find indices where elements should be inserted to maintain order.
  # extract(condition, arr)    Return the elements of an array that satisfy some condition.    
      
      hd3('Counting')
      r('count_nonzero', (a5,), {})
      #count_nonzero(a)	Counts the number of non-zero values in the array a.
      
      
  
  # histogram(a[, bins, range, normed, weights, ...])    Compute the histogram of a set of data.
  # histogram2d(x, y[, bins, range, normed, weights])    Compute the bi-dimensional histogram of two data samples.
  # histogramdd(sample[, bins, range, normed, ...])    Compute the multidimensional histogram of some data.
  # bincount(x[, weights, minlength])    Count number of occurrences of each value in array of non-negative ints.
  # digitize(x, bins[, right])    Return the indices of the bins to which each value in input array belongs.    
  
          
      global src
      src = '<html><body><table border=1>' + src + '</table></body></html>'    
      open(join(split(__file__)[0], 'api_compatibility.html'), 'w').write(src)
      
      print('passed %d, not passed %d' % (num_passed, num_not_passed))
      
  
  
  if __name__ == '__main__':
      global which_passed
      main()
      print(' '.join(which_passed))
  