diff --git a/python/gtsam/examples/DogLegOptimizerExample.ipynb b/python/gtsam/examples/DogLegOptimizerExample.ipynb
new file mode 100644
index 0000000000..6c1c2e6e0d
--- /dev/null
+++ b/python/gtsam/examples/DogLegOptimizerExample.ipynb
@@ -0,0 +1,336 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "0fd8354e",
+ "metadata": {},
+ "source": "# Dogleg vs Levenberg-Marquardt\n\nMost examples in this series use `LevenbergMarquardtOptimizer` without asking whether it's the best choice. GTSAM also ships `DoglegOptimizer`, a different trust-region strategy for nonlinear least squares. This notebook -- inspired by [GitHub issue #452](https://github.com/borglab/gtsam/issues/452) -- empirically compares how often each optimizer actually finds the true optimum as the initial guess gets progressively worse.\n\nThe test problem is a small loop-closure graph with a known ground truth: two \"rows\" of two poses each, pinned by priors, connected by odometry within each row, and tied together diagonally by a single range measurement. That range factor makes the cost landscape trickier than a simple chain -- exactly the kind of case where trust-region strategy matters."
+ },
+ {
+ "cell_type": "markdown",
+ "id": "ab94b0aa",
+ "metadata": {},
+ "source": [
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "524a2862",
+ "metadata": {},
+ "source": [
+ "GTSAM Copyright 2010-2026, Georgia Tech Research Corporation,\n",
+ "Atlanta, Georgia 30332-0415\n",
+ "All Rights Reserved\n",
+ "\n",
+ "Authors: Frank Dellaert, et al. (see THANKS for the full author list)\n",
+ "\n",
+ "See LICENSE for the license information"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "e269297c",
+ "metadata": {
+ "execution": {
+ "iopub.execute_input": "2026-07-22T10:39:38.816324Z",
+ "iopub.status.busy": "2026-07-22T10:39:38.816091Z",
+ "iopub.status.idle": "2026-07-22T10:39:38.823047Z",
+ "shell.execute_reply": "2026-07-22T10:39:38.821759Z"
+ }
+ },
+ "outputs": [],
+ "source": [
+ "try:\n",
+ " import google.colab\n",
+ " %pip install --quiet gtsam-develop\n",
+ "except ImportError:\n",
+ " pass"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "id": "987b9643",
+ "metadata": {
+ "execution": {
+ "iopub.execute_input": "2026-07-22T10:39:38.826115Z",
+ "iopub.status.busy": "2026-07-22T10:39:38.825852Z",
+ "iopub.status.idle": "2026-07-22T10:39:39.163703Z",
+ "shell.execute_reply": "2026-07-22T10:39:39.163136Z"
+ }
+ },
+ "outputs": [],
+ "source": [
+ "import math\n",
+ "\n",
+ "import gtsam\n",
+ "import matplotlib.pyplot as plt\n",
+ "import numpy as np"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "4f886982",
+ "metadata": {},
+ "source": [
+ "## 1. Ground truth and factor graph\n",
+ "\n",
+ "Four ground-truth poses, `T11`/`T12` and `T21`/`T22`, form two parallel unit-length \"rows\". Priors pin `T11` and `T21`; `BetweenFactor`s provide odometry within each row; a single `RangeFactorPose2` between `T12` and `T22` (ground-truth distance `1.0`) closes the loop diagonally. This graph -- and specifically that range factor -- is what makes the problem interesting: it's non-convex enough that a bad initial guess can pull an optimizer toward the wrong local solution."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "id": "b1ee1370",
+ "metadata": {
+ "execution": {
+ "iopub.execute_input": "2026-07-22T10:39:39.164964Z",
+ "iopub.status.busy": "2026-07-22T10:39:39.164874Z",
+ "iopub.status.idle": "2026-07-22T10:39:39.167759Z",
+ "shell.execute_reply": "2026-07-22T10:39:39.167429Z"
+ }
+ },
+ "outputs": [],
+ "source": [
+ "# Ground truth solution\n",
+ "T11 = gtsam.Pose2(0, 0, 0)\n",
+ "T12 = gtsam.Pose2(1, 0, 0)\n",
+ "T21 = gtsam.Pose2(0, 1, 0)\n",
+ "T22 = gtsam.Pose2(1, 1, 0)\n",
+ "\n",
+ "# Factor graph\n",
+ "graph = gtsam.NonlinearFactorGraph()\n",
+ "\n",
+ "# Priors\n",
+ "prior = gtsam.noiseModel.Isotropic.Sigma(3, 1)\n",
+ "graph.add(gtsam.PriorFactorPose2(11, T11, prior))\n",
+ "graph.add(gtsam.PriorFactorPose2(21, T21, prior))\n",
+ "\n",
+ "# Odometry\n",
+ "model = gtsam.noiseModel.Diagonal.Sigmas(np.array([0.01, 0.01, 0.3]))\n",
+ "graph.add(gtsam.BetweenFactorPose2(11, 12, T11.between(T12), model))\n",
+ "graph.add(gtsam.BetweenFactorPose2(21, 22, T21.between(T22), model))\n",
+ "\n",
+ "# Range\n",
+ "model_rho = gtsam.noiseModel.Isotropic.Sigma(1, 0.01)\n",
+ "graph.add(gtsam.RangeFactorPose2(12, 22, 1.0, model_rho))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "8555c2b4",
+ "metadata": {},
+ "source": [
+ "## 2. Monte Carlo comparison setup\n",
+ "\n",
+ "For each noise level `sigma` in a fixed list, we run `num_samples` independent trials. Each trial perturbs every ground-truth pose by Gaussian noise of that magnitude (`retract` applies the noise as a manifold perturbation), then runs both `DoglegOptimizer` and `LevenbergMarquardtOptimizer` from the same noisy start. A run \"succeeds\" if the optimizer converges to (near) zero graph error -- i.e. back to the true global optimum, not stuck somewhere else.\n",
+ "\n",
+ "The success probability at each sigma is estimated with a Bayesian Beta(0.5, 0.5) prior (Jeffreys' prior), which gives a well-behaved uncertainty estimate even when the observed success rate is 0% or 100%."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "id": "73f4e135",
+ "metadata": {
+ "execution": {
+ "iopub.execute_input": "2026-07-22T10:39:39.168798Z",
+ "iopub.status.busy": "2026-07-22T10:39:39.168740Z",
+ "iopub.status.idle": "2026-07-22T10:39:44.976858Z",
+ "shell.execute_reply": "2026-07-22T10:39:44.976461Z"
+ }
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "sigma= 0.01:\tDL success 99.95% +/- 0.07%, LM success 99.95% +/- 0.07%\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "sigma= 0.1:\tDL success 99.95% +/- 0.07%, LM success 99.95% +/- 0.07%\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "sigma= 0.2:\tDL success 99.95% +/- 0.07%, LM success 99.95% +/- 0.07%\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "sigma= 0.5:\tDL success 99.25% +/- 0.27%, LM success 97.75% +/- 0.47%\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "sigma= 1:\tDL success 79.87% +/- 1.27%, LM success 74.28% +/- 1.38%\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "sigma= 2:\tDL success 58.39% +/- 1.56%, LM success 50.10% +/- 1.58%\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "sigma= 5:\tDL success 62.49% +/- 1.53%, LM success 53.40% +/- 1.58%\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "sigma= 10:\tDL success 61.69% +/- 1.54%, LM success 46.40% +/- 1.58%\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "sigma= 20:\tDL success 66.68% +/- 1.49%, LM success 49.80% +/- 1.58%\n"
+ ]
+ }
+ ],
+ "source": [
+ "num_samples = 1000\n",
+ "delta = 10.0 # initial trust-region radius for Dogleg\n",
+ "\n",
+ "params = gtsam.DoglegParams()\n",
+ "params.setDeltaInitial(delta) # default is 10\n",
+ "\n",
+ "# Add progressively more noise to ground truth\n",
+ "sigmas = [0.01, 0.1, 0.2, 0.5, 1, 2, 5, 10, 20]\n",
+ "n = len(sigmas)\n",
+ "p_dl, s_dl, p_lm, s_lm = [0]*n, [0]*n, [0]*n, [0]*n\n",
+ "for i, sigma in enumerate(sigmas):\n",
+ " dl_fails, lm_fails = 0, 0\n",
+ " # Attempt num_samples optimizations for both DL and LM\n",
+ " for _attempt in range(num_samples):\n",
+ " initial = gtsam.Values()\n",
+ " initial.insert(11, T11.retract(np.random.normal(0, sigma, 3)))\n",
+ " initial.insert(12, T12.retract(np.random.normal(0, sigma, 3)))\n",
+ " initial.insert(21, T21.retract(np.random.normal(0, sigma, 3)))\n",
+ " initial.insert(22, T22.retract(np.random.normal(0, sigma, 3)))\n",
+ "\n",
+ " # Run dogleg optimizer\n",
+ " dl = gtsam.DoglegOptimizer(graph, initial, params)\n",
+ " result = dl.optimize()\n",
+ " dl_fails += graph.error(result) > 1e-9\n",
+ "\n",
+ " # Run LM\n",
+ " lm = gtsam.LevenbergMarquardtOptimizer(graph, initial)\n",
+ " result = lm.optimize()\n",
+ " lm_fails += graph.error(result) > 1e-9\n",
+ "\n",
+ " # Calculate Bayes estimate of success probability\n",
+ " # using a beta prior of alpha=0.5, beta=0.5\n",
+ " alpha, beta = 0.5, 0.5\n",
+ " v = num_samples+alpha+beta\n",
+ " p_dl[i] = (num_samples-dl_fails+alpha)/v\n",
+ " p_lm[i] = (num_samples-lm_fails+alpha)/v\n",
+ "\n",
+ " def stddev(p):\n",
+ " \"\"\"Calculate standard deviation.\"\"\"\n",
+ " return math.sqrt(p*(1-p)/(1+v))\n",
+ "\n",
+ " s_dl[i] = stddev(p_dl[i])\n",
+ " s_lm[i] = stddev(p_lm[i])\n",
+ "\n",
+ " fmt = \"sigma= {}:\\tDL success {:.2f}% +/- {:.2f}%, LM success {:.2f}% +/- {:.2f}%\"\n",
+ " print(fmt.format(sigma,\n",
+ " 100*p_dl[i], 100*s_dl[i],\n",
+ " 100*p_lm[i], 100*s_lm[i]))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "30d50c02",
+ "metadata": {},
+ "source": [
+ "## 3. Plot\n",
+ "\n",
+ "The error bars show \\(\\pm 1\\) posterior standard deviation around the estimated success probability at each noise level."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "id": "93b6f71a",
+ "metadata": {
+ "execution": {
+ "iopub.execute_input": "2026-07-22T10:39:44.977984Z",
+ "iopub.status.busy": "2026-07-22T10:39:44.977894Z",
+ "iopub.status.idle": "2026-07-22T10:39:45.045175Z",
+ "shell.execute_reply": "2026-07-22T10:39:45.044762Z"
+ }
+ },
+ "outputs": [
+ {
+ "data": {
+ "image/png": "iVBORw0KGgoAAAANSUhEUgAAAiMAAAGyCAYAAAA2+MTKAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjExLjEsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvctoD+AAAAAlwSFlzAAAPYQAAD2EBqD+naQAAT1hJREFUeJzt3Qd8VFX2wPGTHgIphN57VxRQbAhiAQu2tXdXV3R118qq2DuufW1Y1vZf27rqsnZFsIGIjd4EpAcSAiSBBFLn/zl38oY3k5lkJpnkTWZ+389nPpN5897kzbyZeWfuPefeOJfL5RIAAACHxDv1jwEAABTBCAAAcBTBCAAAcBTBCAAAcBTBCAAAcBTBCAAAcBTBCAAAcBTBCAAAcBTBCGLKli1bZNKkSTJ//nynd6XZviaN/RpyjIDYk+j0DiA2FBYWyr333uu5nZiYKOnp6dKjRw856KCDpF+/fk2yH/n5+fLoo4/KAQccIPvvv3+T/M9IF+pr0tivIceoeX/GR48eLSeddFKt66hjjz1Wjj766Brr/PLLL/LWW2+Zv6+++mrp3r17I+85IgEtI2gSO3fuNCewH3/8UTp27Cht2rSR3bt3y7vvviv77ruvHHbYYbRWOKRTp07y8MMPy7BhwxplfcTWZ3zmzJl1rqOX2267ze86Dz30kGednJycRtxjRBJaRtCkhg8fbpr47TZt2iSnnnqqHH744fLdd9/RYtHENDD0PSbhXB/w9z0wd+5cWb58uQwcONCzfMeOHfK///1PRowYYVpIEDsIRuC4Ll26yHvvvSd9+/aV6667Tr766iuv+5cuXSqffvqpbNu2zax78sknS9euXWs8jgYyM2bMkJSUFPnDH/5guoD019cJJ5wgY8eOrXM/Nm/eLB988IGsX79eMjMz5fjjj5d99tmnyf/P2rVr5emnn5ZLL71U2rdvb5qs9bkfc8wxcuihh5p1tm/fbpbrY40aNco0edv5Psabb74peXl5JtDTwC8+Pt4rR+ORRx6R888/3xMI2rfXlqx///vfsmbNGvnrX/9quth817c/1kcffWS21+2OO+446dOnj7mvpKRE7rjjDs+6+vr17NnTNOl36NBB6tulM23aNPNaapCkr4WeyCya1/L666/L9ddfL507d/Yst/blxBNPlDFjxgT9HEJZJ5j3U137H+w6vvumx0dfV+0y8XX77bfLgAEDzPGrz+OHw7hx48x+vvrqq/Lggw96luv7NCEhQc4880yCkRhDNw0iQrdu3czJ9ptvvpGtW7d6lusJQ7/AZ82aZU6C77zzjgla3njjDa/t9SSpJ5WVK1eaE82f/vQnE+BoU6/+AquLfin27t1b3n77bfN/li1bZn693XfffU3+fzZu3Gge78svvzSBg97+/fffzUni5Zdflt9++80EPnry0FYlPcnZv9DtjzF9+nSz7oYNG0wAc/HFF8tRRx0le/bsqZGjob9S/e2Dbq/Pd8WKFeYE4m999dJLL0mvXr3MPlZVVZn91BOidazi4uLMidu6WNvoSfz777+XUM2ZM8cEgvpa6glMn+NVV10l1157rWcd3UfdVw3E7PTY6fKffvoppOcQ7DrBHOdg9j+YdXxpYPf+++/LXXfdVeM+/XzpPuixqO/jh4P+Lw2G/vWvf0llZaVn+SuvvGIC/IyMjEb9/4hALqAJbNiwwaVvt2uuuSbgOjfffLNZ59tvvzW3P/nkE3P73nvv9axTVVXlOvfcc13JycmulStXmmUffPCBWe/ZZ5/1rFdeXu4688wzzfIpU6Z4li9atMgse+uttzzL5s6d60pISHDdeOONXvvzxhtveO1PKP/Hn2D/z3fffWduDx061LVjxw7PepdddpmrXbt2rj/84Q+ubdu2eZb/+c9/dmVkZLiKioo8y6zHGDRokCsvL89rH+Lj41233nprra+Jtf3AgQO9ti8sLPS7/uzZs83j6vHVY2QpKytzLVu2rNbXZcKECea51rY//px88smuESNG1Fi+YMECz9/6GPpY8+bN81pn69atZvnDDz8c0nMIZp1gj3Mw+x/MOv7cc889rri4ONfq1au9ll9wwQWurKwsV0lJSYMev76fcWsdff8tXbrU/P3pp5+a+xYuXGhuz5gxwzV16lTz95w5c0LeDzRPtIwgYrRs2dKT5Gb9utRlN9xwg2cd/UV35513SllZmWl+V/rrSpuXL7vsMs96+mtUWy2C8eyzz5pfar6/JM8991yTrKmP35T/x6JN1VlZWZ7b2kKhrUZDhw6V7Oxsz3JtGSkqKjLdWb5OP/10adeunef2yJEjTQuU/gINhv5KtW8f6BerPjftdrH/6lZJSUleOQF63D788EOz3o033mhyT/R4L1682Ku1Jhj6WNpKk5ub67VcX5/6COY5BLtOMMc5mP2v73P84x//aLritPXGou8RbcXT/WjRokWDHj8cBg0aZN6P+jlX+p7UVppgujoRfcgZQcTQL0ul/etKm7+1qdv64rRoGbCeEPR+az1t6tfAwM5+EqzNwoULpVWrVnL33Xeb2y6Xy3NRq1evbtL/Y+nfv7/X7bZt2/pdbgULmqPg7wvf1+DBg+Xzzz+X4uJiTwAYiL/t/dFASF8bfX6BaJfSkUceabpItFtD8370JK4BjnZ3FBQUeLpvgjF58mSTP6R5J9p1phfN3ahvuXEwzyGYdYI9zsHsf32fo76248ePl9dee03uueceE5hojpG+9poH1NDHDxcNmjRPTINs7ea64oorvII8xA5aRhAx5s2bZ35RWkl++qWkJylf+qWuy60vLb229ztbKioqgv7fqamp5mSvFz25a9Kn9r1r4qPVEtJU/8fiG4Tpa1Pbcn/74W9/rWXBfOnbW2ZqE+i1sbv//vtNQKLl3c8884w5EWrLiAZH9aHVV5pLozkc+otar7Xc2H6y1WDH32uza9euej2HYNYJ9jgHs//BrBOIrqO5Pxp4Kt1WgwzNXQnH44fD2Wefba4vuugiE5DoNWITLSOICJocqVU02hVhtYzoSUoT8bQZXwdIsyxZskTKy8tlyJAh5rZea2VDaWmpaTGxrxcM/YLWapG//OUv5iQSSFP9n3BatGiR31/umoCZlpYWtv+jz01/2WqSrL0LyU5blrRVS7sq7H744Yd6/18NlrTbQS9KEy//8Y9/mK49ff9o9ZW/ViN/r0swzyHYdYI9znXtf7Dr+KOVQhoEaVeNJohrsu5TTz1Vr31oLPq/tWVGX68jjjjCtIQiNtEyAsdpvoB+IemX+2OPPeZZPnHiRJNHoM3MFg1Cbr31VnMivfDCC80y/RWnIzvat9UB1ay+6Lrol6/+ctbmYt9f0Pqr0Rr2vKn+Tzhp8LRu3TrPba2O+frrr2u0wjSUjpSprVX6HPUYWTSQ/Pnnn83fWk66atUqr/wEHfTO6m4LleaeaM6DndXNY7WI6IB6+r6yRvS0WkXsuRShPIdg1gn2OAez/8GsE4jer58RLS/++9//bgKj8847L+TXUGkrlr9AJhy0LF4H0fOtCENsoWUETUrH6NCmee1q0RwRDUR+/fVX8ytOSy21qdiiYyQ88cQT8re//c2Ufmr3zezZs01Tv5b4WmONaMKbDjGtX2o6/of+utIBkzSBUBP27GNq+KPJejrOwiWXXGJO1joarH4Ra1moNh1r03VT/p9w0hPjWWedZfJMNF9ATz6nnXZa2Act22+//cwx0YBNW5C0+V9P+npsdcwLHTr+lltuMcGRjmExYcIEU0aqJ0I9wevJLlQaVGmptbZE6C9/LXXWUmYdR8OaXkBzYqZMmWJyETQI0mOmwcADDzxgjkWozyGYdYI9zsHsfzDr1EaTq3W/NNn7nHPOkdatW4f8GqrHH3/crKPrBvsZ93XIIYeYqR986efa33g+iC1xWlLj9E4g+ukX9nPPPee5rUmgmuSnwYd+gft+SdppE7ue/K1Bz7QaxOrKsdMve/1y1S4U7e7RhEj9NT516lRzMlL6GJq1r8GP3men3S+6vf5615YXTUzVL0/fICOY/1Obuv6PBlv6S14rWezN1vo6aBfBKaecYsZasehJVis0NCnUSm7VcVn0RKnBhyaNahBgDXqm45XY+XtNAu1DXa+hHmc9AWugoYOMadO7ViBZNCD67LPPzHPR5637prlCOoT4lVdeaV6P2h7fl1aCaICq/09zMzSA9e0GsrrSdIwNDU70cTXvRvNWdP/0/RfKcwh2nWDeT8Hsf7DPMZAXX3zRtOhp1ZW/bpdgHl9/FGiXj9WVE8xn3Je+9w4++GCzjgYmGqQFsmDBAhMUaUtOKM8VzRfBCKLWf/7zH1Meq7/UfE/AzfH/hMIejGgrBABEMnJGEBU0CdLeyKdzXGhTvLYgWEOoN6f/AwCxhJwRRAUtX9ShzrX5VxMLtVtHS141ea+uXI5I/D8AEEtC6qbRL19NzNK+cU3YeuGFF0zzdF10FkYdY0Cz+jUpSkcv1D5WIJx0MCkdw0L7wLV0Vedg8R2Tozn9n4aoLecDAJp1MKIZ1ZropEl6mkSoSXPWzI+BaNLY0UcfbSolNHFME9MeeughUwZHBjUAAAgpGNFV7aNeBhOMaAa3Nl9rNr9FR/jTi79afwAAEFtC6uSuz5wBmtWvzdh22qqiywEAABo1gVUHtdKRCXVOBjutV8/JyQm4ndbn68WiIx7q8Mtax88kSgAANA/ao6JxgI7HU1uSf5NU0/jugA54VVvvkI6YaM14CQAAmjcdVM8aNbvJgxGd3EyrDLTqwE5HgtTWkUB0aGid3dKiowd2795d1qz5XTJ0wjSXS0o/mSwtl70juyVZLiq9UZa6epl1s9OS5LihneTy0X0ku2VyIz47AABQVw+JTjVgn+y0yYMR7VI58MADzciUOoOlvcLG3xwFFh1m2z4rqiU7u41kZGS4b5w3VeTN7ZKxeoZ8mPm8PNv3OfnXcpH8XWXy1rx8c1l6z3hJS2YoFQAAnFRXikXYR2nSmRftk51dc801ZmwSHRRKZ7DU0t65c+cGNeFSrRKSRM58TaTDvpK0J1+u2XKLzLl2hFw1tk/DnwQAAGgyIQUj2qKRlZVlLuryyy83f+usmxad8l27VSw66JLOGqmzXOoU1job5GuvvVbrJElBS0kXOe8dkYwuIvm/SdJ/LpDxA9wTrrVtlUKrCAAA0TbOiLZs6MyMvrRLxRqBUoMRrYTxN6vq7t276zVSpfY56eNpkOPpprHLXSLy8rEipUVSPvg06f/rqeKSeJl3+zHSmrwRAAAcUef5u1pICRVaBWO1igSirR968afRhszuMETkzP8TeeN0SVr6ntydWCh3VFwiq3K2yoH9ujTO/wQAOKqystJMUwLnJCUlmfm5Gip6sjv7jBU58UmR/10pFyZ+Kd9X7SMrt/aXA/s5vWMAgHDSBv0tW7ZIQUEBL2wE0EaKjh07NmgcsOgJRtSw80Q2/ijyy6syLuFnWZh3qtN7BAAIMysQ0SEi0tLSGAzTwaCwpKTEDNehOnXqVO/Hiq5gRHU/xAQjPeJy5f28Eqf3BgAQ5q4ZKxDRUbnhLCv9who/rL5dNmEv7XVcu4HmqntcrqzMJxgBgGhi5Yhoiwgig3UsGpK/E33BSLZ7JNZ2cUWys6hQCneT3AQA0aah85SVlFVIz5s/Nhf9G/UXjjnjoi8YSc0UaZFt/uwelyer8nY6vUcAADS5d955x2scsEgWfTkjVuvIpu0mb2Rl7i4Z0cMdnAAA4IRPPvlEnnzySfO35lXomBv9+vWT448/Xg4++OBG+Z+///67fP/999IcRGcw0rqnyKZf3HkjeTUHaQMAoCmtX79eZs6caaZG0SoUHQRMp0YZP368HH300fLmm2/6nZMtVkRpMOLOG9GWkS8IRgAAESA+Pl6OPfZYz+2zzz5brrjiCjNxrE6V8tBDD3nuW7p0qTz77LMmiNFZ66+66ioZNGiQ1+PNmTNHnnvuOZM4esghh0jXrl3l888/N8sCycnJkWeeeUaWLFlixgY566yzZOzYsQ1+3IaKvpwRWxKryRnJJWcEAKJ6rIuyinpdLPXdPoTZVAIaMGCA/OlPf5J//vOfUlVVZZYtXrzYzHivY3icf/75UlxcLAcccIBZbvnpp59kzJgx0qpVKznllFNk9uzZctFFF8msWbMC/q/Vq1fL8OHDZceOHXLBBReY/33GGWeY+eIa8rjhENUtIxqM5BTukZ17yiU9NcnpvQIAhNnu8koZfMfnDXqMA+6bUa/tlt4zPiwTso4cOVIeffRR02qhrRC33Xabaa14+eWXzf1nnnmmbN682SyfNm2aWXbPPffISSedZFo5rHU0gNE54AK5+eabzTba4mLRsVpuvfVWE3DU93HDIapbRrrG50uCVMoqumoAABE+cFhJiXtsrB9++EFOPPFEr3W0lUJzTCz6tya/2h133HG1/p/p06eb7SZMmCAnnHCC2f7555+XjRs3mhyW+j5uOERny0irjiKJqZJYsUc6x+WbJNZh3Vs7vVcAgDBrkZRgWihCpd0sVovIz7cdVa8WDv3f4ZCTk2PG6ujQoYO5rd0oOtOtnd7W5RZ/s+DWNiuuNYOuJsweeeSRAQOi+jxuOERnMBIfL5LVQyR/hfQwY41QUQMA0UhP4g3tKtHtw9HdUl/vv/++jBgxwhOA9OrVS1auXOm1zm+//SY9e/b03O7Ro4fJAbHzve1Lt9fh9O1JtL7q87jhEJ3dNLauGvdYIySxAgAii+ZhaL7GjBkz5IEHHvAs1+TSF154wbSYqE2bNpnbF154oWedc845xyzLz8/3jCny9ttv1/r/Jk6caCpifvzxR8+y7du3y4svvtigxw2H6GwZ8UpizZWvc2kZAQA4S0tlrVYJ7Q7R6hgt1/3ss8/MWCOWG264wVS16H1DhgwxZbjatXL99dd71pk0aZIZt6R///5mvTVr1pgSYZ3ROJAbb7zRTGin1TIDBw40pca5ubly5513NuhxwyF6gxFbee+mgt1SXFohLVOi9+kCACKXJoxa3SwaBKSnp5sRWNu2bVtj3dTUVFM1s2rVKlm3bp3pOunbt6/XOrr9t99+K/PmzTNBjgYtGlTYy411DBENPCz6fx977DFTlaOBkD7G4MGDvQZbC+ZxG0PUt4z0TtgqUi6yeusuGdo1y+m9AgDEoG7duplLKPr27VsjCLHs3LnTDE42btw4T3eKjheigYZFc0/04is7O1tGjx5d78dtDFGfM6LdNCIuM0cNAABKE1bXPniCuTiZvFpfKSkp8sQTT5juFh0ldZ999jElu1deeWVEPm5dmt8RCFZWd82zlhau3dJGipijBgAQNZKTk83ke5rToQmu2oKiw7tH6uPGbjCSmCKS0UWkaCMVNQCAqNQrQFdMpD5u7HXT+CSxMnsvAACRKbqDkdY9PWONbNhRIrvLKp3eIwAAEIstI32T8kWrkrSiBgAARJboDkaqy3v7JW011yvzGIkVAIBIExMtI11cWt4rlPcCABCBYiJnJL1im7SQPSSxAgDcyopF7sp0X/RvOCq6g5EWrUVSszwVNczeCwBwwqJFi+Tpp5+u9f4nnnjCzODrS+eP0fumTp0q0Sq6gxGf2XvXbSuWPeVU1AAAmtbs2bPNJHS13X/DDTeYGXuLioq87nv++efNfZMnT5ZoFf3BiJXEmrxNqlwiv2+lOQ4AEHnS09Nl6NCh8vbbb3uW6QR1r7zyiowfP16iWcy0jOzbYru5pqIGABCpLrnkEnnppZc8t6dPny5lZWVRH4xE73DwNWbvzTPX5I0AQBTRQaTKS0LfrqzE/9+hSEoTiYuTcDr77LPluuuukyVLlsiQIUNMYHLxxRdLQkKCRLMYCEbcFTUdKjeba2bvBYAoooHIA50b9hiP9K3fdrfkiCS3lHB31ZxxxhkmCLn11lvlgw8+kMWLF8unn34q0SwxVrpp0vdslgSppJsGABDRLr30Ujn11FPNbLkHH3yw9OnTR6Jd9Acj6Z1FElIkvrJUOsVtk7XbEqW0olJSEqO7yQsAYoJ2lWgLRai0a8ZqEZm0SiQ5rX7/uxGMGjVK2rRpI3feeae8+OKLEguiPxiJjxdp3UMk/zcZlJwvG0vby9r8EhnQMd3pPQMANJTmbDS0q0QDkTB3tzTUQw89JF999ZWcdtppEguiPxixkljzf5NhGYUyfau7ooZgBADQlCorK83gZXYpKSny5z//uca6J510krnEitgIRqrzRgal5JtrklgBAE1Jxw+56qqrZO3atV7LW7Ro4bnfX1Bi2X///Wu9v7mLjWCkuqKmR5y7vJexRgAATenQQw81l/reP2rUKHOJVtE/6JltrJF25e4kJ1pGAACIHDHVTdOyZIOOkCNr8oulvLJKkhJiIxYDAPjQhNW7CnlZIkRsnI2zemjKtcSX7ZKuySVSUeUyk+YBAADnxUYwkpQqkuEeoe+Q1u7ZEOmqAQAgMsRGMGLLG9mvVYG5/i13l8M7BAAAYiwYcVfUDEiuLu/N2+nwDgEA6quqqooXL4qORWwksKpsdzDS1bXFXDN7LwA0P8nJyRIfHy85OTnSrl07czsuzDPnIjgul0vKyspk69at5pjosaivxFjrpsku22Suf99aLBWVVZJIRQ0ANBt60uvVq5ds3rzZBCRwXlpamnTv3t0cm/qKnWCkurw3uWi9pCbFy57yKlm/vUR6t2vl9J4BAEKgv8D15FdRUWGGWIdzEhISJDExscGtUzHXMhK3a4sMaZcov+SUmSRWghEAaH705JeUlGQuaP5iJ4E1LVskNdP8OTLLXUmziiRWAAAcFzvBiK2iZt+07eZ6ZR7lvQAAOC3GghF3V02fhK3mmoHPAABwXmwFI9VJrJ2qNpvr1Vt3SWWVy+GdAgAgtsVky0h6yUZJSYyX0ooq2bC9xOm9AgAgpsVky0jcjjXSp7qkl7wRAACcFZMtI1KwXvq3b2H+ZFh4AACcFVvBiM7cG58kUlUuwzLd3TOrmDAPAABHxVYwEp8g0rqH+XNQ6jZz/RtjjQAA4KjYCkZsXTU94/M8E+ZVUVEDAIBjYi8YqU5ibVu2SZIT3HPUbCrY7fReAQAQs2K2ZSS+YK30btfS/E0SKwAAzonZlhHZsVb6tq8u7yWJFQCA5hOMvPLKK9K7d28zZfDAgQNl2rRpta5fUlIif/3rX6Vz585mdkWd9nny5Mlm6mcn56eR7WulX/VYIzp7LwAAaAbByCeffCITJ06U++67T3bs2CFXXnmlnHHGGfLTTz8F3Oamm24yAcunn34qu3fvljfffFOmTp0qDz30kDgajJQWSt+MMvPne79ulJIyh4IjAABiXEjByKOPPionnXSSnHvuuZKeni5XX321DB8+XP7xj38E3Gb+/Pkyfvx42W+//UxryqhRo+Swww4zyx2R1EIkvZP5c0Byvmexy8UcNQAARHQwoifrH374QcaMGeO1/Mgjj5Tvv/8+4HbnnXeefPbZZ6b1pLi4WGbOnClz5swxAY3TSaydq7Z4Fm0u3OPc/gAAEMMSg11x586dJv+jXbt2Xsvbt28vubm5Abe74oorZMWKFTJy5EhzOz4+Xu6//3455ZRTAm5TWlpqLpaioiIJexLr+u8lsXCtiOzrGW+kb/v08P4fAADQ+NU0VVVVEhcXF/D+SZMmmZyRn3/+2QQYX331lTzyyCPy+OOPB9xmypQpkpmZ6bl069ZNGqe8d51n0a/rC8L7PwAAQHiDEc0RadmypeTluUcutWzdulU6duwYMFB55pln5LrrrpMRI0ZIcnKyjB492iTB1pZnotU2hYWFnsuGDRukMZJY43Zoy4jbNyu8nxcAAIiwYERbPw499FDTsmE3Y8YMs9wegFRWVnq20aRV3+RQXUfLfANJSUmRjIwMr0tjjDUSV7DGs2hF7i7ZuMM9eR4AAIjQbhrtcvn444/l5ZdfNi0iDz/8sCxYsMC0fFjuueceadOmjScYOe2000wVzuzZs03eyfTp0+WFF14wyx1jddPs3Cwp4i7vVV8tp3UEAICIDkbGjRsnr732mglCevbsKW+88YbJBxk2bNjeB4yPN60hlqefflrOOussueiii8zAZzoA2jXXXGOCFsekZYukuFtbusXtDUBmEIwAANDk4lzNYIANrabRRFbNHwlbl81zh4tsWShyztvyW9YoGff4t5KcGC/z7zhG0pKDLjICAAANPH/H3tw0vnPUbF8j/dq3km7ZLaSsokpmr9rm9J4BABBTYjcYab13wjzNbTlqYAdzc+bywGOmAACA8IvhYKR6jpod7oqaIwe2N9czluUxNDwAAE0odoMRWzeNOqh3tqQlJ0jezlJZvCnMI74CAICAYjcYsbppdBTWqkpJSUyQw/u1NYtm0FUDAECTid1gJLOrSHySSGWZSFGOWbQ3b4TxRgAAaCqxG4zEJ4hkdffKGxlbnTeycGOh5BUxiy8AAE0hdoMRe95I9Rw17dJTZL9uWebvr5irBgCAJhHbwYhVUVOdxKqOslXVAACAxhfjwYjVMrI3GLFKfL9bmS97yt0T/gEAgMYT28FIRif39ZL/ipQVmz+HdM6QDhkpsru8Un74ndFYAQBobLEdjGRVd9PY6GisR1JVAwBAk4ntYKR1dTWN2r3Db95IM5hHEACAZi22g5GktL1/F6z3/HlY37aSkhgvmwp2y2+5u5zZNwAAYkRsByN223/3/NkiOcEEJIrRWAEAaFwEI5YNP3q9MPaJ8wAAQOMhGLGs/c5vMPLr+h2yvbisEQ8BAACxjWDE3k1TsMFzs3NWCxnUKUM0f/VrRmMFAKDREIzYrfnG66anqoaJ8wAAaDQEI3a/+wQjg9zByLcrtkp5ZVXjHQUAAGJYbAcjyS1F7ioUufhj9+3fvxbTL1Ntv65Z0qZlsuwsrZCf1m53bj8BAIhisR2MWLoeKJLYQqQ4TyRvmWdxfHycjKWqBgCARkUwohJTRHocWmveyEzyRgAAaBQEI5beR+ztqrEZ1a+tJCXEyZr8Yvl9K6OxAgAQbgQjlt5j3NdrZ4lUlnsWp6cmyUG92pi/aR0BACD8CEYsHfYVaZEtUrZLZNOvfqtqGI0VAIDwIxjxvBLxIr1G++2qsUZj1Yqawt17W00AAEDDEYwEkTfSo01L6du+lVRUueS7lVvD8LIDAAALwYi/YGTjTyKlu/yPxsrEeQAAhBXBiF12L5Gs7iJV5SLr5/jtqvlqRZ5UVu0dGA0AADQMwUiQXTUjerSWjNREKSgpl3nrdzTwZQcAABaCkYDBiPfgZ4kJ8XLEACbOAwAg3AhGfPWqHm8kd5HIrq1+S3xnkjcCAEDYEIz4atnWPeaIn6Hhx/RvJwnxcbIid6ds2F4SvqMAAEAMIxipbTRWn2AkKy3Z5I4oRmMFACA8CEZqyxtZ/bWIy+W/xJeJ8wAACAuCEX+6HyISnyRSuF5kxxq/eSM/rN4mxaUV4TkKAADEMIIRf1JaiXQb6beqpk+7VtI9O03KKqtk1qr8pjhGAACEXUlZhfS8+WNz0b+dRDBSV1WNz3gjcXFxVNUAABBGBCN15Y2s+VakqsrrrqMGdjDXM1fkSRWjsQIA0CAEI4F0GS6SnC6ye7t7zBGbkb2ypWVygmzdWSqLNhU27AgAABDjCEYCSUgS6XmY366a5MR4Gd2/nfmbqhoAQHNUZWvZr6j07gFoaomO/vfm0FXz22fuYOSwa2pMnPfp4i0yc3muXH9Mf8d2EQAAl8slu0orZEdxuWwvKZMdxWWyvbhMdpT4XNvu12WWrbtKJaNFsmMvJMFIMHkj6+aIVJSKJKZ47ho7sL3ExYks3lQkWwr3SMfM1MY+VgCAGLG7rNJ/UKG3zfLyGsFGeWX9Z5TfVVopTiIYqU27gSKtOojsyhXZ8KNIr8M9d7VtlSL7d8uSeesL5KsVeXLOyO5NcLgAAM1NaUWlmfHdO5jQIKLcT8tFmbl/T3n9uk3SkhOkdVqyZLdMltYtkyU7Lan6uvq2Lq++PzUpXsY87E5D6Ne+lTiJYKQ22vShJb6L3nF31diCEWs0Vg1GZiwjGAGAWKC5FQW7y31aLGxBhT3YqG7B0O6T+khOiN8bVLRM2htkeAUbep3kWZ6alBD04zs9togdwUgwXTUajJh5am73uuvIgR3kkS9+k9mr8mVPeWVIbwIAgPMJnEV77N0d1UGG35wL93qFu8vr9b90klV3EGELKrxaLJJqBBvayqFjW8UCgpFgJ83b9IvInkKR1EzPXYM6pUunzFTZXLhH5qzeZvJIAADNJ4GzPkNFaXyQ1cKn+8NfUGFbnp6SKPHxsRFY1AfBSF0yu4q06SuybZXI2lkiA0/w3KURq1bVvDF3vcxYnkswAgBhoq3NGjzUzKfY20USrgRODRRaB8ixaOPpJtnbYpHZIsm0dDR3acmJsvbBvec0JxGMBNtVo8GIzlNjC0asifM0GJm5LE9cJ7tipkkNAIJVVlElBRo0+Gmd8A0orCqR3eX1q+5okZRQ3SpRd46F/p2VlmzGjoKzCEaCoUmsP/2zxuBn6tA+bU1Gck7hHlm+ZacM6pTRCIcJACJDZZXLBBZWjoX/stO9LRh62dmABE6voMKrW6S6BcMebKQlS4tkcveaI4KRYJgqmjiR/BUiRTkiGZ09d2nS6qi+beXLZXkyc3kewQiAZpXAuXNPha3FwrcSZG+liLVMEzhdrvomcLoDi7pyLKy/ddoNWptjA8FIMFq0Fuk8TCTnV/fEefudXaOqRoORGcty5aqxfRvpUAFA7QmcxWWVe/MpanSDeFeKmACjpNy0dNRHVlqSJ6DwVIn4Teh0/52eSgInAiMYCaWqRoMR7aqpEYy4q2jmbSiQ/F2lZkA01F3fPviOz83fS+8ZbxKpAISQwOkTbGiuRVk95xepLYHT3g1itWJoAmdiAnkWCB/OAKEksc563B2MaBulLVFVh4If0jlDluQUydcrtsrpI7qG8RABaO5I4ARqRzASrG4HiySmiuzcLJK/UqRd/xqjsWowohPnEYwA0Uu7NTRvwl/i5vZd4U3gTEqIC1ANQgInogvBSLCSUkW6HeQeiVVbR3yCkSMHdZAnZ66Sb3/LN7+CKBVDLGpu3W+aZ1G0RwfKqjvHwrouqGcCpw5L4Z28uXcIb38BR3YrEjgROyL7myISu2qsYOSgiV53De2SaXJFNGfkp7Xb5bC+bR3bzUj/8l+/vUTmrtnmWfbAJ8vMSUvL+JIS4k0gp78I9dp7mV7HSXJCgud+6z6zXvW1+29dL95k8JONHzvvrRKd6bTGqJuBhvh2V4nUN4FT8ybcQYRPUBGgUiQjNYkROIEACEZCDUZm3O0eibWyQiRh78unw/weObCdvPPzRjNxHsGIm375L9hYIPM3uC8LNhSYDH67139YL41FU3v2BijegYpXIFMj4PFellJ9bQ+Wai6zrxdXc5ktWLIeg2Cp9gROf0N41xZsaKtkfbQyCZx7q0NqJm96l5/qUOAkcALhQzASik77ueem0TlqNs8X6XpAjRJfE4wsz5XbJwyKuV/kOk320pwiE3BYwcfabSU11tOT8cBO6bJwY6G5PXF0b3OtJxKtBii3riurqpe5/Czb+7cOAW0t8z0ZaXN6aUWVuUipRBx7sGQFL/ZgKXDAExd0sOR5XNt61jo1l3kHS+E64eqxso+uWdsgWdb92spRH/p8/A3h7bf8VAOLtCRJSWSgLMBJBCOhiE8Q6TVaZNmHIr9/VSMYGdWvrfkiX7etRFZvLZa+7VtJNDeJa6Axf8MOmb++QOZvLJRlOUV+Swt7tW0p+3fL8lw0ENGmcSu34Nqj+4Utt0D3q6LK5RO0uIMVr2XBBjwVLimrrPQKeGIpWNI8B+8ApfZAJt4Wu5z9wg+eRE8dWKs+9P/UzKmwtWD46R5hBE6g+SEYqU9XjQlGvhEZ/bcaTb0H9c6W71bmm6qaaApG9IRiAo8NhZ7uFn9TaetJQQOO/bpmyf7d9TrTzP3gL9GxMWhrlHWi9PNvHdfcgqWqBgRLVstXfRM49X79TMVaCyMQi+oVjFRVVUlhYaFkZWWF9EVRWlpqtm3RooU0W72OcF9vmCtSViKSnFajxFeDEc0bmTi6jzTXvnotU7aCDr3WpFNf+mt4n84Zsn+31rJft0wZ1q21dMtuwckjhoOlXaXlcucHS81jPX3uMOmUmUoCJ4DwByMPP/ywPPDAA7Jnzx5JT0+XBx98UC655JJat1m+fLlcffXV8u2330rLli3l6KOPlmeffVbatGkjzU6bPiIZXUWKNoqsnyPS9yivu48a1EHu+nCp/LxuhxSWlEtmWpJE+twUv+cXe+V5LNtcZE5Ivvq0ayn7dcuSYaa7pbUM6JhOCXOUaWiwpC1eVjCiIxNHemkvgMgQ0jfFO++8I7fffrt88MEHcswxx8hbb70lF1xwgfTp00fGjBnjd5ucnBw5/PDD5aSTTpKtW7dKq1atZNq0afLzzz/L+PHjpdnRliDtqpn/urvM1ycY6ZadJv07tJLfcnfJNyu3ykn77Z1ULxJo6bHmeFgVLhqE6DgLvtq2cne3mC6XblkytGuWKWUMFz1JrX3whLA9HgAgRoKRp556Sk499VQZN26cuX3uuefK1KlT5ZlnngkYjGgrigYgzz33nCQluU9m+hjNfp4aDUZ0vBE/tKpGg5GZy3IdDUZ2l2l3izvHQ+fN0SBkU8HuGutpEuK+XTLdwUd3dwDSJYvuFgBAhAUjmuuhrRlnn+09Sdzo0aPljTfeCLjdxx9/LCeffLIJRDTPRLt24u0p981Rr+rAa/NCkZLtImnZXncfNai9PPfNavlqxVapqKxqkvEItLtl9dZdJuiwulyWb9lZY0Anbdjp266Vp8VDr7W7RZvlAQCI6GBk165dJk+kbVvvkUXbtWsneXl5AbfbsGGD6YceNmyYrF69WioqKkzLiLayZGd7n8Ttia56sRQVFUlESe8g0n6wSN5SkTXfigw5xetuzanQsQsKSsrl1/UFMrKX/+fZEHlFezw5HnpZtLHQ7/wX7dJTvMpq9+2aaUaCBBoD3W8AGjUYsapmNJiw09sJCbUPGKRdNJ9//rlpRVm/fr3JFfnzn/8s//73v/2uP2XKFLn77rsl4ltHNBjRrhqfYERbQo7o306mzc+RM5+f0+B5OjQpUIMNz0im6wskp3BPjfVaJCWYYMMefGg1A6WRAIBIFvTZUbtXMjIyJDc312u53u7cOXBeRJcuXeSAAw4wgYjq3r27XHnllXLLLbeYMkJ/J8rJkyfL9ddf79Uy0q1bN4komsQ6d2rAvBGtqtFgJFTarbIqb1f1mB4afBTKb7n+u1v6t0/36m7RxFmGqAYANDch/VTXqpjp06d7BQpWi4e9O6ekpETat29vbo8dO1a2bNni9Ti6jo41EugXe0pKirlEtJ6HicQliOxYI7JjnUjrHl53j+7fzsw7UtckXFsK7d0tO0wLSLGfYbA7ZqSasTy0pNbqbtEBoQAAaO5COptpi8URRxwhDz30kJx44ony6quvyqpVq0zJr+WRRx6RJ554QgoKCsztG2+8UUaOHClPPvmkTJgwQZYsWSKPP/64XHbZZdKspaS7h4PXwc+0xLf1hV53axnsiO5Z8uPaHZ5lxaUVZlRK+2BiW4pqdrekJSfI0K5W4OG+7piZ2iRPCwCAiA5GDjvsMDPGiJbrajlvv379TEvJwIEDPetoGW+HDh08twcPHixffvml3HnnnfLYY49Jp06d5LbbbpOrrrpKmj3tqtFgRLtqhnsHI2rMgPaeYOTkp2ebahffhhIdIrt/h3QZVl1Sq10u/dqnm1YVAABiQZxLEzcinOaMZGZmmtJgzVuJGOu+F3nlOJG0tiKTVorXLGEiZoyPE56c5bWsc2Zq9Zwte6tbGKUSABCNgj1/k3TQEF0OEElKEynJd1fWdNynxmy1lifP2V8O7tVG2mfQ3QIAgB0jXTVEYrJIj8PcfweoqrEcPagDgQgAAH4QjIQjb0RpEisAAAgZwUg45qlRa2eLVJQ1+OEAAIg1BCMN1X6IO4G1vFhk089hOSgAAMQSElgbSitotHVk8Xsiv38j0uNQz13M0wEAQN1oGQnnLL51JLECAICaCEbCmcSq3TSlO8PykAAAxAqCkXDQeWla9xKpqnAPhAYAAIJGMBLuqhq6agAACAnBSLi7aghGAAAICcFIuPQcrVP9uIeF35kbtocFACDaEYyES8s2Ih33df+95tuwPWzUKisWuSvTfdG/AQAxi2AknOiqAQAgZAQjjRWMuFxhfWgAAKIVwUg4dT9EJCFZpGijyPbfw/rQAABEK4KRcEpOE+l2kPvv378K60MDABCtmJumMcYbWfude56aA/8U9odvlrTLqihHJG+Zu9pIr3MX773//Yki3Q8W6XqgSKf9RJJaOLm3AIAmRjASbr00b+Q+d0VNVaVIfILElOJtewMOz/UykdLCwNss/8h9UfFJ7qokDUzM5QCR1j1F4uKa7CkAAJoWwUi4dR4mkpIhsqdAZPMCkS7DJSrpHDx5y2sGHsV5/tePSxBp20+k/SCR9oNFsnuLvHep+74jJotsXiiy8UeR4q0iOb+6Lz8+774/re3ewESv9TVNSW+65woAaFQEI+GWkCjS83CRFR+LrPmm+Qcj5XtE8n+r2dJRuD7wNtqSoQGHFXjodZu+Iokpe9exjy1y6F9Fklu6u3MK1ots/Elk48/uaw3oSvJFfvvUfTHi3I9rBSd6adtfJJ4UKABojghGGitvRIMRLfEddZ00C5UV7gog35aO7atFXFX+t2nV0Tvg6DBYpO0AkZRW9dsH7Yoxkw72ENn39L3B0JZF1QFKdZCigVDeEvfl19fc62lrVJcR3t07adn1fDEAAE2JYKQxxxtZ/4P7ZJqUKhGjqkqkcEPNlo78FSKVZf63Sc2ytXTYgo+mONnra9ftQPfFsnOLd3Cy6VeR0iJ3BZO9iim7j3f3TochIglJjb/PAICQEIw0Bu0ySO8ksnOzyIa5e2f0bUra5bErr2ZLx9blImW7/G+TlCbSbmDNwCO9Y2QlkOr+DDrRfbFadbSVxN69s22Vu1VHLwvfdq+X2MKd02Pv3sno5OhTAQCIxLlckT9UaFFRkWRmZkphYaFkZGRIs/D+5XtPguqWHHdeRGPYXeAOMuwtHblLRHZv97++VqxowOTb0pHVI3ryLkq2i2z6xdaC8ov/ip6Mrt7BiSktjqCWLABoxoI9f9My0phdNfZgJBzKStzdKb5dLEWbAmwQ565asQccet2mT/R3V2gXUr9j3Bere2rbSu/uHX0NdbTcpXqZVrO0uNtId6CiQVoktQwBQDhoIcEDnRv/B3MQCEYaS0O6ZirL3d0M9oBD/96+Rvtf/G+jv/B9Wzq09UNHhYW7xafdAPdl2Pl7y5Nz5nl37/grLW7Zzjv3xJRvU1oMAOFCMNJYMjq7y1k1qAhEf60XrPWTTLpSpKrc/zZpbaqDDXvp7ECR1MxGeypRSwOKXqPdF2VKi9ftDUxMafFCd4Cy4hP3RcXF1ywtbtMverq4AKCJEYw0Jh1vxApGNJl1hxV4VAcfW1eIlJf43zY5vWZLh163ateouxzTTGlxT/fFq7R4oU9p8Qb3cPZ6+eVV93opmSJdbaXFWmZMaTEABIVgpDH1Olzkl1fcfz81wv86CSnurgPfQcIyu5KnEAlMafFI98VStFlk088+pcWFIqtnui8WbRmzd++019JiPnIA4ItvxsbU/VDv4dD15OTb0qG/wjlBNS9aDpxhLy0ud7d0+ZYWW5cFb+0tnfYtLdYyZQAIB+36Ly8WKd3lzonTS1n1tWdZkXt4B/1bKzEtxfkksEatVFsZ099W0WwfrbQySUuC9WLN1ByotHjdbPfFktnNOzjpOJTSYiCWaK5a+e7ggodal+2sHkOqnqN17N7hHv3aIbSMNNkrbZuXBdHPX2mxzvHjW1qs+Sd6WfJf93oJye6AxN69k9WdLjsg0gKIitLqgKDIOyjwu8wKMAKs5wow5UZ9aUu8Tsuh02Qk63V69aX6b81J1Gs9L828171Nq/biJIIRoClopY1WPell+AXuZfolpPkm9u4dnRRQ81H0Mrd625bt/ZQW13P+HyCWVZTZWhRsrQlBBRQ+ywJVPNZbXHWgYAUPtiDCCh78LkuvGXgktQjuB4yOM2IFIw5XZBKMAE7RLw0dj8Yak0Z/bWnFlb20WCt5ivPcEy/qxVNaPMSntLgvpcWITlWVAYKHXaEvqywN//4ltfRpdagODEIKKFq5HyeGhwcgGAEihf6Sye7lvgw9w71M+5J1rBN7946OGpu7yH2xqrX0V00XW3DSZTg5SnCOdktqMODbCuEJEqrzHrxaHXzWs5YHGv6gIXSeqtqCh1CWxSeEf/9iEMFIY9Khde/yMx8KECxtbu1+kPtiKcqxtZ787B5Fdo+WFs9wXyw6EJtXafFgKrdQRyJlia1rorpLotaAIsCyQJNxNoRO1aBFAZ6gwN7CYM+LSK8joEiP/ukwmiEmygOaOy0t1okR7bknOluxL1NaPNyntLiDE3uMsCZS7gkQPISyrDrJslESKdO9gwd/gUOdAUUrigCifKI8ghEgGhVv8y4t1r/1JOQrs7vPrMVDG/alH0ETb0V8IqXfKgt7yWYdwYO1blVFIyRS1hE8BLssMZVKsBhXxKy9QAxr2Uak/zj3pdbS4vXuy5L33etRWhxYZUWAEs1gAgqf9SrLwn/MrWDAqxojI4hlPgGFBpDMUo0mRs4IEKulxXuKfGYt/lGkZFt0lRZrJYYJDGobkbKuZdXLK3Y3UiJlgPJMr8qLjNoDCpNIGbuVGGj+CEaAWKXJgDVKi9f4lBYv8l9a3GHI3q4dvWT3Cd/JUPdDu3sCjfcQSkChQ2OHm84n5W8AqVCX6W2mggAMghEAttLi3u7L0DNtpcULfEqLN7mDFL38/LJ7vdQsd8uJDolvWfe9O7k2pEGlqoOI+g5pHUh8YvDjPdQ1qFRiMu8YIMxIYAUQmsJN3rMWa1ePVnSEm7bA+GthqE9AoUm55EEATY4EVgCNI7OL+zL4ZFtp8WJ3YLJ+jsji99zLdVRYHYzNk+vgr0LDd5ltXAgtRSaAAGIC3TQAGkYHkNKkVr3sf+7eYOTybyntBRAU0q8BAICjCEYAAICjCEYAAICjCEYAAICjSGAFED7MVA2gHmgZAQAAjiIYAQAAjiIYAQAAjiIYAQAAjiIYAQAAjiIYAQAAjiIYAQAAjiIYAQAAjiIYAQAAjiIYAQAAjiIYAQAAzS8Y2bVrl6xcuVJ2794d0nbl5eWyePFi2bBhQ33+LQAAiEIhByM33XSTtG3bVo444ghp06aNPPzwwyFtu++++8p1110X6r8FAABRKqRg5OWXX5ZnnnlGZs+eLZs2bZJp06bJ5MmT5dNPP61z208++UQ+//xzOfLIIxuyvwAAIJaDkeeff15OP/10GTFihLk9btw400Kiy2uTk5MjEydOlNdff11atGjRsD0GAACxGYxUVVXJ/Pnz5aCDDvJafuihh8ovv/xS63bnn3++XHPNNTJs2LCG7S0AAIg6icGuuHPnTikrKzN5InZ6Oz8/P+B2999/v7m+4YYbgt6p0tJSc7EUFRUFvS0AAIjSlpHERHfcogGJnQYNSUlJfrdZsGCBTJkyRW688UZZunSpqaTRoEaDC/1bq2v80W0yMzM9l27duoX2rAAAQPS1jLRs2VJat24tmzdv9lqutwMFC9u2bZPevXvLpEmTPMvWr18vcXFxcvbZZ8sXX3whnTt3rrGdJsVef/31ntsavBCQAAAQneJcLpcr2JVPO+002b59u3z11Vfmtm46cOBAOeaYY+Tpp582y/Ly8kwQMmjQIL+PMWHCBElNTZV333036J3UYERbSAoLCyUjIyPo7QAAgHOCPX+HVE1z2223yZw5c0y3y3fffSeXXXaZ5ObmerV8PPvss3LIIYc0bO8BAEDMCCkY0WoYbRXR0VevvfZaMxKrBiU9e/b0rNO+fXsZPHhwwMfo0aOHdO/evWF7DQAAYrObxil00wAA0Pw0SjcNAABAuBGMAAAARxGMAAAARxGMAAAARxGMAAAARxGMAAAARxGMAAAARxGMAAAARxGMAAAARxGMAAAARxGMAAAARxGMAAAARxGMAAAARxGMAAAARxGMAAAARxGMAAAARxGMAAAARxGMAAAARxGMAAAARxGMAAAARxGMAAAARxGMAAAARxGMAAAARxGMAAAARxGMAAAARxGMAAAARxGMAAAARxGMAAAARxGMAAAARxGMAAAARxGMAAAARxGMAAAARxGMAAAARxGMAAAARxGMAAAARxGMAAAARxGMAAAARxGMAAAARxGMAAAARxGMAAAARxGMAAAARxGMAAAARxGMAAAARxGMAAAARxGMAAAARxGMAAAARxGMAAAARxGMAAAARxGMAAAARxGMAAAARxGMAAAARxGMAAAARxGMAAAARxGMAAAARxGMAAAARxGMAAAARxGMAAAARxGMAAAARxGMAAAARxGMAAAARxGMAAAARxGMAACA5heMbNq0SebMmSN5eXlBrV9ZWSnLly+XRYsWye7du+vzLwEAQJQKKRipqqqSSy+9VPr27StXXHGFdO/eXW666aZat3n66aelZ8+ecsopp8jZZ58tnTt3lpdeeqmh+w0AAKJEYigrP/PMM/L+++/LggULpH///jJ37lw5/PDD5cADD5TTTz/d7zZFRUXy008/SceOHc3tV155Rf70pz/JAQccIPvtt194ngUAAGi24lwulyvYlYcPH26CiBdeeMGz7IQTTjDXH3/8cVCPof8uNTVVnnrqKZk4cWJQ22hAk5mZKYWFhZKRkRHs7gIAAAcFe/4OuptG8z4052PEiBFey/X2vHnzgt6x+fPnS1lZmfTr1y/gOqWlpeYJ2C8AACA6BR2M7Ny5UyoqKiQ7O9tredu2bWXHjh1BPUZxcbH88Y9/lNGjR8sRRxwRcL0pU6aYSMq6dOvWLdjdBAAA0RqMJCcnm2vfapiSkhLPfbXZs2ePSWLVVpH//Oc/EhcXF3DdyZMnmyYd67Jhw4ZgdxMAAERrAmtaWpppBdGyXju93aNHj1q31W4XDUQ0qPj666+lffv2ta6fkpJiLgAAIPqFVNp7zDHHyAcffOC5rd02H330kVluWbt2rcyaNatGIKLLv/rqK09VDQAAQMilvXfccYcp49WxRiZMmCCvv/666aaZNGmSZ51XX31VnnjiCSkoKDC3zzzzTBOcvPjii7JixQpzUTr2iF4AAEBsCykYGThwoBlb5PHHH5fnnnvOVMTo7U6dOnnW0QBj1KhRntuaY6IVN7q+3cUXX2wuAAAgtoU0zohTGGcEAIDmJ+zjjAAAADQGghEAAOAoghEAAOAoghEAAOAoghEAAOAoghEAAOAoghEAAOAoghEAAOAoghEAAOAoghEAAOAoghEAAOAoghEAAOAoghEAAOAoghEAAOAoghEAAOAoghEAAOAoghEAAOAoghEAAOAoghEAAOAoghEAAOAoghEAAOAoghEAAOAoghEAAOAoghEAAOAoghEAAOAoghEAAOAoghEAAOAoghEAAOAoghEAAOAoghEAAOAoghEAAOAoghEAAOAoghEAAOAoghEAAOAoghEAAOAoghEAAOAoghEAAOAoghEAAOAoghEAAOAoghEAAOAoghEAAOAoghEAAOAoghEAAOAoghEAAOAoghEAAOAoghEAAOAoghEAAOAoghEAAOAoghEAAOAoghEAAOAoghEAAOAoghEAAOAoghEAAOAoghEAAOAoghEAAOAoghEAAOAoghEAAOAoghEAAOAoghEAAOAoghEAAOAoghEAAOAoghEAAOCoxPpstHDhQlm3bp3069dPBg4c2GjbAACA6BdSy0hZWZmccsopMnbsWHniiSdk5MiRcumll4rL5QrrNgAAIHaE1DKiwcTs2bNlwYIF0rVrV1myZIkccMABcsQRR8gFF1wQtm0AAEDsCKll5F//+pecddZZJqhQQ4YMkeOOO84sD+c2AAAgdgTdMlJRUSHLli2Tv/71r17Lhw4dKs8991zYtlGlpaXmYiksLDTXRUVFwe4uAABwmHXeris1I+hgZNeuXVJZWSmtW7f2Wt6mTRspKCgI2zZqypQpcvfdd9dY3q1bt2B3FwAARIidO3dKZmZmw4ORlJQUc11SUlIj4EhNTQ3bNmry5Mly/fXXe25r4NKjRw9Zv359rU8mWqJIDbo2bNggGRkZEs14rtGJ4xqdOK7RqaiRzznaIqKBSOfOnWtdL+hgpEWLFtKxY0cTENjp7d69e4dtGyuIsQIZOw1Eov0EbdHnyXONPhzX6MRxjU4c1/AIphEhpARWTTx9//33paqqytzes2ePfPjhh2a5ZenSpfLBBx+EtA0AAIhdIQUjd9xxh2zcuFFOO+00efHFF+WEE06QxMREry6Vd955Ry688MKQtgEAALErpGCkZ8+e8uuvv5oRVL/++ms5/PDD5aeffjIJqZbBgwfLySefHNI2ddEumzvvvNNv10204blGJ45rdOK4RieOa9OLczEUKgAAcBAT5QEAAEcRjAAAAEcRjAAAgOYzUV5j0aHfdTI9HQxNZ/XVsUkaY5tIsGXLFpk3b560atVKhg0bZq5r880338jmzZu9lnXp0sUkAkcyPTY6iI5d+/bt5cgjj6x1O51CYM6cObJ9+3bz+nTv3l0inVaQWaXrdv3795fhw4f73Wbu3LmyZs0ar2XZ2dkybtw4iTTFxcUyffp0SU9Pl6OOOsrvOnl5efLDDz9Iy5Yt5bDDDqt1UMOGbNPYdOiBL774wiQwjh8/3u86OnzB6tWrzXxb+++/v8TFxQV8PH1f6PvDl35n1TbWUlPQGdX1uOo+nnjiiTXu/89//mNG0LbTz+SAAQNqfVwdpFI//wkJCTJq1Kg6v+Oagn6v6HPV43vqqafW+E7W4gp/dELXQOeW//73v17Tlqh99tnHXJy0Zs0aMyFtu3btzPdPUlKS38/0rFmzzOty6KGH1hgl3Z/6bNOsgpFVq1bJMcccYz78HTp0kJ9//lmeeuopueSSS8K6jdN0BLqJEyeag7nvvvuaD4CWPL/yyium3Lm2ofHXrl1rvvQs+gaL9GDk8ccfl/nz55sZmu2VVrUFI/qa6HHVAFO/qDUoueuuu+TGG2+USPa///3P60tbRzT89NNP5e9//3vAYGTq1KnmC/Dggw/2LOvTp09EBSPl5eVyww03yLvvvivx8fGmMs5fMPLGG2/I5Zdfbp5rfn6+OX6ff/65DBo0KOBj12ebxqR5/JMmTZK3337bnEQ1MPQNRvR75oorrpDdu3eb96f+qNATlY6b1KlTp4An/HPOOce8bm3btvUs1+8tJ4OR22+/3Xz36DALyl8worOqa9BkHzlTA4vaghEN5M4880xTPanPXQe41M+HBptOeeCBB8xcaHpc9XvYNxjJzc2VadOmeS1bvny5mWleT+qBgpHLLrvM/OCw/2DS19OpYGTdunVmnzRQ1u/aFStWmO+l9957z+v8odWsEyZMMO/ZtLQ0Wbx4sbz55ptmWSD12SZkLoeNGTPGNW7cOFdFRYW5PXXqVFdycrJr3bp1Yd3Gabm5ua633nrLVVlZ6Vl24403utLT0127d+8OuN348eNdN9xwg6u5Oe2001yXX355SNucddZZrhEjRnhej//+97+uuLg416+//upqTp566ilXYmKia/PmzQHXueiii1znnXeeK5IVFxe7/vGPf7h27NhhjuVhhx1WY52cnBxXixYtzHNW+v4+/vjjXQcffHDAx63PNo1N9+GRRx5xbdu2zXze9ttvvxrrfP31117vxZKSEtf+++/vOuOMMwI+rr6X9Wv2u+++c0WSxx57zLVlyxbXvffe6+rRo4ffdVJSUlwffvhhSO+Xdu3auW666SbPsksvvdTVs2dPV3l5ucsp+h7etGmT6/HHH3e1adMmqG30e7eu96M+ln6nR4pFixa5pk+f7vWePvXUU1377ruv17J+/fqZ7x/Lrbfe6srOznYVFRX5fdz6bFMfjgYjGzZsMB/Ujz/+2LOsrKzMlZWVZb4YwrVNpJo7d655LkuWLKn1Q3HuueeaE/Ps2bNdu3btcjWXYEQ/CLrfs2bNqvNNq19kGlC+9NJLXst79+7tmjRpkqs50ROUPvfa6Af72GOPdU2bNs317bffugoLC12RLFAwogFFq1atXHv27PEs++KLL8z7euXKlX4fqz7bNKVAwYg/kydPNl/UdQUj+pz1WC9cuNBVVVXlihR1BSNTpkwxn+F58+Z5fvwFYv14sAfhS5cuNc9fAzmnBRuMrF+/3hUfH1/ju8iXPtadd95pnrcGqU4GXIG89tpr5rlY+zZnzhxzPBYsWOBZJy8vz5WQkOB6++23/T5GfbapD0cTWBctWmSu7c1a2r+lzYDWfeHYJlJ9+eWXZv6eupprtTn/n//8p1x88cWmKf+TTz6R5uD77783o+5q02GvXr3MtACBaJOiNuv6NnFql1ZzOq46wJ92T+lzrssvv/wiL7zwglx55ZVmIkjtumhu9Nj069fPa0BCPWZKm3LDtU0k0h9zM2fODKpZXj+/zz//vMlB0DwK7aKNdJoL869//ct8hrXLSrtstIs8ED2u2hVl79bQbjf9fm5On2HtvtI8prPOOqvOdbVbT4+tdrVrPo3mE0XaOWbAgAGe7jg9DnpchwwZ4llHc0v0mNV2zg11m/pwNBgpLCw019o/a6ejs2oSVLi2iUTa/3zffffJ3XffXWvinvbZa7/rRx99ZE7Y2v987rnnmvyKSKZ965rA+vHHH5sPqN7WPmjt14zm4/rSSy+ZGTADJT9adMoE6/XRD/RNN91kcp60r7o50ePm75ip2j7DoW4TiTQXQfMKNK8pEM1T0MRJDVD1R4SezHUW80svvVQinf540JwJfY/qfusPp/POOy/g+v6Oq9JEx+ZyXDXA1GBEv2M1IKmNBmr6edXvZn19NJ9CA5hIGUf03Xfflddff10efPBBr2Okk//p+zKUc26o2zS7YMT6ZaTJa3Z6O9AJuj7bRBr9gOtEgXpC+tvf/lbruprQab0JNDq95557zJvj22+/lUh29NFHe2Vx6xxFmhA5Y8aMqD2umqmvSV16otGEz9poIq+9ZUCDkeTkZJMA2Jzoc/B3zFRtn+FQt4k02sqhn0X9ZTx06NCA6+lnQD8L9hOzzsulv1g1ETaS2Scz1UoqfY/++OOPpgoq2OPa3D7D+v2kBQPBtGzaXx9N6pw8ebJp2fOtknPCF198Ieeff748+uijctJJJ3kdI62K8VXXOTfUbZpdMKJdDkp/+dvp7UBdF/XZJpJoK4GeiE455RRTUREq/XWiTW5bt26V5kRPtPrGDbTf1rHzPa7aktIcjqvSrHWtpKlPVZcGmlqp0NyOq34e/R0zVdtnONRtIol2W1x99dUmELHPwxUs/ZWp5bRavt6c6H6rQO9RPa56nwblFq2U0pag5nBcrZZN7W4ZMWJE2F+fpjJ9+nRzfrn33nvluuuuq3GMtDQ3JyfHs0y7x7WlvbbPa6jbNLtgRPuJtUlb69nt4y9oZGovd9VfEVrmGco2kWjZsmUmENFIVXMF/I1PoPkh3333nflbo1EtRbPTMkJ9Yxx44IESqfTLyLf5Tj8g+lzs+61lztrnbpU66heA/bjqLwwtKYv042r/Ijv22GPN+9OXjqdhtXpoC5F+Sdvp+1s/3JF8XP05/vjjzTg4Oq6E5d///rfpT7a+0PX9oCduKwAJZptIPsZ/+ctf5K233qpRIqr0s6nP9ffffze3/XWnaveHjhVkL5mNNFru6jt2ju53VlaWyfex6Bgq2n2stCxdt9FSXvtx1R9QdY0vFAk0ONSxQwK1iujzt3KaNODwHYNF79cWEntuhRMtOyeffLLp/vfX6j569Gjzo8f+PavnFP2M6neX5YMPPjBdi6Fs02BhS4Wtp3fffdeUQWrFhGY7d+vWzZR42h100EFey4LZJtJoGV3Hjh1d/fv3d7355pumJMy66H2Wo446ynXCCSeYvzdu3OgaNGiQydjXzG59vloSecUVV7giWX5+vmvgwIGmdFn3++abbzbVExdccIHXeieffLIp07Zoxr1W1GjlhlYf6GOMHTvWqxw6Uq1evdpUEmhmvT9axqtly1blkD43rdr45z//6brttttcmZmZrj/84Q8RVWmhPvroI/MePfroo10DBgzwvGft+3nhhRe6unTpYspFtaxTP5tvvPGG536trtCvGnsZZF3bOOGzzz4z+zhhwgRTYWI9V63Ws1eLnHPOOV6fX/0+suzcudM81xdffNFTzaBVSA8++KDrhRdeMFVW+hkO9D5pKjNmzDD7fuaZZ7ratm3reS5WtZ5W/owcOdJ1//33m+eiz1mra/7v//7P63G0ouLhhx/23L7lllvMe1mrcO655x7zXO33O0Gr1fS56XtOh1KwnmtBQYHXek8++aQrLS2txnKLPi+tnrGqv4YPH26qkfQzrNVx+t313HPPuZwyb948s/+jR4/2en/qRcvQ7c8zNTXVPJe///3vrtatW9cYPkI/m/ZlwWzTUBExa6/+atRKAu2D0sG8LrroIq9kGR2gR7N3tWk02G0ijf5SuuWWW/zed9ttt3ky8u+//37Tz2wN9LVt2zZ59dVXTfeOth5oJKqRaqTTlhHdb/0loRn22m9u7ztX2p+prT+aT2JZuHCh2U5/peiAaforxZ5bEak0yU9/JeovZytz3e6ZZ54xzZx6fJW2Er322mvm14cmgo0ZM8a0GESaa6+91u+ve82NsfJi9NewJvPpaMH6y/Dss882FSMWzXHSAc6uueYaOeSQQ4Laxgk333yzaWH19fLLL5t91OPrryJMux/1Pat0RE79LtLnO3bsWLNMj7H+qtTWBm3W1kRuf61nTUnzXfxVfujgkfpdq/R+beXZtGmTqYbT5Hmrm9yiCa263D74lbYuaLKuvj+0u8CeW+GEhx56yFS5+XrkkUfMKLoW7dbQVhwd/M4fzQXT53L66aeb2ytXrjTnIE1E12o4a7A3p8yaNUuefvppv/c9++yzXsnF2kqr72VtydNk+zPOOMNr/auuusqMsmpPWK5rm4aKiGAEAADELibKAwAAjiIYAQAAjiIYAQAAjiIYAQAAjiIYAQAAjiIYAQAAjiIYAQAAjiIYAQAAjiIYAQAAjiIYAQAAjiIYAQAAjiIYAQAA4qT/B1Z7Z7HUjm3JAAAAAElFTkSuQmCC",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "fig, ax = plt.subplots()\n",
+ "dl_plot = plt.errorbar(sigmas, p_dl, yerr=s_dl, label=\"Dogleg\")\n",
+ "lm_plot = plt.errorbar(sigmas, p_lm, yerr=s_lm, label=\"LM\")\n",
+ "plt.title(\"Dogleg empirical success vs. LM\")\n",
+ "plt.legend(handles=[dl_plot, lm_plot])\n",
+ "ax.set_xlim(0, sigmas[-1]+1)\n",
+ "ax.set_ylim(0, 1)\n",
+ "plt.show()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "faa6bbc2",
+ "metadata": {},
+ "source": [
+ "This is a Monte Carlo experiment with no fixed random seed, so the exact numbers will differ every time this notebook runs -- but the qualitative pattern is the point: at small noise both optimizers succeed essentially every time, and as the initial guess gets worse, Dogleg's trust-region approach tends to hold up at least as well as, and often better than, Levenberg-Marquardt on this particular loop-closure geometry."
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.13.12"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
\ No newline at end of file
diff --git a/python/gtsam/examples/DogLegOptimizerExample.py b/python/gtsam/examples/DogLegOptimizerExample.py
deleted file mode 100644
index 26f4fef846..0000000000
--- a/python/gtsam/examples/DogLegOptimizerExample.py
+++ /dev/null
@@ -1,118 +0,0 @@
-"""
-GTSAM Copyright 2010-2019, Georgia Tech Research Corporation,
-Atlanta, Georgia 30332-0415
-All Rights Reserved
-
-See LICENSE for the license information
-
-Example comparing DoglegOptimizer with Levenberg-Marquardt.
-Author: Frank Dellaert
-"""
-# pylint: disable=no-member, invalid-name
-
-import math
-import argparse
-
-import gtsam
-import matplotlib.pyplot as plt
-import numpy as np
-
-
-def run(args):
- """Test Dogleg vs LM, inspired by issue #452."""
-
- # print parameters
- print("num samples = {}, deltaInitial = {}".format(
- args.num_samples, args.delta))
-
- # Ground truth solution
- T11 = gtsam.Pose2(0, 0, 0)
- T12 = gtsam.Pose2(1, 0, 0)
- T21 = gtsam.Pose2(0, 1, 0)
- T22 = gtsam.Pose2(1, 1, 0)
-
- # Factor graph
- graph = gtsam.NonlinearFactorGraph()
-
- # Priors
- prior = gtsam.noiseModel.Isotropic.Sigma(3, 1)
- graph.add(gtsam.PriorFactorPose2(11, T11, prior))
- graph.add(gtsam.PriorFactorPose2(21, T21, prior))
-
- # Odometry
- model = gtsam.noiseModel.Diagonal.Sigmas(np.array([0.01, 0.01, 0.3]))
- graph.add(gtsam.BetweenFactorPose2(11, 12, T11.between(T12), model))
- graph.add(gtsam.BetweenFactorPose2(21, 22, T21.between(T22), model))
-
- # Range
- model_rho = gtsam.noiseModel.Isotropic.Sigma(1, 0.01)
- graph.add(gtsam.RangeFactorPose2(12, 22, 1.0, model_rho))
-
- params = gtsam.DoglegParams()
- params.setDeltaInitial(args.delta) # default is 10
-
- # Add progressively more noise to ground truth
- sigmas = [0.01, 0.1, 0.2, 0.5, 1, 2, 5, 10, 20]
- n = len(sigmas)
- p_dl, s_dl, p_lm, s_lm = [0]*n, [0]*n, [0]*n, [0]*n
- for i, sigma in enumerate(sigmas):
- dl_fails, lm_fails = 0, 0
- # Attempt num_samples optimizations for both DL and LM
- for _attempt in range(args.num_samples):
- initial = gtsam.Values()
- initial.insert(11, T11.retract(np.random.normal(0, sigma, 3)))
- initial.insert(12, T12.retract(np.random.normal(0, sigma, 3)))
- initial.insert(21, T21.retract(np.random.normal(0, sigma, 3)))
- initial.insert(22, T22.retract(np.random.normal(0, sigma, 3)))
-
- # Run dogleg optimizer
- dl = gtsam.DoglegOptimizer(graph, initial, params)
- result = dl.optimize()
- dl_fails += graph.error(result) > 1e-9
-
- # Run
- lm = gtsam.LevenbergMarquardtOptimizer(graph, initial)
- result = lm.optimize()
- lm_fails += graph.error(result) > 1e-9
-
- # Calculate Bayes estimate of success probability
- # using a beta prior of alpha=0.5, beta=0.5
- alpha, beta = 0.5, 0.5
- v = args.num_samples+alpha+beta
- p_dl[i] = (args.num_samples-dl_fails+alpha)/v
- p_lm[i] = (args.num_samples-lm_fails+alpha)/v
-
- def stddev(p):
- """Calculate standard deviation."""
- return math.sqrt(p*(1-p)/(1+v))
-
- s_dl[i] = stddev(p_dl[i])
- s_lm[i] = stddev(p_lm[i])
-
- fmt = "sigma= {}:\tDL success {:.2f}% +/- {:.2f}%, LM success {:.2f}% +/- {:.2f}%"
- print(fmt.format(sigma,
- 100*p_dl[i], 100*s_dl[i],
- 100*p_lm[i], 100*s_lm[i]))
-
- if args.plot:
- fig, ax = plt.subplots()
- dl_plot = plt.errorbar(sigmas, p_dl, yerr=s_dl, label="Dogleg")
- lm_plot = plt.errorbar(sigmas, p_lm, yerr=s_lm, label="LM")
- plt.title("Dogleg emprical success vs. LM")
- plt.legend(handles=[dl_plot, lm_plot])
- ax.set_xlim(0, sigmas[-1]+1)
- ax.set_ylim(0, 1)
- plt.show()
-
-
-if __name__ == "__main__":
- parser = argparse.ArgumentParser(
- description="Compare Dogleg and LM success rates")
- parser.add_argument("-n", "--num_samples", type=int, default=1000,
- help="Number of samples for each sigma")
- parser.add_argument("-d", "--delta", type=float, default=10.0,
- help="Initial delta for dogleg")
- parser.add_argument("-p", "--plot", action="store_true",
- help="Flag to plot results")
- args = parser.parse_args()
- run(args)
diff --git a/python/gtsam/examples/FixedLagSmootherExample.ipynb b/python/gtsam/examples/FixedLagSmootherExample.ipynb
new file mode 100644
index 0000000000..ca1da5428a
--- /dev/null
+++ b/python/gtsam/examples/FixedLagSmootherExample.ipynb
@@ -0,0 +1,323 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "dbdafeea",
+ "metadata": {},
+ "source": "# Fixed-Lag Smoother Example\n\nMost factor-graph examples keep *every* variable in the problem forever. That doesn't scale to a robot that runs for hours: the graph, and the cost of solving it, would grow without bound.\n\nA **fixed-lag smoother** fixes this by only keeping variables whose timestamp falls within a trailing window (the \"lag\"). As new measurements arrive, anything older than the lag is automatically marginalized out -- summarized into the remaining variables and then dropped -- so the problem size stays bounded no matter how long the robot runs.\n\nThe scenario: a robot drives in a straight line at 2 m/s. Two independent odometry-like sensors each measure the motion between consecutive poses (simulating sensor fusion), sampled every 0.25 seconds for 3 seconds, with a 2-second lag."
+ },
+ {
+ "cell_type": "markdown",
+ "id": "d1be22d7",
+ "metadata": {},
+ "source": [
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "6d783a59",
+ "metadata": {},
+ "source": [
+ "GTSAM Copyright 2010-2026, Georgia Tech Research Corporation,\n",
+ "Atlanta, Georgia 30332-0415\n",
+ "All Rights Reserved\n",
+ "\n",
+ "Authors: Frank Dellaert (C++), Jeremy Aguilon (Python), et al. (see THANKS for the full author list)\n",
+ "\n",
+ "See LICENSE for the license information"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "439cb4bd",
+ "metadata": {
+ "execution": {
+ "iopub.execute_input": "2026-07-22T10:34:49.014414Z",
+ "iopub.status.busy": "2026-07-22T10:34:49.014188Z",
+ "iopub.status.idle": "2026-07-22T10:34:49.019899Z",
+ "shell.execute_reply": "2026-07-22T10:34:49.019196Z"
+ }
+ },
+ "outputs": [],
+ "source": [
+ "try:\n",
+ " import google.colab\n",
+ " %pip install --quiet gtsam-develop\n",
+ "except ImportError:\n",
+ " pass"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "id": "e34ae8e2",
+ "metadata": {
+ "execution": {
+ "iopub.execute_input": "2026-07-22T10:34:49.022002Z",
+ "iopub.status.busy": "2026-07-22T10:34:49.021836Z",
+ "iopub.status.idle": "2026-07-22T10:34:49.205992Z",
+ "shell.execute_reply": "2026-07-22T10:34:49.205506Z"
+ }
+ },
+ "outputs": [],
+ "source": [
+ "import numpy as np\n",
+ "import gtsam"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "90c2bdb5",
+ "metadata": {},
+ "source": [
+ "## 1. Configure the smoother\n",
+ "\n",
+ "`BatchFixedLagSmoother` re-solves with Levenberg-Marquardt on every `update()` call (GTSAM also has an `IncrementalFixedLagSmoother`, based on iSAM2, which is more efficient but not covered in this notebook). `lag=2.0` means only the most recent 2 seconds of poses are kept.\n",
+ "\n",
+ "Each update needs three staging containers: new factors, new variable values, and a mapping from key to timestamp -- the timestamps are how the smoother knows which variables have aged out of the window."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "id": "235c12ab",
+ "metadata": {
+ "execution": {
+ "iopub.execute_input": "2026-07-22T10:34:49.207298Z",
+ "iopub.status.busy": "2026-07-22T10:34:49.207189Z",
+ "iopub.status.idle": "2026-07-22T10:34:49.208950Z",
+ "shell.execute_reply": "2026-07-22T10:34:49.208656Z"
+ }
+ },
+ "outputs": [],
+ "source": [
+ "lag = 2.0\n",
+ "smoother_batch = gtsam.BatchFixedLagSmoother(lag)\n",
+ "\n",
+ "new_factors = gtsam.NonlinearFactorGraph()\n",
+ "new_values = gtsam.Values()\n",
+ "new_timestamps = {}"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "fec4ec9f",
+ "metadata": {},
+ "source": [
+ "## 2. Prior on the first pose\n",
+ "\n",
+ "As in the odometry example, a prior anchors pose key `0` at the origin. We also record its timestamp as `0.0` seconds."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "id": "00d5938a",
+ "metadata": {
+ "execution": {
+ "iopub.execute_input": "2026-07-22T10:34:49.209955Z",
+ "iopub.status.busy": "2026-07-22T10:34:49.209902Z",
+ "iopub.status.idle": "2026-07-22T10:34:49.211928Z",
+ "shell.execute_reply": "2026-07-22T10:34:49.211611Z"
+ }
+ },
+ "outputs": [],
+ "source": [
+ "prior_mean = gtsam.Pose2(0, 0, 0)\n",
+ "prior_noise = gtsam.noiseModel.Diagonal.Sigmas(np.array([0.3, 0.3, 0.1]))\n",
+ "X1 = 0\n",
+ "new_factors.push_back(gtsam.PriorFactorPose2(X1, prior_mean, prior_noise))\n",
+ "new_values.insert(X1, prior_mean)\n",
+ "new_timestamps[X1] = 0.0"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "4d0bc0d0",
+ "metadata": {},
+ "source": [
+ "## 3. Simulate two odometry sensors over time\n",
+ "\n",
+ "Every 0.25 seconds we add a new pose key, derived directly from the timestamp (`int(1000 * time)`), and a constant-velocity guess (`time * 2` meters along x). Two `BetweenFactorPose2`s connect it to the previous pose -- one per \"sensor\", each with its own measurement and noise model, simulating fusion of two independently noisy odometry sources.\n",
+ "\n",
+ "`update()` is only called once every two steps (`time >= 0.50`), so the very first call batches two hops of factors at once, while later calls process one hop at a time. The staging containers are cleared after each `update()`, but the smoother's own internal window keeps sliding forward regardless."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "id": "f9fca920",
+ "metadata": {
+ "execution": {
+ "iopub.execute_input": "2026-07-22T10:34:49.212868Z",
+ "iopub.status.busy": "2026-07-22T10:34:49.212810Z",
+ "iopub.status.idle": "2026-07-22T10:34:49.220765Z",
+ "shell.execute_reply": "2026-07-22T10:34:49.220403Z"
+ }
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Timestamp = 0.5, Key = 500\n",
+ "(0.995821, 0.0231012, 0.0300001)\n",
+ "\n",
+ "Timestamp = 0.75, Key = 750\n",
+ "(1.49284, 0.0457247, 0.045)\n",
+ "\n",
+ "Timestamp = 1.0, Key = 1000\n",
+ "(1.98981, 0.0758879, 0.06)\n",
+ "\n",
+ "Timestamp = 1.25, Key = 1250\n",
+ "(2.48627, 0.113502, 0.075)\n",
+ "\n",
+ "Timestamp = 1.5, Key = 1500\n",
+ "(2.98211, 0.158558, 0.09)\n",
+ "\n",
+ "Timestamp = 1.75, Key = 1750\n",
+ "(3.47722, 0.211047, 0.105)\n",
+ "\n",
+ "Timestamp = 2.0, Key = 2000\n",
+ "(3.97149, 0.270956, 0.12)\n",
+ "\n",
+ "Timestamp = 2.25, Key = 2250\n",
+ "(4.4648, 0.338272, 0.135)\n",
+ "\n",
+ "Timestamp = 2.5, Key = 2500\n",
+ "(4.95705, 0.41298, 0.15)\n",
+ "\n",
+ "Timestamp = 2.75, Key = 2750\n",
+ "(5.44812, 0.495063, 0.165)\n",
+ "\n",
+ "Timestamp = 3.0, Key = 3000\n",
+ "(5.9379, 0.584503, 0.18)\n",
+ "\n"
+ ]
+ }
+ ],
+ "source": [
+ "delta_time = 0.25\n",
+ "time = 0.25\n",
+ "\n",
+ "while time <= 3.0:\n",
+ " previous_key = int(1000 * (time - delta_time))\n",
+ " current_key = int(1000 * time)\n",
+ "\n",
+ " # assign current key to the current timestamp\n",
+ " new_timestamps[current_key] = time\n",
+ "\n",
+ " # Add a guess for this pose to the new values\n",
+ " # Assume that the robot moves at 2 m/s. Position is time[s] * 2[m/s]\n",
+ " current_pose = gtsam.Pose2(time * 2, 0, 0)\n",
+ " new_values.insert(current_key, current_pose)\n",
+ "\n",
+ " # Add odometry factors from two different sources with different error\n",
+ " # stats\n",
+ " odometry_measurement_1 = gtsam.Pose2(0.61, -0.08, 0.02)\n",
+ " odometry_noise_1 = gtsam.noiseModel.Diagonal.Sigmas(\n",
+ " np.array([0.1, 0.1, 0.05]))\n",
+ " new_factors.push_back(gtsam.BetweenFactorPose2(\n",
+ " previous_key, current_key, odometry_measurement_1, odometry_noise_1\n",
+ " ))\n",
+ "\n",
+ " odometry_measurement_2 = gtsam.Pose2(0.47, 0.03, 0.01)\n",
+ " odometry_noise_2 = gtsam.noiseModel.Diagonal.Sigmas(\n",
+ " np.array([0.05, 0.05, 0.05]))\n",
+ " new_factors.push_back(gtsam.BetweenFactorPose2(\n",
+ " previous_key, current_key, odometry_measurement_2, odometry_noise_2\n",
+ " ))\n",
+ "\n",
+ " # Update the smoothers with the new factors. In this case,\n",
+ " # one iteration must pass for Levenberg-Marquardt to accurately\n",
+ " # estimate\n",
+ " if time >= 0.50:\n",
+ " smoother_batch.update(new_factors, new_values, new_timestamps)\n",
+ " print(\"Timestamp = \" + str(time) + \", Key = \" + str(current_key))\n",
+ " print(smoother_batch.calculateEstimatePose2(current_key))\n",
+ "\n",
+ " new_timestamps.clear()\n",
+ " new_values.clear()\n",
+ " new_factors.resize(0)\n",
+ "\n",
+ " time += delta_time"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "e39b6a7b",
+ "metadata": {},
+ "source": [
+ "## 4. What's kept in the window\n",
+ "\n",
+ "`smoother_batch.timestamps()` returns the key-to-timestamp map for every variable *currently* in the smoother. After 3 seconds have passed with a 2-second lag, pose `0` (timestamp `0.0`) should be long gone -- marginalized out, not just cosmetically hidden."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 6,
+ "id": "07f8a651",
+ "metadata": {
+ "execution": {
+ "iopub.execute_input": "2026-07-22T10:34:49.221672Z",
+ "iopub.status.busy": "2026-07-22T10:34:49.221622Z",
+ "iopub.status.idle": "2026-07-22T10:34:49.223375Z",
+ "shell.execute_reply": "2026-07-22T10:34:49.223009Z"
+ }
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Key: 1000 Time: 1.0\n",
+ "Key: 1250 Time: 1.25\n",
+ "Key: 1500 Time: 1.5\n",
+ "Key: 1750 Time: 1.75\n",
+ "Key: 2000 Time: 2.0\n",
+ "Key: 2250 Time: 2.25\n",
+ "Key: 2500 Time: 2.5\n",
+ "Key: 2750 Time: 2.75\n",
+ "Key: 3000 Time: 3.0\n"
+ ]
+ }
+ ],
+ "source": [
+ "remaining = smoother_batch.timestamps()\n",
+ "for key, t in sorted(remaining.items(), key=lambda kv: kv[1]):\n",
+ " print(f\"Key: {key} Time: {t}\")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "6b46f14e",
+ "metadata": {},
+ "source": [
+ "Only the poses from the last ~2 seconds remain; pose `0` and the earliest handful of poses are no longer part of the problem at all. This bounded-memory property is exactly why fixed-lag smoothing -- and its incremental, iSAM2-based cousin -- is the tool of choice for real-time or long-duration SLAM, where a robot cannot afford to keep re-optimizing its entire history forever."
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.13.12"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
\ No newline at end of file
diff --git a/python/gtsam/examples/FixedLagSmootherExample.py b/python/gtsam/examples/FixedLagSmootherExample.py
deleted file mode 100644
index c56ebbe075..0000000000
--- a/python/gtsam/examples/FixedLagSmootherExample.py
+++ /dev/null
@@ -1,93 +0,0 @@
-"""
-GTSAM Copyright 2010-2018, Georgia Tech Research Corporation,
-Atlanta, Georgia 30332-0415
-All Rights Reserved
-Authors: Frank Dellaert, et al. (see THANKS for the full author list)
-
-See LICENSE for the license information
-
-Demonstration of the fixed-lag smoothers using a planar robot example
-and multiple odometry-like sensors
-Author: Frank Dellaert (C++), Jeremy Aguilon (Python)
-"""
-
-import numpy as np
-
-import gtsam
-import gtsam_unstable
-
-
-def BatchFixedLagSmootherExample():
- """
- Runs a batch fixed smoother on an agent with two odometry
- sensors that is simply moving to the
- """
-
- # Define a batch fixed lag smoother, which uses
- # Levenberg-Marquardt to perform the nonlinear optimization
- lag = 2.0
- smoother_batch = gtsam.BatchFixedLagSmoother(lag)
-
- # Create containers to store the factors and linearization points
- # that will be sent to the smoothers
- new_factors = gtsam.NonlinearFactorGraph()
- new_values = gtsam.Values()
- new_timestamps = {}
-
- # Create a prior on the first pose, placing it at the origin
- prior_mean = gtsam.Pose2(0, 0, 0)
- prior_noise = gtsam.noiseModel.Diagonal.Sigmas(np.array([0.3, 0.3, 0.1]))
- X1 = 0
- new_factors.push_back(gtsam.PriorFactorPose2(X1, prior_mean, prior_noise))
- new_values.insert(X1, prior_mean)
- new_timestamps[X1] = 0.0
-
- delta_time = 0.25
- time = 0.25
-
- while time <= 3.0:
- previous_key = int(1000 * (time - delta_time))
- current_key = int(1000 * time)
-
- # assign current key to the current timestamp
- new_timestamps[current_key] = time
-
- # Add a guess for this pose to the new values
- # Assume that the robot moves at 2 m/s. Position is time[s] * 2[m/s]
- current_pose = gtsam.Pose2(time * 2, 0, 0)
- new_values.insert(current_key, current_pose)
-
- # Add odometry factors from two different sources with different error
- # stats
- odometry_measurement_1 = gtsam.Pose2(0.61, -0.08, 0.02)
- odometry_noise_1 = gtsam.noiseModel.Diagonal.Sigmas(
- np.array([0.1, 0.1, 0.05]))
- new_factors.push_back(gtsam.BetweenFactorPose2(
- previous_key, current_key, odometry_measurement_1, odometry_noise_1
- ))
-
- odometry_measurement_2 = gtsam.Pose2(0.47, 0.03, 0.01)
- odometry_noise_2 = gtsam.noiseModel.Diagonal.Sigmas(
- np.array([0.05, 0.05, 0.05]))
- new_factors.push_back(gtsam.BetweenFactorPose2(
- previous_key, current_key, odometry_measurement_2, odometry_noise_2
- ))
-
- # Update the smoothers with the new factors. In this case,
- # one iteration must pass for Levenberg-Marquardt to accurately
- # estimate
- if time >= 0.50:
- smoother_batch.update(new_factors, new_values, new_timestamps)
- print("Timestamp = " + str(time) + ", Key = " + str(current_key))
- print(smoother_batch.calculateEstimatePose2(current_key))
-
- new_timestamps.clear()
- new_values.clear()
- new_factors.resize(0)
-
- time += delta_time
-
-
-if __name__ == '__main__':
- BatchFixedLagSmootherExample()
- print("Example complete")
diff --git a/python/gtsam/examples/GPSFactorExample.ipynb b/python/gtsam/examples/GPSFactorExample.ipynb
new file mode 100644
index 0000000000..ecebe45055
--- /dev/null
+++ b/python/gtsam/examples/GPSFactorExample.ipynb
@@ -0,0 +1,297 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "8ff62160",
+ "metadata": {},
+ "source": [
+ "# GPS Factor Example\n",
+ "\n",
+ "A `GPSFactor` ties a 3D position measurement -- for example, a reading from a GPS receiver -- to a `Pose3` variable in a factor graph. Because GPS only observes *position*, a single `GPSFactor` constrains the translation part of a pose but says nothing about orientation.\n",
+ "\n",
+ "This notebook builds the smallest possible example of that idea: one pose, one prior, one GPS measurement. We optimize with Levenberg-Marquardt and see the pose's position pulled toward the GPS reading while its orientation is left to the prior."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "8b9fc902",
+ "metadata": {},
+ "source": [
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "0743d96e",
+ "metadata": {},
+ "source": [
+ "GTSAM Copyright 2010-2026, Georgia Tech Research Corporation,\n",
+ "Atlanta, Georgia 30332-0415\n",
+ "All Rights Reserved\n",
+ "\n",
+ "Authors: Mandy Xie, Frank Dellaert, et al. (see THANKS for the full author list)\n",
+ "\n",
+ "See LICENSE for the license information"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "187215bf",
+ "metadata": {
+ "execution": {
+ "iopub.execute_input": "2026-07-22T06:45:29.202190Z",
+ "iopub.status.busy": "2026-07-22T06:45:29.201991Z",
+ "iopub.status.idle": "2026-07-22T06:45:29.207427Z",
+ "shell.execute_reply": "2026-07-22T06:45:29.206832Z"
+ }
+ },
+ "outputs": [],
+ "source": [
+ "try:\n",
+ " import google.colab\n",
+ " %pip install --quiet gtsam-develop\n",
+ "except ImportError:\n",
+ " pass"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "id": "4542290d",
+ "metadata": {
+ "execution": {
+ "iopub.execute_input": "2026-07-22T06:45:29.210037Z",
+ "iopub.status.busy": "2026-07-22T06:45:29.209742Z",
+ "iopub.status.idle": "2026-07-22T06:45:29.379469Z",
+ "shell.execute_reply": "2026-07-22T06:45:29.378994Z"
+ }
+ },
+ "outputs": [],
+ "source": [
+ "import gtsam"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "5c47d312",
+ "metadata": {},
+ "source": [
+ "## 1. Set up the problem\n",
+ "\n",
+ "`lat0`, `lon0`, `h0` play the role of a single GPS reading -- the ENU origin where the plane was in hold next to the runway. We use two noise models:\n",
+ "\n",
+ "- `GPS_NOISE` is 3-dimensional, since a GPS measurement only observes `x, y, z` position.\n",
+ "- `PRIOR_NOISE` is 6-dimensional, since the prior constrains the full `Pose3` (position **and** orientation)."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "id": "01cc459d",
+ "metadata": {
+ "execution": {
+ "iopub.execute_input": "2026-07-22T06:45:29.380650Z",
+ "iopub.status.busy": "2026-07-22T06:45:29.380575Z",
+ "iopub.status.idle": "2026-07-22T06:45:29.382232Z",
+ "shell.execute_reply": "2026-07-22T06:45:29.381959Z"
+ }
+ },
+ "outputs": [],
+ "source": [
+ "# ENU origin is where the plane was in hold next to runway\n",
+ "lat0 = 33.86998\n",
+ "lon0 = -84.30626\n",
+ "h0 = 274\n",
+ "\n",
+ "GPS_NOISE = gtsam.noiseModel.Isotropic.Sigma(3, 0.1)\n",
+ "PRIOR_NOISE = gtsam.noiseModel.Isotropic.Sigma(6, 0.25)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "4731cba9",
+ "metadata": {},
+ "source": [
+ "## 2. Build the factor graph\n",
+ "\n",
+ "The `PriorFactorPose3` anchors pose key `1` at the identity pose -- deliberately different from the GPS reading, so the optimizer has real work to do. The `GPSFactor` then adds the position-only measurement on the same key."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "id": "f44b9f95",
+ "metadata": {
+ "execution": {
+ "iopub.execute_input": "2026-07-22T06:45:29.383128Z",
+ "iopub.status.busy": "2026-07-22T06:45:29.383075Z",
+ "iopub.status.idle": "2026-07-22T06:45:29.385061Z",
+ "shell.execute_reply": "2026-07-22T06:45:29.384801Z"
+ }
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "NonlinearFactorGraph: size: 2\n",
+ "\n",
+ "Factor 0: PriorFactor on 1\n",
+ " prior mean: R: [\n",
+ "\t1, 0, 0;\n",
+ "\t0, 1, 0;\n",
+ "\t0, 0, 1\n",
+ "]\n",
+ "t: 0 0 0\n",
+ "isotropic dim=6 sigma=0.25\n",
+ "\n",
+ "Factor 1: GPSFactor on 1\n",
+ " GPS measurement: 33.87\n",
+ "-84.3063\n",
+ " 274\n",
+ "isotropic dim=3 sigma=0.1\n",
+ "\n",
+ "\n"
+ ]
+ }
+ ],
+ "source": [
+ "graph = gtsam.NonlinearFactorGraph()\n",
+ "\n",
+ "# Add a prior on the first pose, setting it to the origin\n",
+ "# A prior factor consists of a mean and a noise model (covariance matrix)\n",
+ "priorMean = gtsam.Pose3() # prior at origin\n",
+ "graph.add(gtsam.PriorFactorPose3(1, priorMean, PRIOR_NOISE))\n",
+ "\n",
+ "# Add the GPS factor\n",
+ "gps = gtsam.Point3(lat0, lon0, h0)\n",
+ "graph.add(gtsam.GPSFactor(1, gps, GPS_NOISE))\n",
+ "\n",
+ "print(graph)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "addfae54",
+ "metadata": {},
+ "source": [
+ "## 3. Initial estimate\n",
+ "\n",
+ "For illustrative purposes, the initial estimate is deliberately set to the identity pose -- far from the GPS reading -- so we can watch the optimizer correct it."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "id": "5d2b7077",
+ "metadata": {
+ "execution": {
+ "iopub.execute_input": "2026-07-22T06:45:29.385929Z",
+ "iopub.status.busy": "2026-07-22T06:45:29.385861Z",
+ "iopub.status.idle": "2026-07-22T06:45:29.387422Z",
+ "shell.execute_reply": "2026-07-22T06:45:29.387162Z"
+ }
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Values with 1 values:\n",
+ "Value 1: (gtsam::Pose3)\n",
+ "R: [\n",
+ "\t1, 0, 0;\n",
+ "\t0, 1, 0;\n",
+ "\t0, 0, 1\n",
+ "]\n",
+ "t: 0 0 0\n",
+ "\n",
+ "\n"
+ ]
+ }
+ ],
+ "source": [
+ "initial = gtsam.Values()\n",
+ "initial.insert(1, gtsam.Pose3())\n",
+ "print(initial)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "af9a467a",
+ "metadata": {},
+ "source": [
+ "## 4. Optimize\n",
+ "\n",
+ "We solve with `LevenbergMarquardtOptimizer`, the general-purpose nonlinear least-squares solver used throughout GTSAM."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 6,
+ "id": "622dc9e0",
+ "metadata": {
+ "execution": {
+ "iopub.execute_input": "2026-07-22T06:45:29.388363Z",
+ "iopub.status.busy": "2026-07-22T06:45:29.388295Z",
+ "iopub.status.idle": "2026-07-22T06:45:29.392325Z",
+ "shell.execute_reply": "2026-07-22T06:45:29.391993Z"
+ }
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Values with 1 values:\n",
+ "Value 1: (gtsam::Pose3)\n",
+ "R: [\n",
+ "\t1, 0, 0;\n",
+ "\t0, 1, 0;\n",
+ "\t0, 0, 1\n",
+ "]\n",
+ "t: 29.1983 -72.6778 236.207\n",
+ "\n",
+ "\n"
+ ]
+ }
+ ],
+ "source": [
+ "params = gtsam.LevenbergMarquardtParams()\n",
+ "optimizer = gtsam.LevenbergMarquardtOptimizer(graph, initial, params)\n",
+ "result = optimizer.optimize()\n",
+ "print(result)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "41543a4f",
+ "metadata": {},
+ "source": [
+ "Notice that the optimized translation lands close to, but not exactly at, the GPS reading `(lat0, lon0, h0)`. It's a noise-weighted compromise between the two factors: the prior pulls it toward `(0, 0, 0)` with `sigma=0.25`, while the GPS factor pulls it toward the measurement with a tighter `sigma=0.1`, so the tighter (more confident) factor dominates. The rotation, meanwhile, stays exactly at the prior's identity value -- a single `GPSFactor` has no way to observe orientation from one position measurement. That information has to come from somewhere else (multiple GPS readings over time, an IMU, a compass, etc.)."
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.13.12"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/python/gtsam/examples/GPSFactorExample.py b/python/gtsam/examples/GPSFactorExample.py
deleted file mode 100644
index 8eb663cb4c..0000000000
--- a/python/gtsam/examples/GPSFactorExample.py
+++ /dev/null
@@ -1,57 +0,0 @@
-"""
-GTSAM Copyright 2010-2018, Georgia Tech Research Corporation,
-Atlanta, Georgia 30332-0415
-All Rights Reserved
-Authors: Frank Dellaert, et al. (see THANKS for the full author list)
-
-See LICENSE for the license information
-
-Simple robot motion example, with prior and one GPS measurements
-Author: Mandy Xie
-"""
-# pylint: disable=invalid-name, E1101
-
-from __future__ import print_function
-
-import gtsam
-
-# ENU Origin is where the plane was in hold next to runway
-lat0 = 33.86998
-lon0 = -84.30626
-h0 = 274
-
-# Create noise models
-GPS_NOISE = gtsam.noiseModel.Isotropic.Sigma(3, 0.1)
-PRIOR_NOISE = gtsam.noiseModel.Isotropic.Sigma(6, 0.25)
-
-
-def main():
- """Main runner."""
- # Create an empty nonlinear factor graph
- graph = gtsam.NonlinearFactorGraph()
-
- # Add a prior on the first point, setting it to the origin
- # A prior factor consists of a mean and a noise model (covariance matrix)
- priorMean = gtsam.Pose3() # prior at origin
- graph.add(gtsam.PriorFactorPose3(1, priorMean, PRIOR_NOISE))
-
- # Add GPS factors
- gps = gtsam.Point3(lat0, lon0, h0)
- graph.add(gtsam.GPSFactor(1, gps, GPS_NOISE))
- print("\nFactor Graph:\n{}".format(graph))
-
- # Create the data structure to hold the initialEstimate estimate to the solution
- # For illustrative purposes, these have been deliberately set to incorrect values
- initial = gtsam.Values()
- initial.insert(1, gtsam.Pose3())
- print("\nInitial Estimate:\n{}".format(initial))
-
- # optimize using Levenberg-Marquardt optimization
- params = gtsam.LevenbergMarquardtParams()
- optimizer = gtsam.LevenbergMarquardtOptimizer(graph, initial, params)
- result = optimizer.optimize()
- print("\nFinal Result:\n{}".format(result))
-
-
-if __name__ == "__main__":
- main()
diff --git a/python/gtsam/examples/OdometryExample.ipynb b/python/gtsam/examples/OdometryExample.ipynb
new file mode 100644
index 0000000000..3c0254b4c4
--- /dev/null
+++ b/python/gtsam/examples/OdometryExample.ipynb
@@ -0,0 +1,389 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "45df6316",
+ "metadata": {},
+ "source": [
+ "# Odometry Example\n",
+ "\n",
+ "GTSAM models estimation problems as **factor graphs**: a bipartite graph of *variables* (things we want to estimate) and *factors* (measurement constraints between them). This notebook builds the smallest interesting factor graph -- a robot driving in a straight line -- and is a good first look at what a factor graph actually is.\n",
+ "\n",
+ "- **Variables**: three `Pose2` robot poses `(x, y, \\theta)`, at times 1, 2, 3.\n",
+ "- **Factors**: a `PriorFactor` anchoring the first pose at the origin, and two `BetweenFactor`s encoding noisy odometry -- \"the robot believes it moved 2 meters forward\" -- between consecutive poses.\n",
+ "\n",
+ "We build the graph, optimize it with Levenberg-Marquardt, and then look at the marginal covariances to see how uncertainty accumulates as the robot drives."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "1b8dac26",
+ "metadata": {},
+ "source": [
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "c09df7cc",
+ "metadata": {},
+ "source": [
+ "GTSAM Copyright 2010-2026, Georgia Tech Research Corporation,\n",
+ "Atlanta, Georgia 30332-0415\n",
+ "All Rights Reserved\n",
+ "\n",
+ "Authors: Frank Dellaert, et al. (see THANKS for the full author list)\n",
+ "\n",
+ "See LICENSE for the license information"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "eba10674",
+ "metadata": {
+ "execution": {
+ "iopub.execute_input": "2026-07-22T10:15:29.253772Z",
+ "iopub.status.busy": "2026-07-22T10:15:29.253565Z",
+ "iopub.status.idle": "2026-07-22T10:15:29.259282Z",
+ "shell.execute_reply": "2026-07-22T10:15:29.258576Z"
+ }
+ },
+ "outputs": [],
+ "source": [
+ "try:\n",
+ " import google.colab\n",
+ " %pip install --quiet gtsam-develop\n",
+ "except ImportError:\n",
+ " pass"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "id": "5fd0279f",
+ "metadata": {
+ "execution": {
+ "iopub.execute_input": "2026-07-22T10:15:29.261282Z",
+ "iopub.status.busy": "2026-07-22T10:15:29.261126Z",
+ "iopub.status.idle": "2026-07-22T10:15:29.615820Z",
+ "shell.execute_reply": "2026-07-22T10:15:29.615354Z"
+ }
+ },
+ "outputs": [],
+ "source": [
+ "import gtsam\n",
+ "import gtsam.utils.plot as gtsam_plot\n",
+ "import matplotlib.pyplot as plt\n",
+ "import numpy as np"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "885e3afb",
+ "metadata": {},
+ "source": [
+ "## 1. Noise models\n",
+ "\n",
+ "Both factors below use `noiseModel.Diagonal.Sigmas`, which lets us give each dimension of a `Pose2` -- `x`, `y`, `\\theta` -- its own standard deviation, unlike the `Isotropic` model (a single sigma for every dimension) used in the GPS factor example. Here we trust `\\theta` more than `x`/`y`, since the robot's odometry is better at tracking heading than position."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "id": "7e1a111b",
+ "metadata": {
+ "execution": {
+ "iopub.execute_input": "2026-07-22T10:15:29.617343Z",
+ "iopub.status.busy": "2026-07-22T10:15:29.617246Z",
+ "iopub.status.idle": "2026-07-22T10:15:29.619097Z",
+ "shell.execute_reply": "2026-07-22T10:15:29.618806Z"
+ }
+ },
+ "outputs": [],
+ "source": [
+ "ODOMETRY_NOISE = gtsam.noiseModel.Diagonal.Sigmas(np.array([0.2, 0.2, 0.1]))\n",
+ "PRIOR_NOISE = gtsam.noiseModel.Diagonal.Sigmas(np.array([0.3, 0.3, 0.1]))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "d7686f23",
+ "metadata": {},
+ "source": [
+ "## 2. Build the factor graph\n",
+ "\n",
+ "The `PriorFactorPose2` pins pose `1` at the origin -- without it, the whole chain of poses could float anywhere, since odometry only measures *relative* motion. Each `BetweenFactorPose2` then says \"the robot believes it moved this `Pose2` -- 2 meters forward, no turn -- between these two poses.\" We reuse the same odometry measurement and noise model for both steps, since the robot drives the same way twice."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "id": "3b892842",
+ "metadata": {
+ "execution": {
+ "iopub.execute_input": "2026-07-22T10:15:29.620048Z",
+ "iopub.status.busy": "2026-07-22T10:15:29.619985Z",
+ "iopub.status.idle": "2026-07-22T10:15:29.622666Z",
+ "shell.execute_reply": "2026-07-22T10:15:29.622334Z"
+ }
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "NonlinearFactorGraph: size: 3\n",
+ "\n",
+ "Factor 0: PriorFactor on 1\n",
+ " prior mean: (0, 0, 0)\n",
+ " noise model: diagonal sigmas [0.3; 0.3; 0.1];\n",
+ "\n",
+ "Factor 1: BetweenFactor(1,2)\n",
+ " measured: (2, 0, 0)\n",
+ " noise model: diagonal sigmas [0.2; 0.2; 0.1];\n",
+ "\n",
+ "Factor 2: BetweenFactor(2,3)\n",
+ " measured: (2, 0, 0)\n",
+ " noise model: diagonal sigmas [0.2; 0.2; 0.1];\n",
+ "\n",
+ "\n"
+ ]
+ }
+ ],
+ "source": [
+ "graph = gtsam.NonlinearFactorGraph()\n",
+ "\n",
+ "# Add a prior on the first pose, setting it to the origin\n",
+ "# A prior factor consists of a mean and a noise model (covariance matrix)\n",
+ "priorMean = gtsam.Pose2(0.0, 0.0, 0.0) # prior at origin\n",
+ "graph.add(gtsam.PriorFactorPose2(1, priorMean, PRIOR_NOISE))\n",
+ "\n",
+ "# Add odometry factors\n",
+ "odometry = gtsam.Pose2(2.0, 0.0, 0.0)\n",
+ "# For simplicity, we will use the same noise model for each odometry factor\n",
+ "# Create odometry (Between) factors between consecutive poses\n",
+ "graph.add(gtsam.BetweenFactorPose2(1, 2, odometry, ODOMETRY_NOISE))\n",
+ "graph.add(gtsam.BetweenFactorPose2(2, 3, odometry, ODOMETRY_NOISE))\n",
+ "\n",
+ "print(graph)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "adeabdb2",
+ "metadata": {},
+ "source": [
+ "## 3. Initial estimate\n",
+ "\n",
+ "For illustrative purposes, the initial estimate for each pose is deliberately set to noisy, imprecise values -- not the origin, and not exactly 2 meters apart -- so the optimizer has real work to do."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "id": "a6817f6f",
+ "metadata": {
+ "execution": {
+ "iopub.execute_input": "2026-07-22T10:15:29.623581Z",
+ "iopub.status.busy": "2026-07-22T10:15:29.623523Z",
+ "iopub.status.idle": "2026-07-22T10:15:29.625177Z",
+ "shell.execute_reply": "2026-07-22T10:15:29.624858Z"
+ }
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Values with 3 values:\n",
+ "Value 1: (gtsam::Pose2)\n",
+ "(0.5, 0, 0.2)\n",
+ "\n",
+ "Value 2: (gtsam::Pose2)\n",
+ "(2.3, 0.1, -0.2)\n",
+ "\n",
+ "Value 3: (gtsam::Pose2)\n",
+ "(4.1, 0.1, 0.1)\n",
+ "\n",
+ "\n"
+ ]
+ }
+ ],
+ "source": [
+ "initial = gtsam.Values()\n",
+ "initial.insert(1, gtsam.Pose2(0.5, 0.0, 0.2))\n",
+ "initial.insert(2, gtsam.Pose2(2.3, 0.1, -0.2))\n",
+ "initial.insert(3, gtsam.Pose2(4.1, 0.1, 0.1))\n",
+ "print(initial)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "ae39f901",
+ "metadata": {},
+ "source": [
+ "## 4. Optimize\n",
+ "\n",
+ "As in the GPS factor example, we solve with `LevenbergMarquardtOptimizer`."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 6,
+ "id": "ffa74816",
+ "metadata": {
+ "execution": {
+ "iopub.execute_input": "2026-07-22T10:15:29.626000Z",
+ "iopub.status.busy": "2026-07-22T10:15:29.625940Z",
+ "iopub.status.idle": "2026-07-22T10:15:29.631697Z",
+ "shell.execute_reply": "2026-07-22T10:15:29.631332Z"
+ }
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Values with 3 values:\n",
+ "Value 1: (gtsam::Pose2)\n",
+ "(7.46978315e-16, -5.34409096e-16, -1.78381863e-16)\n",
+ "\n",
+ "Value 2: (gtsam::Pose2)\n",
+ "(2, -1.09236636e-15, -2.48671179e-16)\n",
+ "\n",
+ "Value 3: (gtsam::Pose2)\n",
+ "(4, -1.70076056e-15, -2.50943863e-16)\n",
+ "\n",
+ "\n"
+ ]
+ }
+ ],
+ "source": [
+ "params = gtsam.LevenbergMarquardtParams()\n",
+ "optimizer = gtsam.LevenbergMarquardtOptimizer(graph, initial, params)\n",
+ "result = optimizer.optimize()\n",
+ "print(result)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "d1b430ae",
+ "metadata": {},
+ "source": [
+ "## 5. Marginal covariances\n",
+ "\n",
+ "Beyond the best-estimate poses, GTSAM can also compute the **marginal covariance** of each variable -- how uncertain we are about it, given every factor in the graph. We'd expect pose 1 to be tightly constrained by its prior, and the uncertainty to grow for poses 2 and 3 as odometry noise accumulates along the direction of travel."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "id": "9f66573b",
+ "metadata": {
+ "execution": {
+ "iopub.execute_input": "2026-07-22T10:15:29.632565Z",
+ "iopub.status.busy": "2026-07-22T10:15:29.632505Z",
+ "iopub.status.idle": "2026-07-22T10:15:29.634945Z",
+ "shell.execute_reply": "2026-07-22T10:15:29.634682Z"
+ }
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "X1 covariance:\n",
+ "[[9.00000000e-02 2.92775369e-33 3.54987407e-33]\n",
+ " [2.92775369e-33 9.00000000e-02 2.55795385e-17]\n",
+ " [3.54987407e-33 2.55795385e-17 1.00000000e-02]]\n",
+ "\n",
+ "X2 covariance:\n",
+ "[[1.30000000e-01 1.21229810e-18 6.06149052e-19]\n",
+ " [1.21229810e-18 1.70000000e-01 2.00000000e-02]\n",
+ " [6.06149052e-19 2.00000000e-02 2.00000000e-02]]\n",
+ "\n",
+ "X3 covariance:\n",
+ "[[1.70000000e-01 8.63317033e-18 2.69082498e-18]\n",
+ " [8.63317033e-18 3.70000000e-01 6.00000000e-02]\n",
+ " [2.69082498e-18 6.00000000e-02 3.00000000e-02]]\n",
+ "\n"
+ ]
+ }
+ ],
+ "source": [
+ "marginals = gtsam.Marginals(graph, result)\n",
+ "for i in range(1, 4):\n",
+ " print(\"X{} covariance:\\n{}\\n\".format(i, marginals.marginalCovariance(i)))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "789733f9",
+ "metadata": {},
+ "source": [
+ "## 6. Visualize\n",
+ "\n",
+ "`gtsam.utils.plot.plot_pose2` draws each pose as an axis triad together with a covariance ellipse, so we can see the growing uncertainty directly instead of just reading numbers."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 8,
+ "id": "de5832e4",
+ "metadata": {
+ "execution": {
+ "iopub.execute_input": "2026-07-22T10:15:29.635825Z",
+ "iopub.status.busy": "2026-07-22T10:15:29.635770Z",
+ "iopub.status.idle": "2026-07-22T10:15:29.685041Z",
+ "shell.execute_reply": "2026-07-22T10:15:29.684697Z"
+ }
+ },
+ "outputs": [
+ {
+ "data": {
+ "image/png": "iVBORw0KGgoAAAANSUhEUgAAAjYAAAGxCAYAAABx6/zIAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjExLjEsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvctoD+AAAAAlwSFlzAAAPYQAAD2EBqD+naQAAUpVJREFUeJzt3Qd4VGWzB/AJvQakgzQpUgQ+qiIdpEhXRBBpSpcOon50FBSlSRNQlCJFkKYC0nuV3nsPvRNqCMne5z/3bm5AElJ297T/73nWAAI5nJzsmTPvvDN+LpfLJUREREQ2EMfoAyAiIiLyFAY2REREZBsMbIiIiMg2GNgQERGRbTCwISIiIttgYENERES2wcCGiIiIbIOBDREREdlGPHGY0NBQuXjxoiRPnlz8/PyMPhwiIiKKAvQTvnv3rmTKlEnixIk4L+O4wAZBTZYsWYw+DCIiIoqBgIAAyZw5c4T/33GBDTI17hPj7+9v9OEQERFRFAQGBmpiwn0fj4jjAhv38hOCGgY2RERE1vKiMhIWDxMREZFtMLAhIiIi22BgQ0RERLbBwIaIiIhsg4ENERER2QYDGyIiIrINBjZERERkGwxsiIiIyDYY2BAREZFtMLAhIiIi22BgQ0RERLbBwIaIiIhsg4ENERER2QYDGyIiIrINBjZERERkGwxsiIiIyDYY2BAREZFtMLAhIiIi22BgQ0RERLZhycAmNDTU6EMgIiIiE7JUYLN48WKpWLGi+Pv7S7JkyaRatWpy4MABow+LiIiITMIygU1ISIiMHz9eBgwYINeuXZOAgABJlSqVVK1aVe7cuWP04REREZEJ+LlcLpdY1Pnz5yVLliyybNkyDXCiIjAwUFKkSKHBEDI/REREZH5RvX9bJmPzPBcuXNCPqVOnNvpQiIiIyATiiUU9fvxYunTpIiVLlpSiRYtG+PuCgoL0FT7iIyIiInuyZMYG9TZNmjSRixcvyuzZs8XPzy/C3zt48GBNXblfWLoiIiIie7JcjQ2CmmbNmsm6dev0lTNnzkh///MyNghuWGNDRERkvxqbeFbrX9O8eXMNaNauXfvCoAYSJkyoLyIiIrI/ywQ2SCy1aNFCVqxYobugMmTIIPfu3dP/lyhRIokXzzL/FCIiInJ6jc3Nmzdl7ty5cv/+fSlTpowGNu7XjBkzjD48IiIiMgHLpDmwpdudoSEiIiKydMaGiIiI6EUY2BAREZFtMLAhIiIi22BgQ0RERLbBwIaIiIhsg4ENERER2QYDGyIiIrINBjZERERkGwxsiIiIyDYY2BAREZFtMLAhIiIi22BgQ0RERLbBwIaIiIhsg4ENERER2QYDGyIiIrINBjZERERkGwxsiIiIyDYY2BAREZFtMLAhIiIi22BgQ0RERLbBwIaIiIhsg4ENERER2QYDGyIiIrINBjZERERkGwxsiIiIyDYY2BAREZFtMLAhIiIi22BgQ0RERLbBwIaIiIhsg4ENERER2QYDGyIiIrINBjZERERkGwxsiIiIyDbiGX0AREREvvL48WM5deqUHD9+XI4dO6Yf8bp586b+P/crTpw4kiBBAn0lTJhQMmXKJK+++qq+cufOrR/xa35+fvzimQwDGyIisqXQ0FDZtWuXLFq0SP755x8NZM6cOaO/DkmSJNEgBa+8efOGBTHx48cXl8ulAU5QUJA8evRIAgIC5I8//tA/HxIS8tSfz5Mnj1SqVElq1qwpmTNnNvhfTX4ufPUcJDAwUFKkSCF37twRf39/ow+HiIg86O7du7JixQpZvHix/P3333L58mV9zy9btqwGL+5sCz7GJOOCYOf06dNPZXz2798vW7du1YCncOHCGuDUqlVLSpQoIXHjxuXX18f3bwY2RERkabdu3ZLp06fLwoULZe3atRIcHCz58uULCzBKlSqlWRhvH8OyZcvCAiosbaVJk0aqV68u7733nh4Hg5zYYWATyxNDRETmdvLkSRk5cqRMmjRJg5mKFStqAIGAJkeOHIYdFzI3WPrCEhheyOjkzJlTunbtKh999JEkS5bMsGOzMgY2sTwxRERkTps3b5bhw4fLggULJHXq1NK+fXt9pU+fXsxox44derxz5szR+07btm2lU6dOuhRGnr9/c7s3ERGZ3pMnTzQwePPNN6V06dJy8OBBGT9+vJw7d06+/PJL0wY1ULx4cfntt990N1aLFi3khx9+kOzZs0uzZs1kz549Rh+e7TCwISIiU9u0aZMULVpUGjRoIIkSJdJamkOHDmnmI3HixGIVWbNmlWHDhsn58+fl22+/lXXr1kmRIkWkadOmcuXKFaMPzzYY2BARkSldv35dWrZsKWXKlNGABnUra9as0Toa9JmxKiyjdO/eXWuEfv75Z1myZIluGR83blzYVnKKOeteGUREZEvoM4MbPm728+fP1yWnLVu2yOuvvy52Ei9ePA3cjh49Ku+//7506NBBl9p27txp9KFZGgMbIiIyjb1792qGpnXr1lK7dm296bdr187WW6VRAD1x4kQtikafHPS/6dixo9y+fdvoQ7MkBjZERGSK4uCePXtKsWLFdNcL6k+mTJki6dKlE6dAtgY7qEaMGCFTp07VhoLoi0PRw8CGiIgMdfXqValataoMHTpUBg4cqDuFypUr58ivCpan0O/myJEjmrlBPRF2fbnHQNCLcVYUEREZZtu2bdqZF0swq1atkvLly/OrISIvv/yy/PnnnzJ48GDp27evbN++XaZNmyYvvfQSz88LMGNDRESGQF0JZjhhcCSGVTKoeRp2fvXu3VtHNKD+Bhmcffv28Wp9AQY2RETkU5iWjeLgNm3a6K4gzHdChoKe7+2339bam+TJk0vJkiVl5syZPFWRYGBDREQ+g+Z0qJ/BssrkyZO1d0vChAn5FXgBzL5Co8L69etL48aNtQ4HBdf0b6yxISIin8BIgUqVKonL5dKbNHZAUdQlSZJEd0uhn0+3bt3k0qVLOtXc25PLrYYZGyIi8roTJ05IhQoV9CbMoCbm/Pz8tMcN5mZhCGijRo208Jr+HwMbIiLyqmPHjmlQg7lO6E+DYmGKnXfeeUfmzZunc7MwQ4vBzf9jYENERF6DfiwIajAfCUXCmTJl4tn2EHRmRtZm6dKlumU+KCiI55aBDRERecvBgwc1qMHIAAyvzJgxI0+2h9WoUUP73axcuVLeffdd3XHmdMzYEBGRx+3fv18qVqwo6dOnl9WrV+tH8o5q1arpkhQyYnXr1pWHDx86+lQzsCEiIq/sfkJvGgQ1adOm5Rn2ssqVK+tcqY0bN+qyVEhIiGPPOQMbIiLymMDAQK39SJEihS6PYBmKfAMZsgULFsjy5cvl888/d+xpZ2BDREQegSwBmsehCR+WRhjU+F7VqlXl+++/1wnhkyZNEidigz4iIvKIXr166VyjRYsWSb58+XhWDdKxY0c5cOCAtGvXTl599VUpU6aMo74WzNgQEVGs/frrrzJkyBAZNmyYVK9enWfU4CZ+Y8aMkVKlSkm9evXk7Nmzjvp6MLAhIqJY2bJliw61bNGihc4wIuMlSJBA5s6dK8mSJZM6derIvXv3xCkY2BARUYwFBARo/xTML8JAS2QLyBzSpEmjtU7Ypda0aVMJDQ0VJ2BgQ0REMYJmcOibguncaO/PKd3m89prr8lvv/2mTfwGDBggTsDAhoiIYqRnz55y6NAhvWmmS5eOZ9GkatWqJQMHDpRBgwbJ+vXrxe4Y2BARUbShR83IkSNl8ODBUrhwYZ5Bk/vvf/+ru6OaNWsmd+7cETtjYENERNFy8+ZN+eijj+Stt96SLl268OxZQNy4cXXnGr52nTt3FjuzXGCDGRhTpkzR6BMFUURE5Fvt27eX+/fv63txnDiWu404Vvbs2WXs2LEa4MyZM0fsylJX5NSpUyVnzpzyxx9/yHfffSfnzp0z+pCIiBwFRcKzZ8/WHVCZM2c2+nAompo2baqzpDp06CDXrl2z5fmLY7Xq7oMHD2rESUREvnXjxg29IWIn1AcffMDTb0F+fn7yww8/6PgLuy4jWmqkQvHixfUjUqBEZD8ul0trAK5cuSJBQUHy5MkTCQ4O1jfj+PHj6ytp0qQ6NTpx4sRGH67jdOvWTb8u7FdjbenTp5dRo0Zp9gYBKhr42YmlApuYwDchXuEnzxKRcdAk7MiRI7Jt2zY5ffq0NngL/3rw4EGUm49lyZLlqVfevHnlzTff5NZjL8AMqGnTpsnkyZMlU6ZM3vgU5EONGzeWWbNm6TypcuXKScqUKW1z/m0f2GAr4pdffmn0YRA5FjKs27dvl02bNsnmzZu1/f6tW7c0C5MhQwYNSLJmzSoFCxYMC1AyZsyozd6QoYkXL55mcpC5QQbn7t27Oj0aQRDq7PBx3bp1+tG9jTVXrlxSunRpnZWDjxjIyCLXmHv8+LHupKlcubI0b97cY9cGGcfPz08mTJig3xvob4MZX3bh58I7hsXgTQ1vfmvWrJEKFSpEO2ODP4s3QH9/fx8cLZHzXL16VXdd4Ilw69atGpDg+w3ZFHfA8cYbb+gcG09CcOMOoPBx7969WkuAp9GaNWtKo0aNpGrVqhowUdRh2aJ79+56PgsUKMBTZyODBg3S5n2HDx+WHDlyiJnh/p0iRYoX3r9tH9jE9MQQUfTge2rBggXavn3VqlX6RIggonbt2hrM5M+fX3tp+BIG/2HJC91WEWihS26qVKmkfv36GuQgBc9MTuSQXUMGDDtpfvrpJx995chXHjx4ILlz59bmfdjtZmZRvX9balcUEZkLnouwDISbHgoSMd0ZGVLsurh06ZIsXrxY1/CxzOTroAaQEapUqZLOyDlw4IBmHNq0aSPLly+XihUr6gPSF198IRcuXPD5sVnF119/rV/Tr776yuhDIS9IkiSJfo1///13XSa2A0tlbHbu3KlPXVhjR1U+nriwNo91X7yighkbotjD28aiRYu0hg1vhlie+Pjjj6Vhw4a6Y8kKx48lMmSX0KwMjT9RO/L5559rdoL+F5qgogajT58+0rdvX54WmwoJCZFixYrpjsONGzeadkK7LTM2CRIk0LVyPGXhDbVQoUL680SJEhl9aESOgFqZmTNnyn/+8x/dIoplHAQ4+/bt0xoMKwQ1gDdu1PuMHj1aC5BRY/DXX39Jnjx5dPsrMjsk0qtXL919hq8t2VfcuHG1eBi1afPnzxers1TGxhOYsSGKPrxNILuBp3Y8xb/99tt60ytbtqxtTqd7XMuQIUPkzJkzWmw8dOhQzVg4ETJaCP4mTZqk2Tiyvxo1asixY8e0Fg2JBLOxZcaGiHwPPWcw7BB9L5Al3bVrlyxZssRWQQ2g4d8nn3wix48fl+nTp8vRo0c1M4UALqq9dewUyPbo0UO/3pgGTc4wdOhQ7S01fvx4sTIGNkT0XLiZ9+7dW29uWK5BMINdT0WKFLH1GUPfHARx+/fv19qSESNG6I6uhQsXilPg64zt8sOHDzek6JuMG1vUqlUrLRTHbjirYmBDRP+Cuhm8yeHGhuAGO4qw/OQkqN3r16+f/tvR0Rg1RZiRdPbsWbF7tgY1R9HZlEH28eWXX2pTTStnbRjYEFEYvKFh6QG9Z1BIi5t6//79HV2gj11SyFbNnTtXd2Yie4PRAnaF/mB79uzRbfDkPBkyZNAdgmPGjHmqua2VMLAhIoXOo6+//rruisCNGzdzbn3+/11U6NWDc9SgQQMN/tAP59GjR7a7erA7BrVFqKsiZ+revbtcvnxZd0BaEQMbItI3sBIlSuiZwFynJk2amLaXhZGSJ0+uQyB/+eUXDf6wa+jkyZNiFwcPHtSA9tNPP+XX38Hy5MmjWVsEuVbcOM3AhsjBkHHATiAUy9arV0/HDzh1e3N0oMMytkNjZEPRokVt0fsDUCiNXkRotEjO1qNHD932vXTpUrEaBjZEDoWRB5gPgwwEZgBNnTpVO49S1GC5ZseOHVKlShVdpkJNihWfbsNfD9jm3qVLF1P2MCHfKlu2rGZxsYHAahjYEDkQGtDhjQvr6Og22rp1ay49xACahWHMC9780dgPW2XRnt6Kxo4dqwENrgUiPz8/XZLEQNvdu3db6oQwsCFyGBTAIlMDmAuDpRSK3Q0AxZaouUHWCyMZrLabxL29F0ENxtQQATKR2bJls1zWhoENkYNguzIyNalSpZINGzZI9uzZjT4k20DB9bx587SRH3reIFiwCixHol09lqGIwjer7Natm8yaNUsCAgLEKhjYEDnE+vXrpWLFipI7d25Zu3atZMyY0ehDsh008Pv777+1a2/VqlXl9u3bYnaoCxo1apS8//77+nRO9GyhPHYD/vDDD2IVDGyIHADr5NWqVdM+NStWrNCMDXlHpUqV9HxjyQ+BpNlb02/ZskVOnDghbdu2NfpQyISSJ08uH374oRaWW6V+jNO96Sl4wrx48aLukAj/Edtag4OD5cmTJ1pTED9+fH2lSZNGMmXKpE//eLl/nDBhQp5ZEy0/VahQQetqMAPIyV2EfQmzpnDeMZpi2bJlOmTTjLDdf/HixVpQHicOn3Xp+cFvqVKlNGBH4G726d4MbBwMQQtueu4Xtq7i18LDRYRABQWFWG/FQDykrhHgPH78WK5du6Z/Bj92w+9B2/lixYrpq3jx4ro11qxv7HaGJ/HSpUvLK6+8om9K3M7t+xsCOvgiW4aRDGYbKInvW7TQR7Zm8ODBRh8OmZTL5ZJXX301rD2EURjYxPLE2BF2amAOzF9//aVPaJjYDKlTpw4LQjDJOXPmzJp5wRtekiRJonTR37x5UwMcvE6dOiW7du3SYGnfvn2a6cEb+htvvKHdLFFYiSZw7GzrXdevX5eSJUtqQIrdT8iukTEDRd955x0NHrCl2kzX/R9//CHvvvuuzgRDZokosuGY6ER85cqVKN0XvIGBTSxPjF3cvXtXlx8QzCAdjiUlPL0jwChfvrwGM1mzZvXamy2CKbxpIhuEz4/XgwcPJGfOnBrg4E0VTwFmerO3A5x3NI47cuSI/PPPP/o1J+NMnDhRZ0uNHj1aOnXqZKrtvKdPn9YHEaIXZX+x8eC3337Tlgamvn+7HObOnTtoDaof7Wz//v2u9u3bu5IlS+by8/NzlSxZ0vX111/rr4eGhhp2XA8fPnQtXrzY1bZtW1emTJn0a5EvXz7XmDFjXLdv3zbsuOwEX99mzZq5EiZM6Nq0aZPRh0P/p3v37q44ceLo9W8GN2/edCVIkMA1YsQIow+FLOLNN9901ahRw/T3bwY2NvL48WPX7NmzXeXKldMvfvr06V19+/Z1nTt3zmXWG/Dq1atd9evXd8WNG9eVNGlSDXj27t1r9KFZ2tixY/XrP2PGDKMPhcJ58uSJq06dOi5/f3/XqVOnDD83P/74owZaFy9eNPpQyCLGjRun79VXrlwx5PMzsInlibGSkJAQ18yZM105c+bUfxsCGwQ4QUFBLqs4f/68a8CAAWFZnHr16rkOHz5s9GFZDjJyyNR07NjR6EOh50BWMnv27K5SpUq5goODDT1HZcqUcVWrVs3QYyBruX79uit+/PiuUaNGGfL5GdjE8sRYATIeS5cudRUpUkT/TbVr13bt2bPHZfWs05QpU1zZsmXTp8mWLVu6AgICjD4sS3jw4IGrQIEC+sKPyZw2btyo1zYCeaMgY4T3jGnTphl2DGRNdevWdZUoUcLU9282LbCovXv3aj+Bt99+W7fwYtcLCoSxrdrK0BunefPmcvToURkxYoT8+eefWrCGyckofKaI4RwdP35cZs6cya31Jobt93379pWvvvpKOxQbAS3y8b6B4n2i6GjatKls375d32vMioGNxaDvBLbdoTfM1atXdS4NWuXjzdJO0OAPc2tOnjypN2xsk8VWdIwCoH9DG/8xY8bI0KFDpWDBgjxFJtenTx/dit+4cWPd4eFraPeAkQ/sa0TRhYdpvD/jPcesGNhYyJ49e7Ql/qBBg6RXr146Sr5WrVq23iqNLX0DBgzQfjhZsmTRFvUdO3Zk9iYc9JX4+OOPpUaNGnpuyPzQW2jGjBk6bqF9+/Y+/dz4nGgciBsUUXQhGC5XrpwsXbpUzIqBjQWgyy+yNCVKlNBmeNu2bdOfJ0iQQJwCfW/QXBB9QND5EtmbdevWGX1YpoBgBsEtzoudg1y7wWT18ePH69Ihek35CjpQh4aGajdkophAUIzs+cOHD8WMGNiYHDr6Vq9eXQYOHCg9e/bUtc0iRYqIE2GODZqbIXuD7shoVY9AB8GeU61evVpb9aMeKV26dEYfDkUThgvi+7t79+4+u0ngSRudvznJm2IT2Dx69EjLIMyIgY2JYTowxhCgK+jy5cu12NBJWZrIsje4oXft2lXrcFq3bq2ddp2YycO/H/VVjRo1MvpwKIa+//57OX/+vAwfPtzr5xAPAQhsuAxFsYHAGKUBZl2OYmBj4vkyCGowiRlZGiMnqpq1RgFzS6ZMmSLTpk3T84NaEyeZMGGCHDx4ULNWXIKyrjx58miAiiGUCHC86dChQ3LhwgUGNhQreL9BcIwROWbEwMaERo4cqXOUcLPevHmz5MiRw+hDMi1sDUetDQZvYqcY3ridMuCyX79+0qpVKylatKjRh0OxhK9l8uTJ5fPPP/fqucQTduLEibX4kyg2ENhgVeHs2bNiNgxsTObrr7+Wbt26yWeffSbz58/XNzuKHLbNIqv10ksvSYUKFbTHj92hDwoKQHG9kD12/yFjgwGDGzZs8Gpgg+8RZIKJYgM1jnHjxjVl1oaBjYlgWzP6W6BQ+LvvvtNiWTPB+vz9x/f1ZbaCXRQTY9eUe0s4tsLbFYqnf/rpJ71e0qZNK3Zm5mvOG9lH7Hzs3LmzBq2edv/+fS325G6oyDnpmosNTNl+8803TVlnY647p4N98803uoX722+/1eDGjB4EP5Bkg5PpCz82m9SpU+tW1ly5ckmVKlXkwIEDYkfI0mCrcIcOHcTuzH7NeRIeZFBAjH5VqLHzNGzPRYNPFg5HzknXXGzhWlq5cqUEBweLmTCwMQF0jO3du7cGNuiySzGXMmVKfYJABqdy5craudhOTpw4odu7sVSJ8RNkL2XLltVdbnjA8XS2ABlNfF+8+uqrHv17ybmqVKkid+/e1Z27ZsLAxmBYn8S2ZfSxQN0ExV6qVKlkxYoVWp+EIuzAwEDbnFbsBEuTJo0uW5A94eEGnYEx/82TduzYoTstuYOOPAWzCfGAhRpHM2FgY6Bjx45Jw4YNNZ03ZMgQvuF4EGpPMBQ0ICBAmjRp4pWaBV+7fPmybm9HIIydLWRPNWvWlNdee03r7DwlJCREdu7cqTU8RJ6CmVEIbhA0mwkDG4Pcvn1bswkZM2bUluqoLifPN5HCLhPUK2A7rdWNGjVKGzR+8sknRh8KebnWBtu+Mahy//79Hvk7jx49qvPVGNiQp+GaYsaG9OkJnWLRUA5ZBVSXk/eeflGvgILbWbNmWfY0YwL0uHHjpF27dlpHRPaG9wfs8EMm1xPcT9TFihXzyN9H5Ib+Yehng1obs2DGxgDY+YDamtmzZ0vu3LmNOARHQaEtZvKgmd3p06fFiiZOnKizWbAMRfaHuoVPP/1UM45YTo0tPFGjwzEfosjT3MOZzVRAzMDGxxDZYlkEb1pVq1b19ad3JBRLYooytoO3bNnScvU2eNPA5O733ntPMmXKZPThkI+0aNFClx6nT5/ukcAGT9ZE3ljyT5IkianqbBjY+HgJ6uOPP9YeJBhoSb7t7Przzz/rltcff/zRUqcefU0wKqJp06ZGHwr5EHb1vfvuuzoLLTZbv9G7BtcQ62vIW3P7ihQpYqo6GwY2Pl6CwhcfT9/c1WJMz4U2bdro0pSVlqRwY0uXLp0ePzkLdvQhyxubTtoYlBoUFMTAhhxTQMzAxkeOHDmiS1DoV4M21GSMoUOH6pIU6m2s0C79yZMnumsOxaR4MiJnQTCbPn16DW5jCjcc7LosXLiwR4+NKHxgg0HEN27cEDNgYOPDpluoj+ASlPFLUhMmTJDVq1frjjSzw4gI7J7jMpQzIZhFUIsiYgS5MQ1s0BcHdRBE3uBe5jRLnQ0DGx/YtGmT3kQHDRrEJSgTQEPESpUqSa9evbTuyczwpJ43b14pWrSo0YdCBi5HIbhFN+2YQC8cZmvIm3LmzClJkyb1WN+l2GJg42VY7vjvf/+r3Rk/+OADb386iuIuKfS2QUFubFL83oZpzAsWLNBsDdvgOxeCWuw8ienuKCwRYDAskTebSubIkUOvNTNgYONlf//9t858GTx4sH7xyTyp0/r162vdE/rDmBGmMT948ECPk5wLQe37778vS5YsiXaGEU3Trl27pk/URN6Ea8wsQ4d5p/Ui9EvBckf58uV1+YPMBUuDFy9e1B43ZrRy5UrJmjUrmziSTqq/detWtHdHuW80DGzI2xjYOAQKP/ft2ydffvkllxJMCJ1YUb8wcuRIU9baILDBDY3LUISp3KhhwDURHQxsyJeBzdmzZ2Nc5O5JzNh4EWb7FCxYUMqVK+fNT0Ox0LFjRzl37pwuGZptkveBAwfYu4YUOhBXqFAh2oENah7Q6A8tDoi8CTU2CGo8MQIkthjYeAlultgJ1aFDBz5xmxjazKPeBkGo2bJ9gN1bRIDsHer1Hj58GK2MDZ6kmfUjb3Mvd5qhzoaBjZf89NNPmjpu3Lixtz4FeUj79u1l6dKlpviGdMOTOXbSoeMwkTuwQQdhtI+IbmBD5G3ZsmXTDTJm2BnlkcAmMDBQZs2aJdu2bfPEX2d5mM2CaczNmzeXZMmSGX049AINGzaUl156SRv3maVFgLu+hsgNTfbQhTg6y1EIbLBEQOSLifTY7GCGB8QYBTZz584N68mCnT8VK1bUFvWlSpXyyCRaq8Mbz9WrV3UuEZkf5nY1a9ZMr10zTP5GAd758+f1+4rIDctJuCbWr18fpZMSHBysS+LM2JDTdkbFiek22b59++qPseaLPgnojIlmYkOGDBGnQ20NvsAFChQw+lAoijBFGQW7O3fuNPycYScdsFssPQvXBIrKozLnDEENdvsxsCFfwbVm2aWoY8eOhX2zYOYObgqoJ8HANjNEa0bCE//ChQulTp06LNizkNKlS+tylBnmR6EtOY4Fs8WIwsMuSzTdQ9ASlcwfZM+enSeRfALX2pkzZ8SSgQ3ecFHAhq1dWJZ666239Nexzevll18WJ9u1a5c2fUNgQ9YaNlizZk3TBDbI9nEnCz3LnQWOykwe96RlbvUmX8G1dvv2bcOX9GMU2HTp0kVvAigUQnBTrVo1/XUUEGMSrZMhW4OnbWQAyFoQjGIZyOgnDty08GRO9KwsWbJIihQpohTYoFMxgmP8fiJfSJUqlS6T3rlzRywX2HTq1EnWrVunHVu3bt0qCRMm1F9HtqZHjx7iZGj0hvEJqBAna0GAjsyNkc36sJ0XS70MbOh5EKggaxPVwCZlypScUUc+g4d697Vnye3eaPHdoEED/cZxa9GihXa5dCoMU9yzZ4+UKVPG6EOhGPD399feMUa2LTh69KhmQVl4ThHBtYEC4hfBzcV9oyHyBff1dvPmTTFSvKj+xilTpujHjz76KOzHEcHvcSI8ReGmhG62ZE3FihWTzZs3G/b53U/iDGwoIsjmTZo0SftlYdRCRBjYkFMzNlEObPr06RMWtLh/HBGnBjbYKoyljEKFChl9KBSLwObnn3+WBw8eSJIkSXx+HrGTBQV44TOhROHlypVLe9SgPQHqHCOCp2bUPBD5ivt6s0xgg4Zhz/sxPR3YoDtookSJeFosCtk2VPTv3btX3nzzTZ9/fjR2RHdZooi4x2zgWokssMHNhTuiyJdQioKxCpassTl06FCE/2/58uXi5MAGT/xkXVgCQnrfqEZ9uFlxPhRFNbCJDJeiyNcQ1CDbbHSNTZyYPtX+8MMP/9rN0a1bN90G7kTY4nbkyBHWRlgcgpo8efLI4cOHDfn86ODNwIYikzZt2rBrJTIMbMioOhtLZmww4LFXr15Sq1YtfWpAwSOCnT/++EO3gTsR9u0/fPjQ8Q0K7QANKC9dumTI52bGhqISfOPmEZWMDWtsyNdwzVkysGncuLFua8bBI3VfokQJ3SaLugQMwnQidBsGtsG3PqMDG9bY0IsgqxdZYIM6MXSA5XZv8jVcc5ZcigLsGEGh0P3793WLc5EiRXzaw8bols3Pct8IM2bMaPShUCzha+gOVH0JAwuvX7/OpSiKdWCD0gD35HoiX8I1h55ulgtsFi9erL0UsPSCupI5c+bI4MGDdQjmhQsXxJvwefBEi86+OAYM4TQD942QgY314WuIrbRRmaDsSXjKQcDurqEgimlggyDZXcxJ5Etx48Y1PPEQo6se07y7du0qa9as0dkl+Dlm7OCbyJs9XCZMmCDffPONzJgxQ2ta6tWrp3U+p0+fFjNkbNC51ojeJ+T5wAbNz3ydTnU/5fAaohfBNYIHyxcFNrjJEPkSrjn39WepwAaTvVE8HP5pAHUJy5Ytk969e4u3jBgxQlq2bCmVK1eWZMmSyYABAyRNmjQa8BgNDd2cPE7CTtxfR3xNfQlLuoAmj0SxuXkwsCEnBzYxegdFsXBEA9q6d+8u3nDjxg05fvy4lC9f/qnPh59v2bJFjIZOoLa/IYVfmrl/XyRYzAlZMz+/GP9x99cRX1NfYmDj3GsuJteo+3p5HvdSADM2McBrzpmBjRtqENBL4dlvsMyZM4unuXs2PFt/gLXmyIYWoojOXUgHgYGB4g04B7YPbMJnMNAd16w3mXv3RJImjfEfd38dI7txeAOfsp17zcXk5hHZ9ckam1jgNRcrWMmx5FIUag+w5RvVz6hHQJ1N+Jc3PVuUhJ8jcxNZsXGKFCnCXt46PjMUTJFnGPW0617a5XVEL4JrJLLCYPd7oq8L4IlcLpfhResxSjH06NFDMyhr167VeTq7d+/WrEnfvn3ls88+8/xRhttt9OxOAPw8Q4YMEf65nj17PrU8hoyNN4KbF6WG7SBJijRyr/P/Zs6SfOrb1Hu0xLKA26glIaMyRWbmlGsuuvBEHNn16Q7KjX5ytiJec7GDa87oJdAYvXMvXbpUNmzYIDlz5tSfYydU4cKFJUeOHBr04OWNpj/58+fXnVj169cPe2rBzz/++OMI/1zChAn15YtuoEbv3fc2vzhxJOlL/zunxs7cS5doKeBLvBk595rz9NI3r6WY4zVn/cAmTky3NiOIASzvoLAX0HXYmzN2vvjiC5k0aZLMmzdP+8YgE3Pv3j355JNPxGio/cF54BOS9bnrubDjzpfcgRS2mhPFZrOC+8bCZU3yNcsGNuHXcJFFmT17tv74r7/+8mo7+GbNmsnw4cN1eSlfvnyyY8cOWbFihVeKlaML293xJvKi+S1kfgjcEdQgC+dL7vb37gcFoojgGkmdOnWE/58ZGzIysLFkjU2xYsXCfoy6GjTo69Onj9y9e/dfU789rX379voyG3cNEG6K7D5sbfgaGjHzC8X46KHD4JheBNeIuxQgsuyfr1sWEAWboPVJjD47MiVu1atXl2PHjsmuXbskT548mklxIveNEEtkRYsWNfpwKBbwNTQqOH1Rq3yiqEyBR2CDQBmDMIl8Cdecu1TFKB4Jq7JmzaovJ8ObDJbnjJoKTZ6Dr2HevHkNOaVYymVgQ5FxL3m/aNkfS5u3bt3iySSfwjVn9FR5TkjzEKTesI38xIkTnvoryaAeDPgaZsuWzZDzz4wNReWJGLuiIsvYAAMbMiqwSZUqlRiJgY0HYQlq586dnvwryccCAgLk+vXrT9WR+RIDG3oRd0aPgQ2Z0S1mbOwFN0PUGrHbp3W5A1MjAxv3dnOi53FfHy8KbPDU7OsJ9eRsDx8+1H5ullqKQlElRQw3Q0Srp0+f5mmyKBTGo5O1EbuiAEXLly9f5m4WitCFCxf0Y2Qd14FLUeRr7pouSwU2BQsWlN9//917R2Nx7qd8LkdZF752RmVr3H2hUD+BSfZEz3PgwAF5+eWXtTlqZBjYkFGBjaVqbNAYD03yPvzwQ1bbPwdSw2gWGNm0cTL3bhNkbIwMbPDwAPv37zfsGMjccG24r5PIMLAhX7NkxgYzoPBEe/ToUf3GQtdfetpbb70lS5Ys4WmxoO3bt2tHV3wNjYJusliOwlM50fPg2ohqYIMaG9b8ka+4a7qMDmyi3cfmtddek61bt8qgQYO0OV/x4sX/1WVw48aN4lR16tSRqVOnyqlTpwxvUkTRg5EgSKFi5pmRcNNixoaeB93dz5w5IwUKFHjhCcK1jLljKOhM4uPp4+RMt6yYsQn/zYWsDbpb5sqV618vJ6tatarOGFq4cKHRh0LRhK9ZzZo1DW8HzsCGIuLO5EU1YwNs0ke+gmsNQXTChAnFSNF+B8cyS8uWLXXXCLY2O3WEQkSSJUumSxl4+u/SpYvRh0NRhJ1syJL069fP8HOGp3EMe8XkelxPRG64RjFgMCrvu+6xIOfPn9diYyJvw7VmhlmJ0crYtGvXTpdaENhs2bKFQU0EateuLevWreOTksWyNci0VatWzehDCXsaP3jwoNGHQiYMbHLnzi2JEiV64e91D8nEsjiRL+Bai2w4qykDmzVr1mj9zMCBA8Omx9K/1a1bVz/+9ttvPD0WgOJK1EVhGRHTtc2QscGNa9OmTUYfCpkMrokSJUpE6ff6+/tLmjRp5OTJk14/LiLAtWa5wGb37t3yxhtveO9obALLdAhuxo0bxx0JFtkNhWXVTz75RMwA69Nly5aVlStXGn0oZCIY9YH34MqVK0f5z+Amw8CGfPWAiGvNDJtmohXYsLI+6tq3b69LCRs2bIj+V4V8CgFo9uzZTbEM5YabF5YzsauFCFavXq0fo9OOADcZLkWRL1y7dk3u379vvYwNRV2lSpUkT548etMk80LfmlmzZmn9WNy4ccVMgc2DBw+0tQIRIIOXN29ebQIaVczYkK+4M4MMbGzMz89PlzbmzZuns3/InCZPnqwp1BYtWoiZFC5cWJv1cTmK3HAtRGcZyn2TwWwp9LIh8kVg88orr4jRmLHxoubNm2sRKLbukvngzX7kyJHSsGFDSZs2rZgJtvRiyYGBDQGWk9CSoEqVKtE6Ie6nZzT1I/L2NYqxQmbYgMHAxotSpkwp3bt3l7Fjx+r+fjIXfF2uXLliit41z4Onc8wdu3PnjtGHQgZDgIul0vLly0frz7kLOVlATE7ZEQUMbLzs008/1SZrX375pbc/FUXD7du3ZfDgwdK6dWvTdsvG03lISIgsW7bM6EMhgy1atEh3pL5oovez0CwNWWMGNuRtZtkRBQxsvAy9JHr37i2TJk2SI0eOePvTURR99913EhQUJH379jXtOcNOLdzMpk+fbvShkMHbvNHx/YMPPojRkiZuNgxsyNuYsXEYFBFnyZJFAxwy3sWLF2XUqFHStWtXU7T/jkzTpk31poatlORMs2fP1o8xCWwAuzMPHTrk4aMienqqNzbJ4FozA2ZsfNRwDdPQ58+frzcpMhZmeCVNmlQ+//xz038pUNgc/uZGzjNt2jR5++23Y1zgXrx4cdmxY4eEhoZ6/NiIYOfOnWHXmhkwsPGRxo0bawM41HSgvoOM8fvvv8vcuXO1cDi69QpGQEv86tWrcznKoY4fPy7//POPNGnSJMZ/B242KEDnchR5s3s7yi7MUq/IwMaHfW0mTpwogYGBWlBMvnf16lXp0KGD1KtXTxo0aGCZLwFuari5HTt2zOhDIR9DfRVuGBg+HFPup2jcfIi8AdcWrjPUdJmBOY7CIVBnM2LECC0k5pKU7yGoQTM+dINGoGmlafG4ubGI2FlwreJrXr9+fUmcOHGM/55UqVLpNlwGNuQtWOqM6nBWX2Bg42MtW7YMW5JCO3/yDUxaxxLUDz/8IOnTp7fUacdN7f3335cpU6ZIcHCw0YdDPrJ27VpteoYC8tjC0zQDG/IGFA2jTxsDGwdzL0lhqzGWQ3ij8r49e/ZIq1atpFGjRpZaggqvc+fOEhAQoDVC5AxDhgyRQoUKRbsp3/PgpoPJ4E+ePPHIsRG5uQNmsxQOAzM2Bi1JIXuwfv161tv4oK6mbt26ug3x559/ttQSVHi4waGIGP13sERB9g/Gly5dKl988YVHrlkENhiqevjwYY8cH1H4ZSjs2MuaNauYBQMbg+ApbMyYMfpCBoc87/Hjx1qf8OjRI/nzzz8lSZIklj7N//3vf2X//v2sz3JItgYNGj2VYSxSpIgGSFyOIk/DNYXA2UwPjQxsDNSuXTtt3oei1g0bNhh5KLaDrEanTp1k69at2j8IWTKrK1u2rJQsWVK+/fZbow+FvAh1NehbhN2T8eLF88jficGE+fLlY2BDHn+fdQc2ZsLAxmDogFu6dGldLkH6mTwDs7l++uknmTBhgp5fO8ATEbI2CII3b95s9OGQlwwfPlx3MrVo0cKjfy9uPszYkCedPXtWR36Yqb4GGNgYLH78+LJgwQKd54KhhwcPHjT6kCwPGQ0ENhhy6embgxm2fuPJG7U2ZM+aMLSDQLG4p5dO33zzTX144rR48hTUieKBC5lkM2FgYwIpU6aU5cuXS6ZMmaRSpUpaR0Exg2CmZ8+e0q9fP81u2A0aYKGg9K+//tKmfWQvX3/9tS4/YXna09BmAtPiV61a5fG/m5xp6dKlUqxYMe2QbiYMbEwCqWe84bz88stSoUIF2bVrl9GHZLm13v79+0uvXr1kwIAB+rIrdCIuXLiwPtVz/o99IFuLPkt9+vTR9wNPQzEydgfiZkQUWwiS8UCOOWZmw8DGRBD1IrjJnTu37prCTh56MfQEQuPDr776SjM2CHDMVKHvaXHjxpXRo0fLtm3b5NdffzX6cMhDgTmGs77yyis6dd5bcBNCYMOWAeSJwZdoMsvAhl7opZde0uAGaeN33nlHU9N8E4q862XFihVl5syZepO34/JTRDukPvjgA/33Yv4YWdsff/yh3/fff/+9JEyY0GufBzchNHpkPxuKLQTIGCT8xhtviNkwY2NCSZMm1Q6zKIBFWho3MDTXon8/MWCnx5kzZ7SIzROt563W6wRBzaBBg4w+FIqFhw8fSvfu3TXoqFmzplfPJTLBiRIl4nIUeSSwwYYXT7Uk8CQGNiYuEkUB7Lx582TRokVSpkwZOXr0qNGHZQrIYGFuErIWGTNm1C2sr7/+ujgNevOgpmjkyJGc/G3x7d2YtYOvo7eXUDF3DMEN62woNm7evKmbF8y4DAUMbEyuXr162rPk7t27WjCKN0EUbTnVxYsXdcvzxx9/LA0bNpR169ZpwbVToYkb/v1oRsglS+s5ffq01oWhvgaFvb6AmxEynMwCU0ytXLlSNy6gZMKMGNhYwH/+8x/Zu3evdir+7LPPpFy5co7L3uCmPXXqVHnttdd0CQqF1ZMnT9YnUCfDv3/8+PG6O2Hs2LFGHw5FAwZSNm7cWNKlS6fZWV9BYIOCezwUEMXEsmXLpECBApI5c2YxIwY2FoFmXSgsxJMWmnghe4MaC8xBsruTJ09qluajjz6SWrVq6bbYOnXqGH1YpoEbFbZ+I+hlDyTrQG0UdrbNmDFD/P39ffZ5kRnKli0bl6Moxg+ZWMo06zIUMLCxGNTaIHuDGVOor8CbFOpN7Lg8hR1PHTt2lLx588ru3bs1SzNt2jSv9PiwOnQifvXVV6VRo0ZajErmtnHjRhk4cKD07dtXSpUq5dPPjToe3JRQu8flS4oudK9GSYBZl6GAgY1FszcjRozQzAWKZlFvguUqdKO1wxsVdvrgDT9Xrlz6NIsn2+PHjzNLEwnsdMGWd2S3kLkh87p9+7Y2WcSIg969extyDJh6j2GbyBgRRQfeZ9KmTatF6GbFwMbCkK2ZM2eOvjmlT59eB2mipwCyGlZcosJANbzRY27WsGHDNFuDN1+MEPD03Bw7wpo3zhu61+JpnMwHDx7Itt66dUumT59u2FZZ9H7CCBe8VxBFFVYGENigBQnmHJqWy2Hu3LmDlIZ+tJPQ0FDXsmXLXFWqVNF/X+rUqV2ff/6569SpUy4zCwkJcS1ZssRVu3ZtV5w4cVz+/v6uTp06uc6fP2/0oVn2OqhVq5YrTZo0rnPnzhl9OPSMX375Rb8/f/vtN8PPTY8ePfR94vHjx0YfClnE8uXL9fr9559/TH3/9sN/xEGwzIFuiZhw68uCPV86duyYTJgwQXcN4d+JtdD33ntPC28zZMhg9OHpNkHMwsLSmXv5BEtp7du3lw8//FCSJUtm9CFa2rVr17RxIYaropaD59McUPhfuXJlXTr+8ccfjT4c2bdvX9gSNorziV6kefPmsnXrVjly5IghY2uiev9mYGNj6FMxa9YsLS7etGmTBhRYqsKOIryRYenCVxcnClrXrFmjb6ILFy7U4jOMj8BxYBs7xt7beb6Trx04cECLUjFQdcGCBTpfioxz4sQJ/d7DbkbsKDFLGh+BDYrzZ8+ebfShkMndv39fSx5QGoAaSCMwsInlibGb69evy99//62BBXoQ3Lt3TwMLjJx3v4oXL64TgGMbYKC+B9uO0W9mx44d+hE3WvTtyJkzp9YCIbgqXbq0Kdtx2wVuoGjRj1olX3S1pYi/93CtA5528X1nFkOHDtWb1JUrV/R9kSgi2MiBonfUPWJYqxEY2MTyxNiZuzkXWmIj6MALLd0hefLkWlSIF8YV4IUf45whCMELmR8EKY8fP9Zlj0uXLmkGBh/dP8b/x+9FQz130IQq+nz58vEG60NYkkSxKrrbOmVAqNmecitVqqQdhtFBHDv9zOTChQs6mmPixInSsmVLow+HTKx69er6QLxhwwbDjoGBTSxPjNPgiQ0BDraQhw9Q3B/xBv0sZADSpEnzryAIb5RFihSRQoUK6TZkMtaAAQN0oOqkSZO0voN8Izg4WDOTqHNau3atBvhmhEGGeBDBUjFRRD3FMLpl3Lhx0rZtWzH7/ZvrAKSwdlqjRg19PQ9qzLHVD2/WGNCJbAzrNqyhf//++sbUqlUr/TmDG+/Dcixmma1atUqXgM0a1EDTpk21KPTcuXOSNWtWow+HTOi3337T9/wGDRqIFbCPDUUJsjO4sDGbKGHChAxqLPa1Q2+b1q1bS4sWLbTehrwHA2vxgLBixQrtlo2dUGb27rvvap+oX3/91ehDIRPP6atZs6ap6sMiw8CGyAGQXcOwTOxo6Natmy5POazTg0/cuHFD3nrrLV3WRZE+6hLMDnV1KApF8Iv6O6LwsETpHuNjFQxsiByUufn222+1kBg1NwhwUAhOnoFaNBTIo1AYN4OyZcta5tTiWsByJZYciMIbPny41kuaPfMYHmtsiBwGu6NQgNehQwctwsOOGG67jx1sgUURLnYKYtcIesNYCY4XPaUwkgP1NmwNQIDNJKgRw1KUla4JZmyIHAhpZcwqwgvbkZFtoJjBGz86PaOoHjugrBbUuH366ad6I8MSGhFg2DJ2umI2lJUwsCFyKIyvWL16tY60wPZ8/JiiDluke/XqpUWVmNSNvlDZsmWz7CksV66c9pvC0gPR5cuX9cGnS5cukiBBAkudEAY2RA6GOpDdu3dLwYIFdSll0KBBrLuJ4ps+ztd3332nNUvo6J0qVSqxMiw19OjRQ1auXCl79uwx+nDIYGPHjtWApk2bNmI1DGyIHC5dunS6/NCnTx/p16+fZiAwBoCeD127keHCIEBkuVCzhGUoO8CwXGSdmLVxtvv372szPvS+wjBdq7HHdyMRxXo7OHZKYb7U9u3bdTji3LlzuSX8mf40yGigJgmjQZDpwi4oO0ERedeuXXV4rnvMCjnP5MmTtcsvlqGsiIENEYWpWrWqLkOg1uL999/XPiyYTO1k6PeDIA/BDJ5isVy3fPlyyZAhg9gRZkYlTZpURo0aZfShkAFCQkLk+++/1+9/DEW2IgY2RPSUzJkza8dcvLDcUqBAAW3ohzEBToOgDl2E8SaPsQiHDh2Snj172np7PBr2tW/fXhs6YlYcOcuvv/6q7QuQnbQqBjZE9FwY4Igbeffu3eWbb77RAGfx4sWOWJ7CFGMszeHffPjw4bBAz6pPsNH12Wef6egU1FyRs2pr+vTpo3POzDzf7EUY2BBRhDBDCEENWqpjQGKtWrV0mWrevHm23D118+ZNDWhQQPv1119rUIfeLgjynAQzgTA8FRPh9+/fb/ThkA/71ly/fl13+lkZAxsieiHUl2BSNWpL0LW4fv36kj9/fi0yRLddq0ODQqTeEbxh7AR6/Bw/flyDOtSbOFG7du0kR44c8vnnnxt9KOQDly5d0vYFnTt3lldeecXS59xygQ3W+dE0COkyzGQhIt/1OUHvFmxx3rJli3bYxbTwXLlyaaEpBkBaCZbU9u3bJ23bttU38p9//ll3gZw9e1bGjBlj6WZ7noAeJrjRYaccAlqyt/79++vyI5pOWp7LQn799VdXpkyZXLVq1cIiv2vNmjXR/jvu3LmjfxYfiSh29u/f72rSpIkrbty4rnjx4rlq1KjhmjZtmiswMNC0p/bEiROugQMHuvLnz6/vBenSpXN9++23rtu3bxt9aKYTGhrqKl26tKtQoUKuJ0+eGH045MXv4zhx4rhGjhxp6nMc1fu3H/4jFrFt2zZNjSJrkyVLFp2gW6FChWj9Hdibj1Q6hv/5+/t77ViJnOTq1asyZ84cnQ69adMmSZw4sdbjNGrUSKpVq6a1OkZCTxb38aFPD5aX3nnnHT0+ZKGs1jLelzAqomTJkvLLL79oho7sp0aNGrr0inoyM38vRPX+banAJvybFAMbInPCUs7s2bM1iEBPHGyNLlq0qJQuXVpKlSqlHzNmzOjVPhx4g0aAtXnzZv2IZWu8YeMNHMEMgi6jgy0rwTlDx2Xc/Jxac2RXK1as0P5V2BBQr149MTMGNv8nKChIX+FPDIIiZmyIvM89dsAdYJw5c0Z/HdumMTgS9Tn4fgz/ikomFTuykCUKCAh46oUdPFu3btXvcwRUGH3gDqiQmbFie3gzQGCImirUX6AWg+whJCREt3UnS5ZMNmzYoHV0dghsDO0yNX/+fNm1a1ekvwfbLWMzXA7b1rB9k4h8DzdDvNDwzb37CEEOXljiQBYAuzHCJ47xhoWMDgoZ48ePry/8/+DgYH2hxwyytvixW6JEibSxYJ48eXR2EwKZEiVKMCvjISiuxqgFvJ9+8MEHep7J+kaNGqUF9HgYMHtQEx2GLkUtXLhQ+2NEpkOHDtpTIaZLUczYEJkbAhQEPO6sy7lz53R6tjuQwQtDJhHgIAuDpRAEMeGzPGnSpLHVG7MZPXjwQGeIpU+fXtavX2+bwZ9OdeLECSlYsKBu68cIBSvgUlQsTwwRET0NAQ0Gf44ePVo6derE02NRoaGhOswVDxLI2Filbiqq92+G3EREFCXlypXTLDqW+zBPiKzpxx9/1GVg9G6ySlATHZbaFbV7926t3L57964+MTRp0kSbaCHyxCsqmLEhIoo51DhhCcNdDhA3blyeTostQRUuXFjvnxMmTBArsWXGBt9AKBJMmzatDBw4UAvY8HM7T9olIjIT7KCZOnWqbNy4UYYNG2b04VA0PHnyRAOaDBky2PprZ6mIoFChQvoiIiJjl6QwQ6pv377aAwXb6sn8vvnmG9mxY4cGpQhQ7cpSS1GewKUoIqLYw/DTN954Qz/iZolu02Tuzv2lSpWS3r17W7YFii2XooiIyBzQyXnGjBlaRIxBog57RraUq1evyvvvv6/N+DBA2u4Y2BARUYzkz59fJk+eLNOmTZOhQ4fyLJpQUFCQjkpAZg2bb9APyu4sVWNDRETmgk7EBw4c0C3g+fLlk9q1axt9SPR/kEX75JNPdKkQ27vR2NIJmLEhIqJY+eqrr6Ru3bry4YcfapBD5vD9999rRg39alAP5RQMbIiIKHY3kjhxdDkqR44cUqdOHbl+/TrPqMGWLFkin332mXzxxRe6xdtJGNgQEVGsYfvwX3/9pQ386tevrzUdZIzDhw/rEmHNmjXl66+/dtyXgYENERF5BDrBz58/X6e3d+zYkTulDHDjxg2tc8qaNavuWnNiZ2gGNkRE5DFlypTRVv0TJ06UQYMG8cz6EMYN1a1bV27fvq3Zs+TJkzvy/HNXFBEReVSLFi3kwoUL0q9fPwkJCZH+/fuLn58fz7KXm9e9/fbbcvDgQVm2bJm88sorjj3fDGyIiMjjMG4Bc/x69eqlwQ12TjG48Q5kaBDUHD16VFauXCklSpQQJ2NgQ0REXtGzZ08NbjBXCgMYMauIwY1n3bp1S+d1nTx5UoOaYsWKidMxsCEiIq/BlmMEN927d9fgZsiQIQxuPFgoXKVKFTl37pysXr1aChcu7Km/2tIY2BARkVd169ZNg5vOnTtrcDNixAgGN7GEXkGVK1eWixcvypo1a6RgwYKe+WLZAAMbIiLyuk6dOmlw0759e3n06JGMHj3aEXOLvCEgIEB71Fy5ckWDmtdee83oQzIVbvcmIiKfwNyiX375RVv8I9tw+fJlnvlowpJT0aJF5c6dO7J27VoGNc/BwIaIiHy6FRxZhmPHjmmh65YtW3j2ozjQctiwYVpTg1qanTt36tBR+jcGNkRE5PMmfrt27dJeK+XLl5fx48ezS/ELGu81bNgwbPbT0qVLJU2aNL77glkMAxsiIvK5jBkz6rJKu3bttO7m448/locPH/Ir8Qz0psFkbgy1nDdvnm6Zd+KYhOhgYENERIZIkCCBFhFjMvjvv/8upUuXltOnT/Or8X8WLFigzfawDLV9+3apV68ez00UMLAhIiJDNWnSRAdnooNugQIFtNdNcHCwY78qGEeBpScEMqip2bZtm+TNm9fow7IMBjZERGQ4FMTu2bNH2rRpox2L8fP169eLk6DHz/fff69BDHY8TZ8+XebOnevYYZYxxcCGiIhMwd/fX2/s2PGTIkUKLSxu3ry5XL16VewOGSvsEvv000/134zamsaNG7ORYQwwsCEiIlNBtmbjxo0yceJEWbRokeTJk0cmTJigwzTtOBahdevWWl+EmiMsO40dO1ZSpkxp9KFZFgMbIiIynThx4kirVq00c4FaEzT3Q0YDyzN2qL9BFqp///7y6quvypw5c2TcuHGydetWKV68uNGHZnkMbIiIyLTQrwXdijdt2iQZMmSQpk2bav8bFBij2NhqDh06pAFb1qxZZfjw4brchOANgRu3cXsGAxsiIjK9UqVKaWO6/fv3S9WqVaVv376SJUsW6dq1q+m3iGO79qpVq6RGjRo6AgE9aQYMGKAzn7DdPX369EYfoq34uXDGHSQwMFCL0jBnA4VqRERkPZgzhVoUdC1G5gbLVQ0aNNCgB+/xZnDq1ClZvHixTJo0SXd8FSpUSIuDP/jgA62nIe/cvxnYEBGRZT148ECmTp2qAQ6yOZggXrZsWalVq5a+UMPiK6j9we4mFDwjoDl8+LAGMAi2kFmqVKkSdznFAgObWJ4YIiKylrNnz2pAgReWfoKCgiRXrlxSs2ZNDSqwuwr1OZ7KluB+cvz4cQ2osEyGF+4tqAXC58QLU8zZh8YzGNjE8sQQEZG1MzmYRYXsCV7o5gso0M2ePbvkzp1bsznuj2nTptWAx/0KDQ2Vx48f6+vRo0daD4OJ5Ahk3B+vXLkS9vmwm8mdJSpSpIju6iLPYmATyxNDRET2gFLSixcv/iswwceTJ09Gefs47h3hg6HwH81S12NnDGxieWKIiMgZYwzOnTsnt27dCsvQYAkLmZ3wGZzMmTPr1nM/Pz+jD9mxAqN4/47n06MiIiIyERQb58iRw+jDIA/iIiARERHZBgMbIiIisg0GNkRERGQbDGyIiIjINhjYEBERkW0wsCEiIiLbYGBDREREtsHAhoiIiGyDgQ0RERHZBgMbIiIisg0GNkRERGQbDGyIiIjINhjYEBERkW0wsCEiIiLbYGBDREREtsHAhoiIiGyDgQ0RERHZBgMbIiIisg0GNkRERGQbDGyIiIjINhjYEBERkW0wsCEiIiLbYGBDREREtsHAhoiIiGyDgQ0RERHZBgMbIiIisg0GNkRERGQbDGyIiIjINhjYEBERkW0wsCEiIiLbYGBDREREtsHAhoiIiGyDgQ0RERHZhqUCm1WrVkn16tUlZcqUkjp1aqlbt64cPXrU6MMiIiIik7BMYBMSEiKDBw+Wrl27ytmzZ+XgwYMSL148qVKlity9e9fowyMiIiIT8HO5XC6xqICAAMmaNassX75cA5yoCAwMlBQpUsidO3fE39/f68dIREREsRfV+7dlMjbPc+XKFf2IpSkiIiKieEaegtDQUH1FBstNzxMcHCzdunWT4sWLS7FixSL880FBQfoKH/ERERGRPRmasWndurUkSpQo0tfJkyf/9ecQDLVo0UL/3+zZsyVOnIj/GajLQerK/cqSJYuX/1VERERkFMvV2OBwW7ZsKUuWLJE1a9ZI3rx5I/39z8vYILhhjQ0REZH9amwMXYqKSVDTqlUr+fvvv6MU1EDChAn1RURERPYXz0pBTbt27WTRokWycuVKyZ07tzx58kT/X9y4ccXPz8/oQyQiIiKDWWZX1M2bN+WXX36RGzduSJEiRZ6qw5k8ebLRh0dEREQmYJmMDToNuzM0RERERJbO2BARERG9CAMbIiIisg0GNkRERGQbDGyIiIjINhjYEBERkW0wsCEiIiLbYGBDREREtsHAhoiIiGyDgQ0RERHZBgMbIiIisg0GNkRERGQbDGyIiIjINhjYEBERkW0wsCEiIiLbYGBDREREtsHAhoiIiGyDgQ0RERHZBgMbIiIisg0GNkRERGQbDGyIiIjINuKJw7hcLv0YGBho9KEQERFRFLnv2+77eEQcF9jcvXtXP2bJksXoQyEiIqIY3MdTpEgR4f/3c70o9LGZ0NBQOXr0qOTPn18CAgLE39/f6EOyXMSMoJDnjueN15y58XuV585u1xzCFQQ1mTJlkjhxIq6kcVzGBifj5Zdf1h/jxDOwiRmeO543X+M1x/PGa84a/L14b40sU+PG4mEiIiKyDQY2REREZBuODGwSJkwo/fv314/Ec8drztz4/crzxmvOGhKa5N7quOJhIiIisi9HZmyIiIjInhjYEBERkW0wsCEiIiLbcFwfm8icPXtWGwsVK1ZMEidObPThmM6DBw/k8OHDkjJlSsmZM6fRh2Mp586d01fRokUlSZIkRh+OZVy7dk3Onz8vr7zyil53FDUonTx58qQ8evRIcuTIwWsuBvbs2SP37t2TMmXK8LJ7gWPHjsnVq1ef+jX0sSlUqJAYAsXDTrd27VpX9erVXalTp0Yhtevw4cNGH5LpzJo1y+Xv7+/KnTu3K3ny5K7y5cu7bt68afRhmd769etdNWvWDLu29u/fb/QhWcLWrVtd5cqVc6VNm9ZVuHBhV+LEiV0tWrRwPX782OhDM72ZM2e6cuTI4cqbN68rT548+v363XffGX1YlrJy5UpXvHjx9Hs2ODjY6MMxvcaNG7vSpUvnKl26dNirTZs2hh0Pl6JEZP/+/dKhQwf5+++/jYkuTe706dPSrFkz+fbbbzUyxxM0nqS7dOli9KFZ4tpq166dLF++3OhDsZTjx4/LoEGD9Clw9+7dsm/fPvnzzz9l8ODBRh+a6d28eVM2btyo2dUjR47IlClT5IsvvpAdO3YYfWiWgGuuRYsW0qlTJ6MPxVKqV6+u15379eOPPxp2LAxsRKRjx45Ss2bNSGdPONn06dN1GaBt27ZhKcbOnTvL77//Lvfv3zf68Eytffv2UqtWLV5b0dSkSRMpW7Zs2M9z5colVapU0TdMihwe0jJmzBj284oVK+rHCxcu8NRFYQmvefPm+n2LZWOKuocPH8rOnTv1QRgzGY3EOzm9EJ6YixQp8tTN+fXXX5egoCA5dOgQzyB5XUhIiF6HCHDoxa5fv65B4MKFC6Vx48ZSrlw5efvtt3nqXmDYsGF6g/7ss894rqJpwYIFmukqUaKEfp+uXr1ajGLL4uGDBw/KrVu3Iv09pUqV4lN0NFLb7sGhbqlTpw77f0Tehm6mWALt1q0bT3YU7N27V8/ZlStX5M6dOzJmzBjDu8Ga3bZt2zSwwZIds/fR884778jo0aMlVapUEhwcrN+n7777rt6LM2fOLL5my8Bm8uTJsnXr1kh/z4oVK7jzKYrix4+vuyvCw1MNJEiQIKZfJqIoGTt2rAwdOlTmz58vuXPn5lmLgrfeektfsGjRIr3xYCoyszaRL39++OGHujsWL9QTwqZNm3QXqBE3aKuoX7/+U/eL4cOHy8SJE2XJkiXSunVrnx+PLQMbRN3kOdmyZZMDBw489Wvu9fqsWbPyVJPXjB8/Xj799FOZM2eO1sFR9KHGK1++fLJ06VIGNpHIkiWLbN++XV+ADRLQu3dv+eSTT3RJj6IG2UHUZRpV12XLwIY8C0Wb2Flx6dKlsKJE7FBBbxH2syFvwa6Krl27apF6nTp1eKKjAMsA7qfm8P2n8L3rXj6m51u1atW/Nk00bdpU1q5dK/Hi8VYZkSdPnmgNXPilTiyFYndZgQIFxAj8aono2v2ZM2fk6NGjelJ27dqlxXcogMqQIYM4HdKMSC3WrVtXevbsqedp3LhxMmPGDKMPzfTwxIJdAidOnNCfowD29u3bGhCG37lC8q+bCp6Se/TooTdk926opEmTaiE7PR9qC6tWrSqtWrWSPHnyaNYB36uJEiUyZEmA7O/+/fvaxBDXXN68efX9Dq0asKsRS6BG4HRvEb1BI+X9LFTG42ZOogWIQ4YMkX/++UdTjC1bttS+BRS5WbNmaY3Is7p37y716tXj6YvAwIEDZdmyZf/6dXTR/fXXX3neIoH6EFxz6KGE1gzYpdKmTRutsaGoQ++pr776StatWydx48blqYsEOvajQB39pvAgUqlSJfnoo48MO28MbIiIiMg22MeGiIiIbIOBDREREdkGAxsiIiKyDQY2REREZBsMbIiIiMg2GNgQERGRbTCwISIiIttgYENEjvT48WNtoIhO0ERkHwxsiMgwJ0+elNmzZ0tQUNC/Zh7h148fP+61zx0YGCiNGjXScSpEZB8MbIjIMGnSpNHRJX379n3q1/Fz/HratGm99rkxtK9hw4by0ksvee1zEJHvcQgmERkG84smT54s1apV04F5pUqVkvXr1+vQVczqwVyyiGDqd2hoqM6jyZYtmw7HDD/Vevv27XLlyhWpVavWU0NJN2zYoHPOEidOrJ8z/AwlZIq2bt2q2Zz//Oc/kjlzZi/+64nIGzgriogM16FDB1mxYoUOHCxZsqQ0aNBAhg4dGumfady4sYSEhMiTJ090+B6CmqVLl0qWLFn0/x88eFCKFy8ukyZN0iUn/F5MHEYW6M8//5Tr16/rjzFxvXDhwnL+/HkpX768JEmSRIdtHjhwQJo3by79+vXz0VkgIk9gYENEhnvw4IFmSFDI+/LLL8u2bdskQYIEUf7zyNwgGEqePLlmgNww5bpPnz6yd+9eDXB++uknDYIQ0Dwb2Hz55ZeaJdq0aVPY37lw4UKpW7euV/7NROQdXIoiIsMhS9K6dWv54osvZMiQIVEOag4dOiSnTp2Se/fuaZCCZazwOnbsqFmcGjVqyLFjx2TRokUR1u1gaerGjRu6XIXgKk6cOAxqiCyIGRsiMlxAQIAUKlRIsmbNKrdu3ZL9+/c/VfvyrIcPH0rt2rU121KiRAn9vfg7sIvq2rVrT/1e/J6iRYtqcLN48eKwX382Y3P37l1p27at/PHHH5I/f36pUqWKBkYIcojIOrgriogM5XK5tJYF9TD//POP+Pv7S9euXSP9M9OmTdMg5uzZs5qRwdbwDz/8UP+uZ//uHj16SL58+XSZCYXBEcEy1syZMzUw+uabb7TGBsd0//59j/1bicj7GNgQkaGGDRumNTBTp06VRIkS6cfp06drfUtELl++rJmUZMmShf3avHnzIvy7V61aJW3atJEmTZrostXzYAkKkiZNKlWrVpXRo0fr50HwRETWwaUoIjIMgo7XX39dZsyYIfXr1w/79f79+2uhL3Y2pUqV6l9/bteuXfLGG2/obqoCBQrIggULZPPmzbr1G0tMsGfPHv096C787rvv6vIVMjD4NRQSP7sUhSLjLVu26JIVtpnjmFBzs3PnTokXj+WIRFbBjA0RGQZZGQQU4YMawK/VqVNHl5meBzUz6EeDrd7YxVSzZk2ZP3++1KtXL+z3/PXXXxogIahxFwdjqQkBDgqOn23QN2jQIG0MeOnSJV2ywp/D52BQQ2QtzNgQERGRbTBjQ0RERLbBwIaIiIhsg4ENERER2QYDGyIiIrINBjZERERkGwxsiIiIyDYY2BAREZFtMLAhIiIi22BgQ0RERLbBwIaIiIhsg4ENERER2QYDGyIiIhK7+B8LsXKrMs4KagAAAABJRU5ErkJggg==",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "for i in range(1, 4):\n",
+ " gtsam_plot.plot_pose2(0, result.atPose2(i), 0.5, marginals.marginalCovariance(i))\n",
+ "plt.axis('equal')\n",
+ "plt.show()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "e28dbbc6",
+ "metadata": {},
+ "source": "Notice how the covariance ellipse for pose 1 is small and round -- it's pinned only by the prior, whose sigmas are equal in x and y. For poses 2 and 3, the ellipses grow overall, but not evenly: they stretch more *sideways* (perpendicular to the direction of travel) than forward. This is the classic dead-reckoning \"lever-arm\" effect -- heading uncertainty at an earlier pose, carried forward over each 2-meter step, turns into extra lateral position uncertainty at the next pose, on top of the odometry noise itself. It's the same effect behind the \"banana-shaped\" uncertainty regions common in dead-reckoning navigation, and exactly why SLAM systems add loop-closure or absolute measurements (like the GPS factor in `GPSFactorExample`) to keep it in check."
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.13.12"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
\ No newline at end of file
diff --git a/python/gtsam/examples/OdometryExample.py b/python/gtsam/examples/OdometryExample.py
deleted file mode 100644
index 210aeb8083..0000000000
--- a/python/gtsam/examples/OdometryExample.py
+++ /dev/null
@@ -1,72 +0,0 @@
-"""
-GTSAM Copyright 2010-2018, Georgia Tech Research Corporation,
-Atlanta, Georgia 30332-0415
-All Rights Reserved
-Authors: Frank Dellaert, et al. (see THANKS for the full author list)
-
-See LICENSE for the license information
-
-Simple robot motion example, with prior and two odometry measurements
-Author: Frank Dellaert
-"""
-# pylint: disable=invalid-name, E1101
-
-from __future__ import print_function
-
-import gtsam
-import gtsam.utils.plot as gtsam_plot
-import matplotlib.pyplot as plt
-import numpy as np
-
-# Create noise models
-ODOMETRY_NOISE = gtsam.noiseModel.Diagonal.Sigmas(np.array([0.2, 0.2, 0.1]))
-PRIOR_NOISE = gtsam.noiseModel.Diagonal.Sigmas(np.array([0.3, 0.3, 0.1]))
-
-
-def main():
- """Main runner"""
- # Create an empty nonlinear factor graph
- graph = gtsam.NonlinearFactorGraph()
-
- # Add a prior on the first pose, setting it to the origin
- # A prior factor consists of a mean and a noise model (covariance matrix)
- priorMean = gtsam.Pose2(0.0, 0.0, 0.0) # prior at origin
- graph.add(gtsam.PriorFactorPose2(1, priorMean, PRIOR_NOISE))
-
- # Add odometry factors
- odometry = gtsam.Pose2(2.0, 0.0, 0.0)
- # For simplicity, we will use the same noise model for each odometry factor
- # Create odometry (Between) factors between consecutive poses
- graph.add(gtsam.BetweenFactorPose2(1, 2, odometry, ODOMETRY_NOISE))
- graph.add(gtsam.BetweenFactorPose2(2, 3, odometry, ODOMETRY_NOISE))
- print("\nFactor Graph:\n{}".format(graph))
-
- # Create the data structure to hold the initialEstimate estimate to the solution
- # For illustrative purposes, these have been deliberately set to incorrect values
- initial = gtsam.Values()
- initial.insert(1, gtsam.Pose2(0.5, 0.0, 0.2))
- initial.insert(2, gtsam.Pose2(2.3, 0.1, -0.2))
- initial.insert(3, gtsam.Pose2(4.1, 0.1, 0.1))
- print("\nInitial Estimate:\n{}".format(initial))
-
- # optimize using Levenberg-Marquardt optimization
- params = gtsam.LevenbergMarquardtParams()
- optimizer = gtsam.LevenbergMarquardtOptimizer(graph, initial, params)
- result = optimizer.optimize()
- print("\nFinal Result:\n{}".format(result))
-
- # 5. Calculate and print marginal covariances for all variables
- marginals = gtsam.Marginals(graph, result)
- for i in range(1, 4):
- print("X{} covariance:\n{}\n".format(i,
- marginals.marginalCovariance(i)))
-
- for i in range(1, 4):
- gtsam_plot.plot_pose2(0, result.atPose2(i), 0.5,
- marginals.marginalCovariance(i))
- plt.axis('equal')
- plt.show()
-
-
-if __name__ == "__main__":
- main()
diff --git a/python/gtsam/examples/README.md b/python/gtsam/examples/README.md
index 73ad0bbf02..26dcff49aa 100644
--- a/python/gtsam/examples/README.md
+++ b/python/gtsam/examples/README.md
@@ -10,6 +10,7 @@
| [easyPoint2KalmanFilter](easyPoint2KalmanFilter.ipynb) | ExtendedKalmanFilter not yet exposed through Python |
| [elaboratePoint2KalmanFilter](elaboratePoint2KalmanFilter.ipynb) | GaussianSequentialSolver not yet exposed through Python |
| [FisheyeExample](FisheyeExample.ipynb) | :heavy_check_mark: |
+| [FixedLagSmootherExample](FixedLagSmootherExample.ipynb) | :heavy_check_mark: |
| [HMMExample](HMMExample.ipynb) | :heavy_check_mark: |
| ImuFactorsExample2 | :heavy_check_mark: |
| ImuFactorsExample | |
@@ -19,7 +20,7 @@
| ISAM2_SmartFactorStereo_IMU | |
| LocalizationExample | :heavy_check_mark: |
| METISOrderingExample | |
-| OdometryExample | :heavy_check_mark: |
+| [OdometryExample](OdometryExample.ipynb) | :heavy_check_mark: |
| [PlanarSLAMExample](PlanarSLAMExample.ipynb) | :heavy_check_mark: |
| [Pose2SLAMExample](Pose2SLAMExample.ipynb) | :heavy_check_mark: |
| Pose2SLAMExampleExpressions | ExpressionFactorGraph not yet exposed through Python |
@@ -36,17 +37,17 @@
| Pose3SLAMExample_initializePose3Chordal | :heavy_check_mark: |
| Pose3SLAMExample_initializePose3Gradient | |
| [RangeISAMExample_plaza2](RangeISAMExample_plaza2.ipynb) | :heavy_check_mark: |
-| SelfCalibrationExample | :heavy_check_mark: |
+| [SelfCalibrationExample](SelfCalibrationExample.ipynb) | :heavy_check_mark: |
| SFMdata | :heavy_check_mark: |
| SFMExample_bal_COLAMD_METIS | |
| SFMExample_bal | :heavy_check_mark: |
-| SFMExample | :heavy_check_mark: |
+| [SFMExample](SFMExample.ipynb) | :heavy_check_mark: |
| SFMExampleExpressions_bal | |
| SFMExampleExpressions | |
| SFMExample_SmartFactor | |
| SFMExample_SmartFactorPCG | |
| ShonanAveragingCLI | :heavy_check_mark: |
-| SimpleRotation | :heavy_check_mark: |
+| [SimpleRotation](SimpleRotation.ipynb) | :heavy_check_mark: |
| SolverComparer | |
| [StereoVOExample](StereoVOExample.ipynb) | :heavy_check_mark: |
| [StereoVOExample_large](StereoVOExample_large.ipynb) | :heavy_check_mark: |
@@ -54,12 +55,12 @@
| UGM_chain | discrete functionality not yet exposed |
| UGM_small | discrete functionality not yet exposed |
| VisualISAM2Example | :heavy_check_mark: |
-| VisualISAMExample | :heavy_check_mark: |
+| [VisualISAMExample](VisualISAMExample.ipynb) | :heavy_check_mark: |
Extra Examples (with no C++ equivalent)
- [FitBasisExample](FitBasisExample.ipynb)
-- DogLegOptimizerExample
-- GPSFactorExample
+- [DogLegOptimizerExample](DogLegOptimizerExample.ipynb)
+- [GPSFactorExample](GPSFactorExample.ipynb)
- PlanarManipulatorExample
- PreintegrationExample
- SFMData
diff --git a/python/gtsam/examples/SFMExample.ipynb b/python/gtsam/examples/SFMExample.ipynb
new file mode 100644
index 0000000000..a6e5a00340
--- /dev/null
+++ b/python/gtsam/examples/SFMExample.ipynb
@@ -0,0 +1,1068 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "2d1676d8",
+ "metadata": {},
+ "source": "# SFM Example\n\nThis is the canonical structure-from-motion (SFM) example in GTSAM, and it pulls together ideas used elsewhere in this notebook series: projection factors (`VisualISAMExample`), the `DoglegOptimizer` (`DogLegOptimizerExample`, `SelfCalibrationExample`), and marginal-covariance visualization (`OdometryExample`) -- now applied all at once to a full 3D bundle-adjustment problem.\n\nUnlike `VisualISAMExample`, which fed observations to an incremental solver one pose at a time, this notebook builds the *entire* factor graph up front and solves it in a single batch optimization with `DoglegOptimizer`. The scene is the same 10-meter landmark cube with 8 cameras circling it, this time with a known, fixed calibration."
+ },
+ {
+ "cell_type": "markdown",
+ "id": "ebac1d0d",
+ "metadata": {},
+ "source": [
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "917dbf08",
+ "metadata": {},
+ "source": [
+ "GTSAM Copyright 2010-2026, Georgia Tech Research Corporation,\n",
+ "Atlanta, Georgia 30332-0415\n",
+ "All Rights Reserved\n",
+ "\n",
+ "Authors: Frank Dellaert, et al. (see THANKS for the full author list)\n",
+ "\n",
+ "See LICENSE for the license information"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "fe290a74",
+ "metadata": {
+ "execution": {
+ "iopub.execute_input": "2026-07-22T10:42:51.984077Z",
+ "iopub.status.busy": "2026-07-22T10:42:51.983871Z",
+ "iopub.status.idle": "2026-07-22T10:42:51.989537Z",
+ "shell.execute_reply": "2026-07-22T10:42:51.988771Z"
+ }
+ },
+ "outputs": [],
+ "source": [
+ "try:\n",
+ " import google.colab\n",
+ " %pip install --quiet gtsam-develop\n",
+ "except ImportError:\n",
+ " pass"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "id": "f1166e6c",
+ "metadata": {
+ "execution": {
+ "iopub.execute_input": "2026-07-22T10:42:51.992244Z",
+ "iopub.status.busy": "2026-07-22T10:42:51.992070Z",
+ "iopub.status.idle": "2026-07-22T10:42:52.340460Z",
+ "shell.execute_reply": "2026-07-22T10:42:52.339941Z"
+ }
+ },
+ "outputs": [],
+ "source": [
+ "import matplotlib.pyplot as plt\n",
+ "import numpy as np\n",
+ "\n",
+ "import gtsam\n",
+ "from gtsam import symbol_shorthand\n",
+ "\n",
+ "L = symbol_shorthand.L\n",
+ "X = symbol_shorthand.X\n",
+ "\n",
+ "from gtsam.examples import SFMdata\n",
+ "from gtsam.utils import plot\n",
+ "\n",
+ "from gtsam import (Cal3_S2, DoglegOptimizer, GenericProjectionFactorCal3_S2,\n",
+ " Marginals, NonlinearFactorGraph, PinholeCameraCal3_S2,\n",
+ " PriorFactorPoint3, PriorFactorPose3, Values)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "ef2be028",
+ "metadata": {},
+ "source": [
+ "## 1. Scene and camera setup\n",
+ "\n",
+ "Ground-truth landmarks and poses come from the shared `SFMdata` helper module, same as `VisualISAMExample`. Here calibration `K` is known and fixed -- there's no self-calibration in this notebook."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "id": "581d8efa",
+ "metadata": {
+ "execution": {
+ "iopub.execute_input": "2026-07-22T10:42:52.342067Z",
+ "iopub.status.busy": "2026-07-22T10:42:52.341947Z",
+ "iopub.status.idle": "2026-07-22T10:42:52.343891Z",
+ "shell.execute_reply": "2026-07-22T10:42:52.343522Z"
+ }
+ },
+ "outputs": [],
+ "source": [
+ "# Define the camera calibration parameters\n",
+ "K = Cal3_S2(50.0, 50.0, 0.0, 50.0, 50.0)\n",
+ "\n",
+ "# Define the camera observation noise model\n",
+ "measurement_noise = gtsam.noiseModel.Isotropic.Sigma(2, 1.0) # one pixel in u and v\n",
+ "\n",
+ "# Create the set of ground-truth landmarks\n",
+ "points = SFMdata.createPoints()\n",
+ "\n",
+ "# Create the set of ground-truth poses\n",
+ "poses = SFMdata.createPoses()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "478fc6ad",
+ "metadata": {},
+ "source": [
+ "## 2. Build the factor graph\n",
+ "\n",
+ "A prior on pose `x0` indirectly fixes the origin of the whole reconstruction. Then, for every pose/landmark pair, we project the ground-truth landmark through the camera to get a simulated pixel measurement, and add a `GenericProjectionFactorCal3_S2` -- the same factor type used in `VisualISAMExample`, but here every observation goes into one graph, built entirely before optimization starts."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "id": "6d861248",
+ "metadata": {
+ "execution": {
+ "iopub.execute_input": "2026-07-22T10:42:52.344898Z",
+ "iopub.status.busy": "2026-07-22T10:42:52.344840Z",
+ "iopub.status.idle": "2026-07-22T10:42:52.347204Z",
+ "shell.execute_reply": "2026-07-22T10:42:52.346850Z"
+ }
+ },
+ "outputs": [],
+ "source": [
+ "# Create a factor graph\n",
+ "graph = NonlinearFactorGraph()\n",
+ "\n",
+ "# Add a prior on pose x1. This indirectly specifies where the origin is.\n",
+ "# 0.3 rad std on roll,pitch,yaw and 0.1m on x,y,z\n",
+ "pose_noise = gtsam.noiseModel.Diagonal.Sigmas(np.array([0.3, 0.3, 0.3, 0.1, 0.1, 0.1]))\n",
+ "factor = PriorFactorPose3(X(0), poses[0], pose_noise)\n",
+ "graph.push_back(factor)\n",
+ "\n",
+ "# Simulated measurements from each camera pose, adding them to the factor graph\n",
+ "for i, pose in enumerate(poses):\n",
+ " camera = PinholeCameraCal3_S2(pose, K)\n",
+ " for j, point in enumerate(points):\n",
+ " measurement = camera.project(point)\n",
+ " factor = GenericProjectionFactorCal3_S2(measurement, measurement_noise, X(i), L(j), K)\n",
+ " graph.push_back(factor)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "de63ef23",
+ "metadata": {},
+ "source": "## 3. Fix the scale ambiguity\n\nSFM alone can't distinguish a small scene photographed up close from a large scene photographed from far away -- the pixel measurements look identical either way. This is the same kind of ambiguity that makes self-calibration hard in `SelfCalibrationExample`, but here it's about *scale* rather than focal length. A single prior on landmark `l0` pins the distance between the first camera and the first landmark, and every other landmark position is interpreted relative to that scale."
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "id": "39c3e33e",
+ "metadata": {
+ "execution": {
+ "iopub.execute_input": "2026-07-22T10:42:52.348059Z",
+ "iopub.status.busy": "2026-07-22T10:42:52.348002Z",
+ "iopub.status.idle": "2026-07-22T10:42:52.350198Z",
+ "shell.execute_reply": "2026-07-22T10:42:52.349862Z"
+ }
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "NonlinearFactorGraph: size: 66\n",
+ "\n",
+ "Factor 0: PriorFactor on x0\n",
+ " prior mean: R: [\n",
+ "\t6.12323e-17, -6.12323e-17, -1;\n",
+ "\t1, 3.7494e-33, 6.12323e-17;\n",
+ "\t-0, -1, 6.12323e-17\n",
+ "]\n",
+ "t: 30 0 0\n",
+ " noise model: diagonal sigmas [0.3; 0.3; 0.3; 0.1; 0.1; 0.1];\n",
+ "\n",
+ "Factor 1: GenericProjectionFactor, z = [\n",
+ "\t75;\n",
+ "\t25\n",
+ "]\n",
+ " keys = { x0 l0 }\n",
+ " noise model: unit (2) \n",
+ "\n",
+ "Factor 2: GenericProjectionFactor, z = [\n",
+ "\t62.5;\n",
+ "\t37.5\n",
+ "]\n",
+ " keys = { x0 l1 }\n",
+ " noise model: unit (2) \n",
+ "\n",
+ "Factor 3: GenericProjectionFactor, z = [\n",
+ "\t37.5;\n",
+ "\t37.5\n",
+ "]\n",
+ " keys = { x0 l2 }\n",
+ " noise model: unit (2) \n",
+ "\n",
+ "Factor 4: GenericProjectionFactor, z = [\n",
+ "\t25;\n",
+ "\t25\n",
+ "]\n",
+ " keys = { x0 l3 }\n",
+ " noise model: unit (2) \n",
+ "\n",
+ "Factor 5: GenericProjectionFactor, z = [\n",
+ "\t75;\n",
+ "\t75\n",
+ "]\n",
+ " keys = { x0 l4 }\n",
+ " noise model: unit (2) \n",
+ "\n",
+ "Factor 6: GenericProjectionFactor, z = [\n",
+ "\t62.5;\n",
+ "\t62.5\n",
+ "]\n",
+ " keys = { x0 l5 }\n",
+ " noise model: unit (2) \n",
+ "\n",
+ "Factor 7: GenericProjectionFactor, z = [\n",
+ "\t37.5;\n",
+ "\t62.5\n",
+ "]\n",
+ " keys = { x0 l6 }\n",
+ " noise model: unit (2) \n",
+ "\n",
+ "Factor 8: GenericProjectionFactor, z = [\n",
+ "\t25;\n",
+ "\t75\n",
+ "]\n",
+ " keys = { x0 l7 }\n",
+ " noise model: unit (2) \n",
+ "\n",
+ "Factor 9: GenericProjectionFactor, z = [\n",
+ "\t50;\n",
+ "\t18.4699031\n",
+ "]\n",
+ " keys = { x1 l0 }\n",
+ " noise model: unit (2) \n",
+ "\n",
+ "Factor 10: GenericProjectionFactor, z = [\n",
+ "\t73.570226;\n",
+ "\t33.3333333\n",
+ "]\n",
+ " keys = { x1 l1 }\n",
+ " noise model: unit (2) \n",
+ "\n",
+ "Factor 11: GenericProjectionFactor, z = [\n",
+ "\t50;\n",
+ "\t38.672954\n",
+ "]\n",
+ " keys = { x1 l2 }\n",
+ " noise model: unit (2) \n",
+ "\n",
+ "Factor 12: GenericProjectionFactor, z = [\n",
+ "\t26.429774;\n",
+ "\t33.3333333\n",
+ "]\n",
+ " keys = { x1 l3 }\n",
+ " noise model: unit (2) \n",
+ "\n",
+ "Factor 13: GenericProjectionFactor, z = [\n",
+ "\t50;\n",
+ "\t81.5300969\n",
+ "]\n",
+ " keys = { x1 l4 }\n",
+ " noise model: unit (2) \n",
+ "\n",
+ "Factor 14: GenericProjectionFactor, z = [\n",
+ "\t73.570226;\n",
+ "\t66.6666667\n",
+ "]\n",
+ " keys = { x1 l5 }\n",
+ " noise model: unit (2) \n",
+ "\n",
+ "Factor 15: GenericProjectionFactor, z = [\n",
+ "\t50;\n",
+ "\t61.327046\n",
+ "]\n",
+ " keys = { x1 l6 }\n",
+ " noise model: unit (2) \n",
+ "\n",
+ "Factor 16: GenericProjectionFactor, z = [\n",
+ "\t26.429774;\n",
+ "\t66.6666667\n",
+ "]\n",
+ " keys = { x1 l7 }\n",
+ " noise model: unit (2) \n",
+ "\n",
+ "Factor 17: GenericProjectionFactor, z = [\n",
+ "\t25;\n",
+ "\t25\n",
+ "]\n",
+ " keys = { x2 l0 }\n",
+ " noise model: unit (2) \n",
+ "\n",
+ "Factor 18: GenericProjectionFactor, z = [\n",
+ "\t75;\n",
+ "\t25\n",
+ "]\n",
+ " keys = { x2 l1 }\n",
+ " noise model: unit (2) \n",
+ "\n",
+ "Factor 19: GenericProjectionFactor, z = [\n",
+ "\t62.5;\n",
+ "\t37.5\n",
+ "]\n",
+ " keys = { x2 l2 }\n",
+ " noise model: unit (2) \n",
+ "\n",
+ "Factor 20: GenericProjectionFactor, z = [\n",
+ "\t37.5;\n",
+ "\t37.5\n",
+ "]\n",
+ " keys = { x2 l3 }\n",
+ " noise model: unit (2) \n",
+ "\n",
+ "Factor 21: GenericProjectionFactor, z = [\n",
+ "\t25;\n",
+ "\t75\n",
+ "]\n",
+ " keys = { x2 l4 }\n",
+ " noise model: unit (2) \n",
+ "\n",
+ "Factor 22: GenericProjectionFactor, z = [\n",
+ "\t75;\n",
+ "\t75\n",
+ "]\n",
+ " keys = { x2 l5 }\n",
+ " noise model: unit (2) \n",
+ "\n",
+ "Factor 23: GenericProjectionFactor, z = [\n",
+ "\t62.5;\n",
+ "\t62.5\n",
+ "]\n",
+ " keys = { x2 l6 }\n",
+ " noise model: unit (2) \n",
+ "\n",
+ "Factor 24: GenericProjectionFactor, z = [\n",
+ "\t37.5;\n",
+ "\t62.5\n",
+ "]\n",
+ " keys = { x2 l7 }\n",
+ " noise model: unit (2) \n",
+ "\n",
+ "Factor 25: GenericProjectionFactor, z = [\n",
+ "\t26.429774;\n",
+ "\t33.3333333\n",
+ "]\n",
+ " keys = { x3 l0 }\n",
+ " noise model: unit (2) \n",
+ "\n",
+ "Factor 26: GenericProjectionFactor, z = [\n",
+ "\t50;\n",
+ "\t18.4699031\n",
+ "]\n",
+ " keys = { x3 l1 }\n",
+ " noise model: unit (2) \n",
+ "\n",
+ "Factor 27: GenericProjectionFactor, z = [\n",
+ "\t73.570226;\n",
+ "\t33.3333333\n",
+ "]\n",
+ " keys = { x3 l2 }\n",
+ " noise model: unit (2) \n",
+ "\n",
+ "Factor 28: GenericProjectionFactor, z = [\n",
+ "\t50;\n",
+ "\t38.672954\n",
+ "]\n",
+ " keys = { x3 l3 }\n",
+ " noise model: unit (2) \n",
+ "\n",
+ "Factor 29: GenericProjectionFactor, z = [\n",
+ "\t26.429774;\n",
+ "\t66.6666667\n",
+ "]\n",
+ " keys = { x3 l4 }\n",
+ " noise model: unit (2) \n",
+ "\n",
+ "Factor 30: GenericProjectionFactor, z = [\n",
+ "\t50;\n",
+ "\t81.5300969\n",
+ "]\n",
+ " keys = { x3 l5 }\n",
+ " noise model: unit (2) \n",
+ "\n",
+ "Factor 31: GenericProjectionFactor, z = [\n",
+ "\t73.570226;\n",
+ "\t66.6666667\n",
+ "]\n",
+ " keys = { x3 l6 }\n",
+ " noise model: unit (2) \n",
+ "\n",
+ "Factor 32: GenericProjectionFactor, z = [\n",
+ "\t50;\n",
+ "\t61.327046\n",
+ "]\n",
+ " keys = { x3 l7 }\n",
+ " noise model: unit (2) \n",
+ "\n",
+ "Factor 33: GenericProjectionFactor, z = [\n",
+ "\t37.5;\n",
+ "\t37.5\n",
+ "]\n",
+ " keys = { x4 l0 }\n",
+ " noise model: unit (2) \n",
+ "\n",
+ "Factor 34: GenericProjectionFactor, z = [\n",
+ "\t25;\n",
+ "\t25\n",
+ "]\n",
+ " keys = { x4 l1 }\n",
+ " noise model: unit (2) \n",
+ "\n",
+ "Factor 35: GenericProjectionFactor, z = [\n",
+ "\t75;\n",
+ "\t25\n",
+ "]\n",
+ " keys = { x4 l2 }\n",
+ " noise model: unit (2) \n",
+ "\n",
+ "Factor 36: GenericProjectionFactor, z = [\n",
+ "\t62.5;\n",
+ "\t37.5\n",
+ "]\n",
+ " keys = { x4 l3 }\n",
+ " noise model: unit (2) \n",
+ "\n",
+ "Factor 37: GenericProjectionFactor, z = [\n",
+ "\t37.5;\n",
+ "\t62.5\n",
+ "]\n",
+ " keys = { x4 l4 }\n",
+ " noise model: unit (2) \n",
+ "\n",
+ "Factor 38: GenericProjectionFactor, z = [\n",
+ "\t25;\n",
+ "\t75\n",
+ "]\n",
+ " keys = { x4 l5 }\n",
+ " noise model: unit (2) \n",
+ "\n",
+ "Factor 39: GenericProjectionFactor, z = [\n",
+ "\t75;\n",
+ "\t75\n",
+ "]\n",
+ " keys = { x4 l6 }\n",
+ " noise model: unit (2) \n",
+ "\n",
+ "Factor 40: GenericProjectionFactor, z = [\n",
+ "\t62.5;\n",
+ "\t62.5\n",
+ "]\n",
+ " keys = { x4 l7 }\n",
+ " noise model: unit (2) \n",
+ "\n",
+ "Factor 41: GenericProjectionFactor, z = [\n",
+ "\t50;\n",
+ "\t38.672954\n",
+ "]\n",
+ " keys = { x5 l0 }\n",
+ " noise model: unit (2) \n",
+ "\n",
+ "Factor 42: GenericProjectionFactor, z = [\n",
+ "\t26.429774;\n",
+ "\t33.3333333\n",
+ "]\n",
+ " keys = { x5 l1 }\n",
+ " noise model: unit (2) \n",
+ "\n",
+ "Factor 43: GenericProjectionFactor, z = [\n",
+ "\t50;\n",
+ "\t18.4699031\n",
+ "]\n",
+ " keys = { x5 l2 }\n",
+ " noise model: unit (2) \n",
+ "\n",
+ "Factor 44: GenericProjectionFactor, z = [\n",
+ "\t73.570226;\n",
+ "\t33.3333333\n",
+ "]\n",
+ " keys = { x5 l3 }\n",
+ " noise model: unit (2) \n",
+ "\n",
+ "Factor 45: GenericProjectionFactor, z = [\n",
+ "\t50;\n",
+ "\t61.327046\n",
+ "]\n",
+ " keys = { x5 l4 }\n",
+ " noise model: unit (2) \n",
+ "\n",
+ "Factor 46: GenericProjectionFactor, z = [\n",
+ "\t26.429774;\n",
+ "\t66.6666667\n",
+ "]\n",
+ " keys = { x5 l5 }\n",
+ " noise model: unit (2) \n",
+ "\n",
+ "Factor 47: GenericProjectionFactor, z = [\n",
+ "\t50;\n",
+ "\t81.5300969\n",
+ "]\n",
+ " keys = { x5 l6 }\n",
+ " noise model: unit (2) \n",
+ "\n",
+ "Factor 48: GenericProjectionFactor, z = [\n",
+ "\t73.570226;\n",
+ "\t66.6666667\n",
+ "]\n",
+ " keys = { x5 l7 }\n",
+ " noise model: unit (2) \n",
+ "\n",
+ "Factor 49: GenericProjectionFactor, z = [\n",
+ "\t62.5;\n",
+ "\t37.5\n",
+ "]\n",
+ " keys = { x6 l0 }\n",
+ " noise model: unit (2) \n",
+ "\n",
+ "Factor 50: GenericProjectionFactor, z = [\n",
+ "\t37.5;\n",
+ "\t37.5\n",
+ "]\n",
+ " keys = { x6 l1 }\n",
+ " noise model: unit (2) \n",
+ "\n",
+ "Factor 51: GenericProjectionFactor, z = [\n",
+ "\t25;\n",
+ "\t25\n",
+ "]\n",
+ " keys = { x6 l2 }\n",
+ " noise model: unit (2) \n",
+ "\n",
+ "Factor 52: GenericProjectionFactor, z = [\n",
+ "\t75;\n",
+ "\t25\n",
+ "]\n",
+ " keys = { x6 l3 }\n",
+ " noise model: unit (2) \n",
+ "\n",
+ "Factor 53: GenericProjectionFactor, z = [\n",
+ "\t62.5;\n",
+ "\t62.5\n",
+ "]\n",
+ " keys = { x6 l4 }\n",
+ " noise model: unit (2) \n",
+ "\n",
+ "Factor 54: GenericProjectionFactor, z = [\n",
+ "\t37.5;\n",
+ "\t62.5\n",
+ "]\n",
+ " keys = { x6 l5 }\n",
+ " noise model: unit (2) \n",
+ "\n",
+ "Factor 55: GenericProjectionFactor, z = [\n",
+ "\t25;\n",
+ "\t75\n",
+ "]\n",
+ " keys = { x6 l6 }\n",
+ " noise model: unit (2) \n",
+ "\n",
+ "Factor 56: GenericProjectionFactor, z = [\n",
+ "\t75;\n",
+ "\t75\n",
+ "]\n",
+ " keys = { x6 l7 }\n",
+ " noise model: unit (2) \n",
+ "\n",
+ "Factor 57: GenericProjectionFactor, z = [\n",
+ "\t73.570226;\n",
+ "\t33.3333333\n",
+ "]\n",
+ " keys = { x7 l0 }\n",
+ " noise model: unit (2) \n",
+ "\n",
+ "Factor 58: GenericProjectionFactor, z = [\n",
+ "\t50;\n",
+ "\t38.672954\n",
+ "]\n",
+ " keys = { x7 l1 }\n",
+ " noise model: unit (2) \n",
+ "\n",
+ "Factor 59: GenericProjectionFactor, z = [\n",
+ "\t26.429774;\n",
+ "\t33.3333333\n",
+ "]\n",
+ " keys = { x7 l2 }\n",
+ " noise model: unit (2) \n",
+ "\n",
+ "Factor 60: GenericProjectionFactor, z = [\n",
+ "\t50;\n",
+ "\t18.4699031\n",
+ "]\n",
+ " keys = { x7 l3 }\n",
+ " noise model: unit (2) \n",
+ "\n",
+ "Factor 61: GenericProjectionFactor, z = [\n",
+ "\t73.570226;\n",
+ "\t66.6666667\n",
+ "]\n",
+ " keys = { x7 l4 }\n",
+ " noise model: unit (2) \n",
+ "\n",
+ "Factor 62: GenericProjectionFactor, z = [\n",
+ "\t50;\n",
+ "\t61.327046\n",
+ "]\n",
+ " keys = { x7 l5 }\n",
+ " noise model: unit (2) \n",
+ "\n",
+ "Factor 63: GenericProjectionFactor, z = [\n",
+ "\t26.429774;\n",
+ "\t66.6666667\n",
+ "]\n",
+ " keys = { x7 l6 }\n",
+ " noise model: unit (2) \n",
+ "\n",
+ "Factor 64: GenericProjectionFactor, z = [\n",
+ "\t50;\n",
+ "\t81.5300969\n",
+ "]\n",
+ " keys = { x7 l7 }\n",
+ " noise model: unit (2) \n",
+ "\n",
+ "Factor 65: PriorFactor on l0\n",
+ " prior mean: [\n",
+ "\t10;\n",
+ "\t10;\n",
+ "\t10\n",
+ "]\n",
+ "isotropic dim=3 sigma=0.1\n",
+ "\n",
+ "\n"
+ ]
+ }
+ ],
+ "source": [
+ "point_noise = gtsam.noiseModel.Isotropic.Sigma(3, 0.1)\n",
+ "factor = PriorFactorPoint3(L(0), points[0], point_noise)\n",
+ "graph.push_back(factor)\n",
+ "print(graph)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "74af7db9",
+ "metadata": {},
+ "source": "## 4. Initial estimate\n\nUnlike `VisualISAMExample` and `SelfCalibrationExample`, which perturb the ground truth by a single fixed offset, this one draws independent random Gaussian noise for every pose and landmark (`numpy`'s `default_rng`, with no fixed seed) -- so the exact initial values, and the optimizer's exact path, will differ each time this notebook runs. The qualitative outcome won't: Dogleg should still converge to the true reconstruction."
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 6,
+ "id": "6d4c524b",
+ "metadata": {
+ "execution": {
+ "iopub.execute_input": "2026-07-22T10:42:52.351107Z",
+ "iopub.status.busy": "2026-07-22T10:42:52.351058Z",
+ "iopub.status.idle": "2026-07-22T10:42:52.372343Z",
+ "shell.execute_reply": "2026-07-22T10:42:52.372000Z"
+ }
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Values with 16 values:\n",
+ "Value l0: (Eigen::Matrix)\n",
+ "[\n",
+ "\t10.0869602;\n",
+ "\t9.96091842;\n",
+ "\t10.1211717\n",
+ "]\n",
+ "\n",
+ "Value l1: (Eigen::Matrix)\n",
+ "[\n",
+ "\t-10.1295932;\n",
+ "\t9.97613053;\n",
+ "\t9.94859734\n",
+ "]\n",
+ "\n",
+ "Value l2: (Eigen::Matrix)\n",
+ "[\n",
+ "\t-9.96875639;\n",
+ "\t-9.89461118;\n",
+ "\t10.0942002\n",
+ "]\n",
+ "\n",
+ "Value l3: (Eigen::Matrix)\n",
+ "[\n",
+ "\t9.93882244;\n",
+ "\t-9.98982859;\n",
+ "\t10.0902699\n",
+ "]\n",
+ "\n",
+ "Value l4: (Eigen::Matrix)\n",
+ "[\n",
+ "\t10.1333898;\n",
+ "\t10.0027059;\n",
+ "\t-9.91343828\n",
+ "]\n",
+ "\n",
+ "Value l5: (Eigen::Matrix)\n",
+ "[\n",
+ "\t-10.079499;\n",
+ "\t10.0780763;\n",
+ "\t-9.9280996\n",
+ "]\n",
+ "\n",
+ "Value l6: (Eigen::Matrix)\n",
+ "[\n",
+ "\t-9.97038322;\n",
+ "\t-10.0010005;\n",
+ "\t-9.83838347\n",
+ "]\n",
+ "\n",
+ "Value l7: (Eigen::Matrix)\n",
+ "[\n",
+ "\t10.0938091;\n",
+ "\t-10.0271396;\n",
+ "\t-9.92943968\n",
+ "]\n",
+ "\n",
+ "Value x0: (gtsam::Pose3)\n",
+ "R: [\n",
+ "\t0.00131051623, -0.0734329544, -0.997299295;\n",
+ "\t0.999993616, -0.00321905278, 0.00155108143;\n",
+ "\t-0.00332425956, -0.997294961, 0.073428267\n",
+ "]\n",
+ "t: 29.974475 -0.0698303209 0.0430406692\n",
+ "\n",
+ "Value x1: (gtsam::Pose3)\n",
+ "R: [\n",
+ "\t-0.665185431, 0.114759798, -0.737806568;\n",
+ "\t0.737022932, -0.0574783422, -0.673419215;\n",
+ "\t-0.119689351, -0.99172901, -0.0463468469\n",
+ "]\n",
+ "t: 21.1672625 21.3576308 0.0634480418\n",
+ "\n",
+ "Value x2: (gtsam::Pose3)\n",
+ "R: [\n",
+ "\t-0.990873985, 0.081237772, -0.107560075;\n",
+ "\t0.108299855, 0.00474273315, -0.99410696;\n",
+ "\t-0.0802489059, -0.996683466, -0.0134974898\n",
+ "]\n",
+ "t: -0.130879308 30.0861009 -0.0149462005\n",
+ "\n",
+ "Value x3: (gtsam::Pose3)\n",
+ "R: [\n",
+ "\t-0.682506082, -0.0162543169, 0.730699148;\n",
+ "\t-0.730836216, 0.0261097035, -0.682053303;\n",
+ "\t-0.00799202752, -0.999526928, -0.0296992749\n",
+ "]\n",
+ "t: -21.212913 21.2644247 0.211772482\n",
+ "\n",
+ "Value x4: (gtsam::Pose3)\n",
+ "R: [\n",
+ "\t-0.0265612539, -0.213293, 0.976627153;\n",
+ "\t-0.990504247, -0.12621665, -0.0545040781;\n",
+ "\t0.134891946, -0.968801039, -0.20791515\n",
+ "]\n",
+ "t: -30.0002013 -0.075629172 -0.106982031\n",
+ "\n",
+ "Value x5: (gtsam::Pose3)\n",
+ "R: [\n",
+ "\t0.845260334, 0.0912523278, 0.526505442;\n",
+ "\t-0.534136157, 0.172465482, 0.827619613;\n",
+ "\t-0.0152817985, -0.980779624, 0.194519398\n",
+ "]\n",
+ "t: -21.128498 -21.2672825 -0.00482831433\n",
+ "\n",
+ "Value x6: (gtsam::Pose3)\n",
+ "R: [\n",
+ "\t0.994031577, 0.0975818607, 0.0487750416;\n",
+ "\t-0.0543631594, 0.0554502293, 0.9969804;\n",
+ "\t0.0945826153, -0.993681565, 0.0604241371\n",
+ "]\n",
+ "t: -0.123212357 -29.9287294 -0.0468568972\n",
+ "\n",
+ "Value x7: (gtsam::Pose3)\n",
+ "R: [\n",
+ "\t0.777697232, -0.0300103369, -0.627922285;\n",
+ "\t0.627590223, -0.0206101649, 0.778270989;\n",
+ "\t-0.0362977564, -0.999337081, 0.00280572587\n",
+ "]\n",
+ "t: 21.0784461 -21.3299146 -0.151653135\n",
+ "\n",
+ "\n"
+ ]
+ }
+ ],
+ "source": [
+ "# Create the data structure to hold the initial estimate to the solution\n",
+ "# Intentionally initialize the variables off from the ground truth\n",
+ "initial_estimate = Values()\n",
+ "rng = np.random.default_rng()\n",
+ "for i, pose in enumerate(poses):\n",
+ " transformed_pose = pose.retract(0.1 * rng.standard_normal(6).reshape(6, 1))\n",
+ " initial_estimate.insert(X(i), transformed_pose)\n",
+ "for j, point in enumerate(points):\n",
+ " transformed_point = point + 0.1 * rng.standard_normal(3)\n",
+ " initial_estimate.insert(L(j), transformed_point)\n",
+ "print(initial_estimate)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "426cca10",
+ "metadata": {},
+ "source": [
+ "## 5. Optimize with Dogleg\n",
+ "\n",
+ "`setVerbosity(\"TERMINATION\")` makes the optimizer print why and when it stopped. We also print the graph error before and after optimization, to see how far the solution moved."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "id": "5d041e25",
+ "metadata": {
+ "execution": {
+ "iopub.execute_input": "2026-07-22T10:42:52.373307Z",
+ "iopub.status.busy": "2026-07-22T10:42:52.373224Z",
+ "iopub.status.idle": "2026-07-22T10:42:52.379404Z",
+ "shell.execute_reply": "2026-07-22T10:42:52.379138Z"
+ }
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Optimizing:\n",
+ "Values with 16 values:\n",
+ "Value l0: (Eigen::Matrix)\n",
+ "[\n",
+ "\t10;\n",
+ "\t10;\n",
+ "\t10\n",
+ "]\n",
+ "\n",
+ "Value l1: (Eigen::Matrix)\n",
+ "[\n",
+ "\t-10;\n",
+ "\t9.99999999997;\n",
+ "\t9.99999999995\n",
+ "]\n",
+ "\n",
+ "Value l2: (Eigen::Matrix)\n",
+ "[\n",
+ "\t-10;\n",
+ "\t-10;\n",
+ "\t9.99999999998\n",
+ "]\n",
+ "\n",
+ "Value l3: (Eigen::Matrix)\n",
+ "[\n",
+ "\t9.99999999997;\n",
+ "\t-10;\n",
+ "\t9.99999999998\n",
+ "]\n",
+ "\n",
+ "Value l4: (Eigen::Matrix)\n",
+ "[\n",
+ "\t10;\n",
+ "\t9.99999999999;\n",
+ "\t-10\n",
+ "]\n",
+ "\n",
+ "Value l5: (Eigen::Matrix)\n",
+ "[\n",
+ "\t-9.99999999999;\n",
+ "\t9.99999999995;\n",
+ "\t-10\n",
+ "]\n",
+ "\n",
+ "Value l6: (Eigen::Matrix)\n",
+ "[\n",
+ "\t-10;\n",
+ "\t-10;\n",
+ "\t-10\n",
+ "]\n",
+ "\n",
+ "Value l7: (Eigen::Matrix)\n",
+ "[\n",
+ "\t9.99999999998;\n",
+ "\t-10;\n",
+ "\t-10\n",
+ "]\n",
+ "\n",
+ "Value x0: (gtsam::Pose3)\n",
+ "R: [\n",
+ "\t-1.84188244614e-13, 7.46359676361e-13, -1;\n",
+ "\t1, -2.81088838409e-13, -1.84188226178e-13;\n",
+ "\t-2.81088872272e-13, -1, -7.46360412373e-13\n",
+ "]\n",
+ "t: 30 -1.61865886803e-16 -3.28505942941e-15\n",
+ "\n",
+ "Value x1: (gtsam::Pose3)\n",
+ "R: [\n",
+ "\t-0.707106781184, -3.17775310427e-12, -0.707106781189;\n",
+ "\t0.707106781189, -4.60703908495e-12, -0.707106781184;\n",
+ "\t-1.01064974305e-12, -1, 5.50466383678e-12\n",
+ "]\n",
+ "t: 21.2132034354 21.2132034351 -3.07519530626e-10\n",
+ "\n",
+ "Value x2: (gtsam::Pose3)\n",
+ "R: [\n",
+ "\t-1, 7.56473606448e-13, -4.77949902748e-13;\n",
+ "\t4.77958986821e-13, -8.80037401312e-13, -1;\n",
+ "\t-7.56480167271e-13, -1, 8.80034286343e-13\n",
+ "]\n",
+ "t: 2.22749230661e-11 30 -5.59961028114e-11\n",
+ "\n",
+ "Value x3: (gtsam::Pose3)\n",
+ "R: [\n",
+ "\t-0.707106781186, 7.17443062891e-13, 0.707106781187;\n",
+ "\t-0.707106781187, -6.11028459807e-13, -0.707106781186;\n",
+ "\t-7.52451429824e-14, -1, 9.39375238228e-13\n",
+ "]\n",
+ "t: -21.2132034356 21.2132034356 -5.20548435797e-11\n",
+ "\n",
+ "Value x4: (gtsam::Pose3)\n",
+ "R: [\n",
+ "\t4.0845663467e-12, -1.90256354363e-12, 1;\n",
+ "\t-1, 4.28900112879e-12, 4.0845287159e-12;\n",
+ "\t-4.28902492648e-12, -1, -1.90250258966e-12\n",
+ "]\n",
+ "t: -29.9999999999 -1.86313558169e-10 1.12011956324e-10\n",
+ "\n",
+ "Value x5: (gtsam::Pose3)\n",
+ "R: [\n",
+ "\t0.707106781186, 9.17467623651e-13, 0.707106781187;\n",
+ "\t-0.707106781187, -4.51588072991e-13, 0.707106781186;\n",
+ "\t9.680868399e-13, -1, 3.29450123822e-13\n",
+ "]\n",
+ "t: -21.2132034356 -21.2132034356 -3.59258356179e-11\n",
+ "\n",
+ "Value x6: (gtsam::Pose3)\n",
+ "R: [\n",
+ "\t1, 3.21599739599e-13, 1.48710899624e-12;\n",
+ "\t-1.48712221702e-12, -3.71300031128e-13, 1;\n",
+ "\t3.2158925091e-13, -1, -3.71296412687e-13\n",
+ "]\n",
+ "t: -7.57587293883e-11 -30 -1.57067366298e-11\n",
+ "\n",
+ "Value x7: (gtsam::Pose3)\n",
+ "R: [\n",
+ "\t0.707106781187, 6.96749637853e-13, -0.707106781186;\n",
+ "\t0.707106781186, -5.59419566937e-13, 0.707106781187;\n",
+ "\t9.71081033156e-14, -1, -8.88244183997e-13\n",
+ "]\n",
+ "t: 21.2132034356 -21.2132034356 2.90409832163e-12\n",
+ "\n",
+ "\n",
+ "initial error = 2643.125976874687\n",
+ "final error = 2.1323412899969166e-18\n",
+ "converged\n",
+ "errorThreshold: 2.13234129e-18 0\n",
+ "absoluteDecrease: 1.29489902289e-07 1e-05\n",
+ "relativeDecrease: 0.999999999984 1e-05\n",
+ "iterations: 4 >? 100\n"
+ ]
+ }
+ ],
+ "source": [
+ "params = gtsam.DoglegParams()\n",
+ "params.setVerbosity(\"TERMINATION\")\n",
+ "optimizer = DoglegOptimizer(graph, initial_estimate, params)\n",
+ "print(\"Optimizing:\")\n",
+ "result = optimizer.optimize()\n",
+ "print(result)\n",
+ "print(\"initial error = {}\".format(graph.error(initial_estimate)))\n",
+ "print(\"final error = {}\".format(graph.error(result)))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "ff306405",
+ "metadata": {},
+ "source": [
+ "## 6. Visualize with uncertainty\n",
+ "\n",
+ "As in `OdometryExample`, we compute `Marginals` on the batch result and plot each landmark and camera pose together with its covariance ellipse -- only now in 3D, showing the recovered cube of landmarks and the recovered camera trajectory around it side by side."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 8,
+ "id": "d1e7f87d",
+ "metadata": {
+ "execution": {
+ "iopub.execute_input": "2026-07-22T10:42:52.380354Z",
+ "iopub.status.busy": "2026-07-22T10:42:52.380297Z",
+ "iopub.status.idle": "2026-07-22T10:42:52.471970Z",
+ "shell.execute_reply": "2026-07-22T10:42:52.471642Z"
+ }
+ },
+ "outputs": [
+ {
+ "data": {
+ "image/png": "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",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "marginals = Marginals(graph, result)\n",
+ "plot.plot_3d_points(1, result, marginals=marginals)\n",
+ "plot.plot_trajectory(1, result, marginals=marginals, scale=8)\n",
+ "plot.set_axes_equal(1)\n",
+ "plt.show()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "69727f60",
+ "metadata": {},
+ "source": [
+ "The final error should be many orders of magnitude smaller than the initial error, and the plot above should show landmarks close to a cube and poses close to a circular orbit -- confirming that Dogleg recovered the true reconstruction from a randomly perturbed start, using nothing but pixel observations, a single pose prior to fix the origin, and a single landmark prior to fix the scale."
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.13.12"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
\ No newline at end of file
diff --git a/python/gtsam/examples/SFMExample.py b/python/gtsam/examples/SFMExample.py
deleted file mode 100644
index d8d0ae1dfe..0000000000
--- a/python/gtsam/examples/SFMExample.py
+++ /dev/null
@@ -1,124 +0,0 @@
-"""
-GTSAM Copyright 2010, Georgia Tech Research Corporation,
-Atlanta, Georgia 30332-0415
-All Rights Reserved
-Authors: Frank Dellaert, et al. (see THANKS for the full author list)
-
-See LICENSE for the license information
-
-A structure-from-motion problem on a simulated dataset
-"""
-
-import matplotlib.pyplot as plt
-import numpy as np
-
-import gtsam
-from gtsam import symbol_shorthand
-
-L = symbol_shorthand.L
-X = symbol_shorthand.X
-
-from gtsam.examples import SFMdata
-from gtsam.utils import plot
-
-from gtsam import (Cal3_S2, DoglegOptimizer, GenericProjectionFactorCal3_S2,
- Marginals, NonlinearFactorGraph, PinholeCameraCal3_S2,
- PriorFactorPoint3, PriorFactorPose3, Values)
-
-
-def main():
- """
- Camera observations of landmarks (i.e. pixel coordinates) will be stored as Point2 (x, y).
-
- Each variable in the system (poses and landmarks) must be identified with a unique key.
- We can either use simple integer keys (1, 2, 3, ...) or symbols (X1, X2, L1).
- Here we will use Symbols
-
- In GTSAM, measurement functions are represented as 'factors'. Several common factors
- have been provided with the library for solving robotics/SLAM/Bundle Adjustment problems.
- Here we will use Projection factors to model the camera's landmark observations.
- Also, we will initialize the robot at some location using a Prior factor.
-
- When the factors are created, we will add them to a Factor Graph. As the factors we are using
- are nonlinear factors, we will need a Nonlinear Factor Graph.
-
- Finally, once all of the factors have been added to our factor graph, we will want to
- solve/optimize to graph to find the best (Maximum A Posteriori) set of variable values.
- GTSAM includes several nonlinear optimizers to perform this step. Here we will use a
- trust-region method known as Powell's Dogleg
-
- The nonlinear solvers within GTSAM are iterative solvers, meaning they linearize the
- nonlinear functions around an initial linearization point, then solve the linear system
- to update the linearization point. This happens repeatedly until the solver converges
- to a consistent set of variable values. This requires us to specify an initial guess
- for each variable, held in a Values container.
- """
-
- # Define the camera calibration parameters
- K = Cal3_S2(50.0, 50.0, 0.0, 50.0, 50.0)
-
- # Define the camera observation noise model
- measurement_noise = gtsam.noiseModel.Isotropic.Sigma(2, 1.0) # one pixel in u and v
-
- # Create the set of ground-truth landmarks
- points = SFMdata.createPoints()
-
- # Create the set of ground-truth poses
- poses = SFMdata.createPoses()
-
- # Create a factor graph
- graph = NonlinearFactorGraph()
-
- # Add a prior on pose x1. This indirectly specifies where the origin is.
- # 0.3 rad std on roll,pitch,yaw and 0.1m on x,y,z
- pose_noise = gtsam.noiseModel.Diagonal.Sigmas(np.array([0.3, 0.3, 0.3, 0.1, 0.1, 0.1]))
- factor = PriorFactorPose3(X(0), poses[0], pose_noise)
- graph.push_back(factor)
-
- # Simulated measurements from each camera pose, adding them to the factor graph
- for i, pose in enumerate(poses):
- camera = PinholeCameraCal3_S2(pose, K)
- for j, point in enumerate(points):
- measurement = camera.project(point)
- factor = GenericProjectionFactorCal3_S2(measurement, measurement_noise, X(i), L(j), K)
- graph.push_back(factor)
-
- # Because the structure-from-motion problem has a scale ambiguity, the problem is still under-constrained
- # Here we add a prior on the position of the first landmark. This fixes the scale by indicating the distance
- # between the first camera and the first landmark. All other landmark positions are interpreted using this scale.
- point_noise = gtsam.noiseModel.Isotropic.Sigma(3, 0.1)
- factor = PriorFactorPoint3(L(0), points[0], point_noise)
- graph.push_back(factor)
- graph.print("Factor Graph:\n")
-
- # Create the data structure to hold the initial estimate to the solution
- # Intentionally initialize the variables off from the ground truth
- initial_estimate = Values()
- rng = np.random.default_rng()
- for i, pose in enumerate(poses):
- transformed_pose = pose.retract(0.1 * rng.standard_normal(6).reshape(6, 1))
- initial_estimate.insert(X(i), transformed_pose)
- for j, point in enumerate(points):
- transformed_point = point + 0.1 * rng.standard_normal(3)
- initial_estimate.insert(L(j), transformed_point)
- initial_estimate.print("Initial Estimates:\n")
-
- # Optimize the graph and print results
- params = gtsam.DoglegParams()
- params.setVerbosity("TERMINATION")
- optimizer = DoglegOptimizer(graph, initial_estimate, params)
- print("Optimizing:")
- result = optimizer.optimize()
- result.print("Final results:\n")
- print("initial error = {}".format(graph.error(initial_estimate)))
- print("final error = {}".format(graph.error(result)))
-
- marginals = Marginals(graph, result)
- plot.plot_3d_points(1, result, marginals=marginals)
- plot.plot_trajectory(1, result, marginals=marginals, scale=8)
- plot.set_axes_equal(1)
- plt.show()
-
-
-if __name__ == "__main__":
- main()
diff --git a/python/gtsam/examples/SelfCalibrationExample.ipynb b/python/gtsam/examples/SelfCalibrationExample.ipynb
new file mode 100644
index 0000000000..00de462b3f
--- /dev/null
+++ b/python/gtsam/examples/SelfCalibrationExample.ipynb
@@ -0,0 +1,562 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "a19ea5ea",
+ "metadata": {},
+ "source": [
+ "# Self-Calibration Example\n",
+ "\n",
+ "In `VisualISAMExample`, the camera calibration `K` was assumed known and fixed. Real cameras often aren't calibrated ahead of time, so this notebook solves for `K` jointly with the poses and landmarks -- a technique called **self-calibration** (or auto-calibration).\n",
+ "\n",
+ "Self-calibration is fundamentally harder than ordinary structure-from-motion: an unknown focal length introduces an extra ambiguity, since a farther, larger scene photographed with a longer lens can look almost identical in the image to a closer, smaller scene photographed with a shorter lens. Left unconstrained, this ambiguity has no unique solution -- so, in addition to the usual pose and landmark priors, we also need a prior on the calibration itself to pin the problem down.\n",
+ "\n",
+ "This notebook is a direct transcription of `examples/SelfCalibrationExample.cpp`; the scene (a 10-meter cube of landmarks, 8 cameras circling it) is regenerated locally rather than imported from the shared `SFMdata` helper module, to stay a faithful match to the C++ original."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "0231ad4a",
+ "metadata": {},
+ "source": [
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "512a9b3c",
+ "metadata": {},
+ "source": [
+ "GTSAM Copyright 2010-2026, Georgia Tech Research Corporation,\n",
+ "Atlanta, Georgia 30332-0415\n",
+ "All Rights Reserved\n",
+ "\n",
+ "Authors: Frank Dellaert, et al. (see THANKS for the full author list)\n",
+ "\n",
+ "See LICENSE for the license information"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "7db7fc29",
+ "metadata": {
+ "execution": {
+ "iopub.execute_input": "2026-07-22T10:41:15.287354Z",
+ "iopub.status.busy": "2026-07-22T10:41:15.287158Z",
+ "iopub.status.idle": "2026-07-22T10:41:15.292981Z",
+ "shell.execute_reply": "2026-07-22T10:41:15.292206Z"
+ }
+ },
+ "outputs": [],
+ "source": [
+ "try:\n",
+ " import google.colab\n",
+ " %pip install --quiet gtsam-develop\n",
+ "except ImportError:\n",
+ " pass"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "id": "8f075784",
+ "metadata": {
+ "execution": {
+ "iopub.execute_input": "2026-07-22T10:41:15.295051Z",
+ "iopub.status.busy": "2026-07-22T10:41:15.294880Z",
+ "iopub.status.idle": "2026-07-22T10:41:15.495165Z",
+ "shell.execute_reply": "2026-07-22T10:41:15.494711Z"
+ }
+ },
+ "outputs": [],
+ "source": [
+ "import math\n",
+ "\n",
+ "from gtsam import Cal3_S2\n",
+ "from gtsam.noiseModel import Diagonal, Isotropic\n",
+ "\n",
+ "# SFM-specific factors\n",
+ "from gtsam import GeneralSFMFactor2Cal3_S2 # does calibration !\n",
+ "from gtsam import PinholeCameraCal3_S2\n",
+ "\n",
+ "# Camera observations of landmarks (i.e. pixel coordinates) will be stored as Point2 (x, y).\n",
+ "from gtsam import Point2\n",
+ "from gtsam import Point3, Pose3, Rot3\n",
+ "\n",
+ "# Inference and optimization\n",
+ "from gtsam import NonlinearFactorGraph, DoglegOptimizer, Values\n",
+ "from gtsam.symbol_shorthand import K, L, X"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "cb98ea95",
+ "metadata": {},
+ "source": [
+ "## 1. Scene setup\n",
+ "\n",
+ "Same scene shape as the `VisualISAMExample` notebook -- a 10-meter landmark cube, 8 poses on a circular orbit always facing the center -- regenerated here directly instead of via the shared helper module."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "id": "eeffdd3c",
+ "metadata": {
+ "execution": {
+ "iopub.execute_input": "2026-07-22T10:41:15.496597Z",
+ "iopub.status.busy": "2026-07-22T10:41:15.496523Z",
+ "iopub.status.idle": "2026-07-22T10:41:15.499127Z",
+ "shell.execute_reply": "2026-07-22T10:41:15.498769Z"
+ }
+ },
+ "outputs": [],
+ "source": [
+ "def createPoints() -> list[Point3]:\n",
+ " \"\"\"Create the set of ground-truth landmarks\"\"\"\n",
+ " return [\n",
+ " Point3(10.0, 10.0, 10.0),\n",
+ " Point3(-10.0, 10.0, 10.0),\n",
+ " Point3(-10.0, -10.0, 10.0),\n",
+ " Point3(10.0, -10.0, 10.0),\n",
+ " Point3(10.0, 10.0, -10.0),\n",
+ " Point3(-10.0, 10.0, -10.0),\n",
+ " Point3(-10.0, -10.0, -10.0),\n",
+ " Point3(10.0, -10.0, -10.0),\n",
+ " ]\n",
+ "\n",
+ "\n",
+ "def createPoses(\n",
+ " init: Pose3 = Pose3(Rot3.Ypr(math.pi / 2, 0, -math.pi / 2), Point3(30, 0, 0)),\n",
+ " delta: Pose3 = Pose3(\n",
+ " Rot3.Ypr(0, -math.pi / 4, 0),\n",
+ " Point3(math.sin(math.pi / 4) * 30, 0, 30 * (1 - math.sin(math.pi / 4))),\n",
+ " ),\n",
+ " steps: int = 8,\n",
+ ") -> list[Pose3]:\n",
+ " \"\"\"Create the set of ground-truth poses: a circular trajectory, radius 30\n",
+ " at pi/4 intervals, always facing the circle center.\"\"\"\n",
+ " poses: list[Pose3] = []\n",
+ " poses.append(init)\n",
+ " for i in range(1, steps):\n",
+ " poses.append(poses[i - 1].compose(delta))\n",
+ " return poses\n",
+ "\n",
+ "\n",
+ "points: list[Point3] = createPoints()\n",
+ "poses: list[Pose3] = createPoses()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "6cb96973",
+ "metadata": {},
+ "source": [
+ "## 2. Build the factor graph\n",
+ "\n",
+ "A prior anchors pose `x0`. Then, for every pose/landmark pair, we project the ground-truth landmark through the *true* calibration `Kcal` to get a simulated pixel measurement, and add a `GeneralSFMFactor2Cal3_S2` -- the calibration-aware counterpart to the plain projection factor used in `VisualISAMExample`. Every one of these factors shares the *same* calibration key `K(0)`, since there's only one physical camera whose calibration we're trying to recover from all the views combined."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "id": "74c2de80",
+ "metadata": {
+ "execution": {
+ "iopub.execute_input": "2026-07-22T10:41:15.500106Z",
+ "iopub.status.busy": "2026-07-22T10:41:15.500048Z",
+ "iopub.status.idle": "2026-07-22T10:41:15.502880Z",
+ "shell.execute_reply": "2026-07-22T10:41:15.502544Z"
+ }
+ },
+ "outputs": [],
+ "source": [
+ "graph = NonlinearFactorGraph()\n",
+ "\n",
+ "# Add a prior on pose x1.\n",
+ "# 30cm std on x,y,z 0.1 rad on roll,pitch,yaw\n",
+ "poseNoise = Diagonal.Sigmas([0.1, 0.1, 0.1, 0.3, 0.3, 0.3])\n",
+ "graph.addPriorPose3(X(0), poses[0], poseNoise)\n",
+ "\n",
+ "# Simulated measurements from each camera pose, adding them to the factor graph\n",
+ "Kcal = Cal3_S2(50.0, 50.0, 0.0, 50.0, 50.0)\n",
+ "measurementNoise = Isotropic.Sigma(2, 1.0)\n",
+ "for i, pose in enumerate(poses):\n",
+ " for j, point in enumerate(points):\n",
+ " camera = PinholeCameraCal3_S2(pose, Kcal)\n",
+ " measurement: Point2 = camera.project(point)\n",
+ " # The only real difference with the Visual SLAM example is that here we\n",
+ " # use a different factor type, that also calculates the Jacobian with\n",
+ " # respect to calibration\n",
+ " graph.add(\n",
+ " GeneralSFMFactor2Cal3_S2(\n",
+ " measurement,\n",
+ " measurementNoise,\n",
+ " X(i),\n",
+ " L(j),\n",
+ " K(0),\n",
+ " )\n",
+ " )"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "ed642323",
+ "metadata": {},
+ "source": [
+ "## 3. Priors on landmark and calibration\n",
+ "\n",
+ "As in `VisualISAMExample`, a prior on landmark `l0` fixes the overall scale. Self-calibration adds one more thing to pin down: without *some* outside information about the calibration, the focal-length/scene-scale ambiguity described above leaves the problem underconstrained. A (loose) prior on `K(0)` supplies that information."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "id": "5a69a1bc",
+ "metadata": {
+ "execution": {
+ "iopub.execute_input": "2026-07-22T10:41:15.503781Z",
+ "iopub.status.busy": "2026-07-22T10:41:15.503724Z",
+ "iopub.status.idle": "2026-07-22T10:41:15.505525Z",
+ "shell.execute_reply": "2026-07-22T10:41:15.505225Z"
+ }
+ },
+ "outputs": [],
+ "source": [
+ "# Add a prior on the position of the first landmark.\n",
+ "pointNoise = Isotropic.Sigma(3, 0.1)\n",
+ "graph.addPriorPoint3(L(0), points[0], pointNoise) # add directly to graph\n",
+ "\n",
+ "# Add a prior on the calibration.\n",
+ "calNoise = Diagonal.Sigmas([500, 500, 0.1, 100, 100])\n",
+ "graph.addPriorCal3_S2(K(0), Kcal, calNoise)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "cfc8dc45",
+ "metadata": {},
+ "source": "## 4. Initial estimate\n\nEvery pose and landmark starts from a perturbed guess, just like in `VisualISAMExample` -- but now the calibration itself also starts from a deliberately wrong guess: `fx = fy = 60` and principal point `(45, 45)`, versus the true `fx = fy = 50` and principal point `(50, 50)`."
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 6,
+ "id": "f402da33",
+ "metadata": {
+ "execution": {
+ "iopub.execute_input": "2026-07-22T10:41:15.506426Z",
+ "iopub.status.busy": "2026-07-22T10:41:15.506354Z",
+ "iopub.status.idle": "2026-07-22T10:41:15.508710Z",
+ "shell.execute_reply": "2026-07-22T10:41:15.508318Z"
+ }
+ },
+ "outputs": [],
+ "source": [
+ "initialEstimate = Values()\n",
+ "initialEstimate.insert(K(0), Cal3_S2(60.0, 60.0, 0.0, 45.0, 45.0))\n",
+ "for i, pose in enumerate(poses):\n",
+ " initialEstimate.insert(\n",
+ " X(i),\n",
+ " pose.compose(\n",
+ " Pose3(Rot3.Rodrigues(-0.1, 0.2, 0.25), Point3(0.05, -0.10, 0.20))\n",
+ " ),\n",
+ " )\n",
+ "for j, point in enumerate(points):\n",
+ " initialEstimate.insert(L(j), point + Point3(-0.25, 0.20, 0.15))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "a963dbe5",
+ "metadata": {},
+ "source": "## 5. Optimize\n\nThis time we solve with `DoglegOptimizer`, the trust-region alternative to Levenberg-Marquardt compared against it in `DogLegOptimizerExample`."
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "id": "86d6c7b3",
+ "metadata": {
+ "execution": {
+ "iopub.execute_input": "2026-07-22T10:41:15.509677Z",
+ "iopub.status.busy": "2026-07-22T10:41:15.509620Z",
+ "iopub.status.idle": "2026-07-22T10:41:15.518681Z",
+ "shell.execute_reply": "2026-07-22T10:41:15.518439Z"
+ }
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Final results:\n",
+ "\n",
+ "Values with 17 values:\n",
+ "Value k0: (gtsam::Cal3_S2)\n",
+ "[\n",
+ "\t50, -1.7844e-16, 50;\n",
+ "\t0, 50, 50;\n",
+ "\t0, 0, 1\n",
+ "]\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\n",
+ "Value l0: (Eigen::Matrix)\n",
+ "[\n",
+ "\t10;\n",
+ "\t10;\n",
+ "\t10\n",
+ "]\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\n",
+ "Value l1: (Eigen::Matrix)\n",
+ "[\n",
+ "\t-10;\n",
+ "\t10;\n",
+ "\t10\n",
+ "]\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\n",
+ "Value l2: (Eigen::Matrix)\n",
+ "[\n",
+ "\t-10;\n",
+ "\t-10;\n",
+ "\t10\n",
+ "]\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\n",
+ "Value l3: (Eigen::Matrix)\n",
+ "[\n",
+ "\t10;\n",
+ "\t-10;\n",
+ "\t10\n",
+ "]\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\n",
+ "Value l4: (Eigen::Matrix)\n",
+ "[\n",
+ "\t10;\n",
+ "\t10;\n",
+ "\t-10\n",
+ "]\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\n",
+ "Value l5: (Eigen::Matrix)\n",
+ "[\n",
+ "\t-10;\n",
+ "\t10;\n",
+ "\t-10\n",
+ "]\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\n",
+ "Value l6: (Eigen::Matrix)\n",
+ "[\n",
+ "\t-10;\n",
+ "\t-10;\n",
+ "\t-10\n",
+ "]\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\n",
+ "Value l7: (Eigen::Matrix)\n",
+ "[\n",
+ "\t10;\n",
+ "\t-10;\n",
+ "\t-10\n",
+ "]\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\n",
+ "Value x0: (gtsam::Pose3)\n",
+ "R: [\n",
+ "\t7.88266e-17, -5.33571e-17, -1;\n",
+ "\t1, 1.69742e-17, 2.13565e-17;\n",
+ "\t-8.02971e-18, -1, 6.47159e-17\n",
+ "]\n",
+ "t: 30 -4.01306e-18 1.21656e-20\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\n",
+ "Value x1: (gtsam::Pose3)\n",
+ "R: [\n",
+ "\t-0.707107, -2.07839e-16, -0.707107;\n",
+ "\t0.707107, -3.08858e-17, -0.707107;\n",
+ "\t1.12199e-16, -1, 1.8707e-16\n",
+ "]\n",
+ "t: 21.2132 21.2132 -3.13375e-15\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\n",
+ "Value x2: (gtsam::Pose3)\n",
+ "R: [\n",
+ "\t-1, -9.91995e-17, 1.8202e-17;\n",
+ "\t3.48175e-17, -2.20241e-17, -1;\n",
+ "\t1.6168e-16, -1, 1.25939e-17\n",
+ "]\n",
+ "t: -1.17337e-15 30 7.10179e-16\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\n",
+ "Value x3: (gtsam::Pose3)\n",
+ "R: [\n",
+ "\t-0.707107, -2.56546e-16, 0.707107;\n",
+ "\t-0.707107, 1.24028e-17, -0.707107;\n",
+ "\t1.2373e-16, -1, -1.51259e-16\n",
+ "]\n",
+ "t: -21.2132 21.2132 9.19136e-15\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\n",
+ "Value x4: (gtsam::Pose3)\n",
+ "R: [\n",
+ "\t-2.6377e-16, -2.31823e-16, 1;\n",
+ "\t-1, -2.98388e-17, -3.63243e-16;\n",
+ "\t-4.274e-17, -1, -2.00741e-16\n",
+ "]\n",
+ "t: -30 4.2481e-16 9.38199e-15\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\n",
+ "Value x5: (gtsam::Pose3)\n",
+ "R: [\n",
+ "\t0.707107, -1.7636e-16, 0.707107;\n",
+ "\t-0.707107, -6.52449e-17, 0.707107;\n",
+ "\t-1.37343e-16, -1, -1.38407e-16\n",
+ "]\n",
+ "t: -21.2132 -21.2132 7.60698e-15\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\n",
+ "Value x6: (gtsam::Pose3)\n",
+ "R: [\n",
+ "\t1, -1.16769e-16, 6.68628e-16;\n",
+ "\t-6.46423e-16, 1.16778e-17, 1;\n",
+ "\t-9.30176e-17, -1, 4.11323e-17\n",
+ "]\n",
+ "t: -2.24367e-15 -30 2.73581e-15\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\n",
+ "Value x7: (gtsam::Pose3)\n",
+ "R: [\n",
+ "\t0.707107, -3.35454e-16, -0.707107;\n",
+ "\t0.707107, 6.88657e-17, 0.707107;\n",
+ "\t-2.32754e-16, -1, 2.76909e-16\n",
+ "]\n",
+ "t: 21.2132 -21.2132 -6.87553e-15\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\n"
+ ]
+ }
+ ],
+ "source": [
+ "result: Values = DoglegOptimizer(graph, initialEstimate).optimize()\n",
+ "result.print(\"Final results:\\n\")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "0e31d57e",
+ "metadata": {},
+ "source": [
+ "Despite starting `K(0)` more than 10 pixels off in focal length and 5 pixels off in principal point -- on top of every pose and landmark also starting from a wrong guess -- the optimizer recovers a calibration close to the true `Cal3_S2(50, 50, 0, 50, 50)`. Self-calibration is harder than SFM with known calibration, but it isn't hopeless, provided the graph carries enough independent views and a prior to fix the remaining ambiguity."
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.13.12"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
\ No newline at end of file
diff --git a/python/gtsam/examples/SelfCalibrationExample.py b/python/gtsam/examples/SelfCalibrationExample.py
deleted file mode 100644
index a1919e14e8..0000000000
--- a/python/gtsam/examples/SelfCalibrationExample.py
+++ /dev/null
@@ -1,122 +0,0 @@
-# pylint: disable=unused-import,consider-using-from-import,invalid-name,no-name-in-module,no-member,missing-function-docstring,too-many-locals
-"""
-Transcription of SelfCalibrationExample.cpp
-"""
-import math
-
-from gtsam import Cal3_S2
-from gtsam.noiseModel import Diagonal, Isotropic
-
-# SFM-specific factors
-from gtsam import GeneralSFMFactor2Cal3_S2 # does calibration !
-from gtsam import PinholeCameraCal3_S2
-
-# Camera observations of landmarks (i.e. pixel coordinates) will be stored as Point2 (x, y).
-from gtsam import Point2
-from gtsam import Point3, Pose3, Rot3
-
-# Inference and optimization
-from gtsam import NonlinearFactorGraph, DoglegOptimizer, Values
-from gtsam.symbol_shorthand import K, L, X
-
-
-# this is a direct translation of examples/SFMData.h
-# which is slightly different from python/gtsam/examples/SFMdata.py.
-def createPoints() -> list[Point3]:
- """
- Create the set of ground-truth landmarks
- """
- return [
- Point3(10.0, 10.0, 10.0),
- Point3(-10.0, 10.0, 10.0),
- Point3(-10.0, -10.0, 10.0),
- Point3(10.0, -10.0, 10.0),
- Point3(10.0, 10.0, -10.0),
- Point3(-10.0, 10.0, -10.0),
- Point3(-10.0, -10.0, -10.0),
- Point3(10.0, -10.0, -10.0),
- ]
-
-
-def createPoses(
- init: Pose3 = Pose3(Rot3.Ypr(math.pi / 2, 0, -math.pi / 2), Point3(30, 0, 0)),
- delta: Pose3 = Pose3(
- Rot3.Ypr(0, -math.pi / 4, 0),
- Point3(math.sin(math.pi / 4) * 30, 0, 30 * (1 - math.sin(math.pi / 4))),
- ),
- steps: int = 8,
-) -> list[Pose3]:
- """
- Create the set of ground-truth poses
- Default values give a circular trajectory,
- radius 30 at pi/4 intervals, always facing the circle center
- """
- poses: list[Pose3] = []
- poses.append(init)
- for i in range(1, steps):
- poses.append(poses[i - 1].compose(delta))
- return poses
-
-
-def main() -> None:
- # Create the set of ground-truth
- points: list[Point3] = createPoints()
- poses: list[Pose3] = createPoses()
-
- # Create the factor graph
- graph = NonlinearFactorGraph()
-
- # Add a prior on pose x1.
- # 30cm std on x,y,z 0.1 rad on roll,pitch,yaw
- poseNoise = Diagonal.Sigmas([0.1, 0.1, 0.1, 0.3, 0.3, 0.3])
- graph.addPriorPose3(X(0), poses[0], poseNoise)
-
- # Simulated measurements from each camera pose, adding them to the factor graph
- Kcal = Cal3_S2(50.0, 50.0, 0.0, 50.0, 50.0)
- measurementNoise = Isotropic.Sigma(2, 1.0)
- for i, pose in enumerate(poses):
- for j, point in enumerate(points):
- camera = PinholeCameraCal3_S2(pose, Kcal)
- measurement: Point2 = camera.project(point)
- # The only real difference with the Visual SLAM example is that here we
- # use a different factor type, that also calculates the Jacobian with
- # respect to calibration
- graph.add(
- GeneralSFMFactor2Cal3_S2(
- measurement,
- measurementNoise,
- X(i),
- L(j),
- K(0),
- )
- )
-
- # Add a prior on the position of the first landmark.
- pointNoise = Isotropic.Sigma(3, 0.1)
- graph.addPriorPoint3(L(0), points[0], pointNoise) # add directly to graph
-
- # Add a prior on the calibration.
- calNoise = Diagonal.Sigmas([500, 500, 0.1, 100, 100])
- graph.addPriorCal3_S2(K(0), Kcal, calNoise)
-
- # Create the initial estimate to the solution
- # now including an estimate on the camera calibration parameters
- initialEstimate = Values()
- initialEstimate.insert(K(0), Cal3_S2(60.0, 60.0, 0.0, 45.0, 45.0))
- for i, pose in enumerate(poses):
- initialEstimate.insert(
- X(i),
- pose.compose(
- Pose3(Rot3.Rodrigues(-0.1, 0.2, 0.25), Point3(0.05, -0.10, 0.20))
- ),
- )
- for j, point in enumerate(points):
- initialEstimate.insert(L(j), point + Point3(-0.25, 0.20, 0.15))
-
- # Optimize the graph and print results
- result: Values = DoglegOptimizer(graph, initialEstimate).optimize()
- result.print("Final results:\n")
-
-
-if __name__ == "__main__":
- main()
diff --git a/python/gtsam/examples/SimpleRotation.ipynb b/python/gtsam/examples/SimpleRotation.ipynb
new file mode 100644
index 0000000000..955fc7ef8f
--- /dev/null
+++ b/python/gtsam/examples/SimpleRotation.ipynb
@@ -0,0 +1,295 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "3fdd7d27",
+ "metadata": {},
+ "source": [
+ "# Simple Rotation\n",
+ "\n",
+ "This is the smallest possible GTSAM optimization: a single variable, a single factor. The variable is a 2D rotation (`Rot2`); the factor is a **prior** -- a measurement from a sensor, with a noise model describing how much we trust it.\n",
+ "\n",
+ "The story: a sensor measured a rotation to be close to 30 degrees. We start from a wrong initial guess of 20 degrees, and ask GTSAM to find the best estimate."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "3fbed24c",
+ "metadata": {},
+ "source": [
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "accd699b",
+ "metadata": {},
+ "source": [
+ "GTSAM Copyright 2010-2026, Georgia Tech Research Corporation,\n",
+ "Atlanta, Georgia 30332-0415\n",
+ "All Rights Reserved\n",
+ "\n",
+ "Authors: Frank Dellaert, Alex Cunningham, et al. (see THANKS for the full author list)\n",
+ "\n",
+ "See LICENSE for the license information"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "17ccfe63",
+ "metadata": {
+ "execution": {
+ "iopub.execute_input": "2026-07-22T10:24:40.454062Z",
+ "iopub.status.busy": "2026-07-22T10:24:40.453873Z",
+ "iopub.status.idle": "2026-07-22T10:24:40.459726Z",
+ "shell.execute_reply": "2026-07-22T10:24:40.458982Z"
+ }
+ },
+ "outputs": [],
+ "source": [
+ "try:\n",
+ " import google.colab\n",
+ " %pip install --quiet gtsam-develop\n",
+ "except ImportError:\n",
+ " pass"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "id": "a32e82a5",
+ "metadata": {
+ "execution": {
+ "iopub.execute_input": "2026-07-22T10:24:40.461947Z",
+ "iopub.status.busy": "2026-07-22T10:24:40.461746Z",
+ "iopub.status.idle": "2026-07-22T10:24:40.665633Z",
+ "shell.execute_reply": "2026-07-22T10:24:40.665172Z"
+ }
+ },
+ "outputs": [],
+ "source": [
+ "import numpy as np\n",
+ "import gtsam\n",
+ "from gtsam.symbol_shorthand import X"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "a6165fb4",
+ "metadata": {},
+ "source": "## 1. Keys\n\n`GPSFactorExample` and `OdometryExample` label variables with plain integer keys (`1`, `2`, `3`, ...). Here we instead use `symbol_shorthand.X`, which packs a character (`'x'`) and an index into the same underlying `Key` type -- a more readable choice once a problem has several kinds of variables (poses, landmarks, calibration, ...) that would otherwise collide under a single integer counter."
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "id": "ca4d4925",
+ "metadata": {
+ "execution": {
+ "iopub.execute_input": "2026-07-22T10:24:40.666825Z",
+ "iopub.status.busy": "2026-07-22T10:24:40.666728Z",
+ "iopub.status.idle": "2026-07-22T10:24:40.668351Z",
+ "shell.execute_reply": "2026-07-22T10:24:40.667973Z"
+ }
+ },
+ "outputs": [],
+ "source": [
+ "key = X(1)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "978b8101",
+ "metadata": {},
+ "source": [
+ "## 2. Create the prior factor\n",
+ "\n",
+ "In general, creating a factor requires:\n",
+ "\n",
+ "- a key or set of keys labeling the variables it acts on,\n",
+ "- a measurement value, and\n",
+ "- a measurement model with the correct dimensionality.\n",
+ "\n",
+ "Here the \"measurement\" is the goal angle of 30 degrees, and the noise model says we trust it to within about 1 degree (`Isotropic.Sigma` since a `Rot2` has a single degree of freedom)."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "id": "19bc0234",
+ "metadata": {
+ "execution": {
+ "iopub.execute_input": "2026-07-22T10:24:40.669204Z",
+ "iopub.status.busy": "2026-07-22T10:24:40.669150Z",
+ "iopub.status.idle": "2026-07-22T10:24:40.671001Z",
+ "shell.execute_reply": "2026-07-22T10:24:40.670684Z"
+ }
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "theta: 0.523599\n",
+ "\n"
+ ]
+ }
+ ],
+ "source": [
+ "prior = gtsam.Rot2.fromAngle(np.deg2rad(30))\n",
+ "print(prior)\n",
+ "model = gtsam.noiseModel.Isotropic.Sigma(dim=1, sigma=np.deg2rad(1))\n",
+ "factor = gtsam.PriorFactorRot2(key, prior, model)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "4bb9d7c2",
+ "metadata": {},
+ "source": [
+ "## 3. Build the graph\n",
+ "\n",
+ "Before optimizing, every factor needs to be added to a graph container. In a practical problem many factors would be added; here there is exactly one."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "id": "ee02f2a5",
+ "metadata": {
+ "execution": {
+ "iopub.execute_input": "2026-07-22T10:24:40.671974Z",
+ "iopub.status.busy": "2026-07-22T10:24:40.671907Z",
+ "iopub.status.idle": "2026-07-22T10:24:40.673540Z",
+ "shell.execute_reply": "2026-07-22T10:24:40.673229Z"
+ }
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "NonlinearFactorGraph: size: 1\n",
+ "\n",
+ "Factor 0: PriorFactor on x1\n",
+ " prior mean: : 0.523599\n",
+ "isotropic dim=1 sigma=0.0174533\n",
+ "\n",
+ "\n"
+ ]
+ }
+ ],
+ "source": [
+ "graph = gtsam.NonlinearFactorGraph()\n",
+ "graph.push_back(factor)\n",
+ "print(graph)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "07463895",
+ "metadata": {},
+ "source": [
+ "## 4. Initial estimate\n",
+ "\n",
+ "Optimization needs a starting linearization point for every variable in the graph. We deliberately start 10 degrees away from the prior's goal angle, so the optimizer has something to do."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 6,
+ "id": "b680567b",
+ "metadata": {
+ "execution": {
+ "iopub.execute_input": "2026-07-22T10:24:40.674375Z",
+ "iopub.status.busy": "2026-07-22T10:24:40.674316Z",
+ "iopub.status.idle": "2026-07-22T10:24:40.676032Z",
+ "shell.execute_reply": "2026-07-22T10:24:40.675726Z"
+ }
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Values with 1 values:\n",
+ "Value x1: (gtsam::Rot2)\n",
+ ": 0.349066\n",
+ "\n",
+ "\n"
+ ]
+ }
+ ],
+ "source": [
+ "initial = gtsam.Values()\n",
+ "initial.insert(key, gtsam.Rot2.fromAngle(np.deg2rad(20)))\n",
+ "print(initial)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "4d41edac",
+ "metadata": {},
+ "source": "## 5. Optimize\n\nAs in `GPSFactorExample` and `OdometryExample`, we solve with `LevenbergMarquardtOptimizer`."
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "id": "7aa27b9a",
+ "metadata": {
+ "execution": {
+ "iopub.execute_input": "2026-07-22T10:24:40.676865Z",
+ "iopub.status.busy": "2026-07-22T10:24:40.676803Z",
+ "iopub.status.idle": "2026-07-22T10:24:40.681902Z",
+ "shell.execute_reply": "2026-07-22T10:24:40.681596Z"
+ }
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Values with 1 values:\n",
+ "Value x1: (gtsam::Rot2)\n",
+ ": 0.523599\n",
+ "\n",
+ "\n"
+ ]
+ }
+ ],
+ "source": [
+ "result = gtsam.LevenbergMarquardtOptimizer(graph, initial).optimize()\n",
+ "print(result)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "f3e93e58",
+ "metadata": {},
+ "source": [
+ "With only one factor in the graph, there is nothing else to compromise against, so the optimizer converges exactly to the prior's goal angle of 30 degrees -- unlike the GPS factor notebook, where two competing factors (a prior and a GPS measurement) pulled the result to a noise-weighted blend between them. A single-factor graph like this one just returns that factor's own measurement."
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.13.12"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
\ No newline at end of file
diff --git a/python/gtsam/examples/SimpleRotation.py b/python/gtsam/examples/SimpleRotation.py
deleted file mode 100644
index 3d5fd9e452..0000000000
--- a/python/gtsam/examples/SimpleRotation.py
+++ /dev/null
@@ -1,84 +0,0 @@
-"""
-GTSAM Copyright 2010, Georgia Tech Research Corporation,
-Atlanta, Georgia 30332-0415
-All Rights Reserved
-Authors: Frank Dellaert, et al. (see THANKS for the full author list)
-
-See LICENSE for the license information
-
-This example will perform a relatively trivial optimization on
-a single variable with a single factor.
-"""
-
-import numpy as np
-import gtsam
-from gtsam.symbol_shorthand import X
-
-def main():
- """
- Step 1: Create a factor to express a unary constraint
-
- The "prior" in this case is the measurement from a sensor,
- with a model of the noise on the measurement.
-
- The "Key" created here is a label used to associate parts of the
- state (stored in "RotValues") with particular factors. They require
- an index to allow for lookup, and should be unique.
-
- In general, creating a factor requires:
- - A key or set of keys labeling the variables that are acted upon
- - A measurement value
- - A measurement model with the correct dimensionality for the factor
- """
- prior = gtsam.Rot2.fromAngle(np.deg2rad(30))
- prior.print('goal angle')
- model = gtsam.noiseModel.Isotropic.Sigma(dim=1, sigma=np.deg2rad(1))
- key = X(1)
- factor = gtsam.PriorFactorRot2(key, prior, model)
-
- """
- Step 2: Create a graph container and add the factor to it
-
- Before optimizing, all factors need to be added to a Graph container,
- which provides the necessary top-level functionality for defining a
- system of constraints.
-
- In this case, there is only one factor, but in a practical scenario,
- many more factors would be added.
- """
- graph = gtsam.NonlinearFactorGraph()
- graph.push_back(factor)
- graph.print('full graph')
-
- """
- Step 3: Create an initial estimate
-
- An initial estimate of the solution for the system is necessary to
- start optimization. This system state is the "Values" instance,
- which is similar in structure to a dictionary, in that it maps
- keys (the label created in step 1) to specific values.
-
- The initial estimate provided to optimization will be used as
- a linearization point for optimization, so it is important that
- all of the variables in the graph have a corresponding value in
- this structure.
- """
- initial = gtsam.Values()
- initial.insert(key, gtsam.Rot2.fromAngle(np.deg2rad(20)))
- initial.print('initial estimate')
-
- """
- Step 4: Optimize
-
- After formulating the problem with a graph of constraints
- and an initial estimate, executing optimization is as simple
- as calling a general optimization function with the graph and
- initial estimate. This will yield a new RotValues structure
- with the final state of the optimization.
- """
- result = gtsam.LevenbergMarquardtOptimizer(graph, initial).optimize()
- result.print('final result')
-
-
-if __name__ == '__main__':
- main()
diff --git a/python/gtsam/examples/VisualISAMExample.ipynb b/python/gtsam/examples/VisualISAMExample.ipynb
new file mode 100644
index 0000000000..67fda6f77a
--- /dev/null
+++ b/python/gtsam/examples/VisualISAMExample.ipynb
@@ -0,0 +1,1585 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "3a191daf",
+ "metadata": {},
+ "source": "# Visual ISAM Example\n\nBatch optimizers solve their problem in one shot: build the whole graph, then call `optimize()` once. Real robots don't get to wait until the end of the mission to know where they are -- measurements arrive continuously, and the estimate has to update *incrementally*.\n\nThis notebook is a first taste of that: a structure-from-motion problem where 8 cameras orbit a 10-meter cube of landmarks, always facing the center. As each new camera pose and its landmark observations arrive, we feed them to `NonlinearISAM`, which relinearizes and reorders the problem every few updates instead of resolving from scratch -- the classic \"incremental SLAM\" pattern."
+ },
+ {
+ "cell_type": "markdown",
+ "id": "a50310d9",
+ "metadata": {},
+ "source": [
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "16c9dee2",
+ "metadata": {},
+ "source": [
+ "GTSAM Copyright 2010-2026, Georgia Tech Research Corporation,\n",
+ "Atlanta, Georgia 30332-0415\n",
+ "All Rights Reserved\n",
+ "\n",
+ "Authors: Frank Dellaert, et al. (see THANKS for the full author list)\n",
+ "\n",
+ "See LICENSE for the license information"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "3f18d612",
+ "metadata": {
+ "execution": {
+ "iopub.execute_input": "2026-07-22T10:37:40.992228Z",
+ "iopub.status.busy": "2026-07-22T10:37:40.992023Z",
+ "iopub.status.idle": "2026-07-22T10:37:40.997527Z",
+ "shell.execute_reply": "2026-07-22T10:37:40.996820Z"
+ }
+ },
+ "outputs": [],
+ "source": [
+ "try:\n",
+ " import google.colab\n",
+ " %pip install --quiet gtsam-develop\n",
+ "except ImportError:\n",
+ " pass"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "id": "e26548ff",
+ "metadata": {
+ "execution": {
+ "iopub.execute_input": "2026-07-22T10:37:40.999453Z",
+ "iopub.status.busy": "2026-07-22T10:37:40.999289Z",
+ "iopub.status.idle": "2026-07-22T10:37:41.395257Z",
+ "shell.execute_reply": "2026-07-22T10:37:41.394797Z"
+ }
+ },
+ "outputs": [],
+ "source": [
+ "import numpy as np\n",
+ "import matplotlib.pyplot as plt\n",
+ "\n",
+ "import gtsam\n",
+ "import gtsam.utils.plot as gtsam_plot\n",
+ "from gtsam.examples import SFMdata\n",
+ "from gtsam import (Cal3_S2, GenericProjectionFactorCal3_S2,\n",
+ " NonlinearFactorGraph, NonlinearISAM, Pose3,\n",
+ " PriorFactorPoint3, PriorFactorPose3, Rot3,\n",
+ " PinholeCameraCal3_S2, Values, Point3)\n",
+ "from gtsam.symbol_shorthand import X, L"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "803debaa",
+ "metadata": {},
+ "source": [
+ "## 1. Camera and scene setup\n",
+ "\n",
+ "The scene comes from the shared `SFMdata` helper module: 8 ground-truth landmarks forming a 10-meter cube, and 8 ground-truth camera poses circling it. `K` is a simple pinhole calibration, and `camera_noise` models about one pixel of measurement noise."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "id": "4d4ef32f",
+ "metadata": {
+ "execution": {
+ "iopub.execute_input": "2026-07-22T10:37:41.396436Z",
+ "iopub.status.busy": "2026-07-22T10:37:41.396331Z",
+ "iopub.status.idle": "2026-07-22T10:37:41.398141Z",
+ "shell.execute_reply": "2026-07-22T10:37:41.397796Z"
+ }
+ },
+ "outputs": [],
+ "source": [
+ "# Define the camera calibration parameters\n",
+ "K = Cal3_S2(50.0, 50.0, 0.0, 50.0, 50.0)\n",
+ "\n",
+ "# Define the camera observation noise model\n",
+ "camera_noise = gtsam.noiseModel.Isotropic.Sigma(2, 1.0) # one pixel in u and v\n",
+ "\n",
+ "# Create the set of ground-truth landmarks\n",
+ "points = SFMdata.createPoints()\n",
+ "# Create the set of ground-truth poses\n",
+ "poses = SFMdata.createPoses()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "92ece5ac",
+ "metadata": {},
+ "source": [
+ "## 2. Set up incremental ISAM\n",
+ "\n",
+ "`NonlinearISAM(reorderInterval=3)` relinearizes and reorders the variables every 3 updates, rather than on every single one -- a tradeoff between staying close to the true nonlinear solution and not paying the reordering cost too often."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "id": "0a22d37b",
+ "metadata": {
+ "execution": {
+ "iopub.execute_input": "2026-07-22T10:37:41.399072Z",
+ "iopub.status.busy": "2026-07-22T10:37:41.399014Z",
+ "iopub.status.idle": "2026-07-22T10:37:41.400779Z",
+ "shell.execute_reply": "2026-07-22T10:37:41.400457Z"
+ }
+ },
+ "outputs": [],
+ "source": [
+ "isam = NonlinearISAM(reorderInterval=3)\n",
+ "\n",
+ "graph = NonlinearFactorGraph()\n",
+ "initial_estimate = Values()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "50205176",
+ "metadata": {},
+ "source": [
+ "## 3. Feed observations incrementally\n",
+ "\n",
+ "For each camera pose, we project every landmark into the image to get a (simulated) pixel measurement, and add a `GenericProjectionFactorCal3_S2` per observation. The initial guesses -- for both poses and landmarks -- are deliberately perturbed away from ground truth.\n",
+ "\n",
+ "The first frame is special: since iSAM needs each landmark observed at least twice before it becomes well constrained, we don't call `isam.update()` yet. Instead we add priors on pose `x0` (to fix the coordinate frame) and landmark `l0` (to fix the scale), plus initial guesses for every landmark. From frame 1 onward, each new pose's factors are handed to `isam.update()`, and we read back the current estimate."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "id": "f623969c",
+ "metadata": {
+ "execution": {
+ "iopub.execute_input": "2026-07-22T10:37:41.401704Z",
+ "iopub.status.busy": "2026-07-22T10:37:41.401642Z",
+ "iopub.status.idle": "2026-07-22T10:37:41.418491Z",
+ "shell.execute_reply": "2026-07-22T10:37:41.418129Z"
+ }
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "**************************************************\n",
+ "Frame 1:\n",
+ "Current estimate: \n",
+ "Values with 10 values:\n",
+ "Value l0: (Eigen::Matrix)\n",
+ "[\n",
+ "\t9.99996;\n",
+ "\t9.99995;\n",
+ "\t9.99998\n",
+ "]\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\n",
+ "Value l1: (Eigen::Matrix)\n",
+ "[\n",
+ "\t-12.8291;\n",
+ "\t10.3572;\n",
+ "\t10.376\n",
+ "]\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\n",
+ "Value l2: (Eigen::Matrix)\n",
+ "[\n",
+ "\t-12.4628;\n",
+ "\t-11.5675;\n",
+ "\t10.3645\n",
+ "]\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\n",
+ "Value l3: (Eigen::Matrix)\n",
+ "[\n",
+ "\t9.98338;\n",
+ "\t-11.2238;\n",
+ "\t9.85452\n",
+ "]\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\n",
+ "Value l4: (Eigen::Matrix)\n",
+ "[\n",
+ "\t9.49906;\n",
+ "\t9.94737;\n",
+ "\t-10.8915\n",
+ "]\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\n",
+ "Value l5: (Eigen::Matrix)\n",
+ "[\n",
+ "\t-11.806;\n",
+ "\t10.1893;\n",
+ "\t-11.5028\n",
+ "]\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\n",
+ "Value l6: (Eigen::Matrix)\n",
+ "[\n",
+ "\t-11.9203;\n",
+ "\t-10.5771;\n",
+ "\t-10.774\n",
+ "]\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\n",
+ "Value l7: (Eigen::Matrix)\n",
+ "[\n",
+ "\t8.77424;\n",
+ "\t-10.3664;\n",
+ "\t-10.6539\n",
+ "]\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\n",
+ "Value x0: (gtsam::Pose3)\n",
+ "R: [\n",
+ "\t0.0104087, -0.00870685, -0.999908;\n",
+ "\t0.99994, -0.00329421, 0.0104377;\n",
+ "\t-0.00338479, -0.999957, 0.00867204\n",
+ "]\n",
+ "t: 29.9994 -0.00118953 -0.000751309\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\n",
+ "Value x1: (gtsam::Pose3)\n",
+ "R: [\n",
+ "\t-0.683294, -0.0178895, -0.729924;\n",
+ "\t0.730038, -0.0336979, -0.682575;\n",
+ "\t-0.012386, -0.999272, 0.0360856\n",
+ "]\n",
+ "t: 21.2424 21.5775 -0.99152\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "**************************************************\n",
+ "Frame 2:\n",
+ "Current estimate: \n",
+ "Values with 11 values:\n",
+ "Value l0: (Eigen::Matrix)\n",
+ "[\n",
+ "\t9.99998;\n",
+ "\t9.99998;\n",
+ "\t9.99998\n",
+ "]\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\n",
+ "Value l1: (Eigen::Matrix)\n",
+ "[\n",
+ "\t-11.9967;\n",
+ "\t9.91545;\n",
+ "\t10.0246\n",
+ "]\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\n",
+ "Value l2: (Eigen::Matrix)\n",
+ "[\n",
+ "\t-11.8268;\n",
+ "\t-11.7644;\n",
+ "\t9.95286\n",
+ "]\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\n",
+ "Value l3: (Eigen::Matrix)\n",
+ "[\n",
+ "\t10.044;\n",
+ "\t-11.393;\n",
+ "\t9.78106\n",
+ "]\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\n",
+ "Value l4: (Eigen::Matrix)\n",
+ "[\n",
+ "\t8.97631;\n",
+ "\t9.71935;\n",
+ "\t-10.9304\n",
+ "]\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\n",
+ "Value l5: (Eigen::Matrix)\n",
+ "[\n",
+ "\t-11.568;\n",
+ "\t9.92191;\n",
+ "\t-11.4467\n",
+ "]\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\n",
+ "Value l6: (Eigen::Matrix)\n",
+ "[\n",
+ "\t-11.4585;\n",
+ "\t-10.7162;\n",
+ "\t-11.082\n",
+ "]\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\n",
+ "Value l7: (Eigen::Matrix)\n",
+ "[\n",
+ "\t8.98789;\n",
+ "\t-10.4202;\n",
+ "\t-10.733\n",
+ "]\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\n",
+ "Value x0: (gtsam::Pose3)\n",
+ "R: [\n",
+ "\t0.00374741, -0.00584062, -0.999976;\n",
+ "\t0.999993, -0.000288842, 0.00374916;\n",
+ "\t-0.000310732, -0.999983, 0.00583949\n",
+ "]\n",
+ "t: 29.9996 -0.000387572 -0.00054771\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\n",
+ "Value x1: (gtsam::Pose3)\n",
+ "R: [\n",
+ "\t-0.696357, -0.00664829, -0.717664;\n",
+ "\t0.717688, -0.0109985, -0.696278;\n",
+ "\t-0.00326417, -0.999917, 0.0124303\n",
+ "]\n",
+ "t: 20.8367 21.64 -0.277574\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\n",
+ "Value x2: (gtsam::Pose3)\n",
+ "R: [\n",
+ "\t-0.999874, 0.013676, -0.00806307;\n",
+ "\t0.00795185, -0.00816706, -0.999935;\n",
+ "\t-0.013741, -0.999873, 0.00805728\n",
+ "]\n",
+ "t: -1.63593 30.5496 -0.222778\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "**************************************************\n",
+ "Frame 3:\n",
+ "Current estimate: \n",
+ "Values with 12 values:\n",
+ "Value l0: (Eigen::Matrix)\n",
+ "[\n",
+ "\t10;\n",
+ "\t10;\n",
+ "\t10\n",
+ "]\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\n",
+ "Value l1: (Eigen::Matrix)\n",
+ "[\n",
+ "\t-9.97696;\n",
+ "\t9.70132;\n",
+ "\t10.1426\n",
+ "]\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\n",
+ "Value l2: (Eigen::Matrix)\n",
+ "[\n",
+ "\t-10.2879;\n",
+ "\t-10.5526;\n",
+ "\t9.721\n",
+ "]\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\n",
+ "Value l3: (Eigen::Matrix)\n",
+ "[\n",
+ "\t9.86576;\n",
+ "\t-10.2901;\n",
+ "\t10.0304\n",
+ "]\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\n",
+ "Value l4: (Eigen::Matrix)\n",
+ "[\n",
+ "\t10.1409;\n",
+ "\t9.65675;\n",
+ "\t-9.80039\n",
+ "]\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\n",
+ "Value l5: (Eigen::Matrix)\n",
+ "[\n",
+ "\t-9.81776;\n",
+ "\t9.71664;\n",
+ "\t-9.84937\n",
+ "]\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\n",
+ "Value l6: (Eigen::Matrix)\n",
+ "[\n",
+ "\t-9.75746;\n",
+ "\t-9.98177;\n",
+ "\t-10.3888\n",
+ "]\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\n",
+ "Value l7: (Eigen::Matrix)\n",
+ "[\n",
+ "\t10.1327;\n",
+ "\t-10.1179;\n",
+ "\t-9.97183\n",
+ "]\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\n",
+ "Value x0: (gtsam::Pose3)\n",
+ "R: [\n",
+ "\t-0.00668957, 0.000932254, -0.999977;\n",
+ "\t0.999974, 0.00285256, -0.00668688;\n",
+ "\t0.00284626, -0.999995, -0.000951311\n",
+ "]\n",
+ "t: 30 -2.9699e-05 2.43528e-06\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\n",
+ "Value x1: (gtsam::Pose3)\n",
+ "R: [\n",
+ "\t-0.70804, 0.014962, -0.706013;\n",
+ "\t0.706157, 0.00850201, -0.708004;\n",
+ "\t-0.00459061, -0.999852, -0.0165853\n",
+ "]\n",
+ "t: 21.1437 20.9244 0.536878\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\n",
+ "Value x2: (gtsam::Pose3)\n",
+ "R: [\n",
+ "\t-0.999973, 0.00527312, -0.00514657;\n",
+ "\t0.00519818, 0.00982042, -0.999938;\n",
+ "\t-0.00522225, -0.999938, -0.00984756\n",
+ "]\n",
+ "t: 0.272857 29.7215 0.365141\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\n",
+ "Value x3: (gtsam::Pose3)\n",
+ "R: [\n",
+ "\t-0.717696, 0.0500379, 0.694556;\n",
+ "\t-0.694829, 0.0145604, -0.719028;\n",
+ "\t-0.0460916, -0.998641, 0.0243178\n",
+ "]\n",
+ "t: -20.974 20.928 -0.628741\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "**************************************************\n",
+ "Frame 4:\n",
+ "Current estimate: \n",
+ "Values with 13 values:\n",
+ "Value l0: (Eigen::Matrix)\n",
+ "[\n",
+ "\t10;\n",
+ "\t10;\n",
+ "\t10\n",
+ "]\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\n",
+ "Value l1: (Eigen::Matrix)\n",
+ "[\n",
+ "\t-10.2175;\n",
+ "\t10.0958;\n",
+ "\t10.0266\n",
+ "]\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\n",
+ "Value l2: (Eigen::Matrix)\n",
+ "[\n",
+ "\t-9.98435;\n",
+ "\t-10.3532;\n",
+ "\t9.57353\n",
+ "]\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\n",
+ "Value l3: (Eigen::Matrix)\n",
+ "[\n",
+ "\t10.0266;\n",
+ "\t-10.1551;\n",
+ "\t9.8945\n",
+ "]\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\n",
+ "Value l4: (Eigen::Matrix)\n",
+ "[\n",
+ "\t10.3771;\n",
+ "\t9.61199;\n",
+ "\t-9.7331\n",
+ "]\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\n",
+ "Value l5: (Eigen::Matrix)\n",
+ "[\n",
+ "\t-9.33863;\n",
+ "\t9.27402;\n",
+ "\t-9.90671\n",
+ "]\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\n",
+ "Value l6: (Eigen::Matrix)\n",
+ "[\n",
+ "\t-9.42369;\n",
+ "\t-9.88269;\n",
+ "\t-10.2183\n",
+ "]\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\n",
+ "Value l7: (Eigen::Matrix)\n",
+ "[\n",
+ "\t10.2931;\n",
+ "\t-9.9971;\n",
+ "\t-9.94775\n",
+ "]\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\n",
+ "Value x0: (gtsam::Pose3)\n",
+ "R: [\n",
+ "\t-0.00547431, 0.00270639, -0.999981;\n",
+ "\t0.999984, 0.00137513, -0.0054706;\n",
+ "\t0.0013603, -0.999995, -0.00271387\n",
+ "]\n",
+ "t: 30 -2.22569e-05 -6.81754e-06\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\n",
+ "Value x1: (gtsam::Pose3)\n",
+ "R: [\n",
+ "\t-0.708029, 0.0174675, -0.705967;\n",
+ "\t0.706048, -0.00204497, -0.708161;\n",
+ "\t-0.0138135, -0.999845, -0.010885\n",
+ "]\n",
+ "t: 21.2234 20.875 0.346871\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\n",
+ "Value x2: (gtsam::Pose3)\n",
+ "R: [\n",
+ "\t-0.999867, 0.0162812, -0.000743803;\n",
+ "\t0.000759469, 0.000956036, -0.999999;\n",
+ "\t-0.0162805, -0.999867, -0.000968274\n",
+ "]\n",
+ "t: 0.279827 29.6576 0.172535\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\n",
+ "Value x3: (gtsam::Pose3)\n",
+ "R: [\n",
+ "\t-0.715639, 0.0364834, 0.697517;\n",
+ "\t-0.697016, 0.0271085, -0.716543;\n",
+ "\t-0.0450506, -0.998967, 0.00602961\n",
+ "]\n",
+ "t: -20.803 20.8359 0.0789155\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\n",
+ "Value x4: (gtsam::Pose3)\n",
+ "R: [\n",
+ "\t-0.00205907, 0.00183112, 0.999996;\n",
+ "\t-0.998839, 0.0481298, -0.00214482;\n",
+ "\t-0.0481335, -0.998839, 0.00172989\n",
+ "]\n",
+ "t: -28.9094 -0.628466 0.310697\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "**************************************************\n",
+ "Frame 5:\n",
+ "Current estimate: \n",
+ "Values with 14 values:\n",
+ "Value l0: (Eigen::Matrix)\n",
+ "[\n",
+ "\t10;\n",
+ "\t10;\n",
+ "\t10\n",
+ "]\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\n",
+ "Value l1: (Eigen::Matrix)\n",
+ "[\n",
+ "\t-10.3294;\n",
+ "\t10.158;\n",
+ "\t9.82264\n",
+ "]\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\n",
+ "Value l2: (Eigen::Matrix)\n",
+ "[\n",
+ "\t-10.0218;\n",
+ "\t-10.1264;\n",
+ "\t9.69102\n",
+ "]\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\n",
+ "Value l3: (Eigen::Matrix)\n",
+ "[\n",
+ "\t10.1683;\n",
+ "\t-10.0991;\n",
+ "\t9.81209\n",
+ "]\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\n",
+ "Value l4: (Eigen::Matrix)\n",
+ "[\n",
+ "\t10.4567;\n",
+ "\t9.59648;\n",
+ "\t-9.69058\n",
+ "]\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\n",
+ "Value l5: (Eigen::Matrix)\n",
+ "[\n",
+ "\t-9.05738;\n",
+ "\t9.2479;\n",
+ "\t-9.89342\n",
+ "]\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\n",
+ "Value l6: (Eigen::Matrix)\n",
+ "[\n",
+ "\t-8.92256;\n",
+ "\t-9.90333;\n",
+ "\t-10.0206\n",
+ "]\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\n",
+ "Value l7: (Eigen::Matrix)\n",
+ "[\n",
+ "\t10.3034;\n",
+ "\t-9.93371;\n",
+ "\t-9.97587\n",
+ "]\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\n",
+ "Value x0: (gtsam::Pose3)\n",
+ "R: [\n",
+ "\t-0.00486548, 0.00321872, -0.999983;\n",
+ "\t0.999988, 0.000820143, -0.00486286;\n",
+ "\t0.000804477, -0.999994, -0.00322267\n",
+ "]\n",
+ "t: 30 -1.89292e-05 -9.74907e-06\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\n",
+ "Value x1: (gtsam::Pose3)\n",
+ "R: [\n",
+ "\t-0.708817, 0.0186411, -0.705146;\n",
+ "\t0.705168, -0.00650984, -0.709011;\n",
+ "\t-0.0178071, -0.999805, -0.00853083\n",
+ "]\n",
+ "t: 21.2261 20.8675 0.264764\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\n",
+ "Value x2: (gtsam::Pose3)\n",
+ "R: [\n",
+ "\t-0.999721, 0.0231754, 0.0045882;\n",
+ "\t-0.00478936, -0.00863168, -0.999951;\n",
+ "\t-0.0231346, -0.999694, 0.00874026\n",
+ "]\n",
+ "t: 0.195246 29.5786 -0.117567\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\n",
+ "Value x3: (gtsam::Pose3)\n",
+ "R: [\n",
+ "\t-0.713124, 0.0416573, 0.699799;\n",
+ "\t-0.699337, 0.0272156, -0.714274;\n",
+ "\t-0.0488002, -0.998761, 0.00972435\n",
+ "]\n",
+ "t: -20.6541 20.708 0.0109808\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\n",
+ "Value x4: (gtsam::Pose3)\n",
+ "R: [\n",
+ "\t-0.00523291, 0.00388494, 0.999979;\n",
+ "\t-0.999191, 0.0398587, -0.00538363;\n",
+ "\t-0.0398787, -0.999198, 0.00367322\n",
+ "]\n",
+ "t: -28.7048 -0.426185 0.395639\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\n",
+ "Value x5: (gtsam::Pose3)\n",
+ "R: [\n",
+ "\t0.703305, 0.000669088, 0.710888;\n",
+ "\t-0.70993, 0.052569, 0.702307;\n",
+ "\t-0.0369008, -0.998617, 0.037447\n",
+ "]\n",
+ "t: -19.7723 -20.6982 -0.584802\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "**************************************************\n",
+ "Frame 6:\n",
+ "Current estimate: \n",
+ "Values with 15 values:\n",
+ "Value l0: (Eigen::Matrix)\n",
+ "[\n",
+ "\t10;\n",
+ "\t10;\n",
+ "\t9.99999\n",
+ "]\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\n",
+ "Value l1: (Eigen::Matrix)\n",
+ "[\n",
+ "\t-10.0219;\n",
+ "\t9.92921;\n",
+ "\t9.99582\n",
+ "]\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\n",
+ "Value l2: (Eigen::Matrix)\n",
+ "[\n",
+ "\t-10.169;\n",
+ "\t-10.1261;\n",
+ "\t10.0072\n",
+ "]\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\n",
+ "Value l3: (Eigen::Matrix)\n",
+ "[\n",
+ "\t10.1637;\n",
+ "\t-9.96976;\n",
+ "\t10.0201\n",
+ "]\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\n",
+ "Value l4: (Eigen::Matrix)\n",
+ "[\n",
+ "\t9.98976;\n",
+ "\t9.98664;\n",
+ "\t-9.94795\n",
+ "]\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\n",
+ "Value l5: (Eigen::Matrix)\n",
+ "[\n",
+ "\t-9.85103;\n",
+ "\t10.0035;\n",
+ "\t-9.86214\n",
+ "]\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\n",
+ "Value l6: (Eigen::Matrix)\n",
+ "[\n",
+ "\t-9.64164;\n",
+ "\t-9.67932;\n",
+ "\t-9.77278\n",
+ "]\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\n",
+ "Value l7: (Eigen::Matrix)\n",
+ "[\n",
+ "\t10.0291;\n",
+ "\t-9.97891;\n",
+ "\t-9.97128\n",
+ "]\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\n",
+ "Value x0: (gtsam::Pose3)\n",
+ "R: [\n",
+ "\t-0.000177607, -0.00159482, -0.999999;\n",
+ "\t1, 0.000892652, -0.000179031;\n",
+ "\t0.000892936, -0.999998, 0.00159466\n",
+ "]\n",
+ "t: 30 -2.32307e-06 7.54851e-06\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\n",
+ "Value x1: (gtsam::Pose3)\n",
+ "R: [\n",
+ "\t-0.70921, -0.0013554, -0.704996;\n",
+ "\t0.704997, -0.000423707, -0.709211;\n",
+ "\t0.000662551, -0.999999, 0.00125605\n",
+ "]\n",
+ "t: 21.1492 21.217 0.00448664\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\n",
+ "Value x2: (gtsam::Pose3)\n",
+ "R: [\n",
+ "\t-0.99999, 0.00122015, 0.00435425;\n",
+ "\t-0.00435836, -0.00338973, -0.999985;\n",
+ "\t-0.00120537, -0.999994, 0.00339502\n",
+ "]\n",
+ "t: -0.071174 29.885 -0.0535718\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\n",
+ "Value x3: (gtsam::Pose3)\n",
+ "R: [\n",
+ "\t-0.704649, 0.00599783, 0.709531;\n",
+ "\t-0.709539, 0.000910294, -0.704665;\n",
+ "\t-0.00487234, -0.999982, 0.00361426\n",
+ "]\n",
+ "t: -21.1225 21.048 -0.0176301\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\n",
+ "Value x4: (gtsam::Pose3)\n",
+ "R: [\n",
+ "\t0.00323515, 0.00198442, 0.999993;\n",
+ "\t-0.999977, 0.00598982, 0.00322321;\n",
+ "\t-0.00598338, -0.99998, 0.00200375\n",
+ "]\n",
+ "t: -29.7666 -0.0812114 0.098582\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\n",
+ "Value x5: (gtsam::Pose3)\n",
+ "R: [\n",
+ "\t0.706042, -0.0110079, 0.708085;\n",
+ "\t-0.708169, -0.00886715, 0.705988;\n",
+ "\t-0.00149277, -0.9999, -0.0140561\n",
+ "]\n",
+ "t: -21.0355 -21.006 0.604511\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\n",
+ "Value x6: (gtsam::Pose3)\n",
+ "R: [\n",
+ "\t0.9999, -0.0135399, 0.00416021;\n",
+ "\t-0.00423575, -0.00555538, 0.999976;\n",
+ "\t-0.0135165, -0.999893, -0.00561217\n",
+ "]\n",
+ "t: 0.513276 -29.6569 0.734982\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "**************************************************\n",
+ "Frame 7:\n",
+ "Current estimate: \n",
+ "Values with 16 values:\n",
+ "Value l0: (Eigen::Matrix)\n",
+ "[\n",
+ "\t10;\n",
+ "\t10;\n",
+ "\t9.99999\n",
+ "]\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\n",
+ "Value l1: (Eigen::Matrix)\n",
+ "[\n",
+ "\t-10.151;\n",
+ "\t9.84668;\n",
+ "\t9.97018\n",
+ "]\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\n",
+ "Value l2: (Eigen::Matrix)\n",
+ "[\n",
+ "\t-10.3024;\n",
+ "\t-10.3693;\n",
+ "\t9.90461\n",
+ "]\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\n",
+ "Value l3: (Eigen::Matrix)\n",
+ "[\n",
+ "\t10.0181;\n",
+ "\t-10.108;\n",
+ "\t10.0908\n",
+ "]\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\n",
+ "Value l4: (Eigen::Matrix)\n",
+ "[\n",
+ "\t10.0063;\n",
+ "\t9.9282;\n",
+ "\t-10.0053\n",
+ "]\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\n",
+ "Value l5: (Eigen::Matrix)\n",
+ "[\n",
+ "\t-9.8856;\n",
+ "\t9.9648;\n",
+ "\t-9.94954\n",
+ "]\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\n",
+ "Value l6: (Eigen::Matrix)\n",
+ "[\n",
+ "\t-9.65268;\n",
+ "\t-9.68721;\n",
+ "\t-9.85196\n",
+ "]\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\n",
+ "Value l7: (Eigen::Matrix)\n",
+ "[\n",
+ "\t10.107;\n",
+ "\t-9.90484;\n",
+ "\t-9.88594\n",
+ "]\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\n",
+ "Value x0: (gtsam::Pose3)\n",
+ "R: [\n",
+ "\t-0.00140292, -0.000822064, -0.999999;\n",
+ "\t0.999998, 0.00111816, -0.00140384;\n",
+ "\t0.00111931, -0.999999, 0.000820494\n",
+ "]\n",
+ "t: 30 -7.26208e-06 5.11837e-06\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\n",
+ "Value x1: (gtsam::Pose3)\n",
+ "R: [\n",
+ "\t-0.708757, 0.00307172, -0.705446;\n",
+ "\t0.705449, -6.04046e-06, -0.708761;\n",
+ "\t-0.00218138, -0.999995, -0.00216266\n",
+ "]\n",
+ "t: 21.1763 21.1945 0.0700789\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\n",
+ "Value x2: (gtsam::Pose3)\n",
+ "R: [\n",
+ "\t-0.999981, 0.00457838, 0.00416421;\n",
+ "\t-0.00418486, -0.00450995, -0.999981;\n",
+ "\t-0.00455951, -0.999979, 0.00452903\n",
+ "]\n",
+ "t: -0.0971033 29.9111 -0.126252\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\n",
+ "Value x3: (gtsam::Pose3)\n",
+ "R: [\n",
+ "\t-0.703393, 0.0119506, 0.710701;\n",
+ "\t-0.710741, 0.00120685, -0.703453;\n",
+ "\t-0.00926438, -0.999928, 0.00764487\n",
+ "]\n",
+ "t: -21.2646 21.0034 -0.170016\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\n",
+ "Value x4: (gtsam::Pose3)\n",
+ "R: [\n",
+ "\t0.00720172, 0.0103087, 0.999921;\n",
+ "\t-0.99993, 0.00946178, 0.00710424;\n",
+ "\t-0.00938779, -0.999902, 0.0103761\n",
+ "]\n",
+ "t: -29.8864 -0.275862 -0.165907\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\n",
+ "Value x5: (gtsam::Pose3)\n",
+ "R: [\n",
+ "\t0.707702, -0.00881747, 0.706456;\n",
+ "\t-0.706511, -0.00787646, 0.707658;\n",
+ "\t-0.000675385, -0.99993, -0.0118038\n",
+ "]\n",
+ "t: -21.0699 -21.143 0.554305\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\n",
+ "Value x6: (gtsam::Pose3)\n",
+ "R: [\n",
+ "\t0.999971, -0.00599312, 0.00476305;\n",
+ "\t-0.00479728, -0.00571087, 0.999972;\n",
+ "\t-0.00596575, -0.999966, -0.00573945\n",
+ "]\n",
+ "t: 0.436101 -29.7856 0.775382\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\n",
+ "Value x7: (gtsam::Pose3)\n",
+ "R: [\n",
+ "\t0.711029, -0.0250445, -0.702716;\n",
+ "\t0.703032, 0.0061032, 0.711132;\n",
+ "\t-0.0135212, -0.999668, 0.0219467\n",
+ "]\n",
+ "t: 21.3687 -20.7842 -0.133853\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\n"
+ ]
+ }
+ ],
+ "source": [
+ "# Loop over the different poses, adding the observations to iSAM incrementally\n",
+ "for i, pose in enumerate(poses):\n",
+ " camera = PinholeCameraCal3_S2(pose, K)\n",
+ " # Add factors for each landmark observation\n",
+ " for j, point in enumerate(points):\n",
+ " measurement = camera.project(point)\n",
+ " factor = GenericProjectionFactorCal3_S2(\n",
+ " measurement, camera_noise, X(i), L(j), K)\n",
+ " graph.push_back(factor)\n",
+ "\n",
+ " # Intentionally initialize the variables off from the ground truth\n",
+ " noise = Pose3(r=Rot3.Rodrigues(-0.1, 0.2, 0.25),\n",
+ " t=Point3(0.05, -0.10, 0.20))\n",
+ " initial_xi = pose.compose(noise)\n",
+ "\n",
+ " # Add an initial guess for the current pose\n",
+ " initial_estimate.insert(X(i), initial_xi)\n",
+ "\n",
+ " # If this is the first iteration, add a prior on the first pose to set the coordinate frame\n",
+ " # and a prior on the first landmark to set the scale\n",
+ " # Also, as iSAM solves incrementally, we must wait until each is observed at least twice before\n",
+ " # adding it to iSAM.\n",
+ " if i == 0:\n",
+ " # Add a prior on pose x0, with 0.3 rad std on roll,pitch,yaw and 0.1m x,y,z\n",
+ " pose_noise = gtsam.noiseModel.Diagonal.Sigmas(\n",
+ " np.array([0.3, 0.3, 0.3, 0.1, 0.1, 0.1]))\n",
+ " factor = PriorFactorPose3(X(0), poses[0], pose_noise)\n",
+ " graph.push_back(factor)\n",
+ "\n",
+ " # Add a prior on landmark l0\n",
+ " point_noise = gtsam.noiseModel.Isotropic.Sigma(3, 0.1)\n",
+ " factor = PriorFactorPoint3(L(0), points[0], point_noise)\n",
+ " graph.push_back(factor)\n",
+ "\n",
+ " # Add initial guesses to all observed landmarks\n",
+ " noise = np.array([-0.25, 0.20, 0.15])\n",
+ " for j, point in enumerate(points):\n",
+ " # Intentionally initialize the variables off from the ground truth\n",
+ " initial_lj = points[j] + noise\n",
+ " initial_estimate.insert(L(j), initial_lj)\n",
+ " else:\n",
+ " # Update iSAM with the new factors\n",
+ " isam.update(graph, initial_estimate)\n",
+ " current_estimate = isam.estimate()\n",
+ " print('*' * 50)\n",
+ " print('Frame {}:'.format(i))\n",
+ " current_estimate.print('Current estimate: ')\n",
+ "\n",
+ " # Clear the factor graph and values for the next iteration\n",
+ " graph.resize(0)\n",
+ " initial_estimate.clear()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "38ae5d6f",
+ "metadata": {},
+ "source": [
+ "## 4. Visualize the final estimate\n",
+ "\n",
+ "The printed `Values` above are hard to picture -- 8 poses and 8 landmarks as raw numbers. Plotting the final iSAM estimate in 3D shows the payoff directly: the recovered landmarks should form roughly a cube, and the recovered camera poses should trace out roughly a circle around it, despite every pose and landmark having started from a deliberately wrong initial guess."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 6,
+ "id": "6a105ec5",
+ "metadata": {
+ "execution": {
+ "iopub.execute_input": "2026-07-22T10:37:41.430389Z",
+ "iopub.status.busy": "2026-07-22T10:37:41.430315Z",
+ "iopub.status.idle": "2026-07-22T10:37:41.510405Z",
+ "shell.execute_reply": "2026-07-22T10:37:41.510058Z"
+ }
+ },
+ "outputs": [
+ {
+ "data": {
+ "image/png": "iVBORw0KGgoAAAANSUhEUgAAAbEAAAG+CAYAAAAdhjpkAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjExLjEsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvctoD+AAAAAlwSFlzAAAPYQAAD2EBqD+naQAAu7JJREFUeJztnQW4XdXRhldubowWl+AOwV1CAyFYgrs7xWlxKBQvFGmRUqAEKT8OwQsUd4JLKC4t7gRLQiF+/uddYU7X3TmyZW07Zz6e/Vxy5Zx99l57vjUz38x0q1QqFaNQKBQKRQnRkfcJKBQKhUIRF0piCoVCoSgtlMQUCoVCUVooiSkUCoWitFASUygUCkVpoSSmUCgUitJCSUyhUCgUpYWSmEKhUChKCyWxkuPhhx8266+/vvnkk08K8T5ZnU8rYOzYsfZa3XjjjXmfikJRWnTmfQKK+hg9erTZdttt6/78H//4h/nss8/MfffdZ3744YdUL2XY96n3e+PHjzfXXHONee6558yXX35p5pprLrPKKquYbbbZxvTp06fma02ePNlsv/329jr8+c9/Nssss0zN39too43MpEmTzFprrWWOOuqoqX7+4osvmmOPPdb+/+9//3uz5pprNvwM8nq1MM8885hLL73URL2He++9t9lqq626/GzixIn2Wg0aNMjkgUbnplCUBUpiBQaGHyO34YYbmgMPPHCqn/fo0cOss8465p577rHGtQiodT4ffPCBWXvtte3n4XMMGTLEvP/+++akk04yBx98sHnrrbdM3759p3qtBx54wNx00032c1500UXmwgsvrPmeXCMI79lnn7Wv17t37y4/v/jii+1r8Tu7775708/A60GwJ5xwwlQ/++Uvf2ni3MN11113qp9B3lyrfv36mTzQ6NwUirJASawEgBAIO9XCHHPMYY+ioNb5HHfccebDDz80//73v82CCy5Y/f6+++5rdt11V/PTTz/VfC08nkUXXdRssskm5u9//7s566yzzDTTTFPzd/GuHn/8ceud4r0JeO0bbrjBkuiDDz4Y+nPMNttsda+5L3Tv3j3191AoWh2aEys5auWg7rzzTvu9r7/+2hp2vI8tt9zS/PWvfzUTJkzo8vf/+te/7O9ybLDBBvb3CL1BOL7O57XXXrPhQ5fAwC9+8QubD6pFwiNHjjR33HGH2X///c0BBxxgQ194ZfXA6+NRXHHFFV2+f8stt5gff/zR7LzzziYNvPnmmzaEufXWW9vr/Le//c3mugDXcLvttrP/DwnLdT733HPr5sS4Z3yPe4i3esghh9hQHwSO5wTee+89c+ihh5rNN9/ceotjxoyZ6ry22GKL6vuxCdhvv/2s1yVodm6Cl19+2RxxxBH2vXbYYQf7u8E1pFDkCSWxkqNWDgqvh+9dddVVZujQodY4rbzyytbYQghBLw9DyXHQQQdZY0UOifzTK6+84uV8FllkEft9yKyWN9KrV6+pvg8ZEUaEGCA/QpDNclF77LGHDRt++umn1e9dfvnllpxrhSuT4umnnzbLLbecfT9yS4MHDzbvvPOOWW+99ezPeU+8TbDGGmtUr7P8XHJikJIAYuN7jz32mP3bZZdd1v7+aaedZvbaay8beuXrUkstZcPMhFiFjFz85je/qb7fbrvtZj1YyOzMM88MdW7gggsuMCuuuKL56quvrHfL75188sn2cwqhKhS5g1EsimJi5MiRjMmpzDPPPJUhQ4Z0Oa688kr7O1dffbX9nTfffLP6d+eff7793q677trl9U488cRK9+7dK59++mnD9508eXJlpZVWqmy++ebV79V6n1qo9XtvvPFGZeaZZ6707t27ssMOO1SGDh1aeeaZZyqTJk2q+zr9+vWr7LnnntV/33HHHfZ1ea0g+Ew77bRT5aeffqrMMMMMldNPP91+/4MPPqh069atcuutt1buuece+/fXX399w/OX15ttttmmuuYc5513XvX39t1338q888471d9/8803U93DM888c6rfGzNmjP2ZnC/4+OOPq/ecnwsuueQS+1kGDRpUGTVqVPX7l112mf39l19+uennOvnkkys9e/asjB07tum5/etf/6p0dHRUjj766C7ff/fdd+1rnHXWWU3fT6HIApoTKwGWXnrpqYQdCy20UNO/YwcezBv94Q9/sCGwOeecs/r9119/3Vx33XXm7bffNv/973/Z2FjP6bvvvvNy/osvvrgNX6FOJNyIN4D3MdNMM5ljjjnGHHbYYaZbt27V3ycEyrlwTq5icL755rPhrLPPPrvm+yDowCu58sorzdFHH229uZlnntlsvPHG5qGHHop0zlxfPJMg5p133ur/TzvttOaLL76woT/Or6NjSmCDz5UUhANdEcmvfvUre1+WWGIJM91001W/P2DAAPsVr9lVb3LvuA4vvPCC/X/UlnhUeFDcCzy5Rrj66qutECZ4DfCKeU9yj4cffnjiz6lQJIWSWMmFHY2wwAILdPn3LLPMYr8icRfceuutNhS26aab2nATggZCfBAN5OYLM844oyViIWPyPRhB8i28n2ssCRt2dnZagnNB+I0Q6emnn2569uxZ830IP6JGJNTH7+600042LBkVYYQdRx55pFVEcu24tgMHDrShNsQq9coGwmL++efv8m8hxnrfh6AEbEBQV04//fRmn332sX9DyPaJJ54wL730UqhyjP/85z/2vuy555723xCozM8lpFkrBKxQ5AElsRZG0HiLt8MOW3DiiSdagweZuaAuK01AsHhakNuwYcOqJPb9999bMQYe4worrNDlbzCi1JXddtttNfNAoH///maxxRazghC8vTCS+riA6PAayYM9+uij5pFHHrGfA0/x+eeftyTi+96FuafkQSEyzsEVzXCeYcEmgeO3v/1tzZ8HyxgUirygJNbmwCtbaaWVunwPIiEMVU/OHhV33XWXDbcFgZHE4xI1HyDkiMeFx0a4LggKmgkp1iMxCaNS1IzogiNtUAbAgdeDnB8RBISGSEZIp17xdFr3FAINqj4RvbhodG6EDFGDEnauV2SuUBQBqk5sc6BaxLgh7QbkTFC2zT333N7eA2+PkOVHH31U/R5ERbEzoS3k6QIIivxPLQIDKA3Jb7mKviCQk1NEfP3115s0QdiS/KILPCAgBAKZcDQ63zTuKRuRe++9t/o98mMUnbtodG6EERdeeGHz61//eqq/IywZ9NwVirygnlibg9oxcmHI4En2Y7AQRbBLd41gEpA7on4KUQCScerDEG7ggVGThtcEaElFXRI5r3qAxAgrXnbZZebUU0+t+TszzDBD4iJicmr1XkOuC3kwvK5Ro0bZvBO1bQg9CCeuuuqq1d/nM3JN+WxybrVEI74A8UD0CFrwshF2cN05D2q9XNQ7N0QlhEjZEBCepasIGwtyZfz7jDPOSO38FYoo6IZEMdJfKDIDRaUYIxRxqNJq4fPPP7cGiBoeyAHg8bzxxhs29OYm4PF62EVj0NxQE14Rv48xhsjIU7366qvWO+M16r1P2PMR4B28++679uuss85qjaEr0EDsAblheEWEUgt03sCgClHcf//9ZvbZZ28Y9uKzECIlvMjvNgKv5+aY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Rdth8803rwwaNKj67zFjxlRmmGGGyp/+9Kdcz0sxBePGjatstNFGlemmm64y22yz2Xuz4447Vm644YbKN998U/nvf/8b+rjmmmsq00wzTeXOO+8szOX9+uuvK99++22X751xxhmVPn36VCZOnGj/PWHChErfvn0rxx13XPV37r333gom69VXX838nBXFhXpibQia3hK+ISdy+eWXmw033NAq2HyNbFfEB2KMgw46yO76yV8RSqQdFB06aJ9EUTptk6hNazZ/C3UkBbuEDPH4igLydMGcLA2RqV+UxtasTwQpbnNdclJ0++dzKRQCJbE2BAWd1IhhTBgbs/baa5unn346NQkxxolC0kZGl98hpEkuqN2BHJ+8GB3UkcjTjf3cc8817733nq0/m2+++WyzYghtp512smFCckwuuK977LGHDVWSgysyCHlecskldrKDqP9YL8DtJEMYlBouxtgoFAKV2CtSAyNGzjvvPNs1nF01rZpk7pJrwGg+S2cEcnV4ImeddZYdyqioD64T88OQ7VOQy7WWmWioIffaay8rGoHksuio/vvf/75m6zQBGyTucS1AyAwtffLJJ6vDXi+99FLrRfI53fOnLAAiy0uQoigetP25IjUgTWakB7U29XozYmg5MGA0sh02bJg1vPTxY8CgojbwSrheHIwCIfSIeo8uHNT6IePPisAARdMyGqUW3KnkLmh1xqYFqb8QGJBJ21LXKKCQm0iCQlFF3kk5ResD4QhL7bbbbpvqZ0svvXRlv/326/K9lVZaqbLLLrtkeIatg8mTJ1eGDx9uvxYdZ511VqV3796V+++/f6qfvf7663bN8FkEP/74oxWpXHjhhRmfqaLI0JxYgcBumvBJu3WLX2211bp8nxxQvbohRWPgeXH9ij6UEU+RmXh4YAg2gqBAGzk74WgBIUbCz8GQtKK9oeHEAoFQEEXI119/vWkHEBrCKCEwcYECjYa2itYE89ioW6MpMgXYHAL6ecpU6SuuuMKsv/76ttiYNUJXk6FDh1rhi0IhUBIrEJC6I2hg1Lw7pfell16yxaGtNsFZegYGFYnMzUKVp2jdBtSUdtQCLbEE5MhQKaLUxGvnb4TgFApBa1nFkoOwCp4Ycnc6GFAzs++++1pVH4MLt9lmG9NKoDaNThR0q3DBv5GXK1oT3Ftq3cIApeUmm2yS+jkpygvNiRUIKLJQ5NEtm6nL1M0go37++edbjsCA1EDRx09ATpAaJ0bDKBQKRTMoiRUwpEiBKr3tIDQIjNxBGUFxM+EginTd6bluvovkPh0YTj/9dPtZ9957b1u4SyNchUKhaAYtdi4QMN6EWShepTD0t7/9rSkzHnzwQbPffvtN9X06STBdWkBndWqFPv30Uzua5A9/+IPWAikUilBQEisICBsyc4qiUEY+MJ6CrgthPDcM/1ZbbWU7fitM1etjhhZF1MjN8WoPP/zwqXr2UZBNSye6TSDr5rovtNBCehkVipJAw4kFALLh/v37m4EDB9ruFrQOYvJuGODBYJgJw6FgJJemMFYYQxurk046yRx99NG25yBjSJjdJUD1hoSbbhOUN4wbN85uBEaOHKmXUKEoC/Kutm5njBo1qrLttttWfvnLX9qRGYK77rqrMu2009qRHGFBh4bf//73lQUXXLBLt4Z//etfdqxFIzDi47333qu0EsaOHdvl3++++67tAPHAAw9Uvzdw4MDK1ltvXf33+PHj7eiTE088MdNzVSgU8aGeWI4gdLjLLrvY7hT0uRPgMVA7NXz48IZ/j/QeQQQ98/AeGOGBiOKTTz6p/g6DFht1MUfST46KrvathOAQSamxk44oeF0U3RKOFfTo0cMMHjzYemiK+qBmi+gBa3bnnXe2XTVqTShAZcr63nLLLe3AS+r/FArfUBLLEYybZ85Tv379uny/T58+VmLeKKTIyHa6fL///vu2CJTX2GCDDayxdjtgEJoklCajOiA7/hbRBeD7u+22Wxdj3oogrMhUa8kbkjOjqDzY/YF/B6deK7qCtfn222/btcUYH8aosPHiegpYk5tuuqlt5EydF0Ilcr4KhXck8OIUKeKVV16p/OUvf6n5M8KDvXr1qtx6661dwmfrr79+l4nNgEm5s846qw0ZPvLII5U555yzsuqqq1bef/99+3Pe44knnmjpe3nOOedUevbsWXn44Yer3/vPf/5jw4sPPfRQl99lkvDcc8+dw1mWB999912Xfz///PP2WhK6lvXJmjvppJOqv/PCCy/Y33n88cczP19Fa0M9sYICkcYhhxxS82ey43VbM+E9PPbYY1al6ILfwdtjZhcdQXbccUcbpmQ0CiIH6rTc8GOrgbAXwg5CrngLAvFWv/nmmy6/z7/p3aiojxlmmKHLv19++WXbLkpaQo0YMcJ6/G6jXvofMsyTEKNC4RPadqqkubRTTjnFhgEhJQwIbakgpWD+i874zzzzjB2ayEh7QkACDAqEuNFGG9l/P/zww1aGjsQfSToERziorGBOGRsBJh8HWxdhiBdccEGrBnW7oZAno1OKojFuvPFGW5TPsFNC0oSnhfxZa4DhlcF2U/IzhcIXlMRKiiOPPNJ6WOTNSLSz02UoodsgFSNz4IEH2h0xxiM4mBDvZMiQIbY/HYIHCPHXv/61TcZDaJDbnXfeWcqOIYztEAIjN1ML9KX885//bMsTyClimClRuPjii0074Te/+Y1599136/6cHC0iIhcrr7yyndZMBADRBhse1iLiGBFw8HcuKHlQcYfCN7TYuUXANF+m4DKbi8bB+++/vx1dT0KdzvgQ2ZxzzmkuvPBC+/sYExrw8nNIC3UZvRsJSdLPUMJE77zzTun6NqK4hJg56Jjugk4hO+ywg/3/SZMmWQOOCIHwItft7LPPtqTWTsD7HD16dN2fIxZad9116/4ckQybp2uuucZeW9qI4fkSpnY3VWy0OBCCKBS+oJ5Yi8AN+xEO5N9u30VI7LjjjjN/+9vfbAcLFIt4cOKlEJI85phjrIKMPBJhR4YScpQNeJz1ir4hcjdfSMjxjDPOsDkcwl9BbzUJKHcgnAtBEqJEjRoE4ThCmlx/Ng/B0oAsQOg4Cfr27WvPn64nQNYMI4SExFhrKBrx9BUKr8hbWaLIBl9//XWls7PTKsnA7rvvXtlwww2n+j0Kreebb77Kjjvu2LRIWlEbn3/+uVWK9uvXr7Lpppvar6hCn3rqqS6/d+WVV1ammWYaW3S92GKL2ev+9ttvF/qycn733Xdfl+9ddNFFlW7dulVGjBhR/d7aa69dWWuttWwBOTjjjDPsZ/3iiy8yP2dFa0NJrI3wwQcfVN56663KpEmTKrPMMkvlsssus9+/5557Ko8++mj197799tvKXHPNVTn//PNzPNvyAvn+8OHDu3xvq622qqywwgrVf3/88ce2TGLo0KHVUojBgwdXVl999UqRMXLkyMqWW25ZmXfeeStrrrmm7RAzxxxzVC6//PKp1triiy9u19EyyyxjO9DccsstuZ23onWh4cQ2AhJnAfkucmAAuT2F0gghpOkwQg+3eFURHjQQDjYRXnTRRbuEOBHVEDqU8BqhTa4/ReeIcLgnRQQKRHKt5MHIl/LvhRdeeKpQKWvttddes3J7cpTLL7+8FYIoFL6hJNamcHNDdMEnR0YtGXkz8hc00EUQoogPZOfkvBDdXH311V1Uj6+++qpVRLrGn9pAgPEvKokJ6H7C0QgdHR1arqBIHUpiCgt20+yw8b5QLiKHViQDSs833njDemALLLBAF6Uk5RAzzTRTl9+XAmxUpgqFIhyUxBRdF0RnZ7VZriIZKEiX0Cx9LqnrY7I115dQIiE5F0j8gU+FpELR6tC2UwpF2g9ZR4ft+P7hhx+ajz76yH6PnJn8v4CfAzqJKBSKcFASUyg8I+hhAUbdkP+iwBwg4KDbBTVightuuMHmKpdbbjm9JwpFSGjcSKHwjGHDhpm77rrLtvQi78W8OLqCnHrqqbaLCGCSN22+tt56a9uv8rPPPjPnnnuuufbaa63nplAowkHbTikUKYCmyzRcphMIgg5ady2xxBJdfodcGUNLH3/8cSukgdSSds9QKNoNSmIKhUKhKC00bqFQKBSK0kJJTKFQKBSlhZKYQqFQKEoLJTGFQqFQlBZKYgqFQqEoLZTEFAqFQlFaKIkpFAqForRQElMoFApFaaEkplAoFIrSQklMoVAoFKWFkphCoVAoSgslMYVCoVCYsuL/AWzgZJ/ofIarAAAAAElFTkSuQmCC",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "gtsam_plot.plot_3d_points(0, current_estimate, linespec=\"g*\", title=\"Final iSAM Estimate\")\n",
+ "for i in range(len(poses)):\n",
+ " if current_estimate.exists(X(i)):\n",
+ " gtsam_plot.plot_pose3(0, current_estimate.atPose3(X(i)), axis_length=3)\n",
+ "plt.show()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "31d41aea",
+ "metadata": {},
+ "source": [
+ "This is exactly the kind of incremental estimation problem `NonlinearISAM` was built for -- and it's the direct predecessor to `ISAM2`, GTSAM's more efficient incremental solver, used in the companion `VisualISAM2Example` notebook."
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.13.12"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
\ No newline at end of file
diff --git a/python/gtsam/examples/VisualISAMExample.py b/python/gtsam/examples/VisualISAMExample.py
deleted file mode 100644
index 48e803919a..0000000000
--- a/python/gtsam/examples/VisualISAMExample.py
+++ /dev/null
@@ -1,103 +0,0 @@
-"""
-GTSAM Copyright 2010, Georgia Tech Research Corporation,
-Atlanta, Georgia 30332-0415
-All Rights Reserved
-Authors: Frank Dellaert, et al. (see THANKS for the full author list)
-
-See LICENSE for the license information
-
-A visualSLAM example for the structure-from-motion problem on a simulated dataset
-This version uses iSAM to solve the problem incrementally
-"""
-
-import numpy as np
-import gtsam
-from gtsam.examples import SFMdata
-from gtsam import (Cal3_S2, GenericProjectionFactorCal3_S2,
- NonlinearFactorGraph, NonlinearISAM, Pose3,
- PriorFactorPoint3, PriorFactorPose3, Rot3,
- PinholeCameraCal3_S2, Values, Point3)
-from gtsam.symbol_shorthand import X, L
-
-def main():
- """
- A structure-from-motion example with landmarks
- - The landmarks form a 10 meter cube
- - The robot rotates around the landmarks, always facing towards the cube
- """
-
- # Define the camera calibration parameters
- K = Cal3_S2(50.0, 50.0, 0.0, 50.0, 50.0)
-
- # Define the camera observation noise model
- camera_noise = gtsam.noiseModel.Isotropic.Sigma(
- 2, 1.0) # one pixel in u and v
-
- # Create the set of ground-truth landmarks
- points = SFMdata.createPoints()
- # Create the set of ground-truth poses
- poses = SFMdata.createPoses()
-
- # Create a NonlinearISAM object which will relinearize and reorder the variables
- # every "reorderInterval" updates
- isam = NonlinearISAM(reorderInterval=3)
-
- # Create a Factor Graph and Values to hold the new data
- graph = NonlinearFactorGraph()
- initial_estimate = Values()
-
- # Loop over the different poses, adding the observations to iSAM incrementally
- for i, pose in enumerate(poses):
- camera = PinholeCameraCal3_S2(pose, K)
- # Add factors for each landmark observation
- for j, point in enumerate(points):
- measurement = camera.project(point)
- factor = GenericProjectionFactorCal3_S2(
- measurement, camera_noise, X(i), L(j), K)
- graph.push_back(factor)
-
- # Intentionally initialize the variables off from the ground truth
- noise = Pose3(r=Rot3.Rodrigues(-0.1, 0.2, 0.25),
- t=Point3(0.05, -0.10, 0.20))
- initial_xi = pose.compose(noise)
-
- # Add an initial guess for the current pose
- initial_estimate.insert(X(i), initial_xi)
-
- # If this is the first iteration, add a prior on the first pose to set the coordinate frame
- # and a prior on the first landmark to set the scale
- # Also, as iSAM solves incrementally, we must wait until each is observed at least twice before
- # adding it to iSAM.
- if i == 0:
- # Add a prior on pose x0, with 0.3 rad std on roll,pitch,yaw and 0.1m x,y,z
- pose_noise = gtsam.noiseModel.Diagonal.Sigmas(
- np.array([0.3, 0.3, 0.3, 0.1, 0.1, 0.1]))
- factor = PriorFactorPose3(X(0), poses[0], pose_noise)
- graph.push_back(factor)
-
- # Add a prior on landmark l0
- point_noise = gtsam.noiseModel.Isotropic.Sigma(3, 0.1)
- factor = PriorFactorPoint3(L(0), points[0], point_noise)
- graph.push_back(factor)
-
- # Add initial guesses to all observed landmarks
- noise = np.array([-0.25, 0.20, 0.15])
- for j, point in enumerate(points):
- # Intentionally initialize the variables off from the ground truth
- initial_lj = points[j] + noise
- initial_estimate.insert(L(j), initial_lj)
- else:
- # Update iSAM with the new factors
- isam.update(graph, initial_estimate)
- current_estimate = isam.estimate()
- print('*' * 50)
- print('Frame {}:'.format(i))
- current_estimate.print('Current estimate: ')
-
- # Clear the factor graph and values for the next iteration
- graph.resize(0)
- initial_estimate.clear()
-
-
-if __name__ == '__main__':
- main()