diff --git a/doc/dev/bumping-sympy.md b/doc/dev/bumping-sympy.md new file mode 100644 index 00000000..62849ec6 --- /dev/null +++ b/doc/dev/bumping-sympy.md @@ -0,0 +1,140 @@ +# Bumping the SymPy dependency + +This page documents the process for bumping the pinned SymPy version in CI +and explains the practices that have evolved around it. + +## Version policy + +Target the most recent **minor series** that is not the latest release. +For example, if 1.14 is the latest stable release, target 1.13.x (the +highest patch, e.g. 1.13.3). This gives us a version that is current +enough to catch real compatibility issues but still widely used and stable. + +The same policy applies to Python version bumps. + +## Tracking issue pattern + +A SymPy (or Python) bump typically uncovers several independent blocking +issues. Use the **tracking issue** pattern to manage this: + +1. Open a *tracker* issue describing the overall goal (e.g. "Bump SymPy + to 1.13"). Keep it focused on the goal — do not list specific errors in + the tracker body. +2. For each blocking problem found during testing, open a *sub-issue* + describing only that problem. +3. Add a comment to the tracker referencing all sub-issues. +4. Open a PR for each sub-issue independently. Sub-PRs can be reviewed + and merged in any order. +5. Once all sub-PRs are merged, open the final bump PR that updates + `test_requirements.txt` and closes the tracker. + +This keeps each PR small and reviewable, and makes it easy to see at a +glance which problems are still blocking the bump. + +## Testing locally + +Use `uv` to create a clean venv with the target Python and SymPy versions: + +```bash +uv venv --python 3.12 .venv312 +uv pip install -r test_requirements.txt -e . +``` + +Run the full CI test command: + +```bash +pytest \ + -vv --durations=50 \ + --cov=galgebra \ + --nbval examples/ipython/ \ + --nbval examples/primer/ \ + test \ + --nbval-current-env \ + --nbval-sanitize-with test/.nbval_sanitize.cfg \ + -n 2 --dist loadscope +``` + +CI also accepts a `PYTEST_K_FILTER` environment variable to pass `-k`. +See `.github/workflows/ci.yml` for the authoritative command. + +## Common compatibility issues + +### `distutils` removal (Python 3.12) + +`distutils` was removed in Python 3.12. Any `import distutils.*` must be +replaced with `packaging` (already a test dependency). + +### Unrecognized escape sequences (Python 3.12) + +Python 3.12 promotes `\m`, `\g`, `\i`, etc. in regular string literals from +`DeprecationWarning` to `SyntaxWarning`. nbval catches the resulting stderr +output and fails the cell. Fix: add the `r` prefix to affected string +literals (`r'\mathbf{e}'`). + +### `ImmutableDenseMatrix` (SymPy 1.13) + +Some SymPy 1.13 operations return `ImmutableDenseMatrix` where 1.12 returned +`MutableDenseMatrix`. Any `isinstance(x, Matrix)` check that should cover +both must be changed to `isinstance(x, MatrixBase)` (imported from +`sympy.matrices`). + +### LaTeX printing changes (SymPy 1.13) + +SymPy 1.13 changed matrix LaTeX output in two ways: + +- `\begin{array}{}` → `\begin{array}{ccc}` (column specs added) +- Explicit `\cdot` multiplication dot added/removed in some expressions + +These are cosmetic; the computed values are identical. Fix: re-execute the +affected notebooks (see *Notebook refresh workflow* below). + +### Unicode matrix art alignment (SymPy 1.13) + +Plain-text pretty-printing of matrices shifts by one space in some rows. +Also cosmetic; handled by the notebook refresh. + +## Notebook refresh workflow + +When stored notebook outputs become stale due to a SymPy printing change: + +1. Re-execute the affected notebooks with the target SymPy version: + + ```bash + pip install jupyter nbconvert + jupyter nbconvert --to notebook --execute --inplace \ + examples/ipython/gr_metrics.ipynb + ``` + +2. Validate that every output change is purely cosmetic using + `scripts/validate_nb_refresh.py`: + + ```bash + # Compare the previous commit (HEAD^) against the current working copy: + python scripts/validate_nb_refresh.py --git HEAD^ \ + examples/ipython/gr_metrics.ipynb + ``` + + The script normalizes all known cosmetic patterns (array column specs, + `\cdot`, whitespace, stream warnings) and fails with a detailed diff if + anything else changed. Exit code 0 means all changes are cosmetic. + +3. Verify the refreshed notebooks pass nbval: + + ```bash + pytest --nbval examples/ipython/gr_metrics.ipynb \ + --nbval-current-env \ + --nbval-sanitize-with test/.nbval_sanitize.cfg + ``` + +4. Include the `validate_nb_refresh.py` output in the PR description as + evidence that no mathematical content changed. + +### Adding new cosmetic normalizers + +If a new SymPy version introduces a new cosmetic rendering difference, add a +normalizer function to `scripts/validate_nb_refresh.py`: + +- For LaTeX diffs: add to `LATEX_NORMALIZERS` list. +- For plain-text diffs: update `normalize_plaintext`. +- Document the SymPy version and nature of the change in a comment next to + the normalizer function. diff --git a/doc/dev/bumping-sympy.rst b/doc/dev/bumping-sympy.rst new file mode 100644 index 00000000..a09321f1 --- /dev/null +++ b/doc/dev/bumping-sympy.rst @@ -0,0 +1 @@ +.. mdinclude:: bumping-sympy.md diff --git a/doc/index.rst b/doc/index.rst index 851f2197..6d693bd6 100644 --- a/doc/index.rst +++ b/doc/index.rst @@ -33,6 +33,7 @@ dev/release-process dev/bumping-python + dev/bumping-sympy .. toctree:: :caption: Other information diff --git a/examples/ipython/LaTeX.ipynb b/examples/ipython/LaTeX.ipynb index fab88b66..60805399 100644 --- a/examples/ipython/LaTeX.ipynb +++ b/examples/ipython/LaTeX.ipynb @@ -3,7 +3,14 @@ { "cell_type": "code", "execution_count": 1, - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2026-04-02T05:40:50.309937Z", + "iopub.status.busy": "2026-04-02T05:40:50.309862Z", + "iopub.status.idle": "2026-04-02T05:40:50.313734Z", + "shell.execute_reply": "2026-04-02T05:40:50.313217Z" + } + }, "outputs": [], "source": [ "import os\n", @@ -14,7 +21,14 @@ { "cell_type": "code", "execution_count": 2, - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2026-04-02T05:40:50.315576Z", + "iopub.status.busy": "2026-04-02T05:40:50.315466Z", + "iopub.status.idle": "2026-04-02T05:40:50.895093Z", + "shell.execute_reply": "2026-04-02T05:40:50.894515Z" + } + }, "outputs": [ { "data": { @@ -90,7 +104,14 @@ { "cell_type": "code", "execution_count": 3, - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2026-04-02T05:40:50.912312Z", + "iopub.status.busy": "2026-04-02T05:40:50.912182Z", + "iopub.status.idle": "2026-04-02T05:49:04.977406Z", + "shell.execute_reply": "2026-04-02T05:49:04.975915Z" + } + }, "outputs": [ { "data": { @@ -164,7 +185,7 @@ "\\begin{equation*} A = A^{\\xi } \\boldsymbol{e}_{\\xi } + A^{\\eta } \\boldsymbol{e}_{\\eta } + A^{\\phi } \\boldsymbol{e}_{\\phi } \\end{equation*}\n", "\\begin{equation*} B = B^{\\xi \\eta } \\boldsymbol{e}_{\\xi }\\wedge \\boldsymbol{e}_{\\eta } + B^{\\xi \\phi } \\boldsymbol{e}_{\\xi }\\wedge \\boldsymbol{e}_{\\phi } + B^{\\eta \\phi } \\boldsymbol{e}_{\\eta }\\wedge \\boldsymbol{e}_{\\phi } \\end{equation*}\n", "\\begin{equation*} \\boldsymbol{\\nabla} f = \\frac{\\partial_{\\xi } f }{\\sqrt{{\\sin{\\left (\\eta \\right )}}^{2} + {\\sinh{\\left (\\xi \\right )}}^{2}} \\left|{a}\\right|} \\boldsymbol{e}_{\\xi } + \\frac{\\partial_{\\eta } f }{\\sqrt{{\\sin{\\left (\\eta \\right )}}^{2} + {\\sinh{\\left (\\xi \\right )}}^{2}} \\left|{a}\\right|} \\boldsymbol{e}_{\\eta } + \\frac{\\partial_{\\phi } f }{a \\sin{\\left (\\eta \\right )} \\sinh{\\left (\\xi \\right )}} \\boldsymbol{e}_{\\phi } \\end{equation*}\n", - "\\begin{equation*} \\boldsymbol{\\nabla} \\cdot A = \\frac{a \\left({\\sin{\\left (\\eta \\right )}}^{2} + {\\sinh{\\left (\\xi \\right )}}^{2}\\right)^{3} \\partial_{\\phi } A^{\\phi } + \\frac{\\left(A^{\\eta } \\sin{\\left (2 \\eta \\right )} + A^{\\xi } \\sinh{\\left (2 \\xi \\right )}\\right) \\left({\\sin{\\left (\\eta \\right )}}^{2} + {\\sinh{\\left (\\xi \\right )}}^{2}\\right)^{\\frac{3}{2}} \\sin{\\left (\\eta \\right )} \\sinh{\\left (\\xi \\right )} \\left|{a}\\right|}{2} + \\left({\\sin{\\left (\\eta \\right )}}^{2} + {\\sinh{\\left (\\xi \\right )}}^{2}\\right)^{\\frac{5}{2}} \\left(\\partial_{\\eta } A^{\\eta } + \\partial_{\\xi } A^{\\xi } \\right) \\sin{\\left (\\eta \\right )} \\sinh{\\left (\\xi \\right )} \\left|{a}\\right| + \\left({\\sin{\\left (\\eta \\right )}}^{2} + {\\sinh{\\left (\\xi \\right )}}^{2}\\right)^{\\frac{5}{2}} A^{\\eta } \\cos{\\left (\\eta \\right )} \\sinh{\\left (\\xi \\right )} \\left|{a}\\right| + \\left({\\sin{\\left (\\eta \\right )}}^{2} + {\\sinh{\\left (\\xi \\right )}}^{2}\\right)^{\\frac{5}{2}} A^{\\xi } \\sin{\\left (\\eta \\right )} \\cosh{\\left (\\xi \\right )} \\left|{a}\\right|}{a^{2} \\left({\\sin{\\left (\\eta \\right )}}^{2} + {\\sinh{\\left (\\xi \\right )}}^{2}\\right)^{3} \\sin{\\left (\\eta \\right )} \\sinh{\\left (\\xi \\right )}} \\end{equation*}\n", + "\\begin{equation*} \\boldsymbol{\\nabla} \\cdot A = \\frac{A^{\\eta } \\cos{\\left (\\eta \\right )}}{\\sqrt{{\\sin{\\left (\\eta \\right )}}^{2} + {\\sinh{\\left (\\xi \\right )}}^{2}} \\sin{\\left (\\eta \\right )} \\left|{a}\\right|} + \\frac{A^{\\xi } \\cosh{\\left (\\xi \\right )}}{\\sqrt{{\\sin{\\left (\\eta \\right )}}^{2} + {\\sinh{\\left (\\xi \\right )}}^{2}} \\sinh{\\left (\\xi \\right )} \\left|{a}\\right|} + \\frac{\\partial_{\\eta } A^{\\eta } }{\\sqrt{{\\sin{\\left (\\eta \\right )}}^{2} + {\\sinh{\\left (\\xi \\right )}}^{2}} \\left|{a}\\right|} + \\frac{\\partial_{\\xi } A^{\\xi } }{\\sqrt{{\\sin{\\left (\\eta \\right )}}^{2} + {\\sinh{\\left (\\xi \\right )}}^{2}} \\left|{a}\\right|} + \\frac{A^{\\eta } \\sin{\\left (2 \\eta \\right )}}{2 \\sqrt{{\\sin{\\left (\\eta \\right )}}^{2} + {\\sinh{\\left (\\xi \\right )}}^{2}} {\\sin{\\left (\\eta \\right )}}^{2} \\left|{a}\\right| + 2 \\sqrt{{\\sin{\\left (\\eta \\right )}}^{2} + {\\sinh{\\left (\\xi \\right )}}^{2}} {\\sinh{\\left (\\xi \\right )}}^{2} \\left|{a}\\right|} + \\frac{A^{\\xi } \\sinh{\\left (2 \\xi \\right )}}{2 \\sqrt{{\\sin{\\left (\\eta \\right )}}^{2} + {\\sinh{\\left (\\xi \\right )}}^{2}} {\\sin{\\left (\\eta \\right )}}^{2} \\left|{a}\\right| + 2 \\sqrt{{\\sin{\\left (\\eta \\right )}}^{2} + {\\sinh{\\left (\\xi \\right )}}^{2}} {\\sinh{\\left (\\xi \\right )}}^{2} \\left|{a}\\right|} + \\frac{\\partial_{\\phi } A^{\\phi } }{a \\sin{\\left (\\eta \\right )} \\sinh{\\left (\\xi \\right )}} \\end{equation*}\n", "\\end{document}\n" ] }, @@ -179,7 +200,14 @@ { "cell_type": "code", "execution_count": 4, - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2026-04-02T05:49:04.981090Z", + "iopub.status.busy": "2026-04-02T05:49:04.980894Z", + "iopub.status.idle": "2026-04-02T05:49:05.425896Z", + "shell.execute_reply": "2026-04-02T05:49:05.425263Z" + } + }, "outputs": [ { "data": { @@ -249,7 +277,14 @@ { "cell_type": "code", "execution_count": 5, - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2026-04-02T05:49:05.428151Z", + "iopub.status.busy": "2026-04-02T05:49:05.428047Z", + "iopub.status.idle": "2026-04-02T05:49:05.976487Z", + "shell.execute_reply": "2026-04-02T05:49:05.975732Z" + } + }, "outputs": [ { "data": { @@ -327,7 +362,7 @@ "\\begin{equation*} A = \\left\\{ \\begin{aligned} \\boldsymbol{e}_{a} &\\mapsto a c^{2} x \\boldsymbol{e}_{a} + a b c x^{2} \\boldsymbol{e}_{b} + a^{3} b^{5} x^{2} \\boldsymbol{e}_{c} \\\\ \\boldsymbol{e}_{b} &\\mapsto a^{2} b c x^{3} \\boldsymbol{e}_{a} + a b^{2} c^{5} x^{4} \\boldsymbol{e}_{b} + 5 a b^{2} c x^{4} \\boldsymbol{e}_{c} \\\\ \\boldsymbol{e}_{c} &\\mapsto a b^{2} c^{4} x^{4} \\boldsymbol{e}_{a} + 4 a b^{2} c^{2} x^{4} \\boldsymbol{e}_{b} + 4 a^{5} b^{2} c x^{4} \\boldsymbol{e}_{c} \\end{aligned} \\right\\} \\end{equation*}\n", "\\begin{equation*} v = a \\boldsymbol{e}_{a} + b \\boldsymbol{e}_{b} + c \\boldsymbol{e}_{c} \\end{equation*}\n", "\\begin{equation*} f = v\\cdot \\f{A}{v} = a c x \\left(4 a^{4} b^{2} c^{2} x^{3} + a^{3} b^{5} x + a^{2} b^{2} x^{2} + a^{2} c + a b^{2} c^{4} x^{3} + a b^{2} x + b^{4} c^{4} x^{3} + 4 b^{3} c^{2} x^{3} + 5 b^{3} c x^{3}\\right) \\end{equation*}\n", - "\\begin{equation*} \\f{A}{v} = a c x \\left(a b^{2} x^{2} + a c + b^{2} c^{4} x^{3}\\right) \\boldsymbol{e}_{a} + a b c x^{2} \\left(a + b^{2} c^{4} x^{2} + 4 b c^{2} x^{2}\\right) \\boldsymbol{e}_{b} + a b^{2} x^{2} \\cdot \\left(4 a^{4} c^{2} x^{2} + a^{3} b^{3} + 5 b c x^{2}\\right) \\boldsymbol{e}_{c} \\end{equation*}\n", + "\\begin{equation*} \\f{A}{v} = a c x \\left(a b^{2} x^{2} + a c + b^{2} c^{4} x^{3}\\right) \\boldsymbol{e}_{a} + a b c x^{2} \\left(a + b^{2} c^{4} x^{2} + 4 b c^{2} x^{2}\\right) \\boldsymbol{e}_{b} + a b^{2} x^{2} \\left(4 a^{4} c^{2} x^{2} + a^{3} b^{3} + 5 b c x^{2}\\right) \\boldsymbol{e}_{c} \\end{equation*}\n", "\\end{document}\n" ] }, @@ -342,7 +377,14 @@ { "cell_type": "code", "execution_count": 6, - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2026-04-02T05:49:05.978087Z", + "iopub.status.busy": "2026-04-02T05:49:05.977993Z", + "iopub.status.idle": "2026-04-02T05:49:06.440061Z", + "shell.execute_reply": "2026-04-02T05:49:06.439409Z" + } + }, "outputs": [ { "data": { @@ -412,7 +454,14 @@ { "cell_type": "code", "execution_count": 7, - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2026-04-02T05:49:06.441917Z", + "iopub.status.busy": "2026-04-02T05:49:06.441807Z", + "iopub.status.idle": "2026-04-02T05:49:07.051563Z", + "shell.execute_reply": "2026-04-02T05:49:07.050956Z" + } + }, "outputs": [ { "data": { @@ -493,7 +542,14 @@ { "cell_type": "code", "execution_count": 8, - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2026-04-02T05:49:07.053167Z", + "iopub.status.busy": "2026-04-02T05:49:07.053083Z", + "iopub.status.idle": "2026-04-02T05:49:08.041330Z", + "shell.execute_reply": "2026-04-02T05:49:08.040383Z" + } + }, "outputs": [ { "data": { @@ -579,7 +635,14 @@ { "cell_type": "code", "execution_count": 9, - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2026-04-02T05:49:08.043514Z", + "iopub.status.busy": "2026-04-02T05:49:08.043368Z", + "iopub.status.idle": "2026-04-02T05:49:08.348598Z", + "shell.execute_reply": "2026-04-02T05:49:08.347609Z" + } + }, "outputs": [ { "data": { @@ -652,7 +715,14 @@ { "cell_type": "code", "execution_count": 10, - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2026-04-02T05:49:08.350270Z", + "iopub.status.busy": "2026-04-02T05:49:08.350184Z", + "iopub.status.idle": "2026-04-02T05:49:09.023669Z", + "shell.execute_reply": "2026-04-02T05:49:09.022727Z" + } + }, "outputs": [ { "data": { @@ -811,7 +881,14 @@ { "cell_type": "code", "execution_count": 11, - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2026-04-02T05:49:09.025524Z", + "iopub.status.busy": "2026-04-02T05:49:09.025402Z", + "iopub.status.idle": "2026-04-02T05:49:14.316387Z", + "shell.execute_reply": "2026-04-02T05:49:14.315572Z" + } + }, "outputs": [ { "data": { @@ -1454,7 +1531,14 @@ { "cell_type": "code", "execution_count": 12, - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2026-04-02T05:49:14.317993Z", + "iopub.status.busy": "2026-04-02T05:49:14.317902Z", + "iopub.status.idle": "2026-04-02T05:49:15.459283Z", + "shell.execute_reply": "2026-04-02T05:49:15.458625Z" + } + }, "outputs": [ { "data": { @@ -1579,7 +1663,14 @@ { "cell_type": "code", "execution_count": 13, - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2026-04-02T05:49:15.460720Z", + "iopub.status.busy": "2026-04-02T05:49:15.460649Z", + "iopub.status.idle": "2026-04-02T05:49:18.298338Z", + "shell.execute_reply": "2026-04-02T05:49:18.297606Z" + } + }, "outputs": [ { "data": { @@ -1657,7 +1748,14 @@ { "cell_type": "code", "execution_count": 14, - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2026-04-02T05:49:18.300259Z", + "iopub.status.busy": "2026-04-02T05:49:18.300175Z", + "iopub.status.idle": "2026-04-02T05:49:19.274821Z", + "shell.execute_reply": "2026-04-02T05:49:19.273788Z" + } + }, "outputs": [ { "data": { @@ -1739,7 +1837,14 @@ { "cell_type": "code", "execution_count": 15, - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2026-04-02T05:49:19.277095Z", + "iopub.status.busy": "2026-04-02T05:49:19.276959Z", + "iopub.status.idle": "2026-04-02T05:49:19.651645Z", + "shell.execute_reply": "2026-04-02T05:49:19.651021Z" + } + }, "outputs": [ { "data": { @@ -1808,7 +1913,14 @@ { "cell_type": "code", "execution_count": 16, - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2026-04-02T05:49:19.653393Z", + "iopub.status.busy": "2026-04-02T05:49:19.653280Z", + "iopub.status.idle": "2026-04-02T05:49:20.490206Z", + "shell.execute_reply": "2026-04-02T05:49:20.489532Z" + } + }, "outputs": [ { "data": { @@ -1883,7 +1995,14 @@ { "cell_type": "code", "execution_count": 17, - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2026-04-02T05:49:20.491772Z", + "iopub.status.busy": "2026-04-02T05:49:20.491668Z", + "iopub.status.idle": "2026-04-02T05:49:21.088635Z", + "shell.execute_reply": "2026-04-02T05:49:21.087838Z" + } + }, "outputs": [ { "data": { @@ -1965,7 +2084,14 @@ { "cell_type": "code", "execution_count": 18, - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2026-04-02T05:49:21.090500Z", + "iopub.status.busy": "2026-04-02T05:49:21.090386Z", + "iopub.status.idle": "2026-04-02T05:49:22.810531Z", + "shell.execute_reply": "2026-04-02T05:49:22.809606Z" + } + }, "outputs": [ { "data": { @@ -2087,7 +2213,14 @@ { "cell_type": "code", "execution_count": 19, - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2026-04-02T05:49:22.812118Z", + "iopub.status.busy": "2026-04-02T05:49:22.812027Z", + "iopub.status.idle": "2026-04-02T05:49:23.875534Z", + "shell.execute_reply": "2026-04-02T05:49:23.874700Z" + } + }, "outputs": [ { "data": { @@ -2317,7 +2450,14 @@ { "cell_type": "code", "execution_count": 20, - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2026-04-02T05:49:23.877905Z", + "iopub.status.busy": "2026-04-02T05:49:23.877797Z", + "iopub.status.idle": "2026-04-02T05:49:24.517387Z", + "shell.execute_reply": "2026-04-02T05:49:24.515992Z" + } + }, "outputs": [ { "data": { @@ -2401,7 +2541,14 @@ { "cell_type": "code", "execution_count": 21, - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2026-04-02T05:49:24.520368Z", + "iopub.status.busy": "2026-04-02T05:49:24.520100Z", + "iopub.status.idle": "2026-04-02T05:49:25.171650Z", + "shell.execute_reply": "2026-04-02T05:49:25.171011Z" + } + }, "outputs": [ { "data": { @@ -2498,7 +2645,14 @@ { "cell_type": "code", "execution_count": 22, - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2026-04-02T05:49:25.173298Z", + "iopub.status.busy": "2026-04-02T05:49:25.173208Z", + "iopub.status.idle": "2026-04-02T05:49:25.769799Z", + "shell.execute_reply": "2026-04-02T05:49:25.769109Z" + } + }, "outputs": [ { "data": { @@ -2612,7 +2766,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.11.8" + "version": "3.12.12" } }, "nbformat": 4, diff --git a/examples/ipython/Old Format.ipynb b/examples/ipython/Old Format.ipynb index 0573e2d6..1270705b 100644 --- a/examples/ipython/Old Format.ipynb +++ b/examples/ipython/Old Format.ipynb @@ -5,10 +5,10 @@ "execution_count": 1, "metadata": { "execution": { - "iopub.execute_input": "2026-03-31T04:30:13.495944Z", - "iopub.status.busy": "2026-03-31T04:30:13.495665Z", - "iopub.status.idle": "2026-03-31T04:30:13.506418Z", - "shell.execute_reply": "2026-03-31T04:30:13.505013Z" + "iopub.execute_input": "2026-04-01T13:09:47.400022Z", + "iopub.status.busy": "2026-04-01T13:09:47.399953Z", + "iopub.status.idle": "2026-04-01T13:09:47.403756Z", + "shell.execute_reply": "2026-04-01T13:09:47.403110Z" } }, "outputs": [], @@ -23,10 +23,10 @@ "execution_count": 2, "metadata": { "execution": { - "iopub.execute_input": "2026-03-31T04:30:13.511306Z", - "iopub.status.busy": "2026-03-31T04:30:13.510745Z", - "iopub.status.idle": "2026-03-31T04:30:15.028905Z", - "shell.execute_reply": "2026-03-31T04:30:15.025281Z" + "iopub.execute_input": "2026-04-01T13:09:47.405536Z", + "iopub.status.busy": "2026-04-01T13:09:47.405405Z", + "iopub.status.idle": "2026-04-01T13:09:47.732763Z", + "shell.execute_reply": "2026-04-01T13:09:47.731834Z" } }, "outputs": [ @@ -47,10 +47,6 @@ "name": "stderr", "output_type": "stream", "text": [ - "/Users/lume/projects/galgebra/.venv/lib/python3.11/site-packages/mpmath/ctx_mp.py:35: DeprecationWarning: mpnumeric is deprecated\n", - " warnings.warn(f\"{name} is deprecated\", DeprecationWarning)\n", - "/Users/lume/projects/galgebra/.venv/lib/python3.11/site-packages/mpmath/rational.py:4: DeprecationWarning: the rational private module is deprecated\n", - " warnings.warn(\"the rational private module is deprecated\",\n", "bad_example.py:4: DeprecationWarning: The `galgebra.deprecated` module is deprecated\n", " from galgebra.deprecated import MV\n" ] @@ -65,10 +61,10 @@ "execution_count": 3, "metadata": { "execution": { - "iopub.execute_input": "2026-03-31T04:30:15.154083Z", - "iopub.status.busy": "2026-03-31T04:30:15.153466Z", - "iopub.status.idle": "2026-03-31T04:30:16.930170Z", - "shell.execute_reply": "2026-03-31T04:30:16.926938Z" + "iopub.execute_input": "2026-04-01T13:09:47.747649Z", + "iopub.status.busy": "2026-04-01T13:09:47.747522Z", + "iopub.status.idle": "2026-04-01T13:09:48.215437Z", + "shell.execute_reply": "2026-04-01T13:09:48.214474Z" } }, "outputs": [ @@ -102,10 +98,6 @@ "name": "stderr", "output_type": "stream", "text": [ - "/Users/lume/projects/galgebra/.venv/lib/python3.11/site-packages/mpmath/ctx_mp.py:35: DeprecationWarning: mpnumeric is deprecated\n", - " warnings.warn(f\"{name} is deprecated\", DeprecationWarning)\n", - "/Users/lume/projects/galgebra/.venv/lib/python3.11/site-packages/mpmath/rational.py:4: DeprecationWarning: the rational private module is deprecated\n", - " warnings.warn(\"the rational private module is deprecated\",\n", "eval_check.py:5: DeprecationWarning: The `galgebra.deprecated` module is deprecated\n", " from galgebra.deprecated import MV,ReciprocalFrame\n", "eval_check.py:19: DeprecationWarning: The `galgebra.deprecated.ReciprocalFrame` function is deprecated in favor of the `ReciprocalFrame` method of `Ga` objects.\n", @@ -124,10 +116,10 @@ "execution_count": 4, "metadata": { "execution": { - "iopub.execute_input": "2026-03-31T04:30:16.939293Z", - "iopub.status.busy": "2026-03-31T04:30:16.938621Z", - "iopub.status.idle": "2026-03-31T04:30:20.660064Z", - "shell.execute_reply": "2026-03-31T04:30:20.650801Z" + "iopub.execute_input": "2026-04-01T13:09:48.217633Z", + "iopub.status.busy": "2026-04-01T13:09:48.217515Z", + "iopub.status.idle": "2026-04-01T13:09:48.659332Z", + "shell.execute_reply": "2026-04-01T13:09:48.658743Z" } }, "outputs": [ @@ -145,10 +137,6 @@ "name": "stderr", "output_type": "stream", "text": [ - "/Users/lume/projects/galgebra/.venv/lib/python3.11/site-packages/mpmath/ctx_mp.py:35: DeprecationWarning: mpnumeric is deprecated\n", - " warnings.warn(f\"{name} is deprecated\", DeprecationWarning)\n", - "/Users/lume/projects/galgebra/.venv/lib/python3.11/site-packages/mpmath/rational.py:4: DeprecationWarning: the rational private module is deprecated\n", - " warnings.warn(\"the rational private module is deprecated\",\n", "exp_check.py:5: DeprecationWarning: The `galgebra.deprecated` module is deprecated\n", " from galgebra.deprecated import MV\n", "exp_check.py:12: DeprecationWarning: The `galgebra.deprecated.MV` class is deprecated in favor of `galgebra.mv.Mv`.\n", @@ -169,10 +157,10 @@ "execution_count": 5, "metadata": { "execution": { - "iopub.execute_input": "2026-03-31T04:30:20.693346Z", - "iopub.status.busy": "2026-03-31T04:30:20.692582Z", - "iopub.status.idle": "2026-03-31T04:30:33.527993Z", - "shell.execute_reply": "2026-03-31T04:30:33.518035Z" + "iopub.execute_input": "2026-04-01T13:09:48.660899Z", + "iopub.status.busy": "2026-04-01T13:09:48.660797Z", + "iopub.status.idle": "2026-04-01T13:09:50.745065Z", + "shell.execute_reply": "2026-04-01T13:09:50.744409Z" } }, "outputs": [ @@ -180,10 +168,6 @@ "name": "stderr", "output_type": "stream", "text": [ - "/Users/lume/projects/galgebra/.venv/lib/python3.11/site-packages/mpmath/ctx_mp.py:35: DeprecationWarning: mpnumeric is deprecated\n", - " warnings.warn(f\"{name} is deprecated\", DeprecationWarning)\n", - "/Users/lume/projects/galgebra/.venv/lib/python3.11/site-packages/mpmath/rational.py:4: DeprecationWarning: the rational private module is deprecated\n", - " warnings.warn(\"the rational private module is deprecated\",\n", "latex_check.py:7: DeprecationWarning: The `galgebra.deprecated` module is deprecated\n", " from galgebra.deprecated import MV\n", "latex_check.py:32: DeprecationWarning: The `galgebra.deprecated.MV` class is deprecated in favor of `galgebra.mv.Mv`.\n", @@ -440,7 +424,7 @@ "\\begin{equation*} B = B^{r\\theta } \\boldsymbol{e}_{r}\\wedge \\boldsymbol{e}_{\\theta } + B^{r\\phi } \\boldsymbol{e}_{r}\\wedge \\boldsymbol{e}_{\\phi } + B^{\\theta \\phi } \\boldsymbol{e}_{\\theta }\\wedge \\boldsymbol{e}_{\\phi } \\end{equation*}\n", "\\begin{equation*} \\boldsymbol{\\nabla} f = \\partial_{r} f \\boldsymbol{e}_{r} + \\frac{\\partial_{\\theta } f }{r^{2}} \\boldsymbol{e}_{\\theta } + \\frac{\\partial_{\\phi } f }{r^{2} {\\sin{\\left (\\theta \\right )}}^{2}} \\boldsymbol{e}_{\\phi } \\end{equation*}\n", "\\begin{equation*} \\boldsymbol{\\nabla} \\cdot A = \\frac{A^{\\theta } }{\\tan{\\left (\\theta \\right )}} + \\partial_{\\phi } A^{\\phi } + \\partial_{r} A^{r} + \\partial_{\\theta } A^{\\theta } + \\frac{2 A^{r} }{r} \\end{equation*}\n", - "\\begin{equation*} -I (\\boldsymbol{\\nabla} \\W A) = \\frac{\\sqrt{r^{4} {\\sin{\\left (\\theta \\right )}}^{2}} \\cdot \\left(\\frac{2 A^{\\phi } }{\\tan{\\left (\\theta \\right )}} + \\partial_{\\theta } A^{\\phi } - \\frac{\\partial_{\\phi } A^{\\theta } }{{\\sin{\\left (\\theta \\right )}}^{2}}\\right)}{r^{2}} \\boldsymbol{e}_{r} + \\frac{- r^{2} {\\sin{\\left (\\theta \\right )}}^{2} \\partial_{r} A^{\\phi } - 2 r A^{\\phi } {\\sin{\\left (\\theta \\right )}}^{2} + \\partial_{\\phi } A^{r} }{\\sqrt{r^{4} {\\sin{\\left (\\theta \\right )}}^{2}}} \\boldsymbol{e}_{\\theta } + \\frac{r^{2} \\partial_{r} A^{\\theta } + 2 r A^{\\theta } - \\partial_{\\theta } A^{r} }{\\sqrt{r^{4} {\\sin{\\left (\\theta \\right )}}^{2}}} \\boldsymbol{e}_{\\phi } \\end{equation*}\n", + "\\begin{equation*} -I (\\boldsymbol{\\nabla} \\W A) = \\frac{\\sqrt{r^{4} {\\sin{\\left (\\theta \\right )}}^{2}} \\left(\\frac{2 A^{\\phi } }{\\tan{\\left (\\theta \\right )}} + \\partial_{\\theta } A^{\\phi } - \\frac{\\partial_{\\phi } A^{\\theta } }{{\\sin{\\left (\\theta \\right )}}^{2}}\\right)}{r^{2}} \\boldsymbol{e}_{r} + \\frac{- r^{2} {\\sin{\\left (\\theta \\right )}}^{2} \\partial_{r} A^{\\phi } - 2 r A^{\\phi } {\\sin{\\left (\\theta \\right )}}^{2} + \\partial_{\\phi } A^{r} }{\\sqrt{r^{4} {\\sin{\\left (\\theta \\right )}}^{2}}} \\boldsymbol{e}_{\\theta } + \\frac{r^{2} \\partial_{r} A^{\\theta } + 2 r A^{\\theta } - \\partial_{\\theta } A^{r} }{\\sqrt{r^{4} {\\sin{\\left (\\theta \\right )}}^{2}}} \\boldsymbol{e}_{\\phi } \\end{equation*}\n", "\\begin{equation*} \\boldsymbol{\\nabla} \\W B = \\frac{r^{2} \\partial_{r} B^{\\theta \\phi } + 4 r B^{\\theta \\phi } - \\frac{2 B^{r\\phi } }{\\tan{\\left (\\theta \\right )}} - \\partial_{\\theta } B^{r\\phi } + \\frac{\\partial_{\\phi } B^{r\\theta } }{{\\sin{\\left (\\theta \\right )}}^{2}}}{r^{2}} \\boldsymbol{e}_{r}\\wedge \\boldsymbol{e}_{\\theta }\\wedge \\boldsymbol{e}_{\\phi } \\end{equation*}\n", "\\begin{lstlisting}[language=Python,showspaces=false,showstringspaces=false,backgroundcolor=\\color{gray},frame=single]\n", "def conformal_representations_of_circles_lines_spheres_and_planes():\n", @@ -639,23 +623,13 @@ "execution_count": 6, "metadata": { "execution": { - "iopub.execute_input": "2026-03-31T04:30:33.539087Z", - "iopub.status.busy": "2026-03-31T04:30:33.537389Z", - "iopub.status.idle": "2026-03-31T04:30:35.557924Z", - "shell.execute_reply": "2026-03-31T04:30:35.550811Z" + "iopub.execute_input": "2026-04-01T13:09:50.746626Z", + "iopub.status.busy": "2026-04-01T13:09:50.746545Z", + "iopub.status.idle": "2026-04-01T13:09:51.042444Z", + "shell.execute_reply": "2026-04-01T13:09:51.041534Z" } }, "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/Users/lume/projects/galgebra/.venv/lib/python3.11/site-packages/mpmath/ctx_mp.py:35: DeprecationWarning: mpnumeric is deprecated\n", - " warnings.warn(f\"{name} is deprecated\", DeprecationWarning)\n", - "/Users/lume/projects/galgebra/.venv/lib/python3.11/site-packages/mpmath/rational.py:4: DeprecationWarning: the rational private module is deprecated\n", - " warnings.warn(\"the rational private module is deprecated\",\n" - ] - }, { "data": { "text/plain": [ @@ -725,10 +699,10 @@ "execution_count": 7, "metadata": { "execution": { - "iopub.execute_input": "2026-03-31T04:30:35.561927Z", - "iopub.status.busy": "2026-03-31T04:30:35.561576Z", - "iopub.status.idle": "2026-03-31T04:30:36.975367Z", - "shell.execute_reply": "2026-03-31T04:30:36.973404Z" + "iopub.execute_input": "2026-04-01T13:09:51.044210Z", + "iopub.status.busy": "2026-04-01T13:09:51.044126Z", + "iopub.status.idle": "2026-04-01T13:09:51.345539Z", + "shell.execute_reply": "2026-04-01T13:09:51.344749Z" } }, "outputs": [ @@ -746,10 +720,6 @@ "name": "stderr", "output_type": "stream", "text": [ - "/Users/lume/projects/galgebra/.venv/lib/python3.11/site-packages/mpmath/ctx_mp.py:35: DeprecationWarning: mpnumeric is deprecated\n", - " warnings.warn(f\"{name} is deprecated\", DeprecationWarning)\n", - "/Users/lume/projects/galgebra/.venv/lib/python3.11/site-packages/mpmath/rational.py:4: DeprecationWarning: the rational private module is deprecated\n", - " warnings.warn(\"the rational private module is deprecated\",\n", "mv_setup_options.py:3: DeprecationWarning: The `galgebra.deprecated` module is deprecated\n", " from galgebra.deprecated import MV\n", "mv_setup_options.py:8: DeprecationWarning: The `galgebra.deprecated.MV` class is deprecated in favor of `galgebra.mv.Mv`.\n", @@ -772,10 +742,10 @@ "execution_count": 8, "metadata": { "execution": { - "iopub.execute_input": "2026-03-31T04:30:36.981402Z", - "iopub.status.busy": "2026-03-31T04:30:36.980256Z", - "iopub.status.idle": "2026-03-31T04:30:40.713918Z", - "shell.execute_reply": "2026-03-31T04:30:40.712355Z" + "iopub.execute_input": "2026-04-01T13:09:51.347436Z", + "iopub.status.busy": "2026-04-01T13:09:51.347356Z", + "iopub.status.idle": "2026-04-01T13:09:52.177936Z", + "shell.execute_reply": "2026-04-01T13:09:52.177215Z" } }, "outputs": [ @@ -783,10 +753,6 @@ "name": "stderr", "output_type": "stream", "text": [ - "/Users/lume/projects/galgebra/.venv/lib/python3.11/site-packages/mpmath/ctx_mp.py:35: DeprecationWarning: mpnumeric is deprecated\n", - " warnings.warn(f\"{name} is deprecated\", DeprecationWarning)\n", - "/Users/lume/projects/galgebra/.venv/lib/python3.11/site-packages/mpmath/rational.py:4: DeprecationWarning: the rational private module is deprecated\n", - " warnings.warn(\"the rational private module is deprecated\",\n", "physics_check_latex.py:6: DeprecationWarning: The `galgebra.deprecated` module is deprecated\n", " from galgebra.deprecated import MV\n", "physics_check_latex.py:14: DeprecationWarning: The `galgebra.deprecated.MV` class is deprecated in favor of `galgebra.mv.Mv`.\n", @@ -795,8 +761,6 @@ " E = MV('E','vector',fct=True)\n", "physics_check_latex.py:20: DeprecationWarning: The `galgebra.deprecated.MV` class is deprecated in favor of `galgebra.mv.Mv`.\n", " J = MV('J','vector',fct=True)\n", - "/Users/lume/projects/galgebra/.venv/lib/python3.11/site-packages/mpmath/libmp/libintmath.py:75: DeprecationWarning: bitcount function is deprecated\n", - " warnings.warn(\"bitcount function is deprecated\",\n", "physics_check_latex.py:48: DeprecationWarning: The `galgebra.deprecated.MV` class is deprecated in favor of `galgebra.mv.Mv`.\n", " psi = MV('psi','spinor',fct=True)\n", "physics_check_latex.py:49: DeprecationWarning: The `galgebra.deprecated.MV` class is deprecated in favor of `galgebra.mv.Mv`.\n", @@ -960,10 +924,10 @@ "execution_count": 9, "metadata": { "execution": { - "iopub.execute_input": "2026-03-31T04:30:40.717799Z", - "iopub.status.busy": "2026-03-31T04:30:40.717527Z", - "iopub.status.idle": "2026-03-31T04:30:50.857374Z", - "shell.execute_reply": "2026-03-31T04:30:50.851089Z" + "iopub.execute_input": "2026-04-01T13:09:52.179493Z", + "iopub.status.busy": "2026-04-01T13:09:52.179403Z", + "iopub.status.idle": "2026-04-01T13:09:53.820151Z", + "shell.execute_reply": "2026-04-01T13:09:53.819527Z" } }, "outputs": [ @@ -971,14 +935,8 @@ "name": "stderr", "output_type": "stream", "text": [ - "/Users/lume/projects/galgebra/.venv/lib/python3.11/site-packages/mpmath/ctx_mp.py:35: DeprecationWarning: mpnumeric is deprecated\n", - " warnings.warn(f\"{name} is deprecated\", DeprecationWarning)\n", - "/Users/lume/projects/galgebra/.venv/lib/python3.11/site-packages/mpmath/rational.py:4: DeprecationWarning: the rational private module is deprecated\n", - " warnings.warn(\"the rational private module is deprecated\",\n", "print_check_latex.py:5: DeprecationWarning: The `galgebra.deprecated` module is deprecated\n", " from galgebra.deprecated import MV\n", - "/Users/lume/projects/galgebra/.venv/lib/python3.11/site-packages/mpmath/libmp/libintmath.py:75: DeprecationWarning: bitcount function is deprecated\n", - " warnings.warn(\"bitcount function is deprecated\",\n", "print_check_latex.py:11: DeprecationWarning: The `galgebra.deprecated.MV` class is deprecated in favor of `galgebra.mv.Mv`.\n", " A = MV('A','mv')\n", "print_check_latex.py:19: DeprecationWarning: The `galgebra.deprecated.MV` class is deprecated in favor of `galgebra.mv.Mv`.\n", @@ -1096,7 +1054,7 @@ "\\begin{equation*} B = B^{r\\theta } \\boldsymbol{e}_{r}\\wedge \\boldsymbol{e}_{\\theta } + B^{r\\phi } \\boldsymbol{e}_{r}\\wedge \\boldsymbol{e}_{\\phi } + B^{\\theta \\phi } \\boldsymbol{e}_{\\theta }\\wedge \\boldsymbol{e}_{\\phi } \\end{equation*}\n", "\\begin{equation*} \\boldsymbol{\\nabla} f = \\partial_{r} f \\boldsymbol{e}_{r} + \\frac{\\partial_{\\theta } f }{r^{2}} \\boldsymbol{e}_{\\theta } + \\frac{\\partial_{\\phi } f }{r^{2} {\\sin{\\left (\\theta \\right )}}^{2}} \\boldsymbol{e}_{\\phi } \\end{equation*}\n", "\\begin{equation*} \\boldsymbol{\\nabla} \\cdot A = \\frac{A^{\\theta } }{\\tan{\\left (\\theta \\right )}} + \\partial_{\\phi } A^{\\phi } + \\partial_{r} A^{r} + \\partial_{\\theta } A^{\\theta } + \\frac{2 A^{r} }{r} \\end{equation*}\n", - "\\begin{equation*} -I (\\boldsymbol{\\nabla} \\W A) = \\frac{\\sqrt{r^{4} {\\sin{\\left (\\theta \\right )}}^{2}} \\cdot \\left(\\frac{2 A^{\\phi } }{\\tan{\\left (\\theta \\right )}} + \\partial_{\\theta } A^{\\phi } - \\frac{\\partial_{\\phi } A^{\\theta } }{{\\sin{\\left (\\theta \\right )}}^{2}}\\right)}{r^{2}} \\boldsymbol{e}_{r} + \\frac{- r^{2} {\\sin{\\left (\\theta \\right )}}^{2} \\partial_{r} A^{\\phi } - 2 r A^{\\phi } {\\sin{\\left (\\theta \\right )}}^{2} + \\partial_{\\phi } A^{r} }{\\sqrt{r^{4} {\\sin{\\left (\\theta \\right )}}^{2}}} \\boldsymbol{e}_{\\theta } + \\frac{r^{2} \\partial_{r} A^{\\theta } + 2 r A^{\\theta } - \\partial_{\\theta } A^{r} }{\\sqrt{r^{4} {\\sin{\\left (\\theta \\right )}}^{2}}} \\boldsymbol{e}_{\\phi } \\end{equation*}\n", + "\\begin{equation*} -I (\\boldsymbol{\\nabla} \\W A) = \\frac{\\sqrt{r^{4} {\\sin{\\left (\\theta \\right )}}^{2}} \\left(\\frac{2 A^{\\phi } }{\\tan{\\left (\\theta \\right )}} + \\partial_{\\theta } A^{\\phi } - \\frac{\\partial_{\\phi } A^{\\theta } }{{\\sin{\\left (\\theta \\right )}}^{2}}\\right)}{r^{2}} \\boldsymbol{e}_{r} + \\frac{- r^{2} {\\sin{\\left (\\theta \\right )}}^{2} \\partial_{r} A^{\\phi } - 2 r A^{\\phi } {\\sin{\\left (\\theta \\right )}}^{2} + \\partial_{\\phi } A^{r} }{\\sqrt{r^{4} {\\sin{\\left (\\theta \\right )}}^{2}}} \\boldsymbol{e}_{\\theta } + \\frac{r^{2} \\partial_{r} A^{\\theta } + 2 r A^{\\theta } - \\partial_{\\theta } A^{r} }{\\sqrt{r^{4} {\\sin{\\left (\\theta \\right )}}^{2}}} \\boldsymbol{e}_{\\phi } \\end{equation*}\n", "\\begin{equation*} \\boldsymbol{\\nabla} \\W B = \\frac{r^{2} \\partial_{r} B^{\\theta \\phi } + 4 r B^{\\theta \\phi } - \\frac{2 B^{r\\phi } }{\\tan{\\left (\\theta \\right )}} - \\partial_{\\theta } B^{r\\phi } + \\frac{\\partial_{\\phi } B^{r\\theta } }{{\\sin{\\left (\\theta \\right )}}^{2}}}{r^{2}} \\boldsymbol{e}_{r}\\wedge \\boldsymbol{e}_{\\theta }\\wedge \\boldsymbol{e}_{\\phi } \\end{equation*}\n", "\\begin{equation*} B = \\bm{B\\gamma_{t}} = - B^{x} \\boldsymbol{\\gamma }_{t}\\wedge \\boldsymbol{\\gamma }_{x} - B^{y} \\boldsymbol{\\gamma }_{t}\\wedge \\boldsymbol{\\gamma }_{y} - B^{z} \\boldsymbol{\\gamma }_{t}\\wedge \\boldsymbol{\\gamma }_{z} \\end{equation*}\n", "\\begin{equation*} E = \\bm{E\\gamma_{t}} = - E^{x} \\boldsymbol{\\gamma }_{t}\\wedge \\boldsymbol{\\gamma }_{x} - E^{y} \\boldsymbol{\\gamma }_{t}\\wedge \\boldsymbol{\\gamma }_{y} - E^{z} \\boldsymbol{\\gamma }_{t}\\wedge \\boldsymbol{\\gamma }_{z} \\end{equation*}\n", @@ -1127,10 +1085,10 @@ "execution_count": 10, "metadata": { "execution": { - "iopub.execute_input": "2026-03-31T04:30:50.873709Z", - "iopub.status.busy": "2026-03-31T04:30:50.873152Z", - "iopub.status.idle": "2026-03-31T04:30:52.945881Z", - "shell.execute_reply": "2026-03-31T04:30:52.941600Z" + "iopub.execute_input": "2026-04-01T13:09:53.821925Z", + "iopub.status.busy": "2026-04-01T13:09:53.821835Z", + "iopub.status.idle": "2026-04-01T13:09:54.238078Z", + "shell.execute_reply": "2026-04-01T13:09:54.237423Z" } }, "outputs": [ @@ -1154,10 +1112,6 @@ "name": "stderr", "output_type": "stream", "text": [ - "/Users/lume/projects/galgebra/.venv/lib/python3.11/site-packages/mpmath/ctx_mp.py:35: DeprecationWarning: mpnumeric is deprecated\n", - " warnings.warn(f\"{name} is deprecated\", DeprecationWarning)\n", - "/Users/lume/projects/galgebra/.venv/lib/python3.11/site-packages/mpmath/rational.py:4: DeprecationWarning: the rational private module is deprecated\n", - " warnings.warn(\"the rational private module is deprecated\",\n", "prob_not_solenoidal.py:5: DeprecationWarning: The `galgebra.deprecated` module is deprecated\n", " from galgebra.deprecated import MV\n", "prob_not_solenoidal.py:18: DeprecationWarning: The `galgebra.deprecated.MV` class is deprecated in favor of `galgebra.mv.Mv`.\n", @@ -1174,10 +1128,10 @@ "execution_count": 11, "metadata": { "execution": { - "iopub.execute_input": "2026-03-31T04:30:52.959619Z", - "iopub.status.busy": "2026-03-31T04:30:52.953255Z", - "iopub.status.idle": "2026-03-31T04:30:57.632933Z", - "shell.execute_reply": "2026-03-31T04:30:57.630134Z" + "iopub.execute_input": "2026-04-01T13:09:54.239724Z", + "iopub.status.busy": "2026-04-01T13:09:54.239611Z", + "iopub.status.idle": "2026-04-01T13:09:55.140534Z", + "shell.execute_reply": "2026-04-01T13:09:55.139816Z" } }, "outputs": [ @@ -1361,10 +1315,6 @@ "name": "stderr", "output_type": "stream", "text": [ - "/Users/lume/projects/galgebra/.venv/lib/python3.11/site-packages/mpmath/ctx_mp.py:35: DeprecationWarning: mpnumeric is deprecated\n", - " warnings.warn(f\"{name} is deprecated\", DeprecationWarning)\n", - "/Users/lume/projects/galgebra/.venv/lib/python3.11/site-packages/mpmath/rational.py:4: DeprecationWarning: the rational private module is deprecated\n", - " warnings.warn(\"the rational private module is deprecated\",\n", "products_latex.py:3: DeprecationWarning: The `galgebra.deprecated` module is deprecated\n", " from galgebra.deprecated import MV\n", "products_latex.py:13: DeprecationWarning: The `galgebra.deprecated.MV` class is deprecated in favor of `galgebra.mv.Mv`.\n", @@ -1373,8 +1323,6 @@ " v = MV('v','vector')\n", "products_latex.py:15: DeprecationWarning: The `galgebra.deprecated.MV` class is deprecated in favor of `galgebra.mv.Mv`.\n", " b = MV('b','bivector')\n", - "/Users/lume/projects/galgebra/.venv/lib/python3.11/site-packages/mpmath/libmp/libintmath.py:75: DeprecationWarning: bitcount function is deprecated\n", - " warnings.warn(\"bitcount function is deprecated\",\n", "products_latex.py:38: DeprecationWarning: The `galgebra.deprecated.MV` class is deprecated in favor of `galgebra.mv.Mv`.\n", " fs = MV('s','scalar',fct=True)\n", "products_latex.py:39: DeprecationWarning: The `galgebra.deprecated.MV` class is deprecated in favor of `galgebra.mv.Mv`.\n", @@ -1399,10 +1347,10 @@ "execution_count": 12, "metadata": { "execution": { - "iopub.execute_input": "2026-03-31T04:30:57.639185Z", - "iopub.status.busy": "2026-03-31T04:30:57.638622Z", - "iopub.status.idle": "2026-03-31T04:30:59.334006Z", - "shell.execute_reply": "2026-03-31T04:30:59.332031Z" + "iopub.execute_input": "2026-04-01T13:09:55.142027Z", + "iopub.status.busy": "2026-04-01T13:09:55.141917Z", + "iopub.status.idle": "2026-04-01T13:09:55.526782Z", + "shell.execute_reply": "2026-04-01T13:09:55.526039Z" } }, "outputs": [ @@ -1410,18 +1358,12 @@ "name": "stderr", "output_type": "stream", "text": [ - "/Users/lume/projects/galgebra/.venv/lib/python3.11/site-packages/mpmath/ctx_mp.py:35: DeprecationWarning: mpnumeric is deprecated\n", - " warnings.warn(f\"{name} is deprecated\", DeprecationWarning)\n", - "/Users/lume/projects/galgebra/.venv/lib/python3.11/site-packages/mpmath/rational.py:4: DeprecationWarning: the rational private module is deprecated\n", - " warnings.warn(\"the rational private module is deprecated\",\n", "reflect_test.py:4: DeprecationWarning: The `galgebra.deprecated` module is deprecated\n", " from galgebra.deprecated import MV\n", "reflect_test.py:10: DeprecationWarning: The `galgebra.deprecated.MV` class is deprecated in favor of `galgebra.mv.Mv`.\n", " a = MV('a','vector')\n", "reflect_test.py:13: DeprecationWarning: The `galgebra.deprecated.MV` class is deprecated in favor of `galgebra.mv.Mv`.\n", - " c = MV('c','vector')\n", - "/Users/lume/projects/galgebra/.venv/lib/python3.11/site-packages/mpmath/libmp/libintmath.py:75: DeprecationWarning: bitcount function is deprecated\n", - " warnings.warn(\"bitcount function is deprecated\",\n" + " c = MV('c','vector')\n" ] }, { @@ -1506,10 +1448,10 @@ "execution_count": 13, "metadata": { "execution": { - "iopub.execute_input": "2026-03-31T04:30:59.339506Z", - "iopub.status.busy": "2026-03-31T04:30:59.339069Z", - "iopub.status.idle": "2026-03-31T04:31:01.442894Z", - "shell.execute_reply": "2026-03-31T04:31:01.439257Z" + "iopub.execute_input": "2026-04-01T13:09:55.528811Z", + "iopub.status.busy": "2026-04-01T13:09:55.528704Z", + "iopub.status.idle": "2026-04-01T13:09:55.929416Z", + "shell.execute_reply": "2026-04-01T13:09:55.928508Z" } }, "outputs": [ @@ -1517,10 +1459,6 @@ "name": "stderr", "output_type": "stream", "text": [ - "/Users/lume/projects/galgebra/.venv/lib/python3.11/site-packages/mpmath/ctx_mp.py:35: DeprecationWarning: mpnumeric is deprecated\n", - " warnings.warn(f\"{name} is deprecated\", DeprecationWarning)\n", - "/Users/lume/projects/galgebra/.venv/lib/python3.11/site-packages/mpmath/rational.py:4: DeprecationWarning: the rational private module is deprecated\n", - " warnings.warn(\"the rational private module is deprecated\",\n", "simple_check_latex.py:3: DeprecationWarning: The `galgebra.deprecated` module is deprecated\n", " from galgebra.deprecated import MV\n", "simple_check_latex.py:10: DeprecationWarning: The `galgebra.deprecated.MV` class is deprecated in favor of `galgebra.mv.Mv`.\n", @@ -1611,10 +1549,10 @@ "execution_count": 14, "metadata": { "execution": { - "iopub.execute_input": "2026-03-31T04:31:01.448870Z", - "iopub.status.busy": "2026-03-31T04:31:01.448497Z", - "iopub.status.idle": "2026-03-31T04:31:04.315471Z", - "shell.execute_reply": "2026-03-31T04:31:04.312174Z" + "iopub.execute_input": "2026-04-01T13:09:55.932394Z", + "iopub.status.busy": "2026-04-01T13:09:55.932280Z", + "iopub.status.idle": "2026-04-01T13:09:56.376212Z", + "shell.execute_reply": "2026-04-01T13:09:56.375703Z" } }, "outputs": [ @@ -1636,10 +1574,6 @@ "name": "stderr", "output_type": "stream", "text": [ - "/Users/lume/projects/galgebra/.venv/lib/python3.11/site-packages/mpmath/ctx_mp.py:35: DeprecationWarning: mpnumeric is deprecated\n", - " warnings.warn(f\"{name} is deprecated\", DeprecationWarning)\n", - "/Users/lume/projects/galgebra/.venv/lib/python3.11/site-packages/mpmath/rational.py:4: DeprecationWarning: the rational private module is deprecated\n", - " warnings.warn(\"the rational private module is deprecated\",\n", "simple_check.py:5: DeprecationWarning: The `galgebra.deprecated` module is deprecated\n", " from galgebra.deprecated import MV\n", "simple_check.py:13: DeprecationWarning: The `galgebra.deprecated.MV` class is deprecated in favor of `galgebra.mv.Mv`.\n", @@ -1647,9 +1581,7 @@ "simple_check.py:14: DeprecationWarning: The `galgebra.deprecated.MV` class is deprecated in favor of `galgebra.mv.Mv`.\n", " v = MV('v','vector')\n", "simple_check.py:15: DeprecationWarning: The `galgebra.deprecated.MV` class is deprecated in favor of `galgebra.mv.Mv`.\n", - " w = MV('w','vector')\n", - "/Users/lume/projects/galgebra/.venv/lib/python3.11/site-packages/mpmath/libmp/libintmath.py:75: DeprecationWarning: bitcount function is deprecated\n", - " warnings.warn(\"bitcount function is deprecated\",\n" + " w = MV('w','vector')\n" ] } ], @@ -1662,10 +1594,10 @@ "execution_count": 15, "metadata": { "execution": { - "iopub.execute_input": "2026-03-31T04:31:04.319457Z", - "iopub.status.busy": "2026-03-31T04:31:04.319161Z", - "iopub.status.idle": "2026-03-31T04:31:11.930319Z", - "shell.execute_reply": "2026-03-31T04:31:11.924491Z" + "iopub.execute_input": "2026-04-01T13:09:56.377832Z", + "iopub.status.busy": "2026-04-01T13:09:56.377723Z", + "iopub.status.idle": "2026-04-01T13:09:57.473340Z", + "shell.execute_reply": "2026-04-01T13:09:57.472374Z" } }, "outputs": [ @@ -1673,14 +1605,8 @@ "name": "stderr", "output_type": "stream", "text": [ - "/Users/lume/projects/galgebra/.venv/lib/python3.11/site-packages/mpmath/ctx_mp.py:35: DeprecationWarning: mpnumeric is deprecated\n", - " warnings.warn(f\"{name} is deprecated\", DeprecationWarning)\n", - "/Users/lume/projects/galgebra/.venv/lib/python3.11/site-packages/mpmath/rational.py:4: DeprecationWarning: the rational private module is deprecated\n", - " warnings.warn(\"the rational private module is deprecated\",\n", "spherical_latex.py:5: DeprecationWarning: The `galgebra.deprecated` module is deprecated\n", " from galgebra.deprecated import MV\n", - "/Users/lume/projects/galgebra/.venv/lib/python3.11/site-packages/mpmath/libmp/libintmath.py:75: DeprecationWarning: bitcount function is deprecated\n", - " warnings.warn(\"bitcount function is deprecated\",\n", "spherical_latex.py:14: DeprecationWarning: The `galgebra.deprecated.MV` class is deprecated in favor of `galgebra.mv.Mv`.\n", " f = MV('f','scalar',fct=True)\n", "spherical_latex.py:15: DeprecationWarning: The `galgebra.deprecated.MV` class is deprecated in favor of `galgebra.mv.Mv`.\n", @@ -1764,7 +1690,7 @@ "\\begin{equation*} B = B^{r\\theta } \\boldsymbol{e}_{r}\\wedge \\boldsymbol{e}_{\\theta } + B^{r\\phi } \\boldsymbol{e}_{r}\\wedge \\boldsymbol{e}_{\\phi } + B^{\\theta \\phi } \\boldsymbol{e}_{\\theta }\\wedge \\boldsymbol{e}_{\\phi } \\end{equation*}\n", "\\begin{equation*} \\boldsymbol{\\nabla} f = \\partial_{r} f \\boldsymbol{e}_{r} + \\frac{\\partial_{\\theta } f }{r^{2}} \\boldsymbol{e}_{\\theta } + \\frac{\\partial_{\\phi } f }{r^{2} {\\sin{\\left (\\theta \\right )}}^{2}} \\boldsymbol{e}_{\\phi } \\end{equation*}\n", "\\begin{equation*} \\boldsymbol{\\nabla} \\cdot A = \\frac{A^{\\theta } }{\\tan{\\left (\\theta \\right )}} + \\partial_{\\phi } A^{\\phi } + \\partial_{r} A^{r} + \\partial_{\\theta } A^{\\theta } + \\frac{2 A^{r} }{r} \\end{equation*}\n", - "\\begin{equation*} -I (\\boldsymbol{\\nabla} \\W A) = \\frac{\\sqrt{r^{4} {\\sin{\\left (\\theta \\right )}}^{2}} \\cdot \\left(\\frac{2 A^{\\phi } }{\\tan{\\left (\\theta \\right )}} + \\partial_{\\theta } A^{\\phi } - \\frac{\\partial_{\\phi } A^{\\theta } }{{\\sin{\\left (\\theta \\right )}}^{2}}\\right)}{r^{2}} \\boldsymbol{e}_{r} + \\frac{- r^{2} {\\sin{\\left (\\theta \\right )}}^{2} \\partial_{r} A^{\\phi } - 2 r A^{\\phi } {\\sin{\\left (\\theta \\right )}}^{2} + \\partial_{\\phi } A^{r} }{\\sqrt{r^{4} {\\sin{\\left (\\theta \\right )}}^{2}}} \\boldsymbol{e}_{\\theta } + \\frac{r^{2} \\partial_{r} A^{\\theta } + 2 r A^{\\theta } - \\partial_{\\theta } A^{r} }{\\sqrt{r^{4} {\\sin{\\left (\\theta \\right )}}^{2}}} \\boldsymbol{e}_{\\phi } \\end{equation*}\n", + "\\begin{equation*} -I (\\boldsymbol{\\nabla} \\W A) = \\frac{\\sqrt{r^{4} {\\sin{\\left (\\theta \\right )}}^{2}} \\left(\\frac{2 A^{\\phi } }{\\tan{\\left (\\theta \\right )}} + \\partial_{\\theta } A^{\\phi } - \\frac{\\partial_{\\phi } A^{\\theta } }{{\\sin{\\left (\\theta \\right )}}^{2}}\\right)}{r^{2}} \\boldsymbol{e}_{r} + \\frac{- r^{2} {\\sin{\\left (\\theta \\right )}}^{2} \\partial_{r} A^{\\phi } - 2 r A^{\\phi } {\\sin{\\left (\\theta \\right )}}^{2} + \\partial_{\\phi } A^{r} }{\\sqrt{r^{4} {\\sin{\\left (\\theta \\right )}}^{2}}} \\boldsymbol{e}_{\\theta } + \\frac{r^{2} \\partial_{r} A^{\\theta } + 2 r A^{\\theta } - \\partial_{\\theta } A^{r} }{\\sqrt{r^{4} {\\sin{\\left (\\theta \\right )}}^{2}}} \\boldsymbol{e}_{\\phi } \\end{equation*}\n", "\\begin{equation*} \\boldsymbol{\\nabla} \\W B = \\frac{r^{2} \\partial_{r} B^{\\theta \\phi } + 4 r B^{\\theta \\phi } - \\frac{2 B^{r\\phi } }{\\tan{\\left (\\theta \\right )}} - \\partial_{\\theta } B^{r\\phi } + \\frac{\\partial_{\\phi } B^{r\\theta } }{{\\sin{\\left (\\theta \\right )}}^{2}}}{r^{2}} \\boldsymbol{e}_{r}\\wedge \\boldsymbol{e}_{\\theta }\\wedge \\boldsymbol{e}_{\\phi } \\end{equation*}\n", "\\end{document}\n" ] @@ -1782,10 +1708,10 @@ "execution_count": 16, "metadata": { "execution": { - "iopub.execute_input": "2026-03-31T04:31:11.939086Z", - "iopub.status.busy": "2026-03-31T04:31:11.938174Z", - "iopub.status.idle": "2026-03-31T04:31:35.017597Z", - "shell.execute_reply": "2026-03-31T04:31:35.014079Z" + "iopub.execute_input": "2026-04-01T13:09:57.474910Z", + "iopub.status.busy": "2026-04-01T13:09:57.474817Z", + "iopub.status.idle": "2026-04-01T13:10:01.595705Z", + "shell.execute_reply": "2026-04-01T13:10:01.594542Z" } }, "outputs": [ @@ -1941,10 +1867,6 @@ "name": "stderr", "output_type": "stream", "text": [ - "/Users/lume/projects/galgebra/.venv/lib/python3.11/site-packages/mpmath/ctx_mp.py:35: DeprecationWarning: mpnumeric is deprecated\n", - " warnings.warn(f\"{name} is deprecated\", DeprecationWarning)\n", - "/Users/lume/projects/galgebra/.venv/lib/python3.11/site-packages/mpmath/rational.py:4: DeprecationWarning: the rational private module is deprecated\n", - " warnings.warn(\"the rational private module is deprecated\",\n", "terminal_check.py:6: DeprecationWarning: The `galgebra.deprecated` module is deprecated\n", " from galgebra.deprecated import MV\n", "terminal_check.py:13: DeprecationWarning: The `galgebra.deprecated.MV` class is deprecated in favor of `galgebra.mv.Mv`.\n", @@ -2001,7 +1923,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.11.14" + "version": "3.12.12" } }, "nbformat": 4, diff --git a/examples/ipython/gr_metrics.ipynb b/examples/ipython/gr_metrics.ipynb index 1fccfdf8..4ee0efa1 100644 --- a/examples/ipython/gr_metrics.ipynb +++ b/examples/ipython/gr_metrics.ipynb @@ -3,7 +3,14 @@ { "cell_type": "code", "execution_count": 1, - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2026-04-01T13:09:43.808023Z", + "iopub.status.busy": "2026-04-01T13:09:43.807949Z", + "iopub.status.idle": "2026-04-01T13:09:44.722231Z", + "shell.execute_reply": "2026-04-01T13:09:44.721765Z" + } + }, "outputs": [], "source": [ "from sympy import *\n", @@ -16,7 +23,14 @@ { "cell_type": "code", "execution_count": 2, - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2026-04-01T13:09:44.724408Z", + "iopub.status.busy": "2026-04-01T13:09:44.724285Z", + "iopub.status.idle": "2026-04-01T13:09:44.726547Z", + "shell.execute_reply": "2026-04-01T13:09:44.726096Z" + } + }, "outputs": [], "source": [ "def dot_basis_r_basis(ga):\n", @@ -26,7 +40,14 @@ { "cell_type": "code", "execution_count": 3, - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2026-04-01T13:09:44.728314Z", + "iopub.status.busy": "2026-04-01T13:09:44.728211Z", + "iopub.status.idle": "2026-04-01T13:09:44.730172Z", + "shell.execute_reply": "2026-04-01T13:09:44.729750Z" + } + }, "outputs": [], "source": [ "def gg(ga):\n", @@ -36,7 +57,14 @@ { "cell_type": "code", "execution_count": 4, - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2026-04-01T13:09:44.731894Z", + "iopub.status.busy": "2026-04-01T13:09:44.731741Z", + "iopub.status.idle": "2026-04-01T13:09:44.733355Z", + "shell.execute_reply": "2026-04-01T13:09:44.732974Z" + } + }, "outputs": [], "source": [ "def conv_christoffel_symbols(cf):\n", @@ -46,7 +74,14 @@ { "cell_type": "code", "execution_count": 5, - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2026-04-01T13:09:44.735510Z", + "iopub.status.busy": "2026-04-01T13:09:44.735376Z", + "iopub.status.idle": "2026-04-01T13:09:44.737932Z", + "shell.execute_reply": "2026-04-01T13:09:44.737413Z" + } + }, "outputs": [], "source": [ "def show_christoffel_symbols(ga):\n", @@ -65,7 +100,14 @@ { "cell_type": "code", "execution_count": 6, - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2026-04-01T13:09:44.739617Z", + "iopub.status.busy": "2026-04-01T13:09:44.739521Z", + "iopub.status.idle": "2026-04-01T13:09:44.810243Z", + "shell.execute_reply": "2026-04-01T13:09:44.809775Z" + } + }, "outputs": [], "source": [ "coord = symbols('t x y z')\n", @@ -81,7 +123,14 @@ { "cell_type": "code", "execution_count": 7, - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2026-04-01T13:09:44.813214Z", + "iopub.status.busy": "2026-04-01T13:09:44.813020Z", + "iopub.status.idle": "2026-04-01T13:09:44.816647Z", + "shell.execute_reply": "2026-04-01T13:09:44.815950Z" + } + }, "outputs": [ { "data": { @@ -105,7 +154,14 @@ { "cell_type": "code", "execution_count": 8, - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2026-04-01T13:09:44.832838Z", + "iopub.status.busy": "2026-04-01T13:09:44.832685Z", + "iopub.status.idle": "2026-04-01T13:09:44.836787Z", + "shell.execute_reply": "2026-04-01T13:09:44.836034Z" + } + }, "outputs": [ { "data": { @@ -134,7 +190,14 @@ { "cell_type": "code", "execution_count": 9, - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2026-04-01T13:09:44.839091Z", + "iopub.status.busy": "2026-04-01T13:09:44.839005Z", + "iopub.status.idle": "2026-04-01T13:09:44.841693Z", + "shell.execute_reply": "2026-04-01T13:09:44.841178Z" + } + }, "outputs": [ { "data": { @@ -157,7 +220,14 @@ { "cell_type": "code", "execution_count": 10, - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2026-04-01T13:09:44.843473Z", + "iopub.status.busy": "2026-04-01T13:09:44.843362Z", + "iopub.status.idle": "2026-04-01T13:09:44.847630Z", + "shell.execute_reply": "2026-04-01T13:09:44.846613Z" + } + }, "outputs": [ { "data": { @@ -193,7 +263,14 @@ { "cell_type": "code", "execution_count": 11, - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2026-04-01T13:09:44.850315Z", + "iopub.status.busy": "2026-04-01T13:09:44.850160Z", + "iopub.status.idle": "2026-04-01T13:09:45.051081Z", + "shell.execute_reply": "2026-04-01T13:09:45.050457Z" + } + }, "outputs": [], "source": [ "g4coords = (u, x, y, z) = symbols(\"u x y z\")\n", @@ -209,7 +286,14 @@ { "cell_type": "code", "execution_count": 12, - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2026-04-01T13:09:45.053051Z", + "iopub.status.busy": "2026-04-01T13:09:45.052944Z", + "iopub.status.idle": "2026-04-01T13:09:45.055784Z", + "shell.execute_reply": "2026-04-01T13:09:45.055330Z" + } + }, "outputs": [ { "data": { @@ -232,7 +316,14 @@ { "cell_type": "code", "execution_count": 13, - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2026-04-01T13:09:45.057249Z", + "iopub.status.busy": "2026-04-01T13:09:45.057146Z", + "iopub.status.idle": "2026-04-01T13:09:45.060672Z", + "shell.execute_reply": "2026-04-01T13:09:45.060292Z" + } + }, "outputs": [ { "data": { @@ -269,7 +360,14 @@ { "cell_type": "code", "execution_count": 14, - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2026-04-01T13:09:45.062119Z", + "iopub.status.busy": "2026-04-01T13:09:45.062058Z", + "iopub.status.idle": "2026-04-01T13:09:45.064262Z", + "shell.execute_reply": "2026-04-01T13:09:45.063827Z" + } + }, "outputs": [ { "data": { @@ -295,7 +393,14 @@ { "cell_type": "code", "execution_count": 15, - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2026-04-01T13:09:45.065613Z", + "iopub.status.busy": "2026-04-01T13:09:45.065551Z", + "iopub.status.idle": "2026-04-01T13:09:45.070879Z", + "shell.execute_reply": "2026-04-01T13:09:45.070390Z" + } + }, "outputs": [ { "data": { @@ -321,7 +426,14 @@ { "cell_type": "code", "execution_count": 16, - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2026-04-01T13:09:45.072624Z", + "iopub.status.busy": "2026-04-01T13:09:45.072520Z", + "iopub.status.idle": "2026-04-01T13:09:45.090530Z", + "shell.execute_reply": "2026-04-01T13:09:45.090073Z" + } + }, "outputs": [ { "data": { @@ -350,12 +462,19 @@ { "cell_type": "code", "execution_count": 17, - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2026-04-01T13:09:45.091969Z", + "iopub.status.busy": "2026-04-01T13:09:45.091879Z", + "iopub.status.idle": "2026-04-01T13:09:45.179277Z", + "shell.execute_reply": "2026-04-01T13:09:45.178949Z" + } + }, "outputs": [ { "data": { "text/latex": [ - "\\begin{equation*}\\left[\\begin{array}{}\\left[\\begin{array}{}0 & 0 & 0 & 0\\\\0 & - \\frac{u e^{4 z}}{2} & 0 & 0\\\\0 & 0 & 0 & 0\\\\0 & 0 & 0 & - \\frac{u}{2}\\end{array}\\right] & \\left[\\begin{array}{}0 & \\frac{u e^{4 z}}{2} & 0 & 0\\\\\\frac{u e^{4 z}}{2} & 0 & 0 & u^{2} e^{4 z}\\\\0 & 0 & 0 & 0\\\\0 & u^{2} e^{4 z} & 0 & 0\\end{array}\\right] & \\left[\\begin{array}{}0 & 0 & 0 & e^{- z}\\\\0 & 0 & 0 & 0\\\\0 & 0 & 0 & - 12 e^{- 2 z}\\\\e^{- z} & 0 & - 12 e^{- 2 z} & - u e^{- z}\\end{array}\\right] & \\left[\\begin{array}{}0 & 0 & 0 & \\frac{u}{2}\\\\0 & - u^{2} e^{4 z} & 0 & 0\\\\0 & 0 & 12 e^{- 2 z} & 0\\\\\\frac{u}{2} & 0 & 0 & 0\\end{array}\\right]\\end{array}\\right]\\end{equation*}" + "\\begin{equation*}\\left[\\begin{array}{cccc}\\left[\\begin{array}{cccc}0 & 0 & 0 & 0\\\\0 & - \\frac{u e^{4 z}}{2} & 0 & 0\\\\0 & 0 & 0 & 0\\\\0 & 0 & 0 & - \\frac{u}{2}\\end{array}\\right] & \\left[\\begin{array}{cccc}0 & \\frac{u e^{4 z}}{2} & 0 & 0\\\\\\frac{u e^{4 z}}{2} & 0 & 0 & u^{2} e^{4 z}\\\\0 & 0 & 0 & 0\\\\0 & u^{2} e^{4 z} & 0 & 0\\end{array}\\right] & \\left[\\begin{array}{cccc}0 & 0 & 0 & e^{- z}\\\\0 & 0 & 0 & 0\\\\0 & 0 & 0 & - 12 e^{- 2 z}\\\\e^{- z} & 0 & - 12 e^{- 2 z} & - u e^{- z}\\end{array}\\right] & \\left[\\begin{array}{cccc}0 & 0 & 0 & \\frac{u}{2}\\\\0 & - u^{2} e^{4 z} & 0 & 0\\\\0 & 0 & 12 e^{- 2 z} & 0\\\\\\frac{u}{2} & 0 & 0 & 0\\end{array}\\right]\\end{array}\\right]\\end{equation*}" ], "text/plain": [ "⎡ ⎡ 4⋅z ⎤ ⎤\n", @@ -380,7 +499,7 @@ { "data": { "text/latex": [ - "\\begin{equation*}\\left[\\begin{array}{}\\left[\\begin{array}{}0 & 0 & 0 & 0\\\\0 & 3 u e^{4 z} & 0 & 0\\\\0 & 0 & \\frac{24 e^{- 2 z}}{u} & 12 e^{- z}\\\\0 & 0 & 12 e^{- z} & 6 u\\end{array}\\right] & \\left[\\begin{array}{}0 & \\frac{1}{u} & 0 & 0\\\\\\frac{1}{u} & 0 & 0 & 2\\\\0 & 0 & 0 & 0\\\\0 & 2 & 0 & 0\\end{array}\\right] & \\left[\\begin{array}{}0 & 0 & 0 & 0\\\\0 & \\frac{u e^{5 z}}{2} & 0 & 0\\\\0 & 0 & 0 & 0\\\\0 & 0 & 0 & \\frac{u e^{z}}{2}\\end{array}\\right] & \\left[\\begin{array}{}0 & 0 & 0 & \\frac{1}{u}\\\\0 & - 3 e^{4 z} & 0 & 0\\\\0 & 0 & \\frac{24 e^{- 2 z}}{u^{2}} & 0\\\\\\frac{1}{u} & 0 & 0 & -1\\end{array}\\right]\\end{array}\\right]\\end{equation*}" + "\\begin{equation*}\\left[\\begin{array}{cccc}\\left[\\begin{array}{cccc}0 & 0 & 0 & 0\\\\0 & 3 u e^{4 z} & 0 & 0\\\\0 & 0 & \\frac{24 e^{- 2 z}}{u} & 12 e^{- z}\\\\0 & 0 & 12 e^{- z} & 6 u\\end{array}\\right] & \\left[\\begin{array}{cccc}0 & \\frac{1}{u} & 0 & 0\\\\\\frac{1}{u} & 0 & 0 & 2\\\\0 & 0 & 0 & 0\\\\0 & 2 & 0 & 0\\end{array}\\right] & \\left[\\begin{array}{cccc}0 & 0 & 0 & 0\\\\0 & \\frac{u e^{5 z}}{2} & 0 & 0\\\\0 & 0 & 0 & 0\\\\0 & 0 & 0 & \\frac{u e^{z}}{2}\\end{array}\\right] & \\left[\\begin{array}{cccc}0 & 0 & 0 & \\frac{1}{u}\\\\0 & - 3 e^{4 z} & 0 & 0\\\\0 & 0 & \\frac{24 e^{- 2 z}}{u^{2}} & 0\\\\\\frac{1}{u} & 0 & 0 & -1\\end{array}\\right]\\end{array}\\right]\\end{equation*}" ], "text/plain": [ "⎡ ⎡ 1 ⎤⎤\n", @@ -419,7 +538,14 @@ { "cell_type": "code", "execution_count": 18, - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2026-04-01T13:09:45.181162Z", + "iopub.status.busy": "2026-04-01T13:09:45.181045Z", + "iopub.status.idle": "2026-04-01T13:09:45.325783Z", + "shell.execute_reply": "2026-04-01T13:09:45.325411Z" + } + }, "outputs": [], "source": [ "G, M, c = symbols('G M c')\n", @@ -436,7 +562,14 @@ { "cell_type": "code", "execution_count": 19, - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2026-04-01T13:09:45.328449Z", + "iopub.status.busy": "2026-04-01T13:09:45.328321Z", + "iopub.status.idle": "2026-04-01T13:09:45.330797Z", + "shell.execute_reply": "2026-04-01T13:09:45.330485Z" + } + }, "outputs": [ { "data": { @@ -460,7 +593,14 @@ { "cell_type": "code", "execution_count": 20, - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2026-04-01T13:09:45.332360Z", + "iopub.status.busy": "2026-04-01T13:09:45.332263Z", + "iopub.status.idle": "2026-04-01T13:09:45.336820Z", + "shell.execute_reply": "2026-04-01T13:09:45.336116Z" + } + }, "outputs": [ { "data": { @@ -470,15 +610,15 @@ "text/plain": [ "⎡ 2⋅G⋅M ⎤\n", "⎢- ───── + 1 0 0 0 ⎥\n", - "⎢ 2 ⎥\n", - "⎢ c ⋅r ⎥\n", + "⎢ 2 ⎥\n", + "⎢ c ⋅r ⎥\n", "⎢ ⎥\n", "⎢ -1 ⎥\n", "⎢ 0 ─────────── 0 0 ⎥\n", "⎢ 2⋅G⋅M ⎥\n", "⎢ - ───── + 1 ⎥\n", - "⎢ 2 ⎥\n", - "⎢ c ⋅r ⎥\n", + "⎢ 2 ⎥\n", + "⎢ c ⋅r ⎥\n", "⎢ ⎥\n", "⎢ 2 ⎥\n", "⎢ 0 0 -r 0 ⎥\n", @@ -499,7 +639,14 @@ { "cell_type": "code", "execution_count": 21, - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2026-04-01T13:09:45.338431Z", + "iopub.status.busy": "2026-04-01T13:09:45.338357Z", + "iopub.status.idle": "2026-04-01T13:09:45.341187Z", + "shell.execute_reply": "2026-04-01T13:09:45.340849Z" + } + }, "outputs": [ { "data": { @@ -523,7 +670,14 @@ { "cell_type": "code", "execution_count": 22, - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2026-04-01T13:09:45.342840Z", + "iopub.status.busy": "2026-04-01T13:09:45.342749Z", + "iopub.status.idle": "2026-04-01T13:09:45.346282Z", + "shell.execute_reply": "2026-04-01T13:09:45.345822Z" + } + }, "outputs": [ { "data": { @@ -533,13 +687,13 @@ "text/plain": [ "⎡ ⎛2⋅G⋅M ⎞ ⎤\n", "⎢ -⎜───── - 1⎟ ⎥\n", - "⎢ ⎜ 2 ⎟ ⎥\n", - "⎢ ⎝ c ⋅r ⎠ ⎥\n", + "⎢ ⎜ 2 ⎟ ⎥\n", + "⎢ ⎝c ⋅r ⎠ ⎥\n", "⎢1, ─────────────, 1, 1⎥\n", "⎢ 2⋅G⋅M ⎥\n", "⎢ - ───── + 1 ⎥\n", - "⎢ 2 ⎥\n", - "⎣ c ⋅r ⎦" + "⎢ 2 ⎥\n", + "⎣ c ⋅r ⎦" ] }, "execution_count": 22, @@ -554,7 +708,14 @@ { "cell_type": "code", "execution_count": 23, - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2026-04-01T13:09:45.347732Z", + "iopub.status.busy": "2026-04-01T13:09:45.347660Z", + "iopub.status.idle": "2026-04-01T13:09:45.371768Z", + "shell.execute_reply": "2026-04-01T13:09:45.371344Z" + } + }, "outputs": [ { "data": { @@ -583,12 +744,19 @@ { "cell_type": "code", "execution_count": 24, - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2026-04-01T13:09:45.374220Z", + "iopub.status.busy": "2026-04-01T13:09:45.374076Z", + "iopub.status.idle": "2026-04-01T13:09:45.561232Z", + "shell.execute_reply": "2026-04-01T13:09:45.560810Z" + } + }, "outputs": [ { "data": { "text/latex": [ - "\\begin{equation*}\\left[\\begin{array}{}\\left[\\begin{array}{}0 & \\frac{G M}{c^{2} r^{2}} & 0 & 0\\\\\\frac{G M}{c^{2} r^{2}} & 0 & 0 & 0\\\\0 & 0 & 0 & 0\\\\0 & 0 & 0 & 0\\end{array}\\right] & \\left[\\begin{array}{}- \\frac{G M}{c^{2} r^{2}} & 0 & 0 & 0\\\\0 & \\frac{G M c^{2}}{4 G^{2} M^{2} + c^{2} r \\left(- 4 G M + c^{2} r\\right)} & 0 & 0\\\\0 & 0 & r & 0\\\\0 & 0 & 0 & r {\\sin{\\left (\\theta \\right )}}^{2}\\end{array}\\right] & \\left[\\begin{array}{}0 & 0 & 0 & 0\\\\0 & 0 & - r & 0\\\\0 & - r & 0 & 0\\\\0 & 0 & 0 & \\frac{r^{2} \\sin{\\left (2 \\theta \\right )}}{2}\\end{array}\\right] & \\left[\\begin{array}{}0 & 0 & 0 & 0\\\\0 & 0 & 0 & - r {\\sin{\\left (\\theta \\right )}}^{2}\\\\0 & 0 & 0 & - \\frac{r^{2} \\sin{\\left (2 \\theta \\right )}}{2}\\\\0 & - r {\\sin{\\left (\\theta \\right )}}^{2} & - \\frac{r^{2} \\sin{\\left (2 \\theta \\right )}}{2} & 0\\end{array}\\right]\\end{array}\\right]\\end{equation*}" + "\\begin{equation*}\\left[\\begin{array}{cccc}\\left[\\begin{array}{cccc}0 & \\frac{G M}{c^{2} r^{2}} & 0 & 0\\\\\\frac{G M}{c^{2} r^{2}} & 0 & 0 & 0\\\\0 & 0 & 0 & 0\\\\0 & 0 & 0 & 0\\end{array}\\right] & \\left[\\begin{array}{cccc}- \\frac{G M}{c^{2} r^{2}} & 0 & 0 & 0\\\\0 & \\frac{G M c^{2}}{4 G^{2} M^{2} + c^{2} r \\left(- 4 G M + c^{2} r\\right)} & 0 & 0\\\\0 & 0 & r & 0\\\\0 & 0 & 0 & r {\\sin{\\left (\\theta \\right )}}^{2}\\end{array}\\right] & \\left[\\begin{array}{cccc}0 & 0 & 0 & 0\\\\0 & 0 & - r & 0\\\\0 & - r & 0 & 0\\\\0 & 0 & 0 & \\frac{r^{2} \\sin{\\left (2 \\theta \\right )}}{2}\\end{array}\\right] & \\left[\\begin{array}{cccc}0 & 0 & 0 & 0\\\\0 & 0 & 0 & - r {\\sin{\\left (\\theta \\right )}}^{2}\\\\0 & 0 & 0 & - \\frac{r^{2} \\sin{\\left (2 \\theta \\right )}}{2}\\\\0 & - r {\\sin{\\left (\\theta \\right )}}^{2} & - \\frac{r^{2} \\sin{\\left (2 \\theta \\right )}}{2} & 0\\end{array}\\right]\\end{array}\\right]\\end{equation*}" ], "text/plain": [ "⎡ ⎡-G⋅M ⎤ ⎡0 0 0 0 ⎤⎤\n", @@ -614,7 +782,7 @@ { "data": { "text/latex": [ - "\\begin{equation*}\\left[\\begin{array}{}\\left[\\begin{array}{}0 & \\frac{G M}{r \\left(- 2 G M + c^{2} r\\right)} & 0 & 0\\\\\\frac{G M}{r \\left(- 2 G M + c^{2} r\\right)} & 0 & 0 & 0\\\\0 & 0 & 0 & 0\\\\0 & 0 & 0 & 0\\end{array}\\right] & \\left[\\begin{array}{}\\frac{G M \\left(- 2 G M + c^{2} r\\right)}{c^{4} r^{3}} & 0 & 0 & 0\\\\0 & \\frac{G M}{r \\left(2 G M - c^{2} r\\right)} & 0 & 0\\\\0 & 0 & \\frac{2 G M}{c^{2}} - r & 0\\\\0 & 0 & 0 & \\frac{\\left(2 G M - c^{2} r\\right) {\\sin{\\left (\\theta \\right )}}^{2}}{c^{2}}\\end{array}\\right] & \\left[\\begin{array}{}0 & 0 & 0 & 0\\\\0 & 0 & \\frac{1}{r} & 0\\\\0 & \\frac{1}{r} & 0 & 0\\\\0 & 0 & 0 & - \\frac{\\sin{\\left (2 \\theta \\right )}}{2}\\end{array}\\right] & \\left[\\begin{array}{}0 & 0 & 0 & 0\\\\0 & 0 & 0 & \\frac{1}{r}\\\\0 & 0 & 0 & \\frac{1}{\\tan{\\left (\\theta \\right )}}\\\\0 & \\frac{1}{r} & \\frac{1}{\\tan{\\left (\\theta \\right )}} & 0\\end{array}\\right]\\end{array}\\right]\\end{equation*}" + "\\begin{equation*}\\left[\\begin{array}{cccc}\\left[\\begin{array}{cccc}0 & \\frac{G M}{r \\left(- 2 G M + c^{2} r\\right)} & 0 & 0\\\\\\frac{G M}{r \\left(- 2 G M + c^{2} r\\right)} & 0 & 0 & 0\\\\0 & 0 & 0 & 0\\\\0 & 0 & 0 & 0\\end{array}\\right] & \\left[\\begin{array}{cccc}\\frac{G M \\left(- 2 G M + c^{2} r\\right)}{c^{4} r^{3}} & 0 & 0 & 0\\\\0 & \\frac{G M}{r \\left(2 G M - c^{2} r\\right)} & 0 & 0\\\\0 & 0 & \\frac{2 G M}{c^{2}} - r & 0\\\\0 & 0 & 0 & \\frac{\\left(2 G M - c^{2} r\\right) {\\sin{\\left (\\theta \\right )}}^{2}}{c^{2}}\\end{array}\\right] & \\left[\\begin{array}{cccc}0 & 0 & 0 & 0\\\\0 & 0 & \\frac{1}{r} & 0\\\\0 & \\frac{1}{r} & 0 & 0\\\\0 & 0 & 0 & - \\frac{\\sin{\\left (2 \\theta \\right )}}{2}\\end{array}\\right] & \\left[\\begin{array}{cccc}0 & 0 & 0 & 0\\\\0 & 0 & 0 & \\frac{1}{r}\\\\0 & 0 & 0 & \\frac{1}{\\tan{\\left (\\theta \\right )}}\\\\0 & \\frac{1}{r} & \\frac{1}{\\tan{\\left (\\theta \\right )}} & 0\\end{array}\\right]\\end{array}\\right]\\end{equation*}" ], "text/plain": [ "⎡ ⎡ ⎛ 2 ⎞ ⎤ ⎤\n", @@ -630,8 +798,8 @@ "⎢⎢───────────────── 0 0 0⎥ ⎢ ⎥ ⎢ 1 ⎥ ⎢ 1 ⎥⎥\n", "⎢⎢ ⎛ 2 ⎞ ⎥ ⎢ 2⋅G⋅M ⎥ ⎢0 ─ 0 0 ⎥ ⎢0 0 0 ──────⎥⎥\n", "⎢⎢r⋅⎝-2⋅G⋅M + c ⋅r⎠ ⎥ ⎢ 0 0 ───── - r 0 ⎥ ⎢ r ⎥ ⎢ tan(θ)⎥⎥\n", - "⎢⎢ ⎥ ⎢ 2 ⎥ ⎢ ⎥ ⎢ ⎥⎥\n", - "⎢⎢ 0 0 0 0⎥ ⎢ c ⎥ ⎢ -sin(2⋅θ) ⎥ ⎢ 1 1 ⎥⎥\n", + "⎢⎢ ⎥ ⎢ 2 ⎥ ⎢ ⎥ ⎢ ⎥⎥\n", + "⎢⎢ 0 0 0 0⎥ ⎢ c ⎥ ⎢ -sin(2⋅θ) ⎥ ⎢ 1 1 ⎥⎥\n", "⎢⎢ ⎥ ⎢ ⎥ ⎢0 0 0 ──────────⎥ ⎢0 ─ ────── 0 ⎥⎥\n", "⎢⎣ 0 0 0 0⎦ ⎢ ⎛ 2 ⎞ 2 ⎥ ⎣ 2 ⎦ ⎣ r tan(θ) ⎦⎥\n", "⎢ ⎢ ⎝2⋅G⋅M - c ⋅r⎠⋅sin (θ)⎥ ⎥\n", @@ -665,7 +833,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.11.8" + "version": "3.12.12" } }, "nbformat": 4, diff --git a/examples/ipython/test_gsg_undual_etc.ipynb b/examples/ipython/test_gsg_undual_etc.ipynb index 4c699f2f..fc26ac4a 100644 --- a/examples/ipython/test_gsg_undual_etc.ipynb +++ b/examples/ipython/test_gsg_undual_etc.ipynb @@ -45,10 +45,10 @@ "id": "c59e2276", "metadata": { "execution": { - "iopub.execute_input": "2026-03-30T00:39:08.042647Z", - "iopub.status.busy": "2026-03-30T00:39:08.042498Z", - "iopub.status.idle": "2026-03-30T00:39:08.281340Z", - "shell.execute_reply": "2026-03-30T00:39:08.279771Z" + "iopub.execute_input": "2026-04-02T05:40:40.529897Z", + "iopub.status.busy": "2026-04-02T05:40:40.529754Z", + "iopub.status.idle": "2026-04-02T05:40:40.673798Z", + "shell.execute_reply": "2026-04-02T05:40:40.673000Z" } }, "outputs": [ @@ -90,7 +90,7 @@ { "data": { "text/latex": [ - "$\\displaystyle \\text{This notebook is now using} \\\\\\qquad\\bullet~ \\text{Python }3.11.14\\qquad\\bullet~ \\text{SymPy }1.12\\qquad\\bullet~ \\text{GAlgebra }0.6.0-dev.$" + "$\\displaystyle \\text{This notebook is now using} \\\\\\qquad\\bullet~ \\text{Python }3.12.12\\qquad\\bullet~ \\text{SymPy }1.13.3\\qquad\\bullet~ \\text{GAlgebra }0.6.0.$" ], "text/plain": [ "" @@ -147,13 +147,23 @@ "id": "e053271f", "metadata": { "execution": { - "iopub.execute_input": "2026-03-30T00:39:08.285382Z", - "iopub.status.busy": "2026-03-30T00:39:08.285098Z", - "iopub.status.idle": "2026-03-30T00:39:08.330551Z", - "shell.execute_reply": "2026-03-30T00:39:08.329276Z" + "iopub.execute_input": "2026-04-02T05:40:40.675588Z", + "iopub.status.busy": "2026-04-02T05:40:40.675476Z", + "iopub.status.idle": "2026-04-02T05:40:40.698856Z", + "shell.execute_reply": "2026-04-02T05:40:40.698002Z" } }, "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "<>:4: SyntaxWarning: invalid escape sequence '\\m'\n", + "<>:4: SyntaxWarning: invalid escape sequence '\\m'\n", + "/var/folders/hk/1v10kptj2079x7pyl9pxrxym0000gn/T/ipykernel_83162/4060548529.py:4: SyntaxWarning: invalid escape sequence '\\m'\n", + " g3 = Ga('\\mathbf{e}',\n" + ] + }, { "data": { "text/latex": [ @@ -284,10 +294,10 @@ "id": "c7fa60e5", "metadata": { "execution": { - "iopub.execute_input": "2026-03-30T00:39:08.333705Z", - "iopub.status.busy": "2026-03-30T00:39:08.333412Z", - "iopub.status.idle": "2026-03-30T00:39:08.458394Z", - "shell.execute_reply": "2026-03-30T00:39:08.457085Z" + "iopub.execute_input": "2026-04-02T05:40:40.700976Z", + "iopub.status.busy": "2026-04-02T05:40:40.700877Z", + "iopub.status.idle": "2026-04-02T05:40:40.758898Z", + "shell.execute_reply": "2026-04-02T05:40:40.758120Z" } }, "outputs": [ @@ -394,10 +404,10 @@ "id": "a8c28609", "metadata": { "execution": { - "iopub.execute_input": "2026-03-30T00:39:08.462978Z", - "iopub.status.busy": "2026-03-30T00:39:08.462804Z", - "iopub.status.idle": "2026-03-30T00:39:08.486788Z", - "shell.execute_reply": "2026-03-30T00:39:08.485623Z" + "iopub.execute_input": "2026-04-02T05:40:40.760574Z", + "iopub.status.busy": "2026-04-02T05:40:40.760499Z", + "iopub.status.idle": "2026-04-02T05:40:40.771716Z", + "shell.execute_reply": "2026-04-02T05:40:40.771025Z" } }, "outputs": [ @@ -491,10 +501,10 @@ "id": "aa255f32", "metadata": { "execution": { - "iopub.execute_input": "2026-03-30T00:39:08.490153Z", - "iopub.status.busy": "2026-03-30T00:39:08.489916Z", - "iopub.status.idle": "2026-03-30T00:39:08.516502Z", - "shell.execute_reply": "2026-03-30T00:39:08.515482Z" + "iopub.execute_input": "2026-04-02T05:40:40.773474Z", + "iopub.status.busy": "2026-04-02T05:40:40.773375Z", + "iopub.status.idle": "2026-04-02T05:40:40.785895Z", + "shell.execute_reply": "2026-04-02T05:40:40.785201Z" } }, "outputs": [ @@ -586,10 +596,10 @@ "id": "b89afded", "metadata": { "execution": { - "iopub.execute_input": "2026-03-30T00:39:08.521227Z", - "iopub.status.busy": "2026-03-30T00:39:08.520751Z", - "iopub.status.idle": "2026-03-30T00:39:08.673770Z", - "shell.execute_reply": "2026-03-30T00:39:08.672098Z" + "iopub.execute_input": "2026-04-02T05:40:40.787944Z", + "iopub.status.busy": "2026-04-02T05:40:40.787840Z", + "iopub.status.idle": "2026-04-02T05:40:40.858710Z", + "shell.execute_reply": "2026-04-02T05:40:40.858101Z" } }, "outputs": [ @@ -769,13 +779,23 @@ "id": "648220c5", "metadata": { "execution": { - "iopub.execute_input": "2026-03-30T00:39:08.678702Z", - "iopub.status.busy": "2026-03-30T00:39:08.677953Z", - "iopub.status.idle": "2026-03-30T00:39:08.706559Z", - "shell.execute_reply": "2026-03-30T00:39:08.705096Z" + "iopub.execute_input": "2026-04-02T05:40:40.860595Z", + "iopub.status.busy": "2026-04-02T05:40:40.860500Z", + "iopub.status.idle": "2026-04-02T05:40:40.878320Z", + "shell.execute_reply": "2026-04-02T05:40:40.877634Z" } }, "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "<>:4: SyntaxWarning: invalid escape sequence '\\m'\n", + "<>:4: SyntaxWarning: invalid escape sequence '\\m'\n", + "/var/folders/hk/1v10kptj2079x7pyl9pxrxym0000gn/T/ipykernel_83162/1232613138.py:4: SyntaxWarning: invalid escape sequence '\\m'\n", + " e2 = Ga('\\mathbf{e}', g=[1,1], coords=(x,y))\n" + ] + }, { "data": { "text/latex": [ @@ -890,13 +910,23 @@ "id": "93020af9", "metadata": { "execution": { - "iopub.execute_input": "2026-03-30T00:39:08.710107Z", - "iopub.status.busy": "2026-03-30T00:39:08.709928Z", - "iopub.status.idle": "2026-03-30T00:39:08.825158Z", - "shell.execute_reply": "2026-03-30T00:39:08.823705Z" + "iopub.execute_input": "2026-04-02T05:40:40.880011Z", + "iopub.status.busy": "2026-04-02T05:40:40.879896Z", + "iopub.status.idle": "2026-04-02T05:40:40.936862Z", + "shell.execute_reply": "2026-04-02T05:40:40.936019Z" } }, "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "<>:6: SyntaxWarning: invalid escape sequence '\\m'\n", + "<>:6: SyntaxWarning: invalid escape sequence '\\m'\n", + "/var/folders/hk/1v10kptj2079x7pyl9pxrxym0000gn/T/ipykernel_83162/97417942.py:6: SyntaxWarning: invalid escape sequence '\\m'\n", + " e2_polar = Ga('\\mathbf{b}', g=[1,r**2], coords=(r,theta))\n" + ] + }, { "data": { "text/latex": [ @@ -1015,13 +1045,23 @@ "id": "db8d0100", "metadata": { "execution": { - "iopub.execute_input": "2026-03-30T00:39:08.828578Z", - "iopub.status.busy": "2026-03-30T00:39:08.828413Z", - "iopub.status.idle": "2026-03-30T00:39:08.868968Z", - "shell.execute_reply": "2026-03-30T00:39:08.867640Z" + "iopub.execute_input": "2026-04-02T05:40:40.938628Z", + "iopub.status.busy": "2026-04-02T05:40:40.938483Z", + "iopub.status.idle": "2026-04-02T05:40:40.956181Z", + "shell.execute_reply": "2026-04-02T05:40:40.955679Z" } }, "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "<>:4: SyntaxWarning: invalid escape sequence '\\m'\n", + "<>:4: SyntaxWarning: invalid escape sequence '\\m'\n", + "/var/folders/hk/1v10kptj2079x7pyl9pxrxym0000gn/T/ipykernel_83162/982990053.py:4: SyntaxWarning: invalid escape sequence '\\m'\n", + " m2 = Ga('\\mathbf{e}', g=[1,-1], coords=(s,t))\n" + ] + }, { "data": { "text/latex": [ @@ -1153,13 +1193,23 @@ "id": "bb01bfee", "metadata": { "execution": { - "iopub.execute_input": "2026-03-30T00:39:08.872673Z", - "iopub.status.busy": "2026-03-30T00:39:08.872457Z", - "iopub.status.idle": "2026-03-30T00:39:09.470450Z", - "shell.execute_reply": "2026-03-30T00:39:09.467713Z" + "iopub.execute_input": "2026-04-02T05:40:40.958252Z", + "iopub.status.busy": "2026-04-02T05:40:40.958121Z", + "iopub.status.idle": "2026-04-02T05:40:41.061204Z", + "shell.execute_reply": "2026-04-02T05:40:41.060610Z" } }, "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "<>:6: SyntaxWarning: invalid escape sequence '\\m'\n", + "<>:6: SyntaxWarning: invalid escape sequence '\\m'\n", + "/var/folders/hk/1v10kptj2079x7pyl9pxrxym0000gn/T/ipykernel_83162/3933349969.py:6: SyntaxWarning: invalid escape sequence '\\m'\n", + " m2_polar = Ga('\\mathbf{b}', g=[1,-rho**2], coords=(rho, phi))\n" + ] + }, { "data": { "text/latex": [ @@ -1315,10 +1365,10 @@ "id": "42cf5c27", "metadata": { "execution": { - "iopub.execute_input": "2026-03-30T00:39:09.474194Z", - "iopub.status.busy": "2026-03-30T00:39:09.474011Z", - "iopub.status.idle": "2026-03-30T00:39:09.482139Z", - "shell.execute_reply": "2026-03-30T00:39:09.480877Z" + "iopub.execute_input": "2026-04-02T05:40:41.063410Z", + "iopub.status.busy": "2026-04-02T05:40:41.063286Z", + "iopub.status.idle": "2026-04-02T05:40:41.066991Z", + "shell.execute_reply": "2026-04-02T05:40:41.066184Z" } }, "outputs": [], @@ -1394,10 +1444,10 @@ "id": "813ee65a", "metadata": { "execution": { - "iopub.execute_input": "2026-03-30T00:39:09.485212Z", - "iopub.status.busy": "2026-03-30T00:39:09.485080Z", - "iopub.status.idle": "2026-03-30T00:39:09.651408Z", - "shell.execute_reply": "2026-03-30T00:39:09.650559Z" + "iopub.execute_input": "2026-04-02T05:40:41.068796Z", + "iopub.status.busy": "2026-04-02T05:40:41.068704Z", + "iopub.status.idle": "2026-04-02T05:40:41.125663Z", + "shell.execute_reply": "2026-04-02T05:40:41.125117Z" } }, "outputs": [ @@ -1652,10 +1702,10 @@ "id": "c6748b4f", "metadata": { "execution": { - "iopub.execute_input": "2026-03-30T00:39:09.656314Z", - "iopub.status.busy": "2026-03-30T00:39:09.655870Z", - "iopub.status.idle": "2026-03-30T00:39:09.706869Z", - "shell.execute_reply": "2026-03-30T00:39:09.705987Z" + "iopub.execute_input": "2026-04-02T05:40:41.128204Z", + "iopub.status.busy": "2026-04-02T05:40:41.128053Z", + "iopub.status.idle": "2026-04-02T05:40:41.157168Z", + "shell.execute_reply": "2026-04-02T05:40:41.156411Z" } }, "outputs": [ @@ -1922,10 +1972,10 @@ "id": "df49d984", "metadata": { "execution": { - "iopub.execute_input": "2026-03-30T00:39:09.710460Z", - "iopub.status.busy": "2026-03-30T00:39:09.710192Z", - "iopub.status.idle": "2026-03-30T00:39:09.876871Z", - "shell.execute_reply": "2026-03-30T00:39:09.875018Z" + "iopub.execute_input": "2026-04-02T05:40:41.160208Z", + "iopub.status.busy": "2026-04-02T05:40:41.160016Z", + "iopub.status.idle": "2026-04-02T05:40:41.238601Z", + "shell.execute_reply": "2026-04-02T05:40:41.237343Z" } }, "outputs": [ @@ -2188,10 +2238,10 @@ "id": "71b635d8", "metadata": { "execution": { - "iopub.execute_input": "2026-03-30T00:39:09.880593Z", - "iopub.status.busy": "2026-03-30T00:39:09.880354Z", - "iopub.status.idle": "2026-03-30T00:39:10.134459Z", - "shell.execute_reply": "2026-03-30T00:39:10.133604Z" + "iopub.execute_input": "2026-04-02T05:40:41.241823Z", + "iopub.status.busy": "2026-04-02T05:40:41.241643Z", + "iopub.status.idle": "2026-04-02T05:40:41.376468Z", + "shell.execute_reply": "2026-04-02T05:40:41.375366Z" } }, "outputs": [ @@ -2458,10 +2508,10 @@ "id": "7006e40f", "metadata": { "execution": { - "iopub.execute_input": "2026-03-30T00:39:10.140072Z", - "iopub.status.busy": "2026-03-30T00:39:10.139848Z", - "iopub.status.idle": "2026-03-30T00:39:10.313158Z", - "shell.execute_reply": "2026-03-30T00:39:10.311540Z" + "iopub.execute_input": "2026-04-02T05:40:41.379291Z", + "iopub.status.busy": "2026-04-02T05:40:41.379129Z", + "iopub.status.idle": "2026-04-02T05:40:41.471263Z", + "shell.execute_reply": "2026-04-02T05:40:41.469750Z" } }, "outputs": [ @@ -2716,10 +2766,10 @@ "id": "9b32e234", "metadata": { "execution": { - "iopub.execute_input": "2026-03-30T00:39:10.317888Z", - "iopub.status.busy": "2026-03-30T00:39:10.317628Z", - "iopub.status.idle": "2026-03-30T00:39:10.373015Z", - "shell.execute_reply": "2026-03-30T00:39:10.371419Z" + "iopub.execute_input": "2026-04-02T05:40:41.474449Z", + "iopub.status.busy": "2026-04-02T05:40:41.474282Z", + "iopub.status.idle": "2026-04-02T05:40:41.516052Z", + "shell.execute_reply": "2026-04-02T05:40:41.514809Z" } }, "outputs": [ @@ -2974,10 +3024,10 @@ "id": "3862bdb9", "metadata": { "execution": { - "iopub.execute_input": "2026-03-30T00:39:10.376400Z", - "iopub.status.busy": "2026-03-30T00:39:10.376166Z", - "iopub.status.idle": "2026-03-30T00:39:10.559123Z", - "shell.execute_reply": "2026-03-30T00:39:10.558151Z" + "iopub.execute_input": "2026-04-02T05:40:41.518924Z", + "iopub.status.busy": "2026-04-02T05:40:41.518686Z", + "iopub.status.idle": "2026-04-02T05:40:41.620603Z", + "shell.execute_reply": "2026-04-02T05:40:41.619630Z" } }, "outputs": [ @@ -2996,7 +3046,7 @@ { "data": { "text/latex": [ - "$\\displaystyle \\qquad \\implies \\Vert\\mathbf{A}\\Vert^2 = t^{2} \\cdot \\left(2 s^{2} + t^{2}\\right) $" + "$\\displaystyle \\qquad \\implies \\Vert\\mathbf{A}\\Vert^2 = t^{2} \\left(2 s^{2} + t^{2}\\right) $" ], "text/plain": [ "" @@ -3116,7 +3166,7 @@ { "data": { "text/latex": [ - "$\\displaystyle \\qquad \\implies \\Vert\\left<\\mathbf{A}\\right>_1\\Vert^2 = t^{2} \\cdot \\left(2 s^{2} + t^{2}\\right) $" + "$\\displaystyle \\qquad \\implies \\Vert\\left<\\mathbf{A}\\right>_1\\Vert^2 = t^{2} \\left(2 s^{2} + t^{2}\\right) $" ], "text/plain": [ "" @@ -3248,7 +3298,7 @@ { "data": { "text/latex": [ - "$\\displaystyle \\text{A3.norm2() <= 0}: \\quad t^{2} \\cdot \\left(2 s^{2} + t^{2}\\right) \\leq 0 $" + "$\\displaystyle \\text{A3.norm2() <= 0}: \\quad t^{2} \\left(2 s^{2} + t^{2}\\right) \\leq 0 $" ], "text/plain": [ "" @@ -3343,10 +3393,10 @@ "id": "cf7afd38", "metadata": { "execution": { - "iopub.execute_input": "2026-03-30T00:39:10.563204Z", - "iopub.status.busy": "2026-03-30T00:39:10.562921Z", - "iopub.status.idle": "2026-03-30T00:39:10.778997Z", - "shell.execute_reply": "2026-03-30T00:39:10.777652Z" + "iopub.execute_input": "2026-04-02T05:40:41.623488Z", + "iopub.status.busy": "2026-04-02T05:40:41.623256Z", + "iopub.status.idle": "2026-04-02T05:40:41.744103Z", + "shell.execute_reply": "2026-04-02T05:40:41.743098Z" } }, "outputs": [ @@ -3609,10 +3659,10 @@ "id": "9374e530", "metadata": { "execution": { - "iopub.execute_input": "2026-03-30T00:39:10.782733Z", - "iopub.status.busy": "2026-03-30T00:39:10.782433Z", - "iopub.status.idle": "2026-03-30T00:39:11.526836Z", - "shell.execute_reply": "2026-03-30T00:39:11.525561Z" + "iopub.execute_input": "2026-04-02T05:40:41.747061Z", + "iopub.status.busy": "2026-04-02T05:40:41.746810Z", + "iopub.status.idle": "2026-04-02T05:40:42.087980Z", + "shell.execute_reply": "2026-04-02T05:40:42.087040Z" } }, "outputs": [ @@ -3867,10 +3917,10 @@ "id": "43bb53cd", "metadata": { "execution": { - "iopub.execute_input": "2026-03-30T00:39:11.531582Z", - "iopub.status.busy": "2026-03-30T00:39:11.531301Z", - "iopub.status.idle": "2026-03-30T00:39:11.729234Z", - "shell.execute_reply": "2026-03-30T00:39:11.727338Z" + "iopub.execute_input": "2026-04-02T05:40:42.091174Z", + "iopub.status.busy": "2026-04-02T05:40:42.090989Z", + "iopub.status.idle": "2026-04-02T05:40:42.174979Z", + "shell.execute_reply": "2026-04-02T05:40:42.173811Z" } }, "outputs": [ @@ -4245,7 +4295,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.11.14" + "version": "3.12.12" } }, "nbformat": 4, diff --git a/galgebra/mv.py b/galgebra/mv.py index 27007d0f..873a67ed 100644 --- a/galgebra/mv.py +++ b/galgebra/mv.py @@ -690,7 +690,10 @@ def append_plus(c_str): # str representation of multivector # note: this just replaces `self` for the rest of this function obj = expand(self.obj) - obj = metric.Simp.apply(obj) + try: + obj = metric.Simp.apply(obj) + except ZeroDivisionError: + pass # SymPy trigsimp regression; display without simplification self = Mv(obj, ga=self.Ga) if self.obj == S.Zero: diff --git a/scripts/validate_nb_refresh.py b/scripts/validate_nb_refresh.py new file mode 100644 index 00000000..faa1c0fe --- /dev/null +++ b/scripts/validate_nb_refresh.py @@ -0,0 +1,252 @@ +#!/usr/bin/env python3 +"""Validate that a notebook re-execution introduced only cosmetic output changes. + +Usage +----- +Compare two notebook files directly: + + python scripts/validate_nb_refresh.py OLD.ipynb NEW.ipynb + +Use --git to extract the OLD version automatically from a git ref, comparing +it against the current working-tree file (NEW). BEFORE_REF is any git +revision that existed before the notebook was re-executed: + + python scripts/validate_nb_refresh.py --git BEFORE_REF NOTEBOOK_PATH + +Examples: + + # Compare the version at the previous commit (HEAD^) against the + # current working copy -- typical use when reviewing a refresh PR: + python scripts/validate_nb_refresh.py --git HEAD^ examples/ipython/gr_metrics.ipynb + + # Compare the version on master against the current branch: + python scripts/validate_nb_refresh.py --git master examples/ipython/gr_metrics.ipynb + + # Compare an explicit saved copy against the refreshed file: + git show HEAD^:examples/ipython/gr_metrics.ipynb > /tmp/old.ipynb + python scripts/validate_nb_refresh.py /tmp/old.ipynb examples/ipython/gr_metrics.ipynb + +Exits 0 if every output difference is accounted for by known cosmetic changes. +Exits 1 and prints a detailed report if any unexpected difference is found. + +Intended use: run locally when reviewing a notebook-refresh PR to confirm the +re-execution changed nothing mathematically. See doc/dev/bumping-sympy.rst for +the full workflow. + +Known cosmetic changes handled +------------------------------- +1. LaTeX array column specs: ``\\begin{array}{ccc}`` <-> ``\\begin{array}{}`` + SymPy versions differ on whether they emit column-alignment characters. + +2. LaTeX multiplication dot: ``\\cdot \\left(`` <-> ``\\left(`` + SymPy versions differ on whether an explicit ``\\cdot`` is printed when + multiplying a radical by a parenthesized expression. + +3. Plain-text whitespace: unicode matrix art uses spaces for alignment. + Any whitespace-only difference is considered cosmetic. + +4. Stream outputs (stdout/stderr): warnings from Python packages such as + DeprecationWarnings from mpmath are environment-specific and ignored. + Only ``display_data`` and ``execute_result`` outputs are compared. +""" + +import json +import re +import subprocess +import sys +from pathlib import Path + + +# --------------------------------------------------------------------------- +# Normalizers for text/latex outputs +# --------------------------------------------------------------------------- + +def _norm_array_colspec(text: str) -> str: + """``\\begin{array}{ccc}`` -> ``\\begin{array}{}`` (any column spec).""" + return re.sub(r'\\begin\{array\}\{[^}]*\}', r'\\begin{array}{}', text) + + +def _norm_cdot(text: str) -> str: + r"""``\cdot \left(`` -> ``\left(`` (explicit mult dot added/removed).""" + return text.replace(r'\cdot \left(', r'\left(') + + +LATEX_NORMALIZERS = [ + _norm_array_colspec, + _norm_cdot, +] + + +def normalize_latex(text: str) -> str: + for fn in LATEX_NORMALIZERS: + text = fn(text) + return text + + +_BOX_DRAWING = re.compile(r'[\u2500-\u257F]') + + +def normalize_plaintext(text: str) -> str: + """Normalize whitespace in unicode matrix-art lines only. + + Lines containing box-drawing characters (U+2500–U+257F) may shift + alignment between SymPy versions — treat any whitespace-only diff there + as cosmetic. Lines without box-drawing chars are left verbatim so that + a real content change (e.g. ``- x`` → ``-x``) is still caught. + """ + lines = [] + for line in text.splitlines(): + if _BOX_DRAWING.search(line): + lines.append(re.sub(r'\s+', '', line)) + else: + lines.append(line) + return '\n'.join(lines) + + +# --------------------------------------------------------------------------- +# Comparison helpers +# --------------------------------------------------------------------------- + +OUTPUT_TYPES_WITH_DATA = {'display_data', 'execute_result'} + + +def data_outputs(cell: dict) -> list[dict]: + """Return only outputs with mathematical data, skipping stream outputs.""" + return [o for o in cell.get('outputs', []) if o.get('output_type') in OUTPUT_TYPES_WITH_DATA] + + +def compare_outputs(ci: int, old_outs: list, new_outs: list) -> list[str]: + """Return failure messages for unexpected diffs between two output lists.""" + failures = [] + + if len(old_outs) != len(new_outs): + failures.append( + f" cell {ci}: data output count changed " + f"({len(old_outs)} -> {len(new_outs)})" + ) + return failures + + for oi, (oo, no) in enumerate(zip(old_outs, new_outs)): + old_mimes = set(oo.get('data', {}).keys()) + new_mimes = set(no.get('data', {}).keys()) + + if old_mimes != new_mimes: + failures.append( + f" cell {ci} output {oi}: mime types changed {old_mimes} -> {new_mimes}" + ) + continue + + for mime in old_mimes: + ov = ''.join(oo['data'].get(mime, [])) + nv = ''.join(no['data'].get(mime, [])) + + if ov == nv: + continue + + # Apply normalization: text/plain can contain either unicode art + # (normalize whitespace) or LaTeX strings (normalize latex patterns). + # Apply all normalizers to text/plain since both formats appear there. + if mime in ('text/latex', 'text/plain'): + ov_n = normalize_plaintext(normalize_latex(ov)) + nv_n = normalize_plaintext(normalize_latex(nv)) + else: + ov_n, nv_n = ov, nv + + if ov_n == nv_n: + continue + + # Unexpected difference — report first differing line + old_lines = ov.splitlines() + new_lines = nv.splitlines() + for lo, ln in zip(old_lines, new_lines): + if lo != ln: + failures.append( + f" cell {ci} output {oi} [{mime}]: unexpected diff\n" + f" OLD: {lo[:120]!r}\n" + f" NEW: {ln[:120]!r}" + ) + break + else: + failures.append( + f" cell {ci} output {oi} [{mime}]: unexpected diff " + f"(line count {len(old_lines)} -> {len(new_lines)})" + ) + + return failures + + +# --------------------------------------------------------------------------- +# Main validator +# --------------------------------------------------------------------------- + +def validate(old_path: Path, new_path: Path) -> bool: + with old_path.open() as f: + old_nb = json.load(f) + with new_path.open() as f: + new_nb = json.load(f) + + old_code = [c for c in old_nb['cells'] if c['cell_type'] == 'code'] + new_code = [c for c in new_nb['cells'] if c['cell_type'] == 'code'] + + if len(old_code) != len(new_code): + print(f"FAIL {new_path.name}: code cell count changed " + f"({len(old_code)} -> {len(new_code)})") + return False + + all_failures = [] + for ci, (oc, nc) in enumerate(zip(old_code, new_code)): + all_failures.extend( + compare_outputs(ci, data_outputs(oc), data_outputs(nc)) + ) + + if all_failures: + print(f"FAIL {new_path.name}: {len(all_failures)} unexpected difference(s):") + for msg in all_failures: + print(msg) + return False + + print(f"OK {new_path.name}: all output diffs are cosmetic") + return True + + +# --------------------------------------------------------------------------- +# Entry point +# --------------------------------------------------------------------------- + +def main() -> None: + args = sys.argv[1:] + + if len(args) == 3 and args[0] == '--git': + ref, nb_path_str = args[1], args[2] + nb_path = Path(nb_path_str) + result = subprocess.run( + ['git', 'show', f'{ref}:{nb_path_str}'], + capture_output=True, + ) + if result.returncode != 0: + print(f"Error: git show {ref}:{nb_path_str} failed:\n{result.stderr.decode()}") + sys.exit(2) + import tempfile + with tempfile.NamedTemporaryFile(suffix='.ipynb', delete=False, mode='wb') as tmp: + tmp.write(result.stdout) + old_path = Path(tmp.name) + ok = validate(old_path, nb_path) + old_path.unlink() + sys.exit(0 if ok else 1) + + if len(args) != 2: + print(__doc__) + sys.exit(2) + + old_path, new_path = Path(args[0]), Path(args[1]) + for p in (old_path, new_path): + if not p.exists(): + print(f"Error: {p} does not exist") + sys.exit(2) + + ok = validate(old_path, new_path) + sys.exit(0 if ok else 1) + + +if __name__ == '__main__': + main() diff --git a/test_requirements.txt b/test_requirements.txt index bffdcb59..4ee2b5c8 100644 --- a/test_requirements.txt +++ b/test_requirements.txt @@ -1,6 +1,6 @@ # requirements for CI wheel -sympy == 1.12 +sympy == 1.13.3 flake8 packaging pytest-cov