diff --git a/gtsam/linear/doc/Factors.ipynb b/gtsam/linear/doc/Factors.ipynb new file mode 100644 index 0000000000..4ea5c6a95c --- /dev/null +++ b/gtsam/linear/doc/Factors.ipynb @@ -0,0 +1,151 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "e08a484b", + "metadata": {}, + "source": [ + "# Factors (Jacobian / Hessian / Regular)\n", + "\n", + "This notebook groups the various factor types (JacobianFactor, BinaryJacobianFactor, HessianFactor, RegularHessianFactor, RegularJacobianFactor) together, showing construction patterns and small numpy examples that illustrate each concept." + ] + }, + { + "cell_type": "markdown", + "id": "3bef0e5a", + "metadata": {}, + "source": [ + "\"Open" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "bd07b6dc", + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " import google.colab\n", + " %pip install --quiet gtsam\n", + "except ImportError:\n", + " pass" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b52f6b46", + "metadata": {}, + "outputs": [], + "source": [ + "import gtsam\n", + "import numpy as np" + ] + }, + { + "cell_type": "markdown", + "id": "4fc0b36e", + "metadata": {}, + "source": [ + "## JacobianFactor and BinaryJacobianFactor\n", + "\n", + "Jacobian factors represent linear rows; binary variants connect two variable blocks. We try to construct them and show a numpy least-squares example." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "605445f9", + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " jf = gtsam.JacobianFactor()\n", + " bjf = gtsam.BinaryJacobianFactor()\n", + "except Exception as e:\n", + " jf = None\n", + " bjf = None\n", + " print('JacobianFactor/BinaryJacobianFactor not available in Python bindings:', e)\n", + "\n", + "# LS example (numpy)\n", + "J = np.array([[1.0, 2.0],[3.0,4.0]])\n", + "b = np.array([1.0,2.0])\n", + "x, residuals, rank, s = np.linalg.lstsq(J, b, rcond=None)\n", + "print('Least-squares (numpy):', x)\n", + "x" + ] + }, + { + "cell_type": "markdown", + "id": "6bfe3cd8", + "metadata": {}, + "source": [ + "## HessianFactor and RegularHessianFactor\n", + "\n", + "Hessian factors work in information form. We try to construct them and show a small MAP solve via numpy." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f6f411bd", + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " hf = gtsam.HessianFactor()\n", + " rhf = gtsam.RegularHessianFactor()\n", + "except Exception as e:\n", + " hf = None\n", + " rhf = None\n", + " print('HessianFactor/RegularHessianFactor not available in Python bindings:', e)\n", + "\n", + "# MAP solve (numpy)\n", + "H = np.array([[4.0,0.0],[0.0,2.0]])\n", + "g = np.array([-2.0,-2.0])\n", + "x = np.linalg.solve(H, -g)\n", + "print('MAP estimate (numpy):', x)\n", + "x" + ] + }, + { + "cell_type": "markdown", + "id": "e2e3d4a8", + "metadata": {}, + "source": [ + "## RegularJacobianFactor\n", + "\n", + "Regular Jacobian factors have block regular structure; we include a small numpy example for least-squares." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "af4f4b9c", + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " rjf = gtsam.RegularJacobianFactor()\n", + "except Exception as e:\n", + " rjf = None\n", + " print('RegularJacobianFactor not available in Python bindings:', e)\n", + "\n", + "# Example (numpy)\n", + "J = np.eye(2)\n", + "b = np.array([0.5,-0.5])\n", + "x, *_ = np.linalg.lstsq(J, b, rcond=None)\n", + "print('LS (numpy):', x)\n", + "x" + ] + } + ], + "metadata": { + "language_info": { + "name": "python" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/gtsam/linear/doc/GaussianOverview.ipynb b/gtsam/linear/doc/GaussianOverview.ipynb new file mode 100644 index 0000000000..8500fa9c0e --- /dev/null +++ b/gtsam/linear/doc/GaussianOverview.ipynb @@ -0,0 +1,222 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "65e5517c", + "metadata": {}, + "source": [ + "# Gaussian Overview\n", + "\n", + "This notebook combines the Gaussian-related notebooks (Bayes nets, Bayes trees, conditionals, densities, elimination trees, junction trees, ISAM, factors, and factor graphs) into one consolidated guide. It follows the style of the existing documentation notebooks and includes guarded Python examples that fall back to numpy where bindings are not available." + ] + }, + { + "cell_type": "markdown", + "id": "58a2fcf2", + "metadata": {}, + "source": [ + "\"Open" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5c13d0b9", + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " import google.colab\n", + " %pip install --quiet gtsam\n", + "except ImportError:\n", + " pass" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1692f36a", + "metadata": {}, + "outputs": [], + "source": [ + "import gtsam\n", + "import numpy as np\n", + "import graphviz" + ] + }, + { + "cell_type": "markdown", + "id": "742a3727", + "metadata": {}, + "source": [ + "## GaussianFactor and GaussianFactorGraph\n", + "\n", + "`GaussianFactor` objects contribute linear rows to a system; `GaussianFactorGraph` collects them and can solve the resulting linear system. Below we show guarded construction and a small numpy example." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e861ce74", + "metadata": {}, + "outputs": [], + "source": [ + "# Guarded construction examples\n", + "try:\n", + " gf = gtsam.GaussianFactor()\n", + " gfg = gtsam.GaussianFactorGraph()\n", + "except Exception as e:\n", + " gf = None\n", + " gfg = None\n", + " print('GaussianFactor/GaussianFactorGraph not available in Python bindings:', e)\n", + "\n", + "# Numpy example: form and solve a small system\n", + "A = np.array([[3.0, -1.0], [-1.0, 2.0]])\n", + "b = np.array([1.0, 0.0])\n", + "x = np.linalg.solve(A, b)\n", + "print('Solve (numpy):', x)\n", + "x" + ] + }, + { + "cell_type": "markdown", + "id": "8893299e", + "metadata": {}, + "source": [ + "## GaussianBayesNet and GaussianConditional\n", + "\n", + "A `GaussianBayesNet` is a sequence of `GaussianConditional`s (conditionals). We attempt to construct them if available and otherwise show how a conditional relates to block matrices." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "83a1b87d", + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " gbn = gtsam.GaussianBayesNet()\n", + " gc = gtsam.GaussianConditional()\n", + "except Exception as e:\n", + " gbn = None\n", + " gc = None\n", + " print('GaussianBayesNet/GaussianConditional not available in Python bindings:', e)\n", + "\n", + "# Numpy illustration: solve a small conditional block\n", + "A = np.array([[2.0, -1.0], [-1.0, 2.0]])\n", + "b = np.array([1.0, 0.0])\n", + "x = np.linalg.solve(A, b)\n", + "print('Example conditional solve (numpy):', x)\n", + "x" + ] + }, + { + "cell_type": "markdown", + "id": "df4d9ff3", + "metadata": {}, + "source": [ + "## GaussianBayesTree and GaussianEliminationTree\n", + "\n", + "Bayes trees and elimination trees capture elimination structure for efficient inference. If bindings exist we construct them; otherwise we show a small elimination example using numpy solves." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a5ea2b4e", + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " gbt = gtsam.GaussianBayesTree()\n", + " getree = gtsam.GaussianEliminationTree()\n", + "except Exception as e:\n", + " gbt = None\n", + " getree = None\n", + " print('GaussianBayesTree/GaussianEliminationTree not available in Python bindings:', e)\n", + "\n", + "# Numpy elimination demo\n", + "A = np.array([[4.0, -1.0], [-1.0, 3.0]])\n", + "b = np.array([1.0, 2.0])\n", + "x = np.linalg.solve(A, b)\n", + "print('Elimination example (numpy):', x)\n", + "x" + ] + }, + { + "cell_type": "markdown", + "id": "a39b1efa", + "metadata": {}, + "source": [ + "## GaussianDensity and GaussianJunctionTree\n", + "\n", + "`GaussianDensity` stores densities (unnormalized); `GaussianJunctionTree` supports junction-tree algorithms. Below we show a pdf evaluation and a linear solve example." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "aa40cc22", + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " gd = gtsam.GaussianDensity()\n", + " gjt = gtsam.GaussianJunctionTree()\n", + "except Exception as e:\n", + " gd = None\n", + " gjt = None\n", + " print('GaussianDensity/GaussianJunctionTree not available in Python bindings:', e)\n", + "\n", + "# Numpy gaussian pdf example\n", + "x = np.array([0.1, -0.2])\n", + "mu = np.zeros(2)\n", + "Sigma = np.eye(2)\n", + "det = np.linalg.det(Sigma)\n", + "norm = 1.0 / (2*np.pi*np.sqrt(det))\n", + "val = norm * np.exp(-0.5 * (x-mu).T @ np.linalg.inv(Sigma) @ (x-mu))\n", + "print('Gaussian pdf (numpy):', val)\n", + "val" + ] + }, + { + "cell_type": "markdown", + "id": "28cc2dd0", + "metadata": {}, + "source": [ + "## GaussianISAM (incremental)\n", + "\n", + "`GaussianISAM` is an incremental solver. We try to construct it and otherwise show a simple incremental idea with numpy." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "cce797dc", + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " gisam = gtsam.GaussianISAM()\n", + "except Exception as e:\n", + " gisam = None\n", + " print('GaussianISAM not available in Python bindings:', e)\n", + "\n", + "# Numpy incremental illustration (single step)\n", + "A = np.array([[2.0, 0.0],[0.0,2.0]])\n", + "b = np.array([1.0, 1.0])\n", + "x = np.linalg.solve(A, b)\n", + "print('Incremental example (numpy):', x)\n", + "x" + ] + } + ], + "metadata": { + "language_info": { + "name": "python" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/gtsam/linear/doc/SolversAndMethods.ipynb b/gtsam/linear/doc/SolversAndMethods.ipynb new file mode 100644 index 0000000000..b03a2aa7e2 --- /dev/null +++ b/gtsam/linear/doc/SolversAndMethods.ipynb @@ -0,0 +1,181 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "8f93b7a0", + "metadata": {}, + "source": [ + "# Solvers and Methods\n", + "\n", + "This notebook groups solvers and numerical methods: ConjugateGradientSolver, PCGSolver, IterativeSolver, iterative utilities, Preconditioner, Subgraph-based preconditioning/solving, PowerMethod, SparseEigen helpers, etc. It provides guarded constructions and numpy fallbacks for demonstrations." + ] + }, + { + "cell_type": "markdown", + "id": "32341a0c", + "metadata": {}, + "source": [ + "\"Open" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9363d058", + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " import google.colab\n", + " %pip install --quiet gtsam\n", + "except ImportError:\n", + " pass" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "be207126", + "metadata": {}, + "outputs": [], + "source": [ + "import gtsam\n", + "import numpy as np" + ] + }, + { + "cell_type": "markdown", + "id": "a4b3520a", + "metadata": {}, + "source": [ + "## ConjugateGradientSolver and PCGSolver\n", + "\n", + "Try to create solver objects and otherwise solve with numpy (direct solve as reference)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c617ae7f", + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " cgs = gtsam.ConjugateGradientSolver()\n", + " pcg = gtsam.PCGSolver()\n", + "except Exception as e:\n", + " cgs = None\n", + " pcg = None\n", + " print('ConjugateGradientSolver/PCGSolver not available in Python bindings:', e)\n", + "\n", + "# Reference solve (numpy)\n", + "A = np.array([[6.0,2.0],[2.0,5.0]])\n", + "b = np.array([1.0,2.0])\n", + "x = np.linalg.solve(A, b)\n", + "print('Reference solve (numpy):', x)\n", + "x" + ] + }, + { + "cell_type": "markdown", + "id": "593bfbed", + "metadata": {}, + "source": [ + "## IterativeSolver and iterative utilities\n", + "\n", + "Show a simple iterative method (Jacobi) as a demonstration." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "49460ca1", + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " its = gtsam.IterativeSolver()\n", + "except Exception as e:\n", + " its = None\n", + " print('IterativeSolver not available in Python bindings:', e)\n", + "\n", + "# Jacobi iteration (numpy)\n", + "A = np.array([[4.0,-1.0],[-1.0,3.0]])\n", + "b = np.array([15.0,10.0])\n", + "x = np.zeros(2)\n", + "for _ in range(10):\n", + " x = (b - (A - np.diag(np.diag(A))) @ x) / np.diag(A)\n", + "print('Jacobi iterate (numpy):', x)\n", + "x" + ] + }, + { + "cell_type": "markdown", + "id": "537a9cc8", + "metadata": {}, + "source": [ + "## Preconditioners and Subgraph-based methods\n", + "\n", + "Show a diagonal preconditioner and conceptual subgraph preconditioning/solving examples." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "163fb2d2", + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " pre = gtsam.Preconditioner()\n", + " sgb = gtsam.SubgraphBuilder()\n", + " sgs = gtsam.SubgraphSolver()\n", + " sgp = gtsam.SubgraphPreconditioner()\n", + "except Exception as e:\n", + " pre = None\n", + " sgb = sgs = sgp = None\n", + " print('Preconditioner/Subgraph* bindings not available:', e)\n", + "\n", + "# Diagonal preconditioner (numpy)\n", + "A = np.array([[10.0,1.0],[1.0,5.0]])\n", + "M_inv = np.diag(1.0/np.diag(A))\n", + "print('Diagonal preconditioner (M^-1):', M_inv)\n", + "M_inv" + ] + }, + { + "cell_type": "markdown", + "id": "76bf3b28", + "metadata": {}, + "source": [ + "## PowerMethod and SparseEigen\n", + "\n", + "Compute dominant eigenvector with numpy power iteration as a fallback for sparse eigen helpers." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "21592c52", + "metadata": {}, + "outputs": [], + "source": [ + "# Numpy power iteration\n", + "A = np.array([[2.0,0.5],[0.5,1.0]])\n", + "v = np.random.randn(2)\n", + "for _ in range(20):\n", + " v = A @ v\n", + " v = v / np.linalg.norm(v)\n", + "print('Estimated eigenvector (numpy):', v)\n", + "v" + ] + } + ], + "metadata": { + "language_info": { + "name": "python" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/gtsam/linear/doc/Utilities.ipynb b/gtsam/linear/doc/Utilities.ipynb new file mode 100644 index 0000000000..94bde48c20 --- /dev/null +++ b/gtsam/linear/doc/Utilities.ipynb @@ -0,0 +1,192 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "63acce53", + "metadata": {}, + "source": [ + "# Utilities\n", + "\n", + "This notebook groups helper modules: NoiseModel, LossFunctions, Sampler, VectorValues, Scatter, Errors, linearExceptions, KalmanFilter. Each section contains a guarded construction and a small numpy demonstration." + ] + }, + { + "cell_type": "markdown", + "id": "df6f0d68", + "metadata": {}, + "source": [ + "\"Open" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "fafa98ef", + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " import google.colab\n", + " %pip install --quiet gtsam\n", + "except ImportError:\n", + " pass" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "cf838ccd", + "metadata": {}, + "outputs": [], + "source": [ + "import gtsam\n", + "import numpy as np" + ] + }, + { + "cell_type": "markdown", + "id": "6fb97861", + "metadata": {}, + "source": [ + "## NoiseModel and LossFunctions\n", + "\n", + "Try constructing common noise models and evaluate simple loss functions (Huber) as examples." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b019e3b1", + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " nm = gtsam.noiseModel.Isotropic.Sigma(1, 0.1)\n", + "except Exception as e:\n", + " nm = None\n", + " print('noiseModel bindings not available:', e)\n", + "\n", + "# Huber loss (numpy)\n", + "def huber(r, k=1.0):\n", + " return np.where(np.abs(r) <= k, 0.5*r**2, k*(np.abs(r)-0.5*k))\n", + "r = np.array([0.1, 2.0, -0.5])\n", + "print('Huber loss (numpy):', huber(r))" + ] + }, + { + "cell_type": "markdown", + "id": "2221f440", + "metadata": {}, + "source": [ + "## Sampler and VectorValues\n", + "\n", + "Show sampling and simple vector-values storage examples." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7bf28681", + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " samp = gtsam.Sampler()\n", + " vv = gtsam.VectorValues()\n", + "except Exception as e:\n", + " samp = None\n", + " vv = None\n", + " print('Sampler/VectorValues not available in Python bindings:', e)\n", + "\n", + "# Numpy sampling and dict-of-vectors\n", + "mu = np.zeros(2)\n", + "Sigma = np.eye(2)\n", + "samples = np.random.multivariate_normal(mu, Sigma, size=3)\n", + "values = {0: np.array([1.0,2.0]), 1: np.array([0.5,-0.5])}\n", + "print('Samples (numpy):')\n", + "print(samples)\n", + "print('Vector-like dict (numpy):', values)" + ] + }, + { + "cell_type": "markdown", + "id": "3c030a98", + "metadata": {}, + "source": [ + "## Scatter and Errors, linearExceptions\n", + "\n", + "Show COO-style arrays and a basic residual error computation; demonstrate catching an example exception." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ff7252c3", + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " scat = gtsam.Scatter()\n", + "except Exception as e:\n", + " scat = None\n", + " print('Scatter bindings not available:', e)\n", + "\n", + "rows = [0,1,2]\n", + "cols = [0,2,1]\n", + "vals = [1.0,2.0,3.0]\n", + "print('COO-like arrays (numpy):', rows, cols, vals)\n", + "# Residual error demo\n", + "A = np.array([[2.0,-1.0],[-1.0,2.0]])\n", + "x_true = np.array([1.0,0.0])\n", + "b = A @ x_true\n", + "x_est = np.array([0.9,0.1])\n", + "res = b - A @ x_est\n", + "print('Residual:', res, 'L2 norm:', np.linalg.norm(res))\n", + "# Example catch\n", + "try:\n", + " raise RuntimeError('example linear exception')\n", + "except Exception as e:\n", + " print('Caught exception:', e)" + ] + }, + { + "cell_type": "markdown", + "id": "88a465e0", + "metadata": {}, + "source": [ + "## KalmanFilter\n", + "\n", + "A short numpy-based Kalman filter step is shown as a reference for the linear Kalman utilities." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3f4aeffb", + "metadata": {}, + "outputs": [], + "source": [ + "# 1D Kalman update example\n", + "x = 0.0\n", + "P = 1.0\n", + "Q = 0.1\n", + "# Predict\n", + "x = x\n", + "P = P + Q\n", + "z = 0.5\n", + "R = 0.2\n", + "K = P / (P + R)\n", + "x = x + K * (z - x)\n", + "P = (1 - K) * P\n", + "print('Post-update state:', x, 'P:', P)" + ] + } + ], + "metadata": { + "language_info": { + "name": "python" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +}