def test_conjugate(): """Unit tests of `conjugate` and `conjugate_guf`""" A = SmartArray((np.linspace(1, 12, 12) + 1j * np.linspace(21, 32, 12)).reshape(4, 3).astype(CX)) B = SmartArray(np.ones((4, 3), dtype=CX)) conjugate_guf(A.get(WHERE), B.get(WHERE)) B.mark_changed(WHERE) test = B.get() ref = A.get().conj() assert np.allclose(test, ref, **ALLCLOSE_KW), f"test:\n{test}\n!= ref:\n{ref}" A = SmartArray(np.linspace(1, 12, 12, dtype=FX).reshape(3, 4)) B = SmartArray(np.ones((3, 4), dtype=FX)) conjugate_guf(A.get(WHERE), B.get(WHERE)) B.mark_changed(WHERE) test = B.get() ref = A.get().conj() assert np.allclose(test, ref, **ALLCLOSE_KW), f"test:\n{test}\n!= ref:\n{ref}" logging.info("<< PASS : test_conjugate >>")
def test_prob3numba(ignore_fails=False, define_as_ref=False): """Run all unit test cases for prob3numba code""" # Pull first test case to test calling `propagate_array` tc_name, tc = next(iter(TEST_CASES.items())) tc_ = deepcopy(tc) logging.info( "Testing call and return shape of `propagate_array` with test case '%s'", tc_name, ) # Test simple broadcasting over `nubars` and `energies` where both have # same shape, as this is the "typical" use case input_shape = (4, 5) # Without broadcasting, a single probability matrix is 3x3 prob_array_shape = (3, 3) # Broadcasted shape out_shape = input_shape + prob_array_shape nubars = np.full(shape=input_shape, fill_value=tc_["nubar"], dtype=IX) energies = np.full(shape=input_shape, fill_value=tc_["energy"], dtype=FX) # Fill with NaN to ensure all elements are assinged a value probabilities = SmartArray(np.full(shape=out_shape, fill_value=np.nan, dtype=FX)) propagate_array( SmartArray(tc_["dm"].astype(FX)).get(WHERE), SmartArray(tc_["pmns"].astype(CX)).get(WHERE), SmartArray(tc_["mat_pot"].astype(CX)).get(WHERE), SmartArray(nubars).get(WHERE), SmartArray(energies).get(WHERE), SmartArray(tc_["layer_densities"].astype(FX)).get(WHERE), SmartArray(tc_["layer_distances"].astype(FX)).get(WHERE), # output: probabilities.get(WHERE), ) probabilities.mark_changed(WHERE) probabilities = probabilities.get("host") # Check that all probability matrices have no NaNs and are equal to one # another ref_probs = probabilities[0, 0] for i in range(input_shape[0]): for j in range(input_shape[1]): probs = probabilities[i, j] assert np.all(np.isfinite(probs)) assert np.all(probs == ref_probs) # Run all test cases for tc_name, tc in TEST_CASES.items(): run_test_case( tc_name, tc, ignore_fails=ignore_fails, define_as_ref=define_as_ref )
def test_clear_matrix(): """Unit tests of `clear_matrix` and `clear_matrix_guf`""" A = SmartArray(np.ones((4, 3), dtype=FTYPE)) clear_matrix_guf(A.get(WHERE), A.get(WHERE)) A.mark_changed(WHERE) test = A.get() ref = np.zeros((4, 3), dtype=FTYPE) assert np.array_equal(test, ref), f"test:\n{test}\n!= ref:\n{ref}" logging.info("<< PASS : test_clear_matrix >>")
def test_matrix_dot_vector(): """Unit tests of `matrix_dot_vector` and `matrix_dot_vector_guf`""" A = SmartArray(np.linspace(1, 12, 12, dtype=FTYPE).reshape(4, 3)) v = SmartArray(np.linspace(1, 3, 3, dtype=FTYPE)) w = SmartArray(np.ones(4, dtype=FTYPE)) matrix_dot_vector_guf(A.get(WHERE), v.get(WHERE), w.get(WHERE)) w.mark_changed(WHERE) test = w.get() ref = np.dot(A, v).astype(FTYPE) assert np.allclose(test, ref, **ALLCLOSE_KW), f"test:\n{test}\n!= ref:\n{ref}" logging.info("<< PASS : test_matrix_dot_vector >>")
def test_matrix_dot_matrix(): """Unit tests of `matrix_dot_matrix` and `matrix_dot_matrix_guf`""" A = SmartArray(np.linspace(1, 12, 12, dtype=FTYPE).reshape(3, 4)) B = SmartArray(np.linspace(1, 12, 12, dtype=FTYPE).reshape(4, 3)) C = SmartArray(np.ones((3, 3), dtype=FTYPE)) matrix_dot_matrix_guf(A.get(WHERE), B.get(WHERE), C.get(WHERE)) C.mark_changed(WHERE) test = C.get() ref = np.dot(A, B).astype(FTYPE) assert np.allclose(test, ref, **ALLCLOSE_KW), f"test:\n{test}\n!= ref:\n{ref}" logging.info("<< PASS : test_matrix_dot_matrix >>")
def lookup(sample, flat_hist, binning): ''' the inverse of histograming Paramters -------- sample : list of SmartArrays flat_hist : SmartArray binning : PISA MultiDimBinning Notes ----- this is only a 2d method right now ''' #print(binning) assert binning.num_dims in [2,3], 'can only do 2d and 3d at the moment' bin_edges = [edges.magnitude for edges in binning.bin_edges] # todo: directly return smart array if flat_hist.ndim == 1: #print 'looking up 1D' array = SmartArray(np.zeros_like(sample[0])) if binning.num_dims == 2: lookup_vectorized_2d(sample[0].get(WHERE), sample[1].get(WHERE), flat_hist.get(WHERE), bin_edges[0], bin_edges[1], out=array.get(WHERE)) elif binning.num_dims == 3: lookup_vectorized_3d(sample[0].get(WHERE), sample[1].get(WHERE), sample[2].get(WHERE), flat_hist.get(WHERE), bin_edges[0], bin_edges[1], bin_edges[2], out=array.get(WHERE)) elif flat_hist.ndim == 2: #print 'looking up ND' array = SmartArray(np.zeros((sample[0].size, flat_hist.shape[1]), dtype=FTYPE)) if binning.num_dims == 2: lookup_vectorized_2d_arrays(sample[0].get(WHERE), sample[1].get(WHERE), flat_hist.get(WHERE), bin_edges[0], bin_edges[1], out=array.get(WHERE)) elif binning.num_dims == 3: lookup_vectorized_3d_arrays(sample[0].get(WHERE), sample[1].get(WHERE), sample[2].get(WHERE), flat_hist.get(WHERE), bin_edges[0], bin_edges[1], bin_edges[2], out=array.get(WHERE)) else: raise NotImplementedError() array.mark_changed(WHERE) return array
def main(): print 'ftype=', ftype # hist arrays mix = np.ones((3, 3), dtype=np.float64) n = 1000000 inp = np.arange(3 * n, dtype=np.int32).reshape(n, 3) out = np.ones((n), dtype=np.int32) inp = SmartArray(inp) out = SmartArray(out) start_t = time.time() sum_row(mix, 42. + 2j, inp.get(WHERE), out=out.get(WHERE)) end_t = time.time() print 'took %.5f' % (end_t - start_t) start_t = time.time() sum_row(mix, 42. + 2j, inp.get(WHERE), out=out.get(WHERE)) end_t = time.time() print 'took %.5f' % (end_t - start_t) out.mark_changed(WHERE) print out.get('host')
def lookup_indices(sample, binning): """Lookup (flattened) bin index for sample points. Parameters ---------- sample : length-M_dimensions sequence of length-N_events SmartArrays All smart arrays must have the same lengths; corresponding elements of the arrays are the coordinates of an event in the dimensions each array represents. binning : pisa.core.binning.MultiDimBinning or convertible thereto `binning` is passed to instantiate ``MultiDimBinning``, so e.g., a pisa.core.binning.OneDimBinning is valid to pass as `binning` Returns ------- indices : length-N_events SmartArray One for each event the index of the histogram in which it falls into Notes ----- this method works for 1d, 2d and 3d histogram only """ # Convert non-MultiDimBinning objects into MultiDimBinning if possible; # if this fails, an error will result, as it should binning = MultiDimBinning(binning) if len(sample) != binning.num_dims: raise ValueError( f"`binning` has {binning.num_dims} dimension(s), but `sample`" f"contains {len(sample)} arrays (so represents {len(sample)}" f" dimensions)") lookup_funcs = { 1: lookup_indices_vectorized_1d, 2: lookup_indices_vectorized_2d, 3: lookup_indices_vectorized_3d, } if binning.num_dims not in lookup_funcs: raise NotImplementedError( "binning must have num_dims in {}; got {}".format( sorted(lookup_funcs.keys()), binning.num_dims)) lookup_func = lookup_funcs[binning.num_dims] lookup_func_args = ( [a.get(WHERE) for a in sample] + [SmartArray(dim.edge_magnitudes).get(WHERE) for dim in binning]) logging.trace("lookup_func_args = {}".format(lookup_func_args)) # Create an array to store the results indices = SmartArray(np.empty_like(sample[0], dtype=np.int64)) # Perform the lookup lookup_func(*lookup_func_args, out=indices.get(WHERE)) indices.mark_changed(WHERE) return indices
def lookup(sample, flat_hist, binning): """The inverse of histograming: Extract the histogram values at `sample` points. Parameters ---------- sample : num_dims list of length-num_samples SmartArrays Points at which to find histogram's values flat_hist : SmartArray Histogram values binning : num_dims MultiDimBinning Histogram's binning Returns ------- hist_vals : len-num_samples SmartArray Notes ----- Only handles 2d and 3d right now """ #print(binning) assert binning.num_dims in [2, 3], 'can only do 2d and 3d at the moment' bin_edges = [edges.magnitude for edges in binning.bin_edges] # TODO: directly return smart array if flat_hist.ndim == 1: #print 'looking up 1D' hist_vals = SmartArray(np.zeros_like(sample[0])) if binning.num_dims == 2: lookup_vectorized_2d( sample[0].get(WHERE), sample[1].get(WHERE), flat_hist.get(WHERE), bin_edges[0], bin_edges[1], out=hist_vals.get(WHERE), ) elif binning.num_dims == 3: lookup_vectorized_3d( sample[0].get(WHERE), sample[1].get(WHERE), sample[2].get(WHERE), flat_hist.get(WHERE), bin_edges[0], bin_edges[1], bin_edges[2], out=hist_vals.get(WHERE), ) elif flat_hist.ndim == 2: #print 'looking up ND' hist_vals = SmartArray( np.zeros((sample[0].size, flat_hist.shape[1]), dtype=FTYPE)) if binning.num_dims == 2: lookup_vectorized_2d_arrays( sample[0].get(WHERE), sample[1].get(WHERE), flat_hist.get(WHERE), bin_edges[0], bin_edges[1], out=hist_vals.get(WHERE), ) elif binning.num_dims == 3: lookup_vectorized_3d_arrays( sample[0].get(WHERE), sample[1].get(WHERE), sample[2].get(WHERE), flat_hist.get(WHERE), bin_edges[0], bin_edges[1], bin_edges[2], out=hist_vals.get(WHERE), ) else: raise NotImplementedError() hist_vals.mark_changed(WHERE) return hist_vals
def test_find_index(): """Unit tests for `find_index` function. Correctness is defined as producing the same histogram as numpy.histogramdd by using the output of `find_index` (ignoring underflow and overflow values). Additionally, -1 should be returned if a value is below the range (underflow) or is nan, and num_bins should be returned for a value above the range (overflow). """ # Negative, positive, integer, non-integer, binary-unrepresentable (0.1) edges basic_bin_edges = [-1, -0.5, -0.1, 0, 0.1, 0.5, 1, 2, 3, 4] failures = 0 for basic_bin_edges in [ # Negative, positive, integer, non-integer, binary-unrepresentable (0.1) edges [-1, -0.5, -0.1, 0, 0.1, 0.5, 1, 2, 3, 4], # A single infinite bin: [-np.inf, np.inf] [], # Half-infinite bins (lower or upper edge) & [-inf, .1, +inf] [0.1], # Single bin with finite edges & +/-inf-edge(s)-added variants [-0.1, 0.1], ]: # Bin edges from above, w/ and w/o +/-inf as left and/or right edges for le, re in [(None, None), (-np.inf, None), (None, np.inf), (-np.inf, np.inf)]: bin_edges = deepcopy(basic_bin_edges) if le is not None: bin_edges = [le] + bin_edges if re is not None: bin_edges = bin_edges + [re] if len(bin_edges) < 2: continue logging.debug('bin_edges being tested: %s', bin_edges) bin_edges = SmartArray(np.array(bin_edges, dtype=FTYPE)) num_bins = len(bin_edges) - 1 underflow_idx = -1 overflow_idx = num_bins # # Construct test values to try out # non_finite_vals = [-np.inf, +np.inf, np.nan] # Values within bins (i.e., not on edges) inbin_vals = [] for idx in range(len(bin_edges) - 1): lower_be = bin_edges[idx] upper_be = bin_edges[idx + 1] if np.isfinite(lower_be): if np.isfinite(upper_be): inbin_val = (lower_be + upper_be) / 2 else: inbin_val = lower_be + 10.5 else: if np.isfinite(upper_be): inbin_val = upper_be - 10.5 else: inbin_val = 10.5 inbin_vals.append(inbin_val) # Values above/below bin edges by one unit of floating point # accuracy eps = np.finfo(FTYPE).eps # pylint: disable=no-member below_edges_vals = [FTYPE((1 - eps) * be) for be in bin_edges] above_edges_vals = [FTYPE((1 + eps) * be) for be in bin_edges] test_vals = np.concatenate([ non_finite_vals, bin_edges, inbin_vals, below_edges_vals, above_edges_vals, ]) logging.trace('test_vals = %s', test_vals) # # Run tests # for val in test_vals: val = FTYPE(val) np_histvals, _ = np.histogramdd([val], np.atleast_2d(bin_edges)) nonzero_indices = np.nonzero(np_histvals)[ 0] # select first & only dim if np.isnan(val): assert len(nonzero_indices) == 0, str(len(nonzero_indices)) expected_idx = underflow_idx elif val < bin_edges[0]: assert len(nonzero_indices) == 0, str(len(nonzero_indices)) expected_idx = underflow_idx elif val > bin_edges[-1]: assert len(nonzero_indices) == 0, str(len(nonzero_indices)) expected_idx = overflow_idx else: assert len(nonzero_indices) == 1, str(len(nonzero_indices)) expected_idx = nonzero_indices[0] if TARGET == 'cpu': found_idx = find_index(val, bin_edges) elif TARGET == 'cuda': found_idx_ary = SmartArray(np.zeros(1, dtype=np.int)) find_index_cuda( SmartArray(np.array([val], dtype=FTYPE)).get(WHERE), bin_edges.get(WHERE), found_idx_ary.get(WHERE), ) found_idx_ary.mark_changed(WHERE) found_idx = found_idx_ary.get()[0] else: raise NotImplementedError(f"TARGET='{TARGET}'") if found_idx != expected_idx: failures += 1 msg = 'val={}, edges={}: Expected idx={}, found idx={}'.format( val, bin_edges.get(), expected_idx, found_idx) logging.error(msg) assert failures == 0, f"{failures} failures, inspect ERROR messages above for info" logging.info('<< PASS : test_find_index >>')