diff --git a/psyneulink/core/components/component.py b/psyneulink/core/components/component.py index ead7cba1376..59c81bf3f0a 100644 --- a/psyneulink/core/components/component.py +++ b/psyneulink/core/components/component.py @@ -1317,6 +1317,10 @@ def _get_compilation_state(self): if getattr(self.parameters, 'has_recurrent_input_port', False): blacklist.update(['combination_function']) + # Drop previous_value from MemoryFunctions + if hasattr(self.parameters, 'duplicate_keys'): + blacklist.add("previous_value") + def _is_compilation_state(p): # FIXME: This should use defaults instead of 'p.get' return p.name not in blacklist and \ @@ -1400,7 +1404,7 @@ def _get_compilation_params(self): "random_variables", "smoothing_factor", "per_item", "key_size", "val_size", "max_entries", "random_draw", "randomization_dimension", "save_values", "save_samples", - "max_iterations", + "max_iterations", "duplicate_keys", # not used in compiled learning "learning_results", "learning_signal", "learning_signals", "error_matrix", "error_signal", "activation_input", diff --git a/psyneulink/core/components/functions/stateful/memoryfunctions.py b/psyneulink/core/components/functions/stateful/memoryfunctions.py index bb16c12e8b8..ab854cb0a0a 100644 --- a/psyneulink/core/components/functions/stateful/memoryfunctions.py +++ b/psyneulink/core/components/functions/stateful/memoryfunctions.py @@ -2427,8 +2427,8 @@ def _gen_llvm_function_body(self, ctx, builder, params, state, arg_in, arg_out, store_prob = pnlvm.helpers.load_extract_scalar_array_one(builder, store_prob_ptr) store_rand = builder.fcmp_ordered('<', store_prob, store_prob.type(1.0)) - # The call to random function needs to be behind jump to match python - # code + # The call to random function needs to be behind the check of 'store_rand' + # to match python code semantics with builder.if_then(store_rand): rand_ptr = builder.alloca(ctx.float_ty) builder.call(uniform_f, [rand_struct, rand_ptr]) @@ -2439,6 +2439,27 @@ def _gen_llvm_function_body(self, ctx, builder, params, state, arg_in, arg_out, # Store store = builder.load(store_ptr) with builder.if_then(store, likely=True): + modified_key_ptr = builder.alloca(var_key_ptr.type.pointee) + + # Apply noise to key. + # There are 3 types of noise: scalar, vector1, and vector matching variable + noise_ptr = pnlvm.helpers.get_param_ptr(builder, self, params, "noise") + rate_ptr = pnlvm.helpers.get_param_ptr(builder, self, params, "rate") + with pnlvm.helpers.array_ptr_loop(b, var_key_ptr, "key_apply_rate_noise") as (b, idx): + if pnlvm.helpers.is_2d_matrix(noise_ptr): + noise_elem_ptr = b.gep(noise_ptr, [ctx.int32_ty(0), ctx.int32_ty(0), idx]) + noise_val = b.load(noise_elem_ptr) + else: + noise_val = pnlvm.helpers.load_extract_scalar_array_one(b, noise_ptr) + + rate_val = pnlvm.helpers.load_extract_scalar_array_one(b, rate_ptr) + + modified_key_elem_ptr = b.gep(modified_key_ptr, [ctx.int32_ty(0), idx]) + key_elem_ptr = b.gep(var_key_ptr, [ctx.int32_ty(0), idx]) + key_elem = b.load(key_elem_ptr) + key_elem = b.fmul(key_elem, rate_val) + key_elem = b.fadd(key_elem, noise_val) + b.store(key_elem, modified_key_elem_ptr) # Check if such key already exists is_new_key_ptr = builder.alloca(ctx.bool_ty) @@ -2451,7 +2472,7 @@ def _gen_llvm_function_body(self, ctx, builder, params, state, arg_in, arg_out, key_differs_ptr = b.alloca(ctx.bool_ty) b.store(key_differs_ptr.type.pointee(0), key_differs_ptr) with pnlvm.helpers.array_ptr_loop(b, cmp_key_ptr, "key_compare") as (b2, idx2): - var_key_element = b2.gep(var_key_ptr, [ctx.int32_ty(0), idx2]) + var_key_element = b2.gep(modified_key_ptr, [ctx.int32_ty(0), idx2]) cmp_key_element = b2.gep(cmp_key_ptr, [ctx.int32_ty(0), idx2]) element_differs = b.fcmp_unordered('!=', b.load(var_key_element), @@ -2473,7 +2494,7 @@ def _gen_llvm_function_body(self, ctx, builder, params, state, arg_in, arg_out, store_key_ptr = builder.gep(keys_ptr, [ctx.int32_ty(0), write_idx]) store_val_ptr = builder.gep(vals_ptr, [ctx.int32_ty(0), write_idx]) - builder.store(builder.load(var_key_ptr), store_key_ptr) + builder.store(builder.load(modified_key_ptr), store_key_ptr) builder.store(builder.load(var_val_ptr), store_val_ptr) # Update counters @@ -2674,18 +2695,20 @@ def _function(self, # CURRENT PROBLEM WITH LATTER IS THAT IT CAUSES CRASH ON INIT, SINCE NOT OUTPUT_PORT # SO, WOULD HAVE TO RETURN ZEROS ON INIT AND THEN SUPPRESS AFTERWARDS, AS MOCKED UP BELOW memory = [[0]* self.parameters.key_size._get(context), [0]* self.parameters.val_size._get(context)] + # Store variable to dict: + rate = self._get_current_parameter_value(RATE, context) + if rate is not None: + key = np.asfarray(key) * np.asfarray(rate) + assert len(key) == len(variable[KEYS]), "{} vs. {}".format(key, variable[KEYS]) + if noise is not None: - key = np.asarray(key, dtype=float) - if isinstance(noise, numbers.Number): - key += noise - else: - # assume array with same shape as variable - # TODO: does val need noise? - key += noise[KEYS] + # TODO: does val need noise? + key = np.asfarray(key) + np.asfarray(noise)[KEYS] + assert len(key) == len(variable[KEYS]), "{} vs. {}".format(key, variable[KEYS]) if storage_prob == 1.0 or (storage_prob > 0.0 and storage_prob > random_state.uniform()): - self._store_memory(variable, context) + self._store_memory([key, val], context) # Return 3d array with keys and vals as lists # IMPLEMENTATION NOTE: if try to create np.ndarray directly, and keys and vals have same length diff --git a/tests/functions/test_memory.py b/tests/functions/test_memory.py index fd69756d255..2ccb11e032a 100644 --- a/tests/functions/test_memory.py +++ b/tests/functions/test_memory.py @@ -24,111 +24,108 @@ RAND1 = np.random.random(1) RAND2 = np.random.random() -philox_var = np.random.rand(2, SIZE) +# Use different size for Philox case, +# to easily detect mixups +philox_var = np.random.rand(2, SIZE - 1) +philox_initializer = np.array([[philox_var[0] * 5, philox_var[1] * 4]]) test_data = [ # Default initializer does not work # (Functions.Buffer, test_var, {'rate':RAND1}, [[0.0],[0.0]]), pytest.param(Functions.Buffer, test_var[0], {'history':512, 'rate':RAND1, 'initializer':[test_var[0]]}, - [[0.03841128, 0.05005587, 0.04218721, 0.0381362 , 0.02965146, 0.04520592, 0.03062659, 0.0624149 , 0.06744644, 0.02683695], - [0.14519169, 0.18920736, 0.15946443, 0.1441519 , 0.11208025, 0.17087491, 0.11576615, 0.23592355, 0.25494239, 0.10144161]], id="Buffer"), + # TODO: Why is the first result using rate^2 ? + [test_var[0] * RAND1 * RAND1, test_var[0] * RAND1], id="Buffer"), + + # Tests using Mersenne-Twister as function PRNG pytest.param(Functions.DictionaryMemory, test_var, {'seed': module_seed}, - [[0.5488135039273248, 0.7151893663724195, 0.6027633760716439, 0.5448831829968969, 0.4236547993389047, 0.6458941130666561, 0.4375872112626925, 0.8917730007820798, 0.9636627605010293, 0.3834415188257777], - [0.7917250380826646, 0.5288949197529045, 0.5680445610939323, 0.925596638292661, 0.07103605819788694, 0.08712929970154071, 0.02021839744032572, 0.832619845547938, 0.7781567509498505, 0.8700121482468192 ]], + [test_var[0], test_var[1]], id="DictionaryMemory"), pytest.param(Functions.DictionaryMemory, test_var, {'rate':RAND1, 'seed': module_seed}, - [[0.5488135039273248, 0.7151893663724195, 0.6027633760716439, 0.5448831829968969, 0.4236547993389047, 0.6458941130666561, 0.4375872112626925, 0.8917730007820798, 0.9636627605010293, 0.3834415188257777], - [0.7917250380826646, 0.5288949197529045, 0.5680445610939323, 0.925596638292661, 0.07103605819788694, 0.08712929970154071, 0.02021839744032572, 0.832619845547938, 0.7781567509498505, 0.8700121482468192]], + [test_var[0] * RAND1, test_var[1]], id="DictionaryMemory Rate"), - pytest.param(Functions.DictionaryMemory, test_var, {'initializer':test_initializer, 'rate':RAND1, 'seed': module_seed}, - [[0.5488135039273248, 0.7151893663724195, 0.6027633760716439, 0.5448831829968969, 0.4236547993389047, 0.6458941130666561, 0.4375872112626925, 0.8917730007820798, 0.9636627605010293, 0.3834415188257777], - [0.7917250380826646, 0.5288949197529045, 0.5680445610939323, 0.925596638292661, 0.07103605819788694, 0.08712929970154071, 0.02021839744032572, 0.832619845547938, 0.7781567509498505, 0.8700121482468192]], + pytest.param(Functions.DictionaryMemory, test_var, {'initializer':test_initializer, 'seed': module_seed}, + [test_var[0], test_var[1]], id="DictionaryMemory Initializer"), - pytest.param(Functions.DictionaryMemory, test_var, {'rate':RAND1, 'retrieval_prob':0.5, 'seed': module_seed}, - [[ 0. for i in range(SIZE) ],[ 0. for i in range(SIZE) ]], + pytest.param(Functions.DictionaryMemory, test_var, {'retrieval_prob':0.1, 'seed': module_seed}, + np.zeros_like(test_var), id="DictionaryMemory Low Retrieval"), - pytest.param(Functions.DictionaryMemory, test_var, {'rate':RAND1, 'storage_prob':0.1, 'seed': module_seed}, - [[ 0. for i in range(SIZE) ],[ 0. for i in range(SIZE) ]], + pytest.param(Functions.DictionaryMemory, test_var, {'storage_prob':0.1, 'seed': module_seed}, + np.zeros_like(test_var), id="DictionaryMemory Low Storage"), - pytest.param(Functions.DictionaryMemory, test_var, {'rate':RAND1, 'retrieval_prob':0.9, 'storage_prob':0.9, 'seed': module_seed}, - [[0.5488135039273248, 0.7151893663724195, 0.6027633760716439, 0.5448831829968969, 0.4236547993389047, 0.6458941130666561, 0.4375872112626925, 0.8917730007820798, 0.9636627605010293, 0.3834415188257777], - [0.7917250380826646, 0.5288949197529045, 0.5680445610939323, 0.925596638292661, 0.07103605819788694, 0.08712929970154071, 0.02021839744032572, 0.832619845547938, 0.7781567509498505, 0.8700121482468192]], + pytest.param(Functions.DictionaryMemory, test_var, {'retrieval_prob':0.9, 'storage_prob':0.9, 'seed': module_seed}, + [test_var[0], test_var[1]], id="DictionaryMemory High Storage/Retrieve"), -# Disable noise tests for now as they trigger failure in DictionaryMemory lookup -# (Functions.DictionaryMemory, test_var, {'rate':RAND1, 'noise':RAND2}, [[ -# 0.79172504, 0.52889492, 0.56804456, 0.92559664, 0.07103606, 0.0871293 , 0.0202184 , 0.83261985, 0.77815675, 0.87001215 ],[ -# 1.3230471933615413, 1.4894230558066361, 1.3769970655058605, 1.3191168724311135, 1.1978884887731214, 1.4201278025008728, 1.2118209006969092, 1.6660066902162964, 1.737896449935246, 1.1576752082599944 -#]]), -# (Functions.DictionaryMemory, test_var, {'rate':RAND1, 'noise':[RAND2], 'retrieval_prob':0.5}, -# [[ 0. for i in range(SIZE) ],[ 0. for i in range(SIZE) ]]), -# (Functions.DictionaryMemory, test_var, {'rate':RAND1, 'noise':RAND2, 'storage_prob':0.5}, -# [[ 0. for i in range(SIZE) ],[ 0. for i in range(SIZE) ]]), -# (Functions.DictionaryMemory, test_var, {'initializer':test_initializer, 'rate':RAND1, 'noise':RAND2}, [[ -# 0.79172504, 0.52889492, 0.56804456, 0.92559664, 0.07103606, 0.0871293 , 0.0202184 , 0.83261985, 0.77815675, 0.87001215 ],[ -# 1.3230471933615413, 1.4894230558066361, 1.3769970655058605, 1.3191168724311135, 1.1978884887731214, 1.4201278025008728, 1.2118209006969092, 1.6660066902162964, 1.737896449935246, 1.1576752082599944 -#]]), - pytest.param(Functions.ContentAddressableMemory, test_var, {'rate':RAND1, 'retrieval_prob':0.5, 'seed': module_seed}, - [[ 0. for i in range(SIZE) ],[ 0. for i in range(SIZE) ]], + pytest.param(Functions.DictionaryMemory, test_var, {'noise':RAND2}, + [test_var[0] + RAND2, test_var[1]], + id="DictionaryMemory NoiseScalar"), + pytest.param(Functions.DictionaryMemory, test_var, {'noise':RAND2, 'rate':RAND1}, + [test_var[0] * RAND1 + RAND2, test_var[1]], + id="DictionaryMemory Rate NoiseScalar"), + pytest.param(Functions.DictionaryMemory, test_var, {'noise':[RAND2]}, + [test_var[0] + RAND2, test_var[1]], + id="DictionaryMemory NoiseVec1"), + pytest.param(Functions.DictionaryMemory, test_var, {'noise':test_var / 2}, + [test_var[0] + test_var[0] / 2, test_var[1]], + id="DictionaryMemory NoiseVecN"), + + # ContentAddressableMemory + pytest.param(Functions.ContentAddressableMemory, test_var, {'rate':RAND1, 'retrieval_prob':0.1, 'seed': module_seed}, + np.zeros_like(test_var), id="ContentAddressableMemory Low Retrieval"), pytest.param(Functions.ContentAddressableMemory, test_var, {'rate':RAND1, 'storage_prob':0.1, 'seed': module_seed}, - [[ 0. for i in range(SIZE) ],[ 0. for i in range(SIZE) ]], + np.zeros_like(test_var), id="ContentAddressableMemory Low Storage"), pytest.param(Functions.ContentAddressableMemory, test_var, {'rate':RAND1, 'retrieval_prob':0.9, 'storage_prob':0.9, 'seed': module_seed}, - [[0.5488135039273248, 0.7151893663724195, 0.6027633760716439, 0.5448831829968969, 0.4236547993389047, 0.6458941130666561, 0.4375872112626925, 0.8917730007820798, 0.9636627605010293, 0.3834415188257777], - [0.7917250380826646, 0.5288949197529045, 0.5680445610939323, 0.925596638292661, 0.07103605819788694, 0.08712929970154071, 0.02021839744032572, 0.832619845547938, 0.7781567509498505, 0.8700121482468192]], + [test_var[0], test_var[1]], id="ContentAddressableMemory High Storage/Retrieval"), pytest.param(Functions.ContentAddressableMemory, test_var, {'initializer':test_initializer, 'rate':RAND1, 'seed': module_seed}, - [[0.5488135039273248, 0.7151893663724195, 0.6027633760716439, 0.5448831829968969, 0.4236547993389047, 0.6458941130666561, 0.4375872112626925, 0.8917730007820798, 0.9636627605010293, 0.3834415188257777], - [0.7917250380826646, 0.5288949197529045, 0.5680445610939323, 0.925596638292661, 0.07103605819788694, 0.08712929970154071, 0.02021839744032572, 0.832619845547938, 0.7781567509498505, 0.8700121482468192]], + [test_var[0], test_var[1]], id="ContentAddressableMemory Initializer"), + + # Tests using philox var pytest.param(Functions.DictionaryMemory, philox_var, {'seed': module_seed}, - [[0.45615033221654855, 0.5684339488686485, 0.018789800436355142, 0.6176354970758771, 0.6120957227224214, 0.6169339968747569, 0.9437480785146242, 0.6818202991034834, 0.359507900573786, 0.43703195379934145], - [0.6976311959272649, 0.06022547162926983, 0.6667667154456677, 0.6706378696181594, 0.2103825610738409, 0.1289262976548533, 0.31542835092418386, 0.3637107709426226, 0.5701967704178796, 0.43860151346232035]], + [philox_var[0], philox_var[1]], id="DictionaryMemory Philox"), pytest.param(Functions.DictionaryMemory, philox_var, {'rate':RAND1, 'seed': module_seed}, - [[0.45615033221654855, 0.5684339488686485, 0.018789800436355142, 0.6176354970758771, 0.6120957227224214, 0.6169339968747569, 0.9437480785146242, 0.6818202991034834, 0.359507900573786, 0.43703195379934145], - [0.6976311959272649, 0.06022547162926983, 0.6667667154456677, 0.6706378696181594, 0.2103825610738409, 0.1289262976548533, 0.31542835092418386, 0.3637107709426226, 0.5701967704178796, 0.43860151346232035]], + [philox_var[0] * RAND1, philox_var[1]], id="DictionaryMemory Rate Philox"), - pytest.param(Functions.DictionaryMemory, philox_var, {'initializer':test_initializer, 'rate':RAND1, 'seed': module_seed}, - [[0.45615033221654855, 0.5684339488686485, 0.018789800436355142, 0.6176354970758771, 0.6120957227224214, 0.6169339968747569, 0.9437480785146242, 0.6818202991034834, 0.359507900573786, 0.43703195379934145], - [0.6976311959272649, 0.06022547162926983, 0.6667667154456677, 0.6706378696181594, 0.2103825610738409, 0.1289262976548533, 0.31542835092418386, 0.3637107709426226, 0.5701967704178796, 0.43860151346232035]], + pytest.param(Functions.DictionaryMemory, philox_var, {'initializer':philox_initializer, 'seed': module_seed}, + [philox_var[0], philox_var[1]], id="DictionaryMemory Initializer Philox"), - pytest.param(Functions.DictionaryMemory, philox_var, {'rate':RAND1, 'retrieval_prob':0.01, 'seed': module_seed}, - [[ 0. for i in range(SIZE) ],[ 0. for i in range(SIZE) ]], + pytest.param(Functions.DictionaryMemory, philox_var, {'retrieval_prob':0.01, 'seed': module_seed}, + np.zeros_like(philox_var), id="DictionaryMemory Low Retrieval Philox"), - pytest.param(Functions.DictionaryMemory, philox_var, {'rate':RAND1, 'storage_prob':0.01, 'seed': module_seed}, - [[ 0. for i in range(SIZE) ],[ 0. for i in range(SIZE) ]], + pytest.param(Functions.DictionaryMemory, philox_var, {'storage_prob':0.01, 'seed': module_seed}, + np.zeros_like(philox_var), id="DictionaryMemory Low Storage Philox"), - pytest.param(Functions.DictionaryMemory, philox_var, {'rate':RAND1, 'retrieval_prob':0.95, 'storage_prob':0.95, 'seed': module_seed}, - [[0.45615033221654855, 0.5684339488686485, 0.018789800436355142, 0.6176354970758771, 0.6120957227224214, 0.6169339968747569, 0.9437480785146242, 0.6818202991034834, 0.359507900573786, 0.43703195379934145], - [0.6976311959272649, 0.06022547162926983, 0.6667667154456677, 0.6706378696181594, 0.2103825610738409, 0.1289262976548533, 0.31542835092418386, 0.3637107709426226, 0.5701967704178796, 0.43860151346232035]], + pytest.param(Functions.DictionaryMemory, philox_var, {'retrieval_prob':0.98, 'storage_prob':0.98, 'seed': module_seed}, + [philox_var[0], philox_var[1]], id="DictionaryMemory High Storage/Retrieve Philox"), -# Disable noise tests for now as they trigger failure in DictionaryMemory lookup -# (Functions.DictionaryMemory, philox_var, {'rate':RAND1, 'noise':RAND2}, [[ -# 0.79172504, 0.52889492, 0.56804456, 0.92559664, 0.07103606, 0.0871293 , 0.0202184 , 0.83261985, 0.77815675, 0.87001215 ],[ -# 1.3230471933615413, 1.4894230558066361, 1.3769970655058605, 1.3191168724311135, 1.1978884887731214, 1.4201278025008728, 1.2118209006969092, 1.6660066902162964, 1.737896449935246, 1.1576752082599944 -#]]), -# (Functions.DictionaryMemory, philox_var, {'rate':RAND1, 'noise':[RAND2], 'retrieval_prob':0.5}, -# [[ 0. for i in range(SIZE) ],[ 0. for i in range(SIZE) ]]), -# (Functions.DictionaryMemory, philox_var, {'rate':RAND1, 'noise':RAND2, 'storage_prob':0.5}, -# [[ 0. for i in range(SIZE) ],[ 0. for i in range(SIZE) ]]), -# (Functions.DictionaryMemory, philox_var, {'initializer':test_initializer, 'rate':RAND1, 'noise':RAND2}, [[ -# 0.79172504, 0.52889492, 0.56804456, 0.92559664, 0.07103606, 0.0871293 , 0.0202184 , 0.83261985, 0.77815675, 0.87001215 ],[ -# 1.3230471933615413, 1.4894230558066361, 1.3769970655058605, 1.3191168724311135, 1.1978884887731214, 1.4201278025008728, 1.2118209006969092, 1.6660066902162964, 1.737896449935246, 1.1576752082599944 -#]]), + pytest.param(Functions.DictionaryMemory, philox_var, {'noise':RAND2}, + [philox_var[0] + RAND2, philox_var[1]], + id="DictionaryMemory NoiseScalar Philox"), + pytest.param(Functions.DictionaryMemory, philox_var, {'noise':RAND2, 'rate':RAND1}, + [philox_var[0] * RAND1 + RAND2, philox_var[1]], + id="DictionaryMemory Rate NoiseScalar Philox"), + pytest.param(Functions.DictionaryMemory, philox_var, {'noise':[RAND2]}, + [philox_var[0] + RAND2, philox_var[1]], + id="DictionaryMemory NoiseVec1 Philox"), + pytest.param(Functions.DictionaryMemory, philox_var, {'noise':philox_var / 2}, + [philox_var[0] + philox_var[0] / 2, philox_var[1]], + id="DictionaryMemory NoiseVecN Philox"), + + # ContentAddressableMemory pytest.param(Functions.ContentAddressableMemory, philox_var, {'rate':RAND1, 'retrieval_prob':0.1, 'seed': module_seed}, - [[ 0. for i in range(SIZE) ],[ 0. for i in range(SIZE) ]], + np.zeros_like(philox_var), id="ContentAddressableMemory Low Retrieval Philox"), pytest.param(Functions.ContentAddressableMemory, philox_var, {'rate':RAND1, 'storage_prob':0.01, 'seed': module_seed}, - [[ 0. for i in range(SIZE) ],[ 0. for i in range(SIZE) ]], + np.zeros_like(philox_var), id="ContentAddressableMemory Low Storage Philox"), - pytest.param(Functions.ContentAddressableMemory, philox_var, {'rate':RAND1, 'retrieval_prob':0.9, 'storage_prob':0.9, 'seed': module_seed}, - [[0.45615033221654855, 0.5684339488686485, 0.018789800436355142, 0.6176354970758771, 0.6120957227224214, 0.6169339968747569, 0.9437480785146242, 0.6818202991034834, 0.359507900573786, 0.43703195379934145], - [0.6976311959272649, 0.06022547162926983, 0.6667667154456677, 0.6706378696181594, 0.2103825610738409, 0.1289262976548533, 0.31542835092418386, 0.3637107709426226, 0.5701967704178796, 0.43860151346232035]], + pytest.param(Functions.ContentAddressableMemory, philox_var, {'rate':RAND1, 'retrieval_prob':0.98, 'storage_prob':0.98, 'seed': module_seed}, + [philox_var[0], philox_var[1]], id="ContentAddressableMemory High Storage/Retrieval Philox"), - pytest.param(Functions.ContentAddressableMemory, philox_var, {'initializer':test_initializer, 'rate':RAND1, 'seed': module_seed}, - [[0.45615033221654855, 0.5684339488686485, 0.018789800436355142, 0.6176354970758771, 0.6120957227224214, 0.6169339968747569, 0.9437480785146242, 0.6818202991034834, 0.359507900573786, 0.43703195379934145], - [0.6976311959272649, 0.06022547162926983, 0.6667667154456677, 0.6706378696181594, 0.2103825610738409, 0.1289262976548533, 0.31542835092418386, 0.3637107709426226, 0.5701967704178796, 0.43860151346232035]], + pytest.param(Functions.ContentAddressableMemory, philox_var, {'initializer':philox_initializer, 'rate':RAND1, 'seed': module_seed}, + [philox_var[0], philox_var[1]], id="ContentAddressableMemory Initializer Philox"), ] @@ -152,9 +149,19 @@ def test_basic(func, variable, params, expected, benchmark, func_mode): EX = pytest.helpers.get_func_execution(f, func_mode, writeback=False) EX(variable) + + # Store value * 4 with a duplicate key + # This insertion should be ignored unless the function allows + # "duplicate_keys" + if len(variable) == 2: + EX([variable[0], variable[1] * 4]) res = benchmark(EX, variable) - np.testing.assert_allclose(res[0], expected[0], rtol=1e-5, atol=1e-8) - np.testing.assert_allclose(res[1], expected[1], rtol=1e-5, atol=1e-8) + + # This still needs to use "allclose" as the key gets manipulated before + # storage in some subtests. The rounding in that calculation might not + # match the one done for expected values above. + np.testing.assert_allclose(res[0], expected[0]) + np.testing.assert_allclose(res[1], expected[1]) #endregion