{"id":1852,"date":"2026-06-26T22:00:00","date_gmt":"2026-06-27T02:00:00","guid":{"rendered":"https:\/\/aristotle2digital.blogwyrm.com\/?p=1852"},"modified":"2026-06-14T17:41:55","modified_gmt":"2026-06-14T21:41:55","slug":"a-symbolic-experiment-part-6-elementary-term-rewriting","status":"publish","type":"post","link":"https:\/\/aristotle2digital.blogwyrm.com\/?p=1852","title":{"rendered":"A Symbolic Experiment &#8211; Part 6: Elementary Term Rewriting"},"content":{"rendered":"\n<p>After many months of build-up, we are now in a position to begin methodically exploring how to modify Sympy expression trees that we have defined earlier.&nbsp; Since Sympy expressions are, by design, immutable, it is important to understand that when terms like \u2018modify\u2019, \u2018change\u2019, \u2018substitute\u2019, \u2018replace\u2019 and other synonyms are used they are short hands for the more precise but far more wordy phrases like \u2018making a new expression whose structure is a modified version of an older expression\u2019 or \u2018making a new expression that is based on an older expression but for which certain subexpressions have been replaced\u2019, and so on.&nbsp; While the shorted phrases are easier to deal with it is vital that we don\u2019t forget that they aren\u2019t to be taken literally.<\/p>\n\n\n\n<p>Methods for making changes to an expression tree can be grouped into two broad categories:&nbsp; 1) by-hand methods and 2) built-in methods.&nbsp;<\/p>\n\n\n\n<p>An example of a by-hand method was featured in an <a href=\"https:\/\/aristotle2digital.blogwyrm.com\/?p=1789\">earlier post<\/a> about factoring where a small function using .has, .as_ordered_terms, and .factor was used to factor the, by now very familiar, test case of<\/p>\n\n\n\n<p>\\[ x^2 &#8211; 2ax + a^2 + y^2&nbsp; \\rightarrow (x-a)^2 + y^2 \\; .\\]<\/p>\n\n\n\n<p>The use of .has(a,x) (see <a href=\"https:\/\/aristotle2digital.blogwyrm.com\/?p=1832\">last post<\/a>) allows the relevant terms to be separated from the polynomial without needing to \u2018see\u2019 them or \u2018spell out\u2019 what they are.&nbsp; The function .as_ordered_terms was used to separate the top level of the Add function.&nbsp; Note that for other types of expressions, other choices, like .as_ordered_factors (for Mul) and args, may be needed, with args being the most generic of the lot.&nbsp; The key point being that the tree was \u2018broken down\u2019 into smaller pieces, some of which were amenable to the kinds of simplification functions discussed in a <a href=\"https:\/\/aristotle2digital.blogwyrm.com\/?p=1800\">previous post<\/a>.<\/p>\n\n\n\n<p>There are three often used functions in the second category of built-in methods.&nbsp; On these points, I received an excellent high-level summary from Oscar Benjamin, who is a Sympy developer.&nbsp; I will draw on this summary for what follows with two caveats:&nbsp; first, these methods are nuanced and complex, so I won\u2019t be able to fill in as ably as one of the developers can and, second, any mistakes are solely a consequence of my ignorance.<\/p>\n\n\n\n<p>The three methods are .xreplace, .subs, and .replace, given in order of what seems to be best described as generality and complexity. &nbsp;&nbsp;That is to say that Oscar Benjamin has described them as:<\/p>\n\n\n\n<div class=\"myQuoteDiv\"><p>The xreplace function is the fastest and simplest.&nbsp; The replace function is the most flexible.&nbsp; The subs function is the slowest and is the only one that applies any semantic meaning to the substitution.<\/p><\/div>\n\n\n\n<p>The following table summarizes their usage.<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><td><strong>Method<\/strong><strong><\/strong><\/td><td><strong>Usage<\/strong><strong><\/strong><\/td><td><strong>Comment<\/strong><strong><\/strong><\/td><\/tr><tr><td>.xreplace<\/td><td>expr.xreplace({o1:n1, o2:n2, \u2026})<\/td><td>Purely structural replacement which identifies a exact subexpression to be replaced (hence the \u2018x\u2019 in xreplace).<\/td><\/tr><tr><td>.subs<\/td><td>expr.sub({o1:n1, o2:n2, \u2026})<\/td><td>Mostly structural replacement but some mathematical equivalence is used in simplify terms.<\/td><\/tr><tr><td>.replace<\/td><td>expr.replace(old_pattern,new_pattern)<\/td><td>Purely structural replacement which uses a generic pattern to replace all subexpressions that match)<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p>Note: {o1:n1, o2:n2, \u2026} is a dictionary specifying how old expressions (o1, o2, etc.) are to be replaced by new terms (n1, n2, etc.).<\/p>\n\n\n\n<p>In order to illustrate the differences between these methods, we\u2019ll start with the master expression<\/p>\n\n\n\n<p>\\[ \u00a0Q = a + x + 2 x^2 + 3 x^3 + 4 x^4 + 5 \\cos(x) + \\\\ 6 \\cos(x^2) + 7 \\cos^2 (x) + 8 \\cos(b) + 9 e^{-x^2} \\; .\\]<\/p>\n\n\n\n<p>We\u2019ll look at all three methods under two term-rewriting rules:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Rule 1:\u00a0 $x^2 \\rightarrow y$<\/li>\n\n\n\n<li>Rule 2:\u00a0 $\\cos(x) \\rightarrow \\sin(x)$<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Rule 1: $x^2 \\rightarrow y$<\/h2>\n\n\n\n<p>Under the action of .xreplace $Q$ becomes<\/p>\n\n\n\n<p>\\[ Q \\xrightarrow{x^2 \\rightarrow y} a + x + 2 y + 3 x^3 + 4 x^4 + 5 \\cos(x) \\\\ + 6\\cos(y) + 7 \\cos^2(x) + 8 \\cos(b) + 9 e^{-y} \\; ,\\]<\/p>\n\n\n\n<p>showing that .xreplace simply went through $Q$\u2019s tree structure and structural rewrote sub-trees as shown in the following figure.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><a href=\"https:\/\/aristotle2digital.blogwyrm.com\/wp-content\/uploads\/2026\/06\/image.png\"><img loading=\"lazy\" decoding=\"async\" width=\"411\" height=\"227\" src=\"https:\/\/aristotle2digital.blogwyrm.com\/wp-content\/uploads\/2026\/06\/image.png\" alt=\"\" class=\"wp-image-1853\" srcset=\"https:\/\/aristotle2digital.blogwyrm.com\/wp-content\/uploads\/2026\/06\/image.png 411w, https:\/\/aristotle2digital.blogwyrm.com\/wp-content\/uploads\/2026\/06\/image-300x166.png 300w\" sizes=\"auto, (max-width: 411px) 100vw, 411px\" \/><\/a><\/figure><\/div>\n\n\n<p>Under the action of .subs $Q$ changes more, becoming:<\/p>\n\n\n\n<p>\\[ Q \\xrightarrow{x^2 \\rightarrow y} a + x + 2 y + 3 x^3 + 4 y^2 + 5 \\cos(x) + \\\\ 6\\cos(y) + 7 \\cos^2(x) + 8 \\cos(b) + 9e^{-y} \\; .\\]<\/p>\n\n\n\n<p>Note that .subs \u2018understood\u2019 that $x^2 \\rightarrow y$ properly, and without assumptions, means that $x^4 \\rightarrow y^2$.&nbsp; Odd powers of $x$ remain unchanged since .subs doesn\u2019t know enough to invert the replacement since it would have to choose between $x \\rightarrow +\\sqrt{y}$ and $x \\rightarrow -\\sqrt{y}$.<\/p>\n\n\n\n<p>Finally, under the action of .replace, $Q$ yields<\/p>\n\n\n\n<p>\\[ Q \\xrightarrow{x^2 \\rightarrow y} a + x + 2 y + 3 x^3 + 4 x^4 + 5 \\cos(x) + \\\\ 6\\cos(y) + 7 \\cos^2(x) + 8 \\cos(b) + 9 e^{-y} \\; ,\\]<\/p>\n\n\n\n<p>which is exactly identical to what resulted from the application of .xreplace.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Rule 2 $\\cos(x) \\rightarrow \\sin(x)$<\/h2>\n\n\n\n<p>Under the application of .xreplace, $Q$ becomes<\/p>\n\n\n\n<p>\\[ Q \\xrightarrow{\\cos(x) \\rightarrow \\sin(x)} a + x + 2 x^2 + 3 x^3 + 4 x^4 + 5 \\sin(x) + \\\\ 6\\cos(x^2) + 7 \\sin^2(x) + 8 \\cos(b) + 9 e^{-x^2} \\; , \\]<\/p>\n\n\n\n<p>again, as in the example for Rule 1, .xreplace only makes a structural change\/rewrite for only those subexpressions that, in a tree-sense, exactly match the old subexpression.<\/p>\n\n\n\n<p>The application of .subs gives identical expressions for $Q$, as does a na\u00efve use of .replace.&nbsp; However, a much more interesting example using .replace involves using Sympy\u2019s \u2018Wild\u2019 symbol.&nbsp; The following snippet of the Jupyter notebook<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><a href=\"https:\/\/aristotle2digital.blogwyrm.com\/wp-content\/uploads\/2026\/06\/image-1.png\"><img loading=\"lazy\" decoding=\"async\" width=\"780\" height=\"143\" src=\"https:\/\/aristotle2digital.blogwyrm.com\/wp-content\/uploads\/2026\/06\/image-1.png\" alt=\"\" class=\"wp-image-1854\" srcset=\"https:\/\/aristotle2digital.blogwyrm.com\/wp-content\/uploads\/2026\/06\/image-1.png 780w, https:\/\/aristotle2digital.blogwyrm.com\/wp-content\/uploads\/2026\/06\/image-1-300x55.png 300w, https:\/\/aristotle2digital.blogwyrm.com\/wp-content\/uploads\/2026\/06\/image-1-768x141.png 768w\" sizes=\"auto, (max-width: 780px) 100vw, 780px\" \/><\/a><\/figure><\/div>\n\n\n<p>shows how .replace can substitute the sym.cos node with a sym.sin node without affecting the leaves and branches of the tree underneath.&nbsp; That\u2019s why every instance of $\\cos$ changes to $\\sin$ regardless of whether the argument was $b$, $x$, or $x^2$.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Final Thoughts<\/h2>\n\n\n\n<p>There are a number of variations and nuances that haven\u2019t been covered above but I believe that with the material provided there is enough structure that the Sympy documentation is consumable and a person who understands the material so far should be able to reach the manipulations they want with only some limited trial-and-error.&nbsp; That said there are two nuances that are worth noting.&nbsp; First, .subs is aware of what Sympy calls bound variables.&nbsp; Bound variables are those that appear, for example, as part of a sum or integral; .subs will not allow them to be rewritten while .xreplace will \u2013 again because .subs has some notion of mathematical semantics whereas .xreplace is simply for changing the tree regardless of syntax.&nbsp; The other is that .replace can take functions as arguments so that complex selection of subexpressions can be done.&nbsp; It is that latter functionality that we will try to use as we finally return to our main goal of having a Fourier transform rewriting system.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>After many months of build-up, we are now in a position to begin methodically exploring how to modify Sympy expression trees that we have defined earlier.&nbsp; Since Sympy expressions are,&#8230; <a class=\"read-more-button\" href=\"https:\/\/aristotle2digital.blogwyrm.com\/?p=1852\">Read more &gt;<\/a><\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-1852","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/aristotle2digital.blogwyrm.com\/index.php?rest_route=\/wp\/v2\/posts\/1852","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/aristotle2digital.blogwyrm.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/aristotle2digital.blogwyrm.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/aristotle2digital.blogwyrm.com\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/aristotle2digital.blogwyrm.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=1852"}],"version-history":[{"count":5,"href":"https:\/\/aristotle2digital.blogwyrm.com\/index.php?rest_route=\/wp\/v2\/posts\/1852\/revisions"}],"predecessor-version":[{"id":1859,"href":"https:\/\/aristotle2digital.blogwyrm.com\/index.php?rest_route=\/wp\/v2\/posts\/1852\/revisions\/1859"}],"wp:attachment":[{"href":"https:\/\/aristotle2digital.blogwyrm.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=1852"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/aristotle2digital.blogwyrm.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=1852"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/aristotle2digital.blogwyrm.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=1852"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}