Skip to content

Instantly share code, notes, and snippets.

@WetHat
Last active July 20, 2023 16:50
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save WetHat/1225a0524a53894353e850d458f73bd1 to your computer and use it in GitHub Desktop.
Save WetHat/1225a0524a53894353e850d458f73bd1 to your computer and use it in GitHub Desktop.
A Symbolic Vector Algebra Extension for SymPy
Display the source blob
Display the rendered blob
Raw
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**Note**: Click [here](https://nbviewer.jupyter.org/gist/WetHat/1225a0524a53894353e850d458f73bd1)\n",
"to view the full fidelity version of this notebook with\n",
"[nbviewer](https://nbviewer.jupyter.org/)."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Abstract Vector Algebra with SymPy\n",
"\n",
"This notebook was motivated by the need to work with symbolic vectors at a more abstract level than `sympy`\n",
"currently provides (as far as I know).\n",
"\n",
"Sympy offers a variety of ways to work with symbolic vectors. For vector algebra in 3-D space a typical\n",
"approach would be to use the `sympy.vector` module to model points and vectors in 3-D space like so:"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"from sympy.vector import CoordSys3D\n",
"from sympy import symbols"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"p_x,p_y,p_z = symbols('p_x p_y p_z')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"A symbolic point in 3-D space looks like:"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [
{
"data": {
"text/latex": [
"$\\displaystyle Point\\left(\\vec{p}, (p_{x})\\mathbf{\\hat{i}_{N}} + (p_{y})\\mathbf{\\hat{j}_{N}} + (p_{z})\\mathbf{\\hat{k}_{N}}, Point\\left(N.origin, \\mathbf{\\hat{0}}\\right)\\right)$"
],
"text/plain": [
"\\vec{p}"
]
},
"execution_count": 3,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"N = CoordSys3D('N') # World Coordinate System\n",
"point = N.origin.locate_new(r'\\vec{p}', p_x*N.i + p_y*N.j + p_z*N.k)\n",
"point"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"And a symbolic vector in this notation looks like:"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"data": {
"text/latex": [
"$\\displaystyle (p_{x})\\mathbf{\\hat{i}_{N}} + (p_{y})\\mathbf{\\hat{j}_{N}} + (p_{z})\\mathbf{\\hat{k}_{N}}$"
],
"text/plain": [
"p_x*N.i + p_y*N.j + p_z*N.k"
]
},
"execution_count": 4,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"vector = point.position_wrt(N.origin)\n",
"vector"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"`SymPy`has first class support for working with vectors and points expressed in coordinate system notation. However, this notation is quite verbose as it models each vector component explicitly. The complexity of expressions in coordinate system notation increases very quickly and soon makes the printouts incomprehensible. Also, it is not possible to express assumptions, like a vector being normalized, without explicitly stating that:"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [
{
"data": {
"text/latex": [
"$\\displaystyle (\\frac{p_{x}}{\\sqrt{p_{x}^{2} + p_{y}^{2} + p_{z}^{2}}})\\mathbf{\\hat{i}_{N}} + (\\frac{p_{y}}{\\sqrt{p_{x}^{2} + p_{y}^{2} + p_{z}^{2}}})\\mathbf{\\hat{j}_{N}} + (\\frac{p_{z}}{\\sqrt{p_{x}^{2} + p_{y}^{2} + p_{z}^{2}}})\\mathbf{\\hat{k}_{N}}$"
],
"text/plain": [
"(p_x/sqrt(p_x**2 + p_y**2 + p_z**2))*N.i + (p_y/sqrt(p_x**2 + p_y**2 + p_z**2))*N.j + (p_z/sqrt(p_x**2 + p_y**2 + p_z**2))*N.k"
]
},
"execution_count": 5,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"vector.normalize()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"In this notebook we explore a way to model vectors at the level of a commutative group \n",
"which is independent of the dimension of the underlying vector space and does **not** use component notation. \n",
"\n",
"We will be implementing\n",
"* classes to represent symbolic vectors including assumptions\n",
"* a commutative, bi-linear dot product with support for:\n",
" * differentiation\n",
" * reduction of dot products between unit vectors\n",
"\n",
"Finally we showcase some of the ways how to work with the class developed in this notebook.\n",
"\n",
"To keep track of the equation and expressions we first set up an [EquationRegistry](https://gist.github.com/WetHat/6a8e38fb92ab831d8cdb5d66f2d2e524#file-py-equationregistry-ipynb)."
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [],
"source": [
"from jnbBuffs.eqreg import EquationRegistry\n",
"EQ = EquationRegistry(show_names=True, github = True)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Defining Symbolic Vectors\n",
"\n",
"To support manipulations with symbolic vectors it is necessary to make them identifiable and make use of assumptions they may be associated with. In the following sections we implement the symbolic representations of\n",
"_plain_ and indexed symbolic vectors."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Symbolic Vector"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {
"tags": [
"CodeExport"
]
},
"outputs": [],
"source": [
"from sympy import Symbol"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {
"tags": [
"CodeExport"
]
},
"outputs": [],
"source": [
"class VectorSymbol(Symbol):\n",
" r'''Declare symbolic vectors.'''\n",
" def __new__(cls, name: str, normalized: bool = False ,**kwargs):\n",
" r'''Create a new named symbolic vector.\n",
" \n",
" Args\n",
" ====\n",
" \n",
" `name: str`\n",
" : The math representation of the vector\n",
" \n",
" `normalized: bool = False`\n",
" : Optional assumption about vector normalization\n",
" '''\n",
" obj = super().__new__(cls, name, **kwargs)\n",
" obj.is_scalar = False\n",
" obj.is_Vector = True\n",
" obj.is_normalized = normalized\n",
" return obj"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Vector (or point) symbols are created like so:"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [
{
"data": {
"text/markdown": [
"\n",
"<a name=\"Point\"/>"
],
"text/plain": [
"<IPython.core.display.Markdown object>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/latex": [
"$\\displaystyle \\begin{matrix}\\boxed{\\displaystyle \\vec{p}} & (1)\\ \\text{Point}\\end{matrix}$"
],
"text/plain": [
"<IPython.core.display.Math object>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"EQ.Point = VectorSymbol(r'\\vec{p}')\n",
"EQ('Point')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Indexed Symbolic Vector\n",
"\n",
"This type of vector can be used to symbolically describe indexed members of vector fields or point clouds."
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {
"tags": [
"CodeExport"
]
},
"outputs": [],
"source": [
"from sympy import IndexedBase\n",
"from sympy.abc import *"
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {
"tags": [
"CodeExport"
]
},
"outputs": [],
"source": [
"class VectorIndexedBase(IndexedBase):\n",
" r'''Declare an indexed base of a symbolic vector.'''\n",
"\n",
" def __new__(cls, name: str, normalized: bool = False, **kwargs):\n",
" r'''Create a new indexed symbolic vectors with a given name and\n",
" an optional assumption about normalization.\n",
" \n",
" Args\n",
" ====\n",
"\n",
" `name: str`\n",
" : The math representation of the vector\n",
"\n",
" `normalized: bool = False`\n",
" : Optional assumption about vector normalization\n",
" '''\n",
" obj = super().__new__(cls, name, **kwargs)\n",
" obj.is_scalar = False\n",
" obj.is_Vector = True\n",
" obj.is_normalized = normalized\n",
" return obj\n",
"\n",
" def __getitem__(self, *args):\n",
" '''Get the indexed symbolic vector.'''\n",
" return VectorIndexed(self, *args)"
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {
"tags": [
"CodeExport"
]
},
"outputs": [],
"source": [
"from sympy import Indexed"
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {
"tags": [
"CodeExport"
]
},
"outputs": [],
"source": [
"class VectorIndexed(Indexed):\n",
" '''Express indexed symbolic vectors.'''\n",
"\n",
" def __new__(cls, base: VectorIndexedBase, *args):\n",
" obj = super().__new__(cls, base, *args)\n",
" # promote the assumptions from the indexed base vector\n",
" obj.is_normalized = base.is_normalized\n",
" obj.is_scalar = base.is_scalar\n",
" obj.is_Vector = base.is_Vector\n",
"\n",
" return obj"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"With this an indexed point which is a member of a point cloud can be expressed like so:"
]
},
{
"cell_type": "code",
"execution_count": 14,
"metadata": {},
"outputs": [
{
"data": {
"text/markdown": [
"\n",
"<a name=\"Pt_i\"/>"
],
"text/plain": [
"<IPython.core.display.Markdown object>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/latex": [
"$\\displaystyle \\begin{matrix}\\boxed{\\displaystyle {\\vec{p}}_{i}} & (2)\\ \\text{Pt_i}\\end{matrix}$"
],
"text/plain": [
"<IPython.core.display.Math object>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"EQ.Pt_i = VectorIndexedBase(r'\\vec{p}')[i]\n",
"EQ('Pt_i')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Now we declare an indexed unit-vector which is a member of a vector field. \n",
"We use the _hat_ notation to describe that the vectors are normalized (unit-vectors)."
]
},
{
"cell_type": "code",
"execution_count": 15,
"metadata": {},
"outputs": [
{
"data": {
"text/markdown": [
"\n",
"<a name=\"Nor_i\"/>"
],
"text/plain": [
"<IPython.core.display.Markdown object>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/latex": [
"$\\displaystyle \\begin{matrix}\\boxed{\\displaystyle {\\hat{n}}_{i}} & (3)\\ \\text{Nor_i}\\end{matrix}$"
],
"text/plain": [
"<IPython.core.display.Math object>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"EQ.Nor_i = VectorIndexedBase(r'\\hat{n}', normalized = True)[i]\n",
"EQ('Nor_i')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Dot Product Between Symbolic Vectors"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We can now use the symbolic vector representations developed in the previous section to implement\n",
"a symbolic vector dot product which is aware of specific vector properties (such as normalization)."
]
},
{
"cell_type": "code",
"execution_count": 16,
"metadata": {
"tags": [
"CodeExport"
]
},
"outputs": [],
"source": [
"from sympy.vector import Dot\n",
"from itertools import product\n",
"from numbers import Number\n",
"from sympy import diff, latex, Mul, Add, sympify"
]
},
{
"cell_type": "code",
"execution_count": 17,
"metadata": {
"tags": [
"CodeExport"
]
},
"outputs": [],
"source": [
"class DOT(Dot):\n",
" '''\n",
" Scalar (dot) product between symbolic vectors.\n",
" \n",
" Implemented as a bi-linear, commutative function.\n",
" '''\n",
"\n",
" def _eval_expand_basic(self, *args, **kwargs):\n",
" '''Support for the SymPy _expand_ infrastructure.'''\n",
" # generate all possible parameter combinations\n",
" result = sympify(0)\n",
" for a, b in product(self.args[0].as_ordered_terms(),\n",
" self.args[1].as_ordered_terms()):\n",
" factor_a, arg_a = self.factor_arg(a)\n",
" factor_b, arg_b = self.factor_arg(b)\n",
" # handle special cases\n",
"\n",
" if not arg_a.is_scalar \\\n",
" and arg_a.is_normalized \\\n",
" and arg_a == arg_b:\n",
" dot = sympify(1)\n",
" else:\n",
" dot = DOT(arg_a, arg_b)\n",
" result = result + factor_a * factor_b * dot # accumulate DOT products calls\n",
" return result\n",
"\n",
" def _latex(self, printer):\n",
" r'''A custom printer to unambiguously render\n",
" left and right hand side of the dot product.\n",
" '''\n",
" a, b = self.args\n",
" a_latex, b_latex = printer._print(a), printer._print(b)\n",
" if a.is_scalar:\n",
" a_latex = r'\\left(' + a_latex + r' \\right)'\n",
" if b.is_scalar:\n",
" b_latex = r'\\left(' + b_latex + r' \\right)'\n",
" return r'\\left( ' + a_latex + r'\\cdot' + b_latex + r' \\right)'\n",
"\n",
" def _eval_derivative(self, var):\n",
" r'''Compute the derivative of a symbolic dot product for\n",
" scalar and vector derivatives.\n",
" '''\n",
" result = sympify(0)\n",
" for a, b in product(self.args[0].as_ordered_terms(),\n",
" self.args[1].as_ordered_terms()):\n",
" factor_a, arg_a = self.factor_arg(a)\n",
" factor_b, arg_b = self.factor_arg(b)\n",
" factor = factor_a * factor_b\n",
" if var.is_Vector:\n",
" result += factor * arg_b if var == arg_a else sympify(0)\n",
" result += factor * arg_a if var == arg_b else sympify(0)\n",
" else:\n",
" result += diff(factor, var) * DOT(arg_a, arg_b)\n",
" return result\n",
"\n",
" def doit(self):\n",
" return super().doit().replace(Dot, lambda *args: DOT(*args))\n",
"\n",
" @staticmethod\n",
" def factor_arg(x):\n",
" '''Extract scalar factors from a dot product.'''\n",
" factor = sympify(1)\n",
" product = sympify(1)\n",
" if x.is_Mul:\n",
" for a in x.args:\n",
" if isinstance(a, Number) or a.is_scalar:\n",
" factor *= a\n",
" else:\n",
" product *= a\n",
" else:\n",
" product = x\n",
" return (factor, product)\n",
"\n",
" @property\n",
" def is_commutative(self):\n",
" return True"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Showcase\n",
"\n",
"The code developed in this notebook is used in Gist [Radial Vector Fields](https://gist.github.com/WetHat/63d315df86b3bac4e9f95db3087b04ca) to compute the center of radial\n",
"vector fields from measurement data.\n",
"\n",
"Below we showcase some of the most important use cases."
]
},
{
"cell_type": "code",
"execution_count": 18,
"metadata": {},
"outputs": [],
"source": [
"from sympy import Eq, expand"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Simplifying a Dot Product with Unit Vectors\n",
"\n",
"Here we use the assumption of [$\\hat{n}_i$](#Nor_i) being a unit-vector when expanding\n",
"the dot product $(\\vec{p} - \\hat{n}_i) \\cdot (\\vec{p} - \\hat{n}_i)$. We\n",
"us the vector symbols [$\\vec{p}$](#Point) and [$\\hat{n}_i$](#Pt_i) defined earlier."
]
},
{
"cell_type": "code",
"execution_count": 19,
"metadata": {},
"outputs": [
{
"data": {
"text/markdown": [
"\n",
"<a name=\"dot\"/>"
],
"text/plain": [
"<IPython.core.display.Markdown object>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/latex": [
"$\\displaystyle \\begin{matrix}\\boxed{\\displaystyle \\left( \\left(\\vec{p} - {\\hat{n}}_{i} \\right)\\cdot\\left(\\vec{p} - {\\hat{n}}_{i} \\right) \\right)} & (4)\\ \\text{dot}\\end{matrix}$"
],
"text/plain": [
"<IPython.core.display.Math object>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"EQ.dot = DOT(EQ.Point-EQ.Nor_i,EQ.Point-EQ.Nor_i)\n",
"EQ('dot')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Expansion of [$(\\vec{p} - \\hat{n}_i) \\cdot (\\vec{p} - \\hat{n}_i)$](#dot) product then yields: "
]
},
{
"cell_type": "code",
"execution_count": 20,
"metadata": {},
"outputs": [
{
"data": {
"text/latex": [
"$\\displaystyle \\left( \\vec{p}\\cdot\\vec{p} \\right) - 2 \\left( \\vec{p}\\cdot{\\hat{n}}_{i} \\right) + 1$"
],
"text/plain": [
"DOT(\\vec{p}, \\vec{p}) - 2*DOT(\\vec{p}, \\hat{n}[i]) + 1"
]
},
"execution_count": 20,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"expand(EQ.dot)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Factoring a Sum of Dot Products\n",
"Taking dot product [$(\\vec{p} - \\hat{n}_i) \\cdot (\\vec{p} - \\hat{n}_i)$](#dot) from\n",
"the previous section we now average it over the domain $0 < i < n-1$ and call it $E$:"
]
},
{
"cell_type": "code",
"execution_count": 21,
"metadata": {},
"outputs": [],
"source": [
"from sympy import Sum, Function"
]
},
{
"cell_type": "code",
"execution_count": 22,
"metadata": {},
"outputs": [
{
"data": {
"text/markdown": [
"\n",
"<a name=\"E\"/>"
],
"text/plain": [
"<IPython.core.display.Markdown object>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/latex": [
"$\\displaystyle \\begin{matrix}\\boxed{\\displaystyle E{\\left(\\vec{p} \\right)} = \\frac{\\sum_{i=0}^{n - 1} \\left( \\left(\\vec{p} - {\\hat{n}}_{i} \\right)\\cdot\\left(\\vec{p} - {\\hat{n}}_{i} \\right) \\right)}{n}} & (5)\\ \\text{E}\\end{matrix}$"
],
"text/plain": [
"<IPython.core.display.Math object>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"E = Function('E')(EQ.Point)\n",
"EQ.E = Eq(E,\n",
" Sum(EQ.dot,(i,0,n-1))/n)\n",
"EQ('E')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Expanding that gives:"
]
},
{
"cell_type": "code",
"execution_count": 23,
"metadata": {},
"outputs": [],
"source": [
"from sympy import factor_terms"
]
},
{
"cell_type": "code",
"execution_count": 24,
"metadata": {},
"outputs": [
{
"data": {
"text/markdown": [
"\n",
"<a name=\"E_expanded\"/>"
],
"text/plain": [
"<IPython.core.display.Markdown object>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/latex": [
"$\\displaystyle \\begin{matrix}\\boxed{\\displaystyle E{\\left(\\vec{p} \\right)} = \\left( \\vec{p}\\cdot\\vec{p} \\right) + 1 - \\frac{2 \\sum_{i=0}^{n - 1} \\left( \\vec{p}\\cdot{\\hat{n}}_{i} \\right)}{n}} & (6)\\ \\text{E_expanded}\\end{matrix}$"
],
"text/plain": [
"<IPython.core.display.Math object>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"EQ.E_expanded = Eq(EQ.E.lhs,\n",
" expand(factor_terms(expand(EQ.E.rhs)).doit()))\n",
"EQ('E_expanded')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Differentiating a Sum of Dot Products\n",
"\n",
"Finally, using the equation [$E$](#E) we explore differentiation:"
]
},
{
"cell_type": "code",
"execution_count": 25,
"metadata": {},
"outputs": [
{
"data": {
"text/markdown": [
"\n",
"<a name=\"dEdp\"/>"
],
"text/plain": [
"<IPython.core.display.Markdown object>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/latex": [
"$\\displaystyle \\begin{matrix}\\boxed{\\displaystyle \\frac{d}{d \\vec{p}} E{\\left(\\vec{p} \\right)} = 2 \\vec{p} - \\frac{2 \\sum_{i=0}^{n - 1} {\\hat{n}}_{i}}{n}} & (7)\\ \\text{dEdp}\\end{matrix}$"
],
"text/plain": [
"<IPython.core.display.Math object>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"EQ.dEdp = Eq(diff(EQ.E_expanded.lhs,EQ.Point),\n",
" EQ.E_expanded.rhs.diff(EQ.Point))\n",
"EQ('dEdp')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We note that differentiation of a dot product gives a vector:"
]
},
{
"cell_type": "code",
"execution_count": 26,
"metadata": {},
"outputs": [
{
"data": {
"text/latex": [
"$\\displaystyle \\frac{d}{d\\vec{p}}(\\vec{p} \\cdot \\hat{n}_i) = {\\hat{n}}_{i}$"
],
"text/plain": [
"Eq(\\frac{d}{d\\vec{p}}(\\vec{p} \\cdot \\hat{n}_i), \\hat{n}[i])"
]
},
"execution_count": 26,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"Eq(Symbol(r'\\frac{d}{d\\vec{p}}(\\vec{p} \\cdot \\hat{n}_i)'),\n",
" diff(DOT(EQ.Point,EQ.Nor_i),EQ.Point))"
]
},
{
"cell_type": "code",
"execution_count": 27,
"metadata": {},
"outputs": [
{
"data": {
"text/markdown": [
"\n",
"<a name=\"err\"/>"
],
"text/plain": [
"<IPython.core.display.Markdown object>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/latex": [
"$\\displaystyle \\begin{matrix}\\boxed{\\displaystyle {\\vec{\\epsilon}}_{i} = \\left( \\left(\\vec{p} - {\\vec{c}}_{i} \\right)\\cdot{\\hat{n}}_{i} \\right) {\\hat{n}}_{i} + {\\vec{c}}_{i}} & (8)\\ \\text{err}\\end{matrix}$"
],
"text/plain": [
"<IPython.core.display.Math object>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"line_center_i = VectorIndexedBase(r'\\vec{c}')[i]\n",
"line_direction_i = VectorIndexedBase(r'\\hat{n}', normalized=True)[i]\n",
"lmbda = Symbol(r'\\lambda')\n",
"point_i = Function(r'\\vec{p}_i')(lmbda)\n",
"\n",
"\n",
"err = VectorIndexedBase(r'\\vec{\\epsilon}')[i]\n",
"point = VectorSymbol(r'\\vec{p}')\n",
"EQ.err = Eq(err,\n",
" line_center_i + DOT(point - line_center_i, line_direction_i) * line_direction_i)\n",
"EQ('err')"
]
},
{
"cell_type": "code",
"execution_count": 28,
"metadata": {},
"outputs": [
{
"data": {
"text/latex": [
"$\\displaystyle \\left( \\vec{p}\\cdot{\\hat{n}}_{i} \\right)^{2} - \\left( {\\hat{n}}_{i}\\cdot{\\vec{c}}_{i} \\right)^{2} + \\left( {\\vec{c}}_{i}\\cdot{\\vec{c}}_{i} \\right)$"
],
"text/plain": [
"DOT(\\vec{p}, \\hat{n}[i])**2 - DOT(\\hat{n}[i], \\vec{c}[i])**2 + DOT(\\vec{c}[i], \\vec{c}[i])"
]
},
"execution_count": 28,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"expand(DOT(EQ.err.rhs,EQ.err.rhs))"
]
},
{
"cell_type": "markdown",
"metadata": {
"tags": []
},
"source": [
"# Appendix"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## References\n",
"\n",
"* [Custom Printing](https://docs.sympy.org/latest/modules/printing.html): This guide documents the printing system in `SymPy`\n",
"* [EquationRegistry](https://gist.github.com/WetHat/6a8e38fb92ab831d8cdb5d66f2d2e524#file-py-equationregistry-ipynb) - A Simple Registry for Managing and Auto-numbering sympy Equations\n",
"* [Notebook Manifest](https://gist.github.com/WetHat/b8189b30fa4b0ceec39a60241be6ff45#file-py-notebookmanifest-ipynb) - A Python Package Manifest for Jupyter Notebooks (Python Kernel)\n",
"* [Radial Vector Fields](https://gist.github.com/WetHat/63d315df86b3bac4e9f95db3087b04ca) - Computing the Center of Radial Vector Fields From Inaccurate Measurement Data"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## About this JupyterLab Notebook\n",
"\n",
"This Gist was created using the [Jupyter Lab](https://jupyter.org/) computational notebook with\n",
"the Python3 kernel and following additional Python modules:\n"
]
},
{
"cell_type": "code",
"execution_count": 29,
"metadata": {},
"outputs": [],
"source": [
"from jnbBuffs.manifest import notebook_manifest"
]
},
{
"cell_type": "code",
"execution_count": 30,
"metadata": {},
"outputs": [
{
"data": {
"text/markdown": [
"| Component | Version | Description |\n",
"| --------------------------------- | -------------------------- | -------------------- |\n",
"| [Python](https://www.python.org/) | 3.8.6 | Programming Language |\n",
"| [jnbBuffs](https://github.com/WetHat/jupyter-notebooks) | 0.1.8 | Utilities for authoring JupyterLab Python notebooks. |\n",
"| [jupyterlab](http://jupyter.org) | 3.0.12 | The JupyterLab server extension. |\n",
"| [sympy](https://sympy.org) | 1.7.1 | Computer algebra system (CAS) in Python |"
],
"text/plain": [
"<IPython.core.display.Markdown object>"
]
},
"execution_count": 30,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"notebook_manifest('jupyterlab', 'sympy', 'jnbBuffs')"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python (JupyterLab)",
"language": "python",
"name": "jupyterlab"
},
"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.6"
},
"toc-autonumbering": true
},
"nbformat": 4,
"nbformat_minor": 4
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment