From e78a32c085c78458792409fb77c960e96d956865 Mon Sep 17 00:00:00 2001 From: Daniel Sanchez <40190339+daneelsan@users.noreply.github.com> Date: Mon, 19 Oct 2020 14:09:30 -0500 Subject: [PATCH] Replace all Module's with ModuleScope (#461) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Changes * Closes #460. * Replaces (almost) all `Module`'s with `ModuleScope`'s. * Adds ```PackageImport["GeneralUtilities`"]``` where `ModuleScope` was used. --- This change is [Reviewable](https://reviewable.io/reviews/maxitg/setreplace/461) --- .github/CONTRIBUTING.md | 60 ++++++++++++++++++++++++++-- Kernel/GeneralizedGridGraph.m | 8 ++-- Kernel/HypergraphAutomorphismGroup.m | 12 +++--- Kernel/HypergraphUnifications.m | 5 ++- Kernel/HypergraphUnificationsPlot.m | 10 +++-- Kernel/RulePlot.m | 26 ++++++------ Kernel/SetReplace.m | 4 +- Kernel/SetReplaceAll.m | 4 +- Kernel/SetReplaceFixedPoint.m | 4 +- Kernel/SetReplaceFixedPointList.m | 4 +- Kernel/SetReplaceList.m | 4 +- Kernel/ToPatternRules.m | 8 ++-- Kernel/WolframModel.m | 11 +++-- Kernel/WolframModelEvolutionObject.m | 45 +++++++++------------ Kernel/WolframModelPlot.m | 40 +++++++++---------- Kernel/WolframModelRuleValue.m | 5 ++- Kernel/argumentsChecking.m | 4 +- Kernel/arrow.m | 4 +- Kernel/convexHullPolygon.m | 11 ++--- Kernel/setSubstitutionSystem$cpp.m | 22 ++++------ Kernel/setSubstitutionSystem$wl.m | 39 ++++++++---------- Kernel/setSubstitutionSystem.m | 48 +++++++++++++--------- Kernel/testUtilities.m | 2 + Tests/matching.wlt | 9 ++--- performanceTest.wls | 4 +- scripts/buildInit.wl | 10 ++--- test.wls | 2 + 27 files changed, 237 insertions(+), 168 deletions(-) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 0208b3288..f6ecd85db 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -215,7 +215,8 @@ One way to implement such argument checking is to make special `valid*Q` functio A better approach is to setup the function to catch exceptions, i.e., ```wl -MakeUniverse[args___] := Module[{result = Catch[makeUniverse[args]]}, +MakeUniverse[args___] := ModuleScope[ + result = Catch[makeUniverse[args]]; result /; result =!= $Failed ] ``` @@ -364,6 +365,13 @@ In addition to that, here are some more-or-less established rules: ] ``` + ```wl + If[MatchQ[hypergraph, {__List}], + Sort @ Union @ Catenate @ hypergraph, + Throw @ $Failed + ] + ``` + * However, close the brackets of ordinary functions on the same line as the last argument: ```wl @@ -371,11 +379,57 @@ In addition to that, here are some more-or-less established rules: longArgument1, longArgument2, longArgument3] ``` -* The function arguments should either all go on the same line, or should each be put on a separate line (except for special cases where a large quantity of short arguments is used). +* The function arguments should either all go on the same line, or should each be put on a separate line (except for special cases where a large quantity of short arguments is used): + + ```wl + wolframModelPlot[ + edges_, + edgeType_, + styles_, + hyperedgeRendering_, + vertexCoordinates_, + vertexLabels_, + vertexSize_, + arrowheadLength_, + maxImageSize_, + background_, + graphicsOptions_] := Catch[ + ...] + ``` + * Avoid using [`Flatten`](https://reference.wolfram.com/language/ref/Flatten.html) and [`ReplaceAll`](https://reference.wolfram.com/language/ref/ReplaceAll.html) without explicit level arguments. That is because it is very easy to accidentally assume that the user's input is not a [`List`](https://reference.wolfram.com/language/ref/List.html) (e.g., a vertex name), even though it can be, in which case you would [`Flatten`](https://reference.wolfram.com/language/ref/Flatten.html) too much, and cause a weed. It is preferred to use [`Catenate`](https://reference.wolfram.com/language/ref/Catenate.html) and [`Replace`](https://reference.wolfram.com/language/ref/Replace.html) instead of these functions. * Similar issue could happen with [`Thread`](https://reference.wolfram.com/language/ref/Thread.html), especially when used to thread a single element over multiple. For example, it is easy to assume naively that `Thread[x -> {1, 2, 3}]` would always yield `{x -> 1, x -> 2, x -> 3}`. Except, sometimes it might be called as `With[{x = {4, 5, 6}}, Thread[x -> {1, 2, 3}]]`. -* Use uppercase camel for public symbols, lowercase camel for internal (including PackageScope) symbols. +* Use uppercase camel for public symbols, lowercase camel for internal (including PackageScope) symbols: + + ```wl + PackageExport["WolframModelEvolutionObject"] + + PackageScope["propertyEvaluate"] + ``` + * Start global constants with `$`, whether internal or public, and tags (such as used in [`Throw`](https://reference.wolfram.com/language/ref/Throw.html) or [`Sow`](https://reference.wolfram.com/language/ref/Sow.html), or as generic enum labels) with `$$`. Global pure functions (defined as [`OwnValues`](https://reference.wolfram.com/language/ref/OwnValues.html)) should still be treated as ordinary (e.g., [`DownValues`](https://reference.wolfram.com/language/ref/DownValues.html)) functions and not start with `$`, unless they are public, in which case they should start with `$` and end with the word `Function`. +* Use the macros `ModuleScope` and `Scope` (defined in ``"GeneralUtilities`"``) instead of `Module` and `Block` (respectively) when defining functions of the form `f[x__] := (Module|Block)[...]`. The main benefit of using them is that there is no need to specify a list of local variables (i.e. `{localVar1, localVar2, ...}`) at the begining, as a list of local variables will be automatically generated by looking for expressions of the form `Set` (`=`) or `SetDelayed` (`:=`) anywhere in the body of the function (See `?Scope` and [#460](https://github.com/maxitg/SetReplace/pull/460) for more information). For example: + + ```wl + example[hypergraph1_, hypergraph2_] := ModuleScope[ + {vertexList1, vertexList2} = getVertexList /@ {hypergraph1, hypergraph2}; + If[Length @ hypergraph1 >= Length @ hypergraph2, + size = Length @ hypergraph1, + size = Length @ hypergraph2 + ]; + ] + ``` + is expanded to: + + ```wl + example[hypergraph1_, hypergraph2_] := Module[{vertexList1, vertexList2, size}, + {vertexList1, vertexList2} = getVertexList /@ {hypergraph1, hypergraph2}; + If[Length @ hypergraph1 >= Length @ hypergraph2, + size = Length @ hypergraph1, + size = Length @ hypergraph2 + ]; + ] + ``` #### C++ The code should follow [Google C++ Style](https://google.github.io/styleguide/cppguide.html) guidelines, save for the diff --git a/Kernel/GeneralizedGridGraph.m b/Kernel/GeneralizedGridGraph.m index 0481e7715..79aa57b85 100644 --- a/Kernel/GeneralizedGridGraph.m +++ b/Kernel/GeneralizedGridGraph.m @@ -1,5 +1,7 @@ Package["SetReplace`"] +PackageImport["GeneralUtilities`"] + PackageExport["GeneralizedGridGraph"] (* Documentation *) @@ -31,7 +33,8 @@ (* Implementation *) -GeneralizedGridGraph[args___] := Module[{result = Catch[generalizedGridGraph[args]]}, +GeneralizedGridGraph[args___] := ModuleScope[ + result = Catch[generalizedGridGraph[args]]; result /; result =!= $Failed ] @@ -69,8 +72,7 @@ Throw[$Failed]; ) -generalizedGridGraphExplicit[dimSpecs_, opts___] := Module[{ - edgeStyle, vertexNamingFunction, edges, directionalEdgeStyle}, +generalizedGridGraphExplicit[dimSpecs_, opts___] := ModuleScope[ {edgeStyle, vertexNamingFunction} = OptionValue[GeneralizedGridGraph, {opts}, {EdgeStyle, "VertexNamingFunction"}]; edges = singleDimensionEdges[dimSpecs, #] & /@ Range[Length[dimSpecs]]; directionalEdgeStyle = EdgeStyle -> If[ diff --git a/Kernel/HypergraphAutomorphismGroup.m b/Kernel/HypergraphAutomorphismGroup.m index bb1da51da..2546f2e69 100644 --- a/Kernel/HypergraphAutomorphismGroup.m +++ b/Kernel/HypergraphAutomorphismGroup.m @@ -1,5 +1,7 @@ Package["SetReplace`"] +PackageImport["GeneralUtilities`"] + PackageExport["HypergraphAutomorphismGroup"] (* Documentation *) @@ -14,7 +16,8 @@ (* Implementation *) -HypergraphAutomorphismGroup[args___] := Module[{result = Catch[hypergraphAutomorphismGroup[args]]}, +HypergraphAutomorphismGroup[args___] := ModuleScope[ + result = Catch[hypergraphAutomorphismGroup[args]]; result /; result =!= $Failed ] @@ -28,8 +31,8 @@ removeAuxiliaryElements[GraphAutomorphismGroup[binaryGraph], binaryGraph, e] ] -toStructurePreservingBinaryEdges[hyperedge_] := Module[{ - edgeVertices = Table[edge[Unique[v, {Temporary}]], Length[hyperedge]]}, +toStructurePreservingBinaryEdges[hyperedge_] := ModuleScope[ + edgeVertices = Table[edge[Unique[v, {Temporary}]], Length[hyperedge]]; Join[ EdgeList[PathGraph[edgeVertices, DirectedEdges -> True]], Thread[DirectedEdge[edgeVertices, hyperedge]]] @@ -42,8 +45,7 @@ and deleted), generators affecting both (which will be trimmed), and generators of original vertices only (which will be preserved).*) -removeAuxiliaryElements[group_, graph_, hypergraph_] := Module[{ - trueVertexIndices, binaryGraphIndexToVertex, vertexToHypergraphIndex}, +removeAuxiliaryElements[group_, graph_, hypergraph_] := ModuleScope[ trueVertexIndices = Position[VertexList[graph], Except[_edge], {1}, Heads -> False][[All, 1]]; binaryGraphIndexToVertex = Thread[trueVertexIndices -> VertexList[graph][[trueVertexIndices]]]; vertexToHypergraphIndex = Thread[vertexList[hypergraph] -> Range[Length[binaryGraphIndexToVertex]]]; diff --git a/Kernel/HypergraphUnifications.m b/Kernel/HypergraphUnifications.m index 0b1585b00..d283e1341 100644 --- a/Kernel/HypergraphUnifications.m +++ b/Kernel/HypergraphUnifications.m @@ -1,5 +1,7 @@ Package["SetReplace`"] +PackageImport["GeneralUtilities`"] + PackageExport["HypergraphUnifications"] (* Documentation *) @@ -16,7 +18,8 @@ (* Implementation *) -HypergraphUnifications[args___] := Module[{result = Catch[hypergraphUnifications[args]]}, +HypergraphUnifications[args___] := ModuleScope[ + result = Catch[hypergraphUnifications[args]]; result /; result =!= $Failed ] diff --git a/Kernel/HypergraphUnificationsPlot.m b/Kernel/HypergraphUnificationsPlot.m index fa5af67ec..83642a44c 100644 --- a/Kernel/HypergraphUnificationsPlot.m +++ b/Kernel/HypergraphUnificationsPlot.m @@ -1,5 +1,7 @@ Package["SetReplace`"] +PackageImport["GeneralUtilities`"] + PackageExport["HypergraphUnificationsPlot"] (* Documentation *) @@ -14,7 +16,8 @@ (* Implementation *) -HypergraphUnificationsPlot[args___] := Module[{result = Catch[hypergraphUnificationsPlot[args]]}, +HypergraphUnificationsPlot[args___] := ModuleScope[ + result = Catch[hypergraphUnificationsPlot[args]]; result /; result =!= $Failed ] @@ -26,8 +29,7 @@ HypergraphUnificationsPlot::emptyEdge = "Empty edges are not supported."; -hypergraphUnificationsPlot[e1_, e2_, opts : OptionsPattern[]] := Module[{ - unifications, automaticVertexLabelsList, vertexLabels, edgeStyle}, +hypergraphUnificationsPlot[e1_, e2_, opts : OptionsPattern[]] := ModuleScope[ If[Length[Cases[Join[e1, e2], {}]] > 0, Message[HypergraphUnificationsPlot::emptyEdge]; Throw[$Failed]; @@ -49,7 +51,7 @@ {unifications[[All, 1]], unifications[[All, 2]], unifications[[All, 3]], automaticVertexLabelsList}] ] -unificationVertexLabels[e1_, e2_][unification_, edgeMapping1_, edgeMapping2_] := Module[{labels1, labels2}, +unificationVertexLabels[e1_, e2_][unification_, edgeMapping1_, edgeMapping2_] := ModuleScope[ {labels1, labels2} = Merge[Reverse /@ Union[Catenate[Thread /@ Thread[#1[[Keys[#2]]] -> unification[[Values[#2]]]]]], Identity] & @@@ {{e1, edgeMapping1}, {e2, edgeMapping2}}; diff --git a/Kernel/RulePlot.m b/Kernel/RulePlot.m index 0c38c9bf9..b53d23d9b 100644 --- a/Kernel/RulePlot.m +++ b/Kernel/RulePlot.m @@ -1,5 +1,7 @@ Package["SetReplace`"] +PackageImport["GeneralUtilities`"] + (* Documentation *) $newOptions = { @@ -53,7 +55,8 @@ (* Evaluation *) WolframModel /: func : RulePlot[wm : WolframModel[args___] /; Quiet[Developer`CheckArgumentCount[wm, 1, 1]], opts___] := - Module[{result = rulePlot$parse[{args}, {opts}]}, + ModuleScope[ + result = rulePlot$parse[{args}, {opts}]; If[Head[result] === rulePlot$parse, result = $Failed]; result /; result =!= $Failed @@ -62,7 +65,7 @@ (* Evolution object *) WolframModelEvolutionObject /: RulePlot[evo : WolframModelEvolutionObject[data_ ? evolutionDataQ], opts___] := - Module[{result}, + ModuleScope[ result = rulePlot$parse[{evo["Rules"]}, {opts}]; If[Head[result] === rulePlot$parse, result = $Failed]; @@ -122,7 +125,7 @@ False ] -correctSpacingsQ[opts_] := Module[{spacings, correctQ}, +correctSpacingsQ[opts_] := ModuleScope[ spacings = OptionValue[RulePlot, opts, Spacings]; correctQ = MatchQ[spacings, Automatic | (_ ? NumericQ) | {Repeated[{Repeated[_ ? NumericQ, {2}]}, {2}]}]; If[!correctQ, Message[RulePlot::invalidSpacings, spacings]]; @@ -215,7 +218,7 @@ vertexSize_, arrowheadLength_, background_, - graphicsOpts_] := Module[{explicitSpacings, explicitAspectRatio, singlePlots, shapes, plotRange}, + graphicsOpts_] := ModuleScope[ explicitSpacings = toListSpacings[Replace[spacings, Automatic -> style[$lightTheme][$ruleSidesSpacing]]]; hypergraphPlots = rulePartsPlots[ @@ -243,8 +246,8 @@ aspectRatio[{{xMin_, xMax_}, {yMin_, yMax_}}] := (yMax - yMin) / (xMax - xMin) -aspectRatioFromPlotRanges[plotRanges_] := Module[{ - singleAspectRatios = aspectRatio /@ plotRanges, minMax}, +aspectRatioFromPlotRanges[plotRanges_] := ModuleScope[ + singleAspectRatios = aspectRatio /@ plotRanges; minMax = MinMax[singleAspectRatios]; Switch[minMax, _ ? (Max[#] < 1 &), Max[minMax, style[$lightTheme][$rulePartsAspectRatioMin]], @@ -266,8 +269,7 @@ edgePolygonStyle_, vertexSize_, arrowheadLength_][ - rule_] := Module[{ - vertexCoordinateRules, ruleSidePlots, plotRange}, + rule_] := ModuleScope[ vertexCoordinateRules = Join[ ruleCoordinateRules[edgeType, hyperedgeRendering, externalVertexCoordinateRules, rule], externalVertexCoordinateRules]; @@ -294,7 +296,7 @@ connectedQ[edges_] := ConnectedGraphQ[Graph[UndirectedEdge @@@ Catenate[Partition[#, 2, 1] & /@ edges]]] -layoutReferenceSide[in_, out_] := Module[{inConnectedQ, outConnectedQ}, +layoutReferenceSide[in_, out_] := ModuleScope[ {inConnectedQ, outConnectedQ} = connectedQ /@ {in, out}; If[inConnectedQ && !outConnectedQ, Return[out]]; If[outConnectedQ && !inConnectedQ, Return[in]]; @@ -308,8 +310,7 @@ sharedRuleElements[in_ -> out_] := multisetIntersection @@ (Join[vertexList[#], #] & /@ {in, out}) (* returns {shapes, plotRange} *) -combinedRuleParts[sides_, plotRange_, spacings_, rulePartsAspectRatio_] := Module[{ - xScaleFactor, yScaleFactor, maxRange, xRange, yRange, xDisplacement, frame, separator}, +combinedRuleParts[sides_, plotRange_, spacings_, rulePartsAspectRatio_] := ModuleScope[ xScaleFactor = Min[1, 1 / rulePartsAspectRatio]; yScaleFactor = Min[1, rulePartsAspectRatio]; maxRange = Max[ @@ -351,8 +352,7 @@ separatorPlotRange_, relativeSeparatorWidth_, spacings_, - gridStyle_] := Module[{ - scaledShapes, scaledSeparator, widthWithExtraSeparator, shapesWithExtraSeparator, totalWidth, explicitGridStyle}, + gridStyle_] := ModuleScope[ scaledShapes = MapThread[ Scale[ Translate[#1, -#2[[All, 1]]], diff --git a/Kernel/SetReplace.m b/Kernel/SetReplace.m index d1ed75e62..43ba456fb 100644 --- a/Kernel/SetReplace.m +++ b/Kernel/SetReplace.m @@ -1,5 +1,7 @@ Package["SetReplace`"] +PackageImport["GeneralUtilities`"] + PackageExport["SetReplace"] (* This function behaves similarly to StringReplace. The implementation is done with WolframModel, which is a more @@ -37,7 +39,7 @@ expr : SetReplace[set_, rules_, events : Except[_ ? OptionQ] : 1, o : OptionsPattern[]] /; recognizedOptionsQ[expr, SetReplace, {o}] := - Module[{result}, + ModuleScope[ result = Check[ setSubstitutionSystem[rules, set, <|$maxEvents -> events|>, SetReplace, False, o], $Failed]; diff --git a/Kernel/SetReplaceAll.m b/Kernel/SetReplaceAll.m index d4d52a861..f9a3be7eb 100644 --- a/Kernel/SetReplaceAll.m +++ b/Kernel/SetReplaceAll.m @@ -1,5 +1,7 @@ Package["SetReplace`"] +PackageImport["GeneralUtilities`"] + PackageExport["SetReplaceAll"] (* The idea for SetReplaceAll is to keep performing SetReplace on the graph until no replacement can be done without @@ -29,7 +31,7 @@ expr : SetReplaceAll[ set_, rules_, generations : Except[_ ? OptionQ] : 1, o : OptionsPattern[]] /; recognizedOptionsQ[expr, SetReplaceAll, {o}] := - Module[{result}, + ModuleScope[ result = Check[ setSubstitutionSystem[ rules, set, <|$maxGenerationsLocal -> generations|>, SetReplaceAll, False, o], diff --git a/Kernel/SetReplaceFixedPoint.m b/Kernel/SetReplaceFixedPoint.m index 86052ca62..f1b4dcfee 100644 --- a/Kernel/SetReplaceFixedPoint.m +++ b/Kernel/SetReplaceFixedPoint.m @@ -1,5 +1,7 @@ Package["SetReplace`"] +PackageImport["GeneralUtilities`"] + PackageExport["SetReplaceFixedPoint"] (* Same as SetReplace, but automatically stops replacing when the set no longer changes. *) @@ -25,7 +27,7 @@ "EventOrderingFunction" -> Automatic}; SetReplaceFixedPoint[set_, rules_, o : OptionsPattern[]] /; - recognizedOptionsQ[expr, SetReplaceFixedPoint, {o}] := Module[{result}, + recognizedOptionsQ[expr, SetReplaceFixedPoint, {o}] := ModuleScope[ result = Check[ setSubstitutionSystem[ rules, set, <||>, SetReplaceFixedPoint, False, o], diff --git a/Kernel/SetReplaceFixedPointList.m b/Kernel/SetReplaceFixedPointList.m index 0797025af..0e60c9513 100644 --- a/Kernel/SetReplaceFixedPointList.m +++ b/Kernel/SetReplaceFixedPointList.m @@ -1,5 +1,7 @@ Package["SetReplace`"] +PackageImport["GeneralUtilities`"] + PackageExport["SetReplaceFixedPointList"] (* Same as SetReplaceFixedPoint, but returns all intermediate steps. *) @@ -24,7 +26,7 @@ "EventOrderingFunction" -> Automatic}; SetReplaceFixedPointList[set_, rules_, o : OptionsPattern[]] /; - recognizedOptionsQ[expr, SetReplaceFixedPointList, {o}] := Module[{result}, + recognizedOptionsQ[expr, SetReplaceFixedPointList, {o}] := ModuleScope[ result = Check[ setSubstitutionSystem[ rules, set, <||>, SetReplaceFixedPointList, False, o], diff --git a/Kernel/SetReplaceList.m b/Kernel/SetReplaceList.m index 62ff2bba6..1203a0078 100644 --- a/Kernel/SetReplaceList.m +++ b/Kernel/SetReplaceList.m @@ -1,5 +1,7 @@ Package["SetReplace`"] +PackageImport["GeneralUtilities`"] + PackageExport["SetReplaceList"] (* Same as SetReplace, but returns all intermediate steps in a List. *) @@ -23,7 +25,7 @@ SetReplaceList[set_, rules_, events : Except[_ ? OptionQ] : 1, o : OptionsPattern[]] /; recognizedOptionsQ[expr, SetReplaceList, {o}] := - Module[{result}, + ModuleScope[ result = Check[ setSubstitutionSystem[rules, set, <|$maxEvents -> events|>, SetReplaceList, False, o], $Failed]; diff --git a/Kernel/ToPatternRules.m b/Kernel/ToPatternRules.m index d8661afff..6a40fa9ff 100644 --- a/Kernel/ToPatternRules.m +++ b/Kernel/ToPatternRules.m @@ -1,5 +1,7 @@ Package["SetReplace`"] +PackageImport["GeneralUtilities`"] + PackageExport["ToPatternRules"] (* Anonymous rules make it easier to specify rules, especially when they involve creation of new vertices (objects). @@ -33,9 +35,7 @@ (* We are going to find all non-lists in the rules, map them to symbols, and then replace original rules with these symbols using patterns and modules accordingly. *) -toPatternRules[rule : _Rule, caller_] := Module[ - {leftSymbols, rightSymbols, symbols, newVertexNames, vertexPatterns, - newLeft, leftVertices, rightVertices, rightOnlyVertices}, +toPatternRules[rule : _Rule, caller_] := ModuleScope[ {leftSymbols, rightSymbols} = Union[Cases[#, _ ? AtomQ, {0, 1}], Cases[#, _, {2}]] & /@ List @@ rule; symbols = DeleteDuplicates @ Join[leftSymbols, rightSymbols]; @@ -61,7 +61,7 @@ toPatternRules[rules : {___Rule}, caller_] := toPatternRules[#, caller] & /@ rules -ToPatternRules[rules_] := Module[{result}, +ToPatternRules[rules_] := ModuleScope[ result = Check[toPatternRules[rules, ToPatternRules], $Failed]; result /; result =!= $Failed ] diff --git a/Kernel/WolframModel.m b/Kernel/WolframModel.m index 7a0b7d4b8..08c0993b8 100644 --- a/Kernel/WolframModel.m +++ b/Kernel/WolframModel.m @@ -1,5 +1,7 @@ Package["SetReplace`"] +PackageImport["GeneralUtilities`"] + PackageExport["WolframModel"] PackageExport["$WolframModelProperties"] @@ -92,8 +94,7 @@ renameNodes[evolution_, _, None] := evolution renameNodesExceptExisting[ - evolution_, patternRulesQ_, existing_List] := Module[{ - evolutionAtoms, existingAtoms, atomsToName, newNames}, + evolution_, patternRulesQ_, existing_List] := ModuleScope[ {evolutionAtoms, existingAtoms} = (DeleteDuplicates @ Catenate[If[ListQ[#], #, {#}] & /@ #]) & /@ {evolution[[1]][$atomLists], existing}; atomsToName = DeleteCases[evolutionAtoms, Alternatives @@ existingAtoms]; @@ -138,9 +139,7 @@ stepsSpec : _ ? wolframModelStepsSpecQ : 1, property : _ ? wolframModelPropertyQ : "EvolutionObject", o : OptionsPattern[]] /; recognizedOptionsQ[expr, WolframModel, {o}] := - Module[{ - patternRules, initialSet, steps, terminationReasonOverride, optionsOverride, abortBehavior, overridenOptionValue, - evolution, modifiedEvolution, propertyEvaluateWithOptions, result}, + ModuleScope[ patternRules = fromRulesSpec[rulesSpec]; initialSet = Catch[fromInitSpec[rulesSpec, initSpec]]; {steps, terminationReasonOverride, optionsOverride, abortBehavior} = @@ -202,7 +201,7 @@ WolframModel[ rulesSpec_ ? wolframModelRulesSpecQ, o : OptionsPattern[] /; Quiet[recognizedOptionsQ[None, WolframModel, {o}]]][ - initSpec_ ? wolframModelInitSpecQ] := Module[{result}, + initSpec_ ? wolframModelInitSpecQ] := ModuleScope[ result = Check[WolframModel[rulesSpec, initSpec, 1, "FinalState", o], $Failed]; result /; result =!= $Failed] diff --git a/Kernel/WolframModelEvolutionObject.m b/Kernel/WolframModelEvolutionObject.m index e3fb1b7c6..b8c872bd7 100644 --- a/Kernel/WolframModelEvolutionObject.m +++ b/Kernel/WolframModelEvolutionObject.m @@ -1,5 +1,7 @@ Package["SetReplace`"] +PackageImport["GeneralUtilities`"] + PackageExport["WolframModelEvolutionObject"] (* This is an object that is returned by WolframModel. It allows one to query the set at different generations and @@ -59,8 +61,7 @@ WolframModelEvolutionObject /: MakeBoxes[ evo : WolframModelEvolutionObject[data_ ? evolutionDataQ], - format_] := Module[ - {generationsCount, maxCompleteGeneration, generationsDisplay, eventsCount, terminationReason, rules, initialSet}, + format_] := ModuleScope[ generationsCount = evo["TotalGenerationsCount"]; maxCompleteGeneration = Replace[evo["CompleteGenerationsCount"], _ ? MissingQ -> "?"]; generationsDisplay = If[generationsCount === maxCompleteGeneration, @@ -186,9 +187,7 @@ Throw[$Failed] ) -deleteIncompleteGenerations[WolframModelEvolutionObject[data_]] := Module[{ - maxCompleteGeneration, eventIndicesToKeep, newEventOutputs, expressionIndicesToKeep, - oldToNewExpressionIndices}, +deleteIncompleteGenerations[WolframModelEvolutionObject[data_]] := ModuleScope[ maxCompleteGeneration = data[$maxCompleteGeneration]; eventIndicesToKeep = Position[data[$eventGenerations], _ ? (# <= maxCompleteGeneration &)][[All, 1]]; newEventOutputs = data[$eventOutputs][[eventIndicesToKeep]]; @@ -416,8 +415,7 @@ (* StateEdgeIndicesAfterEvents (not a property yet) *) -stateEdgeIndicesAfterEvents[WolframModelEvolutionObject[data_], caller_, events_] := Module[{ - createdExpressions, destroyedExpressions}, +stateEdgeIndicesAfterEvents[WolframModelEvolutionObject[data_], caller_, events_] := ModuleScope[ createdExpressions = Catenate[data[$eventOutputs][[events + 1]]]; destroyedExpressions = Catenate[data[$eventInputs][[events + 1]]]; If[DuplicateFreeQ[destroyedExpressions], @@ -494,7 +492,7 @@ obj : WolframModelEvolutionObject[data_ ? evolutionDataQ], caller_, "GenerationEdgeIndices", - g_] := Module[{positiveGeneration, eventsUpToGeneration}, + g_] := ModuleScope[ positiveGeneration = toPositiveParameter[ propertyEvaluate[True, None][obj, caller, "TotalGenerationsCount"], g, caller, "Generation"]; eventsUpToGeneration = First /@ Position[_ ? (# <= positiveGeneration &)] @ data[$eventGenerations] - 1; @@ -554,8 +552,7 @@ obj : WolframModelEvolutionObject[_ ? evolutionDataQ], caller_, property : "EventsStatesPlotsList", - o : OptionsPattern[] /; (Complement[{o}, FilterRules[{o}, Options[WolframModelPlot]]] == {})] := Module[{ - events, stateIndices, destroyedOnlyIndices, createdOnlyIndices, destroyedAndCreatedIndices, allEdges}, + o : OptionsPattern[] /; (Complement[{o}, FilterRules[{o}, Options[WolframModelPlot]]] == {})] := ModuleScope[ events = propertyEvaluate[True, boundary][obj, caller, "AllEventsList"][[All, 2]]; stateIndices = FoldList[ Function[{currentState, newEvent}, Module[{alreadyDeletedExpressions}, @@ -664,8 +661,7 @@ (* Event/expression causal relations, used by both expressions-events and causal graphs *) (* Returns {<|event -> {output expression, ...}, ...|>, <|expression -> {destroyer event, ...}|> *) -eventsExpressionsRelations[obj_, caller_, boundary_] := Module[{ - eventIndices, events, eventsToOutputs, expressionDestroyers, expressionsToDestroyers}, +eventsExpressionsRelations[obj_, caller_, boundary_] := ModuleScope[ eventIndices = If[MatchQ[boundary, "Initial" | All], Prepend[0], Identity] @ If[MatchQ[boundary, All | "Final"], Append[Infinity], Identity] @ Range[Length[obj[[1]][$eventRuleIDs]] - 1]; @@ -692,10 +688,7 @@ caller_, property : "ExpressionsEventsGraph", o : OptionsPattern[]] /; - (Complement[{o}, FilterRules[{o}, $propertyOptions[property]]] == {}) := Module[{ - eventsToOutputs, expressionsToDestroyers, labeledEvents, labeledOutputs, labeledExpressions, labeledDestroyers, - graphVertices, allOptionValues, vertexLabelsOptionValue, automaticVertexLabelsPattern, rules, eventRuleIDs, - allExpressions, placementFunction}, + (Complement[{o}, FilterRules[{o}, $propertyOptions[property]]] == {}) := ModuleScope[ {eventsToOutputs, expressionsToDestroyers} = eventsExpressionsRelations[obj, caller, boundary]; {labeledEvents, labeledOutputs, labeledExpressions, labeledDestroyers} = Function[{list, label, level}, Map[{label, #} &, list, level]] @@@ { @@ -768,8 +761,7 @@ connecting them if the same event is a creator and a destroyer for the same expr caller_, property : "CausalGraph", o : OptionsPattern[]] /; - (Complement[{o}, FilterRules[{o}, $propertyOptions[property]]] == {}) := Module[{ - eventsToOutputs, expressionsToDestroyers, eventsToEvents, causalEdges, allOptionValues}, + (Complement[{o}, FilterRules[{o}, $propertyOptions[property]]] == {}) := ModuleScope[ {eventsToOutputs, expressionsToDestroyers} = eventsExpressionsRelations[obj, caller, boundary]; eventsToEvents = Catenate /@ Map[expressionsToDestroyers, eventsToOutputs, {2}]; causalEdges = Catenate[Thread /@ Normal[eventsToEvents]]; @@ -861,7 +853,7 @@ connecting them if the same event is a creator and a destroyer for the same expr propertyEvaluate[True, boundary : includeBoundaryEventsPattern][ obj : WolframModelEvolutionObject[data_ ? evolutionDataQ], caller_, - "EdgeCreatorEventIndices"] := Module[{events, eventOutputs}, + "EdgeCreatorEventIndices"] := ModuleScope[ events = propertyEvaluate[True, "Initial"][obj, caller, "AllEventsList"]; eventOutputs = events[[All, 2, 2]]; Sort[Catenate[Thread /@ Thread[eventOutputs -> Range[Length[events]] - 1]]][[All, 2]] @@ -872,7 +864,7 @@ connecting them if the same event is a creator and a destroyer for the same expr propertyEvaluate[True, boundary : includeBoundaryEventsPattern][ obj : WolframModelEvolutionObject[data_ ? evolutionDataQ], caller_, - "EdgeDestroyerEventsIndices"] := Module[{events, eventInputs, edgeToDestroyerRules, resultWithInfinities}, + "EdgeDestroyerEventsIndices"] := ModuleScope[ events = propertyEvaluate[True, "Final"][obj, caller, "AllEventsList"]; eventInputs = events[[All, 2, 1]]; edgeToDestroyerRules = Sort[Catenate[Thread /@ Thread[eventInputs -> Append[Range[Length[events] - 1], Infinity]]]]; @@ -892,7 +884,7 @@ connecting them if the same event is a creator and a destroyer for the same expr propertyEvaluate[True, boundary : includeBoundaryEventsPattern][ obj : WolframModelEvolutionObject[data_ ? evolutionDataQ], caller_, - "EdgeDestroyerEventIndices"] := Module[{eventLists}, + "EdgeDestroyerEventIndices"] := ModuleScope[ eventLists = propertyEvaluate[True, "Final"][obj, caller, "EdgeDestroyerEventsIndices"]; MapIndexed[eventListToSingleEvent[caller, #, #2[[1]]] &, eventLists] ] @@ -902,18 +894,17 @@ connecting them if the same event is a creator and a destroyer for the same expr propertyEvaluate[True, includeBoundaryEventsPattern][ obj : WolframModelEvolutionObject[_ ? evolutionDataQ], caller_, - "EdgeGenerationsList"] := Module[{}, + "EdgeGenerationsList"] := ( propertyEvaluate[True, "Initial"][obj, caller, "EventGenerations"][[ propertyEvaluate[True, "Initial"][obj, caller, "EdgeCreatorEventIndices"] + 1]] -] +) (* ExpressionsSeparation *) propertyEvaluate[True, includeBoundaryEventsPattern][ obj : WolframModelEvolutionObject[_ ? evolutionDataQ], caller_, - "ExpressionsSeparation", signedExpr1_, signedExpr2_] := Module[{ - expr1, expr2, expressionsEventsGraph, causalCones, intersection, intersectionBoundary, boundaryExpressions}, + "ExpressionsSeparation", signedExpr1_, signedExpr2_] := ModuleScope[ {expr1, expr2} = toPositiveParameter[ 1, propertyEvaluate[True, None][obj, caller, "ExpressionsCountTotal"], #, caller, "Expression"] & /@ @@ -939,7 +930,7 @@ connecting them if the same event is a creator and a destroyer for the same expr WolframModelEvolutionObject[ data_ ? evolutionDataQ][ property__ ? (Not[MatchQ[#, OptionsPattern[]]] &), - opts : OptionsPattern[]] := Module[{result}, + opts : OptionsPattern[]] := ModuleScope[ result = Catch[ (propertyEvaluate @@ (OptionValue[Join[{opts}, $masterOptions], #] & /@ {"IncludePartialGenerations", "IncludeBoundaryEvents"}))[ @@ -983,7 +974,7 @@ connecting them if the same event is a creator and a destroyer for the same expr WolframModelEvolutionObject::migrationInputOrdering = "Migrating the evolution object from version 1. The ordering of event inputs may be incorrect."; -migrateEvolutionObjectData[data_, 1, 2] := Module[{eventsToInputs, eventsToOutputs, eventInputs, eventOutputs}, +migrateEvolutionObjectData[data_, 1, 2] := ModuleScope[ Message[WolframModelEvolutionObject::migrationInputOrdering]; {eventsToInputs, eventsToOutputs} = GroupBy[Thread[data[#] -> Range[Length[data[#]]]], First][[All, All, 2]] & /@ {$destroyerEvents, $creatorEvents}; diff --git a/Kernel/WolframModelPlot.m b/Kernel/WolframModelPlot.m index 7e6485c3e..1e4681d97 100644 --- a/Kernel/WolframModelPlot.m +++ b/Kernel/WolframModelPlot.m @@ -1,5 +1,7 @@ Package["SetReplace`"] +PackageImport["GeneralUtilities`"] + PackageExport["HypergraphPlot"] PackageExport["WolframModelPlot"] @@ -83,7 +85,8 @@ (* Evaluation *) -func : WolframModelPlot[args___] := Module[{result = wolframModelPlot$parse[args]}, +func : WolframModelPlot[args___] := ModuleScope[ + result = wolframModelPlot$parse[args]; result /; result =!= $Failed ] @@ -115,8 +118,7 @@ parseHighlight[_, _, {}, _] := ConstantArray[Automatic, 3] -parseHighlight[vertices_, edges_, highlightList_, highlightStyle_] := Module[{ - highlightCounts, vertexHighlightFlags, edgeHighlightFlags}, +parseHighlight[vertices_, edges_, highlightList_, highlightStyle_] := ModuleScope[ highlightCounts = Counts[highlightList]; {vertexHighlightFlags, edgeHighlightFlags} = Map[ With[{highlightedQ = If[MissingQ[highlightCounts[#]], False, highlightCounts[#]-- > 0]}, @@ -136,9 +138,8 @@ wolframModelPlot$parse[ edges : $hypergraphPattern, edgeType : Alternatives @@ $edgeTypes : $defaultEdgeType, o : OptionsPattern[]] /; - correctWolframModelPlotOptionsQ[WolframModelPlot, Defer[WolframModelPlot[edges, o]], edges, {o}] := Module[{ - optionValue, vertices, highlightedVertexStyles, highlightedEdgeLineStyles, highlightedEdgePointStyles, - highlightedEdgePolygonStyles, styles}, + correctWolframModelPlotOptionsQ[WolframModelPlot, Defer[WolframModelPlot[edges, o]], edges, {o}] := ModuleScope[ + ScopeVariable[optionValue]; optionValue[opt_] := OptionValue[WolframModelPlot, {o}, opt]; vertices = vertexList[edges]; (* these are either single styles or lists, one style for each element *) @@ -294,7 +295,7 @@ arrowheadLength_, maxImageSize_, background_, - graphicsOptions_] := Catch[Module[{embedding, graphics, imageSizeScaleFactor}, + graphicsOptions_] := Catch[Module[{embedding, graphics, imageSizeScaleFactor, numericArrowheadLength}, embedding = hypergraphEmbedding[edgeType, hyperedgeRendering, vertexCoordinates] @ edges; numericArrowheadLength = Replace[ arrowheadLength, @@ -339,8 +340,7 @@ edgeLayoutEdgeType_, hyperedgeRendering : "Subgraphs", coordinateRules_][ - edges_] := Module[{ - vertices, vertexEmbeddingNormalEdges, edgeEmbeddingNormalEdges}, + edges_] := ModuleScope[ vertices = vertexList[edges]; {vertexEmbeddingNormalEdges, edgeEmbeddingNormalEdges} = toNormalEdges[edges, #] & /@ {vertexLayoutEdgeType, edgeLayoutEdgeType}; @@ -361,8 +361,7 @@ toNormalEdges[edges_, "Cyclic"] := toNormalEdges[edges, 2, 1, 1] -graphEmbedding[vertices_, vertexEmbeddingEdges_, edgeEmbeddingEdges_, layout_, coordinateRules_] := Module[{ - relevantCoordinateRules, vertexCoordinateRules, unscaledEmbedding}, +graphEmbedding[vertices_, vertexEmbeddingEdges_, edgeEmbeddingEdges_, layout_, coordinateRules_] := ModuleScope[ relevantCoordinateRules = Normal[Merge[Select[MemberQ[vertices, #[[1]]] &][coordinateRules], Last]]; unscaledEmbedding = If[vertexEmbeddingEdges === edgeEmbeddingEdges, graphEmbedding[vertices, edgeEmbeddingEdges, layout, relevantCoordinateRules], @@ -379,7 +378,7 @@ graphEmbedding[vertices, edges, layout, coordinateRules][[1]] edgeEmbedding[vertices_, edges_, "SpringElectricalEmbedding", vertexCoordinates_] /; - SimpleGraphQ[Graph[UndirectedEdge @@@ edges]] := Module[{coordinates}, + SimpleGraphQ[Graph[UndirectedEdge @@@ edges]] := ModuleScope[ coordinates = Association[vertexCoordinates]; Thread[edges -> List @@@ Map[coordinates, edges, {2}]] ] @@ -400,9 +399,7 @@ {1} ] -normalToHypergraphEmbedding[edges_, normalEdges_, normalEmbedding_] := Module[{ - vertexEmbedding, indexedHyperedges, normalEdgeToIndexedHyperedge, normalEdgeToLinePoints, lineSegments, - indexedHyperedgesToLineSegments, indexedEdgeEmbedding, indexedSingleVertexEdges, indexedSingleVertexEdgeEmbedding}, +normalToHypergraphEmbedding[edges_, normalEdges_, normalEmbedding_] := ModuleScope[ vertexEmbedding = Sort[#[[1]] -> {Point[#[[2]]]} & /@ normalEmbedding[[1]]]; indexedHyperedges = MapIndexed[{#, #2[[1]]} &, edges]; @@ -437,7 +434,7 @@ lineLength[pts_] := Total[EuclideanDistance @@@ Partition[pts, 2, 1]] $selfLoopsScale = 0.7; -edgeScale[{vertexEmbedding_, edgeEmbedding : Except[{}]}] := Module[{selfLoops}, +edgeScale[{vertexEmbedding_, edgeEmbedding : Except[{}]}] := ModuleScope[ selfLoops = Select[#[[1, 1]] == #[[1, 2]] &][edgeEmbedding][[All, 2]]; Mean[lineLength /@ N /@ If[selfLoops =!= {}, $selfLoopsScale * selfLoops, edgeEmbedding[[All, 2]]]] ] @@ -456,8 +453,7 @@ (*** SpringElectricalPolygons ***) -hypergraphEmbedding[edgeType_, hyperedgeRendering : "Polygons", vertexCoordinates_][edges_] := Module[{ - embeddingWithNoRegions, vertexEmbedding, edgeEmbedding}, +hypergraphEmbedding[edgeType_, hyperedgeRendering : "Polygons", vertexCoordinates_][edges_] := ModuleScope[ embeddingWithNoRegions = hypergraphEmbedding["Cyclic", edgeType, "Subgraphs", vertexCoordinates][edges]; vertexEmbedding = embeddingWithNoRegions[[1]]; @@ -467,7 +463,7 @@ addConvexPolygons["Ordered"][edge : {_, _.}, subgraphsShapes_] := edge -> subgraphsShapes -addConvexPolygons[edgeType_][edge_, subgraphsShapes_] := Module[{points, region, convexPolygons, polygon}, +addConvexPolygons[edgeType_][edge_, subgraphsShapes_] := ModuleScope[ points = Flatten[#, 2] & @ (subgraphsShapes /. {Line[pts_] :> {pts}, Point[pts_] :> {{pts}}}); edge -> If[Length[points] > 2, Append[subgraphsShapes, convexHullPolygon[points]], subgraphsShapes] ] @@ -480,8 +476,7 @@ applyStyle[style_List, shapes_] := Replace[DeleteCases[Transpose[{style, shapes}], {_, {}}], {} -> Nothing] -vertexLabelsGraphics[embedding_, vertexSize_, vertexLabels_] := Module[{ - pointsToVertices, edges, vertexCoordinatesDiagonal, graphPlotVertexSize}, +vertexLabelsGraphics[embedding_, vertexSize_, vertexLabels_] := ModuleScope[ pointsToVertices = Association[Reverse /@ Catenate[Function[{v, pts}, v -> # & /@ Cases[pts, _Point]] @@@ embedding[[1]]]]; edges = @@ -506,8 +501,9 @@ vertexLabels_, vertexSize_, arrowheadLength_][ - embedding_] := Module[{singleVertexEdgeCounts, getSingleVertexEdgeRadius}, + embedding_] := ModuleScope[ singleVertexEdgeCounts = <||>; + ScopeVariable[getSingleVertexEdgeRadius]; getSingleVertexEdgeRadius[coords_] := ( singleVertexEdgeCounts[coords] = Lookup[singleVertexEdgeCounts, Key[coords], vertexSize] + vertexSize ); diff --git a/Kernel/WolframModelRuleValue.m b/Kernel/WolframModelRuleValue.m index e0aff3185..9d055715e 100644 --- a/Kernel/WolframModelRuleValue.m +++ b/Kernel/WolframModelRuleValue.m @@ -1,5 +1,7 @@ Package["SetReplace`"] +PackageImport["GeneralUtilities`"] + PackageExport["WolframModelRuleValue"] PackageExport["$WolframModelRuleProperties"] @@ -23,7 +25,8 @@ (* Implementation *) -WolframModelRuleValue[args___] := Module[{result = Catch[wolframModelRuleValue[args]]}, +WolframModelRuleValue[args___] := ModuleScope[ + result = Catch[wolframModelRuleValue[args]]; result /; result =!= $Failed ] diff --git a/Kernel/argumentsChecking.m b/Kernel/argumentsChecking.m index e6c198ab3..c1fa625fa 100644 --- a/Kernel/argumentsChecking.m +++ b/Kernel/argumentsChecking.m @@ -1,12 +1,14 @@ Package["SetReplace`"] +PackageImport["GeneralUtilities`"] + PackageScope["supportedOptionQ"] PackageScope["knownOptionsQ"] General::invalidFiniteOption = "Value `2` of option `1` should be one of `3`."; -supportedOptionQ[func_, optionToCheck_, validValues_, opts_] := Module[{value, supportedQ}, +supportedOptionQ[func_, optionToCheck_, validValues_, opts_] := ModuleScope[ value = OptionValue[func, {opts}, optionToCheck]; supportedQ = MemberQ[validValues, value]; If[!supportedQ, diff --git a/Kernel/arrow.m b/Kernel/arrow.m index 56fb2deb5..48b6f426b 100644 --- a/Kernel/arrow.m +++ b/Kernel/arrow.m @@ -1,8 +1,10 @@ Package["SetReplace`"] +PackageImport["GeneralUtilities`"] + PackageScope["arrow"] -arrow[shape_, arrowheadLength_, vertexSize_][pts_] := Module[{ptsStartToArrowEnd, ptsStartToLineEnd}, +arrow[shape_, arrowheadLength_, vertexSize_][pts_] := ModuleScope[ ptsStartToArrowEnd = lineTake[pts, vertexSize ;; - vertexSize]; ptsStartToLineEnd = lineTake[ptsStartToArrowEnd, 0 ;; - arrowheadLength]; { diff --git a/Kernel/convexHullPolygon.m b/Kernel/convexHullPolygon.m index 7d58fde6b..9466d0928 100644 --- a/Kernel/convexHullPolygon.m +++ b/Kernel/convexHullPolygon.m @@ -1,5 +1,7 @@ Package["SetReplace`"] +PackageImport["GeneralUtilities`"] + PackageScope["convexHullPolygon"] (* Graham scan algorithm, https://en.wikipedia.org/wiki/Graham_scan *) @@ -17,11 +19,10 @@ rotationDirection[pt1_, pt2_, pt3_] := (pt2[[1]] - pt1[[1]]) (pt3[[2]] - pt2[[2]]) - (pt2[[2]] - pt1[[2]]) (pt3[[1]] - pt2[[1]]) -convexHullPolygon[points_] := Module[{ - (* Sort is broken for symbolic values in Wolfram Language 12.2 *) - numericPoints = N[points], - stack = CreateDataStructure["Stack"], - center, centeredPoints, counterClockwisePoints, deduplicatedPoints}, +convexHullPolygon[points_] := ModuleScope[ + (* Sort is broken for symbolic values in Wolfram Language 12.2 *) + numericPoints = N[points]; + stack = CreateDataStructure["Stack"]; (* find a bottommost point, if multiple, find the leftmost one *) center = First[MinimalBy[MinimalBy[numericPoints, Last], First]]; centeredPoints = # - center & /@ DeleteCases[numericPoints, center, {1}]; diff --git a/Kernel/setSubstitutionSystem$cpp.m b/Kernel/setSubstitutionSystem$cpp.m index 0a09b6ea5..691b2bd5d 100644 --- a/Kernel/setSubstitutionSystem$cpp.m +++ b/Kernel/setSubstitutionSystem$cpp.m @@ -1,5 +1,7 @@ Package["SetReplace`"] +PackageImport["GeneralUtilities`"] + PackageScope["$cppSetReplaceAvailable"] PackageScope["setSubstitutionSystem$cpp"] @@ -82,7 +84,7 @@ (* This is the reverse, used to decode set data (a list of expressions) from libSetReplace *) -decodeAtomLists[list_List] := Module[{count, atomPointers, atomRanges, atomLists}, +decodeAtomLists[list_List] := ModuleScope[ count = list[[1]]; atomPointers = list[[2 ;; (count + 1) + 1]]; atomRanges = Partition[atomPointers, 2, 1]; @@ -91,10 +93,8 @@ (* Similar function for the events *) -decodeEvents[list_List] := Module[{ - count = list[[1]], - ruleIDs, inputPointers, outputPointers, generations, - inputRanges, inputLists, outputRanges, outputLists}, +decodeEvents[list_List] := ModuleScope[ + count = list[[1]]; {ruleIDs, inputPointers, outputPointers, generations} = Transpose[Partition[list[[2 ;; 4 (count + 1) + 1]], 4]]; {inputRanges, outputRanges} = Partition[#, 2, 1] & /@ {inputPointers, outputPointers}; @@ -107,8 +107,7 @@ (* Check if we have simple anonymous rules and use C++ library in that case *) -ruleAtoms[left_ :> right_] := Module[{ - leftVertices, patterns, leftAtoms, patternSymbols, createdAtoms, rightAtoms}, +ruleAtoms[left_ :> right_] := ModuleScope[ leftVertices = Union @ Catenate[left[[1]]]; leftAtoms = Select[leftVertices, AtomQ]; patterns = Complement[leftVertices, leftAtoms]; @@ -122,8 +121,7 @@ Union @ Join[patternSymbols, createdAtoms]} ] -ruleAtomsToIndices[left_ :> right_, globalIndex_, localIndex_] := Module[{ - newLeft, newRight}, +ruleAtomsToIndices[left_ :> right_, globalIndex_, localIndex_] := ModuleScope[ newLeft = Replace[ left[[1]], {x_ ? AtomQ :> globalIndex[Hold[x]], @@ -181,11 +179,7 @@ setSubstitutionSystem$cpp[ rules_, set_, stepSpec_, returnOnAbortQ_, timeConstraint_, eventOrderingFunction_, eventSelectionFunction_, eventDeduplication_] /; - $cppSetReplaceAvailable := Module[{ - canonicalRules, - setAtoms, atomsInRules, globalAtoms, globalIndex, - mappedSet, localIndices, mappedRules, setPtr, numericAtomLists, events, maxCompleteGeneration, terminationReason, - resultAtoms, inversePartialGlobalMap, inverseGlobalMap}, + $cppSetReplaceAvailable := ModuleScope[ canonicalRules = toCanonicalRules[rules]; setAtoms = Hold /@ Union[Catenate[set]]; atomsInRules = ruleAtoms /@ canonicalRules; diff --git a/Kernel/setSubstitutionSystem$wl.m b/Kernel/setSubstitutionSystem$wl.m index 1eb49aa49..6a61ae43b 100644 --- a/Kernel/setSubstitutionSystem$wl.m +++ b/Kernel/setSubstitutionSystem$wl.m @@ -1,5 +1,7 @@ Package["SetReplace`"] +PackageImport["GeneralUtilities`"] + PackageScope["setSubstitutionSystem$wl"] (* This is the implementation of setSubstitutionSystem in Wolfram Language. Works better with larger vertex degrees, @@ -8,8 +10,7 @@ (* We are going to transform set substitution rules into a list of n! normal rules, where elements of the input subset are arranged in every possible order with blank null sequences in between. *) -allLeftHandSidePermutations[input_Condition :> output_List] := Module[ - {inputLength, inputPermutations, heldOutput}, +allLeftHandSidePermutations[input_Condition :> output_List] := ModuleScope[ inputLength = Length @ input[[1]]; inputPermutations = Permutations @ input[[1]]; @@ -22,11 +23,10 @@ (* Now, if there are new vertices that need to be created, we will disassemble the Module remembering which variables it applies to, and then reassemble it for the output. *) -allLeftHandSidePermutations[input_Condition :> output_Module] := Module[ - {ruleInputOriginal = input[[1]], - ruleCondition = heldPart[input, 2], - heldModule = mapHold[output, {0, 1}], - moduleInputContents}, +allLeftHandSidePermutations[input_Condition :> output_Module] := ModuleScope[ + ruleInputOriginal = input[[1]]; + ruleCondition = heldPart[input, 2]; + heldModule = mapHold[output, {0, 1}]; moduleInputContents = heldModule[[1, 2]]; With[{ruleInputFinal = #[[1]], moduleArguments = heldModule[[1, 1]], @@ -61,9 +61,7 @@ (* untouched are the expressions that were not used in this event. Note that the Replace[...] arguments of Catenate effectively choose which rule should be used because all but one of the rule patterns will be empty sequences. *) -toNormalRules[rules_List] := Module[{ - ruleNames, separateNormalRules, longestRuleLength, untouchedNames, - finalMatchName, input, output}, +toNormalRules[rules_List] := ModuleScope[ ruleNames = Table[Unique["rule", {Temporary}], Length[rules]]; separateNormalRules = allLeftHandSidePermutations /@ rules; longestRuleLength = Max[Map[Length, separateNormalRules[[All, All, 1, 1]], {2}]]; @@ -102,8 +100,8 @@ (* This function just does the replacements, but it does not keep track of any metadata (generations and events). Returns {finalState, terminationReason}, and sows deleted expressions. *) -setReplace$wl[set_, rules_, stepSpec_, vertexIndex_, returnOnAbortQ_, timeConstraint_] := Module[{ - normalRules, previousResult, eventsCount = 0}, +setReplace$wl[set_, rules_, stepSpec_, vertexIndex_, returnOnAbortQ_, timeConstraint_] := ModuleScope[ + eventsCount = 0; normalRules = toNormalRules @ rules; previousResult = set; Catch[ @@ -175,10 +173,10 @@ getNextExpression_, maxGeneration_, maxVertexDegree_, - vertexIndex_] := Module[{ - inputIDs = Table[Unique["id", {Temporary}], Length[input[[1]]]], - wholeInputPatternNames = Table[Unique["inputExpression", {Temporary}], Length[input[[1]]]], - inputGenerations = Table[Unique["generation", {Temporary}], Length[input[[1]]]]}, + vertexIndex_] := ModuleScope[ + inputIDs = Table[Unique["id", {Temporary}], Length[input[[1]]]]; + wholeInputPatternNames = Table[Unique["inputExpression", {Temporary}], Length[input[[1]]]]; + inputGenerations = Table[Unique["generation", {Temporary}], Length[input[[1]]]]; With[{ heldModule = mapHold[output, {0, 1}]}, With[{ @@ -234,8 +232,7 @@ obtained. Note, matching is necessary to determine that because it's impossible to determine if the last generation is done otherwise. *) -maxCompleteGeneration[output_, rulesNoMetadata_] := Module[{ - patternToMatch, matches}, +maxCompleteGeneration[output_, rulesNoMetadata_] := ModuleScope[ patternToMatch = toNormalRules[ addMetadataManagement[#, Infinity, Infinity &, Infinity, Infinity, $noIndex] & /@ rulesNoMetadata]; matches = Reap[ @@ -313,10 +310,8 @@ All operations here should evaluate in O(1). *) generations and events. It uses setReplace$wl to evaluate that modified system. *) setSubstitutionSystem$wl[ - caller_, rules_, init_, stepSpec_, returnOnAbortQ_, timeConstraint_] := Module[{ - initWithMetadata, renamedRules, rulesWithMetadata, outputWithMetadata, allExpressions, - nextExpressionID = 1, expressionsCountsPerVertex, vertexIndex, nextExpression, - initialEvent, allEvents, generationsCount, maxCompleteGenerationAssumingExceedingStepSpecGenerationsDontExist}, + caller_, rules_, init_, stepSpec_, returnOnAbortQ_, timeConstraint_] := ModuleScope[ + nextExpressionID = 1; nextExpression = nextExpressionID++ &; (* {id, generation, atoms} *) initWithMetadata = {nextExpression[], 0, #} & /@ init; diff --git a/Kernel/setSubstitutionSystem.m b/Kernel/setSubstitutionSystem.m index 90d9febab..4be0430ed 100644 --- a/Kernel/setSubstitutionSystem.m +++ b/Kernel/setSubstitutionSystem.m @@ -1,5 +1,7 @@ Package["SetReplace`"] +PackageImport["GeneralUtilities`"] + PackageExport["$SetReplaceMethods"] (* This is a main function of the package. This function calls either C++ or Wolfram Language implementation, and can @@ -259,24 +261,26 @@ caller_, returnOnAbortQ_, o : OptionsPattern[]] /; - stepSpecQ[caller, set, stepSpec, OptionValue[setSubstitutionSystem, {o}, "EventSelectionFunction"]] := Module[{ - method = OptionValue[Method], - timeConstraint = OptionValue[TimeConstraint], - eventOrderingFunction = parseEventOrderingFunction[caller, OptionValue["EventOrderingFunction"]], - eventSelectionFunction = parseParameterValue[ - caller, "EventSelectionFunction", OptionValue["EventSelectionFunction"], $eventSelectionFunctions], - eventDeduplication = parseParameterValue[ - caller, "EventDeduplication", OptionValue["EventDeduplication"], $eventDeduplications], - symbolicEvaluationSupportedQ = OptionValue["EventOrderingFunction"] === Automatic && - OptionValue["EventSelectionFunction"] === "GlobalSpacelike" && - OptionValue["EventDeduplication"] === None, - canonicalRules, - failedQ = False}, + stepSpecQ[ + caller, set, stepSpec, OptionValue[setSubstitutionSystem, {o}, "EventSelectionFunction"]] := ModuleScope[ + method = OptionValue[Method]; + timeConstraint = OptionValue[TimeConstraint]; + eventOrderingFunction = parseEventOrderingFunction[caller, OptionValue["EventOrderingFunction"]]; + eventSelectionFunction = parseParameterValue[ + caller, "EventSelectionFunction", OptionValue["EventSelectionFunction"], $eventSelectionFunctions]; + eventDeduplication = parseParameterValue[ + caller, "EventDeduplication", OptionValue["EventDeduplication"], $eventDeduplications]; + symbolicEvaluationSupportedQ = OptionValue["EventOrderingFunction"] === Automatic && + OptionValue["EventSelectionFunction"] === "GlobalSpacelike" && + OptionValue["EventDeduplication"] === None; + failedQ = False; If[eventOrderingFunction === $Failed || eventSelectionFunction === $Failed || eventDeduplication === $Failed, - Return[$Failed]]; + Return[$Failed] + ]; If[!symbolicEvaluationSupportedQ && method === "Symbolic", Message[caller::symbOrdering]; - Return[$Failed]]; + Return[$Failed] + ]; If[(timeConstraint > 0) =!= True, Return[$Failed]]; canonicalRules = toCanonicalRules[rules]; If[MatchQ[method, Automatic | $cppMethod] @@ -286,16 +290,22 @@ Return[ setSubstitutionSystem$cpp[ rules, set, stepSpec, returnOnAbortQ, timeConstraint, eventOrderingFunction, eventSelectionFunction, - eventDeduplication]]]]; + eventDeduplication]] + ] + ]; If[MatchQ[method, $cppMethod], failedQ = True; If[!$cppSetReplaceAvailable, makeMessage[caller, "noLowLevel"], - makeMessage[caller, "lowLevelNotImplemented"]]]; + makeMessage[caller, "lowLevelNotImplemented"] + ] + ]; If[failedQ || !MatchQ[OptionValue[Method], Alternatives @@ $SetReplaceMethods], $Failed, If[!symbolicEvaluationSupportedQ, Message[caller::symbNotImplemented]; - Return[$Failed]]; - setSubstitutionSystem$wl[caller, rules, set, stepSpec, returnOnAbortQ, timeConstraint]] + Return[$Failed] + ]; + setSubstitutionSystem$wl[caller, rules, set, stepSpec, returnOnAbortQ, timeConstraint] + ] ] diff --git a/Kernel/testUtilities.m b/Kernel/testUtilities.m index 11d66170c..b8a8fdf79 100644 --- a/Kernel/testUtilities.m +++ b/Kernel/testUtilities.m @@ -1,5 +1,7 @@ Package["SetReplace`"] +PackageImport["GeneralUtilities`"] + PackageScope["testUnevaluated"] PackageScope["testSymbolLeak"] PackageScope["checkGraphics"] diff --git a/Tests/matching.wlt b/Tests/matching.wlt index 32f218a68..376c67711 100644 --- a/Tests/matching.wlt +++ b/Tests/matching.wlt @@ -32,8 +32,7 @@ ); (* Here we generate random graphs and try replacing them to nothing *) - randomSameGraphMatchTests[edgeCount_, edgeLength_, graphCount_, method_] := Module[{ - tests}, + randomSameGraphMatchTests[edgeCount_, edgeLength_, graphCount_, method_] := ModuleScope[ tests = randomConnectedGraphs[edgeCount, edgeLength, graphCount]; Map[ With[{set1 = #[[1]], set2 = #[[2]]}, @@ -45,8 +44,7 @@ (* Here we generate pairs of different graphs, and check they are not being matched *) randomDistinctGraphMatchTests[ - edgeCount_, edgeLength_, graphCount_, method_] := Module[{ - tests}, + edgeCount_, edgeLength_, graphCount_, method_] := ModuleScope[ tests = Select[!IsomorphicGraphQ @@ (graphFromHyperedges /@ #) &] @ Partition[ Select[SimpleGraphQ @* graphFromHyperedges] @@ -64,8 +62,7 @@ (* Here we make initial condition degenerate, and check it still matches, i.e., {{0, 0}} should still match {{0, 1}} *) randomDegenerateGraphMatchTests[ - edgeCount_, edgeLength_, graphCount_, method_] := Module[{ - tests}, + edgeCount_, edgeLength_, graphCount_, method_] := ModuleScope[ tests = randomConnectedGraphs[edgeCount, edgeLength, graphCount]; Map[ With[{set1 = #[[1]], identifiedVertex1 = #[[2]], identifiedVertex2 = #[[3]], set2 = #[[4]]}, diff --git a/performanceTest.wls b/performanceTest.wls index 7c0ebad45..4afb1d7ee 100755 --- a/performanceTest.wls +++ b/performanceTest.wls @@ -1,5 +1,7 @@ #!/usr/bin/env wolframscript +Needs["GeneralUtilities`"]; + Get["scripts/buildInit.wl"]; << SetReplace`; @@ -70,7 +72,7 @@ If[!IntegerQ[$measurementsCount] || $measurementsCount < 2, Attributes[meanAroundTiming] = {HoldAll}; meanAroundTiming[expr_] := MeanAround @ Table[First @ AbsoluteTiming[expr], $measurementsCount] -runTests[repo_, sha_, tests_] := Module[{result, kernel}, +runTests[repo_, sha_, tests_] := ModuleScope[ Print["Testing ", sha]; GitCheckoutReference[repo, sha]; Run["./build.wls"]; diff --git a/scripts/buildInit.wl b/scripts/buildInit.wl index aa0cbe670..30c163dd1 100644 --- a/scripts/buildInit.wl +++ b/scripts/buildInit.wl @@ -1,5 +1,6 @@ Needs["CCompilerDriver`"]; Needs["PacletManager`"]; +Needs["GeneralUtilities`"]; $internalBuildQ = AntProperty["build_target"] === "internal"; @@ -64,7 +65,7 @@ copyWLSourceToBuildDirectory[] /; !$internalBuildQ := With[{ fileStringReplace[file_, rules_] := Export[file, StringReplace[Import[file, "Text"], rules], "Text"] -renameContext[Automatic, version_] := Module[{context}, +renameContext[Automatic, version_] := ModuleScope[ context = Replace[ If[$internalBuildQ, AntProperty["context"], tryEnvironment["CONTEXT", "SetReplace"]], "Version" -> "SetReplace$" <> StringReplace[version, "." -> "$"]] <> "`"; @@ -82,8 +83,7 @@ renameContext[newContext_] := fileStringReplace[#, "SetReplace`" -> newContext] $baseVersionPacletMessage = "Will create paclet with the base version number."; updateVersion::noGitLink = "Could not find GitLink. " <> $baseVersionPacletMessage; -updateVersion[] /; Names["GitLink`*"] =!= {} := Module[{ - versionInformation, gitRepo, minorVersionNumber, versionString, pacletInfoFilename, pacletInfo}, +updateVersion[] /; Names["GitLink`*"] =!= {} := ModuleScope[ Check[ versionInformation = Import[FileNameJoin[{$repoRoot, "scripts", "version.wl"}]]; gitRepo = GitOpen[$repoRoot]; @@ -104,7 +104,7 @@ updateVersion[] /; Names["GitLink`*"] =!= {} := Module[{ updateVersion[] /; Names["GitLink`*"] === {} := Message[updateVersion::noGitLink]; -gitSHA[] /; Names["GitLink`*"] =!= {} := Module[{gitRepo, sha, cleanQ}, +gitSHA[] /; Names["GitLink`*"] =!= {} := ModuleScope[ gitRepo = GitOpen[$repoRoot]; sha = GitSHA[gitRepo, gitRepo["HEAD"]]; cleanQ = AllTrue[# === {} &]@GitStatus[gitRepo]; @@ -127,7 +127,7 @@ addModifiedContextFlag[fileName_] := FileNameJoin[Append[ Most[FileNameSplit[fileName]], StringJoin[StringRiffle[Most[StringSplit[Last[FileNameSplit[fileName]], "."]], "."], "-C.paclet"]]] -packPaclet[context_] := Module[{pacletFileName}, +packPaclet[context_] := ModuleScope[ If[$internalBuildQ, Print["$Version: ", $Version]; Print["$InstallationDirectory: ", $InstallationDirectory]; diff --git a/test.wls b/test.wls index b7ec75ec0..81c152d48 100755 --- a/test.wls +++ b/test.wls @@ -9,6 +9,8 @@ CloseKernels[]; LaunchKernels[]; ParallelEvaluate[<< SetReplace`]; +Needs["GeneralUtilities`"]; + $successQ = True; (* Get test files *)