{"id":1771,"date":"2025-12-26T22:00:00","date_gmt":"2025-12-27T03:00:00","guid":{"rendered":"https:\/\/aristotle2digital.blogwyrm.com\/?p=1771"},"modified":"2025-12-22T08:49:53","modified_gmt":"2025-12-22T13:49:53","slug":"a-symbolic-experiment-part-1-first-expression","status":"publish","type":"post","link":"https:\/\/aristotle2digital.blogwyrm.com\/?p=1771","title":{"rendered":"A Symbolic Experiment \u2013 Part 1:\u00a0 First Expression"},"content":{"rendered":"\n<p>One of the most active areas of artificial intelligence in the earlier days (say from 1960s through the 1990s) was the development of symbolic AI to handle mathematical manipulations.\u00a0 In his book, <em>Paradigms of Artificial Intelligence Programming: Case Studies in Common Lisp<\/em>, Peter Norvig covers numerous applications that were solved as the \u2018hot\u2019 topics of the day; a time before the before the advent of deep learning came along and convinced most people that LLM\u2019s and agentic systems would solve all the world\u2019s problems.\u00a0 However, these former hot topics are still relevant today and I thought that it might be interesting to explore a bit to see what can be done with \u2018old fashioned\u2019 symbolic manipulation.<\/p>\n\n\n\n<p>There are three reasons for embarking on this exploration.&nbsp;<\/p>\n\n\n\n<p>First, understanding the nuts and bolts of symbolic manipulation makes one a better user of the \u2018professional\u2019 computer algebra systems (CASs) on the market today, such as wxMaxima, Maple, Mathematica, and SymPy.&nbsp; Each of these is polished and abstracted (to varying degrees) and seeks to help the user, typically a mathematician, scientist, or engineer, in making a model and subsequently applying it to some specific problem.&nbsp; However, each of these systems (especially the for-profit ones), want the user to be able to solve problems immediately without, necessarily, knowing how the CAS works behind the scenes.&nbsp; While these systems are quite powerful (again to lesser or greater degrees), experience has shown that most users don\u2019t\/can\u2019t take full advantage of the system unless they can program in it.&nbsp; And to program in it requires a firm understanding of at least the rudiments of what is happening under the hood.&nbsp; This is a sentiment Norvig emphases repeatedly in his book, most notably by providing the following quote:<\/p>\n\n\n\n<div class = \"myQuoteDiv\">\n<p>You think you know when you learn, are more sure when you can write, even more when you can teach, but certain when you can program.<\/p>\n\n<p>&#8211;<em>Alan Perlis, Yale University computer scientist<\/em>\n<\/div>\n\n\n\n<p>Second, there are always new mathematics being invented with brand new rules.&nbsp; Being able to manipulate\/simplify and then mine an expression for meaning transcends blindly applying a built-in trig rule like $\\cos^2 + \\sin^2 = 1$, a generic \u2018simplify\u2019 method, or some such thing.&nbsp; It often requires understanding how an expression is formed and what techniques can be used to take an expression apart and reassemble as something more useful.<\/p>\n\n\n\n<p>Third, and finally, it\u2019s fun \u2013 plain and simple \u2013 and most likely will be a gateway activity for even more fun to come.<\/p>\n\n\n\n<p>Not that we\u2019ve resolved to explore, the next choice is which part of terra incognita.&nbsp; The undiscovered country that I\u2019ve chosen is the implementation of a simple set of symbolic rules, via pattern matching, that implement some of the basic properties of the Fourier Transform.<\/p>\n\n\n\n<p>For this first experiment, I chose Sympy as the tool of choice as it seemed a natural one since it provides the basic machinery of symbolic manipulation for free in Python but it doesn\u2019t have a particularly sophisticated set of rules associated with the Fourier Transform.&nbsp; For example, SymPy version 1.14 knows that the transform is linear but it doesn\u2019t know how to simplify the Fourier Transform based on the well-known rule:<\/p>\n\n\n\n<p>\\[ {\\mathcal F}\\left[ \\frac{\\partial f(t)}{\\partial t} \\right] = i \\omega {\\mathcal F}\\left[ f(t) \\right] \\; , \\]<\/p>\n\n\n\n<p>which is one of the most important relationships for the Fourier Transform as it allows us to convert differential equations into algebraic ones, which is one of the primary motivations for employing it (or any other integral transform for that matter).<\/p>\n\n\n\n<p>Before beginning, let\u2019s set some notation.&nbsp; Functions in the time domain will be denoted by lower case Latin letters (e.g., $f$, $g$, etc.) and will depend on the variable $t$.&nbsp; The corresponding Fourier Transform will be denoted by upper case Latin letters (e.g., $F$, $G$, etc.) and will depend on the variable $\\omega$. &nbsp;Arbitrary constants will also be denoted by lower case Latin letters but usually from the beginning of the alphabet (e.g., $a$, $b$, etc.). The pairing between the two will be symbolically written as:<\/p>\n\n\n\n<p>\\[ F(\\omega) = {\\mathcal F}(f(t)) \\; ,\\]<\/p>\n\n\n\n<p>with an analogous expression for the inverse.&nbsp; The sign convention will be chosen so that the relationship for the transform of the derivative is as given above.<\/p>\n\n\n\n<p>For the first experiment, I chose the following four rules\/properties of the Fourier Transform:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Linearity:\u00a0 ${\\mathcal F}(a \\cdot f(t) + b \\cdot g(t) ) = a F(\\omega) + b G(\\omega)$<\/li>\n\n\n\n<li>Differentiation: $\\mathcal{F}\\left[\\frac{d^n f(t)}{dt^n}\\right] = (i \\omega)^n F(\\omega)$<\/li>\n\n\n\n<li>Time Shifting:\u00a0 $\\mathcal{F}{f(t &#8211; t_0)} = e^{-i \\omega t_0} F(\\omega)$<\/li>\n\n\n\n<li>Frequency Shifting: $\\mathcal{F}{e^{i \\omega_0 t} f(t)} = F(\\omega &#8211; \\omega_0)$<\/li>\n<\/ol>\n\n\n\n<p>We expect freshman or, at worst, sophomores in college to absorb and apply the rules above and, so, we may be inclined to think that they are \u2018straightforward\u2019 or \u2018boring\u2019 or \u2018dull\u2019.&nbsp; But, finding a way to make a computer do algorithmically what we expect teenagers to pick up from a brief lecture and context is surprisingly involved.&nbsp;<\/p>\n\n\n\n<p>Our hypothetical college student\u2019s capacity to learn, even when not explicitly taught is an amazing and often overlooked miracle of the human animal.\u00a0 Unfortunately, teaching any computer to parse \u2018glyphs on a page\u2019 in a way that mimics what a person does requires a lot of introspection into just how the symbols are being interpreted.\u00a0 Mathematical expressions are slightly easier as they tend to have less \u2018analogical elasticity\u2019; that is to say, that by their very nature, mathematical terms and symbols tend to be more rigid that everyday speech.\u00a0 More rigid doesn\u2019t mean completely free of ambiguities as the reader may reflect on when thinking about what the derivatives in the Euler-Lagrange equations actually mean:<\/p>\n\n\n\n<p>\\[ \\frac{d}{dt} \\left( \\frac{\\partial L}{\\partial {\\dot q}} \\right) &#8211; \\frac{\\partial L}{\\partial q} = 0 \\; . \\]<\/p>\n\n\n\n<p>Let\u2019s start with a simple mathematical expression that is needed for the Linearity property<\/p>\n\n\n\n<p>\\[ a \\cdot f(t) + &nbsp;b \\cdot g(t) \\; . \\]<\/p>\n\n\n\n<p>When composing this expression, a person dips into the standard glyphs of the English alphabet (10 of them to be precise) and simply writes them down.&nbsp; If pressed, the person may go onto say \u201cwhere $a$ and $b$ are constants and $f$ and $g$ are, as yet undefined functions of the time variable $t$\u201d.&nbsp; But the glyphs on the page remain all the same.&nbsp; For a computer, are the glyphs \u2018a\u2019 and \u2018b\u2019 of the same type as the glyphs \u2018f\u2019 and \u2018g\u2019?&nbsp; And where does \u2018(t)\u2019 figure in?&nbsp;<\/p>\n\n\n\n<p>SymPy\u2019s answer to this (which matches most of the other CASs) is that \u2018a\u2019, \u2018b\u2019, and \u2018t\u2019 are <strong>Symbols<\/strong> and \u2018f\u2019 and \u2018g\u2019 are undefined <strong>Functions<\/strong>.&nbsp; The bold-face terms are syntactically how SymPy creates these symbolic objects. These objects can be used as ordinary Python objects with all the normal Python syntax (e.g., print(), len(), type(), etc.) coming along because SymPy tries to strictly adhere to the Python data model.&nbsp; As a result, we can form new expressions by using \u2018+\u2019 and \u2018*\u2019 without worrying about how SymPy chooses to add and multiply it various objects together.<\/p>\n\n\n\n<p>The following figure shows the output of a Jupyter notebook that implements these simple steps.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><a href=\"http:\/\/aristotle2digital.blogwyrm.com\/wp-content\/uploads\/2025\/12\/A2D_12Dec_2025_First_SymPy_Expression_notebook.png\"><img loading=\"lazy\" decoding=\"async\" width=\"857\" height=\"725\" src=\"http:\/\/aristotle2digital.blogwyrm.com\/wp-content\/uploads\/2025\/12\/A2D_12Dec_2025_First_SymPy_Expression_notebook.png\" alt=\"\" class=\"wp-image-1769\" srcset=\"https:\/\/aristotle2digital.blogwyrm.com\/wp-content\/uploads\/2025\/12\/A2D_12Dec_2025_First_SymPy_Expression_notebook.png 857w, https:\/\/aristotle2digital.blogwyrm.com\/wp-content\/uploads\/2025\/12\/A2D_12Dec_2025_First_SymPy_Expression_notebook-300x254.png 300w, https:\/\/aristotle2digital.blogwyrm.com\/wp-content\/uploads\/2025\/12\/A2D_12Dec_2025_First_SymPy_Expression_notebook-768x650.png 768w, https:\/\/aristotle2digital.blogwyrm.com\/wp-content\/uploads\/2025\/12\/A2D_12Dec_2025_First_SymPy_Expression_notebook-810x685.png 810w\" sizes=\"auto, (max-width: 857px) 100vw, 857px\" \/><\/a><\/figure>\n\n\n\n<p>As expected, querying type(a) gives back sympy.core.symbol.Symbol and type(f) returns sympy.core.function.UndefinedFunction.&nbsp; And, as expected, we can form our first expression<\/p>\n\n\n\n<div class=\"myQuoteDiv\">my_expr = a*f(t) + b*g(t)<\/div>\n\n\n\n<p>from using \u2018+\u2019 and \u2018*\u2019 as effortlessly as we wrote the analogous expression above out of basic glyphs, without having to worry about details.&nbsp; But what to make of type(my_expr) returning sympy.core.add.Add?<\/p>\n\n\n\n<p>The answer to this question gets at the heart of how most (if not all) CASs work.\u00a0 What we humans take for granted as a simple expression $a \\cdot f(t) + b \\cdot g(t)$ is, for SymPy (and all the other CASs that I\u2019ve seen), a tree.\u00a0 The top node is this case is Add meaning that \u2018+\u2019 is the root and each of the two subexpressions ($a \\cdot f(t)$ and $b \\cdot g(t)$) are child nodes, each of type sympy.core.mul.Mul.\u00a0 SymPy symbols are atomic nodes that can only be root nodes or child nodes but can never serve as parent nodes.\u00a0 And the distinction between the <strong>Symbol<\/strong> and <strong>Function<\/strong> objects are now much clearer: giving a glyph the designation as a <strong>Function<\/strong> means it can serve as a parent node, even if all of its behavior is, as yet, undefined.<\/p>\n\n\n\n<p>The innocent-looking expression from above has the tree-form<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><a href=\"http:\/\/aristotle2digital.blogwyrm.com\/wp-content\/uploads\/2025\/12\/A2D_12Dec_2025_First_SymPy_Expression_tree.png\"><img loading=\"lazy\" decoding=\"async\" width=\"710\" height=\"857\" src=\"http:\/\/aristotle2digital.blogwyrm.com\/wp-content\/uploads\/2025\/12\/A2D_12Dec_2025_First_SymPy_Expression_tree.png\" alt=\"\" class=\"wp-image-1770\" srcset=\"https:\/\/aristotle2digital.blogwyrm.com\/wp-content\/uploads\/2025\/12\/A2D_12Dec_2025_First_SymPy_Expression_tree.png 710w, https:\/\/aristotle2digital.blogwyrm.com\/wp-content\/uploads\/2025\/12\/A2D_12Dec_2025_First_SymPy_Expression_tree-249x300.png 249w\" sizes=\"auto, (max-width: 710px) 100vw, 710px\" \/><\/a><\/figure>\n\n\n\n<p>Next month, we\u2019ll continue on to show how to examine, traverse, and modify this tree structure so that we can mimic how a human \u2018plays with\u2019 and \u2018mine meaning from\u2019 an expression.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>One of the most active areas of artificial intelligence in the earlier days (say from 1960s through the 1990s) was the development of symbolic AI to handle mathematical manipulations.\u00a0 In&#8230; <a class=\"read-more-button\" href=\"https:\/\/aristotle2digital.blogwyrm.com\/?p=1771\">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-1771","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/aristotle2digital.blogwyrm.com\/index.php?rest_route=\/wp\/v2\/posts\/1771","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=1771"}],"version-history":[{"count":12,"href":"https:\/\/aristotle2digital.blogwyrm.com\/index.php?rest_route=\/wp\/v2\/posts\/1771\/revisions"}],"predecessor-version":[{"id":1783,"href":"https:\/\/aristotle2digital.blogwyrm.com\/index.php?rest_route=\/wp\/v2\/posts\/1771\/revisions\/1783"}],"wp:attachment":[{"href":"https:\/\/aristotle2digital.blogwyrm.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=1771"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/aristotle2digital.blogwyrm.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=1771"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/aristotle2digital.blogwyrm.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=1771"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}