Wolfram Language Paclet Repository

Community-contributed installable additions to the Wolfram Language

Primary Navigation

    • Cloud & Deployment
    • Core Language & Structure
    • Data Manipulation & Analysis
    • Engineering Data & Computation
    • External Interfaces & Connections
    • Financial Data & Computation
    • Geographic Data & Computation
    • Geometry
    • Graphs & Networks
    • Higher Mathematical Computation
    • Images
    • Knowledge Representation & Natural Language
    • Machine Learning
    • Notebook Documents & Presentation
    • Scientific and Medical Data & Computation
    • Social, Cultural & Linguistic Data
    • Strings & Text
    • Symbolic & Numeric Computation
    • System Operation & Setup
    • Time-Related Computation
    • User Interface Construction
    • Visualization & Graphics
    • Random Paclet
    • Alphabetical List
  • Using Paclets
    • Get Started
    • Download Definition Notebook
  • Learn More about Wolfram Language

CodeEquivalenceUtilities

Guides

  • Code Equivalence Utilities

Tech Notes

  • Adding New Transformation Rules

Symbols

  • CodeEquivalentQ
  • EquivalenceTestData
  • FromCanonicalForm
  • MakeCanonicalForm
  • ToCanonicalForm
  • TransformHold
  • TransformRelease
  • $AllowedEvaluationPatterns
Adding New Transformation Rules
Finding Rules
Adding new rules permanently
Adding new rules temporarily
Adding new unit tests
Testing new rules
Utilities for transformation rules
This explains how to find, test, and deploy new transformation rules.
Finding Rules

Generating Canonical Forms of Expressions

ToCanonicalForm
converts an expression into canonical form
MakeCanonicalForm
converts an expression into canonical form without evaluation
Utility functions for seeing the canonical form of an expression.
Equivalence of code is determined by comparing their canonical representations.
Check if two expressions are equivalent:
In[7]:=
CodeEquivalentQ
[RandomInteger/@Range[5],Array[RandomInteger,5]]
Out[7]=
True
Compare their canonical forms:
In[8]:=
MakeCanonicalForm
[RandomInteger/@Range[5]]
Out[8]=
Table
ℛ
DiscreteUniformDistribution0,
S1∷Int
,
S1∷Int
,1,5,1
In[9]:=
MakeCanonicalForm
[Array[RandomInteger,5]]
Out[9]=
Table
ℛ
DiscreteUniformDistribution0,
S1∷Int
,
S1∷Int
,1,5,1
These can be directly compared:
In[10]:=
%===%%
Out[10]=
True
By tracing the sequence of transformations, you can get an idea of what kind of rule to introduce to get the transformations to converge.
In[3]:=
expr1=HoldForm[Table[RandomReal[],10]]
Out[3]=
Table[RandomReal[],10]
In[4]:=
expr2=HoldForm[Table[RandomReal[1],10]]
Out[4]=
Table[RandomReal[1],10]
Notice that the
RandomReal
[]
does not expand here:
ToCanonicalForm
[expr1,"Trace"True]//Column
Table[RandomReal[],10]
Table[RandomReal[],{S,1,10,1}]
TableRandomReal[],
S1∷Int
,1,10,1
The
RandomReal
[1]
does, which makes comparison fail:
ToCanonicalForm
[expr2,"Trace"True]//Column
RandomReal[1,10]
Table[RandomReal[1],10]
Table[RandomReal[1],{S,1,10,1}]
TableRandomReal[1],
S1∷Int
,1,10,1
TableRandomReal[{0,1}],
S1∷Int
,1,10,1
TableRandomValue[UniformDistribution[{0,1}]],
S1∷Int
,1,10,1
Notice that the only difference between expr1 and the second transformation of expr2 is that one has
RandomReal
[1]
instead of
RandomReal
[]
. Since
RandomReal
[]
is equivalent to
RandomReal
[1]
, this might be a good idea to use as a rule.
Adding new rules temporarily
$TransformationRules
the set of transformation rules used to convert expressions to their canonical forms
BuildDispatch
builds a
Dispatch
used to convert expressions from
$TransformationRules
Tools for building new conversion rules.
The symbol
$TransformationRules
(defined in Kernel/CanonicalForms/Rules.m) contains the rules used by
ToCanonicalForm
. For testing, we can modify the rules in the current session without reloading the package by using
BuildDispatch
.
Here's the desired rule from the previous example:
newRule=HoldPattern[RandomReal[]]RandomReal[1];
Create a new set of rules that includes this one:
newTransformationRules=Append[$TransformationRules,newRule];
BuildDispatch[newTransformationRules]
Rebuilt transformation rules----------------------------Count: 138Added: 1Removed: 0----------------------------
Now we can verify that expr1 reaches the desired canonical form:
ToCanonicalForm
[expr1]===
ToCanonicalForm
[expr2]
True
ToCanonicalForm
[expr1,"Trace"True]//Column
Table[RandomReal[],10]
Table[RandomReal[],{S,1,10,1}]
TableRandomReal[],
S1∷Int
,1,10,1
TableRandomReal[1],
S1∷Int
,1,10,1
TableRandomReal[{0,1}],
S1∷Int
,1,10,1
TableRandomValue[UniformDistribution[{0,1}]],
S1∷Int
,1,10,1
Testing new rules
Run the included unit tests to make sure that adding the new rule doesn't interfere with anything else:
testFile=​​FileNameJoin[{​​Lookup[PacletInformation["CodeEquivalence"],"Location"],​​"Tests",​​"CanonicalForms",​​"Rules.wlt"​​}];
results=Block[{CodeEquivalence`EvaluationControl`$Memoize=False(*toavoidusinganycachedresults*)},​​TestReport[testFile,TimeConstraint1]​​]
TestReportObject
Title: Test Report: Rules.wlt
Success rate: 100%
Tests run: 32

