diff --git a/examples/ipython/tutorial_calculus.ipynb b/examples/ipython/tutorial_calculus.ipynb new file mode 100644 index 00000000..313bca65 --- /dev/null +++ b/examples/ipython/tutorial_calculus.ipynb @@ -0,0 +1,1669 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Geometric Calculus Tutorial" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "from sympy import symbols, sin, cos\n", + "from galgebra.ga import Ga\n", + "from galgebra.dop import Sdop, Pdop, DiffOpExpr\n", + "from galgebra.printer import latex\n", + "from IPython.core.display import Math, Markdown\n", + "import sys" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Differential Opperators\n", + "$$\n", + "\\newcommand{\\pdiff}[2]{\\bfrac{\\partial {#1}}{\\partial {#2}}}\n", + "\\newcommand{\\es}[1]{\\boldsymbol{e}_{#1}}\n", + "\\newcommand{\\bfrac}[2]{\\displaystyle\\frac{#1}{#2}}\n", + "$$\n", + "This is a tutorial to introduce you to scalar and multivector differential operators.\n", + "\n", + "To start with we will define the geometric algebra of a 3 dimensional Euclidaen vector space, `o3d`, with coordinates $x$, $y$, and $z$ and unit vectors $\\es{x}$, $\\es{y}$, and $\\es{z}$:" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "xyz = x, y, z = symbols('x y z', real=True)\n", + "o3d = Ga('e_x e_y e_z', g = [1,1,1], coords=xyz)\n", + "ex, ey, ez = o3d.mv()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Once `o3d` is instantiated we can then define the basic partial derivative operators shown as `pDx`$= \\pdiff{}{x}$, `pDy`$= \\pdiff{}{y}$, and `pDz`$= \\pdiff{}{z}$ below." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "pDx = Pdop(x)\n", + "pDy = Pdop(y)\n", + "pDz = Pdop(z)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Also defined is the gradient operator ($\\nabla$), `o3d.grad`:" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "data": { + "text/latex": [ + "\\begin{equation*} \\boldsymbol{e}_{x} \\frac{\\partial}{\\partial x} + \\boldsymbol{e}_{y} \\frac{\\partial}{\\partial y} + \\boldsymbol{e}_{z} \\frac{\\partial}{\\partial z} \\end{equation*}" + ], + "text/plain": [ + "e_x*D{x} + e_y*D{y} + e_z*D{z}" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "o3d.grad" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Note that when it comes to any kind of differential operators using parenthesis is essential.\n", + "Let `D` be a differential operator and `A` and `B` multivector functions.\n", + "The expression `D*(A*B)` is quite diffenent than `(D*A)*B`.\n", + "Theis is true even if `D` is a simple derivative.\n", + "In the first case we need to use the chain rule but not in the second case.\n", + "For later consideration note that $\\nabla (FG) \\neq (\\nabla F)G + F(\\nabla G)$ because the multivector parts of $\\nabla$ and $F$ do not commute.\n", + "Hestenes developed the \"dot\" notation to resolve this problem so that $\\nabla (FG) = \\nabla FG + \\dot{\\nabla}F\\dot{G}$.\n", + "The dot indicates that the partial derivatives in $\\nabla$ should be applied to $G$ but not $F$ while preserving the order of the geometric or other products (an equivalent to the dot notation has not yet been implemented in galgebra).\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Scalar Differential Operators\n", + "\n", + "We start by illustrating the interoperability of `Pdop` and `Sdop` operators and scalar functions." + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": { + "scrolled": true + }, + "outputs": [], + "source": [ + "import operator\n", + "\n", + "ops = [\n", + " ('+', operator.add),\n", + " ('-', operator.sub),\n", + " ('*', operator.mul),\n", + "]" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "data": { + "text/markdown": [ + "### The ``+`` operator" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/latex": [ + "$\\displaystyle \\underbrace{\\left(\\frac{\\partial}{\\partial x}\\right)}_\\text{Pdop} + \\underbrace{\\left(\\frac{\\partial}{\\partial x}\\right)}_\\text{Pdop} = \\underbrace{2 \\frac{\\partial}{\\partial x}}_\\text{op}$" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/latex": [ + "$\\displaystyle \\underbrace{\\left(\\frac{\\partial}{\\partial x}\\right)}_\\text{Pdop} + \\underbrace{\\left(\\frac{\\partial}{\\partial x} + \\frac{\\partial}{\\partial y} + \\frac{\\partial}{\\partial z}\\right)}_\\text{Sdop} = \\underbrace{2 \\frac{\\partial}{\\partial x} + \\frac{\\partial}{\\partial y} + \\frac{\\partial}{\\partial z}}_\\text{op}$" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/latex": [ + "$\\displaystyle \\underbrace{\\left(\\frac{\\partial}{\\partial x}\\right)}_\\text{Pdop} + \\underbrace{\\left(x^{2} + y^{2} + z^{2}\\right)}_\\text{f(x,y,z)} = \\underbrace{x^{2} + y^{2} + z^{2} + \\frac{\\partial}{\\partial x}}_\\text{op}$" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/latex": [ + "$\\displaystyle \\underbrace{\\left(\\frac{\\partial}{\\partial x} + \\frac{\\partial}{\\partial y} + \\frac{\\partial}{\\partial z}\\right)}_\\text{Sdop} + \\underbrace{\\left(\\frac{\\partial}{\\partial x}\\right)}_\\text{Pdop} = \\underbrace{2 \\frac{\\partial}{\\partial x} + \\frac{\\partial}{\\partial y} + \\frac{\\partial}{\\partial z}}_\\text{op}$" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/latex": [ + "$\\displaystyle \\underbrace{\\left(\\frac{\\partial}{\\partial x} + \\frac{\\partial}{\\partial y} + \\frac{\\partial}{\\partial z}\\right)}_\\text{Sdop} + \\underbrace{\\left(\\frac{\\partial}{\\partial x} + \\frac{\\partial}{\\partial y} + \\frac{\\partial}{\\partial z}\\right)}_\\text{Sdop} = \\underbrace{2 \\frac{\\partial}{\\partial x} + 2 \\frac{\\partial}{\\partial y} + 2 \\frac{\\partial}{\\partial z}}_\\text{op}$" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/latex": [ + "$\\displaystyle \\underbrace{\\left(\\frac{\\partial}{\\partial x} + \\frac{\\partial}{\\partial y} + \\frac{\\partial}{\\partial z}\\right)}_\\text{Sdop} + \\underbrace{\\left(x^{2} + y^{2} + z^{2}\\right)}_\\text{f(x,y,z)} = \\underbrace{x^{2} + y^{2} + z^{2} + \\frac{\\partial}{\\partial x} + \\frac{\\partial}{\\partial y} + \\frac{\\partial}{\\partial z}}_\\text{op}$" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/latex": [ + "$\\displaystyle \\underbrace{\\left(x^{2} + y^{2} + z^{2}\\right)}_\\text{f(x,y,z)} + \\underbrace{\\left(\\frac{\\partial}{\\partial x}\\right)}_\\text{Pdop} = \\underbrace{x^{2} + y^{2} + z^{2} + \\frac{\\partial}{\\partial x}}_\\text{op}$" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/latex": [ + "$\\displaystyle \\underbrace{\\left(x^{2} + y^{2} + z^{2}\\right)}_\\text{f(x,y,z)} + \\underbrace{\\left(\\frac{\\partial}{\\partial x} + \\frac{\\partial}{\\partial y} + \\frac{\\partial}{\\partial z}\\right)}_\\text{Sdop} = \\underbrace{x^{2} + y^{2} + z^{2} + \\frac{\\partial}{\\partial x} + \\frac{\\partial}{\\partial y} + \\frac{\\partial}{\\partial z}}_\\text{op}$" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/latex": [ + "$\\displaystyle \\underbrace{\\left(x^{2} + y^{2} + z^{2}\\right)}_\\text{f(x,y,z)} + \\underbrace{\\left(x^{2} + y^{2} + z^{2}\\right)}_\\text{f(x,y,z)} = \\underbrace{2 x^{2} + 2 y^{2} + 2 z^{2}}_\\text{Add}$" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/markdown": [ + "### The ``-`` operator" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/latex": [ + "$\\displaystyle \\underbrace{\\left(\\frac{\\partial}{\\partial x}\\right)}_\\text{Pdop} - \\underbrace{\\left(\\frac{\\partial}{\\partial x}\\right)}_\\text{Pdop} = \\underbrace{DiffOpZero\\left(\\right)}_\\text{op}$" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/latex": [ + "$\\displaystyle \\underbrace{\\left(\\frac{\\partial}{\\partial x}\\right)}_\\text{Pdop} - \\underbrace{\\left(\\frac{\\partial}{\\partial x} + \\frac{\\partial}{\\partial y} + \\frac{\\partial}{\\partial z}\\right)}_\\text{Sdop} = \\underbrace{\\frac{\\partial}{\\partial x} - \\left(\\frac{\\partial}{\\partial x} + \\frac{\\partial}{\\partial y} + \\frac{\\partial}{\\partial z}\\right)}_\\text{op}$" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/latex": [ + "$\\displaystyle \\underbrace{\\left(\\frac{\\partial}{\\partial x}\\right)}_\\text{Pdop} - \\underbrace{\\left(x^{2} + y^{2} + z^{2}\\right)}_\\text{f(x,y,z)} = \\underbrace{- x^{2} + - y^{2} + - z^{2} + \\frac{\\partial}{\\partial x}}_\\text{op}$" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/latex": [ + "$\\displaystyle \\underbrace{\\left(\\frac{\\partial}{\\partial x} + \\frac{\\partial}{\\partial y} + \\frac{\\partial}{\\partial z}\\right)}_\\text{Sdop} - \\underbrace{\\left(\\frac{\\partial}{\\partial x}\\right)}_\\text{Pdop} = \\underbrace{\\frac{\\partial}{\\partial y} + \\frac{\\partial}{\\partial z}}_\\text{op}$" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/latex": [ + "$\\displaystyle \\underbrace{\\left(\\frac{\\partial}{\\partial x} + \\frac{\\partial}{\\partial y} + \\frac{\\partial}{\\partial z}\\right)}_\\text{Sdop} - \\underbrace{\\left(\\frac{\\partial}{\\partial x} + \\frac{\\partial}{\\partial y} + \\frac{\\partial}{\\partial z}\\right)}_\\text{Sdop} = \\underbrace{\\frac{\\partial}{\\partial x} + \\frac{\\partial}{\\partial y} + \\frac{\\partial}{\\partial z} - \\left(\\frac{\\partial}{\\partial x} + \\frac{\\partial}{\\partial y} + \\frac{\\partial}{\\partial z}\\right)}_\\text{op}$" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/latex": [ + "$\\displaystyle \\underbrace{\\left(\\frac{\\partial}{\\partial x} + \\frac{\\partial}{\\partial y} + \\frac{\\partial}{\\partial z}\\right)}_\\text{Sdop} - \\underbrace{\\left(x^{2} + y^{2} + z^{2}\\right)}_\\text{f(x,y,z)} = \\underbrace{- x^{2} + - y^{2} + - z^{2} + \\frac{\\partial}{\\partial x} + \\frac{\\partial}{\\partial y} + \\frac{\\partial}{\\partial z}}_\\text{op}$" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/latex": [ + "$\\displaystyle \\underbrace{\\left(x^{2} + y^{2} + z^{2}\\right)}_\\text{f(x,y,z)} - \\underbrace{\\left(\\frac{\\partial}{\\partial x}\\right)}_\\text{Pdop} = \\underbrace{x^{2} + y^{2} + z^{2} - \\frac{\\partial}{\\partial x}}_\\text{op}$" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/latex": [ + "$\\displaystyle \\underbrace{\\left(x^{2} + y^{2} + z^{2}\\right)}_\\text{f(x,y,z)} - \\underbrace{\\left(\\frac{\\partial}{\\partial x} + \\frac{\\partial}{\\partial y} + \\frac{\\partial}{\\partial z}\\right)}_\\text{Sdop} = \\underbrace{x^{2} + y^{2} + z^{2} - \\left(\\frac{\\partial}{\\partial x} + \\frac{\\partial}{\\partial y} + \\frac{\\partial}{\\partial z}\\right)}_\\text{op}$" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/latex": [ + "$\\displaystyle \\underbrace{\\left(x^{2} + y^{2} + z^{2}\\right)}_\\text{f(x,y,z)} - \\underbrace{\\left(x^{2} + y^{2} + z^{2}\\right)}_\\text{f(x,y,z)} = \\underbrace{0}_\\text{Zero}$" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/markdown": [ + "### The ``*`` operator" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/latex": [ + "$\\displaystyle \\underbrace{\\left(\\frac{\\partial}{\\partial x}\\right)}_\\text{Pdop} * \\underbrace{\\left(\\frac{\\partial}{\\partial x}\\right)}_\\text{Pdop} = \\underbrace{\\frac{\\partial^{2}}{\\partial x^{2}}}_\\text{op}$" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/latex": [ + "$\\displaystyle \\underbrace{\\left(\\frac{\\partial}{\\partial x}\\right)}_\\text{Pdop} * \\underbrace{\\left(\\frac{\\partial}{\\partial x} + \\frac{\\partial}{\\partial y} + \\frac{\\partial}{\\partial z}\\right)}_\\text{Sdop} = \\underbrace{\\frac{\\partial^{2}}{\\partial x^{2}} + \\frac{\\partial^{2}}{\\partial x\\partial y} + \\frac{\\partial^{2}}{\\partial x\\partial z}}_\\text{op}$" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/latex": [ + "$\\displaystyle \\underbrace{\\left(\\frac{\\partial}{\\partial x}\\right)}_\\text{Pdop} * \\underbrace{\\left(x^{2} + y^{2} + z^{2}\\right)}_\\text{f(x,y,z)} = \\underbrace{2 x}_\\text{Mul}$" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/latex": [ + "$\\displaystyle \\underbrace{\\left(\\frac{\\partial}{\\partial x} + \\frac{\\partial}{\\partial y} + \\frac{\\partial}{\\partial z}\\right)}_\\text{Sdop} * \\underbrace{\\left(\\frac{\\partial}{\\partial x}\\right)}_\\text{Pdop} = \\underbrace{\\frac{\\partial^{2}}{\\partial x^{2}} + \\frac{\\partial^{2}}{\\partial x\\partial y} + \\frac{\\partial^{2}}{\\partial x\\partial z}}_\\text{op}$" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/latex": [ + "$\\displaystyle \\underbrace{\\left(\\frac{\\partial}{\\partial x} + \\frac{\\partial}{\\partial y} + \\frac{\\partial}{\\partial z}\\right)}_\\text{Sdop} * \\underbrace{\\left(\\frac{\\partial}{\\partial x} + \\frac{\\partial}{\\partial y} + \\frac{\\partial}{\\partial z}\\right)}_\\text{Sdop} = \\underbrace{\\frac{\\partial^{2}}{\\partial x^{2}} + 2 \\frac{\\partial^{2}}{\\partial x\\partial y} + 2 \\frac{\\partial^{2}}{\\partial x\\partial z} + \\frac{\\partial^{2}}{\\partial y^{2}} + 2 \\frac{\\partial^{2}}{\\partial y\\partial z} + \\frac{\\partial^{2}}{\\partial z^{2}}}_\\text{op}$" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/latex": [ + "$\\displaystyle \\underbrace{\\left(\\frac{\\partial}{\\partial x} + \\frac{\\partial}{\\partial y} + \\frac{\\partial}{\\partial z}\\right)}_\\text{Sdop} * \\underbrace{\\left(x^{2} + y^{2} + z^{2}\\right)}_\\text{f(x,y,z)} = \\underbrace{2 x + 2 y + 2 z}_\\text{Add}$" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/latex": [ + "$\\displaystyle \\underbrace{\\left(x^{2} + y^{2} + z^{2}\\right)}_\\text{f(x,y,z)} * \\underbrace{\\left(\\frac{\\partial}{\\partial x}\\right)}_\\text{Pdop} = \\underbrace{\\left(x^{2} + y^{2} + z^{2}\\right) \\frac{\\partial}{\\partial x}}_\\text{op}$" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/latex": [ + "$\\displaystyle \\underbrace{\\left(x^{2} + y^{2} + z^{2}\\right)}_\\text{f(x,y,z)} * \\underbrace{\\left(\\frac{\\partial}{\\partial x} + \\frac{\\partial}{\\partial y} + \\frac{\\partial}{\\partial z}\\right)}_\\text{Sdop} = \\underbrace{\\left(x^{2} + y^{2} + z^{2}\\right) \\left(\\frac{\\partial}{\\partial x} + \\frac{\\partial}{\\partial y} + \\frac{\\partial}{\\partial z}\\right)}_\\text{op}$" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/latex": [ + "$\\displaystyle \\underbrace{\\left(x^{2} + y^{2} + z^{2}\\right)}_\\text{f(x,y,z)} * \\underbrace{\\left(x^{2} + y^{2} + z^{2}\\right)}_\\text{f(x,y,z)} = \\underbrace{\\left(x^{2} + y^{2} + z^{2}\\right)^{2}}_\\text{Pow}$" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "fxyz = x**2+y**2+z**2\n", + "dS = pDx + pDy + pDz\n", + "args = [('Pdop', pDx), ('Sdop', dS), ('f(x,y,z)', fxyz)]\n", + "\n", + "for op_name, op in ops:\n", + " display(Markdown(f\"### The ``{op_name}`` operator\"))\n", + " for t1, v1 in args:\n", + " for t2, v2 in args:\n", + " v = op(v1, v2)\n", + " display(Math(\n", + " fr'\\underbrace{{\\left({latex(v1)}\\right)}}_\\text{{{t1}}} {op_name} '\n", + " fr'\\underbrace{{\\left({latex(v2)}\\right)}}_\\text{{{t2}}} = '\n", + " fr'\\underbrace{{{latex(v)}}}_\\text{{{\"op\" if isinstance(v, DiffOpExpr) else type(v).__name__}}}'\n", + " ))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Multivector Differential Operators\n", + "\n", + "Now we illustrate the interoperability of `Pdop`, `Sdop`, and `Dop` operators and scalar and multivector functions." + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": { + "scrolled": false + }, + "outputs": [ + { + "data": { + "text/markdown": [ + "### The ``+`` operator" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/latex": [ + "$\\displaystyle \\underbrace{\\left(\\frac{\\partial}{\\partial x}\\right)}_\\text{Pdop} + \\underbrace{\\left(\\frac{\\partial}{\\partial x}\\right)}_\\text{Pdop} = \\underbrace{2 \\frac{\\partial}{\\partial x}}_\\text{op}$" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/latex": [ + "$\\displaystyle \\underbrace{\\left(\\frac{\\partial}{\\partial x}\\right)}_\\text{Pdop} + \\underbrace{\\left(\\frac{\\partial}{\\partial x} + \\frac{\\partial}{\\partial y} + \\frac{\\partial}{\\partial z}\\right)}_\\text{Sdop} = \\underbrace{2 \\frac{\\partial}{\\partial x} + \\frac{\\partial}{\\partial y} + \\frac{\\partial}{\\partial z}}_\\text{op}$" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/latex": [ + "$\\displaystyle \\underbrace{\\left(\\frac{\\partial}{\\partial x}\\right)}_\\text{Pdop} + \\underbrace{\\left(x^{2} + y^{2} + z^{2}\\right)}_\\text{f(x,y,z)} = \\underbrace{x^{2} + y^{2} + z^{2} + \\frac{\\partial}{\\partial x}}_\\text{op}$" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/latex": [ + "$\\displaystyle \\underbrace{\\left(\\frac{\\partial}{\\partial x}\\right)}_\\text{Pdop} + \\underbrace{\\left(\\boldsymbol{e}_{x} \\frac{\\partial}{\\partial x} + \\boldsymbol{e}_{y} \\frac{\\partial}{\\partial y} + \\boldsymbol{e}_{z} \\frac{\\partial}{\\partial z}\\right)}_\\text{Dop} = \\underbrace{\\frac{\\partial}{\\partial x} + \\boldsymbol{e}_{x} \\frac{\\partial}{\\partial x} + \\boldsymbol{e}_{y} \\frac{\\partial}{\\partial y} + \\boldsymbol{e}_{z} \\frac{\\partial}{\\partial z}}_\\text{Dop}$" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/latex": [ + "$\\displaystyle \\underbrace{\\left(\\frac{\\partial}{\\partial x}\\right)}_\\text{Pdop} + \\underbrace{\\left(x^{2} \\boldsymbol{e}_{x} + y^{2} \\boldsymbol{e}_{y} + z^{2} \\boldsymbol{e}_{z}\\right)}_\\text{Mv} = \\underbrace{\\frac{\\partial}{\\partial x} + \\boldsymbol{e}_{x} x^{2} + \\boldsymbol{e}_{y} y^{2} + \\boldsymbol{e}_{z} z^{2}}_\\text{Dop}$" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/latex": [ + "$\\displaystyle \\underbrace{\\left(\\frac{\\partial}{\\partial x} + \\frac{\\partial}{\\partial y} + \\frac{\\partial}{\\partial z}\\right)}_\\text{Sdop} + \\underbrace{\\left(\\frac{\\partial}{\\partial x}\\right)}_\\text{Pdop} = \\underbrace{2 \\frac{\\partial}{\\partial x} + \\frac{\\partial}{\\partial y} + \\frac{\\partial}{\\partial z}}_\\text{op}$" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/latex": [ + "$\\displaystyle \\underbrace{\\left(\\frac{\\partial}{\\partial x} + \\frac{\\partial}{\\partial y} + \\frac{\\partial}{\\partial z}\\right)}_\\text{Sdop} + \\underbrace{\\left(\\frac{\\partial}{\\partial x} + \\frac{\\partial}{\\partial y} + \\frac{\\partial}{\\partial z}\\right)}_\\text{Sdop} = \\underbrace{2 \\frac{\\partial}{\\partial x} + 2 \\frac{\\partial}{\\partial y} + 2 \\frac{\\partial}{\\partial z}}_\\text{op}$" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/latex": [ + "$\\displaystyle \\underbrace{\\left(\\frac{\\partial}{\\partial x} + \\frac{\\partial}{\\partial y} + \\frac{\\partial}{\\partial z}\\right)}_\\text{Sdop} + \\underbrace{\\left(x^{2} + y^{2} + z^{2}\\right)}_\\text{f(x,y,z)} = \\underbrace{x^{2} + y^{2} + z^{2} + \\frac{\\partial}{\\partial x} + \\frac{\\partial}{\\partial y} + \\frac{\\partial}{\\partial z}}_\\text{op}$" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/latex": [ + "$\\displaystyle \\underbrace{\\left(\\frac{\\partial}{\\partial x} + \\frac{\\partial}{\\partial y} + \\frac{\\partial}{\\partial z}\\right)}_\\text{Sdop} + \\underbrace{\\left(\\boldsymbol{e}_{x} \\frac{\\partial}{\\partial x} + \\boldsymbol{e}_{y} \\frac{\\partial}{\\partial y} + \\boldsymbol{e}_{z} \\frac{\\partial}{\\partial z}\\right)}_\\text{Dop} = \\underbrace{\\frac{\\partial}{\\partial x} + \\frac{\\partial}{\\partial y} + \\frac{\\partial}{\\partial z} + \\boldsymbol{e}_{x} \\frac{\\partial}{\\partial x} + \\boldsymbol{e}_{y} \\frac{\\partial}{\\partial y} + \\boldsymbol{e}_{z} \\frac{\\partial}{\\partial z}}_\\text{Dop}$" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/latex": [ + "$\\displaystyle \\underbrace{\\left(\\frac{\\partial}{\\partial x} + \\frac{\\partial}{\\partial y} + \\frac{\\partial}{\\partial z}\\right)}_\\text{Sdop} + \\underbrace{\\left(x^{2} \\boldsymbol{e}_{x} + y^{2} \\boldsymbol{e}_{y} + z^{2} \\boldsymbol{e}_{z}\\right)}_\\text{Mv} = \\underbrace{\\frac{\\partial}{\\partial x} + \\frac{\\partial}{\\partial y} + \\frac{\\partial}{\\partial z} + \\boldsymbol{e}_{x} x^{2} + \\boldsymbol{e}_{y} y^{2} + \\boldsymbol{e}_{z} z^{2}}_\\text{Dop}$" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/latex": [ + "$\\displaystyle \\underbrace{\\left(x^{2} + y^{2} + z^{2}\\right)}_\\text{f(x,y,z)} + \\underbrace{\\left(\\frac{\\partial}{\\partial x}\\right)}_\\text{Pdop} = \\underbrace{x^{2} + y^{2} + z^{2} + \\frac{\\partial}{\\partial x}}_\\text{op}$" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/latex": [ + "$\\displaystyle \\underbrace{\\left(x^{2} + y^{2} + z^{2}\\right)}_\\text{f(x,y,z)} + \\underbrace{\\left(\\frac{\\partial}{\\partial x} + \\frac{\\partial}{\\partial y} + \\frac{\\partial}{\\partial z}\\right)}_\\text{Sdop} = \\underbrace{x^{2} + y^{2} + z^{2} + \\frac{\\partial}{\\partial x} + \\frac{\\partial}{\\partial y} + \\frac{\\partial}{\\partial z}}_\\text{op}$" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/latex": [ + "$\\displaystyle \\underbrace{\\left(x^{2} + y^{2} + z^{2}\\right)}_\\text{f(x,y,z)} + \\underbrace{\\left(x^{2} + y^{2} + z^{2}\\right)}_\\text{f(x,y,z)} = \\underbrace{2 x^{2} + 2 y^{2} + 2 z^{2}}_\\text{Add}$" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/latex": [ + "$\\displaystyle \\underbrace{\\left(x^{2} + y^{2} + z^{2}\\right)}_\\text{f(x,y,z)} + \\underbrace{\\left(\\boldsymbol{e}_{x} \\frac{\\partial}{\\partial x} + \\boldsymbol{e}_{y} \\frac{\\partial}{\\partial y} + \\boldsymbol{e}_{z} \\frac{\\partial}{\\partial z}\\right)}_\\text{Dop} = \\underbrace{x^{2} + y^{2} + z^{2} + \\boldsymbol{e}_{x} \\frac{\\partial}{\\partial x} + \\boldsymbol{e}_{y} \\frac{\\partial}{\\partial y} + \\boldsymbol{e}_{z} \\frac{\\partial}{\\partial z}}_\\text{Dop}$" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/latex": [ + "$\\displaystyle \\underbrace{\\left(x^{2} + y^{2} + z^{2}\\right)}_\\text{f(x,y,z)} + \\underbrace{\\left(x^{2} \\boldsymbol{e}_{x} + y^{2} \\boldsymbol{e}_{y} + z^{2} \\boldsymbol{e}_{z}\\right)}_\\text{Mv} = \\underbrace{\\left ( x^{2} + y^{2} + z^{2}\\right ) + x^{2} \\boldsymbol{e}_{x} + y^{2} \\boldsymbol{e}_{y} + z^{2} \\boldsymbol{e}_{z}}_\\text{Mv}$" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/latex": [ + "$\\displaystyle \\underbrace{\\left(\\boldsymbol{e}_{x} \\frac{\\partial}{\\partial x} + \\boldsymbol{e}_{y} \\frac{\\partial}{\\partial y} + \\boldsymbol{e}_{z} \\frac{\\partial}{\\partial z}\\right)}_\\text{Dop} + \\underbrace{\\left(\\frac{\\partial}{\\partial x}\\right)}_\\text{Pdop} = \\underbrace{\\frac{\\partial}{\\partial x} + \\boldsymbol{e}_{x} \\frac{\\partial}{\\partial x} + \\boldsymbol{e}_{y} \\frac{\\partial}{\\partial y} + \\boldsymbol{e}_{z} \\frac{\\partial}{\\partial z}}_\\text{Dop}$" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/latex": [ + "$\\displaystyle \\underbrace{\\left(\\boldsymbol{e}_{x} \\frac{\\partial}{\\partial x} + \\boldsymbol{e}_{y} \\frac{\\partial}{\\partial y} + \\boldsymbol{e}_{z} \\frac{\\partial}{\\partial z}\\right)}_\\text{Dop} + \\underbrace{\\left(\\frac{\\partial}{\\partial x} + \\frac{\\partial}{\\partial y} + \\frac{\\partial}{\\partial z}\\right)}_\\text{Sdop} = \\underbrace{\\frac{\\partial}{\\partial x} + \\frac{\\partial}{\\partial y} + \\frac{\\partial}{\\partial z} + \\boldsymbol{e}_{x} \\frac{\\partial}{\\partial x} + \\boldsymbol{e}_{y} \\frac{\\partial}{\\partial y} + \\boldsymbol{e}_{z} \\frac{\\partial}{\\partial z}}_\\text{Dop}$" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/latex": [ + "$\\displaystyle \\underbrace{\\left(\\boldsymbol{e}_{x} \\frac{\\partial}{\\partial x} + \\boldsymbol{e}_{y} \\frac{\\partial}{\\partial y} + \\boldsymbol{e}_{z} \\frac{\\partial}{\\partial z}\\right)}_\\text{Dop} + \\underbrace{\\left(x^{2} + y^{2} + z^{2}\\right)}_\\text{f(x,y,z)} = \\underbrace{x^{2} + y^{2} + z^{2} + \\boldsymbol{e}_{x} \\frac{\\partial}{\\partial x} + \\boldsymbol{e}_{y} \\frac{\\partial}{\\partial y} + \\boldsymbol{e}_{z} \\frac{\\partial}{\\partial z}}_\\text{Dop}$" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/latex": [ + "$\\displaystyle \\underbrace{\\left(\\boldsymbol{e}_{x} \\frac{\\partial}{\\partial x} + \\boldsymbol{e}_{y} \\frac{\\partial}{\\partial y} + \\boldsymbol{e}_{z} \\frac{\\partial}{\\partial z}\\right)}_\\text{Dop} + \\underbrace{\\left(\\boldsymbol{e}_{x} \\frac{\\partial}{\\partial x} + \\boldsymbol{e}_{y} \\frac{\\partial}{\\partial y} + \\boldsymbol{e}_{z} \\frac{\\partial}{\\partial z}\\right)}_\\text{Dop} = \\underbrace{\\boldsymbol{e}_{x} 0 + \\boldsymbol{e}_{y} 0 + \\boldsymbol{e}_{z} 0}_\\text{Dop}$" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/latex": [ + "$\\displaystyle \\underbrace{\\left(\\boldsymbol{e}_{x} \\frac{\\partial}{\\partial x} + \\boldsymbol{e}_{y} \\frac{\\partial}{\\partial y} + \\boldsymbol{e}_{z} \\frac{\\partial}{\\partial z}\\right)}_\\text{Dop} + \\underbrace{\\left(x^{2} \\boldsymbol{e}_{x} + y^{2} \\boldsymbol{e}_{y} + z^{2} \\boldsymbol{e}_{z}\\right)}_\\text{Mv} = \\underbrace{\\boldsymbol{e}_{x} \\left ( x^{2} + \\frac{\\partial}{\\partial x}\\right ) + \\boldsymbol{e}_{y} \\left ( y^{2} + \\frac{\\partial}{\\partial y}\\right ) + \\boldsymbol{e}_{z} \\left ( z^{2} + \\frac{\\partial}{\\partial z}\\right ) }_\\text{Dop}$" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/latex": [ + "$\\displaystyle \\underbrace{\\left(x^{2} \\boldsymbol{e}_{x} + y^{2} \\boldsymbol{e}_{y} + z^{2} \\boldsymbol{e}_{z}\\right)}_\\text{Mv} + \\underbrace{\\left(\\frac{\\partial}{\\partial x}\\right)}_\\text{Pdop} = \\underbrace{\\frac{\\partial}{\\partial x} + \\boldsymbol{e}_{x} x^{2} + \\boldsymbol{e}_{y} y^{2} + \\boldsymbol{e}_{z} z^{2}}_\\text{Dop}$" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/latex": [ + "$\\displaystyle \\underbrace{\\left(x^{2} \\boldsymbol{e}_{x} + y^{2} \\boldsymbol{e}_{y} + z^{2} \\boldsymbol{e}_{z}\\right)}_\\text{Mv} + \\underbrace{\\left(\\frac{\\partial}{\\partial x} + \\frac{\\partial}{\\partial y} + \\frac{\\partial}{\\partial z}\\right)}_\\text{Sdop} = \\underbrace{\\frac{\\partial}{\\partial x} + \\frac{\\partial}{\\partial y} + \\frac{\\partial}{\\partial z} + \\boldsymbol{e}_{x} x^{2} + \\boldsymbol{e}_{y} y^{2} + \\boldsymbol{e}_{z} z^{2}}_\\text{Dop}$" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/latex": [ + "$\\displaystyle \\underbrace{\\left(x^{2} \\boldsymbol{e}_{x} + y^{2} \\boldsymbol{e}_{y} + z^{2} \\boldsymbol{e}_{z}\\right)}_\\text{Mv} + \\underbrace{\\left(x^{2} + y^{2} + z^{2}\\right)}_\\text{f(x,y,z)} = \\underbrace{\\left ( x^{2} + y^{2} + z^{2}\\right ) + x^{2} \\boldsymbol{e}_{x} + y^{2} \\boldsymbol{e}_{y} + z^{2} \\boldsymbol{e}_{z}}_\\text{Mv}$" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/latex": [ + "$\\displaystyle \\underbrace{\\left(x^{2} \\boldsymbol{e}_{x} + y^{2} \\boldsymbol{e}_{y} + z^{2} \\boldsymbol{e}_{z}\\right)}_\\text{Mv} + \\underbrace{\\left(\\boldsymbol{e}_{x} \\frac{\\partial}{\\partial x} + \\boldsymbol{e}_{y} \\frac{\\partial}{\\partial y} + \\boldsymbol{e}_{z} \\frac{\\partial}{\\partial z}\\right)}_\\text{Dop} = \\underbrace{\\boldsymbol{e}_{x} \\left ( x^{2} + \\frac{\\partial}{\\partial x}\\right ) + \\boldsymbol{e}_{y} \\left ( y^{2} + \\frac{\\partial}{\\partial y}\\right ) + \\boldsymbol{e}_{z} \\left ( z^{2} + \\frac{\\partial}{\\partial z}\\right ) }_\\text{Dop}$" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/latex": [ + "$\\displaystyle \\underbrace{\\left(x^{2} \\boldsymbol{e}_{x} + y^{2} \\boldsymbol{e}_{y} + z^{2} \\boldsymbol{e}_{z}\\right)}_\\text{Mv} + \\underbrace{\\left(x^{2} \\boldsymbol{e}_{x} + y^{2} \\boldsymbol{e}_{y} + z^{2} \\boldsymbol{e}_{z}\\right)}_\\text{Mv} = \\underbrace{2 x^{2} \\boldsymbol{e}_{x} + 2 y^{2} \\boldsymbol{e}_{y} + 2 z^{2} \\boldsymbol{e}_{z}}_\\text{Mv}$" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/markdown": [ + "### The ``-`` operator" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/latex": [ + "$\\displaystyle \\underbrace{\\left(\\frac{\\partial}{\\partial x}\\right)}_\\text{Pdop} - \\underbrace{\\left(\\frac{\\partial}{\\partial x}\\right)}_\\text{Pdop} = \\underbrace{DiffOpZero\\left(\\right)}_\\text{op}$" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/latex": [ + "$\\displaystyle \\underbrace{\\left(\\frac{\\partial}{\\partial x}\\right)}_\\text{Pdop} - \\underbrace{\\left(\\frac{\\partial}{\\partial x} + \\frac{\\partial}{\\partial y} + \\frac{\\partial}{\\partial z}\\right)}_\\text{Sdop} = \\underbrace{\\frac{\\partial}{\\partial x} - \\left(\\frac{\\partial}{\\partial x} + \\frac{\\partial}{\\partial y} + \\frac{\\partial}{\\partial z}\\right)}_\\text{op}$" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/latex": [ + "$\\displaystyle \\underbrace{\\left(\\frac{\\partial}{\\partial x}\\right)}_\\text{Pdop} - \\underbrace{\\left(x^{2} + y^{2} + z^{2}\\right)}_\\text{f(x,y,z)} = \\underbrace{- x^{2} + - y^{2} + - z^{2} + \\frac{\\partial}{\\partial x}}_\\text{op}$" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/latex": [ + "$\\displaystyle \\underbrace{\\left(\\frac{\\partial}{\\partial x}\\right)}_\\text{Pdop} - \\underbrace{\\left(\\boldsymbol{e}_{x} \\frac{\\partial}{\\partial x} + \\boldsymbol{e}_{y} \\frac{\\partial}{\\partial y} + \\boldsymbol{e}_{z} \\frac{\\partial}{\\partial z}\\right)}_\\text{Dop} = \\underbrace{\\frac{\\partial}{\\partial x} + \\boldsymbol{e}_{x} 0 + \\boldsymbol{e}_{y} 0 + \\boldsymbol{e}_{z} 0}_\\text{Dop}$" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/latex": [ + "$\\displaystyle \\underbrace{\\left(\\frac{\\partial}{\\partial x}\\right)}_\\text{Pdop} - \\underbrace{\\left(x^{2} \\boldsymbol{e}_{x} + y^{2} \\boldsymbol{e}_{y} + z^{2} \\boldsymbol{e}_{z}\\right)}_\\text{Mv} = \\underbrace{\\frac{\\partial}{\\partial x} -\\boldsymbol{e}_{x} x^{2} -\\boldsymbol{e}_{y} y^{2} -\\boldsymbol{e}_{z} z^{2}}_\\text{Dop}$" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/latex": [ + "$\\displaystyle \\underbrace{\\left(\\frac{\\partial}{\\partial x} + \\frac{\\partial}{\\partial y} + \\frac{\\partial}{\\partial z}\\right)}_\\text{Sdop} - \\underbrace{\\left(\\frac{\\partial}{\\partial x}\\right)}_\\text{Pdop} = \\underbrace{\\frac{\\partial}{\\partial y} + \\frac{\\partial}{\\partial z}}_\\text{op}$" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/latex": [ + "$\\displaystyle \\underbrace{\\left(\\frac{\\partial}{\\partial x} + \\frac{\\partial}{\\partial y} + \\frac{\\partial}{\\partial z}\\right)}_\\text{Sdop} - \\underbrace{\\left(\\frac{\\partial}{\\partial x} + \\frac{\\partial}{\\partial y} + \\frac{\\partial}{\\partial z}\\right)}_\\text{Sdop} = \\underbrace{\\frac{\\partial}{\\partial x} + \\frac{\\partial}{\\partial y} + \\frac{\\partial}{\\partial z} - \\left(\\frac{\\partial}{\\partial x} + \\frac{\\partial}{\\partial y} + \\frac{\\partial}{\\partial z}\\right)}_\\text{op}$" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/latex": [ + "$\\displaystyle \\underbrace{\\left(\\frac{\\partial}{\\partial x} + \\frac{\\partial}{\\partial y} + \\frac{\\partial}{\\partial z}\\right)}_\\text{Sdop} - \\underbrace{\\left(x^{2} + y^{2} + z^{2}\\right)}_\\text{f(x,y,z)} = \\underbrace{- x^{2} + - y^{2} + - z^{2} + \\frac{\\partial}{\\partial x} + \\frac{\\partial}{\\partial y} + \\frac{\\partial}{\\partial z}}_\\text{op}$" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/latex": [ + "$\\displaystyle \\underbrace{\\left(\\frac{\\partial}{\\partial x} + \\frac{\\partial}{\\partial y} + \\frac{\\partial}{\\partial z}\\right)}_\\text{Sdop} - \\underbrace{\\left(\\boldsymbol{e}_{x} \\frac{\\partial}{\\partial x} + \\boldsymbol{e}_{y} \\frac{\\partial}{\\partial y} + \\boldsymbol{e}_{z} \\frac{\\partial}{\\partial z}\\right)}_\\text{Dop} = \\underbrace{\\frac{\\partial}{\\partial x} + \\frac{\\partial}{\\partial y} + \\frac{\\partial}{\\partial z} + \\boldsymbol{e}_{x} 0 + \\boldsymbol{e}_{y} 0 + \\boldsymbol{e}_{z} 0}_\\text{Dop}$" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/latex": [ + "$\\displaystyle \\underbrace{\\left(\\frac{\\partial}{\\partial x} + \\frac{\\partial}{\\partial y} + \\frac{\\partial}{\\partial z}\\right)}_\\text{Sdop} - \\underbrace{\\left(x^{2} \\boldsymbol{e}_{x} + y^{2} \\boldsymbol{e}_{y} + z^{2} \\boldsymbol{e}_{z}\\right)}_\\text{Mv} = \\underbrace{\\frac{\\partial}{\\partial x} + \\frac{\\partial}{\\partial y} + \\frac{\\partial}{\\partial z} -\\boldsymbol{e}_{x} x^{2} -\\boldsymbol{e}_{y} y^{2} -\\boldsymbol{e}_{z} z^{2}}_\\text{Dop}$" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/latex": [ + "$\\displaystyle \\underbrace{\\left(x^{2} + y^{2} + z^{2}\\right)}_\\text{f(x,y,z)} - \\underbrace{\\left(\\frac{\\partial}{\\partial x}\\right)}_\\text{Pdop} = \\underbrace{x^{2} + y^{2} + z^{2} - \\frac{\\partial}{\\partial x}}_\\text{op}$" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/latex": [ + "$\\displaystyle \\underbrace{\\left(x^{2} + y^{2} + z^{2}\\right)}_\\text{f(x,y,z)} - \\underbrace{\\left(\\frac{\\partial}{\\partial x} + \\frac{\\partial}{\\partial y} + \\frac{\\partial}{\\partial z}\\right)}_\\text{Sdop} = \\underbrace{x^{2} + y^{2} + z^{2} - \\left(\\frac{\\partial}{\\partial x} + \\frac{\\partial}{\\partial y} + \\frac{\\partial}{\\partial z}\\right)}_\\text{op}$" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/latex": [ + "$\\displaystyle \\underbrace{\\left(x^{2} + y^{2} + z^{2}\\right)}_\\text{f(x,y,z)} - \\underbrace{\\left(x^{2} + y^{2} + z^{2}\\right)}_\\text{f(x,y,z)} = \\underbrace{0}_\\text{Zero}$" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/latex": [ + "$\\displaystyle \\underbrace{\\left(x^{2} + y^{2} + z^{2}\\right)}_\\text{f(x,y,z)} - \\underbrace{\\left(\\boldsymbol{e}_{x} \\frac{\\partial}{\\partial x} + \\boldsymbol{e}_{y} \\frac{\\partial}{\\partial y} + \\boldsymbol{e}_{z} \\frac{\\partial}{\\partial z}\\right)}_\\text{Dop} = \\underbrace{x^{2} + y^{2} + z^{2} + \\boldsymbol{e}_{x} 0 + \\boldsymbol{e}_{y} 0 + \\boldsymbol{e}_{z} 0}_\\text{Dop}$" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/latex": [ + "$\\displaystyle \\underbrace{\\left(x^{2} + y^{2} + z^{2}\\right)}_\\text{f(x,y,z)} - \\underbrace{\\left(x^{2} \\boldsymbol{e}_{x} + y^{2} \\boldsymbol{e}_{y} + z^{2} \\boldsymbol{e}_{z}\\right)}_\\text{Mv} = \\underbrace{\\left ( x^{2} + y^{2} + z^{2}\\right ) - x^{2} \\boldsymbol{e}_{x} - y^{2} \\boldsymbol{e}_{y} - z^{2} \\boldsymbol{e}_{z}}_\\text{Mv}$" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/latex": [ + "$\\displaystyle \\underbrace{\\left(\\boldsymbol{e}_{x} \\frac{\\partial}{\\partial x} + \\boldsymbol{e}_{y} \\frac{\\partial}{\\partial y} + \\boldsymbol{e}_{z} \\frac{\\partial}{\\partial z}\\right)}_\\text{Dop} - \\underbrace{\\left(\\frac{\\partial}{\\partial x}\\right)}_\\text{Pdop} = \\underbrace{0 + \\boldsymbol{e}_{x} \\frac{\\partial}{\\partial x} + \\boldsymbol{e}_{y} \\frac{\\partial}{\\partial y} + \\boldsymbol{e}_{z} \\frac{\\partial}{\\partial z}}_\\text{Dop}$" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/latex": [ + "$\\displaystyle \\underbrace{\\left(\\boldsymbol{e}_{x} \\frac{\\partial}{\\partial x} + \\boldsymbol{e}_{y} \\frac{\\partial}{\\partial y} + \\boldsymbol{e}_{z} \\frac{\\partial}{\\partial z}\\right)}_\\text{Dop} - \\underbrace{\\left(\\frac{\\partial}{\\partial x} + \\frac{\\partial}{\\partial y} + \\frac{\\partial}{\\partial z}\\right)}_\\text{Sdop} = \\underbrace{- \\frac{\\partial}{\\partial x} - \\frac{\\partial}{\\partial y} - \\frac{\\partial}{\\partial z} + \\boldsymbol{e}_{x} \\frac{\\partial}{\\partial x} + \\boldsymbol{e}_{y} \\frac{\\partial}{\\partial y} + \\boldsymbol{e}_{z} \\frac{\\partial}{\\partial z}}_\\text{Dop}$" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/latex": [ + "$\\displaystyle \\underbrace{\\left(\\boldsymbol{e}_{x} \\frac{\\partial}{\\partial x} + \\boldsymbol{e}_{y} \\frac{\\partial}{\\partial y} + \\boldsymbol{e}_{z} \\frac{\\partial}{\\partial z}\\right)}_\\text{Dop} - \\underbrace{\\left(x^{2} + y^{2} + z^{2}\\right)}_\\text{f(x,y,z)} = \\underbrace{- x^{2} - y^{2} - z^{2} + \\boldsymbol{e}_{x} \\frac{\\partial}{\\partial x} + \\boldsymbol{e}_{y} \\frac{\\partial}{\\partial y} + \\boldsymbol{e}_{z} \\frac{\\partial}{\\partial z}}_\\text{Dop}$" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/latex": [ + "$\\displaystyle \\underbrace{\\left(\\boldsymbol{e}_{x} \\frac{\\partial}{\\partial x} + \\boldsymbol{e}_{y} \\frac{\\partial}{\\partial y} + \\boldsymbol{e}_{z} \\frac{\\partial}{\\partial z}\\right)}_\\text{Dop} - \\underbrace{\\left(\\boldsymbol{e}_{x} \\frac{\\partial}{\\partial x} + \\boldsymbol{e}_{y} \\frac{\\partial}{\\partial y} + \\boldsymbol{e}_{z} \\frac{\\partial}{\\partial z}\\right)}_\\text{Dop} = \\underbrace{ 0 }_\\text{Dop}$" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/latex": [ + "$\\displaystyle \\underbrace{\\left(\\boldsymbol{e}_{x} \\frac{\\partial}{\\partial x} + \\boldsymbol{e}_{y} \\frac{\\partial}{\\partial y} + \\boldsymbol{e}_{z} \\frac{\\partial}{\\partial z}\\right)}_\\text{Dop} - \\underbrace{\\left(x^{2} \\boldsymbol{e}_{x} + y^{2} \\boldsymbol{e}_{y} + z^{2} \\boldsymbol{e}_{z}\\right)}_\\text{Mv} = \\underbrace{\\boldsymbol{e}_{x} \\left ( - x^{2} + \\frac{\\partial}{\\partial x}\\right ) + \\boldsymbol{e}_{y} \\left ( - y^{2} + \\frac{\\partial}{\\partial y}\\right ) + \\boldsymbol{e}_{z} \\left ( - z^{2} + \\frac{\\partial}{\\partial z}\\right ) }_\\text{Dop}$" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/latex": [ + "$\\displaystyle \\underbrace{\\left(x^{2} \\boldsymbol{e}_{x} + y^{2} \\boldsymbol{e}_{y} + z^{2} \\boldsymbol{e}_{z}\\right)}_\\text{Mv} - \\underbrace{\\left(\\frac{\\partial}{\\partial x}\\right)}_\\text{Pdop} = \\underbrace{0 + \\boldsymbol{e}_{x} x^{2} + \\boldsymbol{e}_{y} y^{2} + \\boldsymbol{e}_{z} z^{2}}_\\text{Dop}$" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/latex": [ + "$\\displaystyle \\underbrace{\\left(x^{2} \\boldsymbol{e}_{x} + y^{2} \\boldsymbol{e}_{y} + z^{2} \\boldsymbol{e}_{z}\\right)}_\\text{Mv} - \\underbrace{\\left(\\frac{\\partial}{\\partial x} + \\frac{\\partial}{\\partial y} + \\frac{\\partial}{\\partial z}\\right)}_\\text{Sdop} = \\underbrace{- \\frac{\\partial}{\\partial x} - \\frac{\\partial}{\\partial y} - \\frac{\\partial}{\\partial z} + \\boldsymbol{e}_{x} x^{2} + \\boldsymbol{e}_{y} y^{2} + \\boldsymbol{e}_{z} z^{2}}_\\text{Dop}$" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/latex": [ + "$\\displaystyle \\underbrace{\\left(x^{2} \\boldsymbol{e}_{x} + y^{2} \\boldsymbol{e}_{y} + z^{2} \\boldsymbol{e}_{z}\\right)}_\\text{Mv} - \\underbrace{\\left(x^{2} + y^{2} + z^{2}\\right)}_\\text{f(x,y,z)} = \\underbrace{\\left ( - x^{2} - y^{2} - z^{2}\\right ) + x^{2} \\boldsymbol{e}_{x} + y^{2} \\boldsymbol{e}_{y} + z^{2} \\boldsymbol{e}_{z}}_\\text{Mv}$" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/latex": [ + "$\\displaystyle \\underbrace{\\left(x^{2} \\boldsymbol{e}_{x} + y^{2} \\boldsymbol{e}_{y} + z^{2} \\boldsymbol{e}_{z}\\right)}_\\text{Mv} - \\underbrace{\\left(\\boldsymbol{e}_{x} \\frac{\\partial}{\\partial x} + \\boldsymbol{e}_{y} \\frac{\\partial}{\\partial y} + \\boldsymbol{e}_{z} \\frac{\\partial}{\\partial z}\\right)}_\\text{Dop} = \\underbrace{\\boldsymbol{e}_{x} \\left ( x^{2} - \\frac{\\partial}{\\partial x}\\right ) + \\boldsymbol{e}_{y} \\left ( y^{2} - \\frac{\\partial}{\\partial y}\\right ) + \\boldsymbol{e}_{z} \\left ( z^{2} - \\frac{\\partial}{\\partial z}\\right ) }_\\text{Dop}$" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/latex": [ + "$\\displaystyle \\underbrace{\\left(x^{2} \\boldsymbol{e}_{x} + y^{2} \\boldsymbol{e}_{y} + z^{2} \\boldsymbol{e}_{z}\\right)}_\\text{Mv} - \\underbrace{\\left(x^{2} \\boldsymbol{e}_{x} + y^{2} \\boldsymbol{e}_{y} + z^{2} \\boldsymbol{e}_{z}\\right)}_\\text{Mv} = \\underbrace{ 0 }_\\text{Mv}$" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/markdown": [ + "### The ``*`` operator" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/latex": [ + "$\\displaystyle \\underbrace{\\left(\\frac{\\partial}{\\partial x}\\right)}_\\text{Pdop} * \\underbrace{\\left(\\frac{\\partial}{\\partial x}\\right)}_\\text{Pdop} = \\underbrace{\\frac{\\partial^{2}}{\\partial x^{2}}}_\\text{op}$" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/latex": [ + "$\\displaystyle \\underbrace{\\left(\\frac{\\partial}{\\partial x}\\right)}_\\text{Pdop} * \\underbrace{\\left(\\frac{\\partial}{\\partial x} + \\frac{\\partial}{\\partial y} + \\frac{\\partial}{\\partial z}\\right)}_\\text{Sdop} = \\underbrace{\\frac{\\partial^{2}}{\\partial x^{2}} + \\frac{\\partial^{2}}{\\partial x\\partial y} + \\frac{\\partial^{2}}{\\partial x\\partial z}}_\\text{op}$" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/latex": [ + "$\\displaystyle \\underbrace{\\left(\\frac{\\partial}{\\partial x}\\right)}_\\text{Pdop} * \\underbrace{\\left(x^{2} + y^{2} + z^{2}\\right)}_\\text{f(x,y,z)} = \\underbrace{2 x}_\\text{Mul}$" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/latex": [ + "$\\displaystyle \\underbrace{\\left(\\frac{\\partial}{\\partial x}\\right)}_\\text{Pdop} * \\underbrace{\\left(\\boldsymbol{e}_{x} \\frac{\\partial}{\\partial x} + \\boldsymbol{e}_{y} \\frac{\\partial}{\\partial y} + \\boldsymbol{e}_{z} \\frac{\\partial}{\\partial z}\\right)}_\\text{Dop} = \\underbrace{\\boldsymbol{e}_{x} \\frac{\\partial^{2}}{\\partial x^{2}} + \\boldsymbol{e}_{y} \\frac{\\partial^{2}}{\\partial x\\partial y} + \\boldsymbol{e}_{z} \\frac{\\partial^{2}}{\\partial x\\partial z}}_\\text{Dop}$" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/latex": [ + "$\\displaystyle \\underbrace{\\left(\\frac{\\partial}{\\partial x}\\right)}_\\text{Pdop} * \\underbrace{\\left(x^{2} \\boldsymbol{e}_{x} + y^{2} \\boldsymbol{e}_{y} + z^{2} \\boldsymbol{e}_{z}\\right)}_\\text{Mv} = \\underbrace{\\frac{\\partial^{2}}{\\partial x^{2}}}_\\text{Dop}$" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/latex": [ + "$\\displaystyle \\underbrace{\\left(\\frac{\\partial}{\\partial x} + \\frac{\\partial}{\\partial y} + \\frac{\\partial}{\\partial z}\\right)}_\\text{Sdop} * \\underbrace{\\left(\\frac{\\partial}{\\partial x}\\right)}_\\text{Pdop} = \\underbrace{\\frac{\\partial^{2}}{\\partial x^{2}} + \\frac{\\partial^{2}}{\\partial x\\partial y} + \\frac{\\partial^{2}}{\\partial x\\partial z}}_\\text{op}$" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/latex": [ + "$\\displaystyle \\underbrace{\\left(\\frac{\\partial}{\\partial x} + \\frac{\\partial}{\\partial y} + \\frac{\\partial}{\\partial z}\\right)}_\\text{Sdop} * \\underbrace{\\left(\\frac{\\partial}{\\partial x} + \\frac{\\partial}{\\partial y} + \\frac{\\partial}{\\partial z}\\right)}_\\text{Sdop} = \\underbrace{\\frac{\\partial^{2}}{\\partial x^{2}} + 2 \\frac{\\partial^{2}}{\\partial x\\partial y} + 2 \\frac{\\partial^{2}}{\\partial x\\partial z} + \\frac{\\partial^{2}}{\\partial y^{2}} + 2 \\frac{\\partial^{2}}{\\partial y\\partial z} + \\frac{\\partial^{2}}{\\partial z^{2}}}_\\text{op}$" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/latex": [ + "$\\displaystyle \\underbrace{\\left(\\frac{\\partial}{\\partial x} + \\frac{\\partial}{\\partial y} + \\frac{\\partial}{\\partial z}\\right)}_\\text{Sdop} * \\underbrace{\\left(x^{2} + y^{2} + z^{2}\\right)}_\\text{f(x,y,z)} = \\underbrace{2 x + 2 y + 2 z}_\\text{Add}$" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/latex": [ + "$\\displaystyle \\underbrace{\\left(\\frac{\\partial}{\\partial x} + \\frac{\\partial}{\\partial y} + \\frac{\\partial}{\\partial z}\\right)}_\\text{Sdop} * \\underbrace{\\left(\\boldsymbol{e}_{x} \\frac{\\partial}{\\partial x} + \\boldsymbol{e}_{y} \\frac{\\partial}{\\partial y} + \\boldsymbol{e}_{z} \\frac{\\partial}{\\partial z}\\right)}_\\text{Dop} = \\underbrace{\\boldsymbol{e}_{x} \\left ( \\frac{\\partial^{2}}{\\partial x^{2}} + \\frac{\\partial^{2}}{\\partial x\\partial y} + \\frac{\\partial^{2}}{\\partial x\\partial z}\\right ) + \\boldsymbol{e}_{y} \\left ( \\frac{\\partial^{2}}{\\partial x\\partial y} + \\frac{\\partial^{2}}{\\partial y^{2}} + \\frac{\\partial^{2}}{\\partial y\\partial z}\\right ) + \\boldsymbol{e}_{z} \\left ( \\frac{\\partial^{2}}{\\partial x\\partial z} + \\frac{\\partial^{2}}{\\partial y\\partial z} + \\frac{\\partial^{2}}{\\partial z^{2}}\\right ) }_\\text{Dop}$" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/latex": [ + "$\\displaystyle \\underbrace{\\left(\\frac{\\partial}{\\partial x} + \\frac{\\partial}{\\partial y} + \\frac{\\partial}{\\partial z}\\right)}_\\text{Sdop} * \\underbrace{\\left(x^{2} \\boldsymbol{e}_{x} + y^{2} \\boldsymbol{e}_{y} + z^{2} \\boldsymbol{e}_{z}\\right)}_\\text{Mv} = \\underbrace{\\frac{\\partial^{2}}{\\partial x^{2}} + 2 \\frac{\\partial^{2}}{\\partial x\\partial y} + 2 \\frac{\\partial^{2}}{\\partial x\\partial z} + \\frac{\\partial^{2}}{\\partial y^{2}} + 2 \\frac{\\partial^{2}}{\\partial y\\partial z} + \\frac{\\partial^{2}}{\\partial z^{2}}}_\\text{Dop}$" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/latex": [ + "$\\displaystyle \\underbrace{\\left(x^{2} + y^{2} + z^{2}\\right)}_\\text{f(x,y,z)} * \\underbrace{\\left(\\frac{\\partial}{\\partial x}\\right)}_\\text{Pdop} = \\underbrace{\\left(x^{2} + y^{2} + z^{2}\\right) \\frac{\\partial}{\\partial x}}_\\text{op}$" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/latex": [ + "$\\displaystyle \\underbrace{\\left(x^{2} + y^{2} + z^{2}\\right)}_\\text{f(x,y,z)} * \\underbrace{\\left(\\frac{\\partial}{\\partial x} + \\frac{\\partial}{\\partial y} + \\frac{\\partial}{\\partial z}\\right)}_\\text{Sdop} = \\underbrace{\\left(x^{2} + y^{2} + z^{2}\\right) \\left(\\frac{\\partial}{\\partial x} + \\frac{\\partial}{\\partial y} + \\frac{\\partial}{\\partial z}\\right)}_\\text{op}$" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/latex": [ + "$\\displaystyle \\underbrace{\\left(x^{2} + y^{2} + z^{2}\\right)}_\\text{f(x,y,z)} * \\underbrace{\\left(x^{2} + y^{2} + z^{2}\\right)}_\\text{f(x,y,z)} = \\underbrace{\\left(x^{2} + y^{2} + z^{2}\\right)^{2}}_\\text{Pow}$" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/latex": [ + "$\\displaystyle \\underbrace{\\left(x^{2} + y^{2} + z^{2}\\right)}_\\text{f(x,y,z)} * \\underbrace{\\left(\\boldsymbol{e}_{x} \\frac{\\partial}{\\partial x} + \\boldsymbol{e}_{y} \\frac{\\partial}{\\partial y} + \\boldsymbol{e}_{z} \\frac{\\partial}{\\partial z}\\right)}_\\text{Dop} = \\underbrace{\\boldsymbol{e}_{x} 0 + \\boldsymbol{e}_{y} 0 + \\boldsymbol{e}_{z} 0}_\\text{Dop}$" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/latex": [ + "$\\displaystyle \\underbrace{\\left(x^{2} + y^{2} + z^{2}\\right)}_\\text{f(x,y,z)} * \\underbrace{\\left(x^{2} \\boldsymbol{e}_{x} + y^{2} \\boldsymbol{e}_{y} + z^{2} \\boldsymbol{e}_{z}\\right)}_\\text{Mv} = \\underbrace{x^{2} \\left(x^{2} + y^{2} + z^{2}\\right) \\boldsymbol{e}_{x} + y^{2} \\left(x^{2} + y^{2} + z^{2}\\right) \\boldsymbol{e}_{y} + z^{2} \\left(x^{2} + y^{2} + z^{2}\\right) \\boldsymbol{e}_{z}}_\\text{Mv}$" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/latex": [ + "$\\displaystyle \\underbrace{\\left(\\boldsymbol{e}_{x} \\frac{\\partial}{\\partial x} + \\boldsymbol{e}_{y} \\frac{\\partial}{\\partial y} + \\boldsymbol{e}_{z} \\frac{\\partial}{\\partial z}\\right)}_\\text{Dop} * \\underbrace{\\left(\\frac{\\partial}{\\partial x}\\right)}_\\text{Pdop} = \\underbrace{\\boldsymbol{e}_{x} \\frac{\\partial^{2}}{\\partial x^{2}} + \\boldsymbol{e}_{y} \\frac{\\partial^{2}}{\\partial x\\partial y} + \\boldsymbol{e}_{z} \\frac{\\partial^{2}}{\\partial x\\partial z}}_\\text{Dop}$" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/latex": [ + "$\\displaystyle \\underbrace{\\left(\\boldsymbol{e}_{x} \\frac{\\partial}{\\partial x} + \\boldsymbol{e}_{y} \\frac{\\partial}{\\partial y} + \\boldsymbol{e}_{z} \\frac{\\partial}{\\partial z}\\right)}_\\text{Dop} * \\underbrace{\\left(\\frac{\\partial}{\\partial x} + \\frac{\\partial}{\\partial y} + \\frac{\\partial}{\\partial z}\\right)}_\\text{Sdop} = \\underbrace{\\boldsymbol{e}_{x} \\left ( \\frac{\\partial^{2}}{\\partial x^{2}} + \\frac{\\partial^{2}}{\\partial x\\partial y} + \\frac{\\partial^{2}}{\\partial x\\partial z}\\right ) + \\boldsymbol{e}_{y} \\left ( \\frac{\\partial^{2}}{\\partial x\\partial y} + \\frac{\\partial^{2}}{\\partial y^{2}} + \\frac{\\partial^{2}}{\\partial y\\partial z}\\right ) + \\boldsymbol{e}_{z} \\left ( \\frac{\\partial^{2}}{\\partial x\\partial z} + \\frac{\\partial^{2}}{\\partial y\\partial z} + \\frac{\\partial^{2}}{\\partial z^{2}}\\right ) }_\\text{Dop}$" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/latex": [ + "$\\displaystyle \\underbrace{\\left(\\boldsymbol{e}_{x} \\frac{\\partial}{\\partial x} + \\boldsymbol{e}_{y} \\frac{\\partial}{\\partial y} + \\boldsymbol{e}_{z} \\frac{\\partial}{\\partial z}\\right)}_\\text{Dop} * \\underbrace{\\left(x^{2} + y^{2} + z^{2}\\right)}_\\text{f(x,y,z)} = \\underbrace{2 x \\boldsymbol{e}_{x} + 2 y \\boldsymbol{e}_{y} + 2 z \\boldsymbol{e}_{z}}_\\text{Mv}$" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/latex": [ + "$\\displaystyle \\underbrace{\\left(\\boldsymbol{e}_{x} \\frac{\\partial}{\\partial x} + \\boldsymbol{e}_{y} \\frac{\\partial}{\\partial y} + \\boldsymbol{e}_{z} \\frac{\\partial}{\\partial z}\\right)}_\\text{Dop} * \\underbrace{\\left(\\boldsymbol{e}_{x} \\frac{\\partial}{\\partial x} + \\boldsymbol{e}_{y} \\frac{\\partial}{\\partial y} + \\boldsymbol{e}_{z} \\frac{\\partial}{\\partial z}\\right)}_\\text{Dop} = \\underbrace{\\frac{\\partial^{2}}{\\partial x^{2}} + \\frac{\\partial^{2}}{\\partial y^{2}} + \\frac{\\partial^{2}}{\\partial z^{2}}}_\\text{Dop}$" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/latex": [ + "$\\displaystyle \\underbrace{\\left(\\boldsymbol{e}_{x} \\frac{\\partial}{\\partial x} + \\boldsymbol{e}_{y} \\frac{\\partial}{\\partial y} + \\boldsymbol{e}_{z} \\frac{\\partial}{\\partial z}\\right)}_\\text{Dop} * \\underbrace{\\left(x^{2} \\boldsymbol{e}_{x} + y^{2} \\boldsymbol{e}_{y} + z^{2} \\boldsymbol{e}_{z}\\right)}_\\text{Mv} = \\underbrace{2 x + 2 y + 2 z}_\\text{Mv}$" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/latex": [ + "$\\displaystyle \\underbrace{\\left(x^{2} \\boldsymbol{e}_{x} + y^{2} \\boldsymbol{e}_{y} + z^{2} \\boldsymbol{e}_{z}\\right)}_\\text{Mv} * \\underbrace{\\left(\\frac{\\partial}{\\partial x}\\right)}_\\text{Pdop} = \\underbrace{\\boldsymbol{e}_{x} 0 + \\boldsymbol{e}_{y} 0 + \\boldsymbol{e}_{z} 0}_\\text{Dop}$" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/latex": [ + "$\\displaystyle \\underbrace{\\left(x^{2} \\boldsymbol{e}_{x} + y^{2} \\boldsymbol{e}_{y} + z^{2} \\boldsymbol{e}_{z}\\right)}_\\text{Mv} * \\underbrace{\\left(\\frac{\\partial}{\\partial x} + \\frac{\\partial}{\\partial y} + \\frac{\\partial}{\\partial z}\\right)}_\\text{Sdop} = \\underbrace{\\boldsymbol{e}_{x} \\left ( x^{2} \\frac{\\partial}{\\partial x} + x^{2} \\frac{\\partial}{\\partial y} + x^{2} \\frac{\\partial}{\\partial z}\\right ) + \\boldsymbol{e}_{y} \\left ( y^{2} \\frac{\\partial}{\\partial x} + y^{2} \\frac{\\partial}{\\partial y} + y^{2} \\frac{\\partial}{\\partial z}\\right ) + \\boldsymbol{e}_{z} \\left ( z^{2} \\frac{\\partial}{\\partial x} + z^{2} \\frac{\\partial}{\\partial y} + z^{2} \\frac{\\partial}{\\partial z}\\right ) }_\\text{Dop}$" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/latex": [ + "$\\displaystyle \\underbrace{\\left(x^{2} \\boldsymbol{e}_{x} + y^{2} \\boldsymbol{e}_{y} + z^{2} \\boldsymbol{e}_{z}\\right)}_\\text{Mv} * \\underbrace{\\left(x^{2} + y^{2} + z^{2}\\right)}_\\text{f(x,y,z)} = \\underbrace{x^{2} \\left(x^{2} + y^{2} + z^{2}\\right) \\boldsymbol{e}_{x} + y^{2} \\left(x^{2} + y^{2} + z^{2}\\right) \\boldsymbol{e}_{y} + z^{2} \\left(x^{2} + y^{2} + z^{2}\\right) \\boldsymbol{e}_{z}}_\\text{Mv}$" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/latex": [ + "$\\displaystyle \\underbrace{\\left(x^{2} \\boldsymbol{e}_{x} + y^{2} \\boldsymbol{e}_{y} + z^{2} \\boldsymbol{e}_{z}\\right)}_\\text{Mv} * \\underbrace{\\left(\\boldsymbol{e}_{x} \\frac{\\partial}{\\partial x} + \\boldsymbol{e}_{y} \\frac{\\partial}{\\partial y} + \\boldsymbol{e}_{z} \\frac{\\partial}{\\partial z}\\right)}_\\text{Dop} = \\underbrace{x^{2} \\frac{\\partial}{\\partial x} + y^{2} \\frac{\\partial}{\\partial y} + z^{2} \\frac{\\partial}{\\partial z} + \\boldsymbol{e}_{x}\\wedge \\boldsymbol{e}_{y} \\left ( x^{2} \\frac{\\partial}{\\partial y} - y^{2} \\frac{\\partial}{\\partial x}\\right ) + \\boldsymbol{e}_{x}\\wedge \\boldsymbol{e}_{z} \\left ( x^{2} \\frac{\\partial}{\\partial z} - z^{2} \\frac{\\partial}{\\partial x}\\right ) + \\boldsymbol{e}_{y}\\wedge \\boldsymbol{e}_{z} \\left ( y^{2} \\frac{\\partial}{\\partial z} - z^{2} \\frac{\\partial}{\\partial y}\\right ) }_\\text{Dop}$" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/latex": [ + "$\\displaystyle \\underbrace{\\left(x^{2} \\boldsymbol{e}_{x} + y^{2} \\boldsymbol{e}_{y} + z^{2} \\boldsymbol{e}_{z}\\right)}_\\text{Mv} * \\underbrace{\\left(x^{2} \\boldsymbol{e}_{x} + y^{2} \\boldsymbol{e}_{y} + z^{2} \\boldsymbol{e}_{z}\\right)}_\\text{Mv} = \\underbrace{x^{4} + y^{4} + z^{4}}_\\text{Mv}$" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "r = x**2*ex+y**2*ey+z**2*ez\n", + "args = [('Pdop', pDx), ('Sdop', dS), ('f(x,y,z)', fxyz), ('Dop', o3d.grad), ('Mv', r)]\n", + "\n", + "for op_name, op in ops:\n", + " display(Markdown(f\"### The ``{op_name}`` operator\"))\n", + " for t1, v1 in args:\n", + " for t2, v2 in args:\n", + " v = op(v1, v2)\n", + " display(Math(\n", + " fr'\\underbrace{{\\left({latex(v1)}\\right)}}_\\text{{{t1}}} {op_name} '\n", + " fr'\\underbrace{{\\left({latex(v2)}\\right)}}_\\text{{{t2}}} = '\n", + " fr'\\underbrace{{{latex(v)}}}_\\text{{{\"op\" if isinstance(v, DiffOpExpr) else type(v).__name__}}}'\n", + " ))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Formatting Multivector Differential Operator \n", + "\n", + "Multivectors the mulitvector differential operators have a `Fmt()` member function for formatting the ouput. The default is `Fmt(1)` which prints one differential operator per line and `Fmt(2)` which prints one partial derivative and it's coefficient per line. Some examples are:" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "data": { + "text/latex": [ + "\\begin{equation*} \\left(x^{2} + y^{2} + z^{2}\\right) + \\frac{\\partial}{\\partial x} + \\boldsymbol{e}_{x} \\frac{\\partial}{\\partial x} + \\boldsymbol{e}_{y} \\frac{\\partial}{\\partial y} + \\boldsymbol{e}_{z} \\frac{\\partial}{\\partial z} \\end{equation*}" + ], + "text/plain": [ + "(x**2 + y**2 + z**2)*D{} + D{x} + e_x*D{x} + e_y*D{y} + e_z*D{z}" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/latex": [ + "\\begin{equation*} \\left(x^{2} + y^{2} + z^{2}\\right) + \\frac{\\partial}{\\partial x} + \\boldsymbol{e}_{x} \\frac{\\partial}{\\partial x} + \\boldsymbol{e}_{y} \\frac{\\partial}{\\partial y} + \\boldsymbol{e}_{z} \\frac{\\partial}{\\partial z} \\end{equation*}" + ], + "text/plain": [ + "(x**2 + y**2 + z**2)*D{} + D{x} + e_x*D{x} + e_y*D{y} + e_z*D{z}" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "dDop = o3d.grad + pDx + fxyz\n", + "display(dDop)\n", + "display(dDop.Fmt(3))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Left and Right Differential Operators\n", + "\n", + "In geometric calculus the occasion arises when instead of having a differential operator operate on operators and multivectors to the right in a multiplicative expression we wish the operations to occur to the left. One way of denoting this in a document is to use an arrow accent with the arrow pointing to the left or right. For example the usual $\\nabla$ operator is equivalent to $\\rop{\\nabla}$ while the left operator would be designated by $\\lop{\\nabla}$. When a geometric algebra is instanciated (for example `o3d`) then $\\rop{\\nabla} =$ `o3d.grad` and $\\lop{\\nabla} =$ `o3d.rgrad`. $\\lop{\\nabla}$ is called `o3d.rgrad` because it is to the right of the operands in the expression. Two member of the `Dop` class, `rop()` and `lop()` force an operator to be left or right operating. If `D` is a multivector differential operator then `D.rop()` modifies `D` to the right operation and `D.lop()` modifies `D` to the left operation (both `D.rop()` and `D.lop()` return `None`).\n", + "\n", + "Printing `o3d.grad` and `o3d.rgrag` gives indentical output: " + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\\T{o3d.grad} = e_x*D{x} + e_y*D{y} + e_z*D{z}\n", + "\\T{o3d.rgrad} = D{x}*e_x + D{y}*e_y + D{z}*e_z\n" + ] + } + ], + "source": [ + "print(r'\\T{o3d.grad} =', o3d.grad)\n", + "print(r'\\T{o3d.rgrad} =', o3d.rgrad)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "But if one operates with $\\lop{\\nabla}$ and $\\rop{\\nabla}$ on a multivector function one gets:" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\\rop{\\nabla}\\lp x^2\\es{x}+y^2\\es{y}+z^2\\es{z}\\rp = 2*x + 2*y + 2*z\n", + "\\lp x^2\\es{x}+y^2\\es{y}+z^2\\es{z}\\rp\\rop{\\nabla} = x**2*D{x} + y**2*D{y} + z**2*D{z} + e_x^e_y*(x**2*D{y} + (-y**2)*D{x}) + e_x^e_z*(x**2*D{z} + (-z**2)*D{x}) + e_y^e_z*(y**2*D{z} + (-z**2)*D{y})\n", + "\\lop{\\nabla}\\lp x^2\\es{x}+y^2\\es{y}+z^2\\es{z}\\rp = x**2*D{x} + y**2*D{y} + z**2*D{z} + ((-x**2)*D{y} + y**2*D{x})*e_x^e_y + ((-x**2)*D{z} + z**2*D{x})*e_x^e_z + ((-y**2)*D{z} + z**2*D{y})*e_y^e_z\n", + "\\lp x^2\\es{x}+y^2\\es{y}+z^2\\es{z}\\rp\\lop{\\nabla} = 2*x + 2*y + 2*z\n" + ] + } + ], + "source": [ + "print(r'\\rop{\\nabla}\\lp x^2\\es{x}+y^2\\es{y}+z^2\\es{z}\\rp =',o3d.grad*r)\n", + "print(r'\\lp x^2\\es{x}+y^2\\es{y}+z^2\\es{z}\\rp\\rop{\\nabla} =',r*o3d.grad)\n", + "print(r'\\lop{\\nabla}\\lp x^2\\es{x}+y^2\\es{y}+z^2\\es{z}\\rp =',o3d.rgrad*r)\n", + "print(r'\\lp x^2\\es{x}+y^2\\es{y}+z^2\\es{z}\\rp\\lop{\\nabla} =',r*o3d.rgrad)" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\\bs{A} = A + A__x*e_x + A__y*e_y + A__z*e_z + A__xy*e_x^e_y + A__xz*e_x^e_z + A__yz*e_y^e_z + A__xyz*e_x^e_y^e_z\n", + "\\bs{B} = B + B__x*e_x + B__y*e_y + B__z*e_z + B__xy*e_x^e_y + B__xz*e_x^e_z + B__yz*e_y^e_z + B__xyz*e_x^e_y^e_z\n", + "h \\bs{AB} = A*B + A__x*B__x - A__xy*B__xy - A__xyz*B__xyz - A__xz*B__xz + A__y*B__y - A__yz*B__yz + A__z*B__z\n", + " + (A*B__x + A__x*B + A__xy*B__y - A__xyz*B__yz + A__xz*B__z - A__y*B__xy - A__yz*B__xyz - A__z*B__xz)*e_x\n", + " + (A*B__y + A__x*B__xy - A__xy*B__x + A__xyz*B__xz + A__xz*B__xyz + A__y*B + A__yz*B__z - A__z*B__yz)*e_y\n", + " + (A*B__z + A__x*B__xz - A__xy*B__xyz - A__xyz*B__xy - A__xz*B__x + A__y*B__yz - A__yz*B__y + A__z*B)*e_z\n", + " + (A*B__xy + A__x*B__y + A__xy*B + A__xyz*B__z - A__xz*B__yz - A__y*B__x + A__yz*B__xz + A__z*B__xyz)*e_x^e_y\n", + " + (A*B__xz + A__x*B__z + A__xy*B__yz - A__xyz*B__y + A__xz*B - A__y*B__xyz - A__yz*B__xy - A__z*B__x)*e_x^e_z\n", + " + (A*B__yz + A__x*B__xyz - A__xy*B__xz + A__xyz*B__x + A__xz*B__xy + A__y*B__z + A__yz*B - A__z*B__y)*e_y^e_z\n", + " + (A*B__xyz + A__x*B__yz + A__xy*B__z + A__xyz*B - A__xz*B__y - A__y*B__xz + A__yz*B__x + A__z*B__xy)*e_x^e_y^e_z\n" + ] + }, + { + "ename": "NameError", + "evalue": "name 'grad' is not defined", + "output_type": "error", + "traceback": [ + "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[1;31mNameError\u001b[0m Traceback (most recent call last)", + "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m\u001b[0m\n\u001b[0;32m 5\u001b[0m \u001b[0mC\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mA\u001b[0m\u001b[1;33m*\u001b[0m\u001b[0mB\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 6\u001b[0m \u001b[0mprint\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m'h'\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;34mr'\\bs{AB} ='\u001b[0m\u001b[1;33m,\u001b[0m\u001b[0mC\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mFmt\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;36m3\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 7\u001b[1;33m \u001b[0mdiff\u001b[0m \u001b[1;33m=\u001b[0m \u001b[1;33m(\u001b[0m\u001b[0mgrad\u001b[0m\u001b[1;33m*\u001b[0m\u001b[0mC\u001b[0m\u001b[1;33m)\u001b[0m \u001b[1;33m-\u001b[0m \u001b[1;33m(\u001b[0m\u001b[0mgrad\u001b[0m\u001b[1;33m*\u001b[0m\u001b[0mA\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m*\u001b[0m\u001b[0mB\u001b[0m \u001b[1;33m-\u001b[0m \u001b[1;33m(\u001b[0m\u001b[0mgrad\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0modot\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m*\u001b[0m\u001b[0mA\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m*\u001b[0m\u001b[0mB\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0modot\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 8\u001b[0m \u001b[1;31m#print(r'\\nabla\\lp\\bs{AB}\\rp - \\lp\\nabla \\bs{A}\\rp \\bs{B} - \\lp\\dot{\\nabla}A\\rp\\dot{\\bs{B}}=',diff)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 9\u001b[0m \u001b[0mprint\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m'diff ='\u001b[0m\u001b[1;33m,\u001b[0m\u001b[0mdiff\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", + "\u001b[1;31mNameError\u001b[0m: name 'grad' is not defined" + ] + } + ], + "source": [ + "A = o3d.mv('A','mv',f=True)\n", + "B = o3d.mv('B','mv',f=True)\n", + "print(r'\\bs{A} =',A)\n", + "print(r'\\bs{B} =',B)\n", + "C = A*B\n", + "print('h',r'\\bs{AB} =',C.Fmt(3))\n", + "diff = (grad*C) - (grad*A)*B - (grad.odot()*A)*B.odot()\n", + "#print(r'\\nabla\\lp\\bs{AB}\\rp - \\lp\\nabla \\bs{A}\\rp \\bs{B} - \\lp\\dot{\\nabla}A\\rp\\dot{\\bs{B}}=',diff)\n", + "print('diff =',diff)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.0" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/galgebra/_full_set.py b/galgebra/_full_set.py new file mode 100644 index 00000000..3489724d --- /dev/null +++ b/galgebra/_full_set.py @@ -0,0 +1,50 @@ +class FullSet(set): + """ A set that contains everything. This is used to trick sympy. """ + def __contains__(self, x): + return True + + def __iter__(self): + raise RuntimeError("Set is infinite") + + def __len__(self): + raise RuntimeError("Set is infinite") + + def __and__(self, other): + if isinstance(other, set): + return other + return NotImplemented + __rand__ = __and__ + + def __or__(self, other): + if isinstance(other, set): + return self + return NotImplemented + __ror__ = __or__ + + def __gt__(self, other): + if isinstance(other, set): + return True + elif isinstance(other, FullSet): + return False + return NotImplemented + + def __lt__(self, other): + if isinstance(other, FullSet): + return False + return NotImplemented + + def __ge__(self, other): + return not (self < other) + + def __le__(self, other): + return not (self > other) + + def __eq__(self, other): + if isinstance(other, set): + return False + elif isinstance(other, FullSet): + return True + return NotImplemented + + def __bool__(self): + return True diff --git a/galgebra/dop.py b/galgebra/dop.py index a3d73cbc..23e8ca82 100644 --- a/galgebra/dop.py +++ b/galgebra/dop.py @@ -3,16 +3,20 @@ For multivector-customized differential operators, see :class:`galgebra.mv.Dop`. """ +import abc import copy import numbers import warnings from typing import List, Tuple, Any, Iterable +import functools +import operator -from sympy import Symbol, S, Add, simplify, diff, Expr, Dummy +from sympy import Symbol, S, diff, Expr, Basic, Add, Mul +import sympy +from sympy.core.decorators import _sympifyit from . import printer -from . import metric -from .printer import ZERO_STR +from . import _full_set def _consolidate_terms(terms): @@ -74,190 +78,114 @@ class _BaseDop(printer.GaPrintable): pass -class Sdop(_BaseDop): - """ - Scalar differential operator is of the form (Einstein summation) +class DiffOpExpr(Expr, _BaseDop): + free_symbols = _full_set.FullSet() + is_commutative = False + _op_priority = 50.0 - .. math:: D = c_{i}*D_{i} + def _diff_op_apply(self, x): + raise NotImplementedError - where the :math:`c_{i}`'s are scalar coefficient (they could be functions) - and the :math:`D_{i}`'s are partial differential operators (:class:`Pdop`). + @_sympifyit('x', NotImplemented) + def __add__(self, x): + return DiffOpAdd(self, x) - Attributes - ---------- - terms : tuple of tuple - the structure :math:`((c_{1},D_{1}),(c_{2},D_{2}), ...)` - """ + @_sympifyit('x', NotImplemented) + def __radd__(self, x): + return DiffOpAdd(x, self) - str_mode = False + @_sympifyit('x', NotImplemented) + def __mul__(self, x): + return DiffOpMul(self, x) - def TSimplify(self): - return Sdop([ - (metric.Simp.apply(coef), pdiff) for coef, pdiff in self.terms - ]) + @_sympifyit('x', NotImplemented) + def __rmul__(self, x): + return DiffOpMul(x, self) - @staticmethod - def consolidate_coefs(sdop): - """ - Remove zero coefs and consolidate coefs with repeated pdiffs. - """ - if isinstance(sdop, Sdop): - return Sdop(_consolidate_terms(sdop.terms)) - else: - return _consolidate_terms(sdop) + def __neg__(self): + return DiffOpMul(S.NegativeOne, self) - def simplify(self, modes=simplify): - return Sdop([ - (metric.apply_function_list(modes, coef), pdiff) - for coef, pdiff in self.terms - ]) + @_sympifyit('x', NotImplemented) + def __sub__(self, x): + return DiffOpAdd(self, -x) - def _with_sorted_terms(self): - new_terms = sorted(self.terms, key=lambda term: Pdop.sort_key(term[1])) - return Sdop(new_terms) + @_sympifyit('x', NotImplemented) + def __rsub__(self, x): + return DiffOpAdd(x, -self) - def _sympystr(self, print_obj): - if len(self.terms) == 0: - return ZERO_STR - - self = self._with_sorted_terms() - s = '' - for coef, pdop in self.terms: - coef_str = print_obj.doprint(coef) - pd_str = print_obj.doprint(pdop) - - if coef == S(1): - s += pd_str - elif coef == S(-1): - s += '-' + pd_str - else: - if isinstance(coef, Add): - s += '(' + coef_str + ')*' + pd_str - else: - s += coef_str + '*' + pd_str - s += ' + ' - - s = s.replace('+ -', '- ') - s = s[:-3] - if Sdop.str_mode: - if len(self.terms) > 1 or isinstance(self.terms[0][0], Add): - s = '(' + s + ')' - return s + def __call__(self, x): + return self._diff_op_apply(x) - def _latex(self, print_obj): - if len(self.terms) == 0: - return ZERO_STR - - self = self._with_sorted_terms() - - s = '' - for coef, pdop in self.terms: - coef_str = print_obj.doprint(coef) - pd_str = print_obj.doprint(pdop) - if coef == S(1): - if pd_str == '': - s += '1' - else: - s += pd_str - elif coef == S(-1): - if pd_str == '': - s += '-1' - else: - s += '-' + pd_str - else: - if isinstance(coef, Add): - s += r'\left ( ' + coef_str + r'\right ) ' + pd_str - else: - s += coef_str + ' ' + pd_str - s += ' + ' +def _DiffOpMul_postprocessor(e: sympy.Mul): + assert isinstance(e, sympy.Mul) + return DiffOpMul(*e.args) + + +def _DiffOpAdd_postprocessor(e: sympy.Add): + assert isinstance(e, sympy.Add) + return DiffOpAdd(*e.args) - s = s.replace('+ -', '- ') - return s[:-3] - def __init_from_symbol(self, symbol: Symbol) -> None: - self.terms = ((S(1), Pdop(symbol)),) +Basic._constructor_postprocessor_mapping[DiffOpExpr] = { + "Mul": [_DiffOpMul_postprocessor], + "Add": [_DiffOpAdd_postprocessor], +} + + +def _diff_op_ify(x): + if isinstance(x, DiffOpExpr): + return x + elif isinstance(x, sympy.Add): + return DiffOpAdd(*(a for a in x.args)) + elif isinstance(x, sympy.Mul): + return DiffOpMul(*(a for a in x.args)) + else: + return x * DiffOpPartial({}) + - def __init_from_coef_and_pdiffs(self, coefs: List[Any], pdiffs: List['Pdop']) -> None: +def _diff_op_apply(d, x): + if not isinstance(d, DiffOpExpr): + d = d * DiffOpPartial({}) + return _diff_op_ify(d)._diff_op_apply(x) + + +class Sdop(abc.ABC): + @classmethod + def __subclasshook__(cls, c): + return issubclass(c, DiffOpExpr) + @classmethod + def _from_symbol(cls, symbol: Symbol) -> 'DiffOpExpr': + return Pdop(symbol) + + @classmethod + def _from_coef_and_pdiffs(cls, coefs: List[Any], pdiffs: List['Pdop']) -> None: if not isinstance(coefs, list) or not isinstance(pdiffs, list): raise TypeError("coefs and pdiffs must be lists") if len(coefs) != len(pdiffs): raise ValueError('In Sdop.__init__ coefficent list and Pdop list must be same length.') - self.terms = tuple(zip(coefs, pdiffs)) + return cls._from_terms(tuple(zip(coefs, pdiffs))) - def __init_from_terms(self, terms: Iterable[Tuple[Any, 'Pdop']]) -> None: - self.terms = tuple(terms) + @classmethod + def _from_terms(cls, terms: Iterable[Tuple[Any, 'Pdop']]) -> None: + return sum((a * b for a, b in terms), DiffOpAdd.identity) - def __init__(self, *args): + def __new__(cls, *args): if len(args) == 1: if isinstance(args[0], Symbol): - self.__init_from_symbol(*args) + return cls._from_symbol(*args) elif isinstance(args[0], (list, tuple)): - self.__init_from_terms(*args) + return cls._from_terms(*args) else: raise TypeError( "A symbol or sequence is required (got type {})" .format(type(args[0]).__name__)) elif len(args) == 2: - self.__init_from_coef_and_pdiffs(*args) + return cls._from_coef_and_pdiffs(*args) else: raise TypeError( "Sdop() takes from 1 to 2 positional arguments but {} were " "given".format(len(args))) - def __call__(self, arg): - # Ensure that we return the right type even when there are no terms - we - # do this by adding `0 * d(arg)/d(nonexistant)`, which must be zero, but - # will be a zero of the right type. - dummy_var = Dummy('nonexistant') - terms = self.terms or ((S(0), Pdop(dummy_var)),) - return sum([coef * pdiff(arg) for coef, pdiff in terms]) - - def __neg__(self): - return Sdop([(-coef, pdiff) for coef, pdiff in self.terms]) - - @staticmethod - def Add(sdop1, sdop2): - if isinstance(sdop1, Sdop) and isinstance(sdop2, Sdop): - return Sdop(_merge_terms(sdop1.terms, sdop2.terms)) - else: - # convert values to multiplicative operators - if not isinstance(sdop2, _BaseDop): - sdop2 = Sdop([(sdop2, Pdop({}))]) - elif not isinstance(sdop1, _BaseDop): - sdop1 = Sdop([(sdop1, Pdop({}))]) - else: - return NotImplemented - return Sdop.Add(sdop1, sdop2) - - def __eq__(self, other): - if isinstance(other, Sdop): - diff = self - other - return len(diff.terms) == 0 - else: - return NotImplemented - - def __add__(self, sdop): - return Sdop.Add(self, sdop) - - def __radd__(self, sdop): - return Sdop.Add(sdop, self) - - def __sub__(self, sdop): - return Sdop.Add(self, -sdop) - - def __rsub__(self, sdop): - return Sdop.Add(-self, sdop) - - def __mul__(self, sdopr): - # alias for applying the operator - return self.__call__(sdopr) - - def __rmul__(self, sdop): - return Sdop([(sdop * coef, pdiff) for coef, pdiff in self.terms]) - - def _eval_derivative_n_times(self, x, n): - return Sdop(_eval_derivative_n_times_terms(self.terms, x, n)) - #################### Partial Derivative Operator Class ################# @@ -273,7 +201,7 @@ def _basic_diff(f, x, n=1): raise ValueError('In_basic_diff type(arg) = ' + str(type(f)) + ' not allowed.') -class Pdop(_BaseDop): +class DiffOpPartial(DiffOpExpr, sympy.AtomicExpr): r""" Partial derivative operatorp. @@ -299,25 +227,17 @@ class Pdop(_BaseDop): def sort_key(self, order=None): return ( - # lower order derivatives first + self.class_key(), self.order, # sorted by symbol after that, after expansion - sorted([ + tuple(sorted([ x.sort_key(order) for x, k in self.pdiffs.items() for i in range(k) - ]) + ])) ) - def __eq__(self, A): - if isinstance(A, Pdop) and self.pdiffs == A.pdiffs: - return True - else: - if len(self.pdiffs) == 0 and A == S(1): - return True - return False - - def __init__(self, __arg): + def __new__(cls, __arg): """ The partial differential operator is a partial derivative with respect to a set of real symbols (variables). @@ -330,13 +250,19 @@ def __init__(self, __arg): __arg = {} if isinstance(__arg, dict): # Pdop defined by dictionary - self.pdiffs = __arg + pdiffs = __arg elif isinstance(__arg, Symbol): # First order derivative with respect to symbol - self.pdiffs = {__arg: 1} + pdiffs = {__arg: 1} else: raise TypeError('A dictionary or symbol is required, got {!r}'.format(__arg)) + self = super().__new__(cls) + self.pdiffs = pdiffs self.order = sum(self.pdiffs.values()) + return self + + def _eval_derivative(self, x): + return self._eval_derivative_n_times(x, 1) def _eval_derivative_n_times(self, x, n) -> 'Pdop': # pdiff(self) # d is partial derivative @@ -347,7 +273,7 @@ def _eval_derivative_n_times(self, x, n) -> 'Pdop': # pdiff(self) pdiffs[x] = n return Pdop(pdiffs) - def __call__(self, arg): + def _diff_op_apply(self, arg): """ Calculate nth order partial derivative (order defined by self) of expression @@ -356,13 +282,6 @@ def __call__(self, arg): arg = _basic_diff(arg, x, n) return arg - def __mul__(self, other): # functional product of self and arg (self*arg) - return self(other) - - def __rmul__(self, other): # functional product of arg and self (arg*self) - assert not isinstance(other, Pdop) - return Sdop([(other, self)]) - def _sympystr(self, print_obj): if self.order == 0: return 'D{}' @@ -390,3 +309,139 @@ def _latex(self, print_obj): s += '^{' + print_obj.doprint(i) + '}' s += '}' return s + + + def __srepr__(self): + return '{}({})'.format(type(self).__name__, self.pdiffs) + + def _hashable_content(self): + from sympy.utilities import default_sort_key + sorted_items = sorted( + self.pdiffs.items(), + key=lambda t: (default_sort_key(t[0]), t[1]) + ) + return tuple(sympy.Basic(coeff, sympy.S(n)) for coeff, n in sorted_items) + + +Pdop = DiffOpPartial + + +class DiffOpZero(DiffOpExpr): + def _diff_op_apply(self, x): + return 0 * x + + +class DiffOpMul(DiffOpExpr, sympy.Mul): + identity = DiffOpPartial({}) + + def __new__(cls, *args, **kwargs): + if not args: + return cls.identity + pre_coeffs = [] + it_args = iter(args) + + pre_coeffs = [] + diff_ops = [] + diff_operands = [] + + # extra pre-multiplied coeffs + for a in it_args: + if isinstance(a, DiffOpMul): + pre_coeffs += a.args[:-1] + diff_ops.append(a.args[-1]) + break + if isinstance(a, DiffOpExpr): + diff_ops.append(a) + break + pre_coeffs.append(a) + + # extract differential terms + for a in it_args: + if not isinstance(a, DiffOpExpr): + diff_operands.append(a) + break + diff_ops.append(a) + + # must be only one operand + for a in it_args: + raise TypeError( + "Must pass at most one operand after the differential operators" + ) + + # avoid `sympy.Mul` so that this works on multivectors + if pre_coeffs: + coeff = functools.reduce(operator.mul, pre_coeffs) + else: + coeff = S(1) + + d = cls.identity + for di in diff_ops: + d = d._diff_op_apply(di) + if coeff == S(1): + self = d + elif coeff == S(0): + self = DiffOpZero() + else: + self = sympy.Basic.__new__(cls, coeff, d, **kwargs) + + if diff_operands: + return self._diff_op_apply(diff_operands[0]) + + return self + + def _diff_op_apply(self, x): + coeff, *rest = self.args + for r in rest[::-1]: + x = r._diff_op_apply(x) + return coeff * x + + def diff(self, *args, **kwargs): + return super().diff(*args, simplify=False, **kwargs) + + def _eval_derivative(self, x): + coeff, diff = self.args + return sympy.diff(coeff, x) * diff + coeff * sympy.diff(diff, x) + + +class DiffOpAdd(DiffOpExpr, sympy.Add): + identity = DiffOpZero() + + @classmethod + def _from_args(self, args, is_commutative): + args = [_diff_op_ify(arg) for arg in args] + return super()._from_args(args, is_commutative) + + def _diff_op_apply(self, x): + args = self.args + assert args + # avoid `sympy.Add` so that this works on multivectors + return functools.reduce(operator.add, (_diff_op_apply(a, x) for a in args)) + + def _eval_derivative_n_times(self, x, n): + return DiffOpAdd(*(a.diff(x, n) for a in self.args)) + + def _eval_derivative(self, x): + return DiffOpAdd(*(a.diff(x) for a in self.args)) + + def _eval_simplify(self, *args, **kwargs): + return self + + def diff(self, *args, **kwargs): + return super().diff(*args, simplify=False, **kwargs) + + +def _as_terms(d): + d = d.expand() + if isinstance(d, DiffOpAdd): + for a in d.args: + yield from _as_terms(a) + elif isinstance(d, DiffOpMul): + coeff, pdiff = d.args + for c, p in _as_terms(pdiff): + yield (coeff*c, p) + elif isinstance(d, DiffOpPartial): + yield (S(1), d) + elif isinstance(d, DiffOpZero): + pass + else: + yield (d, DiffOpMul.identity) \ No newline at end of file diff --git a/galgebra/mv.py b/galgebra/mv.py index 1fa8e464..5423fae2 100644 --- a/galgebra/mv.py +++ b/galgebra/mv.py @@ -75,8 +75,14 @@ class Mv(printer.GaPrintable): ################### Multivector initialization ##################### - # This is read by one code path in `galgebra.printer.Fmt`. Only one example - # sets it. + is_number = False + is_Number = False + is_Rational = False + is_commutative = False + + def sort_key(self, *args, **kwargs): + return self.obj.sort_key(*args, **kwargs) + fmt = 1 dual_mode_lst = ['+I', 'I+', '+Iinv', 'Iinv+', '-I', 'I-', '-Iinv', 'Iinv-'] @@ -359,6 +365,8 @@ def __init__(self, *args, ga, recp=None, coords=None, **kwargs): self.is_blade_rep = x.is_blade_rep self.i_grade = x.i_grade else: + if isinstance(x, dop.DiffOpExpr): + raise TypeError("cannot embed a differential operator in a multivector") if isinstance(x, Expr): # copy constructor for obj expression self.obj = x else: # copy constructor for scalar obj expression @@ -497,8 +505,10 @@ def __neg__(self): return Mv(-self.obj, ga=self.Ga) def __add__(self, A): - if isinstance(A, dop._BaseDop): + if isinstance(A, Dop): return NotImplemented + elif isinstance(A, dop.DiffOpExpr): + return self + self.Ga.dop(A) if not isinstance(A, Mv): return Mv(self.obj + A, ga=self.Ga) @@ -519,27 +529,16 @@ def __radd__(self, A): return self + A def __sub__(self, A): - if isinstance(A, dop._BaseDop): - return NotImplemented - - if self.Ga != A.Ga: - raise ValueError('In - operation Mv arguments are not from same geometric algebra') - - if self.is_blade_rep == A.is_blade_rep: - return Mv(self.obj - A.obj, ga=self.Ga) - else: - if self.is_blade_rep: - A = A.blade_rep() - else: - self = self.blade_rep() - return Mv(self.obj - A.obj, ga=self.Ga) + return self + -A def __rsub__(self, A): return -self + A def __mul__(self, A): - if isinstance(A, dop._BaseDop): + if isinstance(A, Dop): return NotImplemented + elif isinstance(A, dop.DiffOpExpr): + return self * self.Ga.dop(A) if not isinstance(A, Mv): return Mv(expand(A * self.obj), ga=self.Ga) @@ -575,8 +574,10 @@ def __mul__(self, A): return Mv(self.Ga.mul(self.obj, A.obj), ga=self.Ga) def __rmul__(self, A): - if isinstance(A, dop._BaseDop): + if isinstance(A, Dop): return NotImplemented + elif isinstance(A, dop.DiffOpExpr): + return self.Ga.dop(A) * A return Mv(expand(A * self.obj), ga=self.Ga) def __truediv__(self, A): @@ -766,8 +767,10 @@ def append_plus(c_str): return s def __xor__(self, A): # wedge (^) product - if isinstance(A, dop._BaseDop): + if isinstance(A, Dop): return NotImplemented + elif isinstance(A, dop.DiffOpExpr): + return self ^ self.Ga.dop(A) if not isinstance(A, Mv): return Mv(A * self.obj, ga=self.Ga) @@ -783,14 +786,17 @@ def __xor__(self, A): # wedge (^) product return Mv(self.Ga.wedge(self.obj, A.obj), ga=self.Ga) def __rxor__(self, A): # wedge (^) product - if isinstance(A, dop._BaseDop): + if isinstance(A, Dop): return NotImplemented - assert not isinstance(A, Mv) + elif isinstance(A, dop.DiffOpExpr): + return self.Ga.dop(A) ^ self return Mv(A * self.obj, ga=self.Ga) def __or__(self, A): # dot (|) product - if isinstance(A, dop._BaseDop): + if isinstance(A, Dop): return NotImplemented + elif isinstance(A, dop.DiffOpExpr): + return self | self.Ga.dop(A) if not isinstance(A, Mv): return Mv(ga=self.Ga) @@ -803,8 +809,10 @@ def __or__(self, A): # dot (|) product return Mv(self.Ga.hestenes_dot(self.obj, A.obj), ga=self.Ga) def __ror__(self, A): # dot (|) product - if isinstance(A, dop._BaseDop): + if isinstance(A, Dop): return NotImplemented + elif isinstance(A, dop.DiffOpExpr): + return self.Ga.dop(A) | self assert not isinstance(A, Mv) return Mv(ga=self.Ga) @@ -832,12 +840,9 @@ def __rrshift__(self, A): # comutator (>>) def __lt__(self, A): # left contraction (<) if isinstance(A, Dop): # Cannot return `NotImplemented` here, as that would call `A > self` - return A.Mul(self, A, op='<') - elif isinstance(A, dop._BaseDop): - raise TypeError( - "'<' not supported between instances of 'Mv' and {!r}" - .format(type(A).__name__) - ) + return Dop.Mul(self, A, op='<') + elif isinstance(A, dop.DiffOpExpr): + return Dop.Mul(self, self.Ga.dop(A), op='<') if not isinstance(A, Mv): # sympy scalar return Mv(A * self.obj, ga=self.Ga) @@ -853,12 +858,8 @@ def __gt__(self, A): # right contraction (>) if isinstance(A, Dop): # Cannot return `NotImplemented` here, as that would call `A < self` return A.Mul(self, A, op='>') - elif isinstance(A, dop._BaseDop): - raise TypeError( - "'>' not supported between instances of 'Mv' and {!r}" - .format(type(A).__name__) - ) - + elif isinstance(A, dop.DiffOpExpr): + return Dop.Mul(self, self.Ga.dop(A), op='>') if not isinstance(A, Mv): # sympy scalar return self.Ga.mv(A * self.scalar()) @@ -1428,13 +1429,21 @@ def __init_from_terms(self, terms: Union[ self.terms = dop._consolidate_terms( (coef * mv, pdiff) for (sdop, mv) in terms - for (coef, pdiff) in sdop.terms + for (coef, pdiff) in dop._as_terms(sdop) ) else: raise TypeError( 'In Dop.__init__ terms are neither (Mv, Pdop) pairs or ' '(Sdop, Mv) pairs, got {}'.format(terms)) + def __init_from_diff_op(self, diff_op): + terms = [] + for coef, pdiff in dop._as_terms(diff_op): + if not isinstance(coef, Mv): + coef = self.Ga.mv(coef) + terms.append((coef, pdiff)) + self.terms = tuple(terms) + def __init__(self, *args, ga: 'Ga', cmpflg: bool = False, debug: bool = False) -> None: """ Parameters @@ -1455,7 +1464,10 @@ def __init__(self, *args, ga: 'Ga', cmpflg: bool = False, debug: bool = False) - if len(args) == 2: self.__init_from_coef_and_pdop(*args) elif len(args) == 1: - self.__init_from_terms(*args) + if isinstance(args[0], dop.DiffOpExpr): + self.__init_from_diff_op(args[0]) + else: + self.__init_from_terms(*args) else: # count include self, as python usually does raise TypeError( @@ -1479,6 +1491,11 @@ def consolidate_coefs(self) -> 'Dop': @staticmethod def Add(dop1, dop2): + # promote pdops to dops + if isinstance(dop1, Dop) and isinstance(dop2, dop.DiffOpExpr): + dop2 = Dop(dop2, cmpflg=dop1.cmpflg, ga=dop1.Ga) + elif isinstance(dop2, Dop) and isinstance(dop1, dop.DiffOpExpr): + dop1 = Dop(dop1, cmpflg=dop2.cmpflg, ga=dop2.Ga) if isinstance(dop1, Dop) and isinstance(dop2, Dop): if dop1.Ga != dop2.Ga: @@ -1524,6 +1541,12 @@ def __rsub__(self, dop): def Mul(dopl, dopr, op='*'): # General multiplication of Dop's # cmpflg is True if the Dop operates on the left argument and # False if the Dop operates on the right argument + # + # promote pdops to dops + if isinstance(dopl, Dop) and isinstance(dopr, dop.DiffOpExpr): + dopr = Dop(dopr, cmpflg=dopl.cmpflg, ga=dopl.Ga) + elif isinstance(dopr, Dop) and isinstance(dopl, dop.DiffOpExpr): + dopl = Dop(dopl, cmpflg=dopr.cmpflg, ga=dopr.Ga) if isinstance(dopl, Dop) and isinstance(dopr, Dop): if dopl.Ga != dopr.Ga: @@ -1662,7 +1685,7 @@ def Dop_mv_expand(self, modes=None) -> List[Tuple[Expr, Expr]]: coefs.append(dop.Sdop([(mv_coef, pdiff)])) if modes is not None: for i in range(len(coefs)): - coefs[i] = coefs[i].simplify(modes) + coefs[i] = coefs[i].simplify(modes=modes) terms = list(zip(coefs, bases)) return sorted(terms, key=lambda x: self.Ga.blades.flat.index(x[1])) @@ -1679,13 +1702,14 @@ def _sympystr(self, print_obj: _StrPrinter) -> str: if base == S(1): s += str_sdop else: - if len(sdop.terms) > 1: + terms = list(dop._as_terms(sdop)) + if len(terms) > 1: if self.cmpflg: s += '(' + str_sdop + ')*' + str_base else: s += str_base + '*(' + str_sdop + ')' else: - if str_sdop[0] == '-' and not isinstance(sdop.terms[0][0], Add): + if str_sdop[0] == '-' and not isinstance(terms[0], Add): if self.cmpflg: s += str_sdop + '*' + str_base else: @@ -1722,13 +1746,14 @@ def _latex(self, print_obj: _LatexPrinter) -> str: if str_sdop[1:] != '1': s += ' ' + str_sdop[1:] else: - if len(sdop.terms) > 1: + terms = list(dop._as_terms(sdop)) + if len(terms) > 1: if self.cmpflg: s += r'\left ( ' + str_sdop + r'\right ) ' + str_base else: s += str_base + ' ' + r'\left ( ' + str_sdop + r'\right ) ' else: - if str_sdop[0] == '-' and not isinstance(sdop.terms[0][0], Add): + if str_sdop[0] == '-' and not isinstance(terms[0][0], Add): if self.cmpflg: s += str_sdop + str_base else: