{"id":1861,"date":"2026-07-31T22:00:00","date_gmt":"2026-08-01T02:00:00","guid":{"rendered":"https:\/\/aristotle2digital.blogwyrm.com\/?p=1861"},"modified":"2026-06-29T09:37:12","modified_gmt":"2026-06-29T13:37:12","slug":"a-symbolic-experiment-part-7-derivative-rewriting","status":"publish","type":"post","link":"https:\/\/aristotle2digital.blogwyrm.com\/?p=1861","title":{"rendered":"A Symbolic Experiment \u2013 Part 7: Derivative Rewriting"},"content":{"rendered":"\n<p>With all of the elementary ingredients for term rewriting for generic expressions in Sympy in hand, we now turn to a specialized but important corner: rewriting expressions involving a derivative.&nbsp; What we specifically want to do is to implement the Fourier differentiation rule<\/p>\n\n\n\n<p>\\[ {\\mathcal F} \\left[ \\frac{d^n f(t)}{d t^n} \\right] = (i \\omega)^n F(\\omega) \\; ,\\]<\/p>\n\n\n\n<p>where the two functions $f(t)$ and $F(\\omega)$ are members of a Fourier transform pair.<\/p>\n\n\n\n<p>The steps involved here are a bit different in than the earlier term rewriting rules covered because even the simplest derivative is a complex expression involving a function, its arguments, the notion of a limit ratio, the number of times a derivative is to be taken (i.e., the value of $n$ in the formula above), and what terms are kept constant.<\/p>\n\n\n\n<p>For instance, the expression<\/p>\n\n\n\n<p>\\[ \\frac{d}{dx} f(x) \\; \\]<\/p>\n\n\n\n<p>has the tree representation of<\/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-2.png\"><img loading=\"lazy\" decoding=\"async\" width=\"196\" height=\"288\" src=\"https:\/\/aristotle2digital.blogwyrm.com\/wp-content\/uploads\/2026\/06\/image-2.png\" alt=\"\" class=\"wp-image-1862\"\/><\/a><\/figure><\/div>\n\n\n<p>where the value of $n$ is held in the Sympy Tuple $(x,1)$, which is a specialized Sympy container designer to look like a conventional Tuple but whose elements are limited to Sympy objects.&nbsp; Likewise the expression<\/p>\n\n\n\n<p>\\[ \\frac{\\partial^3}{\\partial y^2 \\partial x} h(x,y) \\; \\]<\/p>\n\n\n\n<p>corresponds to the following tree diagram<\/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-3.png\"><img loading=\"lazy\" decoding=\"async\" width=\"397\" height=\"280\" src=\"https:\/\/aristotle2digital.blogwyrm.com\/wp-content\/uploads\/2026\/06\/image-3.png\" alt=\"\" class=\"wp-image-1863\" srcset=\"https:\/\/aristotle2digital.blogwyrm.com\/wp-content\/uploads\/2026\/06\/image-3.png 397w, https:\/\/aristotle2digital.blogwyrm.com\/wp-content\/uploads\/2026\/06\/image-3-300x212.png 300w\" sizes=\"auto, (max-width: 397px) 100vw, 397px\" \/><\/a><\/figure><\/div>\n\n\n<p>Note that there are two instances of the Sympy Tuple to hold the number of derivatives with respect to $x$ and $y$ separately.<\/p>\n\n\n\n<p>With so many moving pieces it shouldn\u2019t come as a surprise that the Derivative objects in Sympy come equipped with a few extra functions.&nbsp; The ones we will need to implement the Fourier derivative rule are:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>.derivative_count \u2013 counts the number of times a derivative operator is applied regardless of the variable.\u00a0 Returns 1 for the first expression above and 3 for the second.<\/li>\n\n\n\n<li>.variable_count \u2013 returns a tuple (not a Sympy Tuple) containing the instances of Sympy Tuple used in the expression.\u00a0 Returns $(x,1)$ for the first expression above and $(y,2)$ for the second.<\/li>\n\n\n\n<li>.variables \u2013 returns a tuple (not a Sympy Tuple) containing the variables used in the differentiation, repeated as specified in .variable count.\u00a0 Returns $(x,)$ for the first expression above and $(x,y,y)$ for the second.\u00a0 Variables that are not involved in the Derivative are treated as constants and do not show up (although they will still show up in .args or .atoms())<\/li>\n<\/ul>\n\n\n\n<p>The key term rewriting function is .replace() and, as alluded to in the end of the previous post, we will be passing anonymous lambda functions to it.&nbsp;<\/p>\n\n\n\n<p>To better understand why this is the proper method of attack, we can look at what .replace actually does.\u00a0 The following is an adaptation of <a href=\"https:\/\/docs.sympy.org\/latest\/modules\/core.html#sympy.core.basic.Basic.replace\">Sympy\u2019s own documentation on .replace<\/a> and the Stack Overflow discussion <a href=\"https:\/\/stackoverflow.com\/questions\/56584025\/sympy-subs-vs-replace-vs-xreplace\">Sympy subs vs replace vs xreplace<\/a>.\u00a0 The proper pattern of the .replace function is:<\/p>\n\n\n\n<div class=\"myQuoteDiv\"><preformatted><p>.replace(query, value, map=False, simultaneous=True, exact=None)<\/p><\/preformatted><\/div>\n\n\n\n<p>As .replace walks across the expression tree at each node it runs the provided <strong><em>query<\/em><\/strong>.&nbsp; If that application of <strong><em>query<\/em><\/strong> returns true then that particular node will be replaced with the provided <strong><em>value<\/em><\/strong>.&nbsp; Our strategy will be to make two passes over the expression tree:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>In the first pass, we will query if the node is of type Derivative.\u00a0 If it is we will make the substitution that $\\frac{d^n}{dt^n} f(t) \\rightarrow (i t)^n f(t)$.<\/li>\n\n\n\n<li>In the second pass, we will replace each instance of $t$ by $\\omega$ and each instance of $f$ with $F$.<\/li>\n<\/ol>\n\n\n\n<h2 class=\"wp-block-heading\">Pass 1<\/h2>\n\n\n\n<p>For Pass 1, the <strong><em>query<\/em><\/strong> is given by the lambda function:<\/p>\n\n\n\n<div class=\"myQuoteDiv\"><preformatted><p>is_deriv = lambda e: isinstance(e, sym.Derivative)<\/p><\/preformatted><\/div>\n\n\n\n<p>The <strong><em>value<\/em><\/strong> is a bit more involved and is given by<\/p>\n\n\n\n<div class=\"myQuoteDiv\"><preformatted><p>val&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = lambda e: sym.Mul(e.expr, *[sym.I*v for v,n in e.variable_count for _ in range(n)])<\/p><\/preformatted><\/div>\n\n\n\n<p>To understand this code, lets look at the related list comprehension<\/p>\n\n\n\n<div class=\"myQuoteDiv\"><preformatted><p>[v for v,n in e.variable_count for _ in range(n)]<\/p><\/preformatted><\/div>\n\n\n\n<p>This list comprehension is basically a nested for loop.&nbsp; The outer loop unpacks the expression <strong><em>e<\/em><\/strong>\u2019s .variable_count tuple into the two variables <strong><em>v<\/em><\/strong> and <strong><em>n<\/em><\/strong> while the inner loop writes <strong><em>v<\/em><\/strong>\u2019s value <strong><em>n<\/em><\/strong> times in the list. &nbsp;For the first expression above the resulting list is [$x$] while it is [$x$,$y$,$y$] for the second one.<\/p>\n\n\n\n<p>The actual list comprehension used in the value portion of .replace multiplies each term by $i=\\sqrt{-1}$, giving the lists [$ix$] &nbsp;and [$ix$,$iy$,$iy$] for the first and second expressions above.&nbsp; The splat\/unpacking operator \u2018*\u2019 removes the list container making the arguments acceptable to Mul.<\/p>\n\n\n\n<p>In symbolic form, the value transforms<\/p>\n\n\n\n<p>\\[ \\frac{d}{dx} f(x) \\rightarrow \\imath x f(x) \\; \\]<\/p>\n\n\n\n<p>and<\/p>\n\n\n\n<p>\\[ \\frac{\\partial^3}{\\partial y^2 \\partial x} h(x,y) \\rightarrow -\\imath x y^2 h(x,y) \\; .\\]<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Pass 2<\/h2>\n\n\n\n<p>For Pass 2, the elementary term rewriting rules discussed in the previous post can be followed without any difficulty by using .subs with a dictionary that maps variable and function pairings to each other.<\/p>\n\n\n\n<div class=\"myQuoteDiv\"><preformatted>\n<p>def Fderiv_subs(expr,pairs):\n&nbsp;&nbsp;&nbsp;&nbsp;temp1 = expr.replace(is_deriv,val)\n&nbsp;&nbsp;&nbsp;&nbsp;return temp1.subs(pairs)\n<\/p><\/preformatted><\/div>\n\n\n\n<p>For the first expression, suppose we Fourier pair $t$ and $\\omega$ and $f$ and $F$, then the invocation<\/p>\n\n\n\n<p>simp1 = sym.diff(f(t),t)<\/p>\n\n\n\n<div class=\"myQuoteDiv\"><preformatted><p>simp1 = sym.diff(f(t),t)\ndisplay(Fderiv_subs(simp1,{t:w,f:F}))<\/p><\/preformatted><\/div>\n\n\n\n<p>gives the desired transformation<\/p>\n\n\n\n<p>\\[ \\frac{d}{dt} f(t) \\rightarrow \\imath \\omega F(\\omega) \\; .\\]<\/p>\n\n\n\n<p>With a bit more generalization more complex Fourier pairings can also be accommodated.&nbsp;<\/p>\n\n\n\n<p>In the next post, we\u2019ll put all these pieces together to complete the Fourier term rewriting project embarked upon at the beginning of this series.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>With all of the elementary ingredients for term rewriting for generic expressions in Sympy in hand, we now turn to a specialized but important corner: rewriting expressions involving a derivative.&nbsp;&#8230; <a class=\"read-more-button\" href=\"https:\/\/aristotle2digital.blogwyrm.com\/?p=1861\">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-1861","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/aristotle2digital.blogwyrm.com\/index.php?rest_route=\/wp\/v2\/posts\/1861","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=1861"}],"version-history":[{"count":5,"href":"https:\/\/aristotle2digital.blogwyrm.com\/index.php?rest_route=\/wp\/v2\/posts\/1861\/revisions"}],"predecessor-version":[{"id":1868,"href":"https:\/\/aristotle2digital.blogwyrm.com\/index.php?rest_route=\/wp\/v2\/posts\/1861\/revisions\/1868"}],"wp:attachment":[{"href":"https:\/\/aristotle2digital.blogwyrm.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=1861"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/aristotle2digital.blogwyrm.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=1861"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/aristotle2digital.blogwyrm.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=1861"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}