From f797e187f376c7a45cc70be01a253edef8d01e5e Mon Sep 17 00:00:00 2001 From: howsohazard <143410553+howsohazard@users.noreply.github.com> Date: Tue, 17 Dec 2024 15:58:12 -0500 Subject: [PATCH] 22286: Amlg lang improvements: removes query_weighted_sample, weighted_rand, updates rand, query_sample, sort, reduce, MAJOR (#327) Removes query_weighted_sample and weighted_rand, updates query_sample and rand to handle functionality. Removes access to (target) from reduce and sort opcodes for performance and consistency reasons. Improves documentation and clarifies some opcode use. --- docs/language.js | 45 +- src/Amalgam/Opcodes.cpp | 2 - src/Amalgam/Opcodes.h | 8 +- src/Amalgam/amlg_code/full_test.amlg | 37 +- src/Amalgam/amlg_code/test.amlg | 92 ++- src/Amalgam/entity/EntityQueries.cpp | 98 ++- src/Amalgam/entity/EntityQueryBuilder.h | 21 +- src/Amalgam/entity/EntityQueryCaches.cpp | 87 +-- .../EvaluableNodeTreeFunctions.cpp | 4 +- .../EvaluableNodeTreeManipulation.cpp | 2 - src/Amalgam/interpreter/Interpreter.cpp | 2 - src/Amalgam/interpreter/Interpreter.h | 1 - .../interpreter/InterpreterOpcodesBase.cpp | 410 +++---------- .../InterpreterOpcodesTransformations.cpp | 10 +- src/Amalgam/out.txt | 576 ++++++------------ 15 files changed, 486 insertions(+), 909 deletions(-) diff --git a/docs/language.js b/docs/language.js index fb390c059..2f1f8a1b6 100644 --- a/docs/language.js +++ b/docs/language.js @@ -45,7 +45,7 @@ var data = [ { "parameter" : "if [bool condition1] [code then1] [bool condition2] [code then2] ... [bool conditionN] [code thenN] [code else]", "output" : "*", - "description" : "If the condition1 bool is true, then it will evaluate to the then1 argument. Otherwise condition2 will be checked, repeating for every pair. If there is an odd number of parameters, the last is the final 'else', and will be evaluated as that if all conditions are false.", + "description" : "If the condition1 bool is true, then it will evaluate to the then1 argument. Otherwise condition2 will be checked, repeating for every pair. If there is an odd number of parameters, the last is the final 'else', and will be evaluated as that if all conditions are false. If there is an even number of parameters and none are true, then evaluates to null.", "example" : "(if (null) (print \"nothing\") 0 (print \"nothing\") (print \"hello\") )" }, @@ -506,7 +506,7 @@ var data = [ "parameter" : "weave [* function] list|immediate values1 [list|immediate values2] [list|immediate values3]...", "output" : "list", "new target scope": true, - "description" : "Interleaves the values lists optionally by applying a function. If only values1 is passed in, then it evaluates to values1. If values1 and values2 are passed in, or, if more values are passed in but function is null, it interleaves the two lists out to whichever list is longer, filling in the remainder with null, and if any value is an immediate, then it will repeat the immediate value. If the function is specified and not nulll, it pushes a new target scope onto the stack, so that current_value accesses a list of elements to be woven together from the list, and current_index accesses the list or assoc index, with target representing the original list or assoc. The function should evaluate to a list, and weave will evaluate to a concatenated list of all of the lists that the function evaluated to.", + "description" : "Interleaves the values lists optionally by applying a function. If only values1 is passed in, then it evaluates to values1. If values1 and values2 are passed in, or, if more values are passed in but function is null, it interleaves the two lists out to whichever list is longer, filling in the remainder with null, and if any value is an immediate, then it will repeat the immediate value. If the function is specified and not nulll, it pushes a new target scope onto the stack, so that current_value accesses a list of elements to be woven together from the list, and current_index accesses the list or assoc index, with target representing the resulting list or assoc. The function should evaluate to a list, and weave will evaluate to a concatenated list of all of the lists that the function evaluated to.", "example" : "(print (weave (list 1 3 5) (list 2 4 6)) \"\\n\")\n(print (weave (lambda (list (apply \"min\" (current_value) ) ) (list 1 3 4 5 5 6) (list 2 2 3 4 6 7) )\"\\n\")\n(print (weave (lambda (if (<= (get (current_value) 0) 4) (list (apply \"min\" (current_value 1)) ) (current_value)) ) (list 1 3 4 5 5 6) (list 2 2 3 4 6 7) )\"\\n\")\n(print (weave (null) (list 2 4 6) (null) ) \"\\n\")" }, @@ -515,7 +515,7 @@ var data = [ "output" : "*", "new value" : "conditional", "new target scope": true, - "description" : "For each element in the collection after the first one, it evaluates function with a new target scope on the stack where current_value accesses each of the elements from the collection, current_index accesses the list or assoc index, target accesses the original list or assoc, and previous_result accesses the previously reduced result. If the collection is empty, null is returned. if the collection is of size one, the single element is returned.", + "description" : "For each element in the collection after the first one, it evaluates function with a new scope on the stack where current_value accesses each of the elements from the collection, current_index accesses the list or assoc index and previous_result accesses the previously reduced result. If the collection is empty, null is returned. if the collection is of size one, the single element is returned.", "example" : "(print (reduce (lambda (* (previous_result) (current_value))) (list 1 2 3 4)))" }, @@ -540,7 +540,7 @@ var data = [ "output" : "list", "new value" : "partial", "new target scope": true, - "description" : "Returns a new list containing the list with its elements sorted in increasing order. Numerical values come before strings, and code will be evaluated as the representative strings. If function is specified and not null, it pushes a pair of new target scope onto the stack, so that current_value accesses a list of elements to from the list, and current_index accesses the list or assoc index if it is not already reduced, with target representing the original list or assoc, and evaluates function. The function should return a number, positive if \"(current_value)\" is greater, negative if \"(current_value 1)\" is greater, 0 if equal. If k is specified in addition to function, then it will only return the k smallest values sorted in order, or, if k is negative, it will ignore the negative sign and return the highest k values.", + "description" : "Returns a new list containing the list with its elements sorted in increasing order. Numerical values come before strings, and code will be evaluated as the representative strings. If function is specified and not null, it pushes a pair of new scope onto the stack with (current_value) and (current_value 1) accessesing a pair of elements from the list, and evaluates function. The function should return a number, positive if \"(current_value)\" is greater, negative if \"(current_value 1)\" is greater, 0 if equal. If k is specified in addition to function, then it will only return the k smallest values sorted in order, or, if k is negative, it will ignore the negative sign and return the highest k values.", "example" : "(print (sort (list 4 9 3 5 1)))\n(print (sort (list \"n\" \"b\" \"hello\" 4 1 3.2 (list 1 2 3))))\n(print (sort (list 1 \"1x\" \"10\" 20 \"z2\" \"z10\" \"z100\")))\n(print (sort (lambda (- (current_value) (current_value 1))) (list 4 9 3 5 1)))" }, @@ -548,7 +548,7 @@ var data = [ "parameter" : "indices list|assoc a", "output" : "list of string|number", "new value" : "new", - "description" : "Evaluates to the list of strings or numbers that comprise the indices or indexes for the list or associative list. It is guaranteed that the opcodes indices and values (assuming the parameter only_unique_values is not true) will evaluate and return elements in the same order when given the same node.", + "description" : "Evaluates to the list of strings or numbers that comprise the indices for the list or associative list. It is guaranteed that the opcodes indices and values (assuming the parameter only_unique_values is not true) will evaluate and return elements in the same order when given the same node.", "example" : "(print (indices (assoc \"a\" 1 \"b\" 2 \"c\" 3 4 \"d\")))\n(print (indices (list \"a\" 1 \"b\" 2 \"c\" 3 4 \"d\")))" }, @@ -645,7 +645,7 @@ var data = [ { "parameter" : "target [number stack_distance]", "output" : "*", - "description" : "Evaluates to the current node that is being iterated over, or the base code of a set or replace that is being created. If a number is specified, it climbs back up the target stack that many levels. Useful for seralizing graph data structures or looking up data during iteration.", + "description" : "Evaluates to the current node that is being iterated over, or the base code of a set or replace that is being created. If stack_distance is specified, it climbs back up the target stack that many levels. Useful for seralizing graph data structures or looking up data during iteration.", "example" : ";prints the list of what has been created before its return value is included in the list\n(list 1 2 3 (print (target)) 4)\n (let (assoc moveref (list 0 (list 7 8) (get (target 0) 1) ) )\n (assign (assoc moveref (set moveref 1 1)))\n (print moveref)\n)" }, @@ -653,21 +653,21 @@ var data = [ "parameter" : "current_index [number stack_distance]", "output" : "*", "new value" : "new", - "description" : "Like target, but evaluates to the index of the current node being iterated on within target.", + "description" : "Evaluates to the index of the current node being iterated on within the current target. If stack_distance is specified, it climbs back up the target stack that many levels.", "example" : "(list 1 2 3 (print (current_index)) 4)" }, { "parameter" : "current_value [number stack_distance]", "output" : "*", - "description" : "Like target, but evaluates to the current node being iterated on within target.", + "description" : "Evaluates to the current node being iterated on within the current target. If stack_distance is specified, it climbs back up the target stack that many levels.", "example" : "(list 1 2 3 (print (current_value)) 4)" }, { "parameter" : "previous_result [number stack_distance] [bool copy]", "output" : "*", - "description" : "Like target, but evaluates to the resulting node of the previous iteration for applicable opcodes. If copy is true, then a copy of the resulting node of the previous iteration is returned, otherwise the result of the previous iteration is returned directly and consumed.", + "description" : "Evaluates to the resulting node of the previous iteration for applicable opcodes. If stack_distance is specified, it climbs back up the target stack that many levels. If copy is true, then a copy of the resulting node of the previous iteration is returned, otherwise the result of the previous iteration is returned directly and consumed.", "example" : "(while (< (target_index) 3) (print (previous_result)) (target_index))" }, @@ -799,26 +799,19 @@ var data = [ }, { - "parameter" : "rand [list|number range] [number number_to_generate] [bool unique]", + "parameter" : "rand [list|assoc|number range] [number number_to_generate] [bool unique]", "output" : "*", "new value" : "conditional, new if range is not a list", - "description" : "With no parameters, evaluates to a random number between 0.0 and 1.0. Each entity has its own random stream, and if called from a sandbox, then it uses a new stream without interrupting the stream of the calling entity. If the parameter is a list, it will uniformly randomly choose and evaluate to one element of the list. If number, it will evaluate to a value greater than or equal to zero and less than the number specified. If number_to_generate is specified, it will generate a list of multiple values (even if number_to_generate is 1). If unique is true (it defaults to false), then it will only return unique values, the same as selecting from the list or assoc without replacement.", + "description" : "Generates random values based on its parameters. The random values are drawn from a random stream specific to each execution flow for each entity. With no range, evaluates to a random number between 0.0 and 1.0. If range is a list, it will uniformly randomly choose and evaluate to one element of the list. If range is a number, it will evaluate to a value greater than or equal to zero and less than the number specified. If range is an assoc, then it will randomly evaluate to one of the keys using the values as the weights for the probabilities. If number_to_generate is specified, it will generate a list of multiple values (even if number_to_generate is 1). If unique is true (it defaults to false), then it will only return unique values, the same as selecting from the list or assoc without replacement. Note that if unique only applies to list and assoc ranges. If unique is true and there are not enough values in a list or assoc, it will only generate the number of elements in range.", "example" : "(print (rand))\n(print (rand 50))\n(print (rand (list 1 2 4 5 7)))\n(print (rand (range 0 10) 10 (true)) \"\\n\")" }, - { - "parameter" : "weighted_rand [list of lists|assoc weighted_values] [number number_to_generate] [bool unique]", - "output" : "*", - "description" : "Each entity has its own random stream, and if called from a sandbox, then it uses a new stream without interrupting the stream of the calling entity. If the parameter is a list, it will uniformly randomly choose and evaluate to one element of the list. If an assoc, then it will randomly evaluate to one of the keys using the values as the weights for the probabilities. Nulls and negative numbers are treated as zero. Infinities are normalized as to only select from infinities in the list. If all values are 0, then they are normalized to having the same weight. If a list of lists, it will use the first list as a list of values and the second list as a list of weights and otherwise work like it would for an assoc. If number_to_generate is specified, it will generate a list of multiple values (even if number_to_generate is 1). If unique is true (it defaults to false), then it will only return unique values, the same as selecting from the list or assoc without replacement.", - "example" : "(print (rand (list (list 1 2 4 5 7) (list 0.2 0.2 0.1 0.1 0.4))))\n(print (rand (assoc \"a\" 1 \"b\" 3))\n(print (rand (assoc \"a\" .25 \"b\" .75)) \"\\n\")\n(print (rand (assoc \"a\" .25 \"b\" .75) 4) \"\\n\")\n(print (rand (range 0 10) 10 (true)) \"\\n\")" - }, - { "parameter" : "get_rand_seed", "output" : "string", "permissions" : "", "new value" : "new", - "description" : "Evaluates to a string representing the current state of the random number generator used for the rand command for the entity specified by id.", + "description" : "Evaluates to a string representing the current state of the random number generator.", "example" : "(print (get_rand_seed) \"\\n\")" }, @@ -1410,19 +1403,11 @@ var data = [ }, { - "parameter" : "query_sample number num_to_select [number random_seed]", - "output" : "query", - "new value" : "new", - "description" : "When used as a query argument, selects a random sample of num_to_select entities sorted by entity_id with replacement. If random_seed is specified, then it will select num_to_select entities randomly from the list based on the random seed. If random_seed is not specified then the subsequent calls will return the same sample of entities.", - "example" : "(contained_entities \"TestEntity\" (list\n (query_sample 4 (rand))\n))" - }, - - { - "parameter" : "query_weighted_sample string weight_label_name number num_to_select [number random_seed]", + "parameter" : "query_sample number num_to_select [string weight_label_name] [number random_seed]", "output" : "query", "new value" : "new", - "description" : "When used as a query argument, selects a random sample of num_to_select entities sorted by entity_id with replacement. It will use weight_label_name as the feature containing the weights for the sampling, which will be normalized prior to sampling. Non-numbers and negative infinite values will be ignored, and if there are any infinite values, those will be selected from uniformly. If random_seed is specified, then it will select num_to_select entities randomly from the list based on the random seed. If random_seed is not specified then the subsequent calls will return the same sample of entities.", - "example" : "(contained_entities \"TestEntity\" (list\n (query_weighted_sample \"weight\" 4 (rand))\n))" + "description" : "When used as a query argument, selects a random sample of num_to_select entities sorted by entity_id with replacement. If weight_label_name is specified and not null, it will use weight_label_name as the feature containing the weights for the sampling, which will be normalized prior to sampling. Non-numbers and negative infinite values for weights will be ignored, and if there are any infinite values, those will be selected from uniformly. If random_seed is specified, then it will select num_to_select entities randomly from the list based on the random seed. If random_seed is not specified then the subsequent calls will return the same sample of entities.", + "example" : "(contained_entities \"TestEntity\" (list\n (query_sample 4 (rand))\n))\n(contained_entities \"TestEntity\" (list\n (query_sample 4 \"weight\" (rand))\n))" }, { diff --git a/src/Amalgam/Opcodes.cpp b/src/Amalgam/Opcodes.cpp index 9b96504ff..d22cb1967 100644 --- a/src/Amalgam/Opcodes.cpp +++ b/src/Amalgam/Opcodes.cpp @@ -69,7 +69,6 @@ void StringInternPool::InitializeStaticStrings() //simulation and operations EmplaceNodeTypeString(ENT_RAND, "rand"); - EmplaceNodeTypeString(ENT_WEIGHTED_RAND, "weighted_rand"); EmplaceNodeTypeString(ENT_GET_RAND_SEED, "get_rand_seed"); EmplaceNodeTypeString(ENT_SET_RAND_SEED, "set_rand_seed"); EmplaceNodeTypeString(ENT_SYSTEM_TIME, "system_time"); @@ -257,7 +256,6 @@ void StringInternPool::InitializeStaticStrings() EmplaceNodeTypeString(ENT_COMPUTE_ON_CONTAINED_ENTITIES, "compute_on_contained_entities"); EmplaceNodeTypeString(ENT_QUERY_SELECT, "query_select"); EmplaceNodeTypeString(ENT_QUERY_SAMPLE, "query_sample"); - EmplaceNodeTypeString(ENT_QUERY_WEIGHTED_SAMPLE, "query_weighted_sample"); EmplaceNodeTypeString(ENT_QUERY_IN_ENTITY_LIST, "query_in_entity_list"); EmplaceNodeTypeString(ENT_QUERY_NOT_IN_ENTITY_LIST, "query_not_in_entity_list"); EmplaceNodeTypeString(ENT_QUERY_EXISTS, "query_exists"); diff --git a/src/Amalgam/Opcodes.h b/src/Amalgam/Opcodes.h index 8120c9e7a..18b8bf899 100644 --- a/src/Amalgam/Opcodes.h +++ b/src/Amalgam/Opcodes.h @@ -48,7 +48,6 @@ enum EvaluableNodeType : uint8_t //simulation and operations ENT_RAND, - ENT_WEIGHTED_RAND, ENT_GET_RAND_SEED, ENT_SET_RAND_SEED, ENT_SYSTEM_TIME, @@ -238,7 +237,6 @@ enum EvaluableNodeType : uint8_t ENT_COMPUTE_ON_CONTAINED_ENTITIES, ENT_QUERY_SELECT, ENT_QUERY_SAMPLE, - ENT_QUERY_WEIGHTED_SAMPLE, ENT_QUERY_IN_ENTITY_LIST, ENT_QUERY_NOT_IN_ENTITY_LIST, ENT_QUERY_EXISTS, @@ -337,7 +335,7 @@ constexpr OrderedChildNodeType GetInstructionOrderedChildNodeType(EvaluableNodeT case ENT_SET_ENTITY_RAND_SEED: case ENT_CREATE_ENTITIES: case ENT_CONTAINED_ENTITIES: case ENT_COMPUTE_ON_CONTAINED_ENTITIES: - case ENT_QUERY_SELECT: case ENT_QUERY_SAMPLE: case ENT_QUERY_WEIGHTED_SAMPLE: + case ENT_QUERY_SELECT: case ENT_QUERY_SAMPLE: case ENT_QUERY_IN_ENTITY_LIST: case ENT_QUERY_NOT_IN_ENTITY_LIST: case ENT_QUERY_EXISTS: case ENT_QUERY_NOT_EXISTS: case ENT_QUERY_EQUALS: case ENT_QUERY_NOT_EQUALS: @@ -375,7 +373,7 @@ constexpr OrderedChildNodeType GetInstructionOrderedChildNodeType(EvaluableNodeT case ENT_GET: case ENT_TARGET: case ENT_CURRENT_INDEX: case ENT_CURRENT_VALUE: case ENT_PREVIOUS_RESULT: case ENT_OPCODE_STACK: case ENT_STACK: case ENT_ARGS: - case ENT_RAND: case ENT_WEIGHTED_RAND: case ENT_GET_RAND_SEED: case ENT_SET_RAND_SEED: + case ENT_RAND: case ENT_GET_RAND_SEED: case ENT_SET_RAND_SEED: case ENT_SYSTEM_TIME: case ENT_GET_DIGITS: case ENT_SET_DIGITS: case ENT_FLOOR: case ENT_CEILING: case ENT_ROUND: @@ -482,7 +480,7 @@ constexpr bool DoesEvaluableNodeTypeCreateScope(EvaluableNodeType t) constexpr bool IsEvaluableNodeTypeQuery(EvaluableNodeType t) { return (t == ENT_QUERY_SELECT || t == ENT_QUERY_IN_ENTITY_LIST || t == ENT_QUERY_NOT_IN_ENTITY_LIST - || t == ENT_QUERY_SAMPLE || t == ENT_QUERY_WEIGHTED_SAMPLE || t == ENT_QUERY_EXISTS || t == ENT_QUERY_NOT_EXISTS + || t == ENT_QUERY_SAMPLE || t == ENT_QUERY_EXISTS || t == ENT_QUERY_NOT_EXISTS || t == ENT_QUERY_EQUALS || t == ENT_QUERY_NOT_EQUALS || t == ENT_QUERY_BETWEEN || t == ENT_QUERY_NOT_BETWEEN || t == ENT_QUERY_AMONG || t == ENT_QUERY_NOT_AMONG || t == ENT_QUERY_MAX || t == ENT_QUERY_MIN || t == ENT_QUERY_SUM || t == ENT_QUERY_MODE diff --git a/src/Amalgam/amlg_code/full_test.amlg b/src/Amalgam/amlg_code/full_test.amlg index 739d9fbcb..cc56113e3 100644 --- a/src/Amalgam/amlg_code/full_test.amlg +++ b/src/Amalgam/amlg_code/full_test.amlg @@ -1163,26 +1163,17 @@ (print (rand 50 4) "\n") - (print "--weighted_rand--\n") - (print (weighted_rand (associate "a" .25 "b" .75)) "\n") - (print (weighted_rand (associate "a" .25 "b" .75) 4) "\n") + (print (rand (associate "a" .25 "b" .75)) "\n") + (print (rand (associate "a" .25 "b" .75) 16) "\n") - (print (weighted_rand (list (list "a" "b") (list .25 .75)) ) "\n") - (print (weighted_rand (list (list "a" "b") (list .25 .75)) 4) "\n") - (print (weighted_rand (list (list "a" "b") (list 0 0)) 4 ) "\n" ) - - (print "infinity test c or d: " (weighted_rand (associate "a" .25 "b" .75 "c" .infinity "d" .infinity) 4) "\n") - (print "infinity test c or d: " (weighted_rand (list (list "a" "b" "c" "d") (list .25 .75 .infinity .infinity)) 4) "\n") + (print "infinity test c or d: " (rand (associate "a" .25 "b" .75 "c" .infinity "d" .infinity) 4) "\n") ;these should come out somewhere near the correct proportions - (print (zip (lambda (+ (current_value 1) (current_value))) (weighted_rand (associate "a" .25 "b" .5 "c" .25) 100) 1) "\n") - - ;these should come out somewhere near the correct proportions - (print (zip (lambda (+ (current_value 1) (current_value))) (weighted_rand (list (list "a" "b" "c") (list .25 .5 .25)) 100) 1) "\n") + (print (zip (lambda (+ (current_value 1) (current_value))) (rand (associate "a" .25 "b" .5 "c" .25) 100) 1) "\n") ;these should be weighted toward smaller numbers (print - (weighted_rand + (rand (zip (range 1 10) (map (lambda @@ -2519,38 +2510,38 @@ (print (contained_entities "TestContainerExec" (list - (query_sample 1 (rand) ) + (query_sample 1 (null) (rand) ) ))) (print (contained_entities "TestContainerExec" (list - (query_sample 1 (null) ) + (query_sample 1 (null) (null) ) ))) - (print "--query_weighted_sample--\n") + (print "with weights\n") (print (contained_entities "TestContainerExec" (list - (query_weighted_sample "weight") + (query_sample 1 "weight") ))) (print (contained_entities "TestContainerExec" (list - (query_weighted_sample "weight") + (query_sample 1 "weight") ))) (print (contained_entities "TestContainerExec" (list - (query_weighted_sample "weight" 20 (rand) ) + (query_sample 20 "weight" (rand) ) ))) (print (contained_entities "TestContainerExec" (list - (query_weighted_sample "weight" 20 (null) ) + (query_sample 20 "weight" (null) ) ))) (print (contained_entities "TestContainerExec" (list (query_not_in_entity_list (list "Child1")) - (query_weighted_sample "weight" 10 (rand) ) + (query_sample 10 "weight" (rand) ) ))) (print (contained_entities "TestContainerExec" (list - (query_weighted_sample "weight" 10 (rand) ) + (query_sample 10 "weight" (rand) ) (query_not_in_entity_list (list "Child1")) ))) diff --git a/src/Amalgam/amlg_code/test.amlg b/src/Amalgam/amlg_code/test.amlg index ff99af373..78397870f 100644 --- a/src/Amalgam/amlg_code/test.amlg +++ b/src/Amalgam/amlg_code/test.amlg @@ -1,14 +1,80 @@ (seq - (create_entities "persist_transactions" (list 1 2 3 4)) - (create_entities (list "persist_transactions" "child") (list 5 6 7)) - (create_entities (list "persist_transactions" "child" "doublechild1") (lambda (list ##eight 8 ##nine 9))) - (create_entities (list "persist_transactions" "child" "doublechild3") (list 12 13)) - (store_entity "amlg_code/test_output/persist_transactions.caml" "persist_transactions" (null) (true) {flatten (true) transactional (true)}) - (create_entities (list "persist_transactions" "child" "doublechild2") (list 10 11)) - (destroy_entities (list "persist_transactions" "child" "doublechild3")) - (assign_to_entities (list "persist_transactions" "child" "doublechild1") {eight 88}) - - (load_entity "amlg_code/test_output/persist_transactions.caml" "persist_transactions_copy" (null) (false) {execute_on_load (true) transactional (true) require_version_compatibility (true)}) - (print (difference_entities "persist_transactions_copy" "persist_transactions") "\n") - (destroy_entities "persist_transactions_copy" "persist_transactions") -) \ No newline at end of file + + + (create_entities "TestContainerExec" + (lambda (parallel + ##^a 3 + ##b (contained_entities) + ##c (+ x 1) + ##d (call_entity "Child5" "q" (assoc x x)) + ##!e 12 + ##x 4 + ##y 5 + )) + ) + (create_entities (list "TestContainerExec" "Child1") + (lambda (parallel + ##x 3 + ##y 4 + ##!e 7 + ##weight 0.45 + ##weight_eq 1 + )) + ) + (create_entities (list "TestContainerExec" "Child2") + (lambda (parallel + ##x -1 + ##y -1 + ##weight 0.45 + ##weight_eq 1 + )) + ) + (create_entities (list "TestContainerExec" "Child3") + (lambda (parallel + ##x 100 + ##y 100 + ##weight 0.02 + ##weight_eq 1 + )) + ) + (create_entities (list "TestContainerExec" "Child4") + (lambda (parallel + ##x 100 + ##y 100 + ##radius 400 + ##weight 0.02 + ##weight_eq 1 + )) + ) + (create_entities (list "TestContainerExec" "Child5") + (lambda (parallel + ##p 3 + ##q (+ x (call_container "^a")) + ##bar "crunchy" + ##weight 0.02 + ##weight_eq 1 + )) + ) + (create_entities (list "TestContainerExec" "Child6") + (lambda (parallel + ##x 1 + ##y 2 + ##bar "not crunchy" + ##weight 0.02 + ##weight_eq 1 + )) + ) + (create_entities (list "TestContainerExec" "Child7") + (lambda (parallel + ##x 0 + ##y 10 + ##weight 0.02 + ##weight_eq 1 + )) + ) + +(print (contained_entities "TestContainerExec" (list + (query_sample 1 "weight") + ))) + + ) \ No newline at end of file diff --git a/src/Amalgam/entity/EntityQueries.cpp b/src/Amalgam/entity/EntityQueries.cpp index c896e25c7..c08502755 100644 --- a/src/Amalgam/entity/EntityQueries.cpp +++ b/src/Amalgam/entity/EntityQueries.cpp @@ -19,7 +19,6 @@ bool EntityQueryCondition::DoesEntityMatchCondition(Entity *e) case ENT_QUERY_SELECT: case ENT_QUERY_SAMPLE: - case ENT_QUERY_WEIGHTED_SAMPLE: //it does not fail the condition here - needs to be checked elsewhere return true; @@ -352,75 +351,52 @@ EvaluableNodeReference EntityQueryCondition::GetMatchingEntities(Entity *contain else //just use a random seed random_stream.SetState("12345"); - //select num_to_select entities and save them in the sample vector - for(size_t i = 0; i < num_to_sample; i++) + if(singleLabel == StringInternPool::NOT_A_STRING_ID) { - size_t index_to_swap = randomStream.RandSize(num_entities); - Entity *selected = matching_entities[index_to_swap]; - samples.emplace_back(selected); + //select num_to_select entities and save them in the sample vector + for(size_t i = 0; i < num_to_sample; i++) + { + size_t index_to_swap = randomStream.RandSize(num_entities); + Entity *selected = matching_entities[index_to_swap]; + samples.emplace_back(selected); + } } - - //swap samples vector with the matching_entities - std::swap(matching_entities, samples); - return EvaluableNodeReference::Null(); - } - - case ENT_QUERY_WEIGHTED_SAMPLE: - { - size_t num_entities = matching_entities.size(); - size_t num_to_sample = static_cast(maxToRetrieve); - auto weight_label_id = singleLabel; - - if(num_entities == 0 || num_to_sample == 0) + else //weighted { - matching_entities.clear(); - return EvaluableNodeReference::Null(); - } - - //retrieve weights - std::vector entity_weights; - entity_weights.reserve(num_to_sample); + //retrieve weights + std::vector entity_weights; + entity_weights.reserve(num_to_sample); - //retrieve and accumulate weights - for(size_t i = 0; i < matching_entities.size(); i++) - { - double value; - Entity *e = matching_entities[i]; - if(e != nullptr && e->GetValueAtLabelAsNumber(weight_label_id, value)) + //retrieve and accumulate weights + for(Entity *e : matching_entities) { - if(FastIsNaN(value)) - value = 0.0; + double value; + if(e != nullptr && e->GetValueAtLabelAsNumber(singleLabel, value)) + { + if(FastIsNaN(value)) + value = 0.0; - entity_weights.push_back(value); + entity_weights.push_back(value); + } + else + { + entity_weights.push_back(0.0); + } } - else + + //if just one sample, brute-force it + if(num_to_sample == 1) { - entity_weights.push_back(0.0); + size_t selected_index = WeightedDiscreteRandomSample(entity_weights, random_stream, true); + Entity *selected = matching_entities[selected_index]; + samples.emplace_back(selected); + } + else //build temporary cache and query + { + WeightedDiscreteRandomStreamTransform wdrst(matching_entities, entity_weights, true); + for(size_t i = 0; i < num_to_sample; i++) + samples.emplace_back(wdrst.WeightedDiscreteRand(random_stream)); } - } - - //obtain random stream either from the condition or use a default one - RandomStream random_stream; - if(hasRandomStream) - random_stream = randomStream.CreateOtherStreamViaRand(); - else //just use a random seed - random_stream.SetState("12345"); - - std::vector samples; - samples.reserve(num_to_sample); - - //if just one sample, brute-force it - if(num_to_sample == 1) - { - size_t selected_index = WeightedDiscreteRandomSample(entity_weights, random_stream, true); - Entity *selected = matching_entities[selected_index]; - samples.emplace_back(selected); - } - else //build temporary cache and query - { - WeightedDiscreteRandomStreamTransform wdrst(matching_entities, entity_weights, true); - for(size_t i = 0; i < num_to_sample; i++) - samples.emplace_back(wdrst.WeightedDiscreteRand(random_stream)); } //swap samples vector with the matching_entities diff --git a/src/Amalgam/entity/EntityQueryBuilder.h b/src/Amalgam/entity/EntityQueryBuilder.h index c84a4f50a..b4baf8e0a 100644 --- a/src/Amalgam/entity/EntityQueryBuilder.h +++ b/src/Amalgam/entity/EntityQueryBuilder.h @@ -652,12 +652,12 @@ namespace EntityQueryBuilder { case ENT_QUERY_SELECT: { - cur_condition->maxToRetrieve = (ocn.size() >= 1) ? EvaluableNode::ToNumber(ocn[0], 0.0) : 0; + cur_condition->maxToRetrieve = (ocn.size() > 0) ? EvaluableNode::ToNumber(ocn[0], 0.0) : 0; - cur_condition->hasStartOffset = (ocn.size() >= 2); + cur_condition->hasStartOffset = (ocn.size() > 1); cur_condition->startOffset = cur_condition->hasStartOffset ? static_cast(EvaluableNode::ToNumber(ocn[1], 0.0)) : 0; - cur_condition->hasRandomStream = (ocn.size() >= 3 && !EvaluableNode::IsNull(ocn[2])); + cur_condition->hasRandomStream = (ocn.size() > 2 && !EvaluableNode::IsNull(ocn[2])); if(cur_condition->hasRandomStream) cur_condition->randomStream.SetState(EvaluableNode::ToString(ocn[2])); else @@ -668,23 +668,14 @@ namespace EntityQueryBuilder case ENT_QUERY_SAMPLE: { cur_condition->maxToRetrieve = (ocn.size() > 0) ? EvaluableNode::ToNumber(ocn[0], 0.0) : 1; - cur_condition->hasRandomStream = (ocn.size() > 1 && !EvaluableNode::IsNull(ocn[1])); - if(cur_condition->hasRandomStream) - cur_condition->randomStream.SetState(EvaluableNode::ToString(ocn[1])); - else - cur_condition->randomStream = rs.CreateOtherStreamViaRand(); - break; - } - case ENT_QUERY_WEIGHTED_SAMPLE: - { - cur_condition->singleLabel = (ocn.size() > 0) ? EvaluableNode::ToStringIDIfExists(ocn[0]) : StringInternPool::NOT_A_STRING_ID; - cur_condition->maxToRetrieve = (ocn.size() > 1) ? EvaluableNode::ToNumber(ocn[1], 0.0) : 1; + cur_condition->singleLabel = (ocn.size() > 1) ? EvaluableNode::ToStringIDIfExists(ocn[1]) : StringInternPool::NOT_A_STRING_ID; + cur_condition->hasRandomStream = (ocn.size() > 2 && !EvaluableNode::IsNull(ocn[2])); if(cur_condition->hasRandomStream) cur_condition->randomStream.SetState(EvaluableNode::ToString(ocn[2])); else cur_condition->randomStream = rs.CreateOtherStreamViaRand(); - break; + break; } case ENT_QUERY_IN_ENTITY_LIST: case ENT_QUERY_NOT_IN_ENTITY_LIST: diff --git a/src/Amalgam/entity/EntityQueryCaches.cpp b/src/Amalgam/entity/EntityQueryCaches.cpp index 95434c461..68627a182 100644 --- a/src/Amalgam/entity/EntityQueryCaches.cpp +++ b/src/Amalgam/entity/EntityQueryCaches.cpp @@ -96,7 +96,7 @@ void EntityQueryCaches::EnsureLabelsAreCached(EntityQueryCondition *cond) break; } - case ENT_QUERY_WEIGHTED_SAMPLE: + case ENT_QUERY_SAMPLE: case ENT_QUERY_AMONG: case ENT_QUERY_NOT_AMONG: case ENT_QUERY_MIN: @@ -104,8 +104,11 @@ void EntityQueryCaches::EnsureLabelsAreCached(EntityQueryCondition *cond) case ENT_QUERY_MIN_DIFFERENCE: case ENT_QUERY_MAX_DIFFERENCE: { - if(!DoesHaveLabel(cond->singleLabel)) - labels_to_add.push_back(cond->singleLabel); + if(cond->singleLabel != StringInternPool::NOT_A_STRING_ID) + { + if(!DoesHaveLabel(cond->singleLabel)) + labels_to_add.push_back(cond->singleLabel); + } break; } @@ -894,8 +897,8 @@ void EntityQueryCaches::GetMatchingEntitiesViaSamplingWithReplacement(EntityQuer if(update_matching_entities) matching_entities.insert(eid); - else - entity_indices_sampled.push_back(eid); + + entity_indices_sampled.push_back(eid); } } else //sampling a bunch, better to precompute and use faster method @@ -910,8 +913,8 @@ void EntityQueryCaches::GetMatchingEntitiesViaSamplingWithReplacement(EntityQuer if(update_matching_entities) matching_entities.insert(eid); - else - entity_indices_sampled.push_back(eid); + + entity_indices_sampled.push_back(eid); } } } @@ -1112,48 +1115,50 @@ EvaluableNodeReference EntityQueryCaches::GetMatchingEntitiesFromQueryCaches(Ent case ENT_QUERY_SAMPLE: { - size_t num_entities; - if(is_first) - num_entities = container->GetNumContainedEntities(); - else - num_entities = matching_ents.size(); - - //if matching_ents is empty, there is nothing to select from - if(num_entities == 0) - break; - - size_t num_to_sample = static_cast(cond.maxToRetrieve); - bool update_matching_ents = (!is_last || !return_query_value); - BitArrayIntegerSet &temp = entity_caches->buffers.tempMatchingEntityIndices; - if(update_matching_ents) - temp.clear(); - - for(size_t i = 0; i < num_to_sample; i++) + if(cond.singleLabel != string_intern_pool.NOT_A_STRING_ID) + { + entity_caches->GetMatchingEntitiesViaSamplingWithReplacement(&cond, + matching_ents, indices_with_duplicates, is_first, update_matching_ents); + } + else { - //get a random id out of all valid ones - size_t selected_id; + size_t num_entities; if(is_first) - selected_id = cond.randomStream.RandSize(num_entities); + num_entities = container->GetNumContainedEntities(); else - selected_id = matching_ents.GetNthElement(cond.randomStream.RandSize(num_entities)); + num_entities = matching_ents.size(); - //keep track if necessary - if(!update_matching_ents) - temp.insert(selected_id); - indices_with_duplicates.push_back(selected_id); - } + //if matching_ents is empty, there is nothing to select from + if(num_entities == 0) + break; - if(!update_matching_ents) - matching_ents = temp; + size_t num_to_sample = static_cast(cond.maxToRetrieve); - break; - } + BitArrayIntegerSet &temp = entity_caches->buffers.tempMatchingEntityIndices; + if(update_matching_ents) + temp.clear(); + + for(size_t i = 0; i < num_to_sample; i++) + { + //get a random id out of all valid ones + size_t selected_id; + if(is_first) + selected_id = cond.randomStream.RandSize(num_entities); + else + selected_id = matching_ents.GetNthElement(cond.randomStream.RandSize(num_entities)); + + //keep track if necessary + if(update_matching_ents) + temp.insert(selected_id); + indices_with_duplicates.push_back(selected_id); + } + + if(update_matching_ents) + matching_ents = temp; + } - case ENT_QUERY_WEIGHTED_SAMPLE: - { - entity_caches->GetMatchingEntitiesViaSamplingWithReplacement(&cond, matching_ents, indices_with_duplicates, is_first, !is_last); break; } @@ -1242,7 +1247,7 @@ EvaluableNodeReference EntityQueryCaches::GetMatchingEntitiesFromQueryCaches(Ent const auto entity_index_to_id = [container](size_t entity_index) { return container->GetContainedEntityIdFromIndex(entity_index); }; //if last query condition is query sample, return each sampled entity id which may include duplicates - if(last_query_type == ENT_QUERY_SAMPLE || last_query_type == ENT_QUERY_WEIGHTED_SAMPLE) + if(last_query_type == ENT_QUERY_SAMPLE) { if(immediate_result) return EvaluableNodeReference(static_cast(indices_with_duplicates.size())); diff --git a/src/Amalgam/evaluablenode/EvaluableNodeTreeFunctions.cpp b/src/Amalgam/evaluablenode/EvaluableNodeTreeFunctions.cpp index f1d68b5bc..3e59a5eea 100644 --- a/src/Amalgam/evaluablenode/EvaluableNodeTreeFunctions.cpp +++ b/src/Amalgam/evaluablenode/EvaluableNodeTreeFunctions.cpp @@ -9,8 +9,8 @@ bool CustomEvaluableNodeComparator::operator()(EvaluableNode *a, EvaluableNode *b) { //create context with "a" and "b" variables - interpreter->PushNewConstructionContext(nullptr, targetList, EvaluableNodeImmediateValueWithType(), a); - interpreter->PushNewConstructionContext(nullptr, targetList, EvaluableNodeImmediateValueWithType(), b); + interpreter->PushNewConstructionContext(targetList, nullptr, EvaluableNodeImmediateValueWithType(), a); + interpreter->PushNewConstructionContext(targetList, nullptr, EvaluableNodeImmediateValueWithType(), b); //compare bool retval = (interpreter->InterpretNodeIntoNumberValue(function) > 0); diff --git a/src/Amalgam/evaluablenode/EvaluableNodeTreeManipulation.cpp b/src/Amalgam/evaluablenode/EvaluableNodeTreeManipulation.cpp index d63d4a89f..cba90d316 100644 --- a/src/Amalgam/evaluablenode/EvaluableNodeTreeManipulation.cpp +++ b/src/Amalgam/evaluablenode/EvaluableNodeTreeManipulation.cpp @@ -1940,7 +1940,6 @@ CompactHashMap EvaluableNodeTreeManipulation::evaluab //simulation and operations {ENT_RAND, 0.4}, - {ENT_WEIGHTED_RAND, 0.02}, {ENT_GET_RAND_SEED, 0.02}, {ENT_SET_RAND_SEED, 0.02}, {ENT_SYSTEM_TIME, 0.01}, @@ -2129,7 +2128,6 @@ CompactHashMap EvaluableNodeTreeManipulation::evaluab {ENT_COMPUTE_ON_CONTAINED_ENTITIES, 0.3}, {ENT_QUERY_SELECT, 0.2}, {ENT_QUERY_SAMPLE, 0.2}, - {ENT_QUERY_WEIGHTED_SAMPLE, 0.2}, {ENT_QUERY_IN_ENTITY_LIST, 0.2}, {ENT_QUERY_NOT_IN_ENTITY_LIST, 0.2}, {ENT_QUERY_EXISTS, 0.2}, diff --git a/src/Amalgam/interpreter/Interpreter.cpp b/src/Amalgam/interpreter/Interpreter.cpp index b0e6c4508..d02147498 100644 --- a/src/Amalgam/interpreter/Interpreter.cpp +++ b/src/Amalgam/interpreter/Interpreter.cpp @@ -58,7 +58,6 @@ std::array Interpreter //simulation and operations &Interpreter::InterpretNode_ENT_RAND, // ENT_RAND - &Interpreter::InterpretNode_ENT_WEIGHTED_RAND, // ENT_WEIGHTED_RAND &Interpreter::InterpretNode_ENT_GET_RAND_SEED, // ENT_GET_RAND_SEED &Interpreter::InterpretNode_ENT_SET_RAND_SEED, // ENT_SET_RAND_SEED &Interpreter::InterpretNode_ENT_SYSTEM_TIME, // ENT_SYSTEM_TIME @@ -241,7 +240,6 @@ std::array Interpreter &Interpreter::InterpretNode_ENT_CONTAINED_ENTITIES_and_COMPUTE_ON_CONTAINED_ENTITIES, // ENT_COMPUTE_ON_CONTAINED_ENTITIES &Interpreter::InterpretNode_ENT_QUERY_and_COMPUTE_opcodes, // ENT_QUERY_SELECT &Interpreter::InterpretNode_ENT_QUERY_and_COMPUTE_opcodes, // ENT_QUERY_SAMPLE - &Interpreter::InterpretNode_ENT_QUERY_and_COMPUTE_opcodes, // ENT_QUERY_WEIGHTED_SAMPLE &Interpreter::InterpretNode_ENT_QUERY_and_COMPUTE_opcodes, // ENT_QUERY_IN_ENTITY_LIST &Interpreter::InterpretNode_ENT_QUERY_and_COMPUTE_opcodes, // ENT_QUERY_NOT_IN_ENTITY_LIST &Interpreter::InterpretNode_ENT_QUERY_and_COMPUTE_opcodes, // ENT_QUERY_EXISTS diff --git a/src/Amalgam/interpreter/Interpreter.h b/src/Amalgam/interpreter/Interpreter.h index 51d7c2f29..158bf8f25 100644 --- a/src/Amalgam/interpreter/Interpreter.h +++ b/src/Amalgam/interpreter/Interpreter.h @@ -1184,7 +1184,6 @@ class Interpreter //simulation and operations EvaluableNodeReference InterpretNode_ENT_RAND(EvaluableNode *en, bool immediate_result); - EvaluableNodeReference InterpretNode_ENT_WEIGHTED_RAND(EvaluableNode *en, bool immediate_result); EvaluableNodeReference InterpretNode_ENT_GET_RAND_SEED(EvaluableNode *en, bool immediate_result); EvaluableNodeReference InterpretNode_ENT_SET_RAND_SEED(EvaluableNode *en, bool immediate_result); EvaluableNodeReference InterpretNode_ENT_SYSTEM_TIME(EvaluableNode *en, bool immediate_result); diff --git a/src/Amalgam/interpreter/InterpreterOpcodesBase.cpp b/src/Amalgam/interpreter/InterpreterOpcodesBase.cpp index 5697a89dc..8e4514314 100644 --- a/src/Amalgam/interpreter/InterpreterOpcodesBase.cpp +++ b/src/Amalgam/interpreter/InterpreterOpcodesBase.cpp @@ -1564,157 +1564,6 @@ EvaluableNodeReference Interpreter::InterpretNode_ENT_ARGS(EvaluableNode *en, bo return EvaluableNodeReference::Null(); } -//Generates an EvaluableNode containing a random value based on the random parameter param, using enm and random_stream -// if any part of param is preserved in the return value, then can_free_param will be set to false, otherwise it will be left alone -EvaluableNodeReference GenerateRandomValueBasedOnRandParam(EvaluableNodeReference param, Interpreter *interpreter, - RandomStream &random_stream, bool &can_free_param, bool immediate_result) -{ - if(EvaluableNode::IsNull(param)) - return interpreter->AllocReturn(random_stream.RandFull(), immediate_result); - - auto &ocn = param->GetOrderedChildNodes(); - if(ocn.size() > 0) - { - size_t selection = random_stream.RandSize(ocn.size()); - can_free_param = false; - return EvaluableNodeReference(ocn[selection], param.unique); - } - - if(DoesEvaluableNodeTypeUseNumberData(param->GetType())) - { - double value = random_stream.RandFull() * param->GetNumberValueReference(); - return interpreter->AllocReturn(value, immediate_result); - } - - return EvaluableNodeReference::Null(); -} - -EvaluableNodeReference Interpreter::InterpretNode_ENT_RAND(EvaluableNode *en, bool immediate_result) -{ - auto &ocn = en->GetOrderedChildNodes(); - - if(ocn.size() == 0) - { - double r = randomStream.RandFull(); - return AllocReturn(r, immediate_result); - } - - //get number to generate - bool generate_list = false; - size_t number_to_generate = 1; - if(ocn.size() >= 2) - { - double num_value = InterpretNodeIntoNumberValue(ocn[1]); - if(FastIsNaN(num_value) || num_value < 0) - return EvaluableNodeReference::Null(); - number_to_generate = static_cast(num_value); - generate_list = true; - //because generating a list, can no longer return an immediate - immediate_result = false; - } - //make sure not eating up too much memory - if(ConstrainedAllocatedNodes()) - { - if(performanceConstraints->WouldNewAllocatedNodesExceedConstraint( - evaluableNodeManager->GetNumberOfUsedNodes() + number_to_generate)) - return EvaluableNodeReference::Null(); - } - - //get whether it needs to be unique - bool generate_unique_values = false; - if(ocn.size() >= 3) - generate_unique_values = InterpretNodeIntoBoolValue(ocn[2]); - - //get random param - auto param = InterpretNodeForImmediateUse(ocn[0]); - - if(!generate_list) - { - bool can_free_param = true; - EvaluableNodeReference rand_value = GenerateRandomValueBasedOnRandParam(param, - this, randomStream, can_free_param, immediate_result); - - if(can_free_param) - evaluableNodeManager->FreeNodeTreeIfPossible(param); - else - evaluableNodeManager->FreeNodeIfPossible(param); - return rand_value; - } - - if(generate_unique_values && param != nullptr && param->GetOrderedChildNodes().size() > 0) - { - //clamp to the maximum number that can possibly be generated - size_t num_elements = param->GetOrderedChildNodes().size(); - number_to_generate = std::min(number_to_generate, num_elements); - - //want to generate multiple values, so return a list - //try to reuse param if can so don't need to allocate more memory - EvaluableNodeReference retval; - if(param.unique) - { - retval = param; - } - else - { - retval = EvaluableNodeReference(evaluableNodeManager->AllocNode(ENT_LIST), true); - retval->SetOrderedChildNodes(param->GetOrderedChildNodesReference(), - param->GetNeedCycleCheck(), param->GetIsIdempotent()); - - retval.UpdatePropertiesBasedOnAttachedNode(param, true); - } - - //shuffle ordered child nodes - auto &retval_ocn = retval->GetOrderedChildNodesReference(); - for(size_t i = 0; i < number_to_generate; i++) - { - size_t to_swap_with = randomStream.RandSize(num_elements); - std::swap(retval_ocn[i], retval_ocn[to_swap_with]); - } - - //free unneeded nodes that weren't part of the shuffle - if(param.unique && !param->GetNeedCycleCheck()) - { - for(size_t i = number_to_generate; i < num_elements; i++) - evaluableNodeManager->FreeNodeTree(retval_ocn[i]); - } - - //get rid of unneeded extra nodes - retval->SetOrderedChildNodesSize(number_to_generate); - retval->ReleaseOrderedChildNodesExtraMemory(); - - return retval; - } - - //want to generate multiple values, so return a list - EvaluableNodeReference retval(evaluableNodeManager->AllocNode(ENT_LIST), true); - - //just generate a list of values with replacement; either generate_unique_values was not set or the distribution "always" generates unique values - retval->ReserveOrderedChildNodes(number_to_generate); - - //just get a bunch of random values with replacement - bool can_free_param = true; - for(size_t i = 0; i < number_to_generate; i++) - { - EvaluableNodeReference rand_value = GenerateRandomValueBasedOnRandParam(param, - this, randomStream, can_free_param, immediate_result); - retval->AppendOrderedChildNode(rand_value); - retval.UpdatePropertiesBasedOnAttachedNode(rand_value, i == 0); - } - - if(can_free_param) - { - evaluableNodeManager->FreeNodeTreeIfPossible(param); - } - else - { - //if used the parameters, a parameter might be used more than once - retval->SetNeedCycleCheck(true); - evaluableNodeManager->FreeNodeIfPossible(param); - } - - return retval; -} - //given an assoc of StringID -> value representing the probability weight of each, and a random stream, it randomly selects from the assoc // if it can't find an appropriate probability, it returns an empty string // if normalize is true, then it will accumulate the probability and then normalize @@ -1796,116 +1645,48 @@ static StringInternPool::StringID GetRandomWeightedKey(EvaluableNode::AssocType return StringInternPool::NOT_A_STRING_ID; } -//given a vector of vector of the probability weight of each value as probability_nodes, and a random stream, it randomly selects by probability and returns the index -// if it can't find an appropriate probability, it returns the size of the probabilities list -// if normalize is true, then it will accumulate the probability and then normalize -static size_t GetRandomWeightedValueIndex(std::vector &probability_nodes, RandomStream &rs, bool normalize) -{ - double probability_target = rs.RandFull(); - double accumulated_probability = 0.0; - double total_probability = 1.0; - - if(normalize) - { - total_probability = 0; - for(auto pn : probability_nodes) - total_probability += std::max(0.0, EvaluableNode::ToNumber(pn, 0.0)); - - //if no probabilities, just choose uniformly - if(total_probability <= 0.0) - return static_cast(probability_nodes.size() * probability_target); - - if(total_probability == std::numeric_limits::infinity()) - { - //start over, count infinities - size_t inf_count = 0; - for(auto pn : probability_nodes) - { - if(EvaluableNode::ToNumber(pn, 0.0) == std::numeric_limits::infinity()) - inf_count++; - } - - //get the infinity to use - inf_count = static_cast(inf_count * probability_target); - - //count down until the infinite pair is found - for(size_t index = 0; index < probability_nodes.size(); index++) - { - if(EvaluableNode::ToNumber(probability_nodes[index], 0.0) == std::numeric_limits::infinity()) - { - if(inf_count == 0) - return index; - inf_count--; - } - } - - //shouldn't make it here - return probability_nodes.size(); - } - } - - for(size_t index = 0; index < probability_nodes.size(); index++) - { - accumulated_probability += (EvaluableNode::ToNumber(probability_nodes[index], 0.0) / total_probability); - if(probability_target < accumulated_probability) - return index; - } - - //probability mass didn't add up, just grab the first one with a probability greater than zero - for(size_t index = 0; index < probability_nodes.size(); index++) - { - //make sure don't go past the end of the probability nodes - if(index >= probability_nodes.size()) - break; - - if(EvaluableNode::ToNumber(probability_nodes[index], 0.0) > 0) - return index; - } - - //nothing valid to return - return probability_nodes.size(); -} - //Generates an EvaluableNode containing a random value based on the random parameter param, using enm and random_stream // if any part of param is preserved in the return value, then can_free_param will be set to false, otherwise it will be left alone -static EvaluableNodeReference GenerateWeightedRandomValueBasedOnRandParam(EvaluableNodeReference param, - EvaluableNodeManager *enm, RandomStream &random_stream, bool &can_free_param) +EvaluableNodeReference GenerateRandomValueBasedOnRandParam(EvaluableNodeReference param, Interpreter *interpreter, + RandomStream &random_stream, bool &can_free_param, bool immediate_result) { if(EvaluableNode::IsNull(param)) - return EvaluableNodeReference::Null(); + return interpreter->AllocReturn(random_stream.RandFull(), immediate_result); - auto &ocn = param->GetOrderedChildNodes(); - //need to have a value and probability list - if(ocn.size() >= 2) + if(param->GetNumChildNodes() > 0) { - if(EvaluableNode::IsNull(ocn[0]) || EvaluableNode::IsNull(ocn[1])) - return EvaluableNodeReference::Null(); - - can_free_param = false; - size_t index = GetRandomWeightedValueIndex(ocn[1]->GetOrderedChildNodes(), random_stream, true); - auto &value_ocn = ocn[0]->GetOrderedChildNodes(); - if(index < value_ocn.size()) - return EvaluableNodeReference(value_ocn[index], param.unique); - - return EvaluableNodeReference::Null(); + if(param->IsAssociativeArray()) + { + StringInternPool::StringID id_selected = GetRandomWeightedKey(param->GetMappedChildNodesReference(), + random_stream, true); + return Parser::ParseFromKeyStringId(id_selected, interpreter->evaluableNodeManager); + } + else if(param->IsOrderedArray()) + { + auto &ocn = param->GetOrderedChildNodesReference(); + size_t selection = random_stream.RandSize(ocn.size()); + can_free_param = false; + return EvaluableNodeReference(ocn[selection], param.unique); + } } - - auto &mcn = param->GetMappedChildNodes(); - if(mcn.size() > 0) + else if(DoesEvaluableNodeTypeUseNumberData(param->GetType())) { - StringInternPool::StringID id_selected = GetRandomWeightedKey(mcn, random_stream, true); - return Parser::ParseFromKeyStringId(id_selected, enm); + double value = random_stream.RandFull() * param->GetNumberValueReference(); + return interpreter->AllocReturn(value, immediate_result); } return EvaluableNodeReference::Null(); } -EvaluableNodeReference Interpreter::InterpretNode_ENT_WEIGHTED_RAND(EvaluableNode *en, bool immediate_result) +EvaluableNodeReference Interpreter::InterpretNode_ENT_RAND(EvaluableNode *en, bool immediate_result) { auto &ocn = en->GetOrderedChildNodes(); if(ocn.size() == 0) - return EvaluableNodeReference::Null(); + { + double r = randomStream.RandFull(); + return AllocReturn(r, immediate_result); + } //get number to generate bool generate_list = false; @@ -1933,14 +1714,15 @@ EvaluableNodeReference Interpreter::InterpretNode_ENT_WEIGHTED_RAND(EvaluableNod if(ocn.size() >= 3) generate_unique_values = InterpretNodeIntoBoolValue(ocn[2]); - //get weighted random param + //get random param auto param = InterpretNodeForImmediateUse(ocn[0]); + //if generating a single value if(!generate_list) { bool can_free_param = true; - EvaluableNodeReference rand_value = GenerateWeightedRandomValueBasedOnRandParam(param, - evaluableNodeManager, randomStream, can_free_param); + EvaluableNodeReference rand_value = GenerateRandomValueBasedOnRandParam(param, + this, randomStream, can_free_param, immediate_result); if(can_free_param) evaluableNodeManager->FreeNodeTreeIfPossible(param); @@ -1949,46 +1731,14 @@ EvaluableNodeReference Interpreter::InterpretNode_ENT_WEIGHTED_RAND(EvaluableNod return rand_value; } - if(generate_unique_values) + if(generate_unique_values && !EvaluableNode::IsNull(param) && param->GetNumChildNodes() > 0) { - auto ¶m_ocn = param->GetOrderedChildNodes(); - if(param_ocn.size() > 0) - { - EvaluableNodeReference retval(evaluableNodeManager->AllocNode(ENT_LIST), true); - - if(param_ocn.size() < 2 || EvaluableNode::IsNull(param_ocn[0]) || EvaluableNode::IsNull(param_ocn[1])) - return retval; - - //clamp to the maximum number that can possibly be generated - number_to_generate = std::min(number_to_generate, param_ocn.size()); - retval->ReserveOrderedChildNodes(number_to_generate); - - //make a copy of all of the values and probabilities so they can be removed one at a time - std::vector values(param_ocn[0]->GetOrderedChildNodes()); - std::vector probabilities(param_ocn[1]->GetOrderedChildNodes()); - - for(size_t i = 0; i < number_to_generate; i++) - { - size_t index = GetRandomWeightedValueIndex(probabilities, randomStream, true); - if(index >= values.size()) - break; - - retval->AppendOrderedChildNode(values[index]); - retval.UpdatePropertiesBasedOnAttachedNode(param, i == 0); - - //remove the element so it won't be reselected - values.erase(begin(values) + index); - probabilities.erase(begin(probabilities) + index); - } + //clamp to the maximum number that can possibly be generated + size_t num_elements = (param == nullptr ? 0 : param->GetNumChildNodes()); + number_to_generate = std::min(number_to_generate, num_elements); - evaluableNodeManager->FreeNodeIfPossible(param); - return retval; - } - else if(param->GetMappedChildNodes().size() > 0) + if(param->IsAssociativeArray()) { - //clamp to the maximum number that can possibly be generated - number_to_generate = std::min(number_to_generate, param->GetMappedChildNodesReference().size()); - //want to generate multiple values, so return a list EvaluableNodeReference retval(evaluableNodeManager->AllocNode(ENT_LIST), true); auto &retval_ocn = retval->GetOrderedChildNodesReference(); @@ -2012,70 +1762,78 @@ EvaluableNodeReference Interpreter::InterpretNode_ENT_WEIGHTED_RAND(EvaluableNod return retval; } - return EvaluableNodeReference::Null(); - } - - //just generate a list of values with replacement; either generate_unique_values was not set or the distribution "always" generates unique values - EvaluableNodeReference retval(evaluableNodeManager->AllocNode(ENT_LIST), true); - retval->ReserveOrderedChildNodes(number_to_generate); - - auto ¶m_ocn = param->GetOrderedChildNodes(); - //if generating many values with weighted probabilities, use fast method - if(param_ocn.size() > 0 && (number_to_generate > 10 || (number_to_generate > 3 && param_ocn.size() > 200))) - { - if(param_ocn.size() < 2 || EvaluableNode::IsNull(param_ocn[0]) || EvaluableNode::IsNull(param_ocn[1])) + //want to generate multiple values, so return a list + //try to reuse param if can so don't need to allocate more memory + EvaluableNodeReference retval; + if(param.unique) { - evaluableNodeManager->FreeNodeIfPossible(param); - return retval; + retval = param; } + else + { + retval = EvaluableNodeReference(evaluableNodeManager->AllocNode(ENT_LIST), true); + retval->SetOrderedChildNodes(param->GetOrderedChildNodesReference(), + param->GetNeedCycleCheck(), param->GetIsIdempotent()); - auto &probabilities_ocn = param_ocn[1]->GetOrderedChildNodes(); - std::vector probabilities; - probabilities.reserve(probabilities_ocn.size()); - for(auto pn : probabilities_ocn) - probabilities.push_back(EvaluableNode::ToNumber(pn)); - - auto &values_ocn = param_ocn[0]->GetOrderedChildNodes(); + retval.UpdatePropertiesBasedOnAttachedNode(param, true); + } - WeightedDiscreteRandomStreamTransform wdrst(values_ocn, probabilities, true); + //shuffle ordered child nodes + auto &retval_ocn = retval->GetOrderedChildNodesReference(); for(size_t i = 0; i < number_to_generate; i++) { - EvaluableNode *rand_value = wdrst.WeightedDiscreteRand(randomStream); - retval->AppendOrderedChildNode(rand_value); + size_t to_swap_with = randomStream.RandSize(num_elements); + std::swap(retval_ocn[i], retval_ocn[to_swap_with]); } - retval.unique = param.unique; - retval->SetNeedCycleCheck(true); + //free unneeded nodes that weren't part of the shuffle + if(param.unique && !param->GetNeedCycleCheck()) + { + for(size_t i = number_to_generate; i < num_elements; i++) + evaluableNodeManager->FreeNodeTree(retval_ocn[i]); + } - evaluableNodeManager->FreeNodeIfPossible(param); + //get rid of unneeded extra nodes + retval->SetOrderedChildNodesSize(number_to_generate); + retval->ReleaseOrderedChildNodesExtraMemory(); return retval; } - auto &mcn = param->GetMappedChildNodes(); - //if generating many values with weighted probabilities, use fast method - if(mcn.size() > 0 && (number_to_generate > 10 || (number_to_generate > 3 && mcn.size() > 200))) + //want to generate multiple values, so return a list + EvaluableNodeReference retval(evaluableNodeManager->AllocNode(ENT_LIST), true); + + //just generate a list of values with replacement; either generate_unique_values was not set or the distribution "always" generates unique values + retval->ReserveOrderedChildNodes(number_to_generate); + + bool can_free_param = true; + + //get information to determine which mechanism to use to generate + size_t num_weighted_values = 0; + if(param != nullptr && param->IsAssociativeArray()) + num_weighted_values = param->GetMappedChildNodesReference().size(); + + if(num_weighted_values > 0 + && (number_to_generate > 10 || (number_to_generate > 3 && num_weighted_values > 200))) { + //use fast repeated generation technique WeightedDiscreteRandomStreamTransform wdrst(mcn, false); + EvaluableNode::AssocType, EvaluableNodeAsDouble> wdrst(param->GetMappedChildNodesReference(), false); for(size_t i = 0; i < number_to_generate; i++) { EvaluableNodeReference rand_value(Parser::ParseFromKeyStringId(wdrst.WeightedDiscreteRand(randomStream), evaluableNodeManager)); retval->AppendOrderedChildNode(rand_value); - retval.UpdatePropertiesBasedOnAttachedNode(rand_value); } - - evaluableNodeManager->FreeNodeTreeIfPossible(param); - return retval; } - - //just get a bunch of random values with replacement - bool can_free_param = true; - for(size_t i = 0; i < number_to_generate; i++) + else //perform simple generation { - EvaluableNodeReference rand_value = GenerateWeightedRandomValueBasedOnRandParam(param, evaluableNodeManager, randomStream, can_free_param); - retval->AppendOrderedChildNode(rand_value); - retval.UpdatePropertiesBasedOnAttachedNode(rand_value, i == 0); + for(size_t i = 0; i < number_to_generate; i++) + { + EvaluableNodeReference rand_value = GenerateRandomValueBasedOnRandParam(param, + this, randomStream, can_free_param, immediate_result); + retval->AppendOrderedChildNode(rand_value); + retval.UpdatePropertiesBasedOnAttachedNode(rand_value, i == 0); + } } if(can_free_param) diff --git a/src/Amalgam/interpreter/InterpreterOpcodesTransformations.cpp b/src/Amalgam/interpreter/InterpreterOpcodesTransformations.cpp index 55468204a..ec0c2bce5 100644 --- a/src/Amalgam/interpreter/InterpreterOpcodesTransformations.cpp +++ b/src/Amalgam/interpreter/InterpreterOpcodesTransformations.cpp @@ -768,7 +768,7 @@ EvaluableNodeReference Interpreter::InterpretNode_ENT_REDUCE(EvaluableNode *en, EvaluableNodeReference previous_result = EvaluableNodeReference::Null(); - PushNewConstructionContext(nullptr, list, EvaluableNodeImmediateValueWithType(), nullptr, previous_result); + PushNewConstructionContext(list, nullptr, EvaluableNodeImmediateValueWithType(), nullptr, previous_result); if(list->IsAssociativeArray()) { @@ -779,7 +779,7 @@ EvaluableNodeReference Interpreter::InterpretNode_ENT_REDUCE(EvaluableNode *en, //grab a value if first one if(first_node) { - //can't make any guarantees about the first term because function may retrieve it + //inform that the first result is not unique; if no side effects and unique result, can free all at once previous_result = EvaluableNodeReference(n, false); first_node = false; continue; @@ -794,7 +794,7 @@ EvaluableNodeReference Interpreter::InterpretNode_ENT_REDUCE(EvaluableNode *en, else if(list->GetOrderedChildNodes().size() >= 1) { auto &list_ocn = list->GetOrderedChildNodes(); - //can't make any guarantees about the first term because function may retrieve it + //inform that the first result is not unique; if no side effects and unique result, can free all at once previous_result = EvaluableNodeReference(list_ocn[0], false); //iterate over list @@ -807,7 +807,9 @@ EvaluableNodeReference Interpreter::InterpretNode_ENT_REDUCE(EvaluableNode *en, } } - PopConstructionContextAndGetExecutionSideEffectFlag(); + bool side_effects = PopConstructionContextAndGetExecutionSideEffectFlag(); + if(previous_result.unique && !side_effects) + evaluableNodeManager->FreeNodeTreeIfPossible(list); return previous_result; } diff --git a/src/Amalgam/out.txt b/src/Amalgam/out.txt index a29d04b8c..ab194b760 100644 --- a/src/Amalgam/out.txt +++ b/src/Amalgam/out.txt @@ -156,7 +156,6 @@ hello world: 12 and 2 query_select 0.2 query_sum 0.2 query_value_masses 0.2 - query_weighted_sample 0.2 query_within_generalized_distance 0.2 rand 0.4 range 0.5 @@ -210,7 +209,6 @@ hello world: 12 and 2 unzip 0.25 values 0.5 weave 0.2 - weighted_rand 0.02 while 0.1 xor 0.75 zip 0.35 @@ -230,11 +228,11 @@ hello world: 12 and 2 (print "hello") [(null) (null) .infinity -.infinity] -{b 2 a 1 c ["alpha" "beta" "gamma"]} +{c ["alpha" "beta" "gamma"] a 1 b 2} { - b 2 - a 1 c ["alpha" "beta" "gamma"] + a 1 + b 2 } (apply "6") @@ -651,15 +649,15 @@ a a 1 b 2 c 3 - d 4 + e 5 f 6 } -{d 4 f 6} +{a 1 b 2} { a 1 + b 2 c 3 - d 4 - f 6 + e 5 } { a 1 @@ -702,15 +700,15 @@ c a 1 b 2 c 3 - d 4 + e 5 f 6 } -{d 4 f 6} +{a 1 b 2} { a 1 + b 2 c 3 - d 4 - f 6 + e 5 } { a 1 @@ -1061,7 +1059,7 @@ abcdef [1 3] [9 5] --indices-- -["b" "a" "c" 4] +[4 "c" "a" "b"] [ 0 1 @@ -1073,10 +1071,10 @@ abcdef 7 ] [0 1 2 3] -[3 1 2 0] -[3 1 2 0] +[1 0 3 2] +[1 0 3 2] --values-- -[2 1 3 "d"] +["d" 3 1 2] [ "a" 1 @@ -1097,7 +1095,7 @@ abcdef 4 "d" ] -[1 2 3 "d"] +["d" 3 1 2] [ 1 2 @@ -1249,10 +1247,10 @@ string list assoc [ + 4 "4" - {4 4} [4] - 4 + {4 4} ] --set-- { @@ -1318,7 +1316,7 @@ current_index: 2 8 ] accum_string "abcdef" - argv ["C:\\Users\\ChristopherHazard\\Desktop\\Howso_repos\\amalgam\\src\\Amalgam\\./amlg_code/full_test.amlg"] + argv ["C:\\Users\\Chris Hazard\\Desktop\\Howso_repos\\amalgam\\src\\Amalgam\\./amlg_code/full_test.amlg"] bar (declare {x 6} (+ x 2) @@ -1331,13 +1329,13 @@ current_index: 2 A {B 2} B 2 } - interpreter "C:\\Users\\ChristopherHazard\\Desktop\\Howso_repos\\amalgam\\x64\\MT_Release_EXE\\Amalgam.exe" + interpreter "C:\\Users\\Chris Hazard\\Desktop\\Howso_repos\\amalgam\\x64\\MT_Release_EXE\\Amalgam.exe" raaa 2 rmdir "rmdir /s /q " rmfile "del /s /q " rwww 1 slash "\\" - start_time 1734044389.705283 + start_time 1734362703.305837 www 1 x 12 zz 10 @@ -1364,7 +1362,7 @@ current_index: 2 8 ] accum_string "abcdef" - argv ["C:\\Users\\ChristopherHazard\\Desktop\\Howso_repos\\amalgam\\src\\Amalgam\\./amlg_code/full_test.amlg"] + argv ["C:\\Users\\Chris Hazard\\Desktop\\Howso_repos\\amalgam\\src\\Amalgam\\./amlg_code/full_test.amlg"] bar (declare {x 6} (+ x 2) @@ -1377,13 +1375,13 @@ current_index: 2 A {B 2} B 2 } - interpreter "C:\\Users\\ChristopherHazard\\Desktop\\Howso_repos\\amalgam\\x64\\MT_Release_EXE\\Amalgam.exe" + interpreter "C:\\Users\\Chris Hazard\\Desktop\\Howso_repos\\amalgam\\x64\\MT_Release_EXE\\Amalgam.exe" raaa 2 rmdir "rmdir /s /q " rmfile "del /s /q " rwww 1 slash "\\" - start_time 1734044389.705283 + start_time 1734362703.305837 www 1 x 12 zz 10 @@ -1409,7 +1407,7 @@ current_index: 2 8 ] accum_string "abcdef" - argv ["C:\\Users\\ChristopherHazard\\Desktop\\Howso_repos\\amalgam\\src\\Amalgam\\./amlg_code/full_test.amlg"] + argv ["C:\\Users\\Chris Hazard\\Desktop\\Howso_repos\\amalgam\\src\\Amalgam\\./amlg_code/full_test.amlg"] bar (declare {x 6} (+ x 2) @@ -1422,13 +1420,13 @@ current_index: 2 A {B 2} B 2 } - interpreter "C:\\Users\\ChristopherHazard\\Desktop\\Howso_repos\\amalgam\\x64\\MT_Release_EXE\\Amalgam.exe" + interpreter "C:\\Users\\Chris Hazard\\Desktop\\Howso_repos\\amalgam\\x64\\MT_Release_EXE\\Amalgam.exe" raaa 2 rmdir "rmdir /s /q " rmfile "del /s /q " rwww 1 slash "\\" - start_time 1734044389.705283 + start_time 1734362703.305837 www 1 x 12 zz 10 @@ -1559,32 +1557,39 @@ true [15.147298145412242 2.8707229850232165 1.1842755192409848 26.133999503489054] ---weighted_rand-- a -["b" "b" "b" "b"] - -b -["b" @(get (target 2) 0) "a" @(get (target 2) 2)] - -["b" @(get (target 2) 0) @(get (target 2) 0) "a"] - -infinity test c or d: ["c" "c" "d" "c"] - -infinity test c or d: ["c" "d" @(get (target 2) 1) @(get (target 2) 0)] +[ + "a" + "b" + "b" + "b" + "a" + "b" + "b" + "a" + "b" + "b" + "b" + "b" + "b" + "b" + "b" + "b" +] -{a 34 b 43 c 23} +infinity test c or d: ["d" "d" "c" "c"] -{a 30 b 50 c 20} +{a 34 b 50 c 16} -[1 10 3] +[1 3 2] --get_rand_seed-- -0RÊíõÿ'`¦!šc”lÿ +ü—õ暧I`¦!šc”lÿ --set_rand_seed-- -0.14733430167075878 -0.7960497320657874 -0.14733430167075878 -0.7960497320657874 +0.3458744430299684 +0.5141404672826732 +0.3458744430299684 +0.5141404672826732 --true-- (true) @@ -1672,17 +1677,17 @@ string {a 3 b 4} {c "c"} ] -21: [{"b":4,"a":3},{"c":"c","d":null}] +21: [{"a":3,"b":4},{"d":null,"c":"c"}] 22: [{"a":3,"b":4},{"c":"c","d":null}] -23: e: +23: d: 4 +c: 3 +e: - a - b - - .inf -b: 2 a: 1 -c: 3 -d: 4 +b: 2 24: a: 1 b: 2 @@ -1695,7 +1700,7 @@ e: - .inf 25: {a 1} -current date-time in epoch: 2024-12-12-17.59.49.7654750 +current date-time in epoch: 2024-12-16-10.25.03.8678820 2020-06-07 00:22:59 1391230800 1391230800 @@ -1756,7 +1761,7 @@ domingo, jun. 07, 2020 ) } { - labelA #labelQ #labelA + labelA #labelA #labelQ (lambda #labelB (true) ) @@ -1770,7 +1775,7 @@ domingo, jun. 07, 2020 ) } { - labelA #labelQ #labelA + labelA #labelA #labelQ (lambda #labelB (true) ) @@ -1975,33 +1980,35 @@ decrypted: hello --mutate-- [ 1 - {} - 3 - 4 + (get) + "a" + #a 2.21577725583372 5 - 6 + (move_entities) 7 - 8 - (sin) - (call_container) + #b 8 + 9 + 10 11 12 - (target) - 14 - (associate a (append) "b" (reduce)) + 13 + (=) + (associate + (declare) + 1 + #b "b" + 2 + ) ] [ - 1 - 2 (+) + 2 + 3 4 (associate "alpha" 5 "beta" 6) (associate - (-) - (associate - "count" - [7 8 9] - ) + "nest" + (associate (-) []) "end" [10 11 (+)] ) @@ -2440,7 +2447,7 @@ decrypted: hello --mix-- [ 1 - 4 + 2 5.5 7.5 9.5 @@ -2454,22 +2461,20 @@ decrypted: hello ;comment 3 ;comment 4 1 - 4 + 3.5 5.5 - 7.5 + 8 9.5 11.5 - 13.5 + 13 ] [ 1 - 5 - 3 - 2 + 2.5 (associate "a" 3 "b" 4) (lambda (if - true + false 1 (parallel (get_entity_comments) @@ -2482,12 +2487,12 @@ decrypted: hello ) ) ) - [5 6] ] [ 1 + 5 2.5 - (associate "b" 4) + (associate "a" 3 "b" 4) (lambda (if true @@ -2496,17 +2501,15 @@ decrypted: hello (get_entity_comments) (lambda (print - [9] + [2 9] ) ) - 1 ) ) ) - [5 6] ] [ - 2 + (true) 3.5 5.5 7.5 @@ -2515,25 +2518,22 @@ decrypted: hello 13.5 ] [ - (true) - 2 4 3 6 5 8 - 10 - 9 - 12 + 7 11 + 13 ] -1 4 +1 2.5 2.5 -abceomxyz -abcmxyz -abcmxyz +abcdexyz +abcexyz +abcdoxyz --mix_labels-- [ 1 @@ -2797,58 +2797,57 @@ flatten restore with parallel ) --mutate_entity-- [ - (>) - (first) + 1 + 2.0629881708090316 3 - 0.5226269445601921 + "b" 5 - [] + b 7 8 - (query_not_equals) + 9 10 - (map) - [] + (remove) + (max) 13 - (ceil) - (associate "a" (contains_value) "b" (current_index)) + 14 + (get) ] [ - (floor) - 2 - 7.444375373567071 - 4 - (get_value) + (accum) + -0.23190034392242342 + ##a 2.759376820962708 + (rewrite) + 5 6 - (query_min) + (size) 8 - (lambda) (filter) + a 11 12 - 13 - 119.55976171274764 - (associate "a" (query_less_or_equal_to) "b" 2) + {} + (filter) + (associate) ] [ - 1 - 2 (+) - 4 + 2 + (-) (-) + 5 6 - 7 + (+) + 8 (-) - (*) (+) (+) 12 - (+) - (-) - (associate "a" 1 (+) (+)) - (*) + 13 + 14 + (associate "a" 1 (*) 2) ] --commonality_entities-- @@ -2861,10 +2860,10 @@ MergeEntityChild2 (associate "p" 3 "q" 4) MergeEntityChild1 (associate "x" 3 "y" 4) -_1651806471 -(associate "e" 3 "f" 4) _3130331116 (associate "E" 3 "F" 4) +_1651806471 +(associate "e" 3 "f" 4) --union_entities-- (associate "b" 4 "a" 3 "c" 3) MergeEntityChild2 @@ -2882,26 +2881,26 @@ MergeEntityChild2 ) MergeEntityChild1 (associate "x" 3 "y" 4 "z" 5) -_1651806471 +_3130331116 (associate - "e" + "E" 3 - "f" + "F" 4 - "g" + "G" 5 - "h" + "H" 6 ) -_3130331116 +_1651806471 (associate - "E" + "e" 3 - "F" + "f" 4 - "G" + "g" 5 - "H" + "h" 6 ) (parallel @@ -3258,14 +3257,8 @@ _3532185687 [] (lambda { - E (get - (current_value 1) - "E" - ) - F (get - (current_value 1) - "F" - ) + E 3 + F 4 G 5 H 6 } @@ -3290,16 +3283,7 @@ _3532185687 _ [] (lambda - { - e (get - (current_value 1) - "e" - ) - f (get - (current_value 1) - "f" - ) - } + {e 3 f 4} ) ) ) @@ -3331,89 +3315,7 @@ contained_entities new_entity: ["DiffEntityChild1" "OnlyIn2" "_3626604918" "_382 difference between DiffEntity2 and new_entity: (declare {_ (null) new_entity (null)} - (assign - "new_entity" - (first - (create_entities - new_entity - (call - (lambda - (declare - {_ (null)} - (replace _) - ) - ) - { - _ (retrieve_entity_root _) - } - ) - ) - ) - ) - (create_entities - (append new_entity "_3626604918") - (call - (lambda - (declare - {_ (null)} - (replace - _ - [] - (lambda - { - E (null) - F (null) - G (get - (current_value 1) - "G" - ) - H (get - (current_value 1) - "H" - ) - } - ) - ) - ) - ) - { - _ (retrieve_entity_root - (append _ "_3626604918") - ) - } - ) - ) - (create_entities - (append new_entity "_3823131681") - (call - (lambda - (declare - {_ (null)} - (replace - _ - [] - (lambda - {e (null) f (null)} - ) - ) - ) - ) - { - _ (retrieve_entity_root - (append _ "_3823131681") - ) - } - ) - ) - (clone_entities - (append _ "DiffEntityChild1") - (append new_entity "DiffEntityChild1") - ) - (clone_entities - (append _ "OnlyIn2") - (append new_entity "OnlyIn2") - ) - new_entity + (clone_entities _ new_entity) ) (declare {_ (null) new_entity (null)} @@ -3481,14 +3383,8 @@ difference between DiffEntity2 and new_entity: [] (lambda { - E (get - (current_value 1) - "E" - ) - F (get - (current_value 1) - "F" - ) + E 3 + F 4 G 5 H 6 } @@ -3513,16 +3409,7 @@ difference between DiffEntity2 and new_entity: _ [] (lambda - { - e (get - (current_value 1) - "e" - ) - f (get - (current_value 1) - "f" - ) - } + {e 3 f 4} ) ) ) @@ -3548,89 +3435,7 @@ contained_entities new_entity: ["OnlyIn2" "_1985995361" "_2783372341" "DiffEntit difference between DiffContainer and DiffEntity2: (declare {_ (null) new_entity (null)} - (assign - "new_entity" - (first - (create_entities - new_entity - (call - (lambda - (declare - {_ (null)} - (replace _) - ) - ) - { - _ (retrieve_entity_root _) - } - ) - ) - ) - ) - (create_entities - (append new_entity "_1985995361") - (call - (lambda - (declare - {_ (null)} - (replace - _ - [] - (lambda - { - E (null) - F (null) - G (get - (current_value 1) - "G" - ) - H (get - (current_value 1) - "H" - ) - } - ) - ) - ) - ) - { - _ (retrieve_entity_root - (append _ "_1985995361") - ) - } - ) - ) - (create_entities - (append new_entity "_2783372341") - (call - (lambda - (declare - {_ (null)} - (replace - _ - [] - (lambda - {e (null) f (null)} - ) - ) - ) - ) - { - _ (retrieve_entity_root - (append _ "_2783372341") - ) - } - ) - ) - (clone_entities - (append _ "OnlyIn2") - (append new_entity "OnlyIn2") - ) - (clone_entities - (append _ "DiffEntityChild1") - (append new_entity "DiffEntityChild1") - ) - new_entity + (clone_entities _ new_entity) ) --mix_entities-- (associate "b" 4) @@ -3642,17 +3447,24 @@ MergeEntityChild2 4 "u" 5 - "v" - 6 "w" 7 ) MergeEntityChild1 -(associate "x" 3 "y" 4 "z" 5) -_1651806471 -(associate "e" 3 "f" 4 "h" 6) +(associate "x" 3 "y" 4) _3130331116 -(associate "E" 3 "F" 4 "G" 5) +(associate "E" 3 "F" 4) +_1651806471 +(associate + "e" + 3 + "f" + 4 + "g" + 5 + "h" + 6 +) --get_entity_comments-- Full test This is a suite of unit tests. @@ -3731,7 +3543,7 @@ deep sets --set_entity_root_permission-- RootTest -1734044389.917383 +1734362704.367314 (true) RootTest @@ -4149,74 +3961,74 @@ store to .json normally ["Child1" "Child5"] ["Child3" "Child4"] ["Child6" "Child7"] -["Child1" "Child2" "Child6" "Child7"] ["Child2" "Child3" "Child5" "Child6"] +["Child2" "Child4" "Child6" "Child7"] ["Child4" "Child6"] --query_sample-- -["Child4"] -["Child6" "Child5"] -["Child1"] ["Child6"] ---query_weighted_sample-- -["Child1"] +["Child5" "Child3"] +["Child4"] +["Child7"] +with weights ["Child2"] +["Child1"] [ "Child2" - "Child2" - "Child2" - "Child6" + "Child1" "Child1" "Child1" "Child1" "Child2" - "Child2" - "Child2" - "Child4" - "Child2" - "Child2" + "Child1" + "Child1" + "Child1" "Child2" "Child1" "Child1" + "Child1" + "Child1" + "Child2" "Child2" "Child2" "Child2" "Child1" + "Child1" ] [ - "Child1" - "Child2" - "Child2" + "Child6" "Child2" "Child1" "Child1" + "Child2" + "Child1" + "Child2" "Child1" "Child1" + "Child2" "Child1" "Child1" "Child2" "Child2" - "Child1" + "Child2" "Child1" "Child1" "Child2" - "Child1" "Child2" "Child2" - "Child1" ] [ "Child2" "Child2" "Child2" "Child2" - "Child5" - "Child2" "Child2" + "Child4" + "Child3" + "Child7" "Child2" - "Child5" "Child2" ] -["Child2" "Child6"] +["Child2" "Child5"] --query_in_entity_list-- ["Child6" "Child7"] --query_not_in_entity_list-- @@ -4261,7 +4073,7 @@ cascading query_not_in_entity_list: ["Child6" "Child7"] unweighted query: { Child1 4 Child2 1 - Child4 100 + Child3 100 Child6 2 Child7 10 } @@ -4277,12 +4089,12 @@ weighted query list of lists: [ [0.04 0.2 0.45 1.8 2] ] weighted query list of lists: [ - ["Child2" "Child6" "Child1" "Child7" "Child4"] + ["Child2" "Child6" "Child1" "Child7" "Child3"] [1 2 4 10 100] [-1 2 4 10 100] ] weighted query list of lists with multiple values: [ - ["Child2" "Child6" "Child1" "Child7" "Child3"] + ["Child2" "Child6" "Child1" "Child7" "Child4"] [1 2 4 10 100] [-1 2 4 10 100] [-1 1 3 0 100] @@ -4582,15 +4394,15 @@ case conviction:{ } cyclic feature nearest neighbors: {cyclic1 1 cyclic5 0.5} cyclic test expected: 155, 200, 190 ... deg values of 0 8 and 12: +200: 0.05555555555555555 (null + ##deg 8 +) 155: 0.1 (null ##deg 0 ) 190: 0.045454545454545456 (null ##deg 12 ) -200: 0.05555555555555555 (null - ##deg 8 -) --contains_label-- (true) @@ -4868,12 +4680,12 @@ distance symmetry tests [ "B" "I" + "C" "D" "F" - "C" "A" + "H" "J" - "E" ] [ 0 @@ -4889,13 +4701,13 @@ distance symmetry tests [ [ "B" + "A" "C" "F" - "D" - "A" "I" - "E" - "G" + "D" + "H" + "J" ] [ 0 @@ -5093,4 +4905,4 @@ rmdir /s /q amlg_code\persistent_tree_test_root del /s /q amlg_code\persist_module_test\psm.mdam del /s /q amlg_code\persist_module_test.mdam --total execution time-- -1.6734039783477783 +2.013421058654785