Adding new rules permanently

Current method (soon to be obsolete)

Once a new rule has been successfully tested, it should be added to
$TransformationRules
in Kernel/CanonicalForms/Rules.m.
The format of elements in
$TransformationRules
is somewhat flexible. Items can be given as single transformation rules, such as:
HoldPattern[RandomReal[]]RandomReal[1]
However, in order to separate rules into conceptual categories, it can also accept groups of transformation rules (wrapped in
List
or
HoldComplete
), which is how almost all the rules are defined in Kernel/CanonicalForms/Rules.m.
For convenience, when rules are contained inside a
HoldComplete
, the build code will automatically wrap the left-hand side of the rules in
HoldPattern
, so the previous rule (if given inside a
HoldComplete
group) could also be written as
RandomReal
[]
RandomReal
[1]
which is a bit easier to read.

New method (still a work in progress)

Eventually, rules will be stored as associations that contain additional metadata. For this example, the corresponding transformation rule could be written as:
​​"Category""Random",​​"Usage"{"CanonicalForm"},​​"Rule"HoldPattern[RandomReal[]]RandomReal[1],​​"Description""Eliminate instances of RandomReal with no arguments."​​
However, this system is still a work in progress and subject to change, so don’t worry about it too much yet.
Adding new unit tests
Once a new rule is added, a corresponding unit test should be added to Tests/CanonicalForms/Rules.wlt. In this case, the following test would be appropriate:
Utilities for transformation rules
Symbols that are useful in defining new transformation rules.

WithHolding

Also allows use of local values in subsequent assignments:

TempHold

NewLocalSymbol / LocalContextQ

CodeEquivalence`CanonicalForms`Scope`LocalSymbols`S$12
Other forms:
{CodeEquivalence`CanonicalForms`Scope`LocalSymbols`S$23,
CodeEquivalence`CanonicalForms`Scope`LocalSymbols`S1337,
CodeEquivalence`CanonicalForms`Scope`LocalSymbols`symbol$24,
CodeEquivalence`CanonicalForms`Scope`LocalSymbols`name$25,
CodeEquivalence`CanonicalForms`Scope`LocalSymbols`definition$26}

SymbolQ

Useful for when matching against _Symbol isn’t enough:
Doesn’t evaluate the symbol:

Inline

Replaces symbols with their value:

SafeEvaluatedQ

Tests if an expression has been fully evaluated:
Only works if the evaluation would be free of side effects:
Useful for reducing simple subexpressions:

© 2025 Wolfram. All rights reserved.

  • Legal & Privacy Policy
  • Contact Us
  • WolframAlpha.com
  • WolframCloud.com