From 4aab9ae2f126b99915e26e1b330ae818fca0d9e8 Mon Sep 17 00:00:00 2001 From: Max Piskunov Date: Wed, 16 Jun 2021 15:04:37 -0500 Subject: [PATCH 01/33] Implement GenerateFullMultihistory and GenerateSingleHistory. --- Kernel/A1$GenerateMultihistory.m | 88 +++++++++++++++++++++++++++-- Kernel/MultisetSubstitutionSystem.m | 2 +- 2 files changed, 83 insertions(+), 7 deletions(-) diff --git a/Kernel/A1$GenerateMultihistory.m b/Kernel/A1$GenerateMultihistory.m index 4c7f4790..603c19b4 100644 --- a/Kernel/A1$GenerateMultihistory.m +++ b/Kernel/A1$GenerateMultihistory.m @@ -3,6 +3,8 @@ PackageImport["GeneralUtilities`"] PackageExport["GenerateMultihistory"] +PackageExport["GenerateFullMultihistory"] +PackageExport["GenerateSingleHistory"] PackageExport["$SetReplaceSystems"] PackageExport["EventSelectionParameters"] PackageExport["EventOrderingFunctions"] @@ -13,23 +15,44 @@ PackageScope["declareMultihistoryGenerator"] PackageScope["initializeGenerators"] -SetUsage @ " +$usageSetReplaceSystems = "* A list of all supported systems can be obtained with $SetReplaceSystems."; +$usageEventOrderingSpec = +"* eventOrderingSpec$ can be set to 'UniformRandom', 'Any', or a list of partial event ordering functions. The list of \ +supported functions can be obtained with EventOrderingFunctions[Head[system$]]."; + +SetUsage[Evaluate[" GenerateMultihistory[system$, eventSelectionSpec$, tokenDeduplicationSpec$, eventOrderingSpec$, \ stoppingConditionSpec$][init$] yields a Multihistory object of the evaluation of a specified system$. -* A list of all supported systems can be obtained with $SetReplaceSystems. +" <> $usageSetReplaceSystems <> " * eventSelectionSpec$ is an Association defining constraints on the events that will be generated. The keys that can \ be used depend on the system$, some examples include 'MaxGeneration' and 'MaxDestroyerEvents'. A list for a particular \ system can be obtained with EventSelectionParameters[Head[system$]]. * tokenDeduplicationSpec$ can be set to None or All. -* eventOrderingSpec$ can be set to 'UniformRandom', 'Any', or a list of partial event ordering functions. The list of \ -supported functions can be obtained with EventOrderingFunctions[Head[system$]]. +" <> $usageEventOrderingSpec <> " * stoppingConditionSpec$ is an Association specifying conditions (e.g., 'MaxEvents') that, if satisfied, will cause \ the evaluation to stop immediately. The list of choices can be obtained with StoppingConditionParameters[Head[system$]]. -"; +"]]; SyntaxInformation[GenerateMultihistory] = {"ArgumentsPattern" -> {system_, eventSelectionSpec_, tokenDeduplicationSpec_, eventOrderingSpec_, stoppingConditionSpec_}}; +SetUsage[Evaluate[" +GenerateFullMultihistory[system$, maxGeneration$][init$] yields a complete Multihistory object of the evaluation of a \ +specified system$ up to maxGeneration$. +" <> $usageSetReplaceSystems <> " +"]]; + +SyntaxInformation[GenerateFullMultihistory] = {"ArgumentsPattern" -> {system_, maxGeneration_}}; + +SetUsage[Evaluate[" +GenerateSingleHistory[system$, eventOrderingSpec$, eventCount$][init$] yields a Multihistory object containing \ +eventCount$ events of an evaluation of a single history of the specified system$ using eventOrderingSpec$. +" <> $usageSetReplaceSystems <> " +" <> $usageEventOrderingSpec <> " +"]]; + +SyntaxInformation[GenerateSingleHistory] = {"ArgumentsPattern" -> {system_, eventOrderingSpec_, eventCount_}}; + (* Declaration *) $implementations = CreateDataStructure["HashTable"]; @@ -73,7 +96,7 @@ all specified keys present and valid according to the constraint (substituted wi declareMultihistoryGenerator[args___] := message[SetReplace, Failure["invalidGeneratorDeclaration", <|"args" -> {args}|>]]; -(* Generator call *) +(* GenerateMultihistory *) expr : (generator : GenerateMultihistory[args___])[init___] /; CheckArguments[generator, 5] && CheckArguments[expr, 1] := ModuleScope[ @@ -102,6 +125,58 @@ all specified keys present and valid according to the constraint (substituted wi declareMessage[General::unknownSystem, "System `system` in `expr` is not recognized."]; generateMultihistory[system_, __] := throw[Failure["unknownSystem", <|"system" -> system|>]]; +(* GenerateFullMultihistory *) + +expr : (generator : GenerateFullMultihistory[args___])[init___] /; + CheckArguments[generator, 2] && CheckArguments[expr, 1] := ModuleScope[ + result = Catch[generateFullMultihistory[args, init], + _ ? FailureQ, + message[GenerateFullMultihistory, #, <|"expr" -> HoldForm[expr]|>] &]; + result /; !FailureQ[result] +]; + +generateFullMultihistory[system_ /; $implementations["KeyExistsQ", Head[system]], maxGeneration_, init_] := ModuleScope[ + $implementations["Lookup", Head[system]][ + system, + parseMaxGeneration[maxGeneration, system], + None, + "Any", + parseConstraints["invalidStoppingCondition"][$stoppingConditionSpecs["Lookup", Head[system]]][{}], + init] +]; + +parseMaxGeneration[maxGeneration_, system_] := parseConstraints["invalidEventSelection"][ + $eventSelectionSpecs["Lookup", Head[system]]]["MaxGeneration" -> maxGeneration]; + +generateFullMultihistory[system_, __] := throw[Failure["unknownSystem", <|"system" -> system|>]]; + +(* GenerateSingleHistory *) + +expr : (generator : GenerateSingleHistory[args___])[init___] /; + CheckArguments[generator, 3] && CheckArguments[expr, 1] := ModuleScope[ + result = Catch[generateSingleHistory[args, init], + _ ? FailureQ, + message[GenerateSingleHistory, #, <|"expr" -> HoldForm[expr]|>] &]; + result /; !FailureQ[result] +]; + +generateSingleHistory[ + system_ /; $implementations["KeyExistsQ", Head[system]], rawEventOrdering_, maxEvents_, init_] := ModuleScope[ + $implementations["Lookup", Head[system]][ + system, + parseConstraints["invalidEventSelection"][$eventSelectionSpecs["Lookup", Head[system]]][ + {"MaxDestroyerEvents" -> 1}], + None, + parseEventOrdering[$eventOrderings["Lookup", Head[system]]][rawEventOrdering], + parseMaxEvents[maxEvents, system], + init] +]; + +parseMaxEvents[maxEvents_, system_] := parseConstraints["invalidStoppingCondition"][ + $stoppingConditionSpecs["Lookup", Head[system]]]["MaxEvents" -> maxEvents]; + +generateSingleHistory[system_, __] := throw[Failure["unknownSystem", <|"system" -> system|>]]; + (* Parsing *) (* In addition to associations, lists of rules and single rules are allowed. *) @@ -127,6 +202,7 @@ all specified keys present and valid according to the constraint (substituted wi throw[Failure["invalidTokenDeduplication", <|"value" -> value, "choices" -> $tokenDeduplicationValues|>]]; parseEventOrdering[supportedFunctions_][argument_List] /; SubsetQ[supportedFunctions, argument] := argument; +parseEventOrdering[_][argument : "Any"] := argument; declareMessage[ General::invalidEventOrdering, "Event ordering spec `argument` in `expr` should be a List of values from `choices`."]; parseEventOrdering[supportedFunctions_][argument_] := diff --git a/Kernel/MultisetSubstitutionSystem.m b/Kernel/MultisetSubstitutionSystem.m index c0edccf9..5d6da967 100644 --- a/Kernel/MultisetSubstitutionSystem.m +++ b/Kernel/MultisetSubstitutionSystem.m @@ -326,7 +326,7 @@ according to some (but not all) ordering functions. This new data structure will $supportedEventOrdering = {"InputCount", "SortedInputTokenIndices", "InputTokenIndices", "RuleIndex", "InstantiationIndex"}; -parseEventOrdering[ordering : $supportedEventOrdering] := ordering; +parseEventOrdering[ordering : ($supportedEventOrdering | "Any")] := ordering; declareMessage[General::multisetEventOrderingNotImplemented, "Only " <> ToString[$supportedEventOrdering] <> " event ordering is implemented at this time."]; parseEventOrdering[_] := throw[Failure["multisetEventOrderingNotImplemented", <||>]]; From afe05d7e26d7fb30b73da8468c899a878797c6a4 Mon Sep 17 00:00:00 2001 From: Max Piskunov Date: Wed, 16 Jun 2021 19:28:58 -0500 Subject: [PATCH 02/33] Rename GenerateFullMultihistory -> GenerateAllHistories. --- .../Generators/EventOrderingFunctions.md | 2 +- .../Generators/EventSelectionParameters.md | 2 +- .../Generators/GenerateMultihistory.md | 4 ++-- Documentation/Generators/README.md | 2 +- Kernel/A1$GenerateMultihistory.m | 20 +++++++++---------- 5 files changed, 15 insertions(+), 15 deletions(-) diff --git a/Documentation/Generators/EventOrderingFunctions.md b/Documentation/Generators/EventOrderingFunctions.md index 68d474b4..1297dbe5 100644 --- a/Documentation/Generators/EventOrderingFunctions.md +++ b/Documentation/Generators/EventOrderingFunctions.md @@ -21,7 +21,7 @@ Event ordering functions control the order in which these matches will be instan The importance of that order depends on the system, the rules, and the evaluation parameters. For example, in the example above, full multihistory is generated up to generation 1. In this case, the same multihistory is generated regardless of the event ordering, so the event ordering is not important. For this reason, there is no argument for the -event ordering in `GenerateFullMultihistory` (not yet implemented). +event ordering in `GenerateAllHistories` (not yet implemented). However, if we evaluate a single history instead, we can get different histories for different orders (different orders are made here by rearranging the order of the initial state, as diff --git a/Documentation/Generators/EventSelectionParameters.md b/Documentation/Generators/EventSelectionParameters.md index e159322c..5ab21e99 100644 --- a/Documentation/Generators/EventSelectionParameters.md +++ b/Documentation/Generators/EventSelectionParameters.md @@ -86,7 +86,7 @@ In[] := #["ExpressionsEventsGraph", VertexLabels -> Placed[Automatic, After]] & If unset (i.e., set to [`Infinity`](https://reference.wolfram.com/language/ref/Infinity.html)), it will generate a full -multihistory (similar to `GenerateFullMultihistory`) subject to other selection and stopping parameters: +multihistory (similar to `GenerateAllHistories`) subject to other selection and stopping parameters: ```wl In[] := #["ExpressionsEventsGraph", VertexLabels -> Placed[Automatic, After]] & @ diff --git a/Documentation/Generators/GenerateMultihistory.md b/Documentation/Generators/GenerateMultihistory.md index dcf1753a..511a9dc2 100644 --- a/Documentation/Generators/GenerateMultihistory.md +++ b/Documentation/Generators/GenerateMultihistory.md @@ -30,10 +30,10 @@ In[] := #["ExpressionsEventsGraph", VertexLabels -> Placed[Automatic, After]] & -Everything that can be generated with more specialized `GenerateSingleHistory` and `GenerateFullMultihistory` can be +Everything that can be generated with more specialized `GenerateSingleHistory` and `GenerateAllHistories` can be reproduced with `GenerateMultihistory` as well. This can be done by setting `"MaxDestroyerEvents" -> 1` to emulate `GenerateSingleHistory` and setting `"MaxDestroyerEvents" -> Infinity` and leaving the -[stopping condition](StoppingConditionParameters.md) empty to emulate `GenerateFullMultihistory`. +[stopping condition](StoppingConditionParameters.md) empty to emulate `GenerateAllHistories`. However, by setting `"MaxDestroyerEvents"` to finite values larger than 1, one can generate multihistories not possible with other generators. diff --git a/Documentation/Generators/README.md b/Documentation/Generators/README.md index e64c887d..ea1c7983 100644 --- a/Documentation/Generators/README.md +++ b/Documentation/Generators/README.md @@ -50,7 +50,7 @@ The same generators support multiple systems. In addition to parameters. [`GenerateMultihistory`](GenerateMultihistory.md) is the universal generator. It can generate everything that the -specialized `GenerateSingleHistory` and `GenerateFullMultihistory` can produce. However, it is more verbose, which can +specialized `GenerateSingleHistory` and `GenerateAllHistories` can produce. However, it is more verbose, which can make the code harder to read. * Introspection: diff --git a/Kernel/A1$GenerateMultihistory.m b/Kernel/A1$GenerateMultihistory.m index 603c19b4..8475f138 100644 --- a/Kernel/A1$GenerateMultihistory.m +++ b/Kernel/A1$GenerateMultihistory.m @@ -3,7 +3,7 @@ PackageImport["GeneralUtilities`"] PackageExport["GenerateMultihistory"] -PackageExport["GenerateFullMultihistory"] +PackageExport["GenerateAllHistories"] PackageExport["GenerateSingleHistory"] PackageExport["$SetReplaceSystems"] PackageExport["EventSelectionParameters"] @@ -37,12 +37,12 @@ {system_, eventSelectionSpec_, tokenDeduplicationSpec_, eventOrderingSpec_, stoppingConditionSpec_}}; SetUsage[Evaluate[" -GenerateFullMultihistory[system$, maxGeneration$][init$] yields a complete Multihistory object of the evaluation of a \ -specified system$ up to maxGeneration$. +GenerateAllHistories[system$, maxGeneration$][init$] yields a Multihistory object representing all possible histories \ +of the evaluation of a specified system$ up to maxGeneration$. " <> $usageSetReplaceSystems <> " "]]; -SyntaxInformation[GenerateFullMultihistory] = {"ArgumentsPattern" -> {system_, maxGeneration_}}; +SyntaxInformation[GenerateAllHistories] = {"ArgumentsPattern" -> {system_, maxGeneration_}}; SetUsage[Evaluate[" GenerateSingleHistory[system$, eventOrderingSpec$, eventCount$][init$] yields a Multihistory object containing \ @@ -125,17 +125,17 @@ all specified keys present and valid according to the constraint (substituted wi declareMessage[General::unknownSystem, "System `system` in `expr` is not recognized."]; generateMultihistory[system_, __] := throw[Failure["unknownSystem", <|"system" -> system|>]]; -(* GenerateFullMultihistory *) +(* GenerateAllHistories *) -expr : (generator : GenerateFullMultihistory[args___])[init___] /; +expr : (generator : GenerateAllHistories[args___])[init___] /; CheckArguments[generator, 2] && CheckArguments[expr, 1] := ModuleScope[ - result = Catch[generateFullMultihistory[args, init], + result = Catch[generateAllHistories[args, init], _ ? FailureQ, - message[GenerateFullMultihistory, #, <|"expr" -> HoldForm[expr]|>] &]; + message[GenerateAllHistories, #, <|"expr" -> HoldForm[expr]|>] &]; result /; !FailureQ[result] ]; -generateFullMultihistory[system_ /; $implementations["KeyExistsQ", Head[system]], maxGeneration_, init_] := ModuleScope[ +generateAllHistories[system_ /; $implementations["KeyExistsQ", Head[system]], maxGeneration_, init_] := ModuleScope[ $implementations["Lookup", Head[system]][ system, parseMaxGeneration[maxGeneration, system], @@ -148,7 +148,7 @@ all specified keys present and valid according to the constraint (substituted wi parseMaxGeneration[maxGeneration_, system_] := parseConstraints["invalidEventSelection"][ $eventSelectionSpecs["Lookup", Head[system]]]["MaxGeneration" -> maxGeneration]; -generateFullMultihistory[system_, __] := throw[Failure["unknownSystem", <|"system" -> system|>]]; +generateAllHistories[system_, __] := throw[Failure["unknownSystem", <|"system" -> system|>]]; (* GenerateSingleHistory *) From 261907811396f0539e6649ec0d1481beaa4b7960 Mon Sep 17 00:00:00 2001 From: Max Piskunov Date: Wed, 7 Jul 2021 15:44:11 -0500 Subject: [PATCH 03/33] Implement the new generator system. --- Kernel/A1$GenerateMultihistory.m | 295 ---------------------------- Kernel/A1$generatorSystem.m | 232 ++++++++++++++++++++++ Kernel/MultisetSubstitutionSystem.m | 35 ++-- Kernel/generators.m | 9 + Kernel/init.m | 2 +- 5 files changed, 256 insertions(+), 317 deletions(-) delete mode 100644 Kernel/A1$GenerateMultihistory.m create mode 100644 Kernel/A1$generatorSystem.m create mode 100644 Kernel/generators.m diff --git a/Kernel/A1$GenerateMultihistory.m b/Kernel/A1$GenerateMultihistory.m deleted file mode 100644 index 8475f138..00000000 --- a/Kernel/A1$GenerateMultihistory.m +++ /dev/null @@ -1,295 +0,0 @@ -Package["SetReplace`"] - -PackageImport["GeneralUtilities`"] - -PackageExport["GenerateMultihistory"] -PackageExport["GenerateAllHistories"] -PackageExport["GenerateSingleHistory"] -PackageExport["$SetReplaceSystems"] -PackageExport["EventSelectionParameters"] -PackageExport["EventOrderingFunctions"] -PackageExport["StoppingConditionParameters"] - -PackageScope["generateMultihistory"] - -PackageScope["declareMultihistoryGenerator"] -PackageScope["initializeGenerators"] - -$usageSetReplaceSystems = "* A list of all supported systems can be obtained with $SetReplaceSystems."; -$usageEventOrderingSpec = -"* eventOrderingSpec$ can be set to 'UniformRandom', 'Any', or a list of partial event ordering functions. The list of \ -supported functions can be obtained with EventOrderingFunctions[Head[system$]]."; - -SetUsage[Evaluate[" -GenerateMultihistory[system$, eventSelectionSpec$, tokenDeduplicationSpec$, eventOrderingSpec$, \ -stoppingConditionSpec$][init$] yields a Multihistory object of the evaluation of a specified system$. -" <> $usageSetReplaceSystems <> " -* eventSelectionSpec$ is an Association defining constraints on the events that will be generated. The keys that can \ -be used depend on the system$, some examples include 'MaxGeneration' and 'MaxDestroyerEvents'. A list for a particular \ -system can be obtained with EventSelectionParameters[Head[system$]]. -* tokenDeduplicationSpec$ can be set to None or All. -" <> $usageEventOrderingSpec <> " -* stoppingConditionSpec$ is an Association specifying conditions (e.g., 'MaxEvents') that, if satisfied, will cause \ -the evaluation to stop immediately. The list of choices can be obtained with StoppingConditionParameters[Head[system$]]. -"]]; - -SyntaxInformation[GenerateMultihistory] = {"ArgumentsPattern" -> - {system_, eventSelectionSpec_, tokenDeduplicationSpec_, eventOrderingSpec_, stoppingConditionSpec_}}; - -SetUsage[Evaluate[" -GenerateAllHistories[system$, maxGeneration$][init$] yields a Multihistory object representing all possible histories \ -of the evaluation of a specified system$ up to maxGeneration$. -" <> $usageSetReplaceSystems <> " -"]]; - -SyntaxInformation[GenerateAllHistories] = {"ArgumentsPattern" -> {system_, maxGeneration_}}; - -SetUsage[Evaluate[" -GenerateSingleHistory[system$, eventOrderingSpec$, eventCount$][init$] yields a Multihistory object containing \ -eventCount$ events of an evaluation of a single history of the specified system$ using eventOrderingSpec$. -" <> $usageSetReplaceSystems <> " -" <> $usageEventOrderingSpec <> " -"]]; - -SyntaxInformation[GenerateSingleHistory] = {"ArgumentsPattern" -> {system_, eventOrderingSpec_, eventCount_}}; - -(* Declaration *) - -$implementations = CreateDataStructure["HashTable"]; -$eventSelectionSpecs = CreateDataStructure["HashTable"]; (* generator -> <|key -> {default, constraint}, ...|> *) -$eventOrderings = CreateDataStructure["HashTable"]; (* generator -> {ordering, ...} *) -$stoppingConditionSpecs = CreateDataStructure["HashTable"]; (* generator -> <|key -> {default, constraint}, ...|> *) - -$possibleConstraints = None | "NonNegativeIntegerOrInfinity"; - -$constraintsSpecPattern = - _Association ? (AllTrue[StringQ] @ Keys[#] && MatchQ[Values[#], {{_, $possibleConstraints}...}] &); - -(* Every generator needs to call this function in order to be usable through GenerateMultihistory and related functions. - The metadata about selection, ordering and stopping conditions will be used to automatically check the arguments. - The implementation function can expect event selection and stopping conditions to be passed as associations with - all specified keys present and valid according to the constraint (substituted with defaults if missing). - Event ordering will be passed as a list of strings from the eventOrderings argument. *) - -(* For example, - declareMultihistoryGenerator[ - generateMultisetSubstitutionSystem, - MultisetSubstitutionSystem, - <|"MaxGeneration" -> {Infinity, "NonNegativeIntegerOrInfinity"}, - "MinEventInputs" -> {0, "NonNegativeIntegerOrInfinity"}|>, - {"InputCount", "SortedInputTokenIndices", "InputTokenIndices", "RuleIndex", "InstantiationIndex"}, - <|"MaxEvents" -> {Infinity, "NonNegativeIntegerOrInfinity"}|>] *) - -declareMultihistoryGenerator[implementationFunction_, - systemType_, - eventSelectionSpec : $constraintsSpecPattern, - eventOrderings : {___String}, - stoppingConditionSpec : $constraintsSpecPattern] := ( - $implementations["Insert", systemType -> implementationFunction]; - $eventSelectionSpecs["Insert", systemType -> eventSelectionSpec]; - $eventOrderings["Insert", systemType -> eventOrderings]; - $stoppingConditionSpecs["Insert", systemType -> stoppingConditionSpec]; -); - -declareMessage[General::invalidGeneratorDeclaration, - "Internal error. Multihistory generator is declared incorrectly with arguments `args`."]; -declareMultihistoryGenerator[args___] := - message[SetReplace, Failure["invalidGeneratorDeclaration", <|"args" -> {args}|>]]; - -(* GenerateMultihistory *) - -expr : (generator : GenerateMultihistory[args___])[init___] /; - CheckArguments[generator, 5] && CheckArguments[expr, 1] := ModuleScope[ - result = Catch[generateMultihistory[args, init], - _ ? FailureQ, - message[GenerateMultihistory, #, <|"expr" -> HoldForm[expr]|>] &]; - result /; !FailureQ[result] -]; - -generateMultihistory[system_ /; $implementations["KeyExistsQ", Head[system]], - rawEventSelection_, - rawTokenDeduplication_, - rawEventOrdering_, - rawStoppingCondition_, - init_] := ModuleScope[ - $implementations["Lookup", Head[system]][ - system, - parseConstraints["invalidEventSelection"][$eventSelectionSpecs["Lookup", Head[system]]][rawEventSelection], - parseTokenDeduplication[rawTokenDeduplication], - parseEventOrdering[$eventOrderings["Lookup", Head[system]]][rawEventOrdering], - parseConstraints["invalidStoppingCondition"][$stoppingConditionSpecs["Lookup", Head[system]]][rawStoppingCondition], - init - ] -]; - -declareMessage[General::unknownSystem, "System `system` in `expr` is not recognized."]; -generateMultihistory[system_, __] := throw[Failure["unknownSystem", <|"system" -> system|>]]; - -(* GenerateAllHistories *) - -expr : (generator : GenerateAllHistories[args___])[init___] /; - CheckArguments[generator, 2] && CheckArguments[expr, 1] := ModuleScope[ - result = Catch[generateAllHistories[args, init], - _ ? FailureQ, - message[GenerateAllHistories, #, <|"expr" -> HoldForm[expr]|>] &]; - result /; !FailureQ[result] -]; - -generateAllHistories[system_ /; $implementations["KeyExistsQ", Head[system]], maxGeneration_, init_] := ModuleScope[ - $implementations["Lookup", Head[system]][ - system, - parseMaxGeneration[maxGeneration, system], - None, - "Any", - parseConstraints["invalidStoppingCondition"][$stoppingConditionSpecs["Lookup", Head[system]]][{}], - init] -]; - -parseMaxGeneration[maxGeneration_, system_] := parseConstraints["invalidEventSelection"][ - $eventSelectionSpecs["Lookup", Head[system]]]["MaxGeneration" -> maxGeneration]; - -generateAllHistories[system_, __] := throw[Failure["unknownSystem", <|"system" -> system|>]]; - -(* GenerateSingleHistory *) - -expr : (generator : GenerateSingleHistory[args___])[init___] /; - CheckArguments[generator, 3] && CheckArguments[expr, 1] := ModuleScope[ - result = Catch[generateSingleHistory[args, init], - _ ? FailureQ, - message[GenerateSingleHistory, #, <|"expr" -> HoldForm[expr]|>] &]; - result /; !FailureQ[result] -]; - -generateSingleHistory[ - system_ /; $implementations["KeyExistsQ", Head[system]], rawEventOrdering_, maxEvents_, init_] := ModuleScope[ - $implementations["Lookup", Head[system]][ - system, - parseConstraints["invalidEventSelection"][$eventSelectionSpecs["Lookup", Head[system]]][ - {"MaxDestroyerEvents" -> 1}], - None, - parseEventOrdering[$eventOrderings["Lookup", Head[system]]][rawEventOrdering], - parseMaxEvents[maxEvents, system], - init] -]; - -parseMaxEvents[maxEvents_, system_] := parseConstraints["invalidStoppingCondition"][ - $stoppingConditionSpecs["Lookup", Head[system]]]["MaxEvents" -> maxEvents]; - -generateSingleHistory[system_, __] := throw[Failure["unknownSystem", <|"system" -> system|>]]; - -(* Parsing *) -(* In addition to associations, lists of rules and single rules are allowed. *) - -parseConstraints[errorName_][specs_][listOfRules : {___Rule}] := - parseConstraints[errorName][specs][listOfRules, Association[listOfRules]]; -parseConstraints[errorName_][specs_][rule_Rule] := parseConstraints[errorName][specs][rule, Association[rule]]; -parseConstraints[errorName_][specs_][associationOrInvalid_] := - parseConstraints[errorName][specs][associationOrInvalid, associationOrInvalid]; -parseConstraints[_][specs_][_, argument_Association] /; SubsetQ[Keys[specs], Keys[argument]] := - Association @ KeyValueMap[#1 -> checkParameter[#1, #2[[2]]] @ Lookup[argument, #1, #2[[1]]] &, specs]; -declareMessage[General::invalidEventSelection, - "Event selection spec `argument` in `expr` should be an Association with keys from `choices`."]; -declareMessage[General::invalidStoppingCondition, - "Stopping condition spec `argument` in `expr` should be an Association with keys from `choices`."]; -parseConstraints[errorName_][specs_][originalArgument_, _] := - throw[Failure[errorName, <|"argument" -> originalArgument, "choices" -> Keys[specs]|>]]; - -$tokenDeduplicationValues = {None, All}; -parseTokenDeduplication[value : Alternatives @@ $tokenDeduplicationValues] := value; -declareMessage[ - General::invalidTokenDeduplication, "Token deduplication `value` in `expr` can only be one of `choices`."]; -parseTokenDeduplication[value_] := - throw[Failure["invalidTokenDeduplication", <|"value" -> value, "choices" -> $tokenDeduplicationValues|>]]; - -parseEventOrdering[supportedFunctions_][argument_List] /; SubsetQ[supportedFunctions, argument] := argument; -parseEventOrdering[_][argument : "Any"] := argument; -declareMessage[ - General::invalidEventOrdering, "Event ordering spec `argument` in `expr` should be a List of values from `choices`."]; -parseEventOrdering[supportedFunctions_][argument_] := - throw[Failure["invalidEventOrdering", <|"argument" -> argument, "choices" -> supportedFunctions|>]]; - -checkParameter[_, None][value_] := value; -checkParameter[_, "NonNegativeIntegerOrInfinity"][value : (_Integer ? (# >= 0 &)) | Infinity] := value; -declareMessage[General::notNonNegativeIntegerOrInfinityParameter, - "Parameter `name` in `expr` is expected to be a non-negative integer or Infinity."]; -checkParameter[name_, "NonNegativeIntegerOrInfinity"][_] := - throw[Failure["notNonNegativeIntegerOrInfinityParameter", <|"name" -> name|>]]; - -(* Initialization *) - -(* It would be best to only show autocompletions for specific-system keys, but it does not seem to be possible because - dependent argument completions are only supported in WL if the main argument is a string. *) - -constraintArgumentCompletions[hashTable_] := Replace[Union @ Catenate[Keys /@ hashTable["Values"]], {} -> 0]; - -SetUsage @ " -$SetReplaceSystems gives the list of all computational systems that can be used with GenerateMultihistory and related \ -functions. -"; - -initializeGenerators[] := ( - $SetReplaceSystems = Sort @ $implementations["Keys"]; - With[{ - selectionKeys = constraintArgumentCompletions[$eventSelectionSpecs], - orderings = Replace[Union @ Catenate @ $eventOrderings["Values"], {} -> 0], - stoppingConditionKeys = constraintArgumentCompletions[$stoppingConditionSpecs]}, - FE`Evaluate[FEPrivate`AddSpecialArgCompletion[ - "GenerateMultihistory" -> {0, selectionKeys, 0, orderings, stoppingConditionKeys, 0}]]; - ]; -); - -(* Introspection functions *) - -SetUsage @ " -EventSelectionParameters[system$] yields the list of event selection parameters that can be used with system$. -"; - -SyntaxInformation[EventSelectionParameters] = {"ArgumentsPattern" -> {system_}}; - -expr : EventSelectionParameters[args___] /; CheckArguments[expr, 1] := ModuleScope[ - result = Catch[eventSelectionParameters[args], - _ ? FailureQ, - message[EventSelectionParameters, #, <|"expr" -> HoldForm[expr]|>] &]; - result /; !FailureQ[result] -]; - -eventSelectionParameters[system_Symbol | system_Symbol[___]] /; $eventSelectionSpecs["KeyExistsQ", system] := - Keys @ $eventSelectionSpecs["Lookup", system]; - -eventSelectionParameters[system_] := throw[Failure["unknownSystem", <|"system" -> system|>]]; - -SetUsage @ " -EventOrderingFunctions[system$] yields the list of event ordering functions that can be used with system$. -"; - -SyntaxInformation[EventOrderingFunctions] = {"ArgumentsPattern" -> {system_}}; - -expr : EventOrderingFunctions[args___] /; CheckArguments[expr, 1] := ModuleScope[ - result = Catch[eventOrderingFunctions[args], - _ ? FailureQ, - message[EventOrderingFunctions, #, <|"expr" -> HoldForm[expr]|>] &]; - result /; !FailureQ[result] -]; - -eventOrderingFunctions[system_Symbol | system_Symbol[___]] /; $eventOrderings["KeyExistsQ", system] := - $eventOrderings["Lookup", system]; - -eventOrderingFunctions[system_] := throw[Failure["unknownSystem", <|"system" -> system|>]]; - -SetUsage @ " -StoppingConditionParameters[system$] yields the list of stopping condition parameters that can be used with system$. -"; - -SyntaxInformation[StoppingConditionParameters] = {"ArgumentsPattern" -> {system_}}; - -expr : StoppingConditionParameters[args___] /; CheckArguments[expr, 1] := ModuleScope[ - result = Catch[stoppingConditionParameters[args], - _ ? FailureQ, - message[StoppingConditionParameters, #, <|"expr" -> HoldForm[expr]|>] &]; - result /; !FailureQ[result] -]; - -stoppingConditionParameters[system_Symbol | system_Symbol[___]] /; $stoppingConditionSpecs["KeyExistsQ", system] := - Keys @ $stoppingConditionSpecs["Lookup", system]; - -stoppingConditionParameters[system_] := throw[Failure["unknownSystem", <|"system" -> system|>]]; diff --git a/Kernel/A1$generatorSystem.m b/Kernel/A1$generatorSystem.m new file mode 100644 index 00000000..c9e566e4 --- /dev/null +++ b/Kernel/A1$generatorSystem.m @@ -0,0 +1,232 @@ +Package["SetReplace`"] + +PackageImport["GeneralUtilities`"] + +PackageExport["$SetReplaceSystems"] +PackageExport["$SetReplaceGenerators"] +PackageExport["SetReplaceSystemParameters"] + +PackageScope["declareSystem"] +PackageScope["declareGenerator"] +PackageScope["autoList"] +PackageScope["initializeSystemGenerators"] + +(* System declaration *) + +$systemImplementations = <||>; (* system -> implementationFunction *) +$systemInitPatterns = <||>; (* system -> pattern *) +$systemParameters = <||>; (* system -> <|parameter -> {default, pattern}, ...|> *) +$systemParameterDependencies = <||>; (* system -> logical expressions on parameter keys *) + +(* Every system implementation needs to call this function in order to be usable through GenerateEventSet and other \ + generators. *) + +(* The metadata about parameters has the form {default, pattern} and is used to automatically check the arguments. The + pattern should not contain any internal symbols as it is displayed to users in error messages. Further, the logical + expression in the last argument will check if all required parameters are specified. Some parameters may require + others to be specified, e.g., Implies["MaxDestroyerEvents" || "MaxEvents", "EventOrder"] means that if + "MaxDestroyerEvents" or "MaxEvents" is specified, "EventOrder" must be specified as well. + The implementation function can expect all specified parameters present (substituted with defaults if missing) and + all values satisfying the constraints (substituted with defaults if missing). *) + +(* autoList is a special head useful for, e.g., "EventOrder". It takes a pattern as its argument. It allows a list with + echo element matching that pattern. Alternatively, it can accept a single value matching the pattern, in which case a + list around it will be created automatically and passed to the system generator. *) + +(* For example, + declareMultihistoryGenerator[ + MultisetSubstitutionSystem, + generateMultisetSubstitutionSystem, + <|"MaxGeneration" -> {Infinity, _ ? (# >= 0 &)}, + "MinEventInputs" -> {0, _ ? (# >= 0 &)}, + "MaxDestroyerEvents" -> {Infinity, _ ? (# >= 0 &)} + "MaxEvents" -> {Infinity, _ ? (# >= 0 &)}, + "EventOrder" -> {{"Any"}, autoList["Any" | "Random" | "InputCount" | "SortedInputTokenIndices" | "RuleIndex"]}|>, + Implies["MaxDestroyerEvents" || "MaxEvents", "EventOrder"]] *) + +(* The implementation function is then called as + generateMultisetSubstitutionSystem[MultisetSubstitutionSystem[rules], init, parameters] *) + +declareSystem[systemType_, + implementationFunction_, + initPattern_, + parameters_Association /; AllTrue[Values @ parameters, MatchQ[{_, _}]], + dependencies_ ? SatisfiableQ] := ( + $systemImplementations[systemType] = implementationFunction; + $systemInitPatterns[systemType] = initPattern; + $systemParameters[systemType] = parameters; + $systemParameterDependencies[systemType] = dependencies; +); + +declareMessage[General::invalidGeneratorDeclaration, + "Internal error. Multihistory generator is declared incorrectly with arguments `args`."]; +declareMultihistoryGenerator[args___] := + message[SetReplace, Failure["invalidGeneratorDeclaration", <|"args" -> {args}|>]]; + +(* Generator declaration *) + +$generatorParameters = <||>; (* generator -> <|parameter -> value, ...|> *) +$generatorProperties = <||>; (* generator -> property *) + +(* Generators are functions that are called to produce EventSet objects. They take the form + symbol[system, init, params]. They also define a fixed set of parameter values. These parameter values cannot be + changed in params. Generators can also compute a property at the end of the evaluation. *) + +(* For example, + + declareGenerator[EvaluateSingleHistory, <|"MaxDestroyerEvents" -> 1|>, FinalState] + + Note that the constraint in the last argument of declareMultihistoryGenerator still needs to be specified, which + means "EventOrder" is now a required parameter. *) + +declareGenerator[symbol_, parameterValues_, property_ : Identity] := ( + $generatorParameters[symbol] = parameterValues; + $generatorProperties[symbol] = property; +); + +(* Initialization *) + +(* It would be best to only show autocompletions for specific-system keys, but it does not seem to be possible because + dependent argument completions are only supported in WL if the main argument is a string. *) + +SetUsage @ " +$SetReplaceSystems gives the list of all computational systems that can be used with GenerateEventSet and related \ +functions. +"; + +SetUsage @ " +$SetReplaceGenerators gives the list of all generators that can be used to evaluate systems such as \ +MultisetSubstitutionSystem. +"; + +initializeSystemGenerators[] := Module[{parameterKeys, maxParameterCount}, + $SetReplaceSystems = Sort @ Keys @ $systemImplementations; + $SetReplaceGenerators = Sort @ Keys @ $generatorParameters; + parameterKeys = Union @ Catenate[Keys /@ Values[$systemParameters]]; + maxParameterCount = Length @ parameterKeys; + (* This has quadratic complexity in parameter count. But it does not seem to be possible to define the same set of + completion strings for a range of arguments. *) + With[{ + completionSpec = Join[{0}, Table[parameterKeys, maxParameterCount + 1]]}, + FE`Evaluate[FEPrivate`AddSpecialArgCompletion[# -> completionSpec]] & /@ ToString /@ $SetReplaceGenerators; + ]; + Scan[(SyntaxInformation[#] = {"ArgumentsPattern" -> {system_, init_., parameters___}}) &, $SetReplaceGenerators]; + defineGeneratorImplementation /@ Keys @ $generatorParameters; +]; + +declareMessage[General::argNotInit, "The init `arg` in `expr` should match `pattern`."]; +declareMessage[General::unknownSystem, "`system` is not a recognized SetReplace system."]; + +defineGeneratorImplementation[generator_] := ( + expr : generator[system_, init_, parameters___] /; + MatchQ[init, Lookup[$systemInitPatterns, Head[system], _]] := ModuleScope[ + result = Catch[implementation[generator][system, init, parameters], + _ ? FailureQ, + message[generator, #, <|"expr" -> HoldForm[expr]|>] &]; + result /; !FailureQ[result] + ]; + + expr : generator[args1___][args2___] /; CheckArguments[expr, {1, 1}] := ModuleScope[ + result = Catch[implementationOperator[generator][args1][args2], + _ ? FailureQ, + message[generator, #, <|"expr" -> HoldForm[expr]|>] &]; + result /; !FailureQ[result] + ]; + + expr : generator[] /; CheckArguments[expr, {1, Infinity}] := $Failed; + + implementation[generator][system_, init_, parameters___] /; + MatchQ[init, Lookup[$systemInitPatterns, Head[system], _]] := ModuleScope[ + implementation = $systemImplementations[Head[system]]; + If[MissingQ[implementation], throw[Failure["unknownSystem", <|"system" -> system|>]]]; + $generatorProperties[generator] @ + $systemImplementations[Head[system]][system, init, parseParameters[generator, Head[system]][parameters]] + ]; + implementation[generator][___] := throw[Failure[None, <||>]]; + + implementationOperator[generator][system_][init_] /; MatchQ[init, $systemInitPatterns[Head[system]]] := + implementation[generator][system, init, <||>]; + implementationOperator[generator][system_, parameters_, moreParameters___][init_] /; + MatchQ[init, $systemInitPatterns[Head[system]]] && !MatchQ[parameters, $systemInitPatterns[Head[system]]] := + implementation[generator][system, init, parameters, moreParameters]; + implementationOperator[generator][system_, ___][arg_] := + throw[Failure["argNotInit", <|"arg" -> arg, "pattern" -> $systemInitPatterns[Head[system]]|>]]; +); + +parseParameters[generator_, system_][parameters___] := + addMissingParameters[generator, system] @ + checkParameters[generator, system] @ Association[Join @@ collectParameters /@ {parameters}]; + +collectParameters[key_ -> value_] := <|key -> value|>; +collectParameters[key_ :> value_] := <|key -> value|>; +collectParameters[list_List] := Association[Join @@ collectParameters /@ list]; +collectParameters[association_Association] := association; +declareMessage[General::invalidGeneratorParameterSpec, "Parameter specification `spec` in `expr` should be a Rule."]; +collectParameters[spec_] := throw[Failure["invalidGeneratorParameterSpec", <|"spec" -> spec|>]]; + +checkParameters[generator_, system_][parameters_] := ( + KeyValueMap[checkParameter[generator, system][##] &, parameters]; + checkParameterCompleteness[generator, system][Keys[parameters]]; + parameters +); +checkParameter[generator_, system_][key_, value_] := ( + checkParameterKeyIsRecognized[system][key]; + checkParameterKeyIsNotForbidden[generator][key]; + checkParameterValueMatchesPattern[system][key, value]; +); + +declareMessage[General::unknownParameter, "`system` in `expr` does not support `parameter` parameter."]; +checkParameterKeyIsRecognized[system_][key_] /; !KeyExistsQ[$systemParameters[system], key] := + throw[Failure["unknownParameter", <|"system" -> system, "parameter" -> key|>]]; + +declareMessage[General::forbiddenParameter, "`parameter` in `expr` cannot be used with `generator`."]; +checkParameterKeyIsNotForbidden[generator_][key_] /; KeyExistsQ[$generatorParameters[generator], key] := + throw[Failure["forbiddenParameter", <|"generator" -> generator, "parameter" -> key|>]]; + +declareMessage[ + General::invalidParameter, "`parameter` value `value` in `expr` should match `pattern`."]; +checkParameterValueMatchesPattern[system_][key_, value_] /; !MatchQ[value, $systemParameters[system][key][[2]]] := + throw[Failure[ + "invalidParameter", <|"parameter" -> key, "value" -> value, "pattern" -> $systemParameters[system][key][[2]]|>]]; + +simplifyParameterCondition[generator_, system_, specifiedKeys_] := + FullSimplify[ + $systemParameterDependencies[system] /. + Alternatives @@ Join[specifiedKeys, Keys @ $generatorParameters[generator]] -> True]; +compatibleParametersQ[generator_, system_, specifiedKeys_] := + FullSimplify[ + $systemParameterDependencies[system] /. + Alternatives @@ Join[specifiedKeys, Keys @ $generatorParameters[generator]] -> True /. + Alternatives @@ Keys[$systemParameters[system]] -> False] +compatibleParametersQ[___] := False + +declareMessage[General::incompatibleParameters, + "Parameters in `expr` are incompatible. Specified parameters should satisfy `condition`."]; +checkParameterCompleteness[generator_, system_][keys_] /; + simplifyParameterCondition[generator, system, keys] === False := + throw[Failure["incompatibleParameters", <|"condition" -> $systemParameterDependencies[system]|>]]; + +declareMessage[General::missingParameters, "`missingParameters` should be explicitly specified in `expr`."]; +checkParameterCompleteness[generator_, system_][keys_] /; !compatibleParametersQ[generator, system, keys] := + throw[Failure["missingParameters", <|"missingParameters" -> simplifyParameterCondition[generator, system, keys]|>]]; + +addMissingParameters[generator_, system_][parameters_] := + Join[$systemParameters[system][[All, 1]], parameters, $generatorParameters[generator]]; + +(* Introspection functions *) + +SetUsage @ "SetReplaceSystemParameters[system$] yields the list of parameters supported by system$."; + +SyntaxInformation[SetReplaceSystemParameters] = {"ArgumentsPattern" -> {system_}}; + +expr : SetReplaceSystemParameters[args___] /; CheckArguments[expr, 1] := ModuleScope[ + result = Catch[setReplaceSystemParameters[args], + _ ? FailureQ, + message[SetReplaceSystemParameters, #, <|"expr" -> HoldForm[expr]|>] &]; + result /; !FailureQ[result] +]; + +setReplaceSystemParameters[system_Symbol | system_Symbol[___]] /; KeyExistsQ[$systemParameters, system] := + Keys @ $systemParameters[system]; + +setReplaceSystemParameters[system_] := throw[Failure["unknownSystem", <|"system" -> system|>]]; diff --git a/Kernel/MultisetSubstitutionSystem.m b/Kernel/MultisetSubstitutionSystem.m index 5d6da967..5183a62a 100644 --- a/Kernel/MultisetSubstitutionSystem.m +++ b/Kernel/MultisetSubstitutionSystem.m @@ -13,34 +13,27 @@ SyntaxInformation[MultisetSubstitutionSystem] = {"ArgumentsPattern" -> {rules_}}; -declareMultihistoryGenerator[ - generateMultisetSubstitutionSystem, +declareSystem[ MultisetSubstitutionSystem, - <|"MaxGeneration" -> {Infinity, "NonNegativeIntegerOrInfinity"}, - "MaxDestroyerEvents" -> {Infinity, "NonNegativeIntegerOrInfinity"}, - "MinEventInputs" -> {0, "NonNegativeIntegerOrInfinity"}, - "MaxEventInputs" -> {Infinity, "NonNegativeIntegerOrInfinity"}|>, - {"InputCount", "SortedInputTokenIndices", "InputTokenIndices", "RuleIndex", "InstantiationIndex"}, - <|"MaxEvents" -> {Infinity, "NonNegativeIntegerOrInfinity"}|>]; - -generateMultisetSubstitutionSystem[MultisetSubstitutionSystem[rawRules___], - rawEventSelection_, - rawTokenDeduplication_, - rawEventOrdering_, - rawStoppingCondition_, - rawInit_] := Block[{ + generateMultisetSubstitutionSystem, + _List, + <|"MaxGeneration" -> {Infinity, _ ? (# >= 0 &)}, + "MaxDestroyerEvents" -> {Infinity, _ ? (# >= 0 &)}, + "MinEventInputs" -> {0, _ ? (# >= 0 &)}, + "MaxEventInputs" -> {Infinity, _ ? (# >= 0 &)}, + "MaxEvents" -> {Infinity, _ ? (# >= 0 &)}|>, + True]; + +generateMultisetSubstitutionSystem[MultisetSubstitutionSystem[rawRules___], init_, parameters_] := Block[{ expressions, eventRuleIndices, eventInputs, eventOutputs, eventGenerations, expressionCreatorEvents, expressionDestroyerEventCounts, destroyerChoices, instantiationCounts, instantiations}, - Module[{rules, maxGeneration, maxDestroyerEvents, minEventInputs, maxEventInputs, maxEvents, init, terminationReason}, + Module[{rules, ruleInputCountRanges, maxGeneration, maxDestroyerEvents, minEventInputs, maxEventInputs, maxEvents, + terminationReason}, rules = parseRules[rawRules]; ruleInputCountRanges = inputCountRange /@ rules; - {maxGeneration, maxDestroyerEvents, minEventInputs, maxEventInputs} = Values @ rawEventSelection; + {maxGeneration, maxDestroyerEvents, minEventInputs, maxEventInputs, maxEvents} = Values @ parameters; minEventInputs = Max[minEventInputs, Min[ruleInputCountRanges[[All, 1]]]]; maxEventInputs = Min[maxEventInputs, Max[ruleInputCountRanges[[All, 2]]]]; - parseTokenDeduplication[rawTokenDeduplication]; (* Token deduplication is not implemented at the moment *) - parseEventOrdering[rawEventOrdering]; (* Event ordering is not implemented at the moment *) - {maxEvents} = Values @ rawStoppingCondition; - init = parseInit[rawInit]; (* "HashTable" is causing memory leaks, so we are using Data`UnorderedAssociation instead. *) diff --git a/Kernel/generators.m b/Kernel/generators.m new file mode 100644 index 00000000..03cd0450 --- /dev/null +++ b/Kernel/generators.m @@ -0,0 +1,9 @@ +Package["SetReplace`"] + +PackageImport["GeneralUtilities`"] + +PackageExport["GenerateMultihistory"] +PackageExport["GenerateSingleHistory"] + +declareGenerator[GenerateMultihistory, <||>, Identity]; +declareGenerator[GenerateSingleHistory, <|"MaxDestroyerEvents" -> 1|>, Identity]; diff --git a/Kernel/init.m b/Kernel/init.m index 61fdcfee..47094078 100644 --- a/Kernel/init.m +++ b/Kernel/init.m @@ -32,7 +32,7 @@ (* Type system and generators should be initialized after all Kernel files are loaded. *) SetReplace`PackageScope`initializeTypeSystem[]; - SetReplace`PackageScope`initializeGenerators[]; + SetReplace`PackageScope`initializeSystemGenerators[]; ]; End[]; From bf069ce9ffb9e95691f457eb9291a884f72dcce7 Mon Sep 17 00:00:00 2001 From: Max Piskunov Date: Wed, 7 Jul 2021 15:47:45 -0500 Subject: [PATCH 04/33] Remove unused parsing code from MultisetSubstitutionSystem. --- Kernel/MultisetSubstitutionSystem.m | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/Kernel/MultisetSubstitutionSystem.m b/Kernel/MultisetSubstitutionSystem.m index 5183a62a..ad75407e 100644 --- a/Kernel/MultisetSubstitutionSystem.m +++ b/Kernel/MultisetSubstitutionSystem.m @@ -311,19 +311,3 @@ according to some (but not all) ordering functions. This new data structure will (* Since we have enumerated all pattern constructs above, this case does not correspond to a pattern. However, the completeness of checks above needs to be checked for every new WL version. *) sequencePatternLengthRange[_] := If[$VersionNumber <= 12.3, {1, 1}, {0, Infinity}]; - -parseTokenDeduplication[None] := None; -declareMessage[General::multisetTokenDeduplicationNotImplemented, - "Token deduplication is not implemented for Multiset Substitution System."]; -parseTokenDeduplication[_] := throw[Failure["multisetTokenDeduplicationNotImplemented", <||>]]; - -$supportedEventOrdering = - {"InputCount", "SortedInputTokenIndices", "InputTokenIndices", "RuleIndex", "InstantiationIndex"}; -parseEventOrdering[ordering : ($supportedEventOrdering | "Any")] := ordering; -declareMessage[General::multisetEventOrderingNotImplemented, - "Only " <> ToString[$supportedEventOrdering] <> " event ordering is implemented at this time."]; -parseEventOrdering[_] := throw[Failure["multisetEventOrderingNotImplemented", <||>]]; - -parseInit[init_List] := init; -declareMessage[General::multisetInitNotList, "Multiset Substitution System init `init` should be a List."]; -parseInit[init_] := throw[Failure["multisetInitNotList", <|"init" -> init|>]]; From b979ee73064054225b4df811dab988f021d602d7 Mon Sep 17 00:00:00 2001 From: Max Piskunov Date: Thu, 8 Jul 2021 06:12:27 -0500 Subject: [PATCH 05/33] Update AtomicStateSystem. --- Documentation/Generators/README.md | 22 +++++----------- Kernel/A1$generatorSystem.m | 38 +++++++++++++++----------- Kernel/AtomicStateSystem.m | 41 +++++++---------------------- Kernel/MultisetSubstitutionSystem.m | 10 +++---- Kernel/generators.m | 7 +++-- 5 files changed, 50 insertions(+), 68 deletions(-) diff --git a/Documentation/Generators/README.md b/Documentation/Generators/README.md index ea1c7983..808ae62b 100644 --- a/Documentation/Generators/README.md +++ b/Documentation/Generators/README.md @@ -5,11 +5,10 @@ rules for a [computational system](/Documentation/Systems/README.md) and additio the evaluation. In *SetReplace*, we split the states of [computational systems](/Documentation/Systems/README.md) into components which -we call tokens. Rewrites (which we call events) replace some of these tokens with others. Crucially, *SetReplace* can -evaluate multiple branches of nondeterministic systems simultaneously. That is done by applying different events to the -same tokens and keeping events and tokens instead of states in -[`Multihistory`](/Documentation/Types/Multihistory/README.md) objects. We can reconstruct the states from that -information afterwards. +we call tokens. Rewrites (which we call events) replace some of these tokens with others. *SetReplace* can evaluate +multiple branches of nondeterministic systems simultaneously. That is done by applying different events to the same +tokens and keeping events and tokens instead of states in [`Multihistory`](/Documentation/Types/Multihistory/README.md) +objects. We can reconstruct the states from that information afterwards. Most systems, however, cannot be evaluated completely. And there are multiple groups of parameters to control how to perform a partial evaluation. One needs to decide [which events to include](EventSelectionParameters.md), in @@ -21,11 +20,7 @@ a single history (no nondeterministic branching): ```wl In[] := #["ExpressionsEventsGraph", VertexLabels -> Placed[Automatic, After]] & @ SetReplaceTypeConvert[{WolframModelEvolutionObject, 2}] @ - GenerateMultihistory[MultisetSubstitutionSystem[{a_, b_} /; a < b :> {a + b}], - "MaxDestroyerEvents" -> 1, - None, - EventOrderingFunctions[MultisetSubstitutionSystem], - {}] @ {1, 2, 3, 4} + GenerateSingleHistory[MultisetSubstitutionSystem[{a_, b_} /; a < b :> {a + b}], {1, 2, 3, 4}] ``` @@ -35,11 +30,8 @@ or multiple histories. Note different events (orange) using the same tokens (lig ```wl In[] := #["ExpressionsEventsGraph", VertexLabels -> Placed[Automatic, After]] & @ SetReplaceTypeConvert[{WolframModelEvolutionObject, 2}] @ - GenerateMultihistory[MultisetSubstitutionSystem[{a_, b_} /; a < b :> {a + b}], - "MaxDestroyerEvents" -> 2, - None, - EventOrderingFunctions[MultisetSubstitutionSystem], - {}] @ {1, 2, 3, 4} + GenerateMultihistory[ + MultisetSubstitutionSystem[{a_, b_} /; a < b :> {a + b}], {1, 2, 3, 4}, "MaxDestroyerEvents" -> 2] ``` diff --git a/Kernel/A1$generatorSystem.m b/Kernel/A1$generatorSystem.m index c9e566e4..97ed971d 100644 --- a/Kernel/A1$generatorSystem.m +++ b/Kernel/A1$generatorSystem.m @@ -29,14 +29,17 @@ The implementation function can expect all specified parameters present (substituted with defaults if missing) and all values satisfying the constraints (substituted with defaults if missing). *) +(* _List is the pattern that the init should satisfy. *) + (* autoList is a special head useful for, e.g., "EventOrder". It takes a pattern as its argument. It allows a list with echo element matching that pattern. Alternatively, it can accept a single value matching the pattern, in which case a list around it will be created automatically and passed to the system generator. *) (* For example, - declareMultihistoryGenerator[ + declareSystem[ MultisetSubstitutionSystem, generateMultisetSubstitutionSystem, + _List, <|"MaxGeneration" -> {Infinity, _ ? (# >= 0 &)}, "MinEventInputs" -> {0, _ ? (# >= 0 &)}, "MaxDestroyerEvents" -> {Infinity, _ ? (# >= 0 &)} @@ -65,8 +68,9 @@ all values satisfying the constraints (substituted with defaults if missing). *) (* Generator declaration *) -$generatorParameters = <||>; (* generator -> <|parameter -> value, ...|> *) -$generatorProperties = <||>; (* generator -> property *) +$generatorPackageScopeSymbols = <||>; (* generator (public symbol) -> package-scope symbol *) +$generatorParameters = <||>; (* generator -> <|parameter -> value, ...|> *) +$generatorProperties = <||>; (* generator -> property *) (* Generators are functions that are called to produce EventSet objects. They take the form symbol[system, init, params]. They also define a fixed set of parameter values. These parameter values cannot be @@ -74,14 +78,18 @@ all values satisfying the constraints (substituted with defaults if missing). *) (* For example, - declareGenerator[EvaluateSingleHistory, <|"MaxDestroyerEvents" -> 1|>, FinalState] + declareGenerator[EvaluateSingleHistory, evaluateSingleHistory, <|"MaxDestroyerEvents" -> 1|>, FinalState] - Note that the constraint in the last argument of declareMultihistoryGenerator still needs to be specified, which + Note that the constraint in the last argument of declareGenerator still needs to be specified, which means "EventOrder" is now a required parameter. *) -declareGenerator[symbol_, parameterValues_, property_ : Identity] := ( - $generatorParameters[symbol] = parameterValues; - $generatorProperties[symbol] = property; +(* evaluateSingleHistory is a PackageScope symbol that will throw exceptions instead of returning unevaluated. + It cannot be used in operator form. *) + +declareGenerator[publicSymbol_, packageScopeSymbol_, parameterValues_, property_ : Identity] := ( + $generatorPackageScopeSymbols[publicSymbol] = packageScopeSymbol; + $generatorParameters[publicSymbol] = parameterValues; + $generatorProperties[publicSymbol] = property; ); (* Initialization *) @@ -117,10 +125,10 @@ all values satisfying the constraints (substituted with defaults if missing). *) declareMessage[General::argNotInit, "The init `arg` in `expr` should match `pattern`."]; declareMessage[General::unknownSystem, "`system` is not a recognized SetReplace system."]; -defineGeneratorImplementation[generator_] := ( +defineGeneratorImplementation[generator_] := With[{packageScopeGenerator = $generatorPackageScopeSymbols[generator]}, expr : generator[system_, init_, parameters___] /; MatchQ[init, Lookup[$systemInitPatterns, Head[system], _]] := ModuleScope[ - result = Catch[implementation[generator][system, init, parameters], + result = Catch[packageScopeGenerator[system, init, parameters], _ ? FailureQ, message[generator, #, <|"expr" -> HoldForm[expr]|>] &]; result /; !FailureQ[result] @@ -135,23 +143,23 @@ all values satisfying the constraints (substituted with defaults if missing). *) expr : generator[] /; CheckArguments[expr, {1, Infinity}] := $Failed; - implementation[generator][system_, init_, parameters___] /; + packageScopeGenerator[system_, init_, parameters___] /; MatchQ[init, Lookup[$systemInitPatterns, Head[system], _]] := ModuleScope[ implementation = $systemImplementations[Head[system]]; If[MissingQ[implementation], throw[Failure["unknownSystem", <|"system" -> system|>]]]; $generatorProperties[generator] @ $systemImplementations[Head[system]][system, init, parseParameters[generator, Head[system]][parameters]] ]; - implementation[generator][___] := throw[Failure[None, <||>]]; + packageScopeGenerator[___] := throw[Failure[None, <||>]]; implementationOperator[generator][system_][init_] /; MatchQ[init, $systemInitPatterns[Head[system]]] := - implementation[generator][system, init, <||>]; + packageScopeGenerator[system, init, <||>]; implementationOperator[generator][system_, parameters_, moreParameters___][init_] /; MatchQ[init, $systemInitPatterns[Head[system]]] && !MatchQ[parameters, $systemInitPatterns[Head[system]]] := - implementation[generator][system, init, parameters, moreParameters]; + packageScopeGenerator[system, init, parameters, moreParameters]; implementationOperator[generator][system_, ___][arg_] := throw[Failure["argNotInit", <|"arg" -> arg, "pattern" -> $systemInitPatterns[Head[system]]|>]]; -); +]; parseParameters[generator_, system_][parameters___] := addMissingParameters[generator, system] @ diff --git a/Kernel/AtomicStateSystem.m b/Kernel/AtomicStateSystem.m index 006c35af..62b43faf 100644 --- a/Kernel/AtomicStateSystem.m +++ b/Kernel/AtomicStateSystem.m @@ -12,41 +12,20 @@ SyntaxInformation[AtomicStateSystem] = {"ArgumentsPattern" -> {rules_}}; -declareMultihistoryGenerator[ - generateAtomicStateSystem, +declareSystem[ AtomicStateSystem, - <|"MaxGeneration" -> {Infinity, "NonNegativeIntegerOrInfinity"}, - "MaxDestroyerEvents" -> {Infinity, "NonNegativeIntegerOrInfinity"}|>, - {"InputIndex", "RuleIndex"}, - <|"MaxEvents" -> {Infinity, "NonNegativeIntegerOrInfinity"}|>]; - -declareMessage[General::atomicStateTokenDeduplicationNotImplemented, - "Token deduplication is not implemented for Atomic State System."]; - -$supportedEventOrdering = {"InputIndex", "RuleIndex"}; - -declareMessage[General::atomicStateEventOrderingNotImplemented, - "Only " <> ToString[$supportedEventOrdering] <> " event ordering is implemented at this time."]; - -generateAtomicStateSystem[AtomicStateSystem[rules___], (* BlankNullSequence is needed to catch invalid arg counts *) - eventSelection_, - tokenDeduplication_, - eventOrdering_, - stoppingCondition_, - init_] := ModuleScope[ - If[tokenDeduplication =!= None, throw[Failure["atomicStateTokenDeduplicationNotImplemented", <||>]]]; - If[eventOrdering =!= {"InputIndex", "RuleIndex"}, throw[Failure["atomicStateEventOrderingNotImplemented", <||>]]]; + generateAtomicStateSystem, + _, + <|"MaxGeneration" -> {Infinity, _ ? (GreaterEqualThan[0])}, + "MaxDestroyerEvents" -> {Infinity, _ ? (GreaterEqualThan[0])}, + "MaxEvents" -> {Infinity, _ ? (GreaterEqualThan[0])}|>, + True]; +generateAtomicStateSystem[AtomicStateSystem[rules___], init_, parameters_] := ModuleScope[ toAtomicStateMultihistory[rules] @ generateMultihistory[ MultisetSubstitutionSystem[toMultisetRules[rules]], - <|"MaxGeneration" -> eventSelection["MaxGeneration"], - "MaxDestroyerEvents" -> eventSelection["MaxDestroyerEvents"], - "MinEventInputs" -> 1, - "MaxEventInputs" -> 1|>, - None, - {"InputCount", "SortedInputTokenIndices", "InputTokenIndices", "RuleIndex", "InstantiationIndex"}, - stoppingCondition, - {init}] + {init}, + Join[parameters, <|"MinEventInputs" -> 1, "MaxEventInputs" -> 1|>]] ]; (* Parsing *) diff --git a/Kernel/MultisetSubstitutionSystem.m b/Kernel/MultisetSubstitutionSystem.m index ad75407e..6210233a 100644 --- a/Kernel/MultisetSubstitutionSystem.m +++ b/Kernel/MultisetSubstitutionSystem.m @@ -17,11 +17,11 @@ MultisetSubstitutionSystem, generateMultisetSubstitutionSystem, _List, - <|"MaxGeneration" -> {Infinity, _ ? (# >= 0 &)}, - "MaxDestroyerEvents" -> {Infinity, _ ? (# >= 0 &)}, - "MinEventInputs" -> {0, _ ? (# >= 0 &)}, - "MaxEventInputs" -> {Infinity, _ ? (# >= 0 &)}, - "MaxEvents" -> {Infinity, _ ? (# >= 0 &)}|>, + <|"MaxGeneration" -> {Infinity, _ ? (GreaterEqualThan[0])}, + "MaxDestroyerEvents" -> {Infinity, _ ? (GreaterEqualThan[0])}, + "MinEventInputs" -> {0, _ ? (GreaterEqualThan[0])}, + "MaxEventInputs" -> {Infinity, _ ? (GreaterEqualThan[0])}, + "MaxEvents" -> {Infinity, _ ? (GreaterEqualThan[0])}|>, True]; generateMultisetSubstitutionSystem[MultisetSubstitutionSystem[rawRules___], init_, parameters_] := Block[{ diff --git a/Kernel/generators.m b/Kernel/generators.m index 03cd0450..134de65d 100644 --- a/Kernel/generators.m +++ b/Kernel/generators.m @@ -5,5 +5,8 @@ PackageExport["GenerateMultihistory"] PackageExport["GenerateSingleHistory"] -declareGenerator[GenerateMultihistory, <||>, Identity]; -declareGenerator[GenerateSingleHistory, <|"MaxDestroyerEvents" -> 1|>, Identity]; +PackageScope["generateMultihistory"] +PackageScope["generateSingleHistory"] + +declareGenerator[GenerateMultihistory, generateMultihistory, <||>, Identity]; +declareGenerator[GenerateSingleHistory, generateSingleHistory, <|"MaxDestroyerEvents" -> 1|>, Identity]; From 21fe0ed461f1d40ad60ecd3d16b1bef5afb2b31b Mon Sep 17 00:00:00 2001 From: Max Piskunov Date: Thu, 8 Jul 2021 06:33:04 -0500 Subject: [PATCH 06/33] Update README of generators. --- Documentation/Generators/README.md | 31 ++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/Documentation/Generators/README.md b/Documentation/Generators/README.md index 808ae62b..0b34a97e 100644 --- a/Documentation/Generators/README.md +++ b/Documentation/Generators/README.md @@ -10,12 +10,13 @@ multiple branches of nondeterministic systems simultaneously. That is done by ap tokens and keeping events and tokens instead of states in [`Multihistory`](/Documentation/Types/Multihistory/README.md) objects. We can reconstruct the states from that information afterwards. -Most systems, however, cannot be evaluated completely. And there are multiple groups of parameters to control how to -perform a partial evaluation. One needs to decide [which events to include](EventSelectionParameters.md), in -[which order](EventOrderingFunctions.md), and [when to terminate the evaluation](StoppingConditionParameters.md). +There are parameters that control how this evaluation is done. Some of them control which events to select, which is +essential in cases where the system does not terminate. Other parameters might control how to deduplicate identical +tokens, etc. Different generators correspond to different settings of parameters. Additional parameters can also be +specified similar to options. -For example, in a [`MultisetSubstitutionSystem`](/Documentation/Systems/MultisetSubstitutionSystem.md) we can generate -a single history (no nondeterministic branching): +For example, [`GenerateSingleHistory`](GenerateSingleHistory.md) corresponds to +[`"MaxDestroyerEvents" -> 1`](MaxDestroyerEvents.md) and thus does produce nondeterministic branching: ```wl In[] := #["ExpressionsEventsGraph", VertexLabels -> Placed[Automatic, After]] & @ @@ -25,7 +26,8 @@ In[] := #["ExpressionsEventsGraph", VertexLabels -> Placed[Automatic, After]] & -or multiple histories. Note different events (orange) using the same tokens (light blue): +We can also use a more generate [`GenerateMultihistory`](GenerateMultihistory.md) and specify +[`"MaxDestroyerEvents"`](MaxDestroyerEvents.md) manually. ```wl In[] := #["ExpressionsEventsGraph", VertexLabels -> Placed[Automatic, After]] & @ @@ -41,15 +43,16 @@ The same generators support multiple systems. In addition to `HypergraphSubstitutionSystem`, `StringSubstitutionSystem`, etc. Many of these systems have shared evaluation parameters. -[`GenerateMultihistory`](GenerateMultihistory.md) is the universal generator. It can generate everything that the -specialized `GenerateSingleHistory` and `GenerateAllHistories` can produce. However, it is more verbose, which can -make the code harder to read. - * Introspection: * [`$SetReplaceSystems`]($SetReplaceSystems.md) — yields the list of all implemented systems + * [`$SetReplaceGenerators`]($SetReplaceGenerators.md) — yields the list of all generators + * [`SetReplaceSystemParameters`](SetReplaceSystemParameters.md) — yields the list of parameters for a system * Generators: - * [`GenerateMultihistory`](GenerateMultihistory.md) — the most customizable and explicit generator + * [`GenerateMultihistory`](GenerateMultihistory.md) — the universal generator for multihistories + * [`GenerateSingleHistory`](GenerateSingleHistory.md) — sets `"MaxDestroyerEvents" -> 1` * Parameters: - * [`EventSelectionParameters`](EventSelectionParameters.md) — determines which events to include - * [`EventOrderingFunctions`](EventOrderingFunctions.md) — determines the order of events - * [`StoppingConditionParameters`](StoppingConditionParameters.md) — determines when to stop evaluation + * [`"MaxDestroyerEvents"`](MaxDestroyerEvents.md) — allows one to switch between single and multihistories + * [`"MinEventInputs"`](MinEventInputs.md) + * [`"MaxEventInputs"`](MaxEventInputs.md) + * [`"MaxEvents"`](MaxEvents.md) + * [`"MaxGeneration"`](MaxGeneration.md) From 29314d2c8d85dd4eb859892b9852f146be5cfcea Mon Sep 17 00:00:00 2001 From: Max Piskunov Date: Thu, 8 Jul 2021 08:45:26 -0500 Subject: [PATCH 07/33] Separate parameter and system declarations. --- Kernel/A1$generatorSystem.m | 121 +++++++++++++------- Kernel/AtomicStateSystem.m | 8 +- Kernel/MultisetSubstitutionSystem.m | 15 +-- Kernel/{generators.m => systemGenerators.m} | 4 +- Kernel/systemParameters.m | 9 ++ 5 files changed, 97 insertions(+), 60 deletions(-) rename Kernel/{generators.m => systemGenerators.m} (52%) create mode 100644 Kernel/systemParameters.m diff --git a/Kernel/A1$generatorSystem.m b/Kernel/A1$generatorSystem.m index 97ed971d..762b35a9 100644 --- a/Kernel/A1$generatorSystem.m +++ b/Kernel/A1$generatorSystem.m @@ -7,7 +7,8 @@ PackageExport["SetReplaceSystemParameters"] PackageScope["declareSystem"] -PackageScope["declareGenerator"] +PackageScope["declareSystemGenerator"] +PackageScope["declareSystemParameter"] PackageScope["autoList"] PackageScope["initializeSystemGenerators"] @@ -15,37 +16,28 @@ $systemImplementations = <||>; (* system -> implementationFunction *) $systemInitPatterns = <||>; (* system -> pattern *) -$systemParameters = <||>; (* system -> <|parameter -> {default, pattern}, ...|> *) +$systemParameters = <||>; (* system -> {parameter, ...} *) $systemParameterDependencies = <||>; (* system -> logical expressions on parameter keys *) -(* Every system implementation needs to call this function in order to be usable through GenerateEventSet and other \ +(* Every system implementation needs to call this function in order to be usable through GenerateMultihistory and other generators. *) -(* The metadata about parameters has the form {default, pattern} and is used to automatically check the arguments. The - pattern should not contain any internal symbols as it is displayed to users in error messages. Further, the logical - expression in the last argument will check if all required parameters are specified. Some parameters may require - others to be specified, e.g., Implies["MaxDestroyerEvents" || "MaxEvents", "EventOrder"] means that if - "MaxDestroyerEvents" or "MaxEvents" is specified, "EventOrder" must be specified as well. - The implementation function can expect all specified parameters present (substituted with defaults if missing) and - all values satisfying the constraints (substituted with defaults if missing). *) +(* The third argument is the pattern that the init should satisfy. *) -(* _List is the pattern that the init should satisfy. *) - -(* autoList is a special head useful for, e.g., "EventOrder". It takes a pattern as its argument. It allows a list with - echo element matching that pattern. Alternatively, it can accept a single value matching the pattern, in which case a - list around it will be created automatically and passed to the system generator. *) +(* Parameters in the fourth argument should be declared with declareSystemParameter. Their values are guaranteed to + match the pattern from the declaration. Further, the logical expression in the last argument will check if all + required parameters are specified. Some parameters may require others to be specified, e.g., + Implies["MaxDestroyerEvents" || "MaxEvents", "EventOrder"] means that if "MaxDestroyerEvents" or "MaxEvents" is + specified, "EventOrder" must be specified as well. The implementation function can expect all specified parameters + present (substituted with defaults if missing) and all values satisfying the constraints (substituted with defaults + if missing). *) (* For example, - declareSystem[ - MultisetSubstitutionSystem, - generateMultisetSubstitutionSystem, - _List, - <|"MaxGeneration" -> {Infinity, _ ? (# >= 0 &)}, - "MinEventInputs" -> {0, _ ? (# >= 0 &)}, - "MaxDestroyerEvents" -> {Infinity, _ ? (# >= 0 &)} - "MaxEvents" -> {Infinity, _ ? (# >= 0 &)}, - "EventOrder" -> {{"Any"}, autoList["Any" | "Random" | "InputCount" | "SortedInputTokenIndices" | "RuleIndex"]}|>, - Implies["MaxDestroyerEvents" || "MaxEvents", "EventOrder"]] *) + declareSystem[MultisetSubstitutionSystem, + generateMultisetSubstitutionSystem, + _List, + {"MaxGeneration", "MinEventInputs", "MaxDestroyerEvents", "MaxEvents", "EventOrder"}, + Implies["MaxDestroyerEvents" || "MaxEvents", "EventOrder"]] *) (* The implementation function is then called as generateMultisetSubstitutionSystem[MultisetSubstitutionSystem[rules], init, parameters] *) @@ -53,7 +45,7 @@ all values satisfying the constraints (substituted with defaults if missing). *) declareSystem[systemType_, implementationFunction_, initPattern_, - parameters_Association /; AllTrue[Values @ parameters, MatchQ[{_, _}]], + parameters_List, dependencies_ ? SatisfiableQ] := ( $systemImplementations[systemType] = implementationFunction; $systemInitPatterns[systemType] = initPattern; @@ -61,6 +53,12 @@ all values satisfying the constraints (substituted with defaults if missing). *) $systemParameterDependencies[systemType] = dependencies; ); +declareMessage[General::unsatisfiableParameterDependencies, + "Internal error. Parameter constraints `constraints` for `system` are not satisfyable."]; +declareMultihistoryGenerator[systemType_, _, _, _List, dependencies_] := + message[SetReplace, + Failure["unsatisfiableParameterDependencies", <|"constraints" -> dependencies, "system" -> systemType|>]]; + declareMessage[General::invalidGeneratorDeclaration, "Internal error. Multihistory generator is declared incorrectly with arguments `args`."]; declareMultihistoryGenerator[args___] := @@ -78,20 +76,36 @@ all values satisfying the constraints (substituted with defaults if missing). *) (* For example, - declareGenerator[EvaluateSingleHistory, evaluateSingleHistory, <|"MaxDestroyerEvents" -> 1|>, FinalState] + declareSystemGenerator[EvaluateSingleHistory, evaluateSingleHistory, <|"MaxDestroyerEvents" -> 1|>, FinalState] - Note that the constraint in the last argument of declareGenerator still needs to be specified, which - means "EventOrder" is now a required parameter. *) + Note that the constraint in the last argument of declareSystemGenerator still needs to be specified, which means + "EventOrder" is now a required parameter. *) (* evaluateSingleHistory is a PackageScope symbol that will throw exceptions instead of returning unevaluated. It cannot be used in operator form. *) -declareGenerator[publicSymbol_, packageScopeSymbol_, parameterValues_, property_ : Identity] := ( +declareSystemGenerator[publicSymbol_, packageScopeSymbol_, parameterValues_, property_ : Identity] := ( $generatorPackageScopeSymbols[publicSymbol] = packageScopeSymbol; $generatorParameters[publicSymbol] = parameterValues; $generatorProperties[publicSymbol] = property; ); +(* Parameter declaration *) + +$parameterDefaults = <||>; +$parameterPatterns = <||>; + +(* Parameters are like protocols. Systems can declare that they implement them. Some generators require some parameters + to be supported and define values for them. To declare a new parameter, one needs to specify a default value (which + usually disables whatever the parameter is doing) and a pattern the parameter value should match. *) + +(* declareSystemParameter["MaxGeneration", Infinity, _ ? (GreaterEqualThan[0])] *) + +declareSystemParameter[name_, defaultValue_, pattern_] := ( + $parameterDefaults[name] = defaultValue; + $parameterPatterns[name] = pattern; +); + (* Initialization *) (* It would be best to only show autocompletions for specific-system keys, but it does not seem to be possible because @@ -107,10 +121,26 @@ all values satisfying the constraints (substituted with defaults if missing). *) MultisetSubstitutionSystem. "; +declareMessage[ + General::unknownSystemParameters, "Parameters `parameters` are implemented by `system` but is not declared."]; +declareMessage[ + General::unknownGeneratorParameters, "Parameters `parameters` are set by `generator` but is not declared."]; + initializeSystemGenerators[] := Module[{parameterKeys, maxParameterCount}, $SetReplaceSystems = Sort @ Keys @ $systemImplementations; $SetReplaceGenerators = Sort @ Keys @ $generatorParameters; - parameterKeys = Union @ Catenate[Keys /@ Values[$systemParameters]]; + parameterKeys = Keys[$parameterDefaults]; + With[{missingParameters = Complement[$systemParameters[#], parameterKeys]}, + If[missingParameters =!= {}, + message[SetReplace, Failure["unknownSystemParameters", <|"parameters" -> missingParameters, "system" -> #|>]]; + ]; + ] & /@ $SetReplaceSystems; + With[{missingParameters = Complement[Keys @ $generatorParameters[#], parameterKeys]}, + If[missingParameters =!= {}, + message[ + SetReplace, Failure["unknownGeneratorParameters", <|"parameters" -> missingParameters, "generator" -> #|>]]; + ]; + ] & /@ $SetReplaceGenerators; maxParameterCount = Length @ parameterKeys; (* This has quadratic complexity in parameter count. But it does not seem to be possible to define the same set of completion strings for a range of arguments. *) @@ -147,6 +177,7 @@ all values satisfying the constraints (substituted with defaults if missing). *) MatchQ[init, Lookup[$systemInitPatterns, Head[system], _]] := ModuleScope[ implementation = $systemImplementations[Head[system]]; If[MissingQ[implementation], throw[Failure["unknownSystem", <|"system" -> system|>]]]; + checkSystemGeneratorCompatibility[Head[system], generator]; $generatorProperties[generator] @ $systemImplementations[Head[system]][system, init, parseParameters[generator, Head[system]][parameters]] ]; @@ -161,6 +192,16 @@ all values satisfying the constraints (substituted with defaults if missing). *) throw[Failure["argNotInit", <|"arg" -> arg, "pattern" -> $systemInitPatterns[Head[system]]|>]]; ]; +declareMessage[ + General::incompatibleSystem, "`generator` requires `parameters` parameters, which `system` does not implement."]; +checkSystemGeneratorCompatibility[system_, generator_] := With[{ + missingParameters = Complement[Keys @ $generatorParameters[generator], $systemParameters[system]]}, + If[missingParameters =!= {}, + throw[Failure[ + "incompatibleSystem", <|"generator" -> generator, "parameters" -> missingParameters, "system" -> system|>]]; + ]; +]; + parseParameters[generator_, system_][parameters___] := addMissingParameters[generator, system] @ checkParameters[generator, system] @ Association[Join @@ collectParameters /@ {parameters}]; @@ -180,11 +221,11 @@ all values satisfying the constraints (substituted with defaults if missing). *) checkParameter[generator_, system_][key_, value_] := ( checkParameterKeyIsRecognized[system][key]; checkParameterKeyIsNotForbidden[generator][key]; - checkParameterValueMatchesPattern[system][key, value]; + checkParameterValueMatchesPattern[key, value]; ); declareMessage[General::unknownParameter, "`system` in `expr` does not support `parameter` parameter."]; -checkParameterKeyIsRecognized[system_][key_] /; !KeyExistsQ[$systemParameters[system], key] := +checkParameterKeyIsRecognized[system_][key_] /; !MemberQ[$systemParameters[system], key] := throw[Failure["unknownParameter", <|"system" -> system, "parameter" -> key|>]]; declareMessage[General::forbiddenParameter, "`parameter` in `expr` cannot be used with `generator`."]; @@ -193,9 +234,9 @@ all values satisfying the constraints (substituted with defaults if missing). *) declareMessage[ General::invalidParameter, "`parameter` value `value` in `expr` should match `pattern`."]; -checkParameterValueMatchesPattern[system_][key_, value_] /; !MatchQ[value, $systemParameters[system][key][[2]]] := +checkParameterValueMatchesPattern[key_, value_] /; !MatchQ[value, $parameterPatterns[key]] := throw[Failure[ - "invalidParameter", <|"parameter" -> key, "value" -> value, "pattern" -> $systemParameters[system][key][[2]]|>]]; + "invalidParameter", <|"parameter" -> key, "value" -> value, "pattern" -> $parameterPatterns[key]|>]]; simplifyParameterCondition[generator_, system_, specifiedKeys_] := FullSimplify[ @@ -205,7 +246,7 @@ all values satisfying the constraints (substituted with defaults if missing). *) FullSimplify[ $systemParameterDependencies[system] /. Alternatives @@ Join[specifiedKeys, Keys @ $generatorParameters[generator]] -> True /. - Alternatives @@ Keys[$systemParameters[system]] -> False] + Alternatives @@ $systemParameters[system] -> False] compatibleParametersQ[___] := False declareMessage[General::incompatibleParameters, @@ -219,7 +260,7 @@ all values satisfying the constraints (substituted with defaults if missing). *) throw[Failure["missingParameters", <|"missingParameters" -> simplifyParameterCondition[generator, system, keys]|>]]; addMissingParameters[generator_, system_][parameters_] := - Join[$systemParameters[system][[All, 1]], parameters, $generatorParameters[generator]]; + Join[KeyTake[$parameterDefaults, $systemParameters[system]], parameters, $generatorParameters[generator]]; (* Introspection functions *) @@ -234,7 +275,5 @@ all values satisfying the constraints (substituted with defaults if missing). *) result /; !FailureQ[result] ]; -setReplaceSystemParameters[system_Symbol | system_Symbol[___]] /; KeyExistsQ[$systemParameters, system] := - Keys @ $systemParameters[system]; - -setReplaceSystemParameters[system_] := throw[Failure["unknownSystem", <|"system" -> system|>]]; +setReplaceSystemParameters[system_Symbol[___] | system_] := + Lookup[$systemParameters, system, throw[Failure["unknownSystem", <|"system" -> system|>]]]; diff --git a/Kernel/AtomicStateSystem.m b/Kernel/AtomicStateSystem.m index 62b43faf..2856ca83 100644 --- a/Kernel/AtomicStateSystem.m +++ b/Kernel/AtomicStateSystem.m @@ -13,13 +13,7 @@ SyntaxInformation[AtomicStateSystem] = {"ArgumentsPattern" -> {rules_}}; declareSystem[ - AtomicStateSystem, - generateAtomicStateSystem, - _, - <|"MaxGeneration" -> {Infinity, _ ? (GreaterEqualThan[0])}, - "MaxDestroyerEvents" -> {Infinity, _ ? (GreaterEqualThan[0])}, - "MaxEvents" -> {Infinity, _ ? (GreaterEqualThan[0])}|>, - True]; + AtomicStateSystem, generateAtomicStateSystem, _, {"MaxGeneration", "MaxDestroyerEvents", "MaxEvents"}, True]; generateAtomicStateSystem[AtomicStateSystem[rules___], init_, parameters_] := ModuleScope[ toAtomicStateMultihistory[rules] @ generateMultihistory[ diff --git a/Kernel/MultisetSubstitutionSystem.m b/Kernel/MultisetSubstitutionSystem.m index 6210233a..45206e51 100644 --- a/Kernel/MultisetSubstitutionSystem.m +++ b/Kernel/MultisetSubstitutionSystem.m @@ -13,16 +13,11 @@ SyntaxInformation[MultisetSubstitutionSystem] = {"ArgumentsPattern" -> {rules_}}; -declareSystem[ - MultisetSubstitutionSystem, - generateMultisetSubstitutionSystem, - _List, - <|"MaxGeneration" -> {Infinity, _ ? (GreaterEqualThan[0])}, - "MaxDestroyerEvents" -> {Infinity, _ ? (GreaterEqualThan[0])}, - "MinEventInputs" -> {0, _ ? (GreaterEqualThan[0])}, - "MaxEventInputs" -> {Infinity, _ ? (GreaterEqualThan[0])}, - "MaxEvents" -> {Infinity, _ ? (GreaterEqualThan[0])}|>, - True]; +declareSystem[MultisetSubstitutionSystem, + generateMultisetSubstitutionSystem, + _List, + {"MaxGeneration", "MaxDestroyerEvents", "MinEventInputs", "MaxEventInputs", "MaxEvents"}, + True]; generateMultisetSubstitutionSystem[MultisetSubstitutionSystem[rawRules___], init_, parameters_] := Block[{ expressions, eventRuleIndices, eventInputs, eventOutputs, eventGenerations, expressionCreatorEvents, diff --git a/Kernel/generators.m b/Kernel/systemGenerators.m similarity index 52% rename from Kernel/generators.m rename to Kernel/systemGenerators.m index 134de65d..9d47aa2b 100644 --- a/Kernel/generators.m +++ b/Kernel/systemGenerators.m @@ -8,5 +8,5 @@ PackageScope["generateMultihistory"] PackageScope["generateSingleHistory"] -declareGenerator[GenerateMultihistory, generateMultihistory, <||>, Identity]; -declareGenerator[GenerateSingleHistory, generateSingleHistory, <|"MaxDestroyerEvents" -> 1|>, Identity]; +declareSystemGenerator[GenerateMultihistory, generateMultihistory, <||>, Identity]; +declareSystemGenerator[GenerateSingleHistory, generateSingleHistory, <|"MaxDestroyerEvents" -> 1|>, Identity]; diff --git a/Kernel/systemParameters.m b/Kernel/systemParameters.m new file mode 100644 index 00000000..adbb238d --- /dev/null +++ b/Kernel/systemParameters.m @@ -0,0 +1,9 @@ +Package["SetReplace`"] + +declareSystemParameter @@@ { + {"MaxGeneration", Infinity, _ ? (GreaterEqualThan[0])}, + {"MaxDestroyerEvents", Infinity, _ ? (GreaterEqualThan[0])}, + {"MinEventInputs", 0, _ ? (GreaterEqualThan[0])}, + {"MaxEventInputs", Infinity, _ ? (GreaterEqualThan[0])}, + {"MaxEvents", Infinity, _ ? (GreaterEqualThan[0])} +}; From fc7009197e9e52d0711df65fe80337974406fdd9 Mon Sep 17 00:00:00 2001 From: Max Piskunov Date: Thu, 8 Jul 2021 09:29:58 -0500 Subject: [PATCH 08/33] Add usage to generators. --- Kernel/A1$generatorSystem.m | 19 +++++++++++++++++-- Kernel/systemGenerators.m | 15 +++++++++++++-- 2 files changed, 30 insertions(+), 4 deletions(-) diff --git a/Kernel/A1$generatorSystem.m b/Kernel/A1$generatorSystem.m index 762b35a9..8c869b39 100644 --- a/Kernel/A1$generatorSystem.m +++ b/Kernel/A1$generatorSystem.m @@ -76,7 +76,11 @@ (* For example, - declareSystemGenerator[EvaluateSingleHistory, evaluateSingleHistory, <|"MaxDestroyerEvents" -> 1|>, FinalState] + declareSystemGenerator[EvaluateSingleHistory, + evaluateSingleHistory, + <|"MaxDestroyerEvents" -> 1|>, + FinalState, + "yields a single history object."] Note that the constraint in the last argument of declareSystemGenerator still needs to be specified, which means "EventOrder" is now a required parameter. *) @@ -84,10 +88,21 @@ (* evaluateSingleHistory is a PackageScope symbol that will throw exceptions instead of returning unevaluated. It cannot be used in operator form. *) -declareSystemGenerator[publicSymbol_, packageScopeSymbol_, parameterValues_, property_ : Identity] := ( +systemUsage = "* A list of all supported systems can be obtained with $SetReplaceSystems."; +initUsage = "* init$ is the initial state, the format of which depends on the system$."; +parametersUsage = "* parameters$ is either a Sequence, a List or an Association of key-value rules. A list of " <> + "parameters can be obtained with SetReplaceSystemParameters[system$]."; + +declareSystemGenerator[publicSymbol_, packageScopeSymbol_, parameterValues_, property_ : Identity, usage_] := ( $generatorPackageScopeSymbols[publicSymbol] = packageScopeSymbol; $generatorParameters[publicSymbol] = parameterValues; $generatorProperties[publicSymbol] = property; + SetUsage @ Evaluate @ StringRiffle[ + {ToString[publicSymbol] <> "[system$, init$, parameters$] " <> usage, + systemUsage, + initUsage, + parametersUsage}, + "\n"]; ); (* Parameter declaration *) diff --git a/Kernel/systemGenerators.m b/Kernel/systemGenerators.m index 9d47aa2b..da040bec 100644 --- a/Kernel/systemGenerators.m +++ b/Kernel/systemGenerators.m @@ -8,5 +8,16 @@ PackageScope["generateMultihistory"] PackageScope["generateSingleHistory"] -declareSystemGenerator[GenerateMultihistory, generateMultihistory, <||>, Identity]; -declareSystemGenerator[GenerateSingleHistory, generateSingleHistory, <|"MaxDestroyerEvents" -> 1|>, Identity]; +declareSystemGenerator[ + GenerateMultihistory, + generateMultihistory, + <||>, + Identity, + "yields a Multihistory object of the evaluation of a specified system$ starting from an initial state init$."]; + +declareSystemGenerator[ + GenerateSingleHistory, + generateSingleHistory, + <|"MaxDestroyerEvents" -> 1|>, + Identity, + "yields a single history of the evaluation of a specified system$ starting from an initial state init$."]; From 077487cd7f2412ad5d12dd3534f26b6efa237765 Mon Sep 17 00:00:00 2001 From: Max Piskunov Date: Thu, 8 Jul 2021 09:42:50 -0500 Subject: [PATCH 09/33] Better organize property declarations. --- Kernel/systemParameters.m | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/Kernel/systemParameters.m b/Kernel/systemParameters.m index adbb238d..1c60e781 100644 --- a/Kernel/systemParameters.m +++ b/Kernel/systemParameters.m @@ -1,9 +1,14 @@ Package["SetReplace`"] -declareSystemParameter @@@ { - {"MaxGeneration", Infinity, _ ? (GreaterEqualThan[0])}, - {"MaxDestroyerEvents", Infinity, _ ? (GreaterEqualThan[0])}, - {"MinEventInputs", 0, _ ? (GreaterEqualThan[0])}, - {"MaxEventInputs", Infinity, _ ? (GreaterEqualThan[0])}, - {"MaxEvents", Infinity, _ ? (GreaterEqualThan[0])} +(* Event-selection parameters *) + +declareSystemParameter[##, _ ? (GreaterEqualThan[0])] & @@@ { + {"MaxGeneration", Infinity}, + {"MaxDestroyerEvents", Infinity}, + {"MinEventInputs", 0}, + {"MaxEventInputs", Infinity} }; + +(* Stopping-condition parameters *) + +declareSystemParameter["MaxEvents", Infinity, _ ? (GreaterEqualThan[0])]; From dd3b8eed5a8febba5fcf0c834550f6c8695802a0 Mon Sep 17 00:00:00 2001 From: Max Piskunov Date: Thu, 8 Jul 2021 10:23:35 -0500 Subject: [PATCH 10/33] Change system parameters to symbols. --- Kernel/A1$generatorSystem.m | 40 +++++++++++++---------------- Kernel/AtomicStateSystem.m | 5 ++-- Kernel/MultisetSubstitutionSystem.m | 2 +- Kernel/systemGenerators.m | 2 +- Kernel/systemParameters.m | 19 +++++++++----- 5 files changed, 35 insertions(+), 33 deletions(-) diff --git a/Kernel/A1$generatorSystem.m b/Kernel/A1$generatorSystem.m index 8c869b39..d4210970 100644 --- a/Kernel/A1$generatorSystem.m +++ b/Kernel/A1$generatorSystem.m @@ -27,17 +27,17 @@ (* Parameters in the fourth argument should be declared with declareSystemParameter. Their values are guaranteed to match the pattern from the declaration. Further, the logical expression in the last argument will check if all required parameters are specified. Some parameters may require others to be specified, e.g., - Implies["MaxDestroyerEvents" || "MaxEvents", "EventOrder"] means that if "MaxDestroyerEvents" or "MaxEvents" is - specified, "EventOrder" must be specified as well. The implementation function can expect all specified parameters - present (substituted with defaults if missing) and all values satisfying the constraints (substituted with defaults - if missing). *) + Implies[MaxDestroyerEvents || MaxEvents, EventOrder] means that if MaxDestroyerEvents or MaxEvents is specified, \ + EventOrder must be specified as well. The implementation function can expect all specified parameters present \ + (substituted with defaults if missing) and all values satisfying the constraints (substituted with defaults if \ + missing). *) (* For example, declareSystem[MultisetSubstitutionSystem, generateMultisetSubstitutionSystem, _List, - {"MaxGeneration", "MinEventInputs", "MaxDestroyerEvents", "MaxEvents", "EventOrder"}, - Implies["MaxDestroyerEvents" || "MaxEvents", "EventOrder"]] *) + {MaxGeneration, MinEventInputs, MaxDestroyerEvents, MaxEvents, EventOrder}, + Implies[MaxDestroyerEvents || MaxEvents, EventOrder]] *) (* The implementation function is then called as generateMultisetSubstitutionSystem[MultisetSubstitutionSystem[rules], init, parameters] *) @@ -78,12 +78,12 @@ declareSystemGenerator[EvaluateSingleHistory, evaluateSingleHistory, - <|"MaxDestroyerEvents" -> 1|>, + <|MaxDestroyerEvents -> 1|>, FinalState, "yields a single history object."] Note that the constraint in the last argument of declareSystemGenerator still needs to be specified, which means - "EventOrder" is now a required parameter. *) + EventOrder is now a required parameter. *) (* evaluateSingleHistory is a PackageScope symbol that will throw exceptions instead of returning unevaluated. It cannot be used in operator form. *) @@ -114,11 +114,15 @@ to be supported and define values for them. To declare a new parameter, one needs to specify a default value (which usually disables whatever the parameter is doing) and a pattern the parameter value should match. *) -(* declareSystemParameter["MaxGeneration", Infinity, _ ? (GreaterEqualThan[0])] *) +(* declareSystemParameter[MaxGeneration, + Infinity, + _ ? (GreaterEqualThan[0]), + "is a parameter specifying the maximum generations of tokens that will be created."] *) -declareSystemParameter[name_, defaultValue_, pattern_] := ( +declareSystemParameter[name_, defaultValue_, pattern_, usage_] := ( $parameterDefaults[name] = defaultValue; $parameterPatterns[name] = pattern; + SetUsage @ Evaluate[ToString[name] <> " " <> usage]; ); (* Initialization *) @@ -141,31 +145,23 @@ declareMessage[ General::unknownGeneratorParameters, "Parameters `parameters` are set by `generator` but is not declared."]; -initializeSystemGenerators[] := Module[{parameterKeys, maxParameterCount}, +initializeSystemGenerators[] := ( $SetReplaceSystems = Sort @ Keys @ $systemImplementations; $SetReplaceGenerators = Sort @ Keys @ $generatorParameters; - parameterKeys = Keys[$parameterDefaults]; - With[{missingParameters = Complement[$systemParameters[#], parameterKeys]}, + With[{missingParameters = Complement[$systemParameters[#], Keys[$parameterDefaults]]}, If[missingParameters =!= {}, message[SetReplace, Failure["unknownSystemParameters", <|"parameters" -> missingParameters, "system" -> #|>]]; ]; ] & /@ $SetReplaceSystems; - With[{missingParameters = Complement[Keys @ $generatorParameters[#], parameterKeys]}, + With[{missingParameters = Complement[Keys @ $generatorParameters[#], Keys[$parameterDefaults]]}, If[missingParameters =!= {}, message[ SetReplace, Failure["unknownGeneratorParameters", <|"parameters" -> missingParameters, "generator" -> #|>]]; ]; ] & /@ $SetReplaceGenerators; - maxParameterCount = Length @ parameterKeys; - (* This has quadratic complexity in parameter count. But it does not seem to be possible to define the same set of - completion strings for a range of arguments. *) - With[{ - completionSpec = Join[{0}, Table[parameterKeys, maxParameterCount + 1]]}, - FE`Evaluate[FEPrivate`AddSpecialArgCompletion[# -> completionSpec]] & /@ ToString /@ $SetReplaceGenerators; - ]; Scan[(SyntaxInformation[#] = {"ArgumentsPattern" -> {system_, init_., parameters___}}) &, $SetReplaceGenerators]; defineGeneratorImplementation /@ Keys @ $generatorParameters; -]; +); declareMessage[General::argNotInit, "The init `arg` in `expr` should match `pattern`."]; declareMessage[General::unknownSystem, "`system` is not a recognized SetReplace system."]; diff --git a/Kernel/AtomicStateSystem.m b/Kernel/AtomicStateSystem.m index 2856ca83..33bff92b 100644 --- a/Kernel/AtomicStateSystem.m +++ b/Kernel/AtomicStateSystem.m @@ -12,14 +12,13 @@ SyntaxInformation[AtomicStateSystem] = {"ArgumentsPattern" -> {rules_}}; -declareSystem[ - AtomicStateSystem, generateAtomicStateSystem, _, {"MaxGeneration", "MaxDestroyerEvents", "MaxEvents"}, True]; +declareSystem[AtomicStateSystem, generateAtomicStateSystem, _, {MaxGeneration, MaxDestroyerEvents, MaxEvents}, True]; generateAtomicStateSystem[AtomicStateSystem[rules___], init_, parameters_] := ModuleScope[ toAtomicStateMultihistory[rules] @ generateMultihistory[ MultisetSubstitutionSystem[toMultisetRules[rules]], {init}, - Join[parameters, <|"MinEventInputs" -> 1, "MaxEventInputs" -> 1|>]] + Join[parameters, <|MinEventInputs -> 1, MaxEventInputs -> 1|>]] ]; (* Parsing *) diff --git a/Kernel/MultisetSubstitutionSystem.m b/Kernel/MultisetSubstitutionSystem.m index 45206e51..9af7ee8b 100644 --- a/Kernel/MultisetSubstitutionSystem.m +++ b/Kernel/MultisetSubstitutionSystem.m @@ -16,7 +16,7 @@ declareSystem[MultisetSubstitutionSystem, generateMultisetSubstitutionSystem, _List, - {"MaxGeneration", "MaxDestroyerEvents", "MinEventInputs", "MaxEventInputs", "MaxEvents"}, + {MaxGeneration, MaxDestroyerEvents, MinEventInputs, MaxEventInputs, MaxEvents}, True]; generateMultisetSubstitutionSystem[MultisetSubstitutionSystem[rawRules___], init_, parameters_] := Block[{ diff --git a/Kernel/systemGenerators.m b/Kernel/systemGenerators.m index da040bec..748f5a17 100644 --- a/Kernel/systemGenerators.m +++ b/Kernel/systemGenerators.m @@ -18,6 +18,6 @@ declareSystemGenerator[ GenerateSingleHistory, generateSingleHistory, - <|"MaxDestroyerEvents" -> 1|>, + <|MaxDestroyerEvents -> 1|>, Identity, "yields a single history of the evaluation of a specified system$ starting from an initial state init$."]; diff --git a/Kernel/systemParameters.m b/Kernel/systemParameters.m index 1c60e781..0df32203 100644 --- a/Kernel/systemParameters.m +++ b/Kernel/systemParameters.m @@ -2,13 +2,20 @@ (* Event-selection parameters *) -declareSystemParameter[##, _ ? (GreaterEqualThan[0])] & @@@ { - {"MaxGeneration", Infinity}, - {"MaxDestroyerEvents", Infinity}, - {"MinEventInputs", 0}, - {"MaxEventInputs", Infinity} +PackageExport["MaxGeneration"] +PackageExport["MaxDestroyerEvents"] +PackageExport["MinEventInputs"] +PackageExport["MaxEventInputs"] + +declareSystemParameter[#, #2, _ ? (GreaterEqualThan[0]), #3] & @@@ { + {MaxGeneration, Infinity, "is a parameter specifying the maximum generations of tokens that will be created."}, + {MaxDestroyerEvents, Infinity, "..."}, + {MinEventInputs, 0, "..."}, + {MaxEventInputs, Infinity, "..."} }; (* Stopping-condition parameters *) -declareSystemParameter["MaxEvents", Infinity, _ ? (GreaterEqualThan[0])]; +PackageExport["MaxEvents"] + +declareSystemParameter[MaxEvents, Infinity, _ ? (GreaterEqualThan[0]), "..."]; From 0fb464fbff066de2c1db2337169c0e5be7b1fa02 Mon Sep 17 00:00:00 2001 From: Max Piskunov Date: Thu, 8 Jul 2021 13:21:01 -0500 Subject: [PATCH 11/33] Write usage messages for all parameters. --- Kernel/systemParameters.m | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/Kernel/systemParameters.m b/Kernel/systemParameters.m index 0df32203..5140da32 100644 --- a/Kernel/systemParameters.m +++ b/Kernel/systemParameters.m @@ -8,14 +8,25 @@ PackageExport["MaxEventInputs"] declareSystemParameter[#, #2, _ ? (GreaterEqualThan[0]), #3] & @@@ { - {MaxGeneration, Infinity, "is a parameter specifying the maximum generations of tokens that will be created."}, - {MaxDestroyerEvents, Infinity, "..."}, - {MinEventInputs, 0, "..."}, - {MaxEventInputs, Infinity, "..."} + {MaxGeneration, + Infinity, + "is an event-selection parameter specifying the maximum generation of created tokens.\n" <> + "* Tokens in init$ are assumed to have a generation 0.\n" <> + "* A generation of an event and its output tokens is defined as the largest generation of its inputs plus one."}, + {MaxDestroyerEvents, + Infinity, + "is an event-selection parameter specifying the number of events that can use a single token as their input.\n" <> + "* Setting this to 1 limits evaluation to a single history."}, + {MinEventInputs, 0, "is an event-selection parameter specifying the minimum number of input tokens of events."}, + {MaxEventInputs, Infinity, "is an event-selection parameter specifying the maximum number of input tokens of events."} }; (* Stopping-condition parameters *) PackageExport["MaxEvents"] -declareSystemParameter[MaxEvents, Infinity, _ ? (GreaterEqualThan[0]), "..."]; +declareSystemParameter[ + MaxEvents, + Infinity, + _ ? (GreaterEqualThan[0]), + "is a stopping-condition parameter that stops evaluation after a specified number of events."]; From a76771e93e652fb475d01146d2660b6c64f6aacc Mon Sep 17 00:00:00 2001 From: Max Piskunov Date: Thu, 8 Jul 2021 14:22:48 -0500 Subject: [PATCH 12/33] Update Generators README. --- .../Generators/$SetReplaceGenerators.md | 9 + .../Generators/$SetReplaceSystems.md | 2 +- .../Generators/EventOrderingFunctions.md | 142 --------------- .../Generators/EventSelectionParameters.md | 168 ------------------ .../Generators/GenerateMultihistory.md | 28 +-- .../Generators/GenerateSingleHistory.md | 25 +++ .../Generators/MaxDestroyerEvents.md | 37 ++++ Documentation/Generators/MaxEventInputs.md | 17 ++ Documentation/Generators/MaxEvents.md | 14 ++ Documentation/Generators/MaxGeneration.md | 48 +++++ Documentation/Generators/MinEventInputs.md | 26 +++ Documentation/Generators/README.md | 41 ++++- .../Generators/SetReplaceSystemParameters.md | 16 ++ .../Generators/StoppingConditionParameters.md | 36 ---- .../Images/GenerateSingleHistoryExample.png | Bin 0 -> 30736 bytes 15 files changed, 230 insertions(+), 379 deletions(-) create mode 100644 Documentation/Generators/$SetReplaceGenerators.md delete mode 100644 Documentation/Generators/EventOrderingFunctions.md delete mode 100644 Documentation/Generators/EventSelectionParameters.md create mode 100644 Documentation/Generators/GenerateSingleHistory.md create mode 100644 Documentation/Generators/MaxDestroyerEvents.md create mode 100644 Documentation/Generators/MaxEventInputs.md create mode 100644 Documentation/Generators/MaxEvents.md create mode 100644 Documentation/Generators/MaxGeneration.md create mode 100644 Documentation/Generators/MinEventInputs.md create mode 100644 Documentation/Generators/SetReplaceSystemParameters.md delete mode 100644 Documentation/Generators/StoppingConditionParameters.md create mode 100644 Documentation/Images/GenerateSingleHistoryExample.png diff --git a/Documentation/Generators/$SetReplaceGenerators.md b/Documentation/Generators/$SetReplaceGenerators.md new file mode 100644 index 00000000..9216c191 --- /dev/null +++ b/Documentation/Generators/$SetReplaceGenerators.md @@ -0,0 +1,9 @@ +# $SetReplaceGenerators + +**`$SetReplaceGenerators`** gives the list of all generators that can be used to evaluate +[computational systems](/Documentation/Systems/README.md): + +```wl +In[] := $SetReplaceGenerators +Out[] = {GenerateMultihistory, GenerateSingleHistory} +``` diff --git a/Documentation/Generators/$SetReplaceSystems.md b/Documentation/Generators/$SetReplaceSystems.md index 8a924d14..5a3b1423 100644 --- a/Documentation/Generators/$SetReplaceSystems.md +++ b/Documentation/Generators/$SetReplaceSystems.md @@ -1,7 +1,7 @@ # $SetReplaceSystems **`$SetReplaceSystems`** gives the list of all [computational systems](/Documentation/Systems/README.md) that can be -used with [GenerateMultihistory](/Documentation/Generators/GenerateMultihistory.md) and related functions: +used with [GenerateMultihistory](/Documentation/Generators/GenerateMultihistory.md) and other [generators](README.md): ```wl In[] := $SetReplaceSystems diff --git a/Documentation/Generators/EventOrderingFunctions.md b/Documentation/Generators/EventOrderingFunctions.md deleted file mode 100644 index 1297dbe5..00000000 --- a/Documentation/Generators/EventOrderingFunctions.md +++ /dev/null @@ -1,142 +0,0 @@ -# Event Ordering Functions - -Multiple matches to the same state of a computational system are sometimes possible. For example, the system below can -match any pair of numbers, many of which overlap: - -```wl -In[] := #["ExpressionsEventsGraph", VertexLabels -> Placed[Automatic, After]] & @ - SetReplaceTypeConvert[{WolframModelEvolutionObject, 2}] @ - GenerateMultihistory[MultisetSubstitutionSystem[{a_, b_} /; a < b :> {a + b}], - "MaxGeneration" -> 1, - None, - EventOrderingFunctions[MultisetSubstitutionSystem], - {}] @ - {1, 2, 3, 4} -``` - - - -Event ordering functions control the order in which these matches will be instantiated. - -The importance of that order depends on the system, the rules, and the evaluation parameters. For example, in the -example above, full multihistory is generated up to generation 1. In this case, the same multihistory is generated -regardless of the event ordering, so the event ordering is not important. For this reason, there is no argument for the -event ordering in `GenerateAllHistories` (not yet implemented). - -However, if we evaluate a single history instead, we can get different histories for different orders (different orders -are made here by rearranging the order of the initial state, as -[`MultisetSubstitutionSystem`](/Documentation/Systems/MultisetSubstitutionSystem.md) only supports a single ordering -function at the moment): - -```wl -In[] := #["ExpressionsEventsGraph", VertexLabels -> Placed[Automatic, After]] & /@ - SetReplaceTypeConvert[{WolframModelEvolutionObject, 2}] /@ - GenerateMultihistory[MultisetSubstitutionSystem[{a_, b_} /; a < b :> {a + b}], - "MaxDestroyerEvents" -> 1, - None, - EventOrderingFunctions[MultisetSubstitutionSystem], - {}] /@ - {{1, 2, 3, 4}, {1, 3, 2, 4}} -``` - - - -This system, however, is [confluent](https://en.wikipedia.org/wiki/Confluence_(abstract_rewriting)). So, the final state -will always be the same even if the histories are different, assuming the system is evaluated to completion. - -However, this is not the case for all systems. For example, see what happens if we change `+` to `-`: - -```wl -In[] := #["ExpressionsEventsGraph", VertexLabels -> Placed[Automatic, After]] & /@ - SetReplaceTypeConvert[{WolframModelEvolutionObject, 2}] /@ - GenerateMultihistory[MultisetSubstitutionSystem[{a_, b_} /; a < b :> {a - b}], - "MaxDestroyerEvents" -> 1, - None, - EventOrderingFunctions[MultisetSubstitutionSystem], - {}] /@ - {{1, 2, 3, 5}, {1, 5, 2, 3}} -``` - - - -For this reason, generators such as `GenerateSingleHistory` (not yet implemented) require specification of the ordering -function as one of the arguments, as, without it, the evaluation will be ambiguous. - -**`EventOrderingFunctions`** allows one to obtain the list of event ordering functions that can be used with a -[computational system](/Documentation/Systems/README.md): - -```wl -In[] := EventOrderingFunctions[MultisetSubstitutionSystem] -Out[] = {"InputCount", "SortedInputTokenIndices", "InputTokenIndices", "RuleIndex", "InstantiationIndex"} -``` - -The individual values returned correspond to partial sorting criteria supported by the system. They are used in the -order they are passed to [generators](README.md). The first criterion is applied first. If ambiguities are remaining, -the second criterion is used, etc. - -## InputCount - -As few tokens as possible will be matched. This is particularly useful for systems such as -[`MultisetSubstitutionSystem`](/Documentation/Systems/MultisetSubstitutionSystem.md) where a single rule can match -multiple inputs with different token counts. - -For example, the [multiset](/Documentation/Systems/MultisetSubstitutionSystem.md) pattern `{a___}` will match `{6, 7}` -before `{1, 2, 3}` with this ordering function. - -## SortedInputTokenIndices - -As events are instantiated, each token in a [`Multihistory`](/Documentation/Types/Multihistory/README.md) has an index -corresponding to when that token was first created. (If tokens are created simultaneously, indices correspond to the -order in the rule output or in the initial state.) - -`"SortedInputTokenIndices"` ordering function sorts the tokens in a particular match by index and then selects the -lexicographically smallest result. This corresponds to effectively -`{"MinInputTokenIndex", "SecondMinInputTokenIndex", ...}`. If one of the sorted index lists is a prefix of another, they -are considered equal by this ordering function. [`"InputCount"`](#inputcount) will need to be used to resolve the -ambiguity. - -In other words, this ordering function attempts to match the oldest token possible. And if multiple matches remain, it -attempts to use the oldest of the remaining tokens, etc. - -For example, the [multiset](/Documentation/Systems/MultisetSubstitutionSystem.md) pattern `{a_, b_, c_}` will match -tokens with indices `{7, 1, 6}` before `{3, 2}` (since `1 < 2`), and `{4, 6, 2}` before `{5, 2, 6}` (since `2 == 2` and -`4 < 5`). However, `{3, 2, 1}` and `{3, 4, 1, 2}` will be considered equal by this ordering function as `{1, 2, 3}` is a -prefix of `{1, 2, 3, 4}`. - -## InputTokenIndices - -This function is similar to [`"SortedInputTokenIndices"`](#sortedinputtokenindices), except tokens are not sorted before -being lexicographically compared. This corresponds to greedily matching the first rule input to a token with the -smallest index, then following with the second input, etc. - -For example, the [multiset](/Documentation/Systems/MultisetSubstitutionSystem.md) pattern `{a_, b_, c_}` will match -tokens with indices `{3, 2}` before `{7, 1, 6}` (since `3 < 7`), and `{3, 1, 2}` before `{3, 4}` (since `3 == 3` and -`1 < 4`). Similar to [`"SortedInputTokenIndices"`](#sortedinputtokenindices), `{1, 4}` and `{1, 4, 2}` will be consider -equal by this function, and will be passed to the next one. - -## InputIndex - -This is equivalent to [`"SortedInputTokenIndices"`](#sortedinputtokenindices) and -[`"InputTokenIndices"`](#inputtokenindices) in systems that only take a single token as an input, such as -[`AtomicStateSystem`](/Documentation/Systems/AtomicStateSystem.md). - -## RuleIndex - -This function attempts to use rules in the same order they are specified in the argument for the computational system. -Only if there are no matches for the first rule, the second rule will be attempted, etc. It does not affect single-rule -systems. - -## InstantiationIndex - -In some cases, even the same sequence of input tokens can lead to different outputs. For example, the -[`MultisetSubstitutionSystem`](/Documentation/Systems/MultisetSubstitutionSystem.md) pattern `{a__, b__}` (note -[`BlankSequence`](https://reference.wolfram.com/language/ref/BlankSequence.html)'s) can match tokens `{1, 2, 3}` as -either `{a} -> {1}`, `{b} -> {2, 3}` or `{a} -> {1, 2}`, `{b} -> {3}`, yielding different outputs in a rule such as -`{a__, b__} :> {{a}, {b}}`. - -To resolve this ambiguity, `"InstantiationIndex"` ordering function can be used. The specific order of instantiations -depends on the system. In [`MultisetSubstitutionSystem`](/Documentation/Systems/MultisetSubstitutionSystem.md), the -order is the same as in [`ReplaceList`](https://reference.wolfram.com/language/ref/ReplaceList.html). - -If this ordering is used first, the system only does a single instantiation for each sequence of tokens unless there are -no other matches available. diff --git a/Documentation/Generators/EventSelectionParameters.md b/Documentation/Generators/EventSelectionParameters.md deleted file mode 100644 index 5ab21e99..00000000 --- a/Documentation/Generators/EventSelectionParameters.md +++ /dev/null @@ -1,168 +0,0 @@ -# Event Selection Parameters - -Event selection parameters control which matches will be instantiated during the evaluation. Unlike the -[stopping conditions](StoppingConditionParameters.md), these constraints are local. In other words, the evaluation does -not terminate if any of these constraints are encountered. Only particular matches are skipped instead. - -**`EventSelectionParameters`** allows one to obtain the list of event selection parameters that can be used with a -[computational system](/Documentation/Systems/README.md): - -```wl -In[] := EventSelectionParameters[MultisetSubstitutionSystem] -Out[] = {"MaxGeneration", "MaxDestroyerEvents", "MinEventInputs", "MaxEventInputs"} -``` - -The values returned by this function can be used as keys for the corresponding arguments of [generators](README.md). - -## MaxGeneration - -Roughly speaking, **generation** corresponds to how many "steps" it took to get to a particular token or event starting -from the initial state. More precisely, the generation of the tokens in the initial state is defined to be zero. The -generation of an event is defined as the maximum of the generations of its inputs plus one. The generation of a token is -the same as the generation of its creator event. - -A neat feature of the `TokenEventGraph` property is that it arranges tokens and events in layers corresponding to their -generations. In the following example, the tokens and events are labeled with their generation numbers: - -```wl -In[] := #["ExpressionsEventsGraph", - VertexLabels -> Placed["Name", After, Replace[{{"Expression", n_} :> #["ExpressionGenerations"][[n]], - {"Event", n_} :> #["EventGenerations"][[n]]}]]] & @ - SetReplaceTypeConvert[{WolframModelEvolutionObject, 2}] @ - GenerateMultihistory[MultisetSubstitutionSystem[{a__} /; Total[{a}] == 5 :> {Total[{a}] - 1, Total[{a}] + 1}], - {}, - None, - EventOrderingFunctions[MultisetSubstitutionSystem], - "MaxEvents" -> 3] @ {1, 2, 3} -``` - - - -Restricting the number of generations to one will prevent the last two events from occurring. Note, however, that -another event is created instead: - -```wl -In[] := #["ExpressionsEventsGraph"] & @ SetReplaceTypeConvert[{WolframModelEvolutionObject, 2}] @ - GenerateMultihistory[MultisetSubstitutionSystem[{a__} /; Total[{a}] == 5 :> {Total[{a}] - 1, Total[{a}] + 1}], - "MaxGeneration" -> 1, - None, - EventOrderingFunctions[MultisetSubstitutionSystem], - "MaxEvents" -> 3] @ {1, 2, 3} -``` - - - -Since `"MaxGeneration"` is a selection parameter rather than a [stopping condition](StoppingConditionParameters.md), it -will continue evaluation even after encountering matches exceeding the generations constraint, which might also result -in a different [event ordering](EventOrderingFunctions.md) than if using, e.g., -[`"MaxEvents"`](StoppingConditionParameters.md#maxevents). For this reason, `"MaxGenerations"` (like other selection -parameters) does not have a corresponding termination reason. - -```wl -In[] := #[[2, "TerminationReason"]] & @ - GenerateMultihistory[MultisetSubstitutionSystem[{a__} /; Total[{a}] == 5 :> {Total[{a}] - 1, Total[{a}] + 1}], - "MaxGeneration" -> 1, - None, - EventOrderingFunctions[MultisetSubstitutionSystem], - "MaxEvents" -> 3] @ {1, 2, 3} -Out[] = "Complete" -``` - -## MaxDestroyerEvents - -`"MaxDestroyerEvents"` controls the number of (inconsistent) events that are allowed to take the same token as an input. -If `"MaxDestroyerEvents"` is set to one, a single-history system will be generated similar to `GenerateSingleHistory`: - -```wl -In[] := #["ExpressionsEventsGraph", VertexLabels -> Placed[Automatic, After]] & @ - SetReplaceTypeConvert[{WolframModelEvolutionObject, 2}] @ - GenerateMultihistory[MultisetSubstitutionSystem[{a_, b_} :> {a + b}], - "MaxDestroyerEvents" -> 1, - None, - EventOrderingFunctions[MultisetSubstitutionSystem], - {}] @ {1, 2, 3} -``` - - - -If unset (i.e., set to [`Infinity`](https://reference.wolfram.com/language/ref/Infinity.html)), it will generate a full -multihistory (similar to `GenerateAllHistories`) subject to other selection and stopping parameters: - -```wl -In[] := #["ExpressionsEventsGraph", VertexLabels -> Placed[Automatic, After]] & @ - SetReplaceTypeConvert[{WolframModelEvolutionObject, 2}] @ - GenerateMultihistory[MultisetSubstitutionSystem[{a_, b_} :> {a + b}], - {"MaxDestroyerEvents" -> Infinity, "MaxGeneration" -> 1}, - None, - EventOrderingFunctions[MultisetSubstitutionSystem], - {}] @ {1, 2, 3} -``` - - - -If set to a finite number, it will generate a partial multihistory: - -```wl -In[] := #["ExpressionsEventsGraph", VertexLabels -> Placed[Automatic, After]] & @ - SetReplaceTypeConvert[{WolframModelEvolutionObject, 2}] @ - GenerateMultihistory[MultisetSubstitutionSystem[{a_, b_} :> {a + b}], - "MaxDestroyerEvents" -> 5, - None, - EventOrderingFunctions[MultisetSubstitutionSystem], - {}] @ {1, 2, 3} -``` - - - -Note that in this case, like in the case of a single history, changing [ordering functions](EventOrderingFunctions.md) -will change the result. - -## MinEventInputs and MaxEventInputs - -These parameters control the min and max numbers of input tokens allowed per event. There are two use cases for these -parameters. The first is controlling the number of inputs in systems where rules with variable numbers of inputs are -possible, such as [`MultisetSubstitutionSystem`](/Documentation/Systems/MultisetSubstitutionSystem.md). Compare, for -example, `"MinEventInputs" -> 0` (default): - -```wl -In[] := #["ExpressionsEventsGraph", VertexLabels -> Placed[Automatic, After]] & @ - SetReplaceTypeConvert[{WolframModelEvolutionObject, 2}] @ - GenerateMultihistory[MultisetSubstitutionSystem[{a___} :> {Total[{a}]}], - {"MinEventInputs" -> 0}, - None, - EventOrderingFunctions[MultisetSubstitutionSystem], - {"MaxEvents" -> 10}] @ {1, 2, 3} -``` - - - -and `"MinEventInputs" -> 2`: - -```wl -In[] := #["ExpressionsEventsGraph", VertexLabels -> Placed[Automatic, After]] & @ - SetReplaceTypeConvert[{WolframModelEvolutionObject, 2}] @ - GenerateMultihistory[MultisetSubstitutionSystem[{a___} :> {Total[{a}]}], - {"MinEventInputs" -> 2}, - None, - EventOrderingFunctions[MultisetSubstitutionSystem], - {"MaxEvents" -> 10}] @ {1, 2, 3} -``` - - - -The other use case is optimization. By default, systems like -[`MultisetSubstitutionSystem`](/Documentation/Systems/MultisetSubstitutionSystem.md) consider all subsets of tokens to -find matches, which can be slow, especially to finalize the complete evaluation, as it requires going through all -subsets to find out that no more matches are possible. However, if the range of match sizes is known ahead of time, it -can be used to make the evaluation faster. Compare: - -```wl -In[] := First @ AbsoluteTiming @ - GenerateMultihistory[MultisetSubstitutionSystem[{a___} /; Length[{a}] == 4 :> {Total[{a}]}], - #, - None, - EventOrderingFunctions[MultisetSubstitutionSystem], - {"MaxEvents" -> 20}] @ {1, 2, 3, 4} & /@ - {{}, {"MinEventInputs" -> 4, "MaxEventInputs" -> 4}} -Out[] = {0.682851, 0.011029} -``` diff --git a/Documentation/Generators/GenerateMultihistory.md b/Documentation/Generators/GenerateMultihistory.md index 511a9dc2..6473d7a1 100644 --- a/Documentation/Generators/GenerateMultihistory.md +++ b/Documentation/Generators/GenerateMultihistory.md @@ -1,24 +1,14 @@ # GenerateMultihistory -**`GenerateMultihistory`** is the most verbose and configurable generator. It can create both single histories, full -multihistories, as well as partial ones. It, however, requires one to specify all groups of parameters -([system](/Documentation/Systems/README.md), [event selection](EventSelectionParameters.md), deduplication, -[event ordering](EventOrderingFunctions.md) and [stopping conditions](StoppingConditionParameters.md)), nothing is -implied automatically: - -```wl -GenerateMultihistory[ - system, eventSelectionSpec, tokenDeduplicationSpec, eventOrderingSpec, stoppingConditionSpec] @ init -``` +**`GenerateMultihistory`** is the most configurable multihistory generator. With no parameters, it attempts to generate +all possible histories starting from the initial state. However, it can be configured to generate partial multihistories +and even single histories, although, [`GenerateSingleHistory`](GenerateSingleHistory.md) is more convenient for that. For example, for a [`MultisetSubstitutionSystem`](/Documentation/Systems/MultisetSubstitutionSystem.md): ```wl -In[] := multihistory = GenerateMultihistory[MultisetSubstitutionSystem[{a_, b_} :> {a + b}], - {"MaxDestroyerEvents" -> 3}, - None, - EventOrderingFunctions[MultisetSubstitutionSystem], - {"MaxEvents" -> 10}] @ {1, 2, 3, 4} +In[] := multihistory = GenerateMultihistory[ + MultisetSubstitutionSystem[{a_, b_} :> {a + b}], {1, 2, 3, 4}, MaxDestroyerEvents -> 3, MaxEvents -> 10] ``` @@ -29,11 +19,3 @@ In[] := #["ExpressionsEventsGraph", VertexLabels -> Placed[Automatic, After]] & ``` - -Everything that can be generated with more specialized `GenerateSingleHistory` and `GenerateAllHistories` can be -reproduced with `GenerateMultihistory` as well. This can be done by setting `"MaxDestroyerEvents" -> 1` to emulate -`GenerateSingleHistory` and setting `"MaxDestroyerEvents" -> Infinity` and leaving the -[stopping condition](StoppingConditionParameters.md) empty to emulate `GenerateAllHistories`. - -However, by setting `"MaxDestroyerEvents"` to finite values larger than 1, one can generate multihistories not possible -with other generators. diff --git a/Documentation/Generators/GenerateSingleHistory.md b/Documentation/Generators/GenerateSingleHistory.md new file mode 100644 index 00000000..10ff299c --- /dev/null +++ b/Documentation/Generators/GenerateSingleHistory.md @@ -0,0 +1,25 @@ +# GenerateSingleHistory + +**`GenerateSingleHistory`** generates single histories, which it achieves by setting +[`MaxDestroyerEvents`](MaxDestroyerEvents.md) to one. Note that for non-deterministic systems the history generated may +depend on the event order. + +For example, for a [`MultisetSubstitutionSystem`](/Documentation/Systems/MultisetSubstitutionSystem.md): + +```wl +In[] := multihistory = GenerateSingleHistory[ + MultisetSubstitutionSystem[{a_, b_} :> {a + b, a - b, a * b}], {1, 2}, MaxEvents -> 10] +``` + + + +```wl +In[] := #["ExpressionsEventsGraph", VertexLabels -> Placed[Automatic, After]] & @ + SetReplaceTypeConvert[{WolframModelEvolutionObject, 2}] @ multihistory +``` + + + +Note that single histories are not necessarily single-path systems. Multiple rewriting events can be possible starting +from a given state. However, only one event can take any given token as an input, which ensures that all generated +events do not conflict with each other (i.e., there are no branchlike-separated events). diff --git a/Documentation/Generators/MaxDestroyerEvents.md b/Documentation/Generators/MaxDestroyerEvents.md new file mode 100644 index 00000000..c6373473 --- /dev/null +++ b/Documentation/Generators/MaxDestroyerEvents.md @@ -0,0 +1,37 @@ +# MaxDestroyerEvents + +`MaxDestroyerEvents` is an event-selection parameter that controls the number of (inconsistent) events that are allowed +to take the same token as an input. [`GenerateSingleHistory`](GenerateSingleHistory.md) limits the evaluation to a +single history by setting `MaxDestroyerEvents` to one. + +```wl +In[] := #["ExpressionsEventsGraph", VertexLabels -> Placed[Automatic, After]] & @ + SetReplaceTypeConvert[{WolframModelEvolutionObject, 2}] @ + GenerateMultihistory[MultisetSubstitutionSystem[{a_, b_} :> {a + b}], {1, 2, 3}, MaxDestroyerEvents -> 1] +``` + + + +If unset (which defaults to [`Infinity`](https://reference.wolfram.com/language/ref/Infinity.html)), it will generate a +full multihistory subject to other selection and stopping parameters: + +```wl +In[] := #["ExpressionsEventsGraph", VertexLabels -> Placed[Automatic, After]] & @ + SetReplaceTypeConvert[{WolframModelEvolutionObject, 2}] @ + GenerateMultihistory[ + MultisetSubstitutionSystem[{a_, b_} :> {a + b}], {1, 2, 3}, MaxDestroyerEvents -> Infinity, MaxGeneration -> 1] +``` + + + +If set to a finite number, it will generate a partial multihistory: + +```wl +In[] := #["ExpressionsEventsGraph", VertexLabels -> Placed[Automatic, After]] & @ + SetReplaceTypeConvert[{WolframModelEvolutionObject, 2}] @ + GenerateMultihistory[MultisetSubstitutionSystem[{a_, b_} :> {a + b}], {1, 2, 3}, MaxDestroyerEvents -> 5] +``` + + + +Note that in this case, like in the case of a single history, the result depends on the event order. diff --git a/Documentation/Generators/MaxEventInputs.md b/Documentation/Generators/MaxEventInputs.md new file mode 100644 index 00000000..bf133ae8 --- /dev/null +++ b/Documentation/Generators/MaxEventInputs.md @@ -0,0 +1,17 @@ +# MaxEventInputs + +`MaxEventInputs` and [`MinEventInputs`](MinEventInputs.md) are event-selection parameters that control the max and min +numbers of input tokens allowed per event. In addition to [being useful](MinEventInputs.md) for rules with variable +numbers of inputs, `MaxEventInputs` is sometimes useful for optimization. By default, systems like +[`MultisetSubstitutionSystem`](/Documentation/Systems/MultisetSubstitutionSystem.md) consider all subsets of tokens to +find matches, which can be slow, especially to finalize the complete evaluation, as it requires going through all +subsets to find out that no more matches are possible. However, if the range of match sizes is known ahead of time, it +can be used to make the evaluation faster. Compare: + +```wl +In[] := First @ AbsoluteTiming @ + GenerateMultihistory[ + MultisetSubstitutionSystem[{a___} /; Length[{a}] == 4 :> {Total[{a}]}], {1, 2, 3, 4}, MaxEvents -> 20, #] & /@ + {{}, {MinEventInputs -> 4, MaxEventInputs -> 4}} +Out[] = {0.793215, 0.014419} +``` diff --git a/Documentation/Generators/MaxEvents.md b/Documentation/Generators/MaxEvents.md new file mode 100644 index 00000000..9390d18d --- /dev/null +++ b/Documentation/Generators/MaxEvents.md @@ -0,0 +1,14 @@ +# MaxEvents + +`MaxEvents` is the most basic stopping condition. It stops the evaluation once the given number of events is reached +(regardless of causal dependencies between these events): + +```wl +In[] := #["ExpressionsEventsGraph"] & @ + SetReplaceTypeConvert[{WolframModelEvolutionObject, 2}] @ + GenerateMultihistory[MultisetSubstitutionSystem[{a_, b_} /; a < b :> {a + b}], {1, 2, 3, 4}, MaxEvents -> 9] +``` + + + +Compare to [`MaxGeneration`](MaxGeneration.md) which controls the depth of the evaluation instead. diff --git a/Documentation/Generators/MaxGeneration.md b/Documentation/Generators/MaxGeneration.md new file mode 100644 index 00000000..455b653e --- /dev/null +++ b/Documentation/Generators/MaxGeneration.md @@ -0,0 +1,48 @@ +# MaxGeneration + +`MaxGeneration` is an event-selection parameter specifying the maximum generation of created tokens. + +Roughly speaking, **generation** corresponds to how many "steps" it took to get to a particular token or event starting +from the initial state. More precisely, the generation of the tokens in the initial state is defined to be zero. The +generation of an event is defined as the maximum of the generations of its inputs plus one. The generation of a token is +the same as the generation of its creator event. + +A neat feature of the `TokenEventGraph` property is that it arranges tokens and events in layers corresponding to their +generations. In the following example, the tokens and events are labeled with their generation numbers: + +```wl +In[] := #["ExpressionsEventsGraph", + VertexLabels -> Placed["Name", After, Replace[{{"Expression", n_} :> #["ExpressionGenerations"][[n]], + {"Event", n_} :> #["EventGenerations"][[n]]}]]] & @ + SetReplaceTypeConvert[{WolframModelEvolutionObject, 2}] @ + GenerateMultihistory[MultisetSubstitutionSystem[{a__} /; Total[{a}] == 5 :> {Total[{a}] - 1, Total[{a}] + 1}], + {1, 2, 3}, + MaxEvents -> 3] +``` + + + +Restricting the number of generations to one will prevent the last two events from occurring. Note, however, that +another event is created instead: + +```wl +In[] := #["ExpressionsEventsGraph"] & @ SetReplaceTypeConvert[{WolframModelEvolutionObject, 2}] @ + GenerateMultihistory[MultisetSubstitutionSystem[{a__} /; Total[{a}] == 5 :> {Total[{a}] - 1, Total[{a}] + 1}], + {1, 2, 3}, + MaxGeneration -> 1, MaxEvents -> 3] +``` + + + +Since `MaxGeneration` is a selection parameter rather than a stopping condition, it will continue evaluation even after +encountering matches exceeding the generations constraint, which might also result in a different +event order (i.e., some events being skipped) than if using, e.g., [`MaxEvents`](MaxEvents.md). For this reason, +`MaxGenerations` (like other selection parameters) does not have a corresponding termination reason. + +```wl +In[] := #[[2, "TerminationReason"]] & @ + GenerateMultihistory[MultisetSubstitutionSystem[{a__} /; Total[{a}] == 5 :> {Total[{a}] - 1, Total[{a}] + 1}], + {1, 2, 3}, + MaxGeneration -> 1] +Out[] = "Complete" +``` diff --git a/Documentation/Generators/MinEventInputs.md b/Documentation/Generators/MinEventInputs.md new file mode 100644 index 00000000..4ddfd0e6 --- /dev/null +++ b/Documentation/Generators/MinEventInputs.md @@ -0,0 +1,26 @@ +# MinEventInputs + +`MinEventInputs` and [`MaxEventInputs`](MaxEventInputs.md) are event-selection parameters that control the min and max +numbers of input tokens allowed per event. These parameters are useful in systems where rules with variable numbers of +inputs are possible, such as [`MultisetSubstitutionSystem`](/Documentation/Systems/MultisetSubstitutionSystem.md). +Compare, for example, `MinEventInputs -> 0` (default): + +```wl +In[] := #["ExpressionsEventsGraph", VertexLabels -> Placed[Automatic, After]] & @ + SetReplaceTypeConvert[{WolframModelEvolutionObject, 2}] @ + GenerateMultihistory[ + MultisetSubstitutionSystem[{a___} :> {Total[{a}]}], {1, 2, 3}, MinEventInputs -> 0, MaxEvents -> 10] +``` + + + +and `MinEventInputs -> 2`: + +```wl +In[] := #["ExpressionsEventsGraph", VertexLabels -> Placed[Automatic, After]] & @ + SetReplaceTypeConvert[{WolframModelEvolutionObject, 2}] @ + GenerateMultihistory[ + MultisetSubstitutionSystem[{a___} :> {Total[{a}]}], {1, 2, 3}, MinEventInputs -> 2, MaxEvents -> 10] +``` + + diff --git a/Documentation/Generators/README.md b/Documentation/Generators/README.md index 0b34a97e..9f4455ff 100644 --- a/Documentation/Generators/README.md +++ b/Documentation/Generators/README.md @@ -16,7 +16,7 @@ tokens, etc. Different generators correspond to different settings of parameters specified similar to options. For example, [`GenerateSingleHistory`](GenerateSingleHistory.md) corresponds to -[`"MaxDestroyerEvents" -> 1`](MaxDestroyerEvents.md) and thus does produce nondeterministic branching: +[`MaxDestroyerEvents -> 1`](MaxDestroyerEvents.md) and thus does produce nondeterministic branching: ```wl In[] := #["ExpressionsEventsGraph", VertexLabels -> Placed[Automatic, After]] & @ @@ -27,13 +27,13 @@ In[] := #["ExpressionsEventsGraph", VertexLabels -> Placed[Automatic, After]] & We can also use a more generate [`GenerateMultihistory`](GenerateMultihistory.md) and specify -[`"MaxDestroyerEvents"`](MaxDestroyerEvents.md) manually. +[`MaxDestroyerEvents`](MaxDestroyerEvents.md) manually. ```wl In[] := #["ExpressionsEventsGraph", VertexLabels -> Placed[Automatic, After]] & @ SetReplaceTypeConvert[{WolframModelEvolutionObject, 2}] @ GenerateMultihistory[ - MultisetSubstitutionSystem[{a_, b_} /; a < b :> {a + b}], {1, 2, 3, 4}, "MaxDestroyerEvents" -> 2] + MultisetSubstitutionSystem[{a_, b_} /; a < b :> {a + b}], {1, 2, 3, 4}, MaxDestroyerEvents -> 2] ``` @@ -43,16 +43,39 @@ The same generators support multiple systems. In addition to `HypergraphSubstitutionSystem`, `StringSubstitutionSystem`, etc. Many of these systems have shared evaluation parameters. +All generators take the form + +```wl +Generator[System[rules], init, parameters...] +``` + +or, in operator form, + +```wl +Generator[System[rules], parameters...] @ init +``` + +Note, however, that the first form takes precedence and, if parameters can be interpreted as an init, the second form +may not evaluate as expected. + +`parameters` can be specified either as a [`Sequence`](https://reference.wolfram.com/language/ref/Sequence.html) of +[`Rule`](https://reference.wolfram.com/language/ref/Rule.html)s, a +[`List`](https://reference.wolfram.com/language/ref/List.html) of +[`Rule`](https://reference.wolfram.com/language/ref/Rule.html)s or an +[`Association`](https://reference.wolfram.com/language/ref/Association.html). Keys supported +in such [`Rule`](https://reference.wolfram.com/language/ref/Rule.html)s depend on the system and can be looked up with +[`SetReplaceSystemParameters`](SetReplaceSystemParameters.md). + * Introspection: * [`$SetReplaceSystems`]($SetReplaceSystems.md) — yields the list of all implemented systems * [`$SetReplaceGenerators`]($SetReplaceGenerators.md) — yields the list of all generators * [`SetReplaceSystemParameters`](SetReplaceSystemParameters.md) — yields the list of parameters for a system * Generators: * [`GenerateMultihistory`](GenerateMultihistory.md) — the universal generator for multihistories - * [`GenerateSingleHistory`](GenerateSingleHistory.md) — sets `"MaxDestroyerEvents" -> 1` + * [`GenerateSingleHistory`](GenerateSingleHistory.md) — sets `MaxDestroyerEvents -> 1` * Parameters: - * [`"MaxDestroyerEvents"`](MaxDestroyerEvents.md) — allows one to switch between single and multihistories - * [`"MinEventInputs"`](MinEventInputs.md) - * [`"MaxEventInputs"`](MaxEventInputs.md) - * [`"MaxEvents"`](MaxEvents.md) - * [`"MaxGeneration"`](MaxGeneration.md) + * [`MaxDestroyerEvents`](MaxDestroyerEvents.md) — allows one to switch between single and multihistories + * [`MinEventInputs`](MinEventInputs.md) + * [`MaxEventInputs`](MaxEventInputs.md) + * [`MaxEvents`](MaxEvents.md) + * [`MaxGeneration`](MaxGeneration.md) diff --git a/Documentation/Generators/SetReplaceSystemParameters.md b/Documentation/Generators/SetReplaceSystemParameters.md new file mode 100644 index 00000000..70941c66 --- /dev/null +++ b/Documentation/Generators/SetReplaceSystemParameters.md @@ -0,0 +1,16 @@ +# SetReplaceSystemParameters + +**`SetReplaceSystemParameters`** gives the list of parameters that can be used as keys in generators such as +[`GenerateMultihistory`](GenerateMultihistory.md): + +```wl +In[] := SetReplaceSystemParameters[MultisetSubstitutionSystem] +Out[] = {MaxGeneration, MaxDestroyerEvents, MinEventInputs, MaxEventInputs, MaxEvents} +``` + +The entire system spec including the rules can be passed as well (although the rules don't affect the result): + +```wl +In[] := SetReplaceSystemParameters[AtomicStateSystem[a_ :> a + 1]] +Out[] = {MaxGeneration, MaxDestroyerEvents, MaxEvents} +``` diff --git a/Documentation/Generators/StoppingConditionParameters.md b/Documentation/Generators/StoppingConditionParameters.md deleted file mode 100644 index 9852ec62..00000000 --- a/Documentation/Generators/StoppingConditionParameters.md +++ /dev/null @@ -1,36 +0,0 @@ -# Stopping Condition Parameters - -Stopping condition controls when the evaluation should be terminated. Unlike the -[event selection parameters](EventSelectionParameters.md), the termination occurs immediately once one of these -conditions is reached, even if a further evaluation would be possible with a different -[event ordering](EventOrderingFunctions.md). - -**`StoppingConditionParameters`** allows one to obtain the list of parameters available for a particular system: - -```wl -In[] := StoppingConditionParameters[MultisetSubstitutionSystem] -Out[] = {"MaxEvents"} -``` - -They typically correspond to the values returned by the `TerminationReason` property. These values can be used as keys -for the corresponding arguments of [generators](README.md). - -## MaxEvents - -This is the most basic stopping condition. It stops the evaluation once the given number of events is reached -(regardless of causal dependencies between these events): - -```wl -In[] := #["ExpressionsEventsGraph"] & @ - SetReplaceTypeConvert[{WolframModelEvolutionObject, 2}] @ - GenerateMultihistory[MultisetSubstitutionSystem[{a_, b_} /; a < b :> {a + b}], - {}, - None, - EventOrderingFunctions[MultisetSubstitutionSystem], - {"MaxEvents" -> 9}] @ {1, 2, 3, 4} -``` - - - -Compare to [`"MaxGeneration"`](EventSelectionParameters.md#maxgeneration) which controls the depth of the evaluation -instead. diff --git a/Documentation/Images/GenerateSingleHistoryExample.png b/Documentation/Images/GenerateSingleHistoryExample.png new file mode 100644 index 0000000000000000000000000000000000000000..3921c4129d845ab42d43e6f653ec0dafe665fa18 GIT binary patch literal 30736 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 Date: Thu, 8 Jul 2021 14:32:25 -0500 Subject: [PATCH 13/33] Update Systems documentation. --- .../Generators/GenerateSingleHistory.md | 2 +- Documentation/Systems/AtomicStateSystem.md | 6 +-- .../Systems/MultisetSubstitutionSystem.md | 44 +++++-------------- 3 files changed, 13 insertions(+), 39 deletions(-) diff --git a/Documentation/Generators/GenerateSingleHistory.md b/Documentation/Generators/GenerateSingleHistory.md index 10ff299c..cfaa8436 100644 --- a/Documentation/Generators/GenerateSingleHistory.md +++ b/Documentation/Generators/GenerateSingleHistory.md @@ -1,7 +1,7 @@ # GenerateSingleHistory **`GenerateSingleHistory`** generates single histories, which it achieves by setting -[`MaxDestroyerEvents`](MaxDestroyerEvents.md) to one. Note that for non-deterministic systems the history generated may +[`MaxDestroyerEvents`](MaxDestroyerEvents.md) to one. Note that for nondeterministic systems the history generated may depend on the event order. For example, for a [`MultisetSubstitutionSystem`](/Documentation/Systems/MultisetSubstitutionSystem.md): diff --git a/Documentation/Systems/AtomicStateSystem.md b/Documentation/Systems/AtomicStateSystem.md index eeb1d6af..79baae5f 100644 --- a/Documentation/Systems/AtomicStateSystem.md +++ b/Documentation/Systems/AtomicStateSystem.md @@ -6,11 +6,7 @@ left that can match these states, and the arbitrary code on the right that creat ```wl In[] := #["ExpressionsEventsGraph", VertexLabels -> Placed[Automatic, After]] & @ SetReplaceTypeConvert[{WolframModelEvolutionObject, 2}] @ - GenerateMultihistory[AtomicStateSystem[{n_ :> n + 1, n_ :> n - 1}], - {"MaxGeneration" -> 4}, - None, - EventOrderingFunctions[AtomicStateSystem], - {}] @ 0 + GenerateMultihistory[AtomicStateSystem[{n_ :> n + 1, n_ :> n - 1}], 0, MaxGeneration -> 4] ``` diff --git a/Documentation/Systems/MultisetSubstitutionSystem.md b/Documentation/Systems/MultisetSubstitutionSystem.md index a0ac1162..f8febdb9 100644 --- a/Documentation/Systems/MultisetSubstitutionSystem.md +++ b/Documentation/Systems/MultisetSubstitutionSystem.md @@ -6,9 +6,8 @@ expressions. Events take submultisets of these and replace them with other multi The left-hand sides of rules are written as Wolfram Language patterns. The first level of these patterns should match to a [`List`](https://reference.wolfram.com/language/ref/List.html), and is matched to a multiset of tokens, so -`{n__Integer, s_String}` and `{s_String, n__Integer}` are equivalent aside from their effect on the -[event ordering](/Documentation/Generators/EventOrderingFunctions.md) and can match, e.g., `{1, 2, "s"}`, `{2, "x", 3}` -and `{"q", 1}`. +`{n__Integer, s_String}` and `{s_String, n__Integer}` are equivalent aside from their effect on the event order and can +match, e.g., `{1, 2, "s"}`, `{2, "x", 3}` and `{"q", 1}`. The right-hand sides determine the result of the replacement similar to [`Replace`](https://reference.wolfram.com/language/ref/Replace.html). The top level of the output must be a @@ -20,11 +19,7 @@ For example, to make a system that adds pairs of numbers: ```wl In[] := #["ExpressionsEventsGraph", VertexLabels -> Placed[Automatic, After]] & @ SetReplaceTypeConvert[{WolframModelEvolutionObject, 2}] @ - GenerateMultihistory[MultisetSubstitutionSystem[{a_, b_} /; a < b :> {a + b}], - "MaxDestroyerEvents" -> 1, - None, - EventOrderingFunctions[MultisetSubstitutionSystem], - {}] @ {1, 2, 3, 4} + GenerateSingleHistory[MultisetSubstitutionSystem[{a_, b_} /; a < b :> {a + b}], {1, 2, 3, 4}] ``` @@ -40,10 +35,8 @@ In[] := #["ExpressionsEventsGraph", VertexLabels -> Placed[Automatic, After]] & SetReplaceTypeConvert[{WolframModelEvolutionObject, 2}] @ GenerateMultihistory[ MultisetSubstitutionSystem[{a__} /; OrderedQ[{a}] && PrimeQ[Plus[a]] :> First /@ FactorInteger[Plus[a]]], - {"MinEventInputs" -> 2, "MaxEventInputs" -> 4}, - None, - EventOrderingFunctions[MultisetSubstitutionSystem], - {}] @ {1, 2, 3, 4} + {1, 2, 3, 4}, + MinEventInputs -> 2, MaxEventInputs -> 4] ``` @@ -52,26 +45,11 @@ Note, however, that the system cannot recognize if the code on the right-hand si first output will be used for each assignment of pattern variables. `MultisetSubstitutionSystem` supports -[`"MaxGeneration"`](/Documentation/Generators/EventSelectionParameters.md#maxgeneration), -[`"MaxDestroyerEvents"`](/Documentation/Generators/EventSelectionParameters.md#maxdestroyerevents), -[`"MinEventInputs"` and `"MaxEventInputs"`](/Documentation/Generators/EventSelectionParameters.md#mineventinputs-and-maxeventinputs) -for [event selection](/Documentation/Generators/EventSelectionParameters.md). It supports -[`"MaxEvents"`](/Documentation/Generators/StoppingConditionParameters.md#maxevents) as a -[stopping condition](/Documentation/Generators/StoppingConditionParameters.md). Only a single -[event ordering](/Documentation/Generators/EventOrderingFunctions.md) +[`MaxGeneration`](/Documentation/Generators/MaxGeneration.md), +[`MaxDestroyerEvents`](/Documentation/Generators/MaxDestroyerEvents.md), +[`MinEventInputs`](/Documentation/Generators/MinEventInputs.md) and +[`MaxEventInputs`](/Documentation/Generators/MaxEventInputs.md) +for event selection. It supports +[`MaxEvents`](/Documentation/Generators/MaxEvents.md) as a stopping condition. Only a single event order `{"InputCount", "SortedInputTokenIndices", "InputTokenIndices", "RuleIndex", "InstantiationIndex"}` is implemented at the moment. - -`MultisetSubstitutionSystem` produces -[`{MultisetSubstitutionSystem, 0}`](/Documentation/Types/Multihistory/MultisetSubstitutionSystem0.md) objects. - -## Current Limitations - -* The current version does no introspection of the rules, so it is slow since it has to enumerate all subsets of tokens -in the multihistory for every new event. -[`"MaxEventInputs"`](/Documentation/Generators/EventSelectionParameters.md#mineventinputs-and-maxeventinputs) can be -used as a workaround. -* Token deduplication is not implemented. The only value supported is -[`None`](https://reference.wolfram.com/language/ref/None.html). -* Only `{"InputCount", "SortedInputTokenIndices", "InputTokenIndices", "RuleIndex", "InstantiationIndex"}` is -implemented for event ordering. From 060fe59cace288a59d805819b92b28dac8b744c5 Mon Sep 17 00:00:00 2001 From: Max Piskunov Date: Thu, 8 Jul 2021 14:40:57 -0500 Subject: [PATCH 14/33] Update Types documentation. --- Documentation/Types/Multihistory/AtomicStateSystem0.md | 3 +-- .../Types/Multihistory/MultisetSubstitutionSystem0.md | 9 +++------ Documentation/Types/Multihistory/README.md | 6 +----- 3 files changed, 5 insertions(+), 13 deletions(-) diff --git a/Documentation/Types/Multihistory/AtomicStateSystem0.md b/Documentation/Types/Multihistory/AtomicStateSystem0.md index c04c5ddc..54991bf3 100644 --- a/Documentation/Types/Multihistory/AtomicStateSystem0.md +++ b/Documentation/Types/Multihistory/AtomicStateSystem0.md @@ -5,8 +5,7 @@ [`AtomicStateSystem`](/Documentation/Systems/AtomicStateSystem.md): ```wl -In[] := GenerateMultihistory[ - AtomicStateSystem[a_ :> a + 1], {}, None, EventOrderingFunctions[AtomicStateSystem], {"MaxEvents" -> 10}] @ 0 +In[] := GenerateMultihistory[AtomicStateSystem[a_ :> a + 1], 0, MaxEvents -> 10] ``` diff --git a/Documentation/Types/Multihistory/MultisetSubstitutionSystem0.md b/Documentation/Types/Multihistory/MultisetSubstitutionSystem0.md index 4b53e132..99c96253 100644 --- a/Documentation/Types/Multihistory/MultisetSubstitutionSystem0.md +++ b/Documentation/Types/Multihistory/MultisetSubstitutionSystem0.md @@ -5,11 +5,7 @@ [`MultisetSubstitutionSystem`](/Documentation/Systems/MultisetSubstitutionSystem.md): ```wl -In[] := GenerateMultihistory[MultisetSubstitutionSystem[{a_, b_} :> {a + b}], - {}, - None, - EventOrderingFunctions[MultisetSubstitutionSystem], - {"MaxEvents" -> 10}] @ {1, 2, 3} +In[] := GenerateMultihistory[MultisetSubstitutionSystem[{a_, b_} :> {a + b}], {1, 2, 3}, MaxEvents -> 10] ``` @@ -21,4 +17,5 @@ separations of expressions and other values used for optimization. There are no properties implemented for it yet, however, it can be [converted](/Documentation/TypeSystem/SetReplaceTypeConvert.md) to a -[WolframModelEvolutionObject](/Documentation/SymbolsAndFunctions/WolframModelAndWolframModelEvolutionObject/WolframModelAndWolframModelEvolutionObject.md). +[WolframModelEvolutionObject](/Documentation/SymbolsAndFunctions/WolframModelAndWolframModelEvolutionObject/WolframModelAndWolframModelEvolutionObject.md) +for backwards compatibility. diff --git a/Documentation/Types/Multihistory/README.md b/Documentation/Types/Multihistory/README.md index 4da0bb7b..0ac343d7 100644 --- a/Documentation/Types/Multihistory/README.md +++ b/Documentation/Types/Multihistory/README.md @@ -6,11 +6,7 @@ For example, for a [`MultisetSubstitutionSystem`](/Documentation/Systems/MultisetSubstitutionSystem.md), ```wl -In[] := GenerateMultihistory[MultisetSubstitutionSystem[{a_, b_} :> {a + b}], - {}, - None, - EventOrderingFunctions[MultisetSubstitutionSystem], - {"MaxEvents" -> 10}] @ {1, 2, 3} +In[] := GenerateMultihistory[MultisetSubstitutionSystem[{a_, b_} :> {a + b}], {1, 2, 3}, MaxEvents -> 10] ``` From 760ee3af00140594c127cde4f0df1b3a10018729 Mon Sep 17 00:00:00 2001 From: Max Piskunov Date: Thu, 8 Jul 2021 15:58:47 -0500 Subject: [PATCH 15/33] Update tests for AtomicStateSystem. --- Tests/AtomicStateSystem.wlt | 71 ++++++++++++++----------------------- 1 file changed, 27 insertions(+), 44 deletions(-) diff --git a/Tests/AtomicStateSystem.wlt b/Tests/AtomicStateSystem.wlt index 99f8433a..7f77e094 100644 --- a/Tests/AtomicStateSystem.wlt +++ b/Tests/AtomicStateSystem.wlt @@ -9,54 +9,37 @@ allExpressions[Multihistory[_, data_]] := Normal @ data["MultisetMultihistory"][[2]]["Expressions"]; ), "tests" -> { - With[{anEventOrdering = EventOrderingFunctions[AtomicStateSystem]}, { - (* Symbol Leak *) - testSymbolLeak[ - GenerateMultihistory[AtomicStateSystem[a_ :> a + 1], {}, None, anEventOrdering, {"MaxEvents" -> 5}] @ 0], + (* Symbol Leak *) + testSymbolLeak[GenerateMultihistory[AtomicStateSystem[a_ :> a + 1], 0, MaxEvents -> 5]], - (* Rules *) - testUnevaluated[GenerateMultihistory[AtomicStateSystem[##2], {}, None, anEventOrdering, {}] @ 1, {#}] & @@@ - {{AtomicStateSystem::argx}, - {AtomicStateSystem::argx, 1, 2}, - {GenerateMultihistory::invalidAtomicStateRules, 1}}, + (* Rules *) + testUnevaluated[GenerateMultihistory[AtomicStateSystem[##2], 1], {#}] & @@@ { + {AtomicStateSystem::argx}, + {AtomicStateSystem::argx, 1, 2}, + {GenerateMultihistory::invalidAtomicStateRules, 1}}, - (* Ordering not yet supported *) - testUnevaluated[GenerateMultihistory[AtomicStateSystem[1 -> 2], {}, None, {"RuleIndex"}, {}] @ 1, - {GenerateMultihistory::atomicStateEventOrderingNotImplemented}], + (* Parameters *) + testUnevaluated[GenerateMultihistory[AtomicStateSystem[1 -> 2], 1, MaxGeneration -> -1], + {GenerateMultihistory::invalidParameter}], - (* Token deduplication not yet supported *) - testUnevaluated[GenerateMultihistory[AtomicStateSystem[1 -> 2], {}, All, anEventOrdering, {}] @ 1, - {GenerateMultihistory::atomicStateTokenDeduplicationNotImplemented}], + Function[{rules, parameters, init, expectedCreatedExpressions}, + VerificationTest[allExpressions @ GenerateMultihistory[AtomicStateSystem[rules], init, parameters], + Join[{init}, expectedCreatedExpressions], + SameTest -> MatchQ]] @@@ { + {1 -> 1, MaxEvents -> 1, 1, {1}}, + {1 -> 2, MaxEvents -> 1, 1, {2}}, + {1 -> 2, MaxGeneration -> 1, 1, {2}}, + {2 :> 5, MaxGeneration -> 1, 2, {5}}, + {{2 -> 5, 2 :> 6}, MaxGeneration -> 1, 2, {5, 6}}, + {{2 :> 3, 3 :> 4}, MaxGeneration -> 2, 2, {3, 4}}, + {x_ :> x + 1, MaxGeneration -> 2, 2, {3, 4}}, + {{x_ :> x - 1, x_ :> x + 1}, MaxGeneration -> 2, 0, {-1, 1, -2, 0, 0, 2}}, + {{x_ ? EvenQ :> x - 1, x_ ? OddQ :> x + 1}, MaxGeneration -> 2, 0, {-1, 0}}, + (* only valid patterns should be matched *) + {x_String :> x <> "x", MaxEvents -> 2, 0, {}}}, - (* Parameters *) - testUnevaluated[ - GenerateMultihistory[AtomicStateSystem[1 -> 2], {"MaxGeneration" -> -1}, None, anEventOrdering, {}] @ 1, - {GenerateMultihistory::notNonNegativeIntegerOrInfinityParameter}], - - Function[{rules, selection, stopping, init, expectedCreatedExpressions}, - VerificationTest[ - allExpressions @ GenerateMultihistory[ - AtomicStateSystem[rules], selection, None, anEventOrdering, stopping] @ init, - Join[{init}, expectedCreatedExpressions], - SameTest -> MatchQ]] @@@ - {{1 -> 1, <||>, <|"MaxEvents" -> 1|>, 1, {1}}, - {1 -> 2, <||>, <|"MaxEvents" -> 1|>, 1, {2}}, - {1 -> 2, <|"MaxGeneration" -> 1|>, <||>, 1, {2}}, - {2 :> 5, <|"MaxGeneration" -> 1|>, <||>, 2, {5}}, - {{2 -> 5, 2 :> 6}, <|"MaxGeneration" -> 1|>, <||>, 2, {5, 6}}, - {{2 :> 3, 3 :> 4}, <|"MaxGeneration" -> 2|>, <||>, 2, {3, 4}}, - {x_ :> x + 1, <|"MaxGeneration" -> 2|>, <||>, 2, {3, 4}}, - {{x_ :> x - 1, x_ :> x + 1}, <|"MaxGeneration" -> 2|>, <||>, 0, {-1, 1, -2, 0, 0, 2}}, - {{x_ ? EvenQ :> x - 1, x_ ? OddQ :> x + 1}, <|"MaxGeneration" -> 2|>, <||>, 0, {-1, 0}}, - (* only valid patterns should be matched *) - {x_String :> x <> "x", {}, {"MaxEvents" -> 2}, 0, {}}} - }], - - VerificationTest[ - allExpressions @ GenerateMultihistory[ - AtomicStateSystem[{1 -> 3, 2 -> 3, 0 -> 1, 0 -> 2}], {}, None, {"InputIndex", "RuleIndex"}, {}] @ 0, - {0, 1, 2, 3, 3} - ] + VerificationTest[allExpressions @ GenerateMultihistory[AtomicStateSystem[{1 -> 3, 2 -> 3, 0 -> 1, 0 -> 2}], 0], + {0, 1, 2, 3, 3}] } |> |> From f995136f69bd498fbe27a62adc5cd10cf6a9fe9e Mon Sep 17 00:00:00 2001 From: Max Piskunov Date: Thu, 8 Jul 2021 16:02:12 -0500 Subject: [PATCH 16/33] Remove old GenerateMultihistory tests. --- Tests/GenerateMultihistory.wlt | 120 --------------------------------- 1 file changed, 120 deletions(-) delete mode 100644 Tests/GenerateMultihistory.wlt diff --git a/Tests/GenerateMultihistory.wlt b/Tests/GenerateMultihistory.wlt deleted file mode 100644 index 58e40e89..00000000 --- a/Tests/GenerateMultihistory.wlt +++ /dev/null @@ -1,120 +0,0 @@ -<| - "GenerateMultihistory" -> <| - "init" -> ( - Attributes[Global`testUnevaluated] = {HoldAll}; - Global`testUnevaluated[args___] := SetReplace`PackageScope`testUnevaluated[VerificationTest, args]; - Global`declareMultihistoryGenerator = SetReplace`PackageScope`declareMultihistoryGenerator; - Global`initializeGenerators = SetReplace`PackageScope`initializeGenerators; - - SetReplace`PackageScope`declareMultihistoryGenerator[ - testSystemImplementation, - TestSystem, - <|"MaxGeneration" -> {Infinity, "NonNegativeIntegerOrInfinity"}, - "MinEventInputs" -> {0, "NonNegativeIntegerOrInfinity"}, - "EventPattern" -> {_, None}|>, - {"InputCount", "RuleOrdering"}, - <|"MaxEvents" -> {Infinity, "NonNegativeIntegerOrInfinity"}, - "MinCausalDensityDimension" -> {2., None}, - "TokenEventGraphTest" -> {True &, None}|>]; - - $originalSetReplaceSystem = $SetReplaceSystems; - Unprotect[$SetReplaceSystems]; - initializeGenerators[]; - Protect[$SetReplaceSystems]; - ), - "tests" -> { - (* It's useful to catch unprocessed declarations early *) - VerificationTest[declareMultihistoryGenerator[a, b, {}, {}, <||>], - _, - {SetReplace::invalidGeneratorDeclaration}, - SameTest -> MatchQ], - - (* GenerateMultihistory *) - - $defaultEventSelection = <|"MaxGeneration" -> Infinity, "MinEventInputs" -> 0, "EventPattern" -> _|>; - $defaultStoppingConditions = - <|"MaxEvents" -> Infinity, "MinCausalDensityDimension" -> 2., "TokenEventGraphTest" -> (True &)|>; - - testUnevaluated[GenerateMultihistory[][], GenerateMultihistory::argrx], - testUnevaluated[GenerateMultihistory[][0], GenerateMultihistory::argrx], - testUnevaluated[GenerateMultihistory[0][], GenerateMultihistory::argr], - testUnevaluated[GenerateMultihistory[0, 1, 2, 3, 4, 5][], GenerateMultihistory::argrx], - testUnevaluated[GenerateMultihistory[0, 1, 2, 3, 4][], GenerateMultihistory::argx], - testUnevaluated[GenerateMultihistory[0, 1, 2, 3, 4][1, 2], GenerateMultihistory::argx], - - testUnevaluated[GenerateMultihistory[#, 1, 2, 3, 4][0], GenerateMultihistory::unknownSystem] & /@ - {UnknownSystem[], TestSystem, TestSystem[][]}, - - testUnevaluated[GenerateMultihistory[TestSystem[], 1, 2, 3, 4][0], GenerateMultihistory::invalidEventSelection], - testUnevaluated[GenerateMultihistory[TestSystem[], <|"Unknown" -> 0|>, 2, 3, 4][0], - GenerateMultihistory::invalidEventSelection], - testUnevaluated[GenerateMultihistory[TestSystem[], <|"MaxGeneration" -> -1|>, 2, 3, 4][0], - GenerateMultihistory::notNonNegativeIntegerOrInfinityParameter], - VerificationTest[ - GenerateMultihistory[TestSystem[], #, None, {}, <||>][0], - testSystemImplementation[TestSystem[], - <|"MaxGeneration" -> 2, "MinEventInputs" -> 0, "EventPattern" -> _|>, - None, - {}, - $defaultStoppingConditions, - 0]] & /@ {<|"MaxGeneration" -> 2|>, {"MaxGeneration" -> 2}, "MaxGeneration" -> 2}, - VerificationTest[ - GenerateMultihistory[TestSystem[], <|"EventPattern" -> {__} -> {_}|>, None, {}, <||>][0], - testSystemImplementation[TestSystem[], - <|"MaxGeneration" -> Infinity, "MinEventInputs" -> 0, "EventPattern" -> {__} -> {_}|>, - None, - {}, - $defaultStoppingConditions, - 0]], - - testUnevaluated[ - GenerateMultihistory[TestSystem[], <||>, 2, 3, 4][0], GenerateMultihistory::invalidTokenDeduplication], - VerificationTest[ - GenerateMultihistory[TestSystem[], <||>, #, {}, <||>][0], - testSystemImplementation[TestSystem[], $defaultEventSelection, #, {}, $defaultStoppingConditions, 0]] & /@ - {None, All}, - - testUnevaluated[ - GenerateMultihistory[TestSystem[], <||>, None, 3, 4][0], GenerateMultihistory::invalidEventOrdering], - testUnevaluated[ - GenerateMultihistory[TestSystem[], <||>, None, {"Unknown"}, 4][0], GenerateMultihistory::invalidEventOrdering], - VerificationTest[ - GenerateMultihistory[TestSystem[], <||>, None, {"RuleOrdering", "InputCount"}, <||>][0], - testSystemImplementation[ - TestSystem[], $defaultEventSelection, None, {"RuleOrdering", "InputCount"}, $defaultStoppingConditions, 0]], - - testUnevaluated[ - GenerateMultihistory[TestSystem[], <||>, None, {}, 4][0], GenerateMultihistory::invalidStoppingCondition], - testUnevaluated[GenerateMultihistory[TestSystem[], <||>, None, {}, <|"Unknown" -> 0|>][0], - GenerateMultihistory::invalidStoppingCondition], - testUnevaluated[GenerateMultihistory[TestSystem[], <||>, None, {}, <|"MaxEvents" -> -1|>][0], - GenerateMultihistory::notNonNegativeIntegerOrInfinityParameter], - VerificationTest[ - GenerateMultihistory[TestSystem[], <||>, None, {}, #][0], - testSystemImplementation[ - TestSystem[], - $defaultEventSelection, - None, - {}, - <|"MaxEvents" -> 2, "MinCausalDensityDimension" -> 2., "TokenEventGraphTest" -> (True &)|>, - 0]] & /@ {<|"MaxEvents" -> 2|>, {"MaxEvents" -> 2}, "MaxEvents" -> 2}, - - (* Introspection *) - VerificationTest[$SetReplaceSystems, Sort @ Join[$originalSetReplaceSystem, {TestSystem}]], - - Function[{introspectionFunction}, { - testUnevaluated[introspectionFunction[], introspectionFunction::argx], - testUnevaluated[introspectionFunction[0, 1], introspectionFunction::argx], - testUnevaluated[introspectionFunction[#], introspectionFunction::unknownSystem] & /@ - {0, UnknownSystem, TestSystem[][]} - }] /@ {EventSelectionParameters, EventOrderingFunctions, StoppingConditionParameters}, - - VerificationTest[EventSelectionParameters[#], {"MaxGeneration", "MinEventInputs", "EventPattern"}] & /@ - {TestSystem, TestSystem[1, 2]}, - VerificationTest[EventOrderingFunctions[#], {"InputCount", "RuleOrdering"}] & /@ {TestSystem, TestSystem[1, 2]}, - VerificationTest[ - StoppingConditionParameters[#], {"MaxEvents", "MinCausalDensityDimension", "TokenEventGraphTest"}] & /@ - {TestSystem, TestSystem[1, 2]} - } - |> -|> From 09500fb27c0f6cfb187197a88be5af09f1da42a3 Mon Sep 17 00:00:00 2001 From: Max Piskunov Date: Thu, 8 Jul 2021 16:56:57 -0500 Subject: [PATCH 17/33] Update hypergraphMatching tests. --- Tests/hypergraphMatching.wlt | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/Tests/hypergraphMatching.wlt b/Tests/hypergraphMatching.wlt index 1bb28a27..2a148e01 100644 --- a/Tests/hypergraphMatching.wlt +++ b/Tests/hypergraphMatching.wlt @@ -22,11 +22,7 @@ matchingFunction[MultisetSubstitutionSystem] = (#["EventRuleIndices"]["Length"] > 1 &) @ - Last @ GenerateMultihistory[MultisetSubstitutionSystem[ToPatternRules[#HypergraphRule]], - <||>, - None, - EventOrderingFunctions[MultisetSubstitutionSystem], - <||>] @ #Init &; + Last @ GenerateMultihistory[MultisetSubstitutionSystem[ToPatternRules[#HypergraphRule]], #Init] &; graphFromHyperedges[edges_] := Graph[UndirectedEdge @@@ Flatten[Partition[#, 2, 1] & /@ edges, 1]]; @@ -120,13 +116,8 @@ ] & /@ {"LowLevel", "Symbolic"}, VerificationTest[ - Normal @ - (#["Expressions"] &) @ - Last @ GenerateMultihistory[MultisetSubstitutionSystem[ToPatternRules[{{1, 2}, {2, 3}} -> {{1, 3}}]], - <||>, - None, - EventOrderingFunctions[MultisetSubstitutionSystem], - <|"MaxEvents" -> 1|>][{{1, 2}, {2, 1}}], + Normal @ (#["Expressions"] &) @ Last @ GenerateMultihistory[ + MultisetSubstitutionSystem[ToPatternRules[{{1, 2}, {2, 3}} -> {{1, 3}}]], {{1, 2}, {2, 1}}, MaxEvents -> 1], {{1, 2}, {2, 1}, {1, 1}} ], From f1391c92105a507076b96425e659af8d44996afc Mon Sep 17 00:00:00 2001 From: Max Piskunov Date: Thu, 8 Jul 2021 17:31:14 -0500 Subject: [PATCH 18/33] Update MultisetSubstitutionSystem tests. --- Tests/MultisetSubstitutionSystem.wlt | 653 +++++++++++---------------- 1 file changed, 270 insertions(+), 383 deletions(-) diff --git a/Tests/MultisetSubstitutionSystem.wlt b/Tests/MultisetSubstitutionSystem.wlt index 2899b098..04ae3b24 100644 --- a/Tests/MultisetSubstitutionSystem.wlt +++ b/Tests/MultisetSubstitutionSystem.wlt @@ -6,47 +6,23 @@ Global`testSymbolLeak[args___] := SetReplace`PackageScope`testSymbolLeak[VerificationTest, args]; ), "tests" -> { - With[{anEventOrdering = EventOrderingFunctions[MultisetSubstitutionSystem]}, { - (* Symbol Leak *) - testSymbolLeak[ - GenerateMultihistory[ - MultisetSubstitutionSystem[{a_, b_} :> {a + b}], {}, None, anEventOrdering, <||>] @ {1, 2, 3}], + (* Symbol Leak *) + testSymbolLeak[GenerateMultihistory[MultisetSubstitutionSystem[{a_, b_} :> {a + b}], {1, 2, 3}]], - (* Rules *) - testUnevaluated[ - GenerateMultihistory[MultisetSubstitutionSystem[##2], <||>, None, anEventOrdering, <||>] @ {1}, {#}] & @@@ - {{MultisetSubstitutionSystem::argx}, - {MultisetSubstitutionSystem::argx, 1, 2}, - {GenerateMultihistory::invalidMultisetRules, 1}, - {GenerateMultihistory::ruleOutputNotList, {1} -> 2}}, + (* Rules *) + testUnevaluated[GenerateMultihistory[MultisetSubstitutionSystem[##2], {1}], {#}] & @@@ { + {MultisetSubstitutionSystem::argx}, + {MultisetSubstitutionSystem::argx, 1, 2}, + {GenerateMultihistory::invalidMultisetRules, 1}, + {GenerateMultihistory::ruleOutputNotList, {1} -> 2}}, - (* Init *) - testUnevaluated[ - GenerateMultihistory[MultisetSubstitutionSystem[{1} -> {2}], <||>, None, anEventOrdering, <||>] @ 1, - {GenerateMultihistory::multisetInitNotList}], + (* Init *) + testUnevaluated[GenerateMultihistory[MultisetSubstitutionSystem[{1} -> {2}], 1], {}], - (* Ordering not yet supported *) - testUnevaluated[ - GenerateMultihistory[MultisetSubstitutionSystem[{1} -> {2}], {}, None, {"RuleIndex"}, {}] @ {1}, - {GenerateMultihistory::multisetEventOrderingNotImplemented}], - - (* Token deduplication not yet supported *) - testUnevaluated[ - GenerateMultihistory[MultisetSubstitutionSystem[{1} -> {2}], {}, All, anEventOrdering, {}] @ {1}, - {GenerateMultihistory::multisetTokenDeduplicationNotImplemented}], - - (* Parameters *) - testUnevaluated[ - GenerateMultihistory[MultisetSubstitutionSystem[{1} -> {2}], <|# -> -1|>, None, anEventOrdering, <||>] @ - {1}, - {GenerateMultihistory::notNonNegativeIntegerOrInfinityParameter}] & /@ - {"MaxGeneration", "MaxDestroyerEvents", "MinEventInputs", "MaxEventInputs"}, - - testUnevaluated[ - GenerateMultihistory[ - MultisetSubstitutionSystem[{1} -> {2}], <||>, None, anEventOrdering, <|"MaxEvents" -> -1|>] @ {1}, - {GenerateMultihistory::notNonNegativeIntegerOrInfinityParameter}] - }] + (* Parameters *) + testUnevaluated[GenerateMultihistory[MultisetSubstitutionSystem[{1} -> {2}], {1}, # -> -1], + {GenerateMultihistory::invalidParameter}] & /@ + {MaxGeneration, MaxDestroyerEvents, MinEventInputs, MaxEventInputs, MaxEvents} } |>, "Multiset System Rules" -> <| @@ -61,195 +37,155 @@ lastEventGeneration[Multihistory[_, data_]] := data["EventGenerations"]["Part", -1]; ), "tests" -> { - With[{anEventOrdering = EventOrderingFunctions[MultisetSubstitutionSystem]}, { - Function[{rules, selection, stopping, init, expectedCreatedExpressions}, - VerificationTest[ - allExpressions @ GenerateMultihistory[ - MultisetSubstitutionSystem[rules], selection, None, anEventOrdering, stopping] @ init, - Join[init, expectedCreatedExpressions], - SameTest -> MatchQ]] @@@ - {{{1} -> {1}, <||>, <|"MaxEvents" -> 1|>, {1}, {1}}, - (* 1 does not match any lists, {1} should be used for matching a single 1 as an expression *) - {1 -> 2, <||>, <|"MaxEvents" -> 1|>, {1, 2, 3}, {}}, - {{1} -> {2}, <|"MaxGeneration" -> 1|>, <||>, {1, 2, 3}, {2}}, - {{2} -> {5}, <|"MaxGeneration" -> 1|>, <||>, {1, 2, 3}, {5}}, - {{2} :> {5}, <|"MaxGeneration" -> 1|>, <||>, {1, 2, 3}, {5}}, - {{{2} :> {5}, {3} :> {6}}, <|"MaxGeneration" -> 1|>, <||>, {1, 2, 3}, {5, 6}}, - {{{2} -> {5}, {3} :> {6}}, <|"MaxGeneration" -> 1|>, <||>, {1, 2, 3}, {5, 6}}, - {{{2} -> {5}, {3} :> {6}}, <|"MaxGeneration" -> 2|>, <||>, {1, 2, 3}, {5, 6}}, - {{3, 2} -> {5}, <|"MaxGeneration" -> 1|>, <||>, {1, 2, 3}, {5}}, - {{4} -> {5}, <|"MaxGeneration" -> 1|>, <||>, {1, 2, 3}, {}}, - {{{1}} :> {}, <|"MaxGeneration" -> 1|>, <||>, {{1}}, {}}, - {{{1}, {2}} :> {{3}}, <|"MaxGeneration" -> 1|>, <||>, {{1}, {2}}, {{3}}}, - {{{1}, {2}} :> {{3}}, <|"MaxGeneration" -> 1|>, <||>, {{2}, {1}}, {{3}}}, - {{x_List ? (Length[#] == 3 &), y_List ? (Length[#] == 6 &)} :> {x, y, Join[x, y]}, - <|"MaxGeneration" -> 2, "MaxEventInputs" -> 6|>, - <||>, - {"This" -> "that", {2, 3, 4}, {2, 5}, {1, 2, 3, 4, 5, 6}}, - {{2, 3, 4}, {1, 2, 3, 4, 5, 6}, {2, 3, 4, 1, 2, 3, 4, 5, 6}, {2, 3, 4}, {1, 2, 3, 4, 5, 6}, - {2, 3, 4, 1, 2, 3, 4, 5, 6}}}, - {{x_List /; (Length[x] == 3), y_List /; (Length[y] == 6)} :> {x, y, Join[x, y]}, - <|"MaxGeneration" -> 2, "MaxEventInputs" -> 6|>, - <||>, - {"This" -> "that", {2, 3, 4}, {2, 5}, {1, 2, 3, 4, 5, 6}}, - {{2, 3, 4}, {1, 2, 3, 4, 5, 6}, {2, 3, 4, 1, 2, 3, 4, 5, 6}, {2, 3, 4}, {1, 2, 3, 4, 5, 6}, - {2, 3, 4, 1, 2, 3, 4, 5, 6}}}, - {{{a_, b_}, {b_, c_}} :> {{a, c}}, - <|"MaxGeneration" -> 3, "MaxDestroyerEvents" -> 1|>, - <||>, - {{1, 2}, {2, 3}, {3, 4}, {4, 5}}, - {{1, 3}, {3, 5}, {1, 5}}}, - {{{a_, b_}, {b_, c_}} :> {{a, c}}, - "MaxGeneration" -> 2, - <||>, - {{1, 2}, {2, 3}, {3, 4}, {4, 5}}, - {{1, 3}, {2, 4}, {1, 4}, {3, 5}, {2, 5}, {1, 4}, {2, 5}, {1, 5}}}, - {{{a_, b_}, {b_, c_}} :> {{a, c}}, - "MaxGeneration" -> 1, - <||>, - {{1, 2}, {2, 3}, {3, 4}, {4, 5}}, - {{1, 3}, {2, 4}, {3, 5}}}, - {{{_}} -> {}, <||>, <||>, {{1}, {2}, {3}, {4}, {5}}, {}}, - {{{1}} -> {{2}}, <|"MaxGeneration" -> 1|>, <||>, {{1}, {1}, {1}}, {{2}, {2}, {2}}}, - {{{v[a1_], v[a2_]}, {v[a2_], v[a3_]}} :> {{v[a1], v[a3]}}, - <|"MaxGeneration" -> 1|>, - <||>, - {{v[1], v[2]}, {v[2], v[3]}}, - {{v[1], v[3]}}}, - (* Nested lists of vertices *) - {ToPatternRules[{{2, 2, 1}, {2, 2, 2}} -> {{1, 1, 3}, {1, 1, 1}, {2, 1, 2}, {3, 3, 2}}], - <|"MaxGeneration" -> 2|>, - <||>, - {Table[{0, 0, 0}, 3]}, - {}}, - {ToPatternRules[{{2, 2, 1}, {2, 2, 2}} -> {{1, 1, 3}, {1, 1, 1}, {2, 1, 2}, {3, 3, 2}}], - <|"MaxGeneration" -> 1|>, - <||>, - {{{2}, {2}, 1}, {{2}, {2}, {2}}}, - {{1, 1, v2_ ? AtomQ}, {1, 1, 1}, {{2}, 1, {2}}, {v2_ ? AtomQ, v2_ ? AtomQ, {2}}}}, - {ToPatternRules[{{1, 1, 1}} -> {{1, 1, 1, 1}}], - <|"MaxGeneration" -> 2|>, - <||>, - {Table[{0, 0, 0}, 3]}, - {ConstantArray[{0, 0, 0}, 4]}}, - (* Potential variable collision between different rule inputs and outputs *) - {ToPatternRules[{{{1, 1}, {2, 3}} -> {{2, 1}, {2, 2}, {2, 3}, {4, 2}}, {{1, 2}, {1, 2}} -> {{3, 2}}}], - <||>, - <|"MaxEvents" -> 1|>, - {{1, 0}, {6, 1}, {1, 0}, {1, 1}, {1, 0}, {7, 1}, {3, 0}, {3, 3}, {3, 1}, {8, 3}, {4, 0}, {4, 4}, {4, 0}, - {9, 4}, {2, 2}, {2, 2}, {2, 0}, {10, 2}, {2, 1}, {2, 2}, {2, 0}, {11, 2}, {5, 1}, {5, 5}, {5, 2}, {12, 5}}, - {{_Symbol, 0}}}, - {ToPatternRules[{{1, 2} -> {}, {1} -> {2}}], <||>, <|"MaxEvents" -> 1|>, {{1}}, {_ ? AtomQ}}, - {{0} :> {1, 2}, <||>, <|"MaxEvents" -> 2|>, {0}, {1, 2}}, - (* there is only one created expression because the empty set {} can only be matched once *) - {{} :> {0}, <||>, <|"MaxEvents" -> 2|>, {}, {0}}, - {{x_, y_} /; OddQ[x + y] :> {x + y}, "MaxDestroyerEvents" -> 1, {}, Range[10], {3, 7, 11, 15, 19}}, - {{x_, y_} /; Mod[x + y, 2] == 0 :> {x + y}, - "MaxDestroyerEvents" -> 1, - <||>, - Range[10], - {4, 6, 12, 14, 14, 18, 28, 46}}, - {{x_, y_} /; x >= 8 :> {x - 8, y + 8}, - <|"MaxGeneration" -> 20, "MaxDestroyerEvents" -> 1|>, - <||>, - Range[10], - {__ ? (Not @* Negative)}}, - {{x___} /; Plus[x] == 5 && OrderedQ[{x}] :> {Length[{x}]}, - <|"MaxGeneration" -> 2|>, - <||>, - {1, 2, 3, 5}, - {1, 2, 3, 3}}, - {{x_, y_} /; x < y :> Module[{z = Hash[{x, y}]}, {z}], - "MaxDestroyerEvents" -> 1, - <||>, - {1, 2, 3, 4}, - {Hash[{1, 2}], Hash[{3, 4}], Hash[Sort @ {Hash[{1, 2}], Hash[{3, 4}]}]}}, - {{x__, y__} /; OrderedQ[Catenate[{x, y}]] :> {Catenate[{x, y}]}, - <|"MaxEventInputs" -> 3|>, - <||>, - {{1}, {2}, {3}}, - {{1, 2}, {1, 3}, {2, 3}, {1, 2, 3}, {1, 2, 3}, {1, 2, 3}, {1, 2, 3}}}, - {{a__, b__} /; OrderedQ[{a, b}] :> {{a}, {b}}, - <|"MaxGeneration" -> 1, "MinEventInputs" -> 3, "MaxEventInputs" -> 3|>, - <||>, - {1, 2, 3}, - {{1}, {2, 3}, {1, 2}, {3}}}, - {{Longest[a__], b__} /; OrderedQ[{a, b}] :> {{a}, {b}}, - <|"MaxGeneration" -> 1, "MinEventInputs" -> 3, "MaxEventInputs" -> 3|>, - <||>, - {1, 2, 3}, - {{1, 2}, {3}, {1}, {2, 3}}}, - {{a_Integer, b_Integer} :> {a + b}, "MaxGeneration" -> 1, {}, {1, 2, 3, "x"}, {3, 3, 4, 4, 5, 5}}, - {{PatternSequence[a_, b_], c_} :> {a + b + c}, "MaxGeneration" -> 1, {}, {1, 2, 3}, ConstantArray[6, 6]}, - {{x_ | Repeated[x_, {2}]} :> {2 x}, "MaxGeneration" -> 1, {}, {1, 1, 1}, ConstantArray[2, 9]}, - {{Alternatives[]} :> {}, {}, {}, Range[1000], {}}, (* empty Alternatives does not match to anything *) - {{x_ ..} :> {x + 1}, "MaxGeneration" -> 1, {}, {1, 1}, ConstantArray[2, 4]}, - {{Repeated[x_, 2]} :> {x + 1}, "MaxGeneration" -> 1, {}, {1, 1, 1}, ConstantArray[2, 9]}, - {{Repeated[x_, {2, 3}]} :> {x + 1}, "MaxGeneration" -> 1, {}, {1, 1, 1}, ConstantArray[2, 12]}, - {{Repeated[x_, {2}]} :> {x + 1}, "MaxGeneration" -> 1, {}, {1, 1, 1}, ConstantArray[2, 6]}, - {{x_ ...} :> {x + 1}, "MaxGeneration" -> 1, {}, {1}, {1, 2, 2, 2, 2}}, - {{RepeatedNull[x_, 2]} :> {x + 1}, "MaxGeneration" -> 1, {}, {1, 1}, Join[{1}, ConstantArray[2, 9]]}, - {{RepeatedNull[x_, {2, 3}]} :> {x + 1}, "MaxGeneration" -> 1, {}, {1, 1, 1}, ConstantArray[2, 12]}, - {{RepeatedNull[x_, {2}]} :> {x + 1}, "MaxGeneration" -> 1, {}, {1, 1, 1}, ConstantArray[2, 6]}, - {{x : Except[1]} :> {x + 1}, "MaxGeneration" -> 1, {}, Range[10], Range[3, 11]}, - {{x : Except[1, _Integer]} :> {x + 1}, "MaxGeneration" -> 1, {}, {0, 1, "x"}, {1}}, - {{Longest[Repeated[x_, {2}]]} :> {x + 1}, "MaxGeneration" -> 1, {}, {1, 1, 1}, ConstantArray[2, 6]}, - {{Shortest[Repeated[x_, {2}]]} :> {x + 1}, "MaxGeneration" -> 1, {}, {1, 1, 1}, ConstantArray[2, 6]}, - {{OptionsPattern[]} :> {3}, "MaxGeneration" -> 1, {}, {1, {"test" -> 2}}, {3, 3}}, - {{OptionsPattern[], OptionsPattern[]} :> {3}, "MaxGeneration" -> 1, {}, {1, {"test" -> 2}}, {3, 3, 3}}, - {{PatternSequence[x_, y_]} :> {x + y}, "MaxGeneration" -> 1, {}, {1, 2, 3}, {3, 3, 4, 4, 5, 5}}, - {{Verbatim[_], Verbatim[_]} :> {4}, "MaxGeneration" -> 1, {}, {_, _, 2, 3}, {4, 4}}, - {{HoldPattern[_[x_ + x_]]} :> {0}, - "MaxGeneration" -> 1, - {}, - {Hold[2 + 2], Hold[2 + 3], Hold[x + x]}, - {0, 0, 0, 0}}, - {{OrderlessPatternSequence[x_, y_]} :> {x + y}, - "MaxGeneration" -> 1, - {}, - {1, 2, 3}, - Catenate[ConstantArray[#, 4] & /@ {3, 4, 5}]}, - {{KeyValuePattern[{}]} :> {3}, "MaxGeneration" -> 1, {}, {1, {}, {"test" -> 2}}, {3, 3}}, - {{a_ /; OddQ[a], (b_ ? EvenQ)} :> {a + b}, "MaxGeneration" -> 1, {}, {1, 2, 3, 4}, {3, 5, 5, 7}}, - {{a_ : 0} :> {a}, "MaxGeneration" -> 1, {}, {1, 2, 3, 4}, {0, 1, 2, 3, 4, 0}}, - {HoldPattern @ {_[x_ + x_]} :> {0}, - "MaxGeneration" -> 1, - {}, - {Hold[2 + 2], Hold[2 + 3], Hold[x + x]}, - {0, 0, 0, 0}}, - {{x_} | HoldPattern[{x_, y_}] :> {x + y}, "MaxGeneration" -> 1, {}, {1, 2, 3}, {1, 2, 3, 3, 3, 4, 4, 5, 5}}, - {{a_, b_} /; OddQ[a] && EvenQ[b] :> {a + b}, "MaxGeneration" -> 1, {}, {1, 2, 3, 4}, {3, 5, 5, 7}}, - {x : {_, _} :> {Total[x]}, "MaxGeneration" -> 1, {}, {1, 2, 3, 4}, {3, 3, 4, 4, 5, 5, 5, 5, 6, 6, 7, 7}}, - {Except[{1, 2}, {a_, b_}] /; a < b :> {a + b}, "MaxGeneration" -> 1, {}, {1, 2, 3, 4}, {4, 5, 5, 6, 7}}, - {Verbatim[{_, __}] :> {0}, "MaxGeneration" -> 1, {}, {_, __, 1}, {0}}}, + Function[{rules, parameters, init, expectedCreatedExpressions}, + VerificationTest[allExpressions @ GenerateMultihistory[MultisetSubstitutionSystem[rules], init, parameters], + Join[init, expectedCreatedExpressions], + SameTest -> MatchQ]] @@@ + {{{1} -> {1}, MaxEvents -> 1, {1}, {1}}, + (* 1 does not match any lists, {1} should be used for matching a single 1 as an expression *) + {1 -> 2, MaxEvents -> 1, {1, 2, 3}, {}}, + {{1} -> {2}, MaxGeneration -> 1, {1, 2, 3}, {2}}, + {{2} -> {5}, MaxGeneration -> 1, {1, 2, 3}, {5}}, + {{2} :> {5}, MaxGeneration -> 1, {1, 2, 3}, {5}}, + {{{2} :> {5}, {3} :> {6}}, MaxGeneration -> 1, {1, 2, 3}, {5, 6}}, + {{{2} -> {5}, {3} :> {6}}, MaxGeneration -> 1, {1, 2, 3}, {5, 6}}, + {{{2} -> {5}, {3} :> {6}}, MaxGeneration -> 2, {1, 2, 3}, {5, 6}}, + {{3, 2} -> {5}, MaxGeneration -> 1, {1, 2, 3}, {5}}, + {{4} -> {5}, MaxGeneration -> 1, {1, 2, 3}, {}}, + {{{1}} :> {}, MaxGeneration -> 1, {{1}}, {}}, + {{{1}, {2}} :> {{3}}, MaxGeneration -> 1, {{1}, {2}}, {{3}}}, + {{{1}, {2}} :> {{3}}, MaxGeneration -> 1, {{2}, {1}}, {{3}}}, + {{x_List ? (Length[#] == 3 &), y_List ? (Length[#] == 6 &)} :> {x, y, Join[x, y]}, + {MaxGeneration -> 2, MaxEventInputs -> 6}, + {"This" -> "that", {2, 3, 4}, {2, 5}, {1, 2, 3, 4, 5, 6}}, + {{2, 3, 4}, {1, 2, 3, 4, 5, 6}, {2, 3, 4, 1, 2, 3, 4, 5, 6}, {2, 3, 4}, {1, 2, 3, 4, 5, 6}, + {2, 3, 4, 1, 2, 3, 4, 5, 6}}}, + {{x_List /; (Length[x] == 3), y_List /; (Length[y] == 6)} :> {x, y, Join[x, y]}, + {MaxGeneration -> 2, MaxEventInputs -> 6}, + {"This" -> "that", {2, 3, 4}, {2, 5}, {1, 2, 3, 4, 5, 6}}, + {{2, 3, 4}, {1, 2, 3, 4, 5, 6}, {2, 3, 4, 1, 2, 3, 4, 5, 6}, {2, 3, 4}, {1, 2, 3, 4, 5, 6}, + {2, 3, 4, 1, 2, 3, 4, 5, 6}}}, + {{{a_, b_}, {b_, c_}} :> {{a, c}}, + {MaxGeneration -> 3, MaxDestroyerEvents -> 1}, + {{1, 2}, {2, 3}, {3, 4}, {4, 5}}, + {{1, 3}, {3, 5}, {1, 5}}}, + {{{a_, b_}, {b_, c_}} :> {{a, c}}, + MaxGeneration -> 2, + {{1, 2}, {2, 3}, {3, 4}, {4, 5}}, + {{1, 3}, {2, 4}, {1, 4}, {3, 5}, {2, 5}, {1, 4}, {2, 5}, {1, 5}}}, + {{{a_, b_}, {b_, c_}} :> {{a, c}}, + MaxGeneration -> 1, + {{1, 2}, {2, 3}, {3, 4}, {4, 5}}, + {{1, 3}, {2, 4}, {3, 5}}}, + {{{_}} -> {}, {}, {{1}, {2}, {3}, {4}, {5}}, {}}, + {{{1}} -> {{2}}, MaxGeneration -> 1, {{1}, {1}, {1}}, {{2}, {2}, {2}}}, + {{{v[a1_], v[a2_]}, {v[a2_], v[a3_]}} :> {{v[a1], v[a3]}}, + MaxGeneration -> 1, + {{v[1], v[2]}, {v[2], v[3]}}, + {{v[1], v[3]}}}, + (* Nested lists of vertices *) + {ToPatternRules[{{2, 2, 1}, {2, 2, 2}} -> {{1, 1, 3}, {1, 1, 1}, {2, 1, 2}, {3, 3, 2}}], + MaxGeneration -> 2, + {Table[{0, 0, 0}, 3]}, + {}}, + {ToPatternRules[{{2, 2, 1}, {2, 2, 2}} -> {{1, 1, 3}, {1, 1, 1}, {2, 1, 2}, {3, 3, 2}}], + MaxGeneration -> 1, + {{{2}, {2}, 1}, {{2}, {2}, {2}}}, + {{1, 1, v2_ ? AtomQ}, {1, 1, 1}, {{2}, 1, {2}}, {v2_ ? AtomQ, v2_ ? AtomQ, {2}}}}, + {ToPatternRules[{{1, 1, 1}} -> {{1, 1, 1, 1}}], + MaxGeneration -> 2, + {Table[{0, 0, 0}, 3]}, + {ConstantArray[{0, 0, 0}, 4]}}, + (* Potential variable collision between different rule inputs and outputs *) + {ToPatternRules[{{{1, 1}, {2, 3}} -> {{2, 1}, {2, 2}, {2, 3}, {4, 2}}, {{1, 2}, {1, 2}} -> {{3, 2}}}], + MaxEvents -> 1, + {{1, 0}, {6, 1}, {1, 0}, {1, 1}, {1, 0}, {7, 1}, {3, 0}, {3, 3}, {3, 1}, {8, 3}, {4, 0}, {4, 4}, {4, 0}, + {9, 4}, {2, 2}, {2, 2}, {2, 0}, {10, 2}, {2, 1}, {2, 2}, {2, 0}, {11, 2}, {5, 1}, {5, 5}, {5, 2}, {12, 5}}, + {{_Symbol, 0}}}, + {ToPatternRules[{{1, 2} -> {}, {1} -> {2}}], MaxEvents -> 1, {{1}}, {_ ? AtomQ}}, + {{0} :> {1, 2}, MaxEvents -> 2, {0}, {1, 2}}, + (* there is only one created expression because the empty set {} can only be matched once *) + {{} :> {0}, MaxEvents -> 2, {}, {0}}, + {{x_, y_} /; OddQ[x + y] :> {x + y}, MaxDestroyerEvents -> 1, Range[10], {3, 7, 11, 15, 19}}, + {{x_, y_} /; Mod[x + y, 2] == 0 :> {x + y}, + MaxDestroyerEvents -> 1, + Range[10], + {4, 6, 12, 14, 14, 18, 28, 46}}, + {{x_, y_} /; x >= 8 :> {x - 8, y + 8}, + {MaxGeneration -> 20, MaxDestroyerEvents -> 1}, + Range[10], + {__ ? (Not @* Negative)}}, + {{x___} /; Plus[x] == 5 && OrderedQ[{x}] :> {Length[{x}]}, MaxGeneration -> 2, {1, 2, 3, 5}, {1, 2, 3, 3}}, + {{x_, y_} /; x < y :> Module[{z = Hash[{x, y}]}, {z}], + MaxDestroyerEvents -> 1, + {1, 2, 3, 4}, + {Hash[{1, 2}], Hash[{3, 4}], Hash[Sort @ {Hash[{1, 2}], Hash[{3, 4}]}]}}, + {{x__, y__} /; OrderedQ[Catenate[{x, y}]] :> {Catenate[{x, y}]}, + MaxEventInputs -> 3, + {{1}, {2}, {3}}, + {{1, 2}, {1, 3}, {2, 3}, {1, 2, 3}, {1, 2, 3}, {1, 2, 3}, {1, 2, 3}}}, + {{a__, b__} /; OrderedQ[{a, b}] :> {{a}, {b}}, + {MaxGeneration -> 1, MinEventInputs -> 3, MaxEventInputs -> 3}, + {1, 2, 3}, + {{1}, {2, 3}, {1, 2}, {3}}}, + {{Longest[a__], b__} /; OrderedQ[{a, b}] :> {{a}, {b}}, + {MaxGeneration -> 1, MinEventInputs -> 3, MaxEventInputs -> 3}, + {1, 2, 3}, + {{1, 2}, {3}, {1}, {2, 3}}}, + {{a_Integer, b_Integer} :> {a + b}, MaxGeneration -> 1, {1, 2, 3, "x"}, {3, 3, 4, 4, 5, 5}}, + {{PatternSequence[a_, b_], c_} :> {a + b + c}, MaxGeneration -> 1, {1, 2, 3}, ConstantArray[6, 6]}, + {{x_ | Repeated[x_, {2}]} :> {2 x}, MaxGeneration -> 1, {1, 1, 1}, ConstantArray[2, 9]}, + {{Alternatives[]} :> {}, {}, Range[1000], {}}, (* empty Alternatives does not match to anything *) + {{x_ ..} :> {x + 1}, MaxGeneration -> 1, {1, 1}, ConstantArray[2, 4]}, + {{Repeated[x_, 2]} :> {x + 1}, MaxGeneration -> 1, {1, 1, 1}, ConstantArray[2, 9]}, + {{Repeated[x_, {2, 3}]} :> {x + 1}, MaxGeneration -> 1, {1, 1, 1}, ConstantArray[2, 12]}, + {{Repeated[x_, {2}]} :> {x + 1}, MaxGeneration -> 1, {1, 1, 1}, ConstantArray[2, 6]}, + {{x_ ...} :> {x + 1}, MaxGeneration -> 1, {1}, {1, 2, 2, 2, 2}}, + {{RepeatedNull[x_, 2]} :> {x + 1}, MaxGeneration -> 1, {1, 1}, Join[{1}, ConstantArray[2, 9]]}, + {{RepeatedNull[x_, {2, 3}]} :> {x + 1}, MaxGeneration -> 1, {1, 1, 1}, ConstantArray[2, 12]}, + {{RepeatedNull[x_, {2}]} :> {x + 1}, MaxGeneration -> 1, {1, 1, 1}, ConstantArray[2, 6]}, + {{x : Except[1]} :> {x + 1}, MaxGeneration -> 1, Range[10], Range[3, 11]}, + {{x : Except[1, _Integer]} :> {x + 1}, MaxGeneration -> 1, {0, 1, "x"}, {1}}, + {{Longest[Repeated[x_, {2}]]} :> {x + 1}, MaxGeneration -> 1, {1, 1, 1}, ConstantArray[2, 6]}, + {{Shortest[Repeated[x_, {2}]]} :> {x + 1}, MaxGeneration -> 1, {1, 1, 1}, ConstantArray[2, 6]}, + {{OptionsPattern[]} :> {3}, MaxGeneration -> 1, {1, {"test" -> 2}}, {3, 3}}, + {{OptionsPattern[], OptionsPattern[]} :> {3}, MaxGeneration -> 1, {1, {"test" -> 2}}, {3, 3, 3}}, + {{PatternSequence[x_, y_]} :> {x + y}, MaxGeneration -> 1, {1, 2, 3}, {3, 3, 4, 4, 5, 5}}, + {{Verbatim[_], Verbatim[_]} :> {4}, MaxGeneration -> 1, {_, _, 2, 3}, {4, 4}}, + {{HoldPattern[_[x_ + x_]]} :> {0}, MaxGeneration -> 1, {Hold[2 + 2], Hold[2 + 3], Hold[x + x]}, {0, 0, 0, 0}}, + {{OrderlessPatternSequence[x_, y_]} :> {x + y}, + MaxGeneration -> 1, + {1, 2, 3}, + Catenate[ConstantArray[#, 4] & /@ {3, 4, 5}]}, + {{KeyValuePattern[{}]} :> {3}, MaxGeneration -> 1, {1, {}, {"test" -> 2}}, {3, 3}}, + {{a_ /; OddQ[a], (b_ ? EvenQ)} :> {a + b}, MaxGeneration -> 1, {1, 2, 3, 4}, {3, 5, 5, 7}}, + {{a_ : 0} :> {a}, MaxGeneration -> 1, {1, 2, 3, 4}, {0, 1, 2, 3, 4, 0}}, + {HoldPattern @ {_[x_ + x_]} :> {0}, MaxGeneration -> 1, {Hold[2 + 2], Hold[2 + 3], Hold[x + x]}, {0, 0, 0, 0}}, + {{x_} | HoldPattern[{x_, y_}] :> {x + y}, MaxGeneration -> 1, {1, 2, 3}, {1, 2, 3, 3, 3, 4, 4, 5, 5}}, + {{a_, b_} /; OddQ[a] && EvenQ[b] :> {a + b}, MaxGeneration -> 1, {1, 2, 3, 4}, {3, 5, 5, 7}}, + {x : {_, _} :> {Total[x]}, MaxGeneration -> 1, {1, 2, 3, 4}, {3, 3, 4, 4, 5, 5, 5, 5, 6, 6, 7, 7}}, + {Except[{1, 2}, {a_, b_}] /; a < b :> {a + b}, MaxGeneration -> 1, {1, 2, 3, 4}, {4, 5, 5, 6, 7}}, + {Verbatim[{_, __}] :> {0}, MaxGeneration -> 1, {_, __, 1}, {0}}}, - VerificationTest[ - eventCount @ GenerateMultihistory[ - MultisetSubstitutionSystem[{{1}} :> {}], <|"MaxGeneration" -> 1|>, None, anEventOrdering, <||>] @ {{1}}, - 1], + VerificationTest[ + eventCount @ GenerateMultihistory[MultisetSubstitutionSystem[{{1}} :> {}], {{1}}, MaxGeneration -> 1], 1], - Function[{rules, selection, init, expectedMaxGeneration, expectedEventCount}, - VerificationTest[ - Through[{lastEventGeneration, eventCount} @ GenerateMultihistory[ - MultisetSubstitutionSystem[rules], selection, None, anEventOrdering, <||>] @ init], - {expectedMaxGeneration, expectedEventCount}]] @@@ - {{{{a_, b_}} :> Module[{c}, {{a, c}, {c, b}}], <|"MaxGeneration" -> 7|>, {{1, 2}}, 7, 2^7 - 1}, - {{{_}} :> {}, <||>, {{1}, {2}, {3}, {4}, {5}}, 1, 5}, - {{{x_}} :> {{x}}, <|"MaxGeneration" -> 0|>, {{1}, {2}, {3}, {4}, {5}}, 0, 0}, - {{{{_}} :> {}, {{x_, _}} :> {{x}}}, <|"MaxGeneration" -> 2|>, {{1, 2}, {2}, {3}, {4}, {5}}, 2, 6}}, + Function[{rules, parameters, init, expectedMaxGeneration, expectedEventCount}, + VerificationTest[ + Through[{lastEventGeneration, eventCount} @ GenerateMultihistory[ + MultisetSubstitutionSystem[rules], init, parameters]], + {expectedMaxGeneration, expectedEventCount}]] @@@ + {{{{a_, b_}} :> Module[{c}, {{a, c}, {c, b}}], MaxGeneration -> 7, {{1, 2}}, 7, 2^7 - 1}, + {{{_}} :> {}, {}, {{1}, {2}, {3}, {4}, {5}}, 1, 5}, + {{{x_}} :> {{x}}, MaxGeneration -> 0, {{1}, {2}, {3}, {4}, {5}}, 0, 0}, + {{{{_}} :> {}, {{x_, _}} :> {{x}}}, MaxGeneration -> 2, {{1, 2}, {2}, {3}, {4}, {5}}, 2, 6}}, - (* Test invalid patterns *) - testUnevaluated[ - eventCount @ GenerateMultihistory[ - MultisetSubstitutionSystem[#], - <|"MaxGeneration" -> 1|>, - None, - anEventOrdering, - <||>] @ {{1}}, - {Pattern::patvar, GenerateMultihistory::ruleInstantiationMessage}] & /@ - {{{{Pattern[1, _], v2_}} :> {}, {{Pattern[2, _], v1_}} :> Module[{v2}, {v2}]}, - {{{Pattern[Pattern[a, _], _], v2_}} :> {}, {{Pattern[2, _], v1_}} :> Module[{v2}, {v2}]}} - }] + (* Test invalid patterns *) + testUnevaluated[ + eventCount @ GenerateMultihistory[MultisetSubstitutionSystem[#], {{1}}, MaxGeneration -> 1], + {Pattern::patvar, GenerateMultihistory::ruleInstantiationMessage}] & /@ + {{{{Pattern[1, _], v2_}} :> {}, {{Pattern[2, _], v1_}} :> Module[{v2}, {v2}]}, + {{{Pattern[Pattern[a, _], _], v2_}} :> {}, {{Pattern[2, _], v1_}} :> Module[{v2}, {v2}]}} } |>, "Multiset System Matching" -> <| @@ -262,80 +198,69 @@ allExpressions[Multihistory[_, data_]] := Normal @ data["Expressions"]; ), "tests" -> { - With[{anEventOrdering = EventOrderingFunctions[MultisetSubstitutionSystem]}, { - Function[{rule, selection, init, expectedCreatedExpressions}, - VerificationTest[ - allExpressions @ GenerateMultihistory[ - MultisetSubstitutionSystem[rule], - selection, - None, - anEventOrdering, - <||>] @ init, - Join[init, expectedCreatedExpressions]] - ] @@@ { - (* multihistory branching *) - {{{1} -> {2}, {1} -> {3}}, <||>, {1}, {2, 3}}, - {{{1} -> {2}, {1} -> {3}}, <|"MaxDestroyerEvents" -> 1|>, {1}, {2}}, - (* no branchlike-expressions matching *) - {{{1} -> {2}, {1} -> {3}, {2, 3} -> {4}}, <||>, {1}, {2, 3}}, - (* no timelike-expressions matching *) - {{{1} -> {2}, {2} -> {3}, {2, 3} -> {4}}, <||>, {1}, {2, 3}}, - (* spacelike-expressions matching *) - {{{1} -> {2, 3}, {2, 3} -> {4}}, <||>, {1}, {2, 3, 4}}, - (* no instantiating the same match multiple times *) - {{1} -> {2}, <||>, {1}, {2}}, - (* no matching rules that don't match *) - {{a_, a_} :> {0}, <||>, {1, 2}, {}}, - (* no mixed spacelike/branchlike matching *) - {{{{v, i}} -> {{v, 1}, {v, 2}}, - {{v, 1}} -> {{v, 1, 1}, {v, 1, 2}}, - {{v, 1, 1}, {v, 2}} -> {{v, f, 1}}, - {{v, 1, 2}, {v, 2}} -> {{v, f, 2}}, - {{v, f, 1}, {v, f, 2}} -> {{f}}}, - <||>, - {{v, i}}, - {{v, 1}, {v, 2}, {v, 1, 1}, {v, 1, 2}, {v, f, 1}, {v, f, 2}}}, - (* single-history spacelike merging *) - {{{{a_}, {a_, b_}} :> {{a, b}, {b}}, {{a_}, {a_}} :> {{a, a, a}}}, - <|"MaxDestroyerEvents" -> 1|>, - {{a1}, {a1, a2}, {a2, a3}, {a3, m1}, {b1}, {b1, b2}, {b2, m1}, {m1, m2}}, - {{a1, a2}, {a2}, {a2, a3}, {a3}, {a3, m1}, {m1}, {b1, b2}, {b2}, {b2, m1}, {m1}, {m1, m2}, {m2}, {m1, m2}, - {m2}, {m2, m2, m2}}}, - (* multihistory spacelike merging *) - {{{{a_}, {a_, b_}} :> {{b}}, {{a_}, {a_}} :> {{a, a, a}}}, - <||>, - {{a1}, {a1, a2}, {a2, a3}, {a3, m1}, {b1}, {b1, b2}, {b2, m1}, {m1, m2}}, - {{a2}, {a3}, {m1}, {b2}, {m1}, {m2}, {m2}, {m1, m1, m1}, {m1, m1, m1}}}, - (* no single-history branchlike merging *) - {{{{a_}, {a_, b_}} :> {{a, b}, {b}}, {{a_}, {a_}} :> {{a, a, a}}}, - <|"MaxDestroyerEvents" -> 1|>, - {{o1}, {o1, a1}, {o1, b1}, {a1, a2}, {a2, a3}, {a3, m1}, {b1, b2}, {b2, m1}, {m1, m2}}, - {{o1, a1}, {a1}, {a1, a2}, {a2}, {a2, a3}, {a3}, {a3, m1}, {m1}, {m1, m2}, {m2}}}, - (* no multihistory branchlike merging *) - {{{{a_}, {a_, b_}} :> {{b}}, {{a_}, {a_}} :> {{a, a, a}}}, - <||>, - {{o1}, {o1, a1}, {o1, b1}, {a1, a2}, {a2, a3}, {a3, m1}, {b1, b2}, {b2, m1}, {m1, m2}}, - {{a1}, {b1}, {a2}, {a3}, {m1}, {b2}, {m1}, {m2}, {m2}}}}, + Function[{rule, parameters, init, expectedCreatedExpressions}, + VerificationTest[allExpressions @ GenerateMultihistory[MultisetSubstitutionSystem[rule], init, parameters], + Join[init, expectedCreatedExpressions]] + ] @@@ { + (* multihistory branching *) + {{{1} -> {2}, {1} -> {3}}, {}, {1}, {2, 3}}, + {{{1} -> {2}, {1} -> {3}}, MaxDestroyerEvents -> 1, {1}, {2}}, + (* no branchlike-expressions matching *) + {{{1} -> {2}, {1} -> {3}, {2, 3} -> {4}}, {}, {1}, {2, 3}}, + (* no timelike-expressions matching *) + {{{1} -> {2}, {2} -> {3}, {2, 3} -> {4}}, {}, {1}, {2, 3}}, + (* spacelike-expressions matching *) + {{{1} -> {2, 3}, {2, 3} -> {4}}, {}, {1}, {2, 3, 4}}, + (* no instantiating the same match multiple times *) + {{1} -> {2}, {}, {1}, {2}}, + (* no matching rules that don't match *) + {{a_, a_} :> {0}, {}, {1, 2}, {}}, + (* no mixed spacelike/branchlike matching *) + {{{{v, i}} -> {{v, 1}, {v, 2}}, + {{v, 1}} -> {{v, 1, 1}, {v, 1, 2}}, + {{v, 1, 1}, {v, 2}} -> {{v, f, 1}}, + {{v, 1, 2}, {v, 2}} -> {{v, f, 2}}, + {{v, f, 1}, {v, f, 2}} -> {{f}}}, + {}, + {{v, i}}, + {{v, 1}, {v, 2}, {v, 1, 1}, {v, 1, 2}, {v, f, 1}, {v, f, 2}}}, + (* single-history spacelike merging *) + {{{{a_}, {a_, b_}} :> {{a, b}, {b}}, {{a_}, {a_}} :> {{a, a, a}}}, + MaxDestroyerEvents -> 1, + {{a1}, {a1, a2}, {a2, a3}, {a3, m1}, {b1}, {b1, b2}, {b2, m1}, {m1, m2}}, + {{a1, a2}, {a2}, {a2, a3}, {a3}, {a3, m1}, {m1}, {b1, b2}, {b2}, {b2, m1}, {m1}, {m1, m2}, {m2}, {m1, m2}, + {m2}, {m2, m2, m2}}}, + (* multihistory spacelike merging *) + {{{{a_}, {a_, b_}} :> {{b}}, {{a_}, {a_}} :> {{a, a, a}}}, + {}, + {{a1}, {a1, a2}, {a2, a3}, {a3, m1}, {b1}, {b1, b2}, {b2, m1}, {m1, m2}}, + {{a2}, {a3}, {m1}, {b2}, {m1}, {m2}, {m2}, {m1, m1, m1}, {m1, m1, m1}}}, + (* no single-history branchlike merging *) + {{{{a_}, {a_, b_}} :> {{a, b}, {b}}, {{a_}, {a_}} :> {{a, a, a}}}, + MaxDestroyerEvents -> 1, + {{o1}, {o1, a1}, {o1, b1}, {a1, a2}, {a2, a3}, {a3, m1}, {b1, b2}, {b2, m1}, {m1, m2}}, + {{o1, a1}, {a1}, {a1, a2}, {a2}, {a2, a3}, {a3}, {a3, m1}, {m1}, {m1, m2}, {m2}}}, + (* no multihistory branchlike merging *) + {{{{a_}, {a_, b_}} :> {{b}}, {{a_}, {a_}} :> {{a, a, a}}}, + {}, + {{o1}, {o1, a1}, {o1, b1}, {a1, a2}, {a2, a3}, {a3, m1}, {b1, b2}, {b2, m1}, {m1, m2}}, + {{a1}, {b1}, {a2}, {a3}, {m1}, {b2}, {m1}, {m2}, {m2}}}}, - (* non-overlapping systems produce the same behavior *) - (* "InstantiationCounts" stores the sequences of expressions that were tried but do not match. - "MaxDestroyerEvents" prevents some of these sequences to be tried in the first place, thus changing - "InstantiationCounts" *) - VerificationTest[ - With[{ - serializeMultihistory = (Normal /@ # &) /@ Normal /@ KeyDrop[Last @ #, "InstantiationCounts"] &, - multihistories = GenerateMultihistory[ - MultisetSubstitutionSystem[ - {{v1_, v2_}, {v2_, v3_, v4_}} :> - Module[{v5 = Hash[{{v1, v2}, {v2, v3, v4}}]}, {{v2, v3}, {v3, v4, v5}, {v1, v2, v3, v4}}]], - <|"MaxDestroyerEvents" -> #|>, - None, - anEventOrdering, - <|"MaxEvents" -> 30|>] @ - {{1, 2}, {2, 3, 4}} & /@ {1, Infinity}}, - SameQ @@ serializeMultihistory /@ multihistories] - ] - }] + (* non-overlapping systems produce the same behavior *) + (* "InstantiationCounts" stores the sequences of expressions that were tried but do not match. + "MaxDestroyerEvents" prevents some of these sequences to be tried in the first place, thus changing + "InstantiationCounts" *) + VerificationTest[ + With[{ + serializeMultihistory = (Normal /@ # &) /@ Normal /@ KeyDrop[Last @ #, "InstantiationCounts"] &, + multihistories = GenerateMultihistory[ + MultisetSubstitutionSystem[ + {{v1_, v2_}, {v2_, v3_, v4_}} :> + Module[{v5 = Hash[{{v1, v2}, {v2, v3, v4}}]}, {{v2, v3}, {v3, v4, v5}, {v1, v2, v3, v4}}]], + {{1, 2}, {2, 3, 4}}, + MaxEvents -> 30, MaxDestroyerEvents -> #] & /@ {1, Infinity}}, + SameQ @@ serializeMultihistory /@ multihistories] + ] } |>, "Multiset System Ordering" -> <| @@ -350,13 +275,8 @@ ), "tests" -> { Function[{rule, init, lastEventInputsOutput}, - VerificationTest[ - lastEventInputs @ GenerateMultihistory[MultisetSubstitutionSystem[rule], - <||>, - None, - EventOrderingFunctions[MultisetSubstitutionSystem], - <|"MaxEvents" -> 1|>] @ init, - lastEventInputsOutput] + VerificationTest[lastEventInputs @ GenerateMultihistory[MultisetSubstitutionSystem[rule], init, MaxEvents -> 1], + lastEventInputsOutput] ] @@@ { {{{2, 3, 4} -> {X}, {3} -> {X}}, {1, 2, 3, 4, 5}, {3}}, {{{b_, _}, {_, b_}} :> {}, {{1, 2}, {3, 4}, {4, 5}, {2, 3}, {a, b}, {b, c}, {5, 6}}, {4, 1}}, @@ -366,11 +286,7 @@ Function[{rule, inits, lastExpressions}, VerificationTest[ - lastExpression @* GenerateMultihistory[MultisetSubstitutionSystem[rule], - <||>, - None, - EventOrderingFunctions[MultisetSubstitutionSystem], - <|"MaxEvents" -> 1|>] /@ inits, + lastExpression @* GenerateMultihistory[MultisetSubstitutionSystem[rule], MaxEvents -> 1] /@ inits, lastExpressions] ] @@@ { {{{{1, 2}, {2, 3}} -> {1}, {{4, 5}, {5, 6}} -> {2}}, @@ -398,82 +314,53 @@ destroyerEventCounts[Multihistory[_, data_]] := Normal @ data["ExpressionDestroyerEventCounts"]; ), "tests" -> { - With[{anEventOrdering = EventOrderingFunctions[MultisetSubstitutionSystem]}, { - Function[{ - rule, selection, stopping, init, expectedMaxEventGeneration, expectedEventCount, expectedTerminationReason}, - VerificationTest[ - Through[{maxEventGeneration, eventCount, terminationReason} @ - GenerateMultihistory[ - MultisetSubstitutionSystem[rule], selection, None, anEventOrdering, stopping] @ init], - {expectedMaxEventGeneration, expectedEventCount, expectedTerminationReason}] - ] @@@ { - (* Complete is returned if MaxGeneration is reached because MaxGeneration is not a stopping condition *) - {{_} :> {Unique[]}, <|"MaxGeneration" -> 2|>, <||>, {1}, 2, 2, "Complete"}, - {{_} :> {Unique[]}, <|"MaxGeneration" -> 0|>, <||>, {1}, 0, 0, "Complete"}, - {{_} :> {Unique[]}, <|"MaxGeneration" -> 3|>, <|"MaxEvents" -> 2|>, {1}, 2, 2, "MaxEvents"}, - {{_} :> {Unique[]}, <||>, <|"MaxEvents" -> 0|>, {1}, 0, 0, "MaxEvents"}, - {ToPatternRules[{{0, 1}} -> {{0, 2}, {2, 1}}], <|"MaxGeneration" -> 3|>, <||>, {{0, 1}}, 3, 7, "Complete"}, - {ToPatternRules[{{0, 1}} -> {{0, 2}, {2, 1}}], <||>, <|"MaxEvents" -> 6|>, {{0, 1}}, 3, 6, "MaxEvents"}, - {ToPatternRules[{{0, 1}} -> {{0, 2}, {2, 1}}], - <|"MaxGeneration" -> 3|>, - <|"MaxEvents" -> 6|>, - {{0, 1}}, - 3, 6, "MaxEvents"}, - {ToPatternRules[{{0, 1}} -> {{0, 2}, {2, 1}}], - <|"MaxGeneration" -> 2|>, - <|"MaxEvents" -> 6|>, - {{0, 1}}, - 2, 3, "Complete"}, - {ToPatternRules[{{0, 1}, {1, 2}} -> {{0, 2}}], - <|"MaxDestroyerEvents" -> 1|>, - <||>, - {{0, 1}, {1, 2}, {2, 3}, {3, 4}}, - 2, 3, "Complete"}, - {ToPatternRules[{{0, 1}, {1, 2}} -> {{0, 2}}], - <|"MaxDestroyerEvents" -> 2|>, - <||>, - {{0, 1}, {1, 2}, {2, 3}, {3, 4}}, - 2, 6, "Complete"}, - {ToPatternRules[{{0, 1}, {1, 2}} -> {{0, 2}}], - <|"MaxDestroyerEvents" -> 3|>, - <||>, - {{0, 1}, {1, 2}, {2, 3}, {3, 4}}, - 3, 10, "Complete"}, - {ToPatternRules[{{0, 1}, {1, 2}} -> {{0, 2}}], - <||>, - <||>, - {{0, 1}, {1, 2}, {2, 3}, {3, 4}}, - 3, 12, "Complete"}, - {ToPatternRules[{{0, 1}, {1, 2}} -> {{0, 2}}], - <|"MaxDestroyerEvents" -> 0|>, - <||>, - {{0, 1}, {1, 2}, {2, 3}, {3, 4}}, - 0, 0, "Complete"}}, - - With[{init = {1, 2, 3, 4, 5, 2/3, 5/3, 7/3}}, - VerificationTest[ - allExpressions @ GenerateMultihistory[ - MultisetSubstitutionSystem[{n___} /; Plus[n] == 5 && OrderedQ[{n}] :> {{n}}], - <|"MinEventInputs" -> #1, "MaxEventInputs" -> #2, "MaxGeneration" -> 1|>, - None, - anEventOrdering, - <||>] @ init, - Join[init, #3], - SameTest -> MatchQ] - ] & @@@ - {{1, 2, {{5}, {1, 4}, {2, 3}}}, {2, 3, {{1, 4}, {2, 3}, {1, 5/3, 7/3}, {2/3, 2, 7/3}}}, {2, 0, {}}}, + Function[{ + rule, parameters, init, expectedMaxEventGeneration, expectedEventCount, expectedTerminationReason}, + VerificationTest[ + Through[{maxEventGeneration, eventCount, terminationReason} @ + GenerateMultihistory[MultisetSubstitutionSystem[rule], init, parameters]], + {expectedMaxEventGeneration, expectedEventCount, expectedTerminationReason}] + ] @@@ { + (* Complete is returned if MaxGeneration is reached because MaxGeneration is not a stopping condition *) + {{_} :> {Unique[]}, MaxGeneration -> 2, {1}, 2, 2, "Complete"}, + {{_} :> {Unique[]}, MaxGeneration -> 0, {1}, 0, 0, "Complete"}, + {{_} :> {Unique[]}, {MaxGeneration -> 3, MaxEvents -> 2}, {1}, 2, 2, "MaxEvents"}, + {{_} :> {Unique[]}, MaxEvents -> 0, {1}, 0, 0, "MaxEvents"}, + {ToPatternRules[{{0, 1}} -> {{0, 2}, {2, 1}}], MaxGeneration -> 3, {{0, 1}}, 3, 7, "Complete"}, + {ToPatternRules[{{0, 1}} -> {{0, 2}, {2, 1}}], MaxEvents -> 6, {{0, 1}}, 3, 6, "MaxEvents"}, + {ToPatternRules[{{0, 1}} -> {{0, 2}, {2, 1}}], {MaxGeneration -> 3, MaxEvents -> 6}, {{0, 1}}, + 3, 6, "MaxEvents"}, + {ToPatternRules[{{0, 1}} -> {{0, 2}, {2, 1}}], {MaxGeneration -> 2, MaxEvents -> 6}, {{0, 1}}, + 2, 3, "Complete"}, + {ToPatternRules[{{0, 1}, {1, 2}} -> {{0, 2}}], MaxDestroyerEvents -> 1, {{0, 1}, {1, 2}, {2, 3}, {3, 4}}, + 2, 3, "Complete"}, + {ToPatternRules[{{0, 1}, {1, 2}} -> {{0, 2}}], MaxDestroyerEvents -> 2, {{0, 1}, {1, 2}, {2, 3}, {3, 4}}, + 2, 6, "Complete"}, + {ToPatternRules[{{0, 1}, {1, 2}} -> {{0, 2}}], MaxDestroyerEvents -> 3, {{0, 1}, {1, 2}, {2, 3}, {3, 4}}, + 3, 10, "Complete"}, + {ToPatternRules[{{0, 1}, {1, 2}} -> {{0, 2}}], {}, {{0, 1}, {1, 2}, {2, 3}, {3, 4}}, 3, 12, "Complete"}, + {ToPatternRules[{{0, 1}, {1, 2}} -> {{0, 2}}], MaxDestroyerEvents -> 0, {{0, 1}, {1, 2}, {2, 3}, {3, 4}}, + 0, 0, "Complete"}}, + With[{init = {1, 2, 3, 4, 5, 2/3, 5/3, 7/3}}, VerificationTest[ - destroyerEventCounts @ GenerateMultihistory[ - MultisetSubstitutionSystem[ToPatternRules[{{1, 2}, {2, 3}} -> {{2, 3}, {2, 4}, {3, 4}, {2, 1}}]], - <|"MaxDestroyerEvents" -> #|>, - None, - anEventOrdering, - <|"MaxEvents" -> 5|>] @ {{1, 1}, {1, 1}}, - #2, - SameTest -> MatchQ] & @@@ - {{2, {2, 2, 2, 2, 1, 1, 0..}}, {3, {2, 2, 3, 1, 1, 1, 0..}}} - }] + allExpressions @ GenerateMultihistory[ + MultisetSubstitutionSystem[{n___} /; Plus[n] == 5 && OrderedQ[{n}] :> {{n}}], + init, + MinEventInputs -> #1, MaxEventInputs -> #2, MaxGeneration -> 1], + Join[init, #3], + SameTest -> MatchQ] + ] & @@@ + {{1, 2, {{5}, {1, 4}, {2, 3}}}, {2, 3, {{1, 4}, {2, 3}, {1, 5/3, 7/3}, {2/3, 2, 7/3}}}, {2, 0, {}}}, + + VerificationTest[ + destroyerEventCounts @ GenerateMultihistory[ + MultisetSubstitutionSystem[ToPatternRules[{{1, 2}, {2, 3}} -> {{2, 3}, {2, 4}, {3, 4}, {2, 1}}]], + {{1, 1}, {1, 1}}, + MaxDestroyerEvents -> #, MaxEvents -> 5], + #2, + SameTest -> MatchQ] & @@@ + {{2, {2, 2, 2, 2, 1, 1, 0..}}, {3, {2, 2, 3, 1, 1, 1, 0..}}} } |> |> From 856da202f3f64897e9c31fed51f614593406b7ec Mon Sep 17 00:00:00 2001 From: Max Piskunov Date: Thu, 8 Jul 2021 17:32:24 -0500 Subject: [PATCH 19/33] Update MultisetToWolframModelEvolutionObject tests. --- Tests/MultisetToWolframModelEvolutionObject.wlt | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/Tests/MultisetToWolframModelEvolutionObject.wlt b/Tests/MultisetToWolframModelEvolutionObject.wlt index 46e43eee..e82ca62f 100644 --- a/Tests/MultisetToWolframModelEvolutionObject.wlt +++ b/Tests/MultisetToWolframModelEvolutionObject.wlt @@ -9,23 +9,13 @@ VerificationTest[ (VertexCount @ #["ExpressionsEventsGraph"] &) @ SetReplaceTypeConvert[{WolframModelEvolutionObject, 2}] @ - GenerateMultihistory[MultisetSubstitutionSystem[{a_, b_} :> {a + b}], - {"MaxGeneration" -> 1}, - None, - EventOrderingFunctions[MultisetSubstitutionSystem], - {}] @ - {1, 2, 3}, + GenerateMultihistory[MultisetSubstitutionSystem[{a_, b_} :> {a + b}], {1, 2, 3}, MaxGeneration -> 1], 15], VerificationTest[ (#["EventsCount"] &) @ SetReplaceTypeConvert[{WolframModelEvolutionObject, 2}] @ - GenerateMultihistory[MultisetSubstitutionSystem[{a_, b_} :> {a + b}], - {}, - None, - EventOrderingFunctions[MultisetSubstitutionSystem], - {"MaxEvents" -> 10}] @ - {1, 2, 3}, + GenerateMultihistory[MultisetSubstitutionSystem[{a_, b_} :> {a + b}], {1, 2, 3}, MaxEvents -> 10], 10] } |> From 88bbec575afb86298f2bc0316e37b532bcae26fd Mon Sep 17 00:00:00 2001 From: Max Piskunov Date: Fri, 9 Jul 2021 07:25:59 -0500 Subject: [PATCH 20/33] Allow performance tests to generate messages for old SHAs. --- performanceTest.wls | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/performanceTest.wls b/performanceTest.wls index 89677a2d..0b649253 100755 --- a/performanceTest.wls +++ b/performanceTest.wls @@ -87,7 +87,7 @@ Check[ Attributes[meanAroundTiming] = {HoldAll}; meanAroundTiming[expr_] := MeanAround @ Table[First @ AbsoluteTiming[expr], $measurementsCount]; - runTests[repo_, sha_, tests_] := ModuleScope[ + runTests[repo_, sha_, tests_, resultsFunction_] := ModuleScope[ Print["Testing ", sha]; GitCheckoutReference[repo, sha]; CloseKernels[]; @@ -95,7 +95,7 @@ Check[ result = ParallelEvaluate[ Get[FileNameJoin[{$setReplaceRoot, "Kernel", "init.m"}]]; Check[ - meanAroundTiming @@@ KeyMap[ReleaseHold, ReleaseHold @ Map[Hold, tests, {3}]] + meanAroundTiming @@@ resultsFunction @ KeyMap[ReleaseHold, ReleaseHold @ Map[Hold, tests, {3}]] , $Failed ] @@ -133,7 +133,8 @@ Check[ $symbolicRef = RunProcess[{"git", "symbolic-ref", "--short", "HEAD"}]; $originalRef = If[$symbolicRef["ExitCode"] === 0, StringExtract[$symbolicRef["StandardOutput"], 1], $currentSHA]; - {$oldResults, $newResults} = runTests[$gitRepo, #, tests] & /@ {$oldSHA, $newSHA}; + $oldResults = runTests[$gitRepo, $oldSHA, tests, Quiet]; + $newResults = runTests[$gitRepo, $newSHA, tests, Identity]; RunProcess[{"git", "checkout", "-q", $originalRef}]; (* We need to return to the original branch before exiting. *) From 914be50ef57c836b900cc4c0a5bc9a46482d84b1 Mon Sep 17 00:00:00 2001 From: Max Piskunov Date: Fri, 9 Jul 2021 07:33:38 -0500 Subject: [PATCH 21/33] Update the test in performanceTest. --- performanceTest.wls | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/performanceTest.wls b/performanceTest.wls index 0b649253..6efdc97e 100755 --- a/performanceTest.wls +++ b/performanceTest.wls @@ -66,10 +66,8 @@ Check[ {8, 7, 7}, {8, 8, 8, 8, 8, 8}, {1, 4, 1}, {1, 1, 1, 1, 1}, {2, 2, 8}, {2, 2}}, 64], "Multiset addition" -> GenerateMultihistory[MultisetSubstitutionSystem[{a_, b_} :> {a + b}], - {"MaxGeneration" -> 2, "MinEventInputs" -> 2, "MaxEventInputs" -> 2}, - None, - EventOrderingFunctions[MultisetSubstitutionSystem], - {}][{1, 2, 3, 4}] + {1, 2, 3, 4}, + MaxGeneration -> 2, MinEventInputs -> 2, MaxEventInputs -> 2] |>; $defaultMeasurementsCount = 5; From 249a9fa4bdaa02d20831ba0e406a82328c72aae8 Mon Sep 17 00:00:00 2001 From: Max Piskunov Date: Fri, 9 Jul 2021 07:42:30 -0500 Subject: [PATCH 22/33] Move resultsFunction to a correct place. --- performanceTest.wls | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/performanceTest.wls b/performanceTest.wls index 6efdc97e..50d826c6 100755 --- a/performanceTest.wls +++ b/performanceTest.wls @@ -83,7 +83,8 @@ Check[ ]; Attributes[meanAroundTiming] = {HoldAll}; - meanAroundTiming[expr_] := MeanAround @ Table[First @ AbsoluteTiming[expr], $measurementsCount]; + meanAroundTiming[expr_, resultsFunction_] := + MeanAround @ Table[First @ AbsoluteTiming[resultsFunction @ expr], $measurementsCount]; runTests[repo_, sha_, tests_, resultsFunction_] := ModuleScope[ Print["Testing ", sha]; @@ -93,7 +94,7 @@ Check[ result = ParallelEvaluate[ Get[FileNameJoin[{$setReplaceRoot, "Kernel", "init.m"}]]; Check[ - meanAroundTiming @@@ resultsFunction @ KeyMap[ReleaseHold, ReleaseHold @ Map[Hold, tests, {3}]] + meanAroundTiming[#, resultsFunction] & @@@ KeyMap[ReleaseHold, ReleaseHold @ Map[Hold, tests, {3}]] , $Failed ] From 1e10610ba15dabf62425ddea25f325ad9bd66134 Mon Sep 17 00:00:00 2001 From: Max Piskunov Date: Fri, 9 Jul 2021 08:03:01 -0500 Subject: [PATCH 23/33] Define SyntaxInformation for parameters. --- Kernel/A1$generatorSystem.m | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Kernel/A1$generatorSystem.m b/Kernel/A1$generatorSystem.m index d4210970..14ec4cf1 100644 --- a/Kernel/A1$generatorSystem.m +++ b/Kernel/A1$generatorSystem.m @@ -97,6 +97,7 @@ $generatorPackageScopeSymbols[publicSymbol] = packageScopeSymbol; $generatorParameters[publicSymbol] = parameterValues; $generatorProperties[publicSymbol] = property; + SyntaxInformation[publicSymbol] = {"ArgumentsPattern" -> {system_, init_., parameters___}}; SetUsage @ Evaluate @ StringRiffle[ {ToString[publicSymbol] <> "[system$, init$, parameters$] " <> usage, systemUsage, @@ -122,6 +123,7 @@ declareSystemParameter[name_, defaultValue_, pattern_, usage_] := ( $parameterDefaults[name] = defaultValue; $parameterPatterns[name] = pattern; + SyntaxInformation[name] = {"ArgumentsPattern" -> {}}; SetUsage @ Evaluate[ToString[name] <> " " <> usage]; ); @@ -159,7 +161,6 @@ SetReplace, Failure["unknownGeneratorParameters", <|"parameters" -> missingParameters, "generator" -> #|>]]; ]; ] & /@ $SetReplaceGenerators; - Scan[(SyntaxInformation[#] = {"ArgumentsPattern" -> {system_, init_., parameters___}}) &, $SetReplaceGenerators]; defineGeneratorImplementation /@ Keys @ $generatorParameters; ); From 6de5e12684be343d75f257ebeee3ac0b71463850 Mon Sep 17 00:00:00 2001 From: Max Piskunov Date: Fri, 9 Jul 2021 13:12:22 -0500 Subject: [PATCH 24/33] Add internal error messages. --- Kernel/A1$generatorSystem.m | 21 +++++--- Tests/generatorSystem.wlt | 102 ++++++++++++++++++++++++++++++++++++ 2 files changed, 117 insertions(+), 6 deletions(-) create mode 100644 Tests/generatorSystem.wlt diff --git a/Kernel/A1$generatorSystem.m b/Kernel/A1$generatorSystem.m index 14ec4cf1..92f04a4c 100644 --- a/Kernel/A1$generatorSystem.m +++ b/Kernel/A1$generatorSystem.m @@ -9,7 +9,6 @@ PackageScope["declareSystem"] PackageScope["declareSystemGenerator"] PackageScope["declareSystemParameter"] -PackageScope["autoList"] PackageScope["initializeSystemGenerators"] (* System declaration *) @@ -55,14 +54,14 @@ declareMessage[General::unsatisfiableParameterDependencies, "Internal error. Parameter constraints `constraints` for `system` are not satisfyable."]; -declareMultihistoryGenerator[systemType_, _, _, _List, dependencies_] := +declareSystem[systemType_, _, _, _List, dependencies_] := message[SetReplace, Failure["unsatisfiableParameterDependencies", <|"constraints" -> dependencies, "system" -> systemType|>]]; -declareMessage[General::invalidGeneratorDeclaration, - "Internal error. Multihistory generator is declared incorrectly with arguments `args`."]; -declareMultihistoryGenerator[args___] := - message[SetReplace, Failure["invalidGeneratorDeclaration", <|"args" -> {args}|>]]; +declareMessage[General::invalidSystemDeclaration, + "Internal error. System is declared incorrectly with arguments `args`."]; +declareSystem[args___] := + message[SetReplace, Failure["invalidSystemDeclaration", <|"args" -> {args}|>]]; (* Generator declaration *) @@ -106,6 +105,11 @@ "\n"]; ); +declareMessage[General::invalidSystemGeneratorDeclaration, + "Internal error. Generator is declared incorrectly with arguments `args`."]; +declareSystemGenerator[args___] := + message[SetReplace, Failure["invalidSystemGeneratorDeclaration", <|"args" -> {args}|>]]; + (* Parameter declaration *) $parameterDefaults = <||>; @@ -127,6 +131,11 @@ SetUsage @ Evaluate[ToString[name] <> " " <> usage]; ); +declareMessage[General::invalidSystemParameterDeclaration, + "Internal error. Parameter is declared incorrectly with arguments `args`."]; +declareSystemParameter[args___] := + message[SetReplace, Failure["invalidSystemParameterDeclaration", <|"args" -> {args}|>]]; + (* Initialization *) (* It would be best to only show autocompletions for specific-system keys, but it does not seem to be possible because diff --git a/Tests/generatorSystem.wlt b/Tests/generatorSystem.wlt new file mode 100644 index 00000000..245e093a --- /dev/null +++ b/Tests/generatorSystem.wlt @@ -0,0 +1,102 @@ +<| + "generatorSystem" -> <| + "init" -> ( + Attributes[Global`testUnevaluated] = Attributes[Global`testSymbolLeak] = {HoldAll}; + Global`testUnevaluated[args___] := SetReplace`PackageScope`testUnevaluated[VerificationTest, args]; + Global`testSymbolLeak[args___] := SetReplace`PackageScope`testSymbolLeak[VerificationTest, args]; + Global`declareSystem = SetReplace`PackageScope`declareSystem; + Global`declareSystemGenerator = SetReplace`PackageScope`declareSystemGenerator; + Global`declareSystemParameter = SetReplace`PackageScope`declareSystemParameter; + Global`initializeSystemGenerators = SetReplace`PackageScope`initializeSystemGenerators; + + (* Echo system *) + + declareSystem[echoSystem, List, _, {}, True]; + + (* UnknownObject *) + + declareSystemGenerator[identityGenerator, internalIdentityGenerator, <||>, Identity, "does nothing."]; + + Unprotect[$SetReplaceSystems]; + Unprotect[$SetReplaceGenerators]; + initializeSystemGenerators[]; + Protect[$SetReplaceGenerators]; + Protect[$SetReplaceSystems]; + ), + "tests" -> { + (* Type and property lists *) + (* unknownObject is not here because there are no translations or properties defined for it, so it's invisible to + the type system. *) + VerificationTest[ + $SetReplaceTypes, Sort @ Join[originalTypes, {"String", "Expression", "HalfInteger", "EvenInteger", "Real"}]], + VerificationTest[$SetReplaceProperties, Sort @ Join[originalProperties, {description, multipliedHalf}]], + + VerificationTest[GraphQ @ $SetReplaceTypeGraph], + VerificationTest[ContainsOnly[Head /@ VertexList[$SetReplaceTypeGraph], + {SetReplaceType, SetReplaceProperty, SetReplaceMethodImplementation}]], + VerificationTest[ + Cases[ + EdgeList[$SetReplaceTypeGraph], + Except[ + DirectedEdge[_SetReplaceType | _SetReplaceProperty, _SetReplaceMethodImplementation] | + DirectedEdge[_SetReplaceMethodImplementation, _SetReplaceType | _SetReplaceProperty]]], + {}], + + (* Type querying *) + VerificationTest[SetReplaceObjectType[evenInteger[4]], "EvenInteger"], + VerificationTest[SetReplaceObjectType[2.4], "Real"], + VerificationTest[SetReplaceObjectType[unknownObject[4]], "Unknown"], + testUnevaluated[SetReplaceObjectType[unseenObject[4]], SetReplaceObjectType::unknownObject], + + VerificationTest[SetReplaceObjectQ[evenInteger[4]]], + VerificationTest[SetReplaceObjectQ[2.4]], + (* unknownObject an object because it returns a type even though it's not in $SetReplaceTypes. *) + VerificationTest[SetReplaceObjectQ[unknownObject[4]]], + VerificationTest[!SetReplaceObjectQ[unseenObject[4]]], + + (* Translations *) + VerificationTest[ + SetReplaceTypeConvert["Expression"] @ SetReplaceTypeConvert["String"] @ expression[4], expression[4]], + VerificationTest[SetReplaceTypeConvert["HalfInteger"] @ evenInteger[4], halfInteger[2]], + VerificationTest[SetReplaceTypeConvert["HalfInteger"] @ halfInteger[3], halfInteger[3]], + VerificationTest[SetReplaceTypeConvert["EvenInteger"] @ halfInteger[3], evenInteger[6]], + + testUnevaluated[SetReplaceTypeConvert["Expression"] @ unknownObject[5], SetReplaceTypeConvert::unconvertibleType], + testUnevaluated[SetReplaceTypeConvert["Unknown"] @ expression[4], SetReplaceTypeConvert::unconvertibleType], + testUnevaluated[SetReplaceTypeConvert["Expression"] @ halfInteger[3], SetReplaceTypeConvert::noConversionPath], + testUnevaluated[SetReplaceTypeConvert["HalfInteger"] @ evenInteger[3], SetReplaceTypeConvert::notEven], + testUnevaluated[SetReplaceTypeConvert["EvenInteger"] @ halfInteger[a], SetReplaceTypeConvert::notAnInteger], + + (* Raw Properties *) + VerificationTest[multipliedHalf[5] @ halfInteger[3], 15], + VerificationTest[multipliedHalf[5] @ evenInteger[4], 10], + VerificationTest[multipliedHalf[halfInteger[3], 4], 12], + VerificationTest[multipliedHalf[evenInteger[4], 4], 8], + VerificationTest[description @ evenInteger[4], "I am an integer 4."], + VerificationTest[description @ halfInteger[4], "I am an integer 8."], + VerificationTest[description[] @ halfInteger[4], "I am an integer 8."], (* Operator form with no arguments *) + VerificationTest[description @ 2.4, "I am a real 2.4."], + + testUnevaluated[multipliedHalf[] @ halfInteger[3], multipliedHalf::invalidPropertyArgumentCount], + testUnevaluated[multipliedHalf[1, 2, 3] @ halfInteger[3], multipliedHalf::invalidPropertyArgumentCount], + testUnevaluated[multipliedHalf @ halfInteger[3], multipliedHalf::invalidPropertyArgumentCount], + testUnevaluated[multipliedHalf[halfInteger[3], 4, 5], multipliedHalf::invalidPropertyArgumentCount], + testUnevaluated[description[1] @ halfInteger[4], description::invalidPropertyArgumentCount], + testUnevaluated[description[halfInteger[3], 3], description::invalidPropertyArgumentCount], + + testUnevaluated[multipliedHalf[4, 4, 5][], multipliedHalf::invalidPropertyOperatorArgument], + testUnevaluated[multipliedHalf[4, 4, 5][halfInteger[4], 2, 3], multipliedHalf::invalidPropertyOperatorArgument], + testUnevaluated[description[][], description::invalidPropertyOperatorArgument], + + testUnevaluated[multipliedHalf[4] @ cookie, multipliedHalf::unknownObject], + testUnevaluated[multipliedHalf[4, 4, 5] @ cookie, multipliedHalf::unknownObject], + testUnevaluated[description[] @ cookie, description::unknownObject], + testUnevaluated[multipliedHalf[5] @ expression[3], multipliedHalf::noPropertyPath], + testUnevaluated[multipliedHalf[5] @ evenInteger[3], multipliedHalf::notEven], + testUnevaluated[multipliedHalf[evenInteger[3], 4], multipliedHalf::notEven], + testUnevaluated[multipliedHalf[x] @ halfInteger[3], multipliedHalf::nonIntegerFactor], + testUnevaluated[multipliedHalf @ cookie, {}], (* should not throw a message because it might be an operator *) + testUnevaluated[description @ cookie, {}] + } + |> +|> From d063dc9d16f0c20188dafc2d26c43b3ee3923a62 Mon Sep 17 00:00:00 2001 From: Max Piskunov Date: Sun, 11 Jul 2021 08:57:09 -0500 Subject: [PATCH 25/33] Fix declareSystemGenerator. --- Kernel/A1$generatorSystem.m | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Kernel/A1$generatorSystem.m b/Kernel/A1$generatorSystem.m index 92f04a4c..661760e1 100644 --- a/Kernel/A1$generatorSystem.m +++ b/Kernel/A1$generatorSystem.m @@ -92,7 +92,7 @@ parametersUsage = "* parameters$ is either a Sequence, a List or an Association of key-value rules. A list of " <> "parameters can be obtained with SetReplaceSystemParameters[system$]."; -declareSystemGenerator[publicSymbol_, packageScopeSymbol_, parameterValues_, property_ : Identity, usage_] := ( +declareSystemGenerator[publicSymbol_, packageScopeSymbol_, parameterValues_, property_, usage_] := ( $generatorPackageScopeSymbols[publicSymbol] = packageScopeSymbol; $generatorParameters[publicSymbol] = parameterValues; $generatorProperties[publicSymbol] = property; @@ -152,9 +152,9 @@ "; declareMessage[ - General::unknownSystemParameters, "Parameters `parameters` are implemented by `system` but is not declared."]; + General::unknownSystemParameters, "Parameters `parameters` are implemented by `system` but are not declared."]; declareMessage[ - General::unknownGeneratorParameters, "Parameters `parameters` are set by `generator` but is not declared."]; + General::unknownGeneratorParameters, "Parameters `parameters` are set by `generator` but are not declared."]; initializeSystemGenerators[] := ( $SetReplaceSystems = Sort @ Keys @ $systemImplementations; From 4a7b9ee59b786b965074bd65728f7c9344642456 Mon Sep 17 00:00:00 2001 From: Max Piskunov Date: Sun, 11 Jul 2021 10:36:42 -0500 Subject: [PATCH 26/33] Add generator system tests. --- Tests/generatorSystem.wlt | 211 ++++++++++++++++++++++++-------------- 1 file changed, 133 insertions(+), 78 deletions(-) diff --git a/Tests/generatorSystem.wlt b/Tests/generatorSystem.wlt index 245e093a..458f30a9 100644 --- a/Tests/generatorSystem.wlt +++ b/Tests/generatorSystem.wlt @@ -3,100 +3,155 @@ "init" -> ( Attributes[Global`testUnevaluated] = Attributes[Global`testSymbolLeak] = {HoldAll}; Global`testUnevaluated[args___] := SetReplace`PackageScope`testUnevaluated[VerificationTest, args]; - Global`testSymbolLeak[args___] := SetReplace`PackageScope`testSymbolLeak[VerificationTest, args]; Global`declareSystem = SetReplace`PackageScope`declareSystem; Global`declareSystemGenerator = SetReplace`PackageScope`declareSystemGenerator; Global`declareSystemParameter = SetReplace`PackageScope`declareSystemParameter; Global`initializeSystemGenerators = SetReplace`PackageScope`initializeSystemGenerators; - (* Echo system *) + declareSystemParameter[maxSomething, Infinity, _?(GreaterEqualThan[0]), "is a max param."]; + declareSystemParameter[minSomething, 0, _?(GreaterEqualThan[0]), "is a min param."]; + declareSystemParameter[pickNumber, None, None | 0 | 1 | 2, "is a pick param."]; - declareSystem[echoSystem, List, _, {}, True]; - - (* UnknownObject *) + declareSystem[echoSystem, List, _Integer, {maxSomething, pickNumber}, True]; + declareSystem[needSomethingForPicking, + List, + _Integer, + {minSomething, maxSomething, pickNumber}, + Implies[pickNumber, minSomething || maxSomething]]; + declareSystem[minXorMax, List, _Integer, {minSomething, maxSomething}, Xor[minSomething, maxSomething]]; + declareSystem[listInit, List, _List, {minSomething, maxSomething, pickNumber}, True]; + declareSystem[realSystem, List, _, {MaxDestroyerEvents, MaxEvents, MaxGeneration}, True]; declareSystemGenerator[identityGenerator, internalIdentityGenerator, <||>, Identity, "does nothing."]; + declareSystemGenerator[pick2Generator, internalPick2Generator, <|pickNumber -> 2|>, picked, "picks 2."]; - Unprotect[$SetReplaceSystems]; - Unprotect[$SetReplaceGenerators]; + Unprotect[$SetReplaceSystems, $SetReplaceGenerators, GenerateSingleHistory, GenerateMultihistory]; initializeSystemGenerators[]; - Protect[$SetReplaceGenerators]; - Protect[$SetReplaceSystems]; + Protect[$SetReplaceSystems, $SetReplaceGenerators, GenerateSingleHistory, GenerateMultihistory]; ), "tests" -> { - (* Type and property lists *) - (* unknownObject is not here because there are no translations or properties defined for it, so it's invisible to - the type system. *) + (* Internal errors *) + VerificationTest[declareSystem[invalidSystem, List, _, {minSomething}, minSomething && !minSomething], + _, + {SetReplace::unsatisfiableParameterDependencies}, + SameTest -> MatchQ], + VerificationTest[declareSystem[invalidSystem, List, _, {minSomething}], + _, + {SetReplace::invalidSystemDeclaration}, + SameTest -> MatchQ], + VerificationTest[declareSystemGenerator[invalidGenerator, internalInvalidGenerator, <||>, Identity], + _, + {SetReplace::invalidSystemGeneratorDeclaration}, + SameTest -> MatchQ], + VerificationTest[declareSystemParameter[invalidParameter, 0, _], + _, + {SetReplace::invalidSystemParameterDeclaration}, + SameTest -> MatchQ], + + (* Zero args *) + testUnevaluated[identityGenerator[], {identityGenerator::argm}], + + (* One arg *) + testUnevaluated[identityGenerator[0], {}], + testUnevaluated[identityGenerator[echoSystem[0]], {}], + + (* Two args *) + testUnevaluated[identityGenerator[0, 0], {identityGenerator::unknownSystem}], + VerificationTest[ + identityGenerator[echoSystem[0], 0], {echoSystem[0], 0, <|maxSomething -> Infinity, pickNumber -> None|>}], + testUnevaluated[identityGenerator[echoSystem[0], "test"], {}], (* parameters are not yet parsed at this stage *) + + (* Parameters *) + testUnevaluated[identityGenerator[echoSystem[0], 0, abc], {identityGenerator::invalidGeneratorParameterSpec}], + testUnevaluated[identityGenerator[echoSystem[0], 0, {abc}], {identityGenerator::invalidGeneratorParameterSpec}], + testUnevaluated[identityGenerator[echoSystem[0], 0, abc -> 4], {identityGenerator::unknownParameter}], + testUnevaluated[identityGenerator[echoSystem[0], maxSomething -> 4], {}], (* no init, treated as an operator *) + VerificationTest[identityGenerator[echoSystem[0], 0, maxSomething -> 4], + {echoSystem[0], 0, <|maxSomething -> 4, pickNumber -> None|>}], + testUnevaluated[identityGenerator[echoSystem[0], 0, maxSomething -> -1], {identityGenerator::invalidParameter}], + testUnevaluated[identityGenerator[echoSystem[0], 0, minSomething -> 4], {identityGenerator::unknownParameter}], + + VerificationTest[ + identityGenerator[echoSystem[0], 0, ##], {echoSystem[0], 0, <|maxSomething -> 4, pickNumber -> 0|>}] & @@@ { + {maxSomething -> 4, pickNumber -> 0}, + {{maxSomething -> 4}, pickNumber -> 0}, + {maxSomething -> 4, {pickNumber -> 0}}, + {<|maxSomething -> 4|>, {{pickNumber -> 0}}} + }, + + VerificationTest[identityGenerator[echoSystem[0], 0, pickNumber -> 0, pickNumber -> 1], + {echoSystem[0], 0, <|maxSomething -> Infinity, pickNumber -> 1|>}], + testUnevaluated[identityGenerator[echoSystem[0], 0, pickNumber -> 0, pickNumber -> 1, 3], + {identityGenerator::invalidGeneratorParameterSpec}], + VerificationTest[ - $SetReplaceTypes, Sort @ Join[originalTypes, {"String", "Expression", "HalfInteger", "EvenInteger", "Real"}]], - VerificationTest[$SetReplaceProperties, Sort @ Join[originalProperties, {description, multipliedHalf}]], + pick2Generator[echoSystem[0], 0], picked[{echoSystem[0], 0, <|maxSomething -> Infinity, pickNumber -> 2|>}]], + testUnevaluated[pick2Generator[echoSystem[0], 0, pickNumber -> 1], {pick2Generator::forbiddenParameter}], + VerificationTest[pick2Generator[echoSystem[0], 0, maxSomething -> 2], + picked[{echoSystem[0], 0, <|maxSomething -> 2, pickNumber -> 2|>}]], - VerificationTest[GraphQ @ $SetReplaceTypeGraph], - VerificationTest[ContainsOnly[Head /@ VertexList[$SetReplaceTypeGraph], - {SetReplaceType, SetReplaceProperty, SetReplaceMethodImplementation}]], VerificationTest[ - Cases[ - EdgeList[$SetReplaceTypeGraph], - Except[ - DirectedEdge[_SetReplaceType | _SetReplaceProperty, _SetReplaceMethodImplementation] | - DirectedEdge[_SetReplaceMethodImplementation, _SetReplaceType | _SetReplaceProperty]]], - {}], - - (* Type querying *) - VerificationTest[SetReplaceObjectType[evenInteger[4]], "EvenInteger"], - VerificationTest[SetReplaceObjectType[2.4], "Real"], - VerificationTest[SetReplaceObjectType[unknownObject[4]], "Unknown"], - testUnevaluated[SetReplaceObjectType[unseenObject[4]], SetReplaceObjectType::unknownObject], - - VerificationTest[SetReplaceObjectQ[evenInteger[4]]], - VerificationTest[SetReplaceObjectQ[2.4]], - (* unknownObject an object because it returns a type even though it's not in $SetReplaceTypes. *) - VerificationTest[SetReplaceObjectQ[unknownObject[4]]], - VerificationTest[!SetReplaceObjectQ[unseenObject[4]]], - - (* Translations *) + identityGenerator[needSomethingForPicking[0], 0], + {needSomethingForPicking[0], 0, <|minSomething -> 0, maxSomething -> Infinity, pickNumber -> None|>}], + testUnevaluated[ + identityGenerator[needSomethingForPicking[0], 0, pickNumber -> 2], {identityGenerator::missingParameters}], + VerificationTest[ + identityGenerator[needSomethingForPicking[0], 0, pickNumber -> 2, minSomething -> 2], + {needSomethingForPicking[0], 0, <|minSomething -> 2, maxSomething -> Infinity, pickNumber -> 2|>}], + VerificationTest[ + identityGenerator[needSomethingForPicking[0], 0, pickNumber -> 2, maxSomething -> 2], + {needSomethingForPicking[0], 0, <|minSomething -> 0, maxSomething -> 2, pickNumber -> 2|>}], + + testUnevaluated[pick2Generator[needSomethingForPicking[0], 0], {pick2Generator::missingParameters}], + VerificationTest[ + pick2Generator[needSomethingForPicking[0], 0, minSomething -> 2], + picked[{needSomethingForPicking[0], 0, <|minSomething -> 2, maxSomething -> Infinity, pickNumber -> 2|>}]], + + testUnevaluated[pick2Generator[minXorMax[0], 0], {pick2Generator::incompatibleSystem}], + testUnevaluated[pick2Generator[minXorMax[0], 0, pickNumber -> 2], {pick2Generator::incompatibleSystem}], + testUnevaluated[identityGenerator[minXorMax[0], 0], {identityGenerator::missingParameters}], + VerificationTest[identityGenerator[minXorMax[0], 0, minSomething -> 2], + {minXorMax[0], 0, <|minSomething -> 2, maxSomething -> Infinity|>}], + testUnevaluated[identityGenerator[minXorMax[0], 0, minSomething -> 2, maxSomething -> 3], + {identityGenerator::incompatibleParameters}], + + (* Operator form *) + testUnevaluated[identityGenerator[echoSystem[0]] @ "test", {identityGenerator::argNotInit}], + testUnevaluated[identityGenerator[echoSystem[0], maxSomething -> 2] @ "test", {identityGenerator::argNotInit}], + VerificationTest[ + identityGenerator[echoSystem[0]] @ 0, {echoSystem[0], 0, <|maxSomething -> Infinity, pickNumber -> None|>}], + testUnevaluated[identityGenerator[echoSystem[0]][], {identityGenerator::argx}], + testUnevaluated[identityGenerator[echoSystem[0]][0, 1], {identityGenerator::argx}], + VerificationTest[identityGenerator[echoSystem[0], maxSomething -> 2] @ 0, + {echoSystem[0], 0, <|maxSomething -> 2, pickNumber -> None|>}], + VerificationTest[identityGenerator[echoSystem[0], {maxSomething -> 2}] @ 0, + {echoSystem[0], 0, <|maxSomething -> 2, pickNumber -> None|>}], + VerificationTest[identityGenerator[echoSystem[0], <|maxSomething -> 2|>] @ 0, + {echoSystem[0], 0, <|maxSomething -> 2, pickNumber -> None|>}], + VerificationTest[identityGenerator[echoSystem[0], maxSomething -> 2, pickNumber -> 2] @ 0, + {echoSystem[0], 0, <|maxSomething -> 2, pickNumber -> 2|>}], + VerificationTest[ + identityGenerator[listInit[0], {maxSomething -> 2}] @ 0, + {listInit[0], {maxSomething -> 2}, <|minSomething -> 0, maxSomething -> Infinity, pickNumber -> None|>}[0]], + VerificationTest[ + identityGenerator[listInit[0], {maxSomething -> 2}, minSomething -> 1] @ {0}, + {listInit[0], {maxSomething -> 2}, <|minSomething -> 1, maxSomething -> Infinity, pickNumber -> None|>}[{0}]], + VerificationTest[identityGenerator[listInit[0], minSomething -> 1, {maxSomething -> 2}] @ {0}, + {listInit[0], {0}, <|minSomething -> 1, maxSomething -> 2, pickNumber -> None|>}], + + (* Existing generators *) + VerificationTest[ + GenerateMultihistory[realSystem[0], 0], + {realSystem[0], 0, <|MaxDestroyerEvents -> Infinity, MaxEvents -> Infinity, MaxGeneration -> Infinity|>}], + VerificationTest[ + GenerateSingleHistory[realSystem[0], 0], + {realSystem[0], 0, <|MaxDestroyerEvents -> 1, MaxEvents -> Infinity, MaxGeneration -> Infinity|>}], + + (* Introspection *) VerificationTest[ - SetReplaceTypeConvert["Expression"] @ SetReplaceTypeConvert["String"] @ expression[4], expression[4]], - VerificationTest[SetReplaceTypeConvert["HalfInteger"] @ evenInteger[4], halfInteger[2]], - VerificationTest[SetReplaceTypeConvert["HalfInteger"] @ halfInteger[3], halfInteger[3]], - VerificationTest[SetReplaceTypeConvert["EvenInteger"] @ halfInteger[3], evenInteger[6]], - - testUnevaluated[SetReplaceTypeConvert["Expression"] @ unknownObject[5], SetReplaceTypeConvert::unconvertibleType], - testUnevaluated[SetReplaceTypeConvert["Unknown"] @ expression[4], SetReplaceTypeConvert::unconvertibleType], - testUnevaluated[SetReplaceTypeConvert["Expression"] @ halfInteger[3], SetReplaceTypeConvert::noConversionPath], - testUnevaluated[SetReplaceTypeConvert["HalfInteger"] @ evenInteger[3], SetReplaceTypeConvert::notEven], - testUnevaluated[SetReplaceTypeConvert["EvenInteger"] @ halfInteger[a], SetReplaceTypeConvert::notAnInteger], - - (* Raw Properties *) - VerificationTest[multipliedHalf[5] @ halfInteger[3], 15], - VerificationTest[multipliedHalf[5] @ evenInteger[4], 10], - VerificationTest[multipliedHalf[halfInteger[3], 4], 12], - VerificationTest[multipliedHalf[evenInteger[4], 4], 8], - VerificationTest[description @ evenInteger[4], "I am an integer 4."], - VerificationTest[description @ halfInteger[4], "I am an integer 8."], - VerificationTest[description[] @ halfInteger[4], "I am an integer 8."], (* Operator form with no arguments *) - VerificationTest[description @ 2.4, "I am a real 2.4."], - - testUnevaluated[multipliedHalf[] @ halfInteger[3], multipliedHalf::invalidPropertyArgumentCount], - testUnevaluated[multipliedHalf[1, 2, 3] @ halfInteger[3], multipliedHalf::invalidPropertyArgumentCount], - testUnevaluated[multipliedHalf @ halfInteger[3], multipliedHalf::invalidPropertyArgumentCount], - testUnevaluated[multipliedHalf[halfInteger[3], 4, 5], multipliedHalf::invalidPropertyArgumentCount], - testUnevaluated[description[1] @ halfInteger[4], description::invalidPropertyArgumentCount], - testUnevaluated[description[halfInteger[3], 3], description::invalidPropertyArgumentCount], - - testUnevaluated[multipliedHalf[4, 4, 5][], multipliedHalf::invalidPropertyOperatorArgument], - testUnevaluated[multipliedHalf[4, 4, 5][halfInteger[4], 2, 3], multipliedHalf::invalidPropertyOperatorArgument], - testUnevaluated[description[][], description::invalidPropertyOperatorArgument], - - testUnevaluated[multipliedHalf[4] @ cookie, multipliedHalf::unknownObject], - testUnevaluated[multipliedHalf[4, 4, 5] @ cookie, multipliedHalf::unknownObject], - testUnevaluated[description[] @ cookie, description::unknownObject], - testUnevaluated[multipliedHalf[5] @ expression[3], multipliedHalf::noPropertyPath], - testUnevaluated[multipliedHalf[5] @ evenInteger[3], multipliedHalf::notEven], - testUnevaluated[multipliedHalf[evenInteger[3], 4], multipliedHalf::notEven], - testUnevaluated[multipliedHalf[x] @ halfInteger[3], multipliedHalf::nonIntegerFactor], - testUnevaluated[multipliedHalf @ cookie, {}], (* should not throw a message because it might be an operator *) - testUnevaluated[description @ cookie, {}] + SubsetQ[$SetReplaceSystems, {echoSystem, needSomethingForPicking, minXorMax, listInit, realSystem}]], + VerificationTest[SubsetQ[$SetReplaceGenerators, {identityGenerator, pick2Generator}]], + VerificationTest[SetReplaceSystemParameters[listInit], {minSomething, maxSomething, pickNumber}] } |> |> From 45f5d3eb9a6473d6829946908bbd65be8cf6c28f Mon Sep 17 00:00:00 2001 From: Max Piskunov Date: Sun, 11 Jul 2021 17:18:55 -0500 Subject: [PATCH 27/33] Cleanup generator system tests. --- Tests/generatorSystem.wlt | 189 ++++++++++++++++++++------------------ 1 file changed, 100 insertions(+), 89 deletions(-) diff --git a/Tests/generatorSystem.wlt b/Tests/generatorSystem.wlt index 458f30a9..1850f50a 100644 --- a/Tests/generatorSystem.wlt +++ b/Tests/generatorSystem.wlt @@ -8,34 +8,34 @@ Global`declareSystemParameter = SetReplace`PackageScope`declareSystemParameter; Global`initializeSystemGenerators = SetReplace`PackageScope`initializeSystemGenerators; - declareSystemParameter[maxSomething, Infinity, _?(GreaterEqualThan[0]), "is a max param."]; - declareSystemParameter[minSomething, 0, _?(GreaterEqualThan[0]), "is a min param."]; - declareSystemParameter[pickNumber, None, None | 0 | 1 | 2, "is a pick param."]; + declareSystemParameter[maxEventSize, Infinity, _ ? (GreaterEqualThan[0]), "is a max parameter for a test value."]; + declareSystemParameter[minEventSize, 0, _ ? (GreaterEqualThan[0]), "is a min parameter for a test value."]; + declareSystemParameter[eventType, None, None | 0 | 1 | 2, "is an optional choice between 0, 1, and 2."]; - declareSystem[echoSystem, List, _Integer, {maxSomething, pickNumber}, True]; - declareSystem[needSomethingForPicking, + declareSystem[genericSystem, List, _Integer, {maxEventSize, eventType}, True]; + declareSystem[systemWithParameterDependencies, List, _Integer, - {minSomething, maxSomething, pickNumber}, - Implies[pickNumber, minSomething || maxSomething]]; - declareSystem[minXorMax, List, _Integer, {minSomething, maxSomething}, Xor[minSomething, maxSomething]]; - declareSystem[listInit, List, _List, {minSomething, maxSomething, pickNumber}, True]; - declareSystem[realSystem, List, _, {MaxDestroyerEvents, MaxEvents, MaxGeneration}, True]; + {minEventSize, maxEventSize, eventType}, + Implies[eventType, minEventSize || maxEventSize]]; + declareSystem[minXorMaxSystem, List, _Integer, {minEventSize, maxEventSize}, Xor[minEventSize, maxEventSize]]; + declareSystem[listStateSystem, List, _List, {minEventSize, maxEventSize, eventType}, True]; + declareSystem[realParameterSystem, List, _, {MaxDestroyerEvents, MaxEvents, MaxGeneration}, True]; - declareSystemGenerator[identityGenerator, internalIdentityGenerator, <||>, Identity, "does nothing."]; - declareSystemGenerator[pick2Generator, internalPick2Generator, <|pickNumber -> 2|>, picked, "picks 2."]; + declareSystemGenerator[genericGenerator, internalGenericGenerator, <||>, Identity, "does nothing."]; + declareSystemGenerator[typeTwoGenerator, internalTypeTwoGenerator, <|eventType -> 2|>, property, "picks 2."]; Unprotect[$SetReplaceSystems, $SetReplaceGenerators, GenerateSingleHistory, GenerateMultihistory]; initializeSystemGenerators[]; Protect[$SetReplaceSystems, $SetReplaceGenerators, GenerateSingleHistory, GenerateMultihistory]; ), "tests" -> { - (* Internal errors *) - VerificationTest[declareSystem[invalidSystem, List, _, {minSomething}, minSomething && !minSomething], + (* Declaration errors *) + VerificationTest[declareSystem[invalidSystem, List, _, {minEventSize}, minEventSize && !minEventSize], _, {SetReplace::unsatisfiableParameterDependencies}, SameTest -> MatchQ], - VerificationTest[declareSystem[invalidSystem, List, _, {minSomething}], + VerificationTest[declareSystem[invalidSystem, List, _, {minEventSize}], _, {SetReplace::invalidSystemDeclaration}, SameTest -> MatchQ], @@ -49,109 +49,120 @@ SameTest -> MatchQ], (* Zero args *) - testUnevaluated[identityGenerator[], {identityGenerator::argm}], + testUnevaluated[genericGenerator[], {genericGenerator::argm}], (* One arg *) - testUnevaluated[identityGenerator[0], {}], - testUnevaluated[identityGenerator[echoSystem[0]], {}], + testUnevaluated[genericGenerator[0], {}], + testUnevaluated[genericGenerator[genericSystem[]], {}], (* Two args *) - testUnevaluated[identityGenerator[0, 0], {identityGenerator::unknownSystem}], + testUnevaluated[genericGenerator[0, 0], {genericGenerator::unknownSystem}], + testUnevaluated[genericGenerator[genericSystem[], "test"], {}], (* parameters are not yet parsed at this stage *) VerificationTest[ - identityGenerator[echoSystem[0], 0], {echoSystem[0], 0, <|maxSomething -> Infinity, pickNumber -> None|>}], - testUnevaluated[identityGenerator[echoSystem[0], "test"], {}], (* parameters are not yet parsed at this stage *) - - (* Parameters *) - testUnevaluated[identityGenerator[echoSystem[0], 0, abc], {identityGenerator::invalidGeneratorParameterSpec}], - testUnevaluated[identityGenerator[echoSystem[0], 0, {abc}], {identityGenerator::invalidGeneratorParameterSpec}], - testUnevaluated[identityGenerator[echoSystem[0], 0, abc -> 4], {identityGenerator::unknownParameter}], - testUnevaluated[identityGenerator[echoSystem[0], maxSomething -> 4], {}], (* no init, treated as an operator *) - VerificationTest[identityGenerator[echoSystem[0], 0, maxSomething -> 4], - {echoSystem[0], 0, <|maxSomething -> 4, pickNumber -> None|>}], - testUnevaluated[identityGenerator[echoSystem[0], 0, maxSomething -> -1], {identityGenerator::invalidParameter}], - testUnevaluated[identityGenerator[echoSystem[0], 0, minSomething -> 4], {identityGenerator::unknownParameter}], + genericGenerator[genericSystem[], 0], {genericSystem[], 0, <|maxEventSize -> Infinity, eventType -> None|>}], + + (* Parameters spec *) + testUnevaluated[genericGenerator[genericSystem[], 0, abc], {genericGenerator::invalidGeneratorParameterSpec}], + testUnevaluated[genericGenerator[genericSystem[], 0, {abc}], {genericGenerator::invalidGeneratorParameterSpec}], + testUnevaluated[genericGenerator[genericSystem[], 0, abc -> 4], {genericGenerator::unknownParameter}], + testUnevaluated[genericGenerator[genericSystem[], maxEventSize -> 4], {}], (* no init, treated as operator form *) + VerificationTest[genericGenerator[genericSystem[], 0, maxEventSize -> 4], + {genericSystem[], 0, <|maxEventSize -> 4, eventType -> None|>}], + testUnevaluated[genericGenerator[genericSystem[], 0, maxEventSize -> -1], {genericGenerator::invalidParameter}], + testUnevaluated[genericGenerator[genericSystem[], 0, minEventSize -> 4], {genericGenerator::unknownParameter}], VerificationTest[ - identityGenerator[echoSystem[0], 0, ##], {echoSystem[0], 0, <|maxSomething -> 4, pickNumber -> 0|>}] & @@@ { - {maxSomething -> 4, pickNumber -> 0}, - {{maxSomething -> 4}, pickNumber -> 0}, - {maxSomething -> 4, {pickNumber -> 0}}, - {<|maxSomething -> 4|>, {{pickNumber -> 0}}} + genericGenerator[genericSystem[], 0, ##], {genericSystem[], 0, <|maxEventSize -> 4, eventType -> 0|>}] & @@@ { + {maxEventSize -> 4, eventType -> 0}, + {{maxEventSize -> 4}, eventType -> 0}, + {maxEventSize -> 4, {eventType -> 0}}, + {<|maxEventSize -> 4|>, {{eventType -> 0}}} }, - VerificationTest[identityGenerator[echoSystem[0], 0, pickNumber -> 0, pickNumber -> 1], - {echoSystem[0], 0, <|maxSomething -> Infinity, pickNumber -> 1|>}], - testUnevaluated[identityGenerator[echoSystem[0], 0, pickNumber -> 0, pickNumber -> 1, 3], - {identityGenerator::invalidGeneratorParameterSpec}], + VerificationTest[genericGenerator[genericSystem[], 0, eventType -> 0, eventType -> 1], + {genericSystem[], 0, <|maxEventSize -> Infinity, eventType -> 1|>}], + testUnevaluated[genericGenerator[genericSystem[], 0, eventType -> 0, eventType -> 1, 3], + {genericGenerator::invalidGeneratorParameterSpec}], - VerificationTest[ - pick2Generator[echoSystem[0], 0], picked[{echoSystem[0], 0, <|maxSomething -> Infinity, pickNumber -> 2|>}]], - testUnevaluated[pick2Generator[echoSystem[0], 0, pickNumber -> 1], {pick2Generator::forbiddenParameter}], - VerificationTest[pick2Generator[echoSystem[0], 0, maxSomething -> 2], - picked[{echoSystem[0], 0, <|maxSomething -> 2, pickNumber -> 2|>}]], + (* Generator with predefined parameters *) + VerificationTest[typeTwoGenerator[genericSystem[], 0], + property[{genericSystem[], 0, <|maxEventSize -> Infinity, eventType -> 2|>}]], + testUnevaluated[typeTwoGenerator[genericSystem[], 0, eventType -> 1], {typeTwoGenerator::forbiddenParameter}], + VerificationTest[typeTwoGenerator[genericSystem[], 0, maxEventSize -> 2], + property[{genericSystem[], 0, <|maxEventSize -> 2, eventType -> 2|>}]], + (* Parameter dependencies *) VerificationTest[ - identityGenerator[needSomethingForPicking[0], 0], - {needSomethingForPicking[0], 0, <|minSomething -> 0, maxSomething -> Infinity, pickNumber -> None|>}], + genericGenerator[systemWithParameterDependencies[], 0], + {systemWithParameterDependencies[], 0, <|minEventSize -> 0, maxEventSize -> Infinity, eventType -> None|>}], testUnevaluated[ - identityGenerator[needSomethingForPicking[0], 0, pickNumber -> 2], {identityGenerator::missingParameters}], + genericGenerator[systemWithParameterDependencies[], 0, eventType -> 2], {genericGenerator::missingParameters}], VerificationTest[ - identityGenerator[needSomethingForPicking[0], 0, pickNumber -> 2, minSomething -> 2], - {needSomethingForPicking[0], 0, <|minSomething -> 2, maxSomething -> Infinity, pickNumber -> 2|>}], + genericGenerator[systemWithParameterDependencies[], 0, eventType -> 2, minEventSize -> 2], + {systemWithParameterDependencies[], 0, <|minEventSize -> 2, maxEventSize -> Infinity, eventType -> 2|>}], VerificationTest[ - identityGenerator[needSomethingForPicking[0], 0, pickNumber -> 2, maxSomething -> 2], - {needSomethingForPicking[0], 0, <|minSomething -> 0, maxSomething -> 2, pickNumber -> 2|>}], + genericGenerator[systemWithParameterDependencies[], 0, eventType -> 2, maxEventSize -> 2], + {systemWithParameterDependencies[], 0, <|minEventSize -> 0, maxEventSize -> 2, eventType -> 2|>}], - testUnevaluated[pick2Generator[needSomethingForPicking[0], 0], {pick2Generator::missingParameters}], + testUnevaluated[typeTwoGenerator[systemWithParameterDependencies[], 0], {typeTwoGenerator::missingParameters}], VerificationTest[ - pick2Generator[needSomethingForPicking[0], 0, minSomething -> 2], - picked[{needSomethingForPicking[0], 0, <|minSomething -> 2, maxSomething -> Infinity, pickNumber -> 2|>}]], - - testUnevaluated[pick2Generator[minXorMax[0], 0], {pick2Generator::incompatibleSystem}], - testUnevaluated[pick2Generator[minXorMax[0], 0, pickNumber -> 2], {pick2Generator::incompatibleSystem}], - testUnevaluated[identityGenerator[minXorMax[0], 0], {identityGenerator::missingParameters}], - VerificationTest[identityGenerator[minXorMax[0], 0, minSomething -> 2], - {minXorMax[0], 0, <|minSomething -> 2, maxSomething -> Infinity|>}], - testUnevaluated[identityGenerator[minXorMax[0], 0, minSomething -> 2, maxSomething -> 3], - {identityGenerator::incompatibleParameters}], + typeTwoGenerator[systemWithParameterDependencies[], 0, minEventSize -> 2], + property[ + {systemWithParameterDependencies[], 0, <|minEventSize -> 2, maxEventSize -> Infinity, eventType -> 2|>}]], + + testUnevaluated[typeTwoGenerator[minXorMaxSystem[], 0], {typeTwoGenerator::incompatibleSystem}], + testUnevaluated[typeTwoGenerator[minXorMaxSystem[], 0, eventType -> 2], {typeTwoGenerator::incompatibleSystem}], + testUnevaluated[genericGenerator[minXorMaxSystem[], 0], {genericGenerator::missingParameters}], + VerificationTest[genericGenerator[minXorMaxSystem[], 0, minEventSize -> 2], + {minXorMaxSystem[], 0, <|minEventSize -> 2, maxEventSize -> Infinity|>}], + testUnevaluated[genericGenerator[minXorMaxSystem[], 0, minEventSize -> 2, maxEventSize -> 3], + {genericGenerator::incompatibleParameters}], (* Operator form *) - testUnevaluated[identityGenerator[echoSystem[0]] @ "test", {identityGenerator::argNotInit}], - testUnevaluated[identityGenerator[echoSystem[0], maxSomething -> 2] @ "test", {identityGenerator::argNotInit}], + testUnevaluated[genericGenerator[genericSystem[]] @ "test", {genericGenerator::argNotInit}], + testUnevaluated[genericGenerator[genericSystem[], maxEventSize -> 2] @ "test", {genericGenerator::argNotInit}], VerificationTest[ - identityGenerator[echoSystem[0]] @ 0, {echoSystem[0], 0, <|maxSomething -> Infinity, pickNumber -> None|>}], - testUnevaluated[identityGenerator[echoSystem[0]][], {identityGenerator::argx}], - testUnevaluated[identityGenerator[echoSystem[0]][0, 1], {identityGenerator::argx}], - VerificationTest[identityGenerator[echoSystem[0], maxSomething -> 2] @ 0, - {echoSystem[0], 0, <|maxSomething -> 2, pickNumber -> None|>}], - VerificationTest[identityGenerator[echoSystem[0], {maxSomething -> 2}] @ 0, - {echoSystem[0], 0, <|maxSomething -> 2, pickNumber -> None|>}], - VerificationTest[identityGenerator[echoSystem[0], <|maxSomething -> 2|>] @ 0, - {echoSystem[0], 0, <|maxSomething -> 2, pickNumber -> None|>}], - VerificationTest[identityGenerator[echoSystem[0], maxSomething -> 2, pickNumber -> 2] @ 0, - {echoSystem[0], 0, <|maxSomething -> 2, pickNumber -> 2|>}], + genericGenerator[genericSystem[]] @ 0, {genericSystem[], 0, <|maxEventSize -> Infinity, eventType -> None|>}], + testUnevaluated[genericGenerator[genericSystem[]][], {genericGenerator::argx}], + testUnevaluated[genericGenerator[genericSystem[]][0, 1], {genericGenerator::argx}], + VerificationTest[genericGenerator[genericSystem[], maxEventSize -> 2] @ 0, + {genericSystem[], 0, <|maxEventSize -> 2, eventType -> None|>}], + VerificationTest[genericGenerator[genericSystem[], {maxEventSize -> 2}] @ 0, + {genericSystem[], 0, <|maxEventSize -> 2, eventType -> None|>}], + VerificationTest[genericGenerator[genericSystem[], <|maxEventSize -> 2|>] @ 0, + {genericSystem[], 0, <|maxEventSize -> 2, eventType -> None|>}], + VerificationTest[genericGenerator[genericSystem[], maxEventSize -> 2, eventType -> 2] @ 0, + {genericSystem[], 0, <|maxEventSize -> 2, eventType -> 2|>}], VerificationTest[ - identityGenerator[listInit[0], {maxSomething -> 2}] @ 0, - {listInit[0], {maxSomething -> 2}, <|minSomething -> 0, maxSomething -> Infinity, pickNumber -> None|>}[0]], + genericGenerator[listStateSystem[], {maxEventSize -> 2}] @ 0, + {listStateSystem[], + {maxEventSize -> 2}, + <|minEventSize -> 0, maxEventSize -> Infinity, eventType -> None|>}[0]], VerificationTest[ - identityGenerator[listInit[0], {maxSomething -> 2}, minSomething -> 1] @ {0}, - {listInit[0], {maxSomething -> 2}, <|minSomething -> 1, maxSomething -> Infinity, pickNumber -> None|>}[{0}]], - VerificationTest[identityGenerator[listInit[0], minSomething -> 1, {maxSomething -> 2}] @ {0}, - {listInit[0], {0}, <|minSomething -> 1, maxSomething -> 2, pickNumber -> None|>}], + genericGenerator[listStateSystem[], {maxEventSize -> 2}, minEventSize -> 1] @ {0}, + {listStateSystem[], + {maxEventSize -> 2}, + <|minEventSize -> 1, maxEventSize -> Infinity, eventType -> None|>}[{0}]], + VerificationTest[genericGenerator[listStateSystem[], minEventSize -> 1, {maxEventSize -> 2}] @ {0}, + {listStateSystem[], {0}, <|minEventSize -> 1, maxEventSize -> 2, eventType -> None|>}], (* Existing generators *) VerificationTest[ - GenerateMultihistory[realSystem[0], 0], - {realSystem[0], 0, <|MaxDestroyerEvents -> Infinity, MaxEvents -> Infinity, MaxGeneration -> Infinity|>}], + GenerateMultihistory[realParameterSystem[], 0], + {realParameterSystem[], + 0, + <|MaxDestroyerEvents -> Infinity, MaxEvents -> Infinity, MaxGeneration -> Infinity|>}], VerificationTest[ - GenerateSingleHistory[realSystem[0], 0], - {realSystem[0], 0, <|MaxDestroyerEvents -> 1, MaxEvents -> Infinity, MaxGeneration -> Infinity|>}], + GenerateSingleHistory[realParameterSystem[], 0], + {realParameterSystem[], 0, <|MaxDestroyerEvents -> 1, MaxEvents -> Infinity, MaxGeneration -> Infinity|>}], (* Introspection *) VerificationTest[ - SubsetQ[$SetReplaceSystems, {echoSystem, needSomethingForPicking, minXorMax, listInit, realSystem}]], - VerificationTest[SubsetQ[$SetReplaceGenerators, {identityGenerator, pick2Generator}]], - VerificationTest[SetReplaceSystemParameters[listInit], {minSomething, maxSomething, pickNumber}] + SubsetQ[ + $SetReplaceSystems, + {genericSystem, systemWithParameterDependencies, minXorMaxSystem, listStateSystem, realParameterSystem}]], + VerificationTest[SubsetQ[$SetReplaceGenerators, {genericGenerator, typeTwoGenerator}]], + VerificationTest[SetReplaceSystemParameters[listStateSystem], {minEventSize, maxEventSize, eventType}] } |> |> From 20a7e700d0981706b6446cfb734df7eb43a28800 Mon Sep 17 00:00:00 2001 From: Max Piskunov Date: Sun, 11 Jul 2021 19:31:20 -0500 Subject: [PATCH 28/33] Small improvements. --- .../Generators/GenerateMultihistory.md | 7 +- .../Generators/GenerateSingleHistory.md | 6 +- .../Generators/MaxDestroyerEvents.md | 10 +- Documentation/Generators/MaxEventInputs.md | 11 ++- Documentation/Generators/MaxEvents.md | 2 +- Documentation/Generators/README.md | 19 ++-- .../Generators/SetReplaceSystemParameters.md | 2 +- Kernel/A1$generatorSystem.m | 93 +++++++++---------- Kernel/systemParameters.m | 2 +- Tests/generatorSystem.wlt | 3 +- 10 files changed, 77 insertions(+), 78 deletions(-) diff --git a/Documentation/Generators/GenerateMultihistory.md b/Documentation/Generators/GenerateMultihistory.md index 6473d7a1..a44afb56 100644 --- a/Documentation/Generators/GenerateMultihistory.md +++ b/Documentation/Generators/GenerateMultihistory.md @@ -1,8 +1,9 @@ # GenerateMultihistory -**`GenerateMultihistory`** is the most configurable multihistory generator. With no parameters, it attempts to generate -all possible histories starting from the initial state. However, it can be configured to generate partial multihistories -and even single histories, although, [`GenerateSingleHistory`](GenerateSingleHistory.md) is more convenient for that. +**`GenerateMultihistory`** is the most configurable multihistory generator. With no parameters specified, it attempts to +generate all possible histories starting from the initial state. However, it can be configured to generate partial +multihistories and even single histories, although [`GenerateSingleHistory`](GenerateSingleHistory.md) is more +convenient for that. For example, for a [`MultisetSubstitutionSystem`](/Documentation/Systems/MultisetSubstitutionSystem.md): diff --git a/Documentation/Generators/GenerateSingleHistory.md b/Documentation/Generators/GenerateSingleHistory.md index cfaa8436..bb69c32c 100644 --- a/Documentation/Generators/GenerateSingleHistory.md +++ b/Documentation/Generators/GenerateSingleHistory.md @@ -1,7 +1,7 @@ # GenerateSingleHistory **`GenerateSingleHistory`** generates single histories, which it achieves by setting -[`MaxDestroyerEvents`](MaxDestroyerEvents.md) to one. Note that for nondeterministic systems the history generated may +[`MaxDestroyerEvents`](MaxDestroyerEvents.md) to one. Note that for nondeterministic systems, the history generated may depend on the event order. For example, for a [`MultisetSubstitutionSystem`](/Documentation/Systems/MultisetSubstitutionSystem.md): @@ -21,5 +21,5 @@ In[] := #["ExpressionsEventsGraph", VertexLabels -> Placed[Automatic, After]] & Note that single histories are not necessarily single-path systems. Multiple rewriting events can be possible starting -from a given state. However, only one event can take any given token as an input, which ensures that all generated -events do not conflict with each other (i.e., there are no branchlike-separated events). +from a given state. However, only one event can take any given token as an input, ensuring that all generated events do +not conflict with each other (i.e., there are no branchlike-separated events). diff --git a/Documentation/Generators/MaxDestroyerEvents.md b/Documentation/Generators/MaxDestroyerEvents.md index c6373473..a6c7f0b9 100644 --- a/Documentation/Generators/MaxDestroyerEvents.md +++ b/Documentation/Generators/MaxDestroyerEvents.md @@ -1,8 +1,8 @@ # MaxDestroyerEvents -`MaxDestroyerEvents` is an event-selection parameter that controls the number of (inconsistent) events that are allowed -to take the same token as an input. [`GenerateSingleHistory`](GenerateSingleHistory.md) limits the evaluation to a -single history by setting `MaxDestroyerEvents` to one. +`MaxDestroyerEvents` is an event-selection parameter that controls the number of inconsistent events allowed to take the +same token as an input. [`GenerateSingleHistory`](GenerateSingleHistory.md) limits the evaluation to a single history by +setting `MaxDestroyerEvents` to one. ```wl In[] := #["ExpressionsEventsGraph", VertexLabels -> Placed[Automatic, After]] & @ @@ -13,7 +13,7 @@ In[] := #["ExpressionsEventsGraph", VertexLabels -> Placed[Automatic, After]] & If unset (which defaults to [`Infinity`](https://reference.wolfram.com/language/ref/Infinity.html)), it will generate a -full multihistory subject to other selection and stopping parameters: +full multihistory object subject to other selection and stopping parameters: ```wl In[] := #["ExpressionsEventsGraph", VertexLabels -> Placed[Automatic, After]] & @ @@ -34,4 +34,4 @@ In[] := #["ExpressionsEventsGraph", VertexLabels -> Placed[Automatic, After]] & -Note that in this case, like in the case of a single history, the result depends on the event order. +Note that results generally depend on the event order in this case, similar to single histories. diff --git a/Documentation/Generators/MaxEventInputs.md b/Documentation/Generators/MaxEventInputs.md index bf133ae8..6013d255 100644 --- a/Documentation/Generators/MaxEventInputs.md +++ b/Documentation/Generators/MaxEventInputs.md @@ -1,12 +1,13 @@ # MaxEventInputs `MaxEventInputs` and [`MinEventInputs`](MinEventInputs.md) are event-selection parameters that control the max and min -numbers of input tokens allowed per event. In addition to [being useful](MinEventInputs.md) for rules with variable -numbers of inputs, `MaxEventInputs` is sometimes useful for optimization. By default, systems like +numbers of input tokens allowed per event. + +In addition to [being useful](MinEventInputs.md) for rules with variable numbers of inputs, `MaxEventInputs` is +sometimes useful for optimization. By default, systems like [`MultisetSubstitutionSystem`](/Documentation/Systems/MultisetSubstitutionSystem.md) consider all subsets of tokens to -find matches, which can be slow, especially to finalize the complete evaluation, as it requires going through all -subsets to find out that no more matches are possible. However, if the range of match sizes is known ahead of time, it -can be used to make the evaluation faster. Compare: +find matches, which can be slow. However, if the range of match sizes is known ahead of time, one can set it explicitly. +Compare: ```wl In[] := First @ AbsoluteTiming @ diff --git a/Documentation/Generators/MaxEvents.md b/Documentation/Generators/MaxEvents.md index 9390d18d..bdfcc8b9 100644 --- a/Documentation/Generators/MaxEvents.md +++ b/Documentation/Generators/MaxEvents.md @@ -11,4 +11,4 @@ In[] := #["ExpressionsEventsGraph"] & @ -Compare to [`MaxGeneration`](MaxGeneration.md) which controls the depth of the evaluation instead. +Compare to [`MaxGeneration`](MaxGeneration.md), which controls the depth of the evaluation instead. diff --git a/Documentation/Generators/README.md b/Documentation/Generators/README.md index 9f4455ff..8f7c9245 100644 --- a/Documentation/Generators/README.md +++ b/Documentation/Generators/README.md @@ -8,15 +8,15 @@ In *SetReplace*, we split the states of [computational systems](/Documentation/S we call tokens. Rewrites (which we call events) replace some of these tokens with others. *SetReplace* can evaluate multiple branches of nondeterministic systems simultaneously. That is done by applying different events to the same tokens and keeping events and tokens instead of states in [`Multihistory`](/Documentation/Types/Multihistory/README.md) -objects. We can reconstruct the states from that information afterwards. +objects. We can reconstruct the states from that information afterward. There are parameters that control how this evaluation is done. Some of them control which events to select, which is -essential in cases where the system does not terminate. Other parameters might control how to deduplicate identical -tokens, etc. Different generators correspond to different settings of parameters. Additional parameters can also be -specified similar to options. +essential when the system does not terminate. Other parameters might control how to deduplicate identical tokens, etc. +Different generators correspond to different settings of parameters. Additional parameters can be specified with a +syntax similar to options. For example, [`GenerateSingleHistory`](GenerateSingleHistory.md) corresponds to -[`MaxDestroyerEvents -> 1`](MaxDestroyerEvents.md) and thus does produce nondeterministic branching: +[`MaxDestroyerEvents -> 1`](MaxDestroyerEvents.md) and thus does not produce nondeterministic branching: ```wl In[] := #["ExpressionsEventsGraph", VertexLabels -> Placed[Automatic, After]] & @ @@ -26,7 +26,7 @@ In[] := #["ExpressionsEventsGraph", VertexLabels -> Placed[Automatic, After]] & -We can also use a more generate [`GenerateMultihistory`](GenerateMultihistory.md) and specify +We can also use a more general [`GenerateMultihistory`](GenerateMultihistory.md) and specify [`MaxDestroyerEvents`](MaxDestroyerEvents.md) manually. ```wl @@ -40,8 +40,7 @@ In[] := #["ExpressionsEventsGraph", VertexLabels -> Placed[Automatic, After]] & The same generators support multiple systems. In addition to [`MultisetSubstitutionSystem`](/Documentation/Systems/MultisetSubstitutionSystem.md), other examples include -`HypergraphSubstitutionSystem`, `StringSubstitutionSystem`, etc. Many of these systems have shared evaluation -parameters. +`HypergraphSubstitutionSystem`, `StringSubstitutionSystem`, etc. Many of these systems have shared parameters. All generators take the form @@ -55,7 +54,7 @@ or, in operator form, Generator[System[rules], parameters...] @ init ``` -Note, however, that the first form takes precedence and, if parameters can be interpreted as an init, the second form +Note, however, that the first form takes precedence, and if parameters can be interpreted as an init, the second form may not evaluate as expected. `parameters` can be specified either as a [`Sequence`](https://reference.wolfram.com/language/ref/Sequence.html) of @@ -78,4 +77,4 @@ in such [`Rule`](https://reference.wolfram.com/language/ref/Rule.html)s depend o * [`MinEventInputs`](MinEventInputs.md) * [`MaxEventInputs`](MaxEventInputs.md) * [`MaxEvents`](MaxEvents.md) - * [`MaxGeneration`](MaxGeneration.md) + * [`MaxGeneration`](MaxGeneration.md) — controls the depth of the evaluation diff --git a/Documentation/Generators/SetReplaceSystemParameters.md b/Documentation/Generators/SetReplaceSystemParameters.md index 70941c66..15e17e76 100644 --- a/Documentation/Generators/SetReplaceSystemParameters.md +++ b/Documentation/Generators/SetReplaceSystemParameters.md @@ -8,7 +8,7 @@ In[] := SetReplaceSystemParameters[MultisetSubstitutionSystem] Out[] = {MaxGeneration, MaxDestroyerEvents, MinEventInputs, MaxEventInputs, MaxEvents} ``` -The entire system spec including the rules can be passed as well (although the rules don't affect the result): +The entire system spec including the rules can be passed as well (rules don't affect the result): ```wl In[] := SetReplaceSystemParameters[AtomicStateSystem[a_ :> a + 1]] diff --git a/Kernel/A1$generatorSystem.m b/Kernel/A1$generatorSystem.m index 661760e1..c12e9d74 100644 --- a/Kernel/A1$generatorSystem.m +++ b/Kernel/A1$generatorSystem.m @@ -16,7 +16,7 @@ $systemImplementations = <||>; (* system -> implementationFunction *) $systemInitPatterns = <||>; (* system -> pattern *) $systemParameters = <||>; (* system -> {parameter, ...} *) -$systemParameterDependencies = <||>; (* system -> logical expressions on parameter keys *) +$systemParameterDependencies = <||>; (* system -> logical expression on parameter keys *) (* Every system implementation needs to call this function in order to be usable through GenerateMultihistory and other generators. *) @@ -24,22 +24,21 @@ (* The third argument is the pattern that the init should satisfy. *) (* Parameters in the fourth argument should be declared with declareSystemParameter. Their values are guaranteed to - match the pattern from the declaration. Further, the logical expression in the last argument will check if all + match the pattern from that declaration. Further, the logical expression in the last argument will check if all required parameters are specified. Some parameters may require others to be specified, e.g., - Implies[MaxDestroyerEvents || MaxEvents, EventOrder] means that if MaxDestroyerEvents or MaxEvents is specified, \ - EventOrder must be specified as well. The implementation function can expect all specified parameters present \ - (substituted with defaults if missing) and all values satisfying the constraints (substituted with defaults if \ + Implies[MaxDestroyerEvents || MaxEvents, EventOrder] means that if MaxDestroyerEvents or MaxEvents is specified, + EventOrder must be specified as well. The implementation function can expect all specified parameters present + (substituted with defaults if missing) and all values will satisfy the constraints (substituted with defaults if missing). *) -(* For example, - declareSystem[MultisetSubstitutionSystem, +(* declareSystem[MultisetSubstitutionSystem, generateMultisetSubstitutionSystem, _List, {MaxGeneration, MinEventInputs, MaxDestroyerEvents, MaxEvents, EventOrder}, Implies[MaxDestroyerEvents || MaxEvents, EventOrder]] *) (* The implementation function is then called as - generateMultisetSubstitutionSystem[MultisetSubstitutionSystem[rules], init, parameters] *) + generateMultisetSubstitutionSystem[MultisetSubstitutionSystem[rules], init, <|MaxGeneration -> value, ...|>] *) declareSystem[systemType_, implementationFunction_, @@ -53,7 +52,7 @@ ); declareMessage[General::unsatisfiableParameterDependencies, - "Internal error. Parameter constraints `constraints` for `system` are not satisfyable."]; + "Internal error. Parameter constraints `constraints` for `system` are not satisfiable."]; declareSystem[systemType_, _, _, _List, dependencies_] := message[SetReplace, Failure["unsatisfiableParameterDependencies", <|"constraints" -> dependencies, "system" -> systemType|>]]; @@ -69,17 +68,15 @@ $generatorParameters = <||>; (* generator -> <|parameter -> value, ...|> *) $generatorProperties = <||>; (* generator -> property *) -(* Generators are functions that are called to produce EventSet objects. They take the form +(* Generators are functions that are called to produce Multihistory objects. They take the form symbol[system, init, params]. They also define a fixed set of parameter values. These parameter values cannot be changed in params. Generators can also compute a property at the end of the evaluation. *) -(* For example, - - declareSystemGenerator[EvaluateSingleHistory, +(* declareSystemGenerator[EvaluateSingleHistory, evaluateSingleHistory, <|MaxDestroyerEvents -> 1|>, FinalState, - "yields a single history object."] + "yields a single-history object."] Note that the constraint in the last argument of declareSystemGenerator still needs to be specified, which means EventOrder is now a required parameter. *) @@ -87,10 +84,10 @@ (* evaluateSingleHistory is a PackageScope symbol that will throw exceptions instead of returning unevaluated. It cannot be used in operator form. *) -systemUsage = "* A list of all supported systems can be obtained with $SetReplaceSystems."; -initUsage = "* init$ is the initial state, the format of which depends on the system$."; -parametersUsage = "* parameters$ is either a Sequence, a List or an Association of key-value rules. A list of " <> - "parameters can be obtained with SetReplaceSystemParameters[system$]."; +$systemUsage = "* A list of all supported systems can be obtained with $SetReplaceSystems."; +$initUsage = "* init$ is the initial state, the format of which depends on the system$."; +$parametersUsage = "* parameters$ is either a Sequence, a List or an Association of key-value rules. A list of " <> + "parameter keys can be obtained with SetReplaceSystemParameters[system$]."; declareSystemGenerator[publicSymbol_, packageScopeSymbol_, parameterValues_, property_, usage_] := ( $generatorPackageScopeSymbols[publicSymbol] = packageScopeSymbol; @@ -98,10 +95,7 @@ $generatorProperties[publicSymbol] = property; SyntaxInformation[publicSymbol] = {"ArgumentsPattern" -> {system_, init_., parameters___}}; SetUsage @ Evaluate @ StringRiffle[ - {ToString[publicSymbol] <> "[system$, init$, parameters$] " <> usage, - systemUsage, - initUsage, - parametersUsage}, + {ToString[publicSymbol] <> "[system$, init$, parameters$] " <> usage, $systemUsage, $initUsage, $parametersUsage}, "\n"]; ); @@ -115,9 +109,9 @@ $parameterDefaults = <||>; $parameterPatterns = <||>; -(* Parameters are like protocols. Systems can declare that they implement them. Some generators require some parameters - to be supported and define values for them. To declare a new parameter, one needs to specify a default value (which - usually disables whatever the parameter is doing) and a pattern the parameter value should match. *) +(* Both systems and generators use parameters. Systems declare parameters they implement. Generators set fixed values + for a subset of parameters. To declare a new parameter, one needs to specify a default value (which usually disables + whatever the parameter is doing) and a pattern the parameter value should match. *) (* declareSystemParameter[MaxGeneration, Infinity, @@ -138,11 +132,8 @@ (* Initialization *) -(* It would be best to only show autocompletions for specific-system keys, but it does not seem to be possible because - dependent argument completions are only supported in WL if the main argument is a string. *) - SetUsage @ " -$SetReplaceSystems gives the list of all computational systems that can be used with GenerateEventSet and related \ +$SetReplaceSystems gives the list of all computational systems that can be used with GenerateMultihistory and related \ functions. "; @@ -152,9 +143,8 @@ "; declareMessage[ - General::unknownSystemParameters, "Parameters `parameters` are implemented by `system` but are not declared."]; -declareMessage[ - General::unknownGeneratorParameters, "Parameters `parameters` are set by `generator` but are not declared."]; + General::unknownSystemParameters, "Parameters `parameters` are implemented by `system` but not declared."]; +declareMessage[General::unknownGeneratorParameters, "Parameters `parameters` are set by `generator` but not declared."]; initializeSystemGenerators[] := ( $SetReplaceSystems = Sort @ Keys @ $systemImplementations; @@ -175,6 +165,7 @@ declareMessage[General::argNotInit, "The init `arg` in `expr` should match `pattern`."]; declareMessage[General::unknownSystem, "`system` is not a recognized SetReplace system."]; +declareMessage[General::noRules, "Rules need to be specified as `system`[\[Ellipsis]] in `expr`."]; defineGeneratorImplementation[generator_] := With[{packageScopeGenerator = $generatorPackageScopeSymbols[generator]}, expr : generator[system_, init_, parameters___] /; @@ -195,13 +186,18 @@ expr : generator[] /; CheckArguments[expr, {1, Infinity}] := $Failed; packageScopeGenerator[system_, init_, parameters___] /; - MatchQ[init, Lookup[$systemInitPatterns, Head[system], _]] := ModuleScope[ - implementation = $systemImplementations[Head[system]]; - If[MissingQ[implementation], throw[Failure["unknownSystem", <|"system" -> system|>]]]; + MatchQ[init, Lookup[$systemInitPatterns, Head[system], _]] := ( + If[MissingQ[$systemImplementations[Head[system]]], + If[MissingQ[$systemImplementations[system]], + throw[Failure["unknownSystem", <|"system" -> system|>]] + , + throw[Failure["noRules", <|"system" -> system|>]] + ]; + ]; checkSystemGeneratorCompatibility[Head[system], generator]; $generatorProperties[generator] @ $systemImplementations[Head[system]][system, init, parseParameters[generator, Head[system]][parameters]] - ]; + ); packageScopeGenerator[___] := throw[Failure[None, <||>]]; implementationOperator[generator][system_][init_] /; MatchQ[init, $systemInitPatterns[Head[system]]] := @@ -259,33 +255,34 @@ throw[Failure[ "invalidParameter", <|"parameter" -> key, "value" -> value, "pattern" -> $parameterPatterns[key]|>]]; -simplifyParameterCondition[generator_, system_, specifiedKeys_] := - FullSimplify[ - $systemParameterDependencies[system] /. - Alternatives @@ Join[specifiedKeys, Keys @ $generatorParameters[generator]] -> True]; -compatibleParametersQ[generator_, system_, specifiedKeys_] := - FullSimplify[ - $systemParameterDependencies[system] /. - Alternatives @@ Join[specifiedKeys, Keys @ $generatorParameters[generator]] -> True /. - Alternatives @@ $systemParameters[system] -> False] -compatibleParametersQ[___] := False - declareMessage[General::incompatibleParameters, "Parameters in `expr` are incompatible. Specified parameters should satisfy `condition`."]; checkParameterCompleteness[generator_, system_][keys_] /; simplifyParameterCondition[generator, system, keys] === False := throw[Failure["incompatibleParameters", <|"condition" -> $systemParameterDependencies[system]|>]]; +simplifyParameterCondition[generator_, system_, specifiedKeys_] := + FullSimplify[ + $systemParameterDependencies[system] /. + Alternatives @@ Join[specifiedKeys, Keys @ $generatorParameters[generator]] -> True]; + declareMessage[General::missingParameters, "`missingParameters` should be explicitly specified in `expr`."]; checkParameterCompleteness[generator_, system_][keys_] /; !compatibleParametersQ[generator, system, keys] := throw[Failure["missingParameters", <|"missingParameters" -> simplifyParameterCondition[generator, system, keys]|>]]; +compatibleParametersQ[generator_, system_, specifiedKeys_] := + FullSimplify[ + $systemParameterDependencies[system] /. + Alternatives @@ Join[specifiedKeys, Keys @ $generatorParameters[generator]] -> True /. + Alternatives @@ $systemParameters[system] -> False]; +compatibleParametersQ[___] := False; + addMissingParameters[generator_, system_][parameters_] := Join[KeyTake[$parameterDefaults, $systemParameters[system]], parameters, $generatorParameters[generator]]; (* Introspection functions *) -SetUsage @ "SetReplaceSystemParameters[system$] yields the list of parameters supported by system$."; +SetUsage @ "SetReplaceSystemParameters[system$] yields the list of parameters supported by the system$."; SyntaxInformation[SetReplaceSystemParameters] = {"ArgumentsPattern" -> {system_}}; diff --git a/Kernel/systemParameters.m b/Kernel/systemParameters.m index 5140da32..d6a266ec 100644 --- a/Kernel/systemParameters.m +++ b/Kernel/systemParameters.m @@ -11,7 +11,7 @@ {MaxGeneration, Infinity, "is an event-selection parameter specifying the maximum generation of created tokens.\n" <> - "* Tokens in init$ are assumed to have a generation 0.\n" <> + "* Tokens in init$ are assumed to have generation 0.\n" <> "* A generation of an event and its output tokens is defined as the largest generation of its inputs plus one."}, {MaxDestroyerEvents, Infinity, diff --git a/Tests/generatorSystem.wlt b/Tests/generatorSystem.wlt index 1850f50a..33832c30 100644 --- a/Tests/generatorSystem.wlt +++ b/Tests/generatorSystem.wlt @@ -10,7 +10,7 @@ declareSystemParameter[maxEventSize, Infinity, _ ? (GreaterEqualThan[0]), "is a max parameter for a test value."]; declareSystemParameter[minEventSize, 0, _ ? (GreaterEqualThan[0]), "is a min parameter for a test value."]; - declareSystemParameter[eventType, None, None | 0 | 1 | 2, "is an optional choice between 0, 1, and 2."]; + declareSystemParameter[eventType, None, None | 0 | 1 | 2, "is a choice parameter between None, 0, 1, and 2."]; declareSystem[genericSystem, List, _Integer, {maxEventSize, eventType}, True]; declareSystem[systemWithParameterDependencies, @@ -57,6 +57,7 @@ (* Two args *) testUnevaluated[genericGenerator[0, 0], {genericGenerator::unknownSystem}], + testUnevaluated[genericGenerator[genericSystem, 0], {genericGenerator::noRules}], testUnevaluated[genericGenerator[genericSystem[], "test"], {}], (* parameters are not yet parsed at this stage *) VerificationTest[ genericGenerator[genericSystem[], 0], {genericSystem[], 0, <|maxEventSize -> Infinity, eventType -> None|>}], From 3c7e9aabb70f4cfc28a952195b1f0f5ca74ad1e2 Mon Sep 17 00:00:00 2001 From: Max Piskunov Date: Thu, 15 Jul 2021 08:09:06 -0500 Subject: [PATCH 29/33] Improvements to docs readability. --- Documentation/Generators/GenerateSingleHistory.md | 8 +++++--- Documentation/Generators/MaxEventInputs.md | 8 ++++---- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/Documentation/Generators/GenerateSingleHistory.md b/Documentation/Generators/GenerateSingleHistory.md index bb69c32c..ae19576a 100644 --- a/Documentation/Generators/GenerateSingleHistory.md +++ b/Documentation/Generators/GenerateSingleHistory.md @@ -20,6 +20,8 @@ In[] := #["ExpressionsEventsGraph", VertexLabels -> Placed[Automatic, After]] & -Note that single histories are not necessarily single-path systems. Multiple rewriting events can be possible starting -from a given state. However, only one event can take any given token as an input, ensuring that all generated events do -not conflict with each other (i.e., there are no branchlike-separated events). +Note that there is a distinction between single-history and single-path systems. Single-path systems are defined as ones +where there is only one event possible from every state. A Turing machine would be an example of a single-path system. +On the other hand, single-history systems allow multiple events from a single state, but all these events must be +consistent, i.e., take non-overlapping inputs. Neither single-path nor single-history systems have branchlike-separated +events. diff --git a/Documentation/Generators/MaxEventInputs.md b/Documentation/Generators/MaxEventInputs.md index 6013d255..b64595f2 100644 --- a/Documentation/Generators/MaxEventInputs.md +++ b/Documentation/Generators/MaxEventInputs.md @@ -1,13 +1,13 @@ # MaxEventInputs -`MaxEventInputs` and [`MinEventInputs`](MinEventInputs.md) are event-selection parameters that control the max and min -numbers of input tokens allowed per event. +`MaxEventInputs` and [`MinEventInputs`](MinEventInputs.md) are event-selection parameters that control the maximum and +minimum numbers of input tokens allowed per event. In addition to [being useful](MinEventInputs.md) for rules with variable numbers of inputs, `MaxEventInputs` is sometimes useful for optimization. By default, systems like [`MultisetSubstitutionSystem`](/Documentation/Systems/MultisetSubstitutionSystem.md) consider all subsets of tokens to -find matches, which can be slow. However, if the range of match sizes is known ahead of time, one can set it explicitly. -Compare: +find matches, which can be slow. However, if the range of match sizes is known ahead of time, one can set it explicitly +to reduce the number of matches enumerated. Compare: ```wl In[] := First @ AbsoluteTiming @ From 26a506e945172cab2a338df158f5864eee958358 Mon Sep 17 00:00:00 2001 From: Max Piskunov Date: Thu, 15 Jul 2021 11:46:26 -0500 Subject: [PATCH 30/33] Address remaining review comments. --- Documentation/Generators/MaxGeneration.md | 9 ++-- Documentation/Generators/README.md | 10 +++-- Kernel/A1$generatorSystem.m | 54 +++++++++++------------ Kernel/systemParameters.m | 3 +- 4 files changed, 39 insertions(+), 37 deletions(-) diff --git a/Documentation/Generators/MaxGeneration.md b/Documentation/Generators/MaxGeneration.md index 455b653e..55d69a38 100644 --- a/Documentation/Generators/MaxGeneration.md +++ b/Documentation/Generators/MaxGeneration.md @@ -34,10 +34,11 @@ In[] := #["ExpressionsEventsGraph"] & @ SetReplaceTypeConvert[{WolframModelEvolu -Since `MaxGeneration` is a selection parameter rather than a stopping condition, it will continue evaluation even after -encountering matches exceeding the generations constraint, which might also result in a different -event order (i.e., some events being skipped) than if using, e.g., [`MaxEvents`](MaxEvents.md). For this reason, -`MaxGenerations` (like other selection parameters) does not have a corresponding termination reason. +`MaxGeneration` is an event selection parameter, not a stopping condition. That is, the evolution of the system won't +stop if a match with a generation greater than the constraint is encountered. Instead, it will ignore those matches and +instantiate only those that satisfy the generation constraint. This selection of events according to their generation +will (in most cases) affect the event order, as opposed to using stopping conditions, e.g., `MaxEvents`. For this +reason, `MaxGenerations` (like other selection parameters) does not have a corresponding termination reason. ```wl In[] := #[[2, "TerminationReason"]] & @ diff --git a/Documentation/Generators/README.md b/Documentation/Generators/README.md index 8f7c9245..740a1a56 100644 --- a/Documentation/Generators/README.md +++ b/Documentation/Generators/README.md @@ -10,10 +10,12 @@ multiple branches of nondeterministic systems simultaneously. That is done by ap tokens and keeping events and tokens instead of states in [`Multihistory`](/Documentation/Types/Multihistory/README.md) objects. We can reconstruct the states from that information afterward. -There are parameters that control how this evaluation is done. Some of them control which events to select, which is -essential when the system does not terminate. Other parameters might control how to deduplicate identical tokens, etc. -Different generators correspond to different settings of parameters. Additional parameters can be specified with a -syntax similar to options. +There are parameters that control how this evaluation is done. Some of them control which events to select. Other +parameters might control how to deduplicate identical tokens, etc. Different generators correspond to different settings +of parameters. Additional parameters can be specified with a syntax similar to options. + +Note that if the system does not terminate, it is necessary to specify some parameters, such as +[`MaxEvents`](MaxEvents.md) or [`MaxGeneration`](MaxGeneration.md). For example, [`GenerateSingleHistory`](GenerateSingleHistory.md) corresponds to [`MaxDestroyerEvents -> 1`](MaxDestroyerEvents.md) and thus does not produce nondeterministic branching: diff --git a/Kernel/A1$generatorSystem.m b/Kernel/A1$generatorSystem.m index c12e9d74..7c87167e 100644 --- a/Kernel/A1$generatorSystem.m +++ b/Kernel/A1$generatorSystem.m @@ -6,11 +6,37 @@ PackageExport["$SetReplaceGenerators"] PackageExport["SetReplaceSystemParameters"] +PackageScope["declareSystemParameter"] PackageScope["declareSystem"] PackageScope["declareSystemGenerator"] -PackageScope["declareSystemParameter"] PackageScope["initializeSystemGenerators"] +(* Parameter declaration *) + +$parameterDefaults = <||>; +$parameterPatterns = <||>; + +(* Both systems and generators use parameters. Systems declare parameters they implement. Generators set fixed values + for a subset of parameters. To declare a new parameter, one needs to specify a default value (which usually disables + whatever the parameter is doing) and a pattern the parameter value should match. *) + +(* declareSystemParameter[MaxGeneration, + Infinity, + _ ? (GreaterEqualThan[0]), + "is a parameter specifying the maximum generations of tokens that will be created."] *) + +declareSystemParameter[name_, defaultValue_, pattern_, usage_] := ( + $parameterDefaults[name] = defaultValue; + $parameterPatterns[name] = pattern; + SyntaxInformation[name] = {"ArgumentsPattern" -> {}}; + SetUsage @ Evaluate[ToString[name] <> " " <> usage]; +); + +declareMessage[General::invalidSystemParameterDeclaration, + "Internal error. Parameter is declared incorrectly with arguments `args`."]; +declareSystemParameter[args___] := + message[SetReplace, Failure["invalidSystemParameterDeclaration", <|"args" -> {args}|>]]; + (* System declaration *) $systemImplementations = <||>; (* system -> implementationFunction *) @@ -104,32 +130,6 @@ declareSystemGenerator[args___] := message[SetReplace, Failure["invalidSystemGeneratorDeclaration", <|"args" -> {args}|>]]; -(* Parameter declaration *) - -$parameterDefaults = <||>; -$parameterPatterns = <||>; - -(* Both systems and generators use parameters. Systems declare parameters they implement. Generators set fixed values - for a subset of parameters. To declare a new parameter, one needs to specify a default value (which usually disables - whatever the parameter is doing) and a pattern the parameter value should match. *) - -(* declareSystemParameter[MaxGeneration, - Infinity, - _ ? (GreaterEqualThan[0]), - "is a parameter specifying the maximum generations of tokens that will be created."] *) - -declareSystemParameter[name_, defaultValue_, pattern_, usage_] := ( - $parameterDefaults[name] = defaultValue; - $parameterPatterns[name] = pattern; - SyntaxInformation[name] = {"ArgumentsPattern" -> {}}; - SetUsage @ Evaluate[ToString[name] <> " " <> usage]; -); - -declareMessage[General::invalidSystemParameterDeclaration, - "Internal error. Parameter is declared incorrectly with arguments `args`."]; -declareSystemParameter[args___] := - message[SetReplace, Failure["invalidSystemParameterDeclaration", <|"args" -> {args}|>]]; - (* Initialization *) SetUsage @ " diff --git a/Kernel/systemParameters.m b/Kernel/systemParameters.m index d6a266ec..c0ed1b53 100644 --- a/Kernel/systemParameters.m +++ b/Kernel/systemParameters.m @@ -6,6 +6,7 @@ PackageExport["MaxDestroyerEvents"] PackageExport["MinEventInputs"] PackageExport["MaxEventInputs"] +PackageExport["MaxEvents"] declareSystemParameter[#, #2, _ ? (GreaterEqualThan[0]), #3] & @@@ { {MaxGeneration, @@ -23,8 +24,6 @@ (* Stopping-condition parameters *) -PackageExport["MaxEvents"] - declareSystemParameter[ MaxEvents, Infinity, From 2fe9993b56c9029ab54aabda49e62f2d16a37e43 Mon Sep 17 00:00:00 2001 From: Max Piskunov Date: Fri, 16 Jul 2021 07:50:21 -0500 Subject: [PATCH 31/33] Clarify what match is in MaxGeneration.md. --- Documentation/Generators/MaxGeneration.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/Documentation/Generators/MaxGeneration.md b/Documentation/Generators/MaxGeneration.md index 55d69a38..592b7d84 100644 --- a/Documentation/Generators/MaxGeneration.md +++ b/Documentation/Generators/MaxGeneration.md @@ -35,10 +35,11 @@ In[] := #["ExpressionsEventsGraph"] & @ SetReplaceTypeConvert[{WolframModelEvolu `MaxGeneration` is an event selection parameter, not a stopping condition. That is, the evolution of the system won't -stop if a match with a generation greater than the constraint is encountered. Instead, it will ignore those matches and -instantiate only those that satisfy the generation constraint. This selection of events according to their generation -will (in most cases) affect the event order, as opposed to using stopping conditions, e.g., `MaxEvents`. For this -reason, `MaxGenerations` (like other selection parameters) does not have a corresponding termination reason. +stop if a match (tentative event) with a generation greater than the constraint is encountered. Instead, it will ignore +those matches and instantiate only those that satisfy the generation constraint. This selection of events according to +their generation will (in most cases) affect the event order, as opposed to using stopping conditions, e.g., +`MaxEvents`. For this reason, `MaxGenerations` (like other selection parameters) does not have a corresponding +termination reason. ```wl In[] := #[[2, "TerminationReason"]] & @ From b63e5e60cac16c4d853f7052b1a507fd18e1f58f Mon Sep 17 00:00:00 2001 From: Max Piskunov Date: Fri, 16 Jul 2021 10:53:20 -0500 Subject: [PATCH 32/33] Switch generators to the operator form only. --- .../Generators/GenerateMultihistory.md | 2 +- .../Generators/GenerateSingleHistory.md | 2 +- .../Generators/MaxDestroyerEvents.md | 6 +- Documentation/Generators/MaxEventInputs.md | 2 +- Documentation/Generators/MaxEvents.md | 2 +- Documentation/Generators/MaxGeneration.md | 9 +- Documentation/Generators/MinEventInputs.md | 4 +- Documentation/Generators/README.md | 13 +-- Documentation/Systems/AtomicStateSystem.md | 2 +- .../Systems/MultisetSubstitutionSystem.md | 5 +- .../Types/Multihistory/AtomicStateSystem0.md | 2 +- .../MultisetSubstitutionSystem0.md | 2 +- Documentation/Types/Multihistory/README.md | 2 +- Kernel/A1$generatorSystem.m | 36 ++----- Kernel/AtomicStateSystem.m | 3 +- Tests/AtomicStateSystem.wlt | 10 +- Tests/MultisetSubstitutionSystem.wlt | 34 ++++--- .../MultisetToWolframModelEvolutionObject.wlt | 4 +- Tests/generatorSystem.wlt | 93 +++++++------------ Tests/hypergraphMatching.wlt | 4 +- performanceTest.wls | 6 +- 21 files changed, 93 insertions(+), 150 deletions(-) diff --git a/Documentation/Generators/GenerateMultihistory.md b/Documentation/Generators/GenerateMultihistory.md index a44afb56..be7e19d7 100644 --- a/Documentation/Generators/GenerateMultihistory.md +++ b/Documentation/Generators/GenerateMultihistory.md @@ -9,7 +9,7 @@ For example, for a [`MultisetSubstitutionSystem`](/Documentation/Systems/Multise ```wl In[] := multihistory = GenerateMultihistory[ - MultisetSubstitutionSystem[{a_, b_} :> {a + b}], {1, 2, 3, 4}, MaxDestroyerEvents -> 3, MaxEvents -> 10] + MultisetSubstitutionSystem[{a_, b_} :> {a + b}], MaxDestroyerEvents -> 3, MaxEvents -> 10] @ {1, 2, 3, 4} ``` diff --git a/Documentation/Generators/GenerateSingleHistory.md b/Documentation/Generators/GenerateSingleHistory.md index ae19576a..2cbb4ba8 100644 --- a/Documentation/Generators/GenerateSingleHistory.md +++ b/Documentation/Generators/GenerateSingleHistory.md @@ -8,7 +8,7 @@ For example, for a [`MultisetSubstitutionSystem`](/Documentation/Systems/Multise ```wl In[] := multihistory = GenerateSingleHistory[ - MultisetSubstitutionSystem[{a_, b_} :> {a + b, a - b, a * b}], {1, 2}, MaxEvents -> 10] + MultisetSubstitutionSystem[{a_, b_} :> {a + b, a - b, a * b}], MaxEvents -> 10] @ {1, 2} ``` diff --git a/Documentation/Generators/MaxDestroyerEvents.md b/Documentation/Generators/MaxDestroyerEvents.md index a6c7f0b9..22f8672f 100644 --- a/Documentation/Generators/MaxDestroyerEvents.md +++ b/Documentation/Generators/MaxDestroyerEvents.md @@ -7,7 +7,7 @@ setting `MaxDestroyerEvents` to one. ```wl In[] := #["ExpressionsEventsGraph", VertexLabels -> Placed[Automatic, After]] & @ SetReplaceTypeConvert[{WolframModelEvolutionObject, 2}] @ - GenerateMultihistory[MultisetSubstitutionSystem[{a_, b_} :> {a + b}], {1, 2, 3}, MaxDestroyerEvents -> 1] + GenerateMultihistory[MultisetSubstitutionSystem[{a_, b_} :> {a + b}], MaxDestroyerEvents -> 1] @ {1, 2, 3} ``` @@ -19,7 +19,7 @@ full multihistory object subject to other selection and stopping parameters: In[] := #["ExpressionsEventsGraph", VertexLabels -> Placed[Automatic, After]] & @ SetReplaceTypeConvert[{WolframModelEvolutionObject, 2}] @ GenerateMultihistory[ - MultisetSubstitutionSystem[{a_, b_} :> {a + b}], {1, 2, 3}, MaxDestroyerEvents -> Infinity, MaxGeneration -> 1] + MultisetSubstitutionSystem[{a_, b_} :> {a + b}], MaxDestroyerEvents -> Infinity, MaxGeneration -> 1] @ {1, 2, 3} ``` @@ -29,7 +29,7 @@ If set to a finite number, it will generate a partial multihistory: ```wl In[] := #["ExpressionsEventsGraph", VertexLabels -> Placed[Automatic, After]] & @ SetReplaceTypeConvert[{WolframModelEvolutionObject, 2}] @ - GenerateMultihistory[MultisetSubstitutionSystem[{a_, b_} :> {a + b}], {1, 2, 3}, MaxDestroyerEvents -> 5] + GenerateMultihistory[MultisetSubstitutionSystem[{a_, b_} :> {a + b}], MaxDestroyerEvents -> 5] @ {1, 2, 3} ``` diff --git a/Documentation/Generators/MaxEventInputs.md b/Documentation/Generators/MaxEventInputs.md index b64595f2..faebc8f0 100644 --- a/Documentation/Generators/MaxEventInputs.md +++ b/Documentation/Generators/MaxEventInputs.md @@ -12,7 +12,7 @@ to reduce the number of matches enumerated. Compare: ```wl In[] := First @ AbsoluteTiming @ GenerateMultihistory[ - MultisetSubstitutionSystem[{a___} /; Length[{a}] == 4 :> {Total[{a}]}], {1, 2, 3, 4}, MaxEvents -> 20, #] & /@ + MultisetSubstitutionSystem[{a___} /; Length[{a}] == 4 :> {Total[{a}]}], MaxEvents -> 20, #] @ {1, 2, 3, 4} & /@ {{}, {MinEventInputs -> 4, MaxEventInputs -> 4}} Out[] = {0.793215, 0.014419} ``` diff --git a/Documentation/Generators/MaxEvents.md b/Documentation/Generators/MaxEvents.md index bdfcc8b9..460b76ca 100644 --- a/Documentation/Generators/MaxEvents.md +++ b/Documentation/Generators/MaxEvents.md @@ -6,7 +6,7 @@ ```wl In[] := #["ExpressionsEventsGraph"] & @ SetReplaceTypeConvert[{WolframModelEvolutionObject, 2}] @ - GenerateMultihistory[MultisetSubstitutionSystem[{a_, b_} /; a < b :> {a + b}], {1, 2, 3, 4}, MaxEvents -> 9] + GenerateMultihistory[MultisetSubstitutionSystem[{a_, b_} /; a < b :> {a + b}], MaxEvents -> 9] @ {1, 2, 3, 4} ``` diff --git a/Documentation/Generators/MaxGeneration.md b/Documentation/Generators/MaxGeneration.md index 592b7d84..56e3b76e 100644 --- a/Documentation/Generators/MaxGeneration.md +++ b/Documentation/Generators/MaxGeneration.md @@ -16,8 +16,7 @@ In[] := #["ExpressionsEventsGraph", {"Event", n_} :> #["EventGenerations"][[n]]}]]] & @ SetReplaceTypeConvert[{WolframModelEvolutionObject, 2}] @ GenerateMultihistory[MultisetSubstitutionSystem[{a__} /; Total[{a}] == 5 :> {Total[{a}] - 1, Total[{a}] + 1}], - {1, 2, 3}, - MaxEvents -> 3] + MaxEvents -> 3] @ {1, 2, 3} ``` @@ -28,8 +27,7 @@ another event is created instead: ```wl In[] := #["ExpressionsEventsGraph"] & @ SetReplaceTypeConvert[{WolframModelEvolutionObject, 2}] @ GenerateMultihistory[MultisetSubstitutionSystem[{a__} /; Total[{a}] == 5 :> {Total[{a}] - 1, Total[{a}] + 1}], - {1, 2, 3}, - MaxGeneration -> 1, MaxEvents -> 3] + MaxGeneration -> 1, MaxEvents -> 3] @ {1, 2, 3} ``` @@ -44,7 +42,6 @@ termination reason. ```wl In[] := #[[2, "TerminationReason"]] & @ GenerateMultihistory[MultisetSubstitutionSystem[{a__} /; Total[{a}] == 5 :> {Total[{a}] - 1, Total[{a}] + 1}], - {1, 2, 3}, - MaxGeneration -> 1] + MaxGeneration -> 1] @ {1, 2, 3} Out[] = "Complete" ``` diff --git a/Documentation/Generators/MinEventInputs.md b/Documentation/Generators/MinEventInputs.md index 4ddfd0e6..b8a52d24 100644 --- a/Documentation/Generators/MinEventInputs.md +++ b/Documentation/Generators/MinEventInputs.md @@ -9,7 +9,7 @@ Compare, for example, `MinEventInputs -> 0` (default): In[] := #["ExpressionsEventsGraph", VertexLabels -> Placed[Automatic, After]] & @ SetReplaceTypeConvert[{WolframModelEvolutionObject, 2}] @ GenerateMultihistory[ - MultisetSubstitutionSystem[{a___} :> {Total[{a}]}], {1, 2, 3}, MinEventInputs -> 0, MaxEvents -> 10] + MultisetSubstitutionSystem[{a___} :> {Total[{a}]}], MinEventInputs -> 0, MaxEvents -> 10] @ {1, 2, 3} ``` @@ -20,7 +20,7 @@ and `MinEventInputs -> 2`: In[] := #["ExpressionsEventsGraph", VertexLabels -> Placed[Automatic, After]] & @ SetReplaceTypeConvert[{WolframModelEvolutionObject, 2}] @ GenerateMultihistory[ - MultisetSubstitutionSystem[{a___} :> {Total[{a}]}], {1, 2, 3}, MinEventInputs -> 2, MaxEvents -> 10] + MultisetSubstitutionSystem[{a___} :> {Total[{a}]}], MinEventInputs -> 2, MaxEvents -> 10] @ {1, 2, 3} ``` diff --git a/Documentation/Generators/README.md b/Documentation/Generators/README.md index 740a1a56..4a465932 100644 --- a/Documentation/Generators/README.md +++ b/Documentation/Generators/README.md @@ -23,7 +23,7 @@ For example, [`GenerateSingleHistory`](GenerateSingleHistory.md) corresponds to ```wl In[] := #["ExpressionsEventsGraph", VertexLabels -> Placed[Automatic, After]] & @ SetReplaceTypeConvert[{WolframModelEvolutionObject, 2}] @ - GenerateSingleHistory[MultisetSubstitutionSystem[{a_, b_} /; a < b :> {a + b}], {1, 2, 3, 4}] + GenerateSingleHistory[MultisetSubstitutionSystem[{a_, b_} /; a < b :> {a + b}]] @ {1, 2, 3, 4} ``` @@ -35,7 +35,7 @@ We can also use a more general [`GenerateMultihistory`](GenerateMultihistory.md) In[] := #["ExpressionsEventsGraph", VertexLabels -> Placed[Automatic, After]] & @ SetReplaceTypeConvert[{WolframModelEvolutionObject, 2}] @ GenerateMultihistory[ - MultisetSubstitutionSystem[{a_, b_} /; a < b :> {a + b}], {1, 2, 3, 4}, MaxDestroyerEvents -> 2] + MultisetSubstitutionSystem[{a_, b_} /; a < b :> {a + b}], MaxDestroyerEvents -> 2] @ {1, 2, 3, 4} ``` @@ -46,19 +46,10 @@ The same generators support multiple systems. In addition to All generators take the form -```wl -Generator[System[rules], init, parameters...] -``` - -or, in operator form, - ```wl Generator[System[rules], parameters...] @ init ``` -Note, however, that the first form takes precedence, and if parameters can be interpreted as an init, the second form -may not evaluate as expected. - `parameters` can be specified either as a [`Sequence`](https://reference.wolfram.com/language/ref/Sequence.html) of [`Rule`](https://reference.wolfram.com/language/ref/Rule.html)s, a [`List`](https://reference.wolfram.com/language/ref/List.html) of diff --git a/Documentation/Systems/AtomicStateSystem.md b/Documentation/Systems/AtomicStateSystem.md index 79baae5f..8b4481be 100644 --- a/Documentation/Systems/AtomicStateSystem.md +++ b/Documentation/Systems/AtomicStateSystem.md @@ -6,7 +6,7 @@ left that can match these states, and the arbitrary code on the right that creat ```wl In[] := #["ExpressionsEventsGraph", VertexLabels -> Placed[Automatic, After]] & @ SetReplaceTypeConvert[{WolframModelEvolutionObject, 2}] @ - GenerateMultihistory[AtomicStateSystem[{n_ :> n + 1, n_ :> n - 1}], 0, MaxGeneration -> 4] + GenerateMultihistory[AtomicStateSystem[{n_ :> n + 1, n_ :> n - 1}], MaxGeneration -> 4][0] ``` diff --git a/Documentation/Systems/MultisetSubstitutionSystem.md b/Documentation/Systems/MultisetSubstitutionSystem.md index f8febdb9..21930a2b 100644 --- a/Documentation/Systems/MultisetSubstitutionSystem.md +++ b/Documentation/Systems/MultisetSubstitutionSystem.md @@ -19,7 +19,7 @@ For example, to make a system that adds pairs of numbers: ```wl In[] := #["ExpressionsEventsGraph", VertexLabels -> Placed[Automatic, After]] & @ SetReplaceTypeConvert[{WolframModelEvolutionObject, 2}] @ - GenerateSingleHistory[MultisetSubstitutionSystem[{a_, b_} /; a < b :> {a + b}], {1, 2, 3, 4}] + GenerateSingleHistory[MultisetSubstitutionSystem[{a_, b_} /; a < b :> {a + b}]] @ {1, 2, 3, 4} ``` @@ -35,8 +35,7 @@ In[] := #["ExpressionsEventsGraph", VertexLabels -> Placed[Automatic, After]] & SetReplaceTypeConvert[{WolframModelEvolutionObject, 2}] @ GenerateMultihistory[ MultisetSubstitutionSystem[{a__} /; OrderedQ[{a}] && PrimeQ[Plus[a]] :> First /@ FactorInteger[Plus[a]]], - {1, 2, 3, 4}, - MinEventInputs -> 2, MaxEventInputs -> 4] + MinEventInputs -> 2, MaxEventInputs -> 4] @ {1, 2, 3, 4} ``` diff --git a/Documentation/Types/Multihistory/AtomicStateSystem0.md b/Documentation/Types/Multihistory/AtomicStateSystem0.md index 54991bf3..9266086b 100644 --- a/Documentation/Types/Multihistory/AtomicStateSystem0.md +++ b/Documentation/Types/Multihistory/AtomicStateSystem0.md @@ -5,7 +5,7 @@ [`AtomicStateSystem`](/Documentation/Systems/AtomicStateSystem.md): ```wl -In[] := GenerateMultihistory[AtomicStateSystem[a_ :> a + 1], 0, MaxEvents -> 10] +In[] := GenerateMultihistory[AtomicStateSystem[a_ :> a + 1], MaxEvents -> 10][0] ``` diff --git a/Documentation/Types/Multihistory/MultisetSubstitutionSystem0.md b/Documentation/Types/Multihistory/MultisetSubstitutionSystem0.md index 99c96253..97761db3 100644 --- a/Documentation/Types/Multihistory/MultisetSubstitutionSystem0.md +++ b/Documentation/Types/Multihistory/MultisetSubstitutionSystem0.md @@ -5,7 +5,7 @@ [`MultisetSubstitutionSystem`](/Documentation/Systems/MultisetSubstitutionSystem.md): ```wl -In[] := GenerateMultihistory[MultisetSubstitutionSystem[{a_, b_} :> {a + b}], {1, 2, 3}, MaxEvents -> 10] +In[] := GenerateMultihistory[MultisetSubstitutionSystem[{a_, b_} :> {a + b}], MaxEvents -> 10] @ {1, 2, 3} ``` diff --git a/Documentation/Types/Multihistory/README.md b/Documentation/Types/Multihistory/README.md index 0ac343d7..4cb5b7e4 100644 --- a/Documentation/Types/Multihistory/README.md +++ b/Documentation/Types/Multihistory/README.md @@ -6,7 +6,7 @@ For example, for a [`MultisetSubstitutionSystem`](/Documentation/Systems/MultisetSubstitutionSystem.md), ```wl -In[] := GenerateMultihistory[MultisetSubstitutionSystem[{a_, b_} :> {a + b}], {1, 2, 3}, MaxEvents -> 10] +In[] := GenerateMultihistory[MultisetSubstitutionSystem[{a_, b_} :> {a + b}], MaxEvents -> 10] @ {1, 2, 3} ``` diff --git a/Kernel/A1$generatorSystem.m b/Kernel/A1$generatorSystem.m index 7c87167e..4c5a9557 100644 --- a/Kernel/A1$generatorSystem.m +++ b/Kernel/A1$generatorSystem.m @@ -111,17 +111,17 @@ It cannot be used in operator form. *) $systemUsage = "* A list of all supported systems can be obtained with $SetReplaceSystems."; -$initUsage = "* init$ is the initial state, the format of which depends on the system$."; $parametersUsage = "* parameters$ is either a Sequence, a List or an Association of key-value rules. A list of " <> "parameter keys can be obtained with SetReplaceSystemParameters[system$]."; +$initUsage = "* init$ is the initial state, the format of which depends on the system$."; declareSystemGenerator[publicSymbol_, packageScopeSymbol_, parameterValues_, property_, usage_] := ( $generatorPackageScopeSymbols[publicSymbol] = packageScopeSymbol; $generatorParameters[publicSymbol] = parameterValues; $generatorProperties[publicSymbol] = property; - SyntaxInformation[publicSymbol] = {"ArgumentsPattern" -> {system_, init_., parameters___}}; + SyntaxInformation[publicSymbol] = {"ArgumentsPattern" -> {system_, parameters___}}; SetUsage @ Evaluate @ StringRiffle[ - {ToString[publicSymbol] <> "[system$, init$, parameters$] " <> usage, $systemUsage, $initUsage, $parametersUsage}, + {ToString[publicSymbol] <> "[system$, parameters$][init$] " <> usage, $systemUsage, $parametersUsage, $initUsage}, "\n"]; ); @@ -168,25 +168,15 @@ declareMessage[General::noRules, "Rules need to be specified as `system`[\[Ellipsis]] in `expr`."]; defineGeneratorImplementation[generator_] := With[{packageScopeGenerator = $generatorPackageScopeSymbols[generator]}, - expr : generator[system_, init_, parameters___] /; - MatchQ[init, Lookup[$systemInitPatterns, Head[system], _]] := ModuleScope[ - result = Catch[packageScopeGenerator[system, init, parameters], + expr : (operator : generator[args1___])[args2___] /; + CheckArguments[operator, {1, Infinity}] && CheckArguments[expr, {1, 1}] := ModuleScope[ + result = Catch[packageScopeGenerator[args1][args2], _ ? FailureQ, message[generator, #, <|"expr" -> HoldForm[expr]|>] &]; result /; !FailureQ[result] ]; - expr : generator[args1___][args2___] /; CheckArguments[expr, {1, 1}] := ModuleScope[ - result = Catch[implementationOperator[generator][args1][args2], - _ ? FailureQ, - message[generator, #, <|"expr" -> HoldForm[expr]|>] &]; - result /; !FailureQ[result] - ]; - - expr : generator[] /; CheckArguments[expr, {1, Infinity}] := $Failed; - - packageScopeGenerator[system_, init_, parameters___] /; - MatchQ[init, Lookup[$systemInitPatterns, Head[system], _]] := ( + packageScopeGenerator[system_, parameters___][init_] := ( If[MissingQ[$systemImplementations[Head[system]]], If[MissingQ[$systemImplementations[system]], throw[Failure["unknownSystem", <|"system" -> system|>]] @@ -194,19 +184,13 @@ throw[Failure["noRules", <|"system" -> system|>]] ]; ]; + If[!MatchQ[init, Lookup[$systemInitPatterns, Head[system]]], + throw[Failure["argNotInit", <|"arg" -> arg, "pattern" -> $systemInitPatterns[Head[system]]|>]] + ]; checkSystemGeneratorCompatibility[Head[system], generator]; $generatorProperties[generator] @ $systemImplementations[Head[system]][system, init, parseParameters[generator, Head[system]][parameters]] ); - packageScopeGenerator[___] := throw[Failure[None, <||>]]; - - implementationOperator[generator][system_][init_] /; MatchQ[init, $systemInitPatterns[Head[system]]] := - packageScopeGenerator[system, init, <||>]; - implementationOperator[generator][system_, parameters_, moreParameters___][init_] /; - MatchQ[init, $systemInitPatterns[Head[system]]] && !MatchQ[parameters, $systemInitPatterns[Head[system]]] := - packageScopeGenerator[system, init, parameters, moreParameters]; - implementationOperator[generator][system_, ___][arg_] := - throw[Failure["argNotInit", <|"arg" -> arg, "pattern" -> $systemInitPatterns[Head[system]]|>]]; ]; declareMessage[ diff --git a/Kernel/AtomicStateSystem.m b/Kernel/AtomicStateSystem.m index 33bff92b..07e4dfc9 100644 --- a/Kernel/AtomicStateSystem.m +++ b/Kernel/AtomicStateSystem.m @@ -17,8 +17,7 @@ generateAtomicStateSystem[AtomicStateSystem[rules___], init_, parameters_] := ModuleScope[ toAtomicStateMultihistory[rules] @ generateMultihistory[ MultisetSubstitutionSystem[toMultisetRules[rules]], - {init}, - Join[parameters, <|MinEventInputs -> 1, MaxEventInputs -> 1|>]] + Join[parameters, <|MinEventInputs -> 1, MaxEventInputs -> 1|>]] @ {init} ]; (* Parsing *) diff --git a/Tests/AtomicStateSystem.wlt b/Tests/AtomicStateSystem.wlt index 7f77e094..2121cda5 100644 --- a/Tests/AtomicStateSystem.wlt +++ b/Tests/AtomicStateSystem.wlt @@ -10,20 +10,20 @@ ), "tests" -> { (* Symbol Leak *) - testSymbolLeak[GenerateMultihistory[AtomicStateSystem[a_ :> a + 1], 0, MaxEvents -> 5]], + testSymbolLeak[GenerateMultihistory[AtomicStateSystem[a_ :> a + 1], MaxEvents -> 5][0]], (* Rules *) - testUnevaluated[GenerateMultihistory[AtomicStateSystem[##2], 1], {#}] & @@@ { + testUnevaluated[GenerateMultihistory[AtomicStateSystem[##2]][1], {#}] & @@@ { {AtomicStateSystem::argx}, {AtomicStateSystem::argx, 1, 2}, {GenerateMultihistory::invalidAtomicStateRules, 1}}, (* Parameters *) - testUnevaluated[GenerateMultihistory[AtomicStateSystem[1 -> 2], 1, MaxGeneration -> -1], + testUnevaluated[GenerateMultihistory[AtomicStateSystem[1 -> 2], MaxGeneration -> -1][1], {GenerateMultihistory::invalidParameter}], Function[{rules, parameters, init, expectedCreatedExpressions}, - VerificationTest[allExpressions @ GenerateMultihistory[AtomicStateSystem[rules], init, parameters], + VerificationTest[allExpressions @ GenerateMultihistory[AtomicStateSystem[rules], parameters] @ init, Join[{init}, expectedCreatedExpressions], SameTest -> MatchQ]] @@@ { {1 -> 1, MaxEvents -> 1, 1, {1}}, @@ -38,7 +38,7 @@ (* only valid patterns should be matched *) {x_String :> x <> "x", MaxEvents -> 2, 0, {}}}, - VerificationTest[allExpressions @ GenerateMultihistory[AtomicStateSystem[{1 -> 3, 2 -> 3, 0 -> 1, 0 -> 2}], 0], + VerificationTest[allExpressions @ GenerateMultihistory[AtomicStateSystem[{1 -> 3, 2 -> 3, 0 -> 1, 0 -> 2}]][0], {0, 1, 2, 3, 3}] } |> diff --git a/Tests/MultisetSubstitutionSystem.wlt b/Tests/MultisetSubstitutionSystem.wlt index 04ae3b24..10f57300 100644 --- a/Tests/MultisetSubstitutionSystem.wlt +++ b/Tests/MultisetSubstitutionSystem.wlt @@ -7,20 +7,21 @@ ), "tests" -> { (* Symbol Leak *) - testSymbolLeak[GenerateMultihistory[MultisetSubstitutionSystem[{a_, b_} :> {a + b}], {1, 2, 3}]], + testSymbolLeak[GenerateMultihistory[MultisetSubstitutionSystem[{a_, b_} :> {a + b}]] @ {1, 2, 3}], (* Rules *) - testUnevaluated[GenerateMultihistory[MultisetSubstitutionSystem[##2], {1}], {#}] & @@@ { + testUnevaluated[GenerateMultihistory[MultisetSubstitutionSystem[##2]][{1}], {#}] & @@@ { {MultisetSubstitutionSystem::argx}, {MultisetSubstitutionSystem::argx, 1, 2}, {GenerateMultihistory::invalidMultisetRules, 1}, {GenerateMultihistory::ruleOutputNotList, {1} -> 2}}, (* Init *) - testUnevaluated[GenerateMultihistory[MultisetSubstitutionSystem[{1} -> {2}], 1], {}], + testUnevaluated[ + GenerateMultihistory[MultisetSubstitutionSystem[{1} -> {2}]][1], {GenerateMultihistory::argNotInit}], (* Parameters *) - testUnevaluated[GenerateMultihistory[MultisetSubstitutionSystem[{1} -> {2}], {1}, # -> -1], + testUnevaluated[GenerateMultihistory[MultisetSubstitutionSystem[{1} -> {2}], # -> -1] @ {1}, {GenerateMultihistory::invalidParameter}] & /@ {MaxGeneration, MaxDestroyerEvents, MinEventInputs, MaxEventInputs, MaxEvents} } @@ -38,7 +39,7 @@ ), "tests" -> { Function[{rules, parameters, init, expectedCreatedExpressions}, - VerificationTest[allExpressions @ GenerateMultihistory[MultisetSubstitutionSystem[rules], init, parameters], + VerificationTest[allExpressions @ GenerateMultihistory[MultisetSubstitutionSystem[rules], parameters] @ init, Join[init, expectedCreatedExpressions], SameTest -> MatchQ]] @@@ {{{1} -> {1}, MaxEvents -> 1, {1}, {1}}, @@ -168,12 +169,12 @@ {Verbatim[{_, __}] :> {0}, MaxGeneration -> 1, {_, __, 1}, {0}}}, VerificationTest[ - eventCount @ GenerateMultihistory[MultisetSubstitutionSystem[{{1}} :> {}], {{1}}, MaxGeneration -> 1], 1], + eventCount @ GenerateMultihistory[MultisetSubstitutionSystem[{{1}} :> {}], MaxGeneration -> 1] @ {{1}}, 1], Function[{rules, parameters, init, expectedMaxGeneration, expectedEventCount}, VerificationTest[ - Through[{lastEventGeneration, eventCount} @ GenerateMultihistory[ - MultisetSubstitutionSystem[rules], init, parameters]], + Through[{lastEventGeneration, eventCount} @ + GenerateMultihistory[MultisetSubstitutionSystem[rules], parameters] @ init], {expectedMaxGeneration, expectedEventCount}]] @@@ {{{{a_, b_}} :> Module[{c}, {{a, c}, {c, b}}], MaxGeneration -> 7, {{1, 2}}, 7, 2^7 - 1}, {{{_}} :> {}, {}, {{1}, {2}, {3}, {4}, {5}}, 1, 5}, @@ -182,7 +183,7 @@ (* Test invalid patterns *) testUnevaluated[ - eventCount @ GenerateMultihistory[MultisetSubstitutionSystem[#], {{1}}, MaxGeneration -> 1], + eventCount @ GenerateMultihistory[MultisetSubstitutionSystem[#], MaxGeneration -> 1] @ {{1}}, {Pattern::patvar, GenerateMultihistory::ruleInstantiationMessage}] & /@ {{{{Pattern[1, _], v2_}} :> {}, {{Pattern[2, _], v1_}} :> Module[{v2}, {v2}]}, {{{Pattern[Pattern[a, _], _], v2_}} :> {}, {{Pattern[2, _], v1_}} :> Module[{v2}, {v2}]}} @@ -199,7 +200,7 @@ ), "tests" -> { Function[{rule, parameters, init, expectedCreatedExpressions}, - VerificationTest[allExpressions @ GenerateMultihistory[MultisetSubstitutionSystem[rule], init, parameters], + VerificationTest[allExpressions @ GenerateMultihistory[MultisetSubstitutionSystem[rule], parameters] @ init, Join[init, expectedCreatedExpressions]] ] @@@ { (* multihistory branching *) @@ -257,8 +258,7 @@ MultisetSubstitutionSystem[ {{v1_, v2_}, {v2_, v3_, v4_}} :> Module[{v5 = Hash[{{v1, v2}, {v2, v3, v4}}]}, {{v2, v3}, {v3, v4, v5}, {v1, v2, v3, v4}}]], - {{1, 2}, {2, 3, 4}}, - MaxEvents -> 30, MaxDestroyerEvents -> #] & /@ {1, Infinity}}, + MaxEvents -> 30, MaxDestroyerEvents -> #] @ {{1, 2}, {2, 3, 4}} & /@ {1, Infinity}}, SameQ @@ serializeMultihistory /@ multihistories] ] } @@ -275,7 +275,7 @@ ), "tests" -> { Function[{rule, init, lastEventInputsOutput}, - VerificationTest[lastEventInputs @ GenerateMultihistory[MultisetSubstitutionSystem[rule], init, MaxEvents -> 1], + VerificationTest[lastEventInputs @ GenerateMultihistory[MultisetSubstitutionSystem[rule], MaxEvents -> 1][init], lastEventInputsOutput] ] @@@ { {{{2, 3, 4} -> {X}, {3} -> {X}}, {1, 2, 3, 4, 5}, {3}}, @@ -318,7 +318,7 @@ rule, parameters, init, expectedMaxEventGeneration, expectedEventCount, expectedTerminationReason}, VerificationTest[ Through[{maxEventGeneration, eventCount, terminationReason} @ - GenerateMultihistory[MultisetSubstitutionSystem[rule], init, parameters]], + GenerateMultihistory[MultisetSubstitutionSystem[rule], parameters] @ init], {expectedMaxEventGeneration, expectedEventCount, expectedTerminationReason}] ] @@@ { (* Complete is returned if MaxGeneration is reached because MaxGeneration is not a stopping condition *) @@ -346,8 +346,7 @@ VerificationTest[ allExpressions @ GenerateMultihistory[ MultisetSubstitutionSystem[{n___} /; Plus[n] == 5 && OrderedQ[{n}] :> {{n}}], - init, - MinEventInputs -> #1, MaxEventInputs -> #2, MaxGeneration -> 1], + MinEventInputs -> #1, MaxEventInputs -> #2, MaxGeneration -> 1] @ init, Join[init, #3], SameTest -> MatchQ] ] & @@@ @@ -356,8 +355,7 @@ VerificationTest[ destroyerEventCounts @ GenerateMultihistory[ MultisetSubstitutionSystem[ToPatternRules[{{1, 2}, {2, 3}} -> {{2, 3}, {2, 4}, {3, 4}, {2, 1}}]], - {{1, 1}, {1, 1}}, - MaxDestroyerEvents -> #, MaxEvents -> 5], + MaxDestroyerEvents -> #, MaxEvents -> 5] @ {{1, 1}, {1, 1}}, #2, SameTest -> MatchQ] & @@@ {{2, {2, 2, 2, 2, 1, 1, 0..}}, {3, {2, 2, 3, 1, 1, 1, 0..}}} diff --git a/Tests/MultisetToWolframModelEvolutionObject.wlt b/Tests/MultisetToWolframModelEvolutionObject.wlt index e82ca62f..0ce416fe 100644 --- a/Tests/MultisetToWolframModelEvolutionObject.wlt +++ b/Tests/MultisetToWolframModelEvolutionObject.wlt @@ -9,13 +9,13 @@ VerificationTest[ (VertexCount @ #["ExpressionsEventsGraph"] &) @ SetReplaceTypeConvert[{WolframModelEvolutionObject, 2}] @ - GenerateMultihistory[MultisetSubstitutionSystem[{a_, b_} :> {a + b}], {1, 2, 3}, MaxGeneration -> 1], + GenerateMultihistory[MultisetSubstitutionSystem[{a_, b_} :> {a + b}], MaxGeneration -> 1] @ {1, 2, 3}, 15], VerificationTest[ (#["EventsCount"] &) @ SetReplaceTypeConvert[{WolframModelEvolutionObject, 2}] @ - GenerateMultihistory[MultisetSubstitutionSystem[{a_, b_} :> {a + b}], {1, 2, 3}, MaxEvents -> 10], + GenerateMultihistory[MultisetSubstitutionSystem[{a_, b_} :> {a + b}], MaxEvents -> 10] @ {1, 2, 3}, 10] } |> diff --git a/Tests/generatorSystem.wlt b/Tests/generatorSystem.wlt index 33832c30..b3ab4f97 100644 --- a/Tests/generatorSystem.wlt +++ b/Tests/generatorSystem.wlt @@ -49,112 +49,87 @@ SameTest -> MatchQ], (* Zero args *) - testUnevaluated[genericGenerator[], {genericGenerator::argm}], + testUnevaluated[genericGenerator[], {}], (* nothing is evaluated until the init is given *) (* One arg *) testUnevaluated[genericGenerator[0], {}], testUnevaluated[genericGenerator[genericSystem[]], {}], (* Two args *) - testUnevaluated[genericGenerator[0, 0], {genericGenerator::unknownSystem}], - testUnevaluated[genericGenerator[genericSystem, 0], {genericGenerator::noRules}], - testUnevaluated[genericGenerator[genericSystem[], "test"], {}], (* parameters are not yet parsed at this stage *) + testUnevaluated[genericGenerator[0, 0][0], {genericGenerator::unknownSystem}], + testUnevaluated[genericGenerator[genericSystem, 0][0], {genericGenerator::noRules}], + testUnevaluated[genericGenerator[genericSystem[], "test"][0], {genericGenerator::invalidGeneratorParameterSpec}], VerificationTest[ - genericGenerator[genericSystem[], 0], {genericSystem[], 0, <|maxEventSize -> Infinity, eventType -> None|>}], + genericGenerator[genericSystem[]][0], {genericSystem[], 0, <|maxEventSize -> Infinity, eventType -> None|>}], + + (* Operator args *) + testUnevaluated[genericGenerator[genericSystem[]][##], {genericGenerator::argx}] & @@@ {{0, 1}, {}}, (* Parameters spec *) - testUnevaluated[genericGenerator[genericSystem[], 0, abc], {genericGenerator::invalidGeneratorParameterSpec}], - testUnevaluated[genericGenerator[genericSystem[], 0, {abc}], {genericGenerator::invalidGeneratorParameterSpec}], - testUnevaluated[genericGenerator[genericSystem[], 0, abc -> 4], {genericGenerator::unknownParameter}], - testUnevaluated[genericGenerator[genericSystem[], maxEventSize -> 4], {}], (* no init, treated as operator form *) - VerificationTest[genericGenerator[genericSystem[], 0, maxEventSize -> 4], + testUnevaluated[genericGenerator[genericSystem[], abc][0], {genericGenerator::invalidGeneratorParameterSpec}], + testUnevaluated[genericGenerator[genericSystem[], {abc}][0], {genericGenerator::invalidGeneratorParameterSpec}], + testUnevaluated[genericGenerator[genericSystem[], abc -> 4][0], {genericGenerator::unknownParameter}], + testUnevaluated[genericGenerator[genericSystem[], maxEventSize -> 4], {}], + VerificationTest[genericGenerator[genericSystem[], maxEventSize -> 4][0], {genericSystem[], 0, <|maxEventSize -> 4, eventType -> None|>}], - testUnevaluated[genericGenerator[genericSystem[], 0, maxEventSize -> -1], {genericGenerator::invalidParameter}], - testUnevaluated[genericGenerator[genericSystem[], 0, minEventSize -> 4], {genericGenerator::unknownParameter}], + testUnevaluated[genericGenerator[genericSystem[], maxEventSize -> -1][0], {genericGenerator::invalidParameter}], + testUnevaluated[genericGenerator[genericSystem[], minEventSize -> 4][0], {genericGenerator::unknownParameter}], VerificationTest[ - genericGenerator[genericSystem[], 0, ##], {genericSystem[], 0, <|maxEventSize -> 4, eventType -> 0|>}] & @@@ { + genericGenerator[genericSystem[], ##][0], {genericSystem[], 0, <|maxEventSize -> 4, eventType -> 0|>}] & @@@ { {maxEventSize -> 4, eventType -> 0}, {{maxEventSize -> 4}, eventType -> 0}, {maxEventSize -> 4, {eventType -> 0}}, {<|maxEventSize -> 4|>, {{eventType -> 0}}} }, - VerificationTest[genericGenerator[genericSystem[], 0, eventType -> 0, eventType -> 1], + VerificationTest[genericGenerator[genericSystem[], eventType -> 0, eventType -> 1][0], {genericSystem[], 0, <|maxEventSize -> Infinity, eventType -> 1|>}], - testUnevaluated[genericGenerator[genericSystem[], 0, eventType -> 0, eventType -> 1, 3], + testUnevaluated[genericGenerator[genericSystem[], eventType -> 0, eventType -> 1, 3][0], {genericGenerator::invalidGeneratorParameterSpec}], (* Generator with predefined parameters *) - VerificationTest[typeTwoGenerator[genericSystem[], 0], + VerificationTest[typeTwoGenerator[genericSystem[]][0], property[{genericSystem[], 0, <|maxEventSize -> Infinity, eventType -> 2|>}]], - testUnevaluated[typeTwoGenerator[genericSystem[], 0, eventType -> 1], {typeTwoGenerator::forbiddenParameter}], - VerificationTest[typeTwoGenerator[genericSystem[], 0, maxEventSize -> 2], + testUnevaluated[typeTwoGenerator[genericSystem[], eventType -> 1][0], {typeTwoGenerator::forbiddenParameter}], + VerificationTest[typeTwoGenerator[genericSystem[], maxEventSize -> 2][0], property[{genericSystem[], 0, <|maxEventSize -> 2, eventType -> 2|>}]], (* Parameter dependencies *) VerificationTest[ - genericGenerator[systemWithParameterDependencies[], 0], + genericGenerator[systemWithParameterDependencies[]][0], {systemWithParameterDependencies[], 0, <|minEventSize -> 0, maxEventSize -> Infinity, eventType -> None|>}], testUnevaluated[ - genericGenerator[systemWithParameterDependencies[], 0, eventType -> 2], {genericGenerator::missingParameters}], + genericGenerator[systemWithParameterDependencies[], eventType -> 2][0], {genericGenerator::missingParameters}], VerificationTest[ - genericGenerator[systemWithParameterDependencies[], 0, eventType -> 2, minEventSize -> 2], + genericGenerator[systemWithParameterDependencies[], eventType -> 2, minEventSize -> 2][0], {systemWithParameterDependencies[], 0, <|minEventSize -> 2, maxEventSize -> Infinity, eventType -> 2|>}], VerificationTest[ - genericGenerator[systemWithParameterDependencies[], 0, eventType -> 2, maxEventSize -> 2], + genericGenerator[systemWithParameterDependencies[], eventType -> 2, maxEventSize -> 2][0], {systemWithParameterDependencies[], 0, <|minEventSize -> 0, maxEventSize -> 2, eventType -> 2|>}], - testUnevaluated[typeTwoGenerator[systemWithParameterDependencies[], 0], {typeTwoGenerator::missingParameters}], + testUnevaluated[typeTwoGenerator[systemWithParameterDependencies[]][0], {typeTwoGenerator::missingParameters}], VerificationTest[ - typeTwoGenerator[systemWithParameterDependencies[], 0, minEventSize -> 2], + typeTwoGenerator[systemWithParameterDependencies[], minEventSize -> 2][0], property[ {systemWithParameterDependencies[], 0, <|minEventSize -> 2, maxEventSize -> Infinity, eventType -> 2|>}]], - testUnevaluated[typeTwoGenerator[minXorMaxSystem[], 0], {typeTwoGenerator::incompatibleSystem}], - testUnevaluated[typeTwoGenerator[minXorMaxSystem[], 0, eventType -> 2], {typeTwoGenerator::incompatibleSystem}], - testUnevaluated[genericGenerator[minXorMaxSystem[], 0], {genericGenerator::missingParameters}], - VerificationTest[genericGenerator[minXorMaxSystem[], 0, minEventSize -> 2], + testUnevaluated[typeTwoGenerator[minXorMaxSystem[]][0], {typeTwoGenerator::incompatibleSystem}], + testUnevaluated[typeTwoGenerator[minXorMaxSystem[], eventType -> 2][0], {typeTwoGenerator::incompatibleSystem}], + testUnevaluated[genericGenerator[minXorMaxSystem[]][0], {genericGenerator::missingParameters}], + VerificationTest[genericGenerator[minXorMaxSystem[], minEventSize -> 2][0], {minXorMaxSystem[], 0, <|minEventSize -> 2, maxEventSize -> Infinity|>}], - testUnevaluated[genericGenerator[minXorMaxSystem[], 0, minEventSize -> 2, maxEventSize -> 3], + testUnevaluated[genericGenerator[minXorMaxSystem[], minEventSize -> 2, maxEventSize -> 3][0], {genericGenerator::incompatibleParameters}], - (* Operator form *) - testUnevaluated[genericGenerator[genericSystem[]] @ "test", {genericGenerator::argNotInit}], - testUnevaluated[genericGenerator[genericSystem[], maxEventSize -> 2] @ "test", {genericGenerator::argNotInit}], - VerificationTest[ - genericGenerator[genericSystem[]] @ 0, {genericSystem[], 0, <|maxEventSize -> Infinity, eventType -> None|>}], - testUnevaluated[genericGenerator[genericSystem[]][], {genericGenerator::argx}], - testUnevaluated[genericGenerator[genericSystem[]][0, 1], {genericGenerator::argx}], - VerificationTest[genericGenerator[genericSystem[], maxEventSize -> 2] @ 0, - {genericSystem[], 0, <|maxEventSize -> 2, eventType -> None|>}], - VerificationTest[genericGenerator[genericSystem[], {maxEventSize -> 2}] @ 0, - {genericSystem[], 0, <|maxEventSize -> 2, eventType -> None|>}], - VerificationTest[genericGenerator[genericSystem[], <|maxEventSize -> 2|>] @ 0, - {genericSystem[], 0, <|maxEventSize -> 2, eventType -> None|>}], - VerificationTest[genericGenerator[genericSystem[], maxEventSize -> 2, eventType -> 2] @ 0, - {genericSystem[], 0, <|maxEventSize -> 2, eventType -> 2|>}], - VerificationTest[ - genericGenerator[listStateSystem[], {maxEventSize -> 2}] @ 0, - {listStateSystem[], - {maxEventSize -> 2}, - <|minEventSize -> 0, maxEventSize -> Infinity, eventType -> None|>}[0]], - VerificationTest[ - genericGenerator[listStateSystem[], {maxEventSize -> 2}, minEventSize -> 1] @ {0}, - {listStateSystem[], - {maxEventSize -> 2}, - <|minEventSize -> 1, maxEventSize -> Infinity, eventType -> None|>}[{0}]], - VerificationTest[genericGenerator[listStateSystem[], minEventSize -> 1, {maxEventSize -> 2}] @ {0}, - {listStateSystem[], {0}, <|minEventSize -> 1, maxEventSize -> 2, eventType -> None|>}], - (* Existing generators *) VerificationTest[ - GenerateMultihistory[realParameterSystem[], 0], + GenerateMultihistory[realParameterSystem[]][0], {realParameterSystem[], 0, <|MaxDestroyerEvents -> Infinity, MaxEvents -> Infinity, MaxGeneration -> Infinity|>}], VerificationTest[ - GenerateSingleHistory[realParameterSystem[], 0], + GenerateSingleHistory[realParameterSystem[]][0], {realParameterSystem[], 0, <|MaxDestroyerEvents -> 1, MaxEvents -> Infinity, MaxGeneration -> Infinity|>}], (* Introspection *) diff --git a/Tests/hypergraphMatching.wlt b/Tests/hypergraphMatching.wlt index 2a148e01..23c8a6dc 100644 --- a/Tests/hypergraphMatching.wlt +++ b/Tests/hypergraphMatching.wlt @@ -22,7 +22,7 @@ matchingFunction[MultisetSubstitutionSystem] = (#["EventRuleIndices"]["Length"] > 1 &) @ - Last @ GenerateMultihistory[MultisetSubstitutionSystem[ToPatternRules[#HypergraphRule]], #Init] &; + Last @ GenerateMultihistory[MultisetSubstitutionSystem[ToPatternRules[#HypergraphRule]]][#Init] &; graphFromHyperedges[edges_] := Graph[UndirectedEdge @@@ Flatten[Partition[#, 2, 1] & /@ edges, 1]]; @@ -117,7 +117,7 @@ VerificationTest[ Normal @ (#["Expressions"] &) @ Last @ GenerateMultihistory[ - MultisetSubstitutionSystem[ToPatternRules[{{1, 2}, {2, 3}} -> {{1, 3}}]], {{1, 2}, {2, 1}}, MaxEvents -> 1], + MultisetSubstitutionSystem[ToPatternRules[{{1, 2}, {2, 3}} -> {{1, 3}}]], MaxEvents -> 1] @ {{1, 2}, {2, 1}}, {{1, 2}, {2, 1}, {1, 1}} ], diff --git a/performanceTest.wls b/performanceTest.wls index 7aefee45..8fcc6ecd 100755 --- a/performanceTest.wls +++ b/performanceTest.wls @@ -65,9 +65,9 @@ Check[ {{3, 3, 3, 6}, {3, 3, 7, 3}, {3, 5, 5}, {3, 3, 1}, {3, 2, 3}, {3, 3, 3, 3, 3, 3}, {4, 6, 6}, {4, 4, 4, 4, 4, 4}, {8, 7, 7}, {8, 8, 8, 8, 8, 8}, {1, 4, 1}, {1, 1, 1, 1, 1}, {2, 2, 8}, {2, 2}}, 64], - "Multiset addition" -> GenerateMultihistory[MultisetSubstitutionSystem[{a_, b_} :> {a + b}], - {1, 2, 3, 4}, - MaxGeneration -> 2, MinEventInputs -> 2, MaxEventInputs -> 2] + "Multiset addition" -> GenerateMultihistory[ + MultisetSubstitutionSystem[{a_, b_} :> {a + b}], + MaxGeneration -> 2, MinEventInputs -> 2, MaxEventInputs -> 2] @ {1, 2, 3, 4} |>; $defaultMeasurementsCount = 5; From 841f62b2a795998d5b4ec255b61642ee1d0220bb Mon Sep 17 00:00:00 2001 From: Max Piskunov Date: Fri, 16 Jul 2021 12:27:02 -0500 Subject: [PATCH 33/33] Fix performanceTest. --- performanceTest.wls | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/performanceTest.wls b/performanceTest.wls index 8fcc6ecd..3178747e 100755 --- a/performanceTest.wls +++ b/performanceTest.wls @@ -82,7 +82,7 @@ Check[ Exit[1]; ]; - Attributes[meanAroundTiming] = {HoldAll}; + Attributes[meanAroundTiming] = {HoldFirst}; meanAroundTiming[expr_, resultsFunction_] := MeanAround @ Table[First @ AbsoluteTiming[resultsFunction @ expr], $measurementsCount]; @@ -94,7 +94,8 @@ Check[ result = ParallelEvaluate[ Get[FileNameJoin[{$setReplaceRoot, "Kernel", "init.m"}]]; Check[ - meanAroundTiming[#, resultsFunction] & @@@ KeyMap[ReleaseHold, ReleaseHold @ Map[Hold, tests, {3}]] + Function[{test}, meanAroundTiming[test, resultsFunction], HoldFirst] @@@ + KeyMap[ReleaseHold, ReleaseHold @ Map[Hold, tests, {3}]] , $Failed ]