Merge remote-tracking branch 'upstream/develop' into generate_docs
commit
88ee439a63
|
@ -3,9 +3,9 @@ name: Linux CI
|
|||
on:
|
||||
pull_request:
|
||||
paths-ignore:
|
||||
- '**.md'
|
||||
- '**.ipynb'
|
||||
- 'myst.yml'
|
||||
- "**.md"
|
||||
- "**.ipynb"
|
||||
- "myst.yml"
|
||||
|
||||
# Every time you make a push to your PR, it cancel immediately the previous checks,
|
||||
# and start a new one. The other runner will be available more quickly to your PR.
|
||||
|
@ -30,9 +30,9 @@ jobs:
|
|||
# Github Actions requires a single row to be added to the build matrix.
|
||||
# See https://help.github.com/en/articles/workflow-syntax-for-github-actions.
|
||||
name: [
|
||||
# "Bracket" the versions from GCC [9-14] and Clang [9-16]
|
||||
ubuntu-20.04-gcc-9,
|
||||
ubuntu-20.04-clang-9,
|
||||
# "Bracket" the versions from GCC [9-14] and Clang [11-16]
|
||||
ubuntu-22.04-gcc-9,
|
||||
ubuntu-22.04-clang-11,
|
||||
ubuntu-24.04-gcc-14,
|
||||
ubuntu-24.04-clang-16,
|
||||
]
|
||||
|
@ -40,15 +40,15 @@ jobs:
|
|||
build_type: [Debug, Release]
|
||||
build_unstable: [ON]
|
||||
include:
|
||||
- name: ubuntu-20.04-gcc-9
|
||||
os: ubuntu-20.04
|
||||
- name: ubuntu-22.04-gcc-9
|
||||
os: ubuntu-22.04
|
||||
compiler: gcc
|
||||
version: "9"
|
||||
|
||||
- name: ubuntu-20.04-clang-9
|
||||
os: ubuntu-20.04
|
||||
- name: ubuntu-22.04-clang-11
|
||||
os: ubuntu-22.04
|
||||
compiler: clang
|
||||
version: "9"
|
||||
version: "11"
|
||||
|
||||
- name: ubuntu-24.04-gcc-14
|
||||
os: ubuntu-24.04
|
||||
|
|
|
@ -22,18 +22,18 @@ jobs:
|
|||
id: filter
|
||||
uses: dorny/paths-filter@v3
|
||||
with:
|
||||
predicate-quantifier: 'every' # If any changed file matches every filter, proceed with build
|
||||
predicate-quantifier: "every" # If any changed file matches every filter, proceed with build
|
||||
filters: |
|
||||
relevant_changes:
|
||||
- '!**.md'
|
||||
- '!**.ipynb'
|
||||
- '!myst.yml'
|
||||
|
||||
|
||||
build:
|
||||
# Only run build if relevant files have been modified in this PR.
|
||||
needs: check-paths
|
||||
if: needs.check-paths.outputs.should_run == 'true'
|
||||
|
||||
|
||||
name: ${{ matrix.name }} ${{ matrix.build_type }} Python ${{ matrix.python_version }}
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
||||
|
@ -52,8 +52,8 @@ jobs:
|
|||
# See https://help.github.com/en/articles/workflow-syntax-for-github-actions.
|
||||
name:
|
||||
[
|
||||
ubuntu-20.04-gcc-9,
|
||||
ubuntu-20.04-clang-9,
|
||||
ubuntu-22.04-gcc-9,
|
||||
ubuntu-22.04-clang-11,
|
||||
macos-13-xcode-14.2,
|
||||
macos-14-xcode-15.4,
|
||||
windows-2022-msbuild,
|
||||
|
@ -62,15 +62,15 @@ jobs:
|
|||
build_type: [Release]
|
||||
python_version: [3]
|
||||
include:
|
||||
- name: ubuntu-20.04-gcc-9
|
||||
os: ubuntu-20.04
|
||||
- name: ubuntu-22.04-gcc-9
|
||||
os: ubuntu-22.04
|
||||
compiler: gcc
|
||||
version: "9"
|
||||
|
||||
- name: ubuntu-20.04-clang-9
|
||||
os: ubuntu-20.04
|
||||
- name: ubuntu-22.04-clang-11
|
||||
os: ubuntu-22.04
|
||||
compiler: clang
|
||||
version: "9"
|
||||
version: "11"
|
||||
|
||||
- name: macos-13-xcode-14.2
|
||||
os: macos-13
|
||||
|
|
10
README.md
10
README.md
|
@ -15,11 +15,11 @@ matrices.
|
|||
|
||||
The current support matrix is:
|
||||
|
||||
| Platform | Compiler | Build Status |
|
||||
|:------------------:|:---------:|:--------------------------------------------------------------------------------:|
|
||||
| Ubuntu 20.04/22.04 | gcc/clang |  |
|
||||
| macOS | clang |  |
|
||||
| Windows | MSVC |  |
|
||||
| Platform | Compiler | Build Status |
|
||||
| :----------------: | :-------: | :------------------------------------------------------------------------------: |
|
||||
| Ubuntu 22.04/24.04 | gcc/clang |  |
|
||||
| macOS | clang |  |
|
||||
| Windows | MSVC |  |
|
||||
|
||||
|
||||
On top of the C++ library, GTSAM includes [wrappers for MATLAB & Python](#wrappers).
|
||||
|
|
|
@ -23,6 +23,24 @@ namespace gtsam {
|
|||
|
||||
using namespace std;
|
||||
|
||||
const FactorIndices& VariableIndex::operator[](Key variable) const {
|
||||
return index_.find(variable)->second;
|
||||
}
|
||||
|
||||
const FactorIndices& VariableIndex::at(Key variable) const {
|
||||
KeyMap::const_iterator item = index_.find(variable);
|
||||
if(item == index_.end())
|
||||
throw std::invalid_argument("Requested non-existent variable '" +
|
||||
DefaultKeyFormatter(variable) +
|
||||
"' from VariableIndex");
|
||||
else
|
||||
return item->second;
|
||||
}
|
||||
|
||||
bool VariableIndex::empty(Key variable) const {
|
||||
return (*this)[variable].empty();
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
bool VariableIndex::equals(const VariableIndex& other, double tol) const {
|
||||
return this->nEntries_ == other.nEntries_ && this->nFactors_ == other.nFactors_
|
||||
|
|
|
@ -83,21 +83,13 @@ class GTSAM_EXPORT VariableIndex {
|
|||
/// The number of nonzero blocks, i.e. the number of variable-factor entries
|
||||
size_t nEntries() const { return nEntries_; }
|
||||
|
||||
/// Access a list of factors by variable without checking for existence
|
||||
const FactorIndices& operator[](Key variable) const;
|
||||
/// Access a list of factors by variable
|
||||
const FactorIndices& operator[](Key variable) const {
|
||||
KeyMap::const_iterator item = index_.find(variable);
|
||||
if(item == index_.end())
|
||||
throw std::invalid_argument("Requested non-existent variable '" +
|
||||
DefaultKeyFormatter(variable) +
|
||||
"' from VariableIndex");
|
||||
else
|
||||
return item->second;
|
||||
}
|
||||
const FactorIndices& at(Key variable) const;
|
||||
|
||||
/// Return true if no factors associated with a variable
|
||||
bool empty(Key variable) const {
|
||||
return (*this)[variable].empty();
|
||||
}
|
||||
bool empty(Key variable) const;
|
||||
|
||||
/// @}
|
||||
/// @name Testable
|
||||
|
|
|
@ -0,0 +1,753 @@
|
|||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "bayesnet_intro_md"
|
||||
},
|
||||
"source": [
|
||||
"# BayesNet"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "bayesnet_desc_md"
|
||||
},
|
||||
"source": [
|
||||
"A `BayesNet` in GTSAM represents a directed graphical model, created by running sequential variable elimination (like Cholesky or QR factorization) on a `FactorGraph` or constructing from scratch.\n",
|
||||
"\n",
|
||||
"It is essentially a collection of `Conditional` objects, ordered according to the elimination order. Each conditional represents $P(\\text{variable} | \\text{parents})$, where the parents are variables that appear later in the elimination ordering.\n",
|
||||
"\n",
|
||||
"A Bayes net represents the joint probability distribution as a product of conditional probabilities stored in the net:\n",
|
||||
"\n",
|
||||
"$$\n",
|
||||
"P(X_1, X_2, \\dots, X_N) = \\prod_{i=1}^N P(X_i | \\text{Parents}(X_i))\n",
|
||||
"$$\n",
|
||||
"The total log-probability of an assignment is the sum of the log-probabilities of its conditionals:\n",
|
||||
"$$\n",
|
||||
"\\log P(X_1, \\dots, X_N) = \\sum_{i=1}^N \\log P(X_i | \\text{Parents}(X_i))\n",
|
||||
"$$\n",
|
||||
"\n",
|
||||
"Like `FactorGraph`, `BayesNet` is templated on the type of conditional it stores (e.g., `GaussianBayesNet`, `DiscreteBayesNet`)."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "bayesnet_colab_md"
|
||||
},
|
||||
"source": [
|
||||
"<a href=\"https://colab.research.google.com/github/borglab/gtsam/blob/develop/gtsam/inference/doc/BayesNet.ipynb\" target=\"_parent\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"/></a>"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "bayesnet_pip_code",
|
||||
"tags": [
|
||||
"remove-cell"
|
||||
]
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"%pip install gtsam"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 44,
|
||||
"metadata": {
|
||||
"id": "bayesnet_import_code"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import gtsam\n",
|
||||
"import numpy as np\n",
|
||||
"import graphviz\n",
|
||||
"\n",
|
||||
"# We need concrete graph types and elimination to get a BayesNet\n",
|
||||
"from gtsam import GaussianFactorGraph, Ordering, GaussianBayesNet\n",
|
||||
"# For the Asia example\n",
|
||||
"from gtsam import DiscreteBayesNet, DiscreteConditional, DiscreteKeys, DiscreteValues, symbol\n",
|
||||
"from gtsam import symbol_shorthand\n",
|
||||
"\n",
|
||||
"X = symbol_shorthand.X\n",
|
||||
"L = symbol_shorthand.L"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "bayesnet_create_md"
|
||||
},
|
||||
"source": [
|
||||
"## Creating a BayesNet (via Elimination)\n",
|
||||
"\n",
|
||||
"BayesNets are typically obtained by eliminating a `FactorGraph`."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 45,
|
||||
"metadata": {
|
||||
"colab": {
|
||||
"base_uri": "https://localhost:8080/"
|
||||
},
|
||||
"id": "bayesnet_eliminate_code",
|
||||
"outputId": "01234567-89ab-cdef-0123-456789abcdef"
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Original Factor Graph:\n",
|
||||
"\n",
|
||||
"size: 3\n",
|
||||
"factor 0: \n",
|
||||
" A[x0] = [\n",
|
||||
"\t-1\n",
|
||||
"]\n",
|
||||
" b = [ 0 ]\n",
|
||||
" Noise model: unit (1) \n",
|
||||
"factor 1: \n",
|
||||
" A[x0] = [\n",
|
||||
"\t-1\n",
|
||||
"]\n",
|
||||
" A[x1] = [\n",
|
||||
"\t1\n",
|
||||
"]\n",
|
||||
" b = [ 0 ]\n",
|
||||
" Noise model: unit (1) \n",
|
||||
"factor 2: \n",
|
||||
" A[x1] = [\n",
|
||||
"\t-1\n",
|
||||
"]\n",
|
||||
" A[x2] = [\n",
|
||||
"\t1\n",
|
||||
"]\n",
|
||||
" b = [ 0 ]\n",
|
||||
" Noise model: unit (1) \n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# Create a simple Gaussian Factor Graph P(x0) P(x1|x0) P(x2|x1)\n",
|
||||
"graph = GaussianFactorGraph()\n",
|
||||
"model = gtsam.noiseModel.Isotropic.Sigma(1, 1.0)\n",
|
||||
"graph.add(X(0), -np.eye(1), np.zeros(1), model)\n",
|
||||
"graph.add(X(0), -np.eye(1), X(1), np.eye(1), np.zeros(1), model)\n",
|
||||
"graph.add(X(1), -np.eye(1), X(2), np.eye(1), np.zeros(1), model)\n",
|
||||
"print(\"Original Factor Graph:\")\n",
|
||||
"graph.print()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 46,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"\n",
|
||||
"Resulting BayesNet:\n",
|
||||
"\n",
|
||||
"size: 3\n",
|
||||
"conditional 0: p(x0 | x1)\n",
|
||||
" R = [ 1.41421 ]\n",
|
||||
" S[x1] = [ -0.707107 ]\n",
|
||||
" d = [ 0 ]\n",
|
||||
" logNormalizationConstant: -0.572365\n",
|
||||
" No noise model\n",
|
||||
"conditional 1: p(x1 | x2)\n",
|
||||
" R = [ 1.22474 ]\n",
|
||||
" S[x2] = [ -0.816497 ]\n",
|
||||
" d = [ 0 ]\n",
|
||||
" logNormalizationConstant: -0.716206\n",
|
||||
" No noise model\n",
|
||||
"conditional 2: p(x2)\n",
|
||||
" R = [ 0.57735 ]\n",
|
||||
" d = [ 0 ]\n",
|
||||
" mean: 1 elements\n",
|
||||
" x2: 0\n",
|
||||
" logNormalizationConstant: -1.46824\n",
|
||||
" No noise model\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# Eliminate sequentially using a specific ordering\n",
|
||||
"ordering = Ordering([X(0), X(1), X(2)])\n",
|
||||
"bayes_net = graph.eliminateSequential(ordering)\n",
|
||||
"\n",
|
||||
"print(\"\\nResulting BayesNet:\")\n",
|
||||
"bayes_net.print()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "bayesnet_props_md"
|
||||
},
|
||||
"source": [
|
||||
"## Properties and Access\n",
|
||||
"\n",
|
||||
"A `BayesNet` provides access to its constituent conditionals and basic properties."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 47,
|
||||
"metadata": {
|
||||
"colab": {
|
||||
"base_uri": "https://localhost:8080/"
|
||||
},
|
||||
"id": "bayesnet_access_code",
|
||||
"outputId": "12345678-9abc-def0-1234-56789abcdef0"
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"BayesNet size: 3\n",
|
||||
"Conditional at index 1: \n",
|
||||
"GaussianConditional p(x1 | x2)\n",
|
||||
" R = [ 1.22474 ]\n",
|
||||
" S[x2] = [ -0.816497 ]\n",
|
||||
" d = [ 0 ]\n",
|
||||
" logNormalizationConstant: -0.716206\n",
|
||||
" No noise model\n",
|
||||
"Keys in BayesNet: x0x1x2\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"print(f\"BayesNet size: {bayes_net.size()}\")\n",
|
||||
"\n",
|
||||
"# Access conditional by index\n",
|
||||
"conditional1 = bayes_net.at(1)\n",
|
||||
"print(\"Conditional at index 1: \")\n",
|
||||
"conditional1.print()\n",
|
||||
"\n",
|
||||
"# Get all keys involved\n",
|
||||
"bn_keys = bayes_net.keys()\n",
|
||||
"print(f\"Keys in BayesNet: {bn_keys}\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "bayesnet_eval_md"
|
||||
},
|
||||
"source": [
|
||||
"## Evaluation and Solution\n",
|
||||
"\n",
|
||||
"The `logProbability(Values)` method computes the log probability of a variable assignment given the conditional distributions in the Bayes net. For Gaussian Bayes nets, the `optimize()` method can be used to find the maximum likelihood estimate (MLE) solution via back-substitution."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 48,
|
||||
"metadata": {
|
||||
"colab": {
|
||||
"base_uri": "https://localhost:8080/"
|
||||
},
|
||||
"id": "bayesnet_eval_code",
|
||||
"outputId": "23456789-abcd-ef01-2345-6789abcdef01"
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Log Probability at 0,0,0]: -2.7568155996140185\n",
|
||||
"Optimized Solution (MLE):\n",
|
||||
"VectorValues: 3 elements\n",
|
||||
" x0: 0\n",
|
||||
" x1: 0\n",
|
||||
" x2: 0\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# For GaussianBayesNet, we use VectorValues\n",
|
||||
"mle_solution = bayes_net.optimize()\n",
|
||||
"\n",
|
||||
"# Calculate log probability (requires providing values for all variables)\n",
|
||||
"log_prob = bayes_net.logProbability(mle_solution)\n",
|
||||
"print(f\"Log Probability at {mle_solution.at(X(0))[0]:.0f},{mle_solution.at(X(1))[0]:.0f},{mle_solution.at(X(2))[0]:.0f}]: {log_prob}\")\n",
|
||||
"\n",
|
||||
"print(\"Optimized Solution (MLE):\")\n",
|
||||
"mle_solution.print()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "bayesnet_viz_md"
|
||||
},
|
||||
"source": [
|
||||
"## Visualization\n",
|
||||
"\n",
|
||||
"Bayes nets can also be visualized using Graphviz."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 49,
|
||||
"metadata": {
|
||||
"colab": {
|
||||
"base_uri": "https://localhost:8080/"
|
||||
},
|
||||
"id": "bayesnet_dot_code",
|
||||
"outputId": "3456789a-bcde-f012-3456-789abcdef012"
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"image/svg+xml": [
|
||||
"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n",
|
||||
"<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"\n",
|
||||
" \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n",
|
||||
"<!-- Generated by graphviz version 2.50.0 (0)\n",
|
||||
" -->\n",
|
||||
"<!-- Pages: 1 -->\n",
|
||||
"<svg width=\"62pt\" height=\"188pt\"\n",
|
||||
" viewBox=\"0.00 0.00 62.00 188.00\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n",
|
||||
"<g id=\"graph0\" class=\"graph\" transform=\"scale(1 1) rotate(0) translate(4 184)\">\n",
|
||||
"<polygon fill=\"white\" stroke=\"transparent\" points=\"-4,4 -4,-184 58,-184 58,4 -4,4\"/>\n",
|
||||
"<!-- var8646911284551352320 -->\n",
|
||||
"<g id=\"node1\" class=\"node\">\n",
|
||||
"<title>var8646911284551352320</title>\n",
|
||||
"<ellipse fill=\"none\" stroke=\"black\" cx=\"27\" cy=\"-18\" rx=\"27\" ry=\"18\"/>\n",
|
||||
"<text text-anchor=\"middle\" x=\"27\" y=\"-14.3\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">x0</text>\n",
|
||||
"</g>\n",
|
||||
"<!-- var8646911284551352321 -->\n",
|
||||
"<g id=\"node2\" class=\"node\">\n",
|
||||
"<title>var8646911284551352321</title>\n",
|
||||
"<ellipse fill=\"none\" stroke=\"black\" cx=\"27\" cy=\"-90\" rx=\"27\" ry=\"18\"/>\n",
|
||||
"<text text-anchor=\"middle\" x=\"27\" y=\"-86.3\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">x1</text>\n",
|
||||
"</g>\n",
|
||||
"<!-- var8646911284551352321->var8646911284551352320 -->\n",
|
||||
"<g id=\"edge2\" class=\"edge\">\n",
|
||||
"<title>var8646911284551352321->var8646911284551352320</title>\n",
|
||||
"<path fill=\"none\" stroke=\"black\" d=\"M27,-71.7C27,-63.98 27,-54.71 27,-46.11\"/>\n",
|
||||
"<polygon fill=\"black\" stroke=\"black\" points=\"30.5,-46.1 27,-36.1 23.5,-46.1 30.5,-46.1\"/>\n",
|
||||
"</g>\n",
|
||||
"<!-- var8646911284551352322 -->\n",
|
||||
"<g id=\"node3\" class=\"node\">\n",
|
||||
"<title>var8646911284551352322</title>\n",
|
||||
"<ellipse fill=\"none\" stroke=\"black\" cx=\"27\" cy=\"-162\" rx=\"27\" ry=\"18\"/>\n",
|
||||
"<text text-anchor=\"middle\" x=\"27\" y=\"-158.3\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">x2</text>\n",
|
||||
"</g>\n",
|
||||
"<!-- var8646911284551352322->var8646911284551352321 -->\n",
|
||||
"<g id=\"edge1\" class=\"edge\">\n",
|
||||
"<title>var8646911284551352322->var8646911284551352321</title>\n",
|
||||
"<path fill=\"none\" stroke=\"black\" d=\"M27,-143.7C27,-135.98 27,-126.71 27,-118.11\"/>\n",
|
||||
"<polygon fill=\"black\" stroke=\"black\" points=\"30.5,-118.1 27,-108.1 23.5,-118.1 30.5,-118.1\"/>\n",
|
||||
"</g>\n",
|
||||
"</g>\n",
|
||||
"</svg>\n"
|
||||
],
|
||||
"text/plain": [
|
||||
"<graphviz.sources.Source at 0x18b7757b020>"
|
||||
]
|
||||
},
|
||||
"execution_count": 49,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"graphviz.Source(bayes_net.dot())"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "bayesnet_discrete_md"
|
||||
},
|
||||
"source": [
|
||||
"## Example: DiscreteBayesNet (Asia Network)\n",
|
||||
"\n",
|
||||
"While the previous examples focused on `GaussianBayesNet`, GTSAM also supports `DiscreteBayesNet` for representing probability distributions over discrete variables. Here we construct the classic 'Asia' network example directly by adding `DiscreteConditional` objects."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 50,
|
||||
"metadata": {
|
||||
"id": "bayesnet_discrete_imports_code"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Define keys for the Asia network variables\n",
|
||||
"A = symbol('A', 8) # Visit to Asia?\n",
|
||||
"S = symbol('S', 7) # Smoker?\n",
|
||||
"T = symbol('T', 6) # Tuberculosis?\n",
|
||||
"L = symbol('L', 5) # Lung Cancer?\n",
|
||||
"B = symbol('B', 4) # Bronchitis?\n",
|
||||
"E = symbol('E', 3) # Tuberculosis or Lung Cancer?\n",
|
||||
"X = symbol('X', 2) # Positive X-Ray?\n",
|
||||
"D = symbol('D', 1) # Dyspnea (Shortness of breath)?\n",
|
||||
"\n",
|
||||
"# Define cardinalities (all are binary in this case)\n",
|
||||
"cardinalities = { A: 2, S: 2, T: 2, L: 2, B: 2, E: 2, X: 2, D: 2 }\n",
|
||||
"\n",
|
||||
"# Helper to create DiscreteKeys object\n",
|
||||
"def make_keys(keys_list):\n",
|
||||
" dk = DiscreteKeys()\n",
|
||||
" for k in keys_list:\n",
|
||||
" dk.push_back((k, cardinalities[k]))\n",
|
||||
" return dk"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 51,
|
||||
"metadata": {
|
||||
"colab": {
|
||||
"base_uri": "https://localhost:8080/"
|
||||
},
|
||||
"id": "bayesnet_discrete_build_code",
|
||||
"outputId": "456789ab-cdef-0123-4567-89abcdef0123"
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Asia Bayes Net:\n",
|
||||
"DiscreteBayesNet\n",
|
||||
" \n",
|
||||
"size: 8\n",
|
||||
"conditional 0: P( D1 | E3 B4 ):\n",
|
||||
" Choice(E3) \n",
|
||||
" 0 Choice(D1) \n",
|
||||
" 0 0 Choice(B4) \n",
|
||||
" 0 0 0 Leaf 0.9\n",
|
||||
" 0 0 1 Leaf 0.2\n",
|
||||
" 0 1 Choice(B4) \n",
|
||||
" 0 1 0 Leaf 0.1\n",
|
||||
" 0 1 1 Leaf 0.8\n",
|
||||
" 1 Choice(D1) \n",
|
||||
" 1 0 Choice(B4) \n",
|
||||
" 1 0 0 Leaf 0.3\n",
|
||||
" 1 0 1 Leaf 0.1\n",
|
||||
" 1 1 Choice(B4) \n",
|
||||
" 1 1 0 Leaf 0.7\n",
|
||||
" 1 1 1 Leaf 0.9\n",
|
||||
"\n",
|
||||
"conditional 1: P( X2 | E3 ):\n",
|
||||
" Choice(X2) \n",
|
||||
" 0 Choice(E3) \n",
|
||||
" 0 0 Leaf 0.95\n",
|
||||
" 0 1 Leaf 0.02\n",
|
||||
" 1 Choice(E3) \n",
|
||||
" 1 0 Leaf 0.05\n",
|
||||
" 1 1 Leaf 0.98\n",
|
||||
"\n",
|
||||
"conditional 2: P( E3 | T6 L5 ):\n",
|
||||
" Choice(T6) \n",
|
||||
" 0 Choice(L5) \n",
|
||||
" 0 0 Choice(E3) \n",
|
||||
" 0 0 0 Leaf 1\n",
|
||||
" 0 0 1 Leaf 0\n",
|
||||
" 0 1 Choice(E3) \n",
|
||||
" 0 1 0 Leaf 0\n",
|
||||
" 0 1 1 Leaf 1\n",
|
||||
" 1 Choice(L5) \n",
|
||||
" 1 0 Choice(E3) \n",
|
||||
" 1 0 0 Leaf 0\n",
|
||||
" 1 0 1 Leaf 1\n",
|
||||
" 1 1 Choice(E3) \n",
|
||||
" 1 1 0 Leaf 0\n",
|
||||
" 1 1 1 Leaf 1\n",
|
||||
"\n",
|
||||
"conditional 3: P( B4 | S7 ):\n",
|
||||
" Choice(S7) \n",
|
||||
" 0 Choice(B4) \n",
|
||||
" 0 0 Leaf 0.7\n",
|
||||
" 0 1 Leaf 0.3\n",
|
||||
" 1 Choice(B4) \n",
|
||||
" 1 0 Leaf 0.4\n",
|
||||
" 1 1 Leaf 0.6\n",
|
||||
"\n",
|
||||
"conditional 4: P( L5 | S7 ):\n",
|
||||
" Choice(S7) \n",
|
||||
" 0 Choice(L5) \n",
|
||||
" 0 0 Leaf 0.99\n",
|
||||
" 0 1 Leaf 0.01\n",
|
||||
" 1 Choice(L5) \n",
|
||||
" 1 0 Leaf 0.9\n",
|
||||
" 1 1 Leaf 0.1\n",
|
||||
"\n",
|
||||
"conditional 5: P( T6 | A8 ):\n",
|
||||
" Choice(T6) \n",
|
||||
" 0 Choice(A8) \n",
|
||||
" 0 0 Leaf 0.99\n",
|
||||
" 0 1 Leaf 0.95\n",
|
||||
" 1 Choice(A8) \n",
|
||||
" 1 0 Leaf 0.01\n",
|
||||
" 1 1 Leaf 0.05\n",
|
||||
"\n",
|
||||
"conditional 6: P( S7 ):\n",
|
||||
" Leaf 0.5\n",
|
||||
"\n",
|
||||
"conditional 7: P( A8 ):\n",
|
||||
" Choice(A8) \n",
|
||||
" 0 Leaf 0.99\n",
|
||||
" 1 Leaf 0.01\n",
|
||||
"\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# Create the DiscreteBayesNet\n",
|
||||
"asia_net = DiscreteBayesNet()\n",
|
||||
"\n",
|
||||
"# Helper function to create parent list in correct format\n",
|
||||
"def make_parent_tuples(parent_keys):\n",
|
||||
" return [(pk, cardinalities[pk]) for pk in parent_keys]\n",
|
||||
"\n",
|
||||
"# P(D | E, B) - Dyspnea given Either and Bronchitis\n",
|
||||
"asia_net.add(DiscreteConditional((D, cardinalities[D]), make_parent_tuples([E, B]), \"9/1 2/8 3/7 1/9\"))\n",
|
||||
"\n",
|
||||
"# P(X | E) - X-Ray result given Either\n",
|
||||
"asia_net.add(DiscreteConditional((X, cardinalities[X]), make_parent_tuples([E]), \"95/5 2/98\"))\n",
|
||||
"\n",
|
||||
"# P(E | T, L) - Either Tub. or Lung Cancer (OR gate)\n",
|
||||
"# \"F T T T\" means P(E=1|T=0,L=0)=0, P(E=1|T=0,L=1)=1, P(E=1|T=1,L=0)=1, P(E=1|T=1,L=1)=1\n",
|
||||
"asia_net.add(DiscreteConditional((E, cardinalities[E]), make_parent_tuples([T, L]), \"F T T T\"))\n",
|
||||
"\n",
|
||||
"# P(B | S) - Bronchitis given Smoker\n",
|
||||
"asia_net.add(DiscreteConditional((B, cardinalities[B]), make_parent_tuples([S]), \"70/30 40/60\"))\n",
|
||||
"\n",
|
||||
"# P(L | S) - Lung Cancer given Smoker\n",
|
||||
"asia_net.add(DiscreteConditional((L, cardinalities[L]), make_parent_tuples([S]), \"99/1 90/10\"))\n",
|
||||
"\n",
|
||||
"# P(T | A) - Tuberculosis given Asia\n",
|
||||
"asia_net.add(DiscreteConditional((T, cardinalities[T]), make_parent_tuples([A]), \"99/1 95/5\"))\n",
|
||||
"\n",
|
||||
"# P(S) - Prior on Smoking\n",
|
||||
"asia_net.add(DiscreteConditional((S, cardinalities[S]), [], \"1/1\")) # or \"50/50\"\n",
|
||||
"\n",
|
||||
"# Add conditional probability tables (CPTs) using C++ sugar syntax\n",
|
||||
"# P(A) - Prior on Asia\n",
|
||||
"asia_net.add(DiscreteConditional((A, cardinalities[A]), [], \"99/1\"))\n",
|
||||
"\n",
|
||||
"print(\"Asia Bayes Net:\")\n",
|
||||
"asia_net.print()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 58,
|
||||
"metadata": {
|
||||
"colab": {
|
||||
"base_uri": "https://localhost:8080/"
|
||||
},
|
||||
"id": "bayesnet_discrete_viz_eval_code",
|
||||
"outputId": "56789abc-def0-1234-5678-9abcdef01234"
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"image/svg+xml": [
|
||||
"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n",
|
||||
"<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"\n",
|
||||
" \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n",
|
||||
"<!-- Generated by graphviz version 2.50.0 (0)\n",
|
||||
" -->\n",
|
||||
"<!-- Pages: 1 -->\n",
|
||||
"<svg width=\"189pt\" height=\"260pt\"\n",
|
||||
" viewBox=\"0.00 0.00 189.00 260.00\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n",
|
||||
"<g id=\"graph0\" class=\"graph\" transform=\"scale(1 1) rotate(0) translate(4 256)\">\n",
|
||||
"<polygon fill=\"white\" stroke=\"transparent\" points=\"-4,4 -4,-256 185,-256 185,4 -4,4\"/>\n",
|
||||
"<!-- var4683743612465315848 -->\n",
|
||||
"<g id=\"node1\" class=\"node\">\n",
|
||||
"<title>var4683743612465315848</title>\n",
|
||||
"<ellipse fill=\"none\" stroke=\"black\" cx=\"27\" cy=\"-234\" rx=\"27\" ry=\"18\"/>\n",
|
||||
"<text text-anchor=\"middle\" x=\"27\" y=\"-230.3\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">A8</text>\n",
|
||||
"</g>\n",
|
||||
"<!-- var6052837899185946630 -->\n",
|
||||
"<g id=\"node7\" class=\"node\">\n",
|
||||
"<title>var6052837899185946630</title>\n",
|
||||
"<ellipse fill=\"none\" stroke=\"black\" cx=\"27\" cy=\"-162\" rx=\"27\" ry=\"18\"/>\n",
|
||||
"<text text-anchor=\"middle\" x=\"27\" y=\"-158.3\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">T6</text>\n",
|
||||
"</g>\n",
|
||||
"<!-- var4683743612465315848->var6052837899185946630 -->\n",
|
||||
"<g id=\"edge1\" class=\"edge\">\n",
|
||||
"<title>var4683743612465315848->var6052837899185946630</title>\n",
|
||||
"<path fill=\"none\" stroke=\"black\" d=\"M27,-215.7C27,-207.98 27,-198.71 27,-190.11\"/>\n",
|
||||
"<polygon fill=\"black\" stroke=\"black\" points=\"30.5,-190.1 27,-180.1 23.5,-190.1 30.5,-190.1\"/>\n",
|
||||
"</g>\n",
|
||||
"<!-- var4755801206503243780 -->\n",
|
||||
"<g id=\"node2\" class=\"node\">\n",
|
||||
"<title>var4755801206503243780</title>\n",
|
||||
"<ellipse fill=\"none\" stroke=\"black\" cx=\"154\" cy=\"-90\" rx=\"27\" ry=\"18\"/>\n",
|
||||
"<text text-anchor=\"middle\" x=\"154\" y=\"-86.3\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">B4</text>\n",
|
||||
"</g>\n",
|
||||
"<!-- var4899916394579099649 -->\n",
|
||||
"<g id=\"node3\" class=\"node\">\n",
|
||||
"<title>var4899916394579099649</title>\n",
|
||||
"<ellipse fill=\"none\" stroke=\"black\" cx=\"154\" cy=\"-18\" rx=\"27\" ry=\"18\"/>\n",
|
||||
"<text text-anchor=\"middle\" x=\"154\" y=\"-14.3\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">D1</text>\n",
|
||||
"</g>\n",
|
||||
"<!-- var4755801206503243780->var4899916394579099649 -->\n",
|
||||
"<g id=\"edge8\" class=\"edge\">\n",
|
||||
"<title>var4755801206503243780->var4899916394579099649</title>\n",
|
||||
"<path fill=\"none\" stroke=\"black\" d=\"M154,-71.7C154,-63.98 154,-54.71 154,-46.11\"/>\n",
|
||||
"<polygon fill=\"black\" stroke=\"black\" points=\"157.5,-46.1 154,-36.1 150.5,-46.1 157.5,-46.1\"/>\n",
|
||||
"</g>\n",
|
||||
"<!-- var4971973988617027587 -->\n",
|
||||
"<g id=\"node4\" class=\"node\">\n",
|
||||
"<title>var4971973988617027587</title>\n",
|
||||
"<ellipse fill=\"none\" stroke=\"black\" cx=\"82\" cy=\"-90\" rx=\"27\" ry=\"18\"/>\n",
|
||||
"<text text-anchor=\"middle\" x=\"82\" y=\"-86.3\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">E3</text>\n",
|
||||
"</g>\n",
|
||||
"<!-- var4971973988617027587->var4899916394579099649 -->\n",
|
||||
"<g id=\"edge7\" class=\"edge\">\n",
|
||||
"<title>var4971973988617027587->var4899916394579099649</title>\n",
|
||||
"<path fill=\"none\" stroke=\"black\" d=\"M96.57,-74.83C106.75,-64.94 120.52,-51.55 132.03,-40.36\"/>\n",
|
||||
"<polygon fill=\"black\" stroke=\"black\" points=\"134.47,-42.87 139.2,-33.38 129.59,-37.85 134.47,-42.87\"/>\n",
|
||||
"</g>\n",
|
||||
"<!-- var6341068275337658370 -->\n",
|
||||
"<g id=\"node8\" class=\"node\">\n",
|
||||
"<title>var6341068275337658370</title>\n",
|
||||
"<ellipse fill=\"none\" stroke=\"black\" cx=\"82\" cy=\"-18\" rx=\"27\" ry=\"18\"/>\n",
|
||||
"<text text-anchor=\"middle\" x=\"82\" y=\"-14.3\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">X2</text>\n",
|
||||
"</g>\n",
|
||||
"<!-- var4971973988617027587->var6341068275337658370 -->\n",
|
||||
"<g id=\"edge6\" class=\"edge\">\n",
|
||||
"<title>var4971973988617027587->var6341068275337658370</title>\n",
|
||||
"<path fill=\"none\" stroke=\"black\" d=\"M82,-71.7C82,-63.98 82,-54.71 82,-46.11\"/>\n",
|
||||
"<polygon fill=\"black\" stroke=\"black\" points=\"85.5,-46.1 82,-36.1 78.5,-46.1 85.5,-46.1\"/>\n",
|
||||
"</g>\n",
|
||||
"<!-- var5476377146882523141 -->\n",
|
||||
"<g id=\"node5\" class=\"node\">\n",
|
||||
"<title>var5476377146882523141</title>\n",
|
||||
"<ellipse fill=\"none\" stroke=\"black\" cx=\"99\" cy=\"-162\" rx=\"27\" ry=\"18\"/>\n",
|
||||
"<text text-anchor=\"middle\" x=\"99\" y=\"-158.3\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">L5</text>\n",
|
||||
"</g>\n",
|
||||
"<!-- var5476377146882523141->var4971973988617027587 -->\n",
|
||||
"<g id=\"edge5\" class=\"edge\">\n",
|
||||
"<title>var5476377146882523141->var4971973988617027587</title>\n",
|
||||
"<path fill=\"none\" stroke=\"black\" d=\"M94.88,-144.05C92.99,-136.26 90.7,-126.82 88.58,-118.08\"/>\n",
|
||||
"<polygon fill=\"black\" stroke=\"black\" points=\"91.96,-117.17 86.2,-108.28 85.15,-118.82 91.96,-117.17\"/>\n",
|
||||
"</g>\n",
|
||||
"<!-- var5980780305148018695 -->\n",
|
||||
"<g id=\"node6\" class=\"node\">\n",
|
||||
"<title>var5980780305148018695</title>\n",
|
||||
"<ellipse fill=\"none\" stroke=\"black\" cx=\"126\" cy=\"-234\" rx=\"27\" ry=\"18\"/>\n",
|
||||
"<text text-anchor=\"middle\" x=\"126\" y=\"-230.3\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">S7</text>\n",
|
||||
"</g>\n",
|
||||
"<!-- var5980780305148018695->var4755801206503243780 -->\n",
|
||||
"<g id=\"edge3\" class=\"edge\">\n",
|
||||
"<title>var5980780305148018695->var4755801206503243780</title>\n",
|
||||
"<path fill=\"none\" stroke=\"black\" d=\"M129.38,-215.87C134.17,-191.56 142.99,-146.82 148.67,-118.01\"/>\n",
|
||||
"<polygon fill=\"black\" stroke=\"black\" points=\"152.11,-118.68 150.61,-108.19 145.24,-117.32 152.11,-118.68\"/>\n",
|
||||
"</g>\n",
|
||||
"<!-- var5980780305148018695->var5476377146882523141 -->\n",
|
||||
"<g id=\"edge2\" class=\"edge\">\n",
|
||||
"<title>var5980780305148018695->var5476377146882523141</title>\n",
|
||||
"<path fill=\"none\" stroke=\"black\" d=\"M119.6,-216.41C116.49,-208.34 112.67,-198.43 109.17,-189.35\"/>\n",
|
||||
"<polygon fill=\"black\" stroke=\"black\" points=\"112.4,-188.03 105.54,-179.96 105.87,-190.55 112.4,-188.03\"/>\n",
|
||||
"</g>\n",
|
||||
"<!-- var6052837899185946630->var4971973988617027587 -->\n",
|
||||
"<g id=\"edge4\" class=\"edge\">\n",
|
||||
"<title>var6052837899185946630->var4971973988617027587</title>\n",
|
||||
"<path fill=\"none\" stroke=\"black\" d=\"M38.93,-145.81C46.21,-136.55 55.66,-124.52 63.85,-114.09\"/>\n",
|
||||
"<polygon fill=\"black\" stroke=\"black\" points=\"66.66,-116.18 70.09,-106.16 61.16,-111.86 66.66,-116.18\"/>\n",
|
||||
"</g>\n",
|
||||
"</g>\n",
|
||||
"</svg>\n"
|
||||
],
|
||||
"text/plain": [
|
||||
"<graphviz.sources.Source at 0x18b782e0520>"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
},
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Log Probability of all zeros: -1.2366269421045588\n",
|
||||
"Sampled Values (basic print):\n",
|
||||
"DiscreteValues{4683743612465315848: 0, 4755801206503243780: 1, 4899916394579099649: 1, 4971973988617027587: 0, 5476377146882523141: 0, 5980780305148018695: 1, 6052837899185946630: 0, 6341068275337658370: 0}\n",
|
||||
"Sampled Values (pretty print):\n",
|
||||
" A8: 0\n",
|
||||
" B4: 1\n",
|
||||
" D1: 1\n",
|
||||
" E3: 0\n",
|
||||
" L5: 0\n",
|
||||
" S7: 1\n",
|
||||
" T6: 0\n",
|
||||
" X2: 0\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# Visualize the network structure\n",
|
||||
"dot_string = asia_net.dot()\n",
|
||||
"display(graphviz.Source(dot_string))\n",
|
||||
"\n",
|
||||
"# Evaluate the log probability of a specific assignment\n",
|
||||
"# Example: Calculate P(A=0, S=0, T=0, L=0, B=0, E=0, X=0, D=0)\n",
|
||||
"values = DiscreteValues()\n",
|
||||
"for key, card in cardinalities.items():\n",
|
||||
" values[key] = 0 # Assign 0 to all variables to start\n",
|
||||
"\n",
|
||||
"log_prob_zeros = asia_net.logProbability(values)\n",
|
||||
"print(f\"Log Probability of all zeros: {log_prob_zeros}\")\n",
|
||||
"\n",
|
||||
"# Sample from the Bayes Net\n",
|
||||
"sample = asia_net.sample()\n",
|
||||
"print(\"Sampled Values (basic print):\")\n",
|
||||
"print(sample)\n",
|
||||
"\n",
|
||||
"# --- Pretty Print ---\n",
|
||||
"print(\"Sampled Values (pretty print):\")\n",
|
||||
"# Create a reverse mapping from integer key to string like 'A8'\n",
|
||||
"# We defined A=symbol('A',8), S=symbol('S',7), etc. above\n",
|
||||
"symbol_map = { A: 'A8', S: 'S7', T: 'T6', L: 'L5', B: 'B4', E: 'E3', X: 'X2', D: 'D1' }\n",
|
||||
"# Iterate through the sampled values and print nicely\n",
|
||||
"# Sort items by the symbol string for consistent order (optional)\n",
|
||||
"for key, value in sorted(sample.items(), key=lambda item: symbol_map.get(item[0], str(item[0]))):\n",
|
||||
" symbol_str = symbol_map.get(key, f\"UnknownKey({key})\") # Get 'A8' from key A\n",
|
||||
" print(f\" {symbol_str}: {value}\")"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"colab": {
|
||||
"provenance": []
|
||||
},
|
||||
"kernelspec": {
|
||||
"display_name": "gtsam",
|
||||
"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.1"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 0
|
||||
}
|
|
@ -0,0 +1,493 @@
|
|||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "bayestree_intro_md"
|
||||
},
|
||||
"source": [
|
||||
"# BayesTree"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "bayestree_desc_md"
|
||||
},
|
||||
"source": [
|
||||
"A `BayesTree` is a graphical model that represents the result of multifrontal variable elimination on a `FactorGraph`. It is a tree structure where each node is a 'clique' containing a set of conditional distributions $P(\\text{Frontals} | \\text{Separator})$.\n",
|
||||
"\n",
|
||||
"Each clique k contains a conditional $P(F_k∣S_k)$, where $F_k$ are frontal variables and $S_k$ are separator variables. The joint probability distribution encoded by the Bayes tree is given by the product of all clique conditionals:\n",
|
||||
"\n",
|
||||
"$$\n",
|
||||
"P(X) = \\prod_k P(F_k | S_k)\n",
|
||||
"$$\n",
|
||||
"\n",
|
||||
"Key properties:\n",
|
||||
"* **Cliques:** Each node (clique) groups variables that are eliminated together.\n",
|
||||
"* **Frontal Variables:** Variables eliminated within a specific clique.\n",
|
||||
"* **Separator Variables:** Variables shared between a clique and its parent in the tree. These variables were eliminated higher up in the tree.\n",
|
||||
"* **Tree Structure:** Represents the dependencies introduced during elimination more compactly than a Bayes net, especially for sparse problems.\n",
|
||||
"\n",
|
||||
"Like `FactorGraph` and `BayesNet`, `BayesTree` is templated on the type of conditional/clique (e.g., `GaussianBayesTree`)."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "bayestree_colab_md"
|
||||
},
|
||||
"source": [
|
||||
"<a href=\"https://colab.research.google.com/github/borglab/gtsam/blob/develop/gtsam/inference/doc/BayesTree.ipynb\" target=\"_parent\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"/></a>"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "bayestree_pip_code",
|
||||
"tags": [
|
||||
"remove-cell"
|
||||
]
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"%pip install gtsam"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 9,
|
||||
"metadata": {
|
||||
"id": "bayestree_import_code"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import gtsam\n",
|
||||
"import numpy as np\n",
|
||||
"import graphviz\n",
|
||||
"\n",
|
||||
"# We need concrete graph types and elimination to get a BayesTree\n",
|
||||
"from gtsam import GaussianFactorGraph, Ordering, GaussianBayesTree, VariableIndex\n",
|
||||
"from gtsam import symbol_shorthand\n",
|
||||
"\n",
|
||||
"X = symbol_shorthand.X\n",
|
||||
"L = symbol_shorthand.L"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "bayestree_create_md"
|
||||
},
|
||||
"source": [
|
||||
"## Creating a BayesTree (via Elimination)\n",
|
||||
"\n",
|
||||
"BayesTrees are typically obtained by performing multifrontal elimination on a `FactorGraph`."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 10,
|
||||
"metadata": {
|
||||
"colab": {
|
||||
"base_uri": "https://localhost:8080/"
|
||||
},
|
||||
"id": "bayestree_eliminate_code",
|
||||
"outputId": "456789ab-cdef-0123-4567-89abcdef0123"
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Original Factor Graph:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"data": {
|
||||
"image/svg+xml": [
|
||||
"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n",
|
||||
"<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"\n",
|
||||
" \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n",
|
||||
"<!-- Generated by graphviz version 2.50.0 (0)\n",
|
||||
" -->\n",
|
||||
"<!-- Pages: 1 -->\n",
|
||||
"<svg width=\"350pt\" height=\"84pt\"\n",
|
||||
" viewBox=\"0.00 0.00 350.00 83.60\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n",
|
||||
"<g id=\"graph0\" class=\"graph\" transform=\"scale(1 1) rotate(0) translate(4 79.6)\">\n",
|
||||
"<polygon fill=\"white\" stroke=\"transparent\" points=\"-4,4 -4,-79.6 346,-79.6 346,4 -4,4\"/>\n",
|
||||
"<!-- var7782220156096217089 -->\n",
|
||||
"<g id=\"node1\" class=\"node\">\n",
|
||||
"<title>var7782220156096217089</title>\n",
|
||||
"<ellipse fill=\"none\" stroke=\"black\" cx=\"99\" cy=\"-57.6\" rx=\"27\" ry=\"18\"/>\n",
|
||||
"<text text-anchor=\"middle\" x=\"99\" y=\"-53.9\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">l1</text>\n",
|
||||
"</g>\n",
|
||||
"<!-- factor3 -->\n",
|
||||
"<g id=\"node9\" class=\"node\">\n",
|
||||
"<title>factor3</title>\n",
|
||||
"<ellipse fill=\"black\" stroke=\"black\" cx=\"75\" cy=\"-1.8\" rx=\"1.8\" ry=\"1.8\"/>\n",
|
||||
"</g>\n",
|
||||
"<!-- var7782220156096217089--factor3 -->\n",
|
||||
"<g id=\"edge6\" class=\"edge\">\n",
|
||||
"<title>var7782220156096217089--factor3</title>\n",
|
||||
"<path fill=\"none\" stroke=\"black\" d=\"M91.67,-40.17C85.49,-26.32 77.36,-8.1 75.43,-3.76\"/>\n",
|
||||
"</g>\n",
|
||||
"<!-- factor4 -->\n",
|
||||
"<g id=\"node10\" class=\"node\">\n",
|
||||
"<title>factor4</title>\n",
|
||||
"<ellipse fill=\"black\" stroke=\"black\" cx=\"123\" cy=\"-1.8\" rx=\"1.8\" ry=\"1.8\"/>\n",
|
||||
"</g>\n",
|
||||
"<!-- var7782220156096217089--factor4 -->\n",
|
||||
"<g id=\"edge8\" class=\"edge\">\n",
|
||||
"<title>var7782220156096217089--factor4</title>\n",
|
||||
"<path fill=\"none\" stroke=\"black\" d=\"M106.33,-40.17C112.51,-26.32 120.64,-8.1 122.57,-3.76\"/>\n",
|
||||
"</g>\n",
|
||||
"<!-- var7782220156096217090 -->\n",
|
||||
"<g id=\"node2\" class=\"node\">\n",
|
||||
"<title>var7782220156096217090</title>\n",
|
||||
"<ellipse fill=\"none\" stroke=\"black\" cx=\"315\" cy=\"-57.6\" rx=\"27\" ry=\"18\"/>\n",
|
||||
"<text text-anchor=\"middle\" x=\"315\" y=\"-53.9\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">l2</text>\n",
|
||||
"</g>\n",
|
||||
"<!-- factor5 -->\n",
|
||||
"<g id=\"node11\" class=\"node\">\n",
|
||||
"<title>factor5</title>\n",
|
||||
"<ellipse fill=\"black\" stroke=\"black\" cx=\"243\" cy=\"-1.8\" rx=\"1.8\" ry=\"1.8\"/>\n",
|
||||
"</g>\n",
|
||||
"<!-- var7782220156096217090--factor5 -->\n",
|
||||
"<g id=\"edge10\" class=\"edge\">\n",
|
||||
"<title>var7782220156096217090--factor5</title>\n",
|
||||
"<path fill=\"none\" stroke=\"black\" d=\"M297.57,-43.58C278.26,-29.15 249.13,-7.38 243.84,-3.43\"/>\n",
|
||||
"</g>\n",
|
||||
"<!-- factor6 -->\n",
|
||||
"<g id=\"node12\" class=\"node\">\n",
|
||||
"<title>factor6</title>\n",
|
||||
"<ellipse fill=\"black\" stroke=\"black\" cx=\"279\" cy=\"-1.8\" rx=\"1.8\" ry=\"1.8\"/>\n",
|
||||
"</g>\n",
|
||||
"<!-- var7782220156096217090--factor6 -->\n",
|
||||
"<g id=\"edge12\" class=\"edge\">\n",
|
||||
"<title>var7782220156096217090--factor6</title>\n",
|
||||
"<path fill=\"none\" stroke=\"black\" d=\"M304.39,-40.75C295.1,-26.86 282.63,-8.22 279.66,-3.78\"/>\n",
|
||||
"</g>\n",
|
||||
"<!-- var8646911284551352320 -->\n",
|
||||
"<g id=\"node3\" class=\"node\">\n",
|
||||
"<title>var8646911284551352320</title>\n",
|
||||
"<ellipse fill=\"none\" stroke=\"black\" cx=\"27\" cy=\"-57.6\" rx=\"27\" ry=\"18\"/>\n",
|
||||
"<text text-anchor=\"middle\" x=\"27\" y=\"-53.9\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">x0</text>\n",
|
||||
"</g>\n",
|
||||
"<!-- factor0 -->\n",
|
||||
"<g id=\"node6\" class=\"node\">\n",
|
||||
"<title>factor0</title>\n",
|
||||
"<ellipse fill=\"black\" stroke=\"black\" cx=\"27\" cy=\"-1.8\" rx=\"1.8\" ry=\"1.8\"/>\n",
|
||||
"</g>\n",
|
||||
"<!-- var8646911284551352320--factor0 -->\n",
|
||||
"<g id=\"edge1\" class=\"edge\">\n",
|
||||
"<title>var8646911284551352320--factor0</title>\n",
|
||||
"<path fill=\"none\" stroke=\"black\" d=\"M27,-39.58C27,-25.79 27,-7.97 27,-3.73\"/>\n",
|
||||
"</g>\n",
|
||||
"<!-- factor1 -->\n",
|
||||
"<g id=\"node7\" class=\"node\">\n",
|
||||
"<title>factor1</title>\n",
|
||||
"<ellipse fill=\"black\" stroke=\"black\" cx=\"100\" cy=\"-1.8\" rx=\"1.8\" ry=\"1.8\"/>\n",
|
||||
"</g>\n",
|
||||
"<!-- var8646911284551352320--factor1 -->\n",
|
||||
"<g id=\"edge2\" class=\"edge\">\n",
|
||||
"<title>var8646911284551352320--factor1</title>\n",
|
||||
"<path fill=\"none\" stroke=\"black\" d=\"M44.67,-43.58C64.25,-29.15 93.78,-7.38 99.15,-3.43\"/>\n",
|
||||
"</g>\n",
|
||||
"<!-- var8646911284551352320--factor3 -->\n",
|
||||
"<g id=\"edge7\" class=\"edge\">\n",
|
||||
"<title>var8646911284551352320--factor3</title>\n",
|
||||
"<path fill=\"none\" stroke=\"black\" d=\"M40.37,-41.61C52.8,-27.68 69.99,-8.41 74.09,-3.81\"/>\n",
|
||||
"</g>\n",
|
||||
"<!-- var8646911284551352321 -->\n",
|
||||
"<g id=\"node4\" class=\"node\">\n",
|
||||
"<title>var8646911284551352321</title>\n",
|
||||
"<ellipse fill=\"none\" stroke=\"black\" cx=\"171\" cy=\"-57.6\" rx=\"27\" ry=\"18\"/>\n",
|
||||
"<text text-anchor=\"middle\" x=\"171\" y=\"-53.9\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">x1</text>\n",
|
||||
"</g>\n",
|
||||
"<!-- var8646911284551352321--factor1 -->\n",
|
||||
"<g id=\"edge3\" class=\"edge\">\n",
|
||||
"<title>var8646911284551352321--factor1</title>\n",
|
||||
"<path fill=\"none\" stroke=\"black\" d=\"M153.81,-43.58C134.77,-29.15 106.05,-7.38 100.83,-3.43\"/>\n",
|
||||
"</g>\n",
|
||||
"<!-- factor2 -->\n",
|
||||
"<g id=\"node8\" class=\"node\">\n",
|
||||
"<title>factor2</title>\n",
|
||||
"<ellipse fill=\"black\" stroke=\"black\" cx=\"178\" cy=\"-1.8\" rx=\"1.8\" ry=\"1.8\"/>\n",
|
||||
"</g>\n",
|
||||
"<!-- var8646911284551352321--factor2 -->\n",
|
||||
"<g id=\"edge4\" class=\"edge\">\n",
|
||||
"<title>var8646911284551352321--factor2</title>\n",
|
||||
"<path fill=\"none\" stroke=\"black\" d=\"M173.21,-39.58C175.01,-25.79 177.33,-7.97 177.88,-3.73\"/>\n",
|
||||
"</g>\n",
|
||||
"<!-- var8646911284551352321--factor4 -->\n",
|
||||
"<g id=\"edge9\" class=\"edge\">\n",
|
||||
"<title>var8646911284551352321--factor4</title>\n",
|
||||
"<path fill=\"none\" stroke=\"black\" d=\"M157.63,-41.61C145.2,-27.68 128.01,-8.41 123.91,-3.81\"/>\n",
|
||||
"</g>\n",
|
||||
"<!-- var8646911284551352321--factor5 -->\n",
|
||||
"<g id=\"edge11\" class=\"edge\">\n",
|
||||
"<title>var8646911284551352321--factor5</title>\n",
|
||||
"<path fill=\"none\" stroke=\"black\" d=\"M188.43,-43.58C207.74,-29.15 236.87,-7.38 242.16,-3.43\"/>\n",
|
||||
"</g>\n",
|
||||
"<!-- var8646911284551352322 -->\n",
|
||||
"<g id=\"node5\" class=\"node\">\n",
|
||||
"<title>var8646911284551352322</title>\n",
|
||||
"<ellipse fill=\"none\" stroke=\"black\" cx=\"243\" cy=\"-57.6\" rx=\"27\" ry=\"18\"/>\n",
|
||||
"<text text-anchor=\"middle\" x=\"243\" y=\"-53.9\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">x2</text>\n",
|
||||
"</g>\n",
|
||||
"<!-- var8646911284551352322--factor2 -->\n",
|
||||
"<g id=\"edge5\" class=\"edge\">\n",
|
||||
"<title>var8646911284551352322--factor2</title>\n",
|
||||
"<path fill=\"none\" stroke=\"black\" d=\"M226.6,-43.02C209.75,-29.08 185.18,-8.74 179.3,-3.87\"/>\n",
|
||||
"</g>\n",
|
||||
"<!-- var8646911284551352322--factor6 -->\n",
|
||||
"<g id=\"edge13\" class=\"edge\">\n",
|
||||
"<title>var8646911284551352322--factor6</title>\n",
|
||||
"<path fill=\"none\" stroke=\"black\" d=\"M253.61,-40.75C262.9,-26.86 275.37,-8.22 278.34,-3.78\"/>\n",
|
||||
"</g>\n",
|
||||
"</g>\n",
|
||||
"</svg>\n"
|
||||
],
|
||||
"text/plain": [
|
||||
"<graphviz.sources.Source at 0x1d6fb24ec10>"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# Create a simple Gaussian Factor Graph\n",
|
||||
"graph = GaussianFactorGraph()\n",
|
||||
"model = gtsam.noiseModel.Isotropic.Sigma(1, 1.0)\n",
|
||||
"graph.add(X(0), -np.eye(1), np.zeros(1), model) # Prior on x0\n",
|
||||
"graph.add(X(0), -np.eye(1), X(1), np.eye(1), np.zeros(1), model) # x0 -> x1\n",
|
||||
"graph.add(X(1), -np.eye(1), X(2), np.eye(1), np.zeros(1), model) # x1 -> x2\n",
|
||||
"graph.add(L(1), -np.eye(1), X(0), np.eye(1), np.zeros(1), model) # l1 -> x0 (measurement)\n",
|
||||
"graph.add(L(1), -np.eye(1), X(1), np.eye(1), np.zeros(1), model) # l1 -> x1 (measurement)\n",
|
||||
"graph.add(L(2), -np.eye(1), X(1), np.eye(1), np.zeros(1), model) # l2 -> x1 (measurement)\n",
|
||||
"graph.add(L(2), -np.eye(1), X(2), np.eye(1), np.zeros(1), model) # l2 -> x2 (measurement)\n",
|
||||
"\n",
|
||||
"print(\"Original Factor Graph:\")\n",
|
||||
"display(graphviz.Source(graph.dot()))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 12,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Resulting BayesTree:\n",
|
||||
": cliques: 2, variables: 5\n",
|
||||
"- p(x1 l2 x2 )\n",
|
||||
" R = [ 1.61245 -0.620174 -0.620174 ]\n",
|
||||
" [ 0 1.27098 -1.08941 ]\n",
|
||||
" [ 0 0 0.654654 ]\n",
|
||||
" d = [ 0 0 0 ]\n",
|
||||
" mean: 3 elements\n",
|
||||
" l2: 0\n",
|
||||
" x1: 0\n",
|
||||
" x2: 0\n",
|
||||
" logNormalizationConstant: -2.46292\n",
|
||||
" No noise model\n",
|
||||
"| - p(l1 x0 | x1)\n",
|
||||
" R = [ 1.41421 -0.707107 ]\n",
|
||||
" [ 0 1.58114 ]\n",
|
||||
" S[x1] = [ -0.707107 ]\n",
|
||||
" [ -0.948683 ]\n",
|
||||
" d = [ 0 0 ]\n",
|
||||
" logNormalizationConstant: -1.03316\n",
|
||||
" No noise model\n",
|
||||
"\n",
|
||||
"Visualization:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"data": {
|
||||
"image/svg+xml": [
|
||||
"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n",
|
||||
"<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"\n",
|
||||
" \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n",
|
||||
"<!-- Generated by graphviz version 2.50.0 (0)\n",
|
||||
" -->\n",
|
||||
"<!-- Title: G Pages: 1 -->\n",
|
||||
"<svg width=\"103pt\" height=\"116pt\"\n",
|
||||
" viewBox=\"0.00 0.00 102.89 116.00\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n",
|
||||
"<g id=\"graph0\" class=\"graph\" transform=\"scale(1 1) rotate(0) translate(4 112)\">\n",
|
||||
"<title>G</title>\n",
|
||||
"<polygon fill=\"white\" stroke=\"transparent\" points=\"-4,4 -4,-112 98.89,-112 98.89,4 -4,4\"/>\n",
|
||||
"<!-- 2 -->\n",
|
||||
"<g id=\"node1\" class=\"node\">\n",
|
||||
"<title>2</title>\n",
|
||||
"<ellipse fill=\"none\" stroke=\"black\" cx=\"47.45\" cy=\"-90\" rx=\"44.69\" ry=\"18\"/>\n",
|
||||
"<text text-anchor=\"middle\" x=\"47.45\" y=\"-86.3\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">x1, l2, x2</text>\n",
|
||||
"</g>\n",
|
||||
"<!-- 3 -->\n",
|
||||
"<g id=\"node2\" class=\"node\">\n",
|
||||
"<title>3</title>\n",
|
||||
"<ellipse fill=\"none\" stroke=\"black\" cx=\"47.45\" cy=\"-18\" rx=\"47.39\" ry=\"18\"/>\n",
|
||||
"<text text-anchor=\"middle\" x=\"47.45\" y=\"-14.3\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">l1, x0 : x1</text>\n",
|
||||
"</g>\n",
|
||||
"<!-- 2->3 -->\n",
|
||||
"<g id=\"edge1\" class=\"edge\">\n",
|
||||
"<title>2->3</title>\n",
|
||||
"<path fill=\"none\" stroke=\"black\" d=\"M47.45,-71.7C47.45,-63.98 47.45,-54.71 47.45,-46.11\"/>\n",
|
||||
"<polygon fill=\"black\" stroke=\"black\" points=\"50.95,-46.1 47.45,-36.1 43.95,-46.1 50.95,-46.1\"/>\n",
|
||||
"</g>\n",
|
||||
"</g>\n",
|
||||
"</svg>\n"
|
||||
],
|
||||
"text/plain": [
|
||||
"<graphviz.sources.Source at 0x1d6fb28be10>"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# Eliminate multifrontally using COLAMD ordering\n",
|
||||
"ordering = Ordering.ColamdGaussianFactorGraph(graph)\n",
|
||||
"# Note: Multifrontal typically yields multiple roots if graph is disconnected\n",
|
||||
"bayes_tree = graph.eliminateMultifrontal(ordering)\n",
|
||||
"\n",
|
||||
"print(\"Resulting BayesTree:\")\n",
|
||||
"bayes_tree.print()\n",
|
||||
"print(\"\\nVisualization:\")\n",
|
||||
"display(graphviz.Source(bayes_tree.dot()))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 6,
|
||||
"metadata": {
|
||||
"colab": {
|
||||
"base_uri": "https://localhost:8080/"
|
||||
},
|
||||
"id": "bayestree_access_code",
|
||||
"outputId": "56789abc-def0-1234-5678-9abcdef01234"
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"BayesTree number of cliques: 2\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"print(f\"BayesTree number of cliques: {bayes_tree.size()}\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "bayestree_solve_md"
|
||||
},
|
||||
"source": [
|
||||
"## Solution and Marginals\n",
|
||||
"\n",
|
||||
"Similar to `BayesNet`, `BayesTree` (specifically derived types like `GaussianBayesTree`) provides an `optimize()` method for finding the MLE solution. It also allows for efficient computation of marginals on individual variables or joint marginals on pairs of variables using belief propagation or shortcut evaluation on the tree."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 7,
|
||||
"metadata": {
|
||||
"colab": {
|
||||
"base_uri": "https://localhost:8080/"
|
||||
},
|
||||
"id": "bayestree_solve_code",
|
||||
"outputId": "6789abcd-ef01-2345-6789-abcdef012345"
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Optimized Solution (MLE):\n",
|
||||
"VectorValues: 5 elements\n",
|
||||
" l1: 0\n",
|
||||
" l2: 0\n",
|
||||
" x0: 0\n",
|
||||
" x1: 0\n",
|
||||
" x2: 0\n",
|
||||
"\n",
|
||||
"Marginal Factor on x1:\n",
|
||||
"GaussianConditional p(x1)\n",
|
||||
" R = [ 0.774597 ]\n",
|
||||
" d = [ 0 ]\n",
|
||||
" mean: 1 elements\n",
|
||||
" x1: 0\n",
|
||||
" logNormalizationConstant: -1.17435\n",
|
||||
" No noise model\n",
|
||||
"\n",
|
||||
"Joint Marginal Factor Graph on (x0, x2):\n",
|
||||
"\n",
|
||||
"size: 2\n",
|
||||
"factor 0: p(x0 | x2)\n",
|
||||
" R = [ 1.32288 ]\n",
|
||||
" S[x2] = [ -0.566947 ]\n",
|
||||
" d = [ 0 ]\n",
|
||||
" logNormalizationConstant: -0.639131\n",
|
||||
" No noise model\n",
|
||||
"factor 1: p(x2)\n",
|
||||
" R = [ 0.654654 ]\n",
|
||||
" d = [ 0 ]\n",
|
||||
" mean: 1 elements\n",
|
||||
" x2: 0\n",
|
||||
" logNormalizationConstant: -1.34259\n",
|
||||
" No noise model\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# Optimize to find the MLE solution (for GaussianBayesTree)\n",
|
||||
"mle_solution = bayes_tree.optimize()\n",
|
||||
"print(\"Optimized Solution (MLE):\")\n",
|
||||
"mle_solution.print()\n",
|
||||
"\n",
|
||||
"# Compute marginal factor on a single variable (returns a Conditional)\n",
|
||||
"marginal_x1 = bayes_tree.marginalFactor(X(1))\n",
|
||||
"print(\"\\nMarginal Factor on x1:\")\n",
|
||||
"marginal_x1.print()\n",
|
||||
"\n",
|
||||
"# Compute joint marginal factor graph on two variables\n",
|
||||
"joint_x0_x2 = bayes_tree.joint(X(0), X(2))\n",
|
||||
"print(\"\\nJoint Marginal Factor Graph on (x0, x2):\")\n",
|
||||
"joint_x0_x2.print()"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"colab": {
|
||||
"provenance": []
|
||||
},
|
||||
"kernelspec": {
|
||||
"display_name": "gtsam",
|
||||
"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.1"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 0
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "clustertree_intro_md"
|
||||
},
|
||||
"source": [
|
||||
"# ClusterTree"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "clustertree_desc_md"
|
||||
},
|
||||
"source": [
|
||||
"A `ClusterTree` is a more general structure than an `EliminationTree` or `JunctionTree`. It represents a tree where each node (a 'Cluster') contains a subset of factors from an original factor graph. The key property is that the tree must be 'family preserving', meaning each original factor must belong entirely within a single cluster.\n",
|
||||
"\n",
|
||||
"`ClusterTree` itself is a base class. `EliminatableClusterTree` adds the ability to perform elimination, and `JunctionTree` is a specific type of `EliminatableClusterTree` derived from an `EliminationTree`.\n",
|
||||
"\n",
|
||||
"Direct use of `ClusterTree` in Python applications is uncommon; see the subclasses."
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"colab": {
|
||||
"provenance": []
|
||||
},
|
||||
"kernelspec": {
|
||||
"display_name": "gtsam",
|
||||
"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.1"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 0
|
||||
}
|
|
@ -0,0 +1,266 @@
|
|||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "conditional_intro_md"
|
||||
},
|
||||
"source": [
|
||||
"# Conditional"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "conditional_desc_md"
|
||||
},
|
||||
"source": [
|
||||
"`gtsam.Conditional` is the base class for conditional probability distributions or densities that result from variable elimination.\n",
|
||||
"\n",
|
||||
"Let $F$ be the set of frontal variables and $S$ be the set of parent (separator) variables. A conditional represents:\n",
|
||||
"\n",
|
||||
"$$\n",
|
||||
"P(F | S)\n",
|
||||
"$$\n",
|
||||
"The methods `evaluate`, `logProbability`, and `error` are related:\n",
|
||||
"$$\n",
|
||||
"\\text{evaluate}(F, S) = P(F | S)\n",
|
||||
"$$\n",
|
||||
"$$\n",
|
||||
"\\text{logProbability}(F, S) = \\log P(F | S)\n",
|
||||
"$$\n",
|
||||
"$$\n",
|
||||
"\\text{logProbability}(F, S) = -(\\text{negLogConstant} + \\text{error}(F, S))\n",
|
||||
"$$\n",
|
||||
"where `negLogConstant` is $-\\log k$ for the normalization constant $k$ ensuring $\\int P(F|S) dF = 1$.\n",
|
||||
"\n",
|
||||
"Like `gtsam.Factor`, you typically don't instantiate `gtsam.Conditional` directly. Instead, you work with derived classes obtained from elimination, such as:\n",
|
||||
"* `gtsam.GaussianConditional`\n",
|
||||
"* `gtsam.DiscreteConditional`\n",
|
||||
"* `gtsam.HybridGaussianConditional`\n",
|
||||
"* `gtsam.SymbolicConditional`\n",
|
||||
"\n",
|
||||
"This notebook demonstrates the common interface provided by the base class."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "conditional_colab_md"
|
||||
},
|
||||
"source": [
|
||||
"<a href=\"https://colab.research.google.com/github/borglab/gtsam/blob/develop/gtsam/inference/doc/Conditional.ipynb\" target=\"_parent\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"/></a>"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "conditional_pip_code",
|
||||
"tags": [
|
||||
"remove-cell"
|
||||
]
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"%pip install gtsam"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"metadata": {
|
||||
"id": "conditional_import_code"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import gtsam\n",
|
||||
"import numpy as np\n",
|
||||
"\n",
|
||||
"# We need concrete graph types and elimination to get a Conditional\n",
|
||||
"from gtsam import GaussianFactorGraph, Ordering\n",
|
||||
"from gtsam import symbol_shorthand\n",
|
||||
"\n",
|
||||
"X = symbol_shorthand.X\n",
|
||||
"L = symbol_shorthand.L"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "conditional_example_md"
|
||||
},
|
||||
"source": [
|
||||
"## Example: Obtaining and Inspecting a Conditional\n",
|
||||
"\n",
|
||||
"We'll create a simple `GaussianFactorGraph` and eliminate one variable to get a `GaussianConditional`."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 6,
|
||||
"metadata": {
|
||||
"colab": {
|
||||
"base_uri": "https://localhost:8080/"
|
||||
},
|
||||
"id": "conditional_create_code",
|
||||
"outputId": "def01234-5678-9abc-def0-123456789abc"
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Eliminating x0 from graph:\n",
|
||||
"\n",
|
||||
"size: 2\n",
|
||||
"factor 0: \n",
|
||||
" A[x0] = [\n",
|
||||
"\t-1\n",
|
||||
"]\n",
|
||||
" b = [ 0 ]\n",
|
||||
" Noise model: unit (1) \n",
|
||||
"factor 1: \n",
|
||||
" A[x0] = [\n",
|
||||
"\t-1\n",
|
||||
"]\n",
|
||||
" A[x1] = [\n",
|
||||
"\t1\n",
|
||||
"]\n",
|
||||
" b = [ 0 ]\n",
|
||||
" Noise model: unit (1) \n",
|
||||
"\n",
|
||||
"Resulting BayesNet:\n",
|
||||
"\n",
|
||||
"size: 1\n",
|
||||
"conditional 0: p(x0 | x1)\n",
|
||||
" R = [ 1.41421 ]\n",
|
||||
" S[x1] = [ -0.707107 ]\n",
|
||||
" d = [ 0 ]\n",
|
||||
" logNormalizationConstant: -0.572365\n",
|
||||
" No noise model\n",
|
||||
"Conditional Keys (all): [8646911284551352320, 8646911284551352321]\n",
|
||||
"First Frontal Key: 8646911284551352320 (x0)\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# Create a simple Gaussian Factor Graph P(x0) P(x1|x0)\n",
|
||||
"graph = GaussianFactorGraph()\n",
|
||||
"model1 = gtsam.noiseModel.Isotropic.Sigma(1, 1.0)\n",
|
||||
"model2 = gtsam.noiseModel.Isotropic.Sigma(1, 1.0)\n",
|
||||
"\n",
|
||||
"# Prior on x0\n",
|
||||
"graph.add(X(0), -np.eye(1), np.zeros(1), model1)\n",
|
||||
"# Factor between x0 and x1\n",
|
||||
"graph.add(X(0), -np.eye(1), X(1), np.eye(1), np.zeros(1), model2)\n",
|
||||
"\n",
|
||||
"print(\"Eliminating x0 from graph:\")\n",
|
||||
"graph.print()\n",
|
||||
"\n",
|
||||
"# Eliminate x0\n",
|
||||
"ordering = Ordering([X(0)])\n",
|
||||
"bayes_net, remaining_graph = graph.eliminatePartialSequential(ordering)\n",
|
||||
"\n",
|
||||
"print(\"\\nResulting BayesNet:\")\n",
|
||||
"bayes_net.print()\n",
|
||||
"\n",
|
||||
"# Get the resulting conditional P(x0 | x1)\n",
|
||||
"# In this case, it's a GaussianConditional\n",
|
||||
"conditional = bayes_net.at(0) # or bayes_net[0]\n",
|
||||
"\n",
|
||||
"# Access methods from the Conditional base class\n",
|
||||
"print(f\"Conditional Keys (all): {conditional.keys()}\")\n",
|
||||
"print(f\"First Frontal Key: {conditional.firstFrontalKey()} ({gtsam.DefaultKeyFormatter(conditional.firstFrontalKey())})\")\n",
|
||||
"\n",
|
||||
"# Conditional objects can also be printed\n",
|
||||
"# conditional.print(\"P(x0 | x1): \")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "conditional_eval_md"
|
||||
},
|
||||
"source": [
|
||||
"## Evaluation (Derived Class Methods)\n",
|
||||
"\n",
|
||||
"Concrete conditional classes provide methods like `logProbability(values)` or `evaluate(values)` to compute the conditional probability (or density) given values for the parent variables. These methods are defined in the derived classes, not the `Conditional` base class itself."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 9,
|
||||
"metadata": {
|
||||
"id": "conditional_eval_code"
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"\n",
|
||||
"Log Probability P(x0|x1=1.0): -0.8223649429247\n",
|
||||
"Probability P(x0|x1=1.0): 0.43939128946772243\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"-0.8223649429247"
|
||||
]
|
||||
},
|
||||
"execution_count": 9,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# Example for GaussianConditional (requires VectorValues)\n",
|
||||
"vector_values = gtsam.VectorValues()\n",
|
||||
"vector_values.insert(X(0), np.array([0.0])) # Value for frontal variable\n",
|
||||
"vector_values.insert(X(1), np.array([1.0])) # Value for parent variable\n",
|
||||
"\n",
|
||||
"# These methods are specific to GaussianConditional / other concrete types\n",
|
||||
"try:\n",
|
||||
" log_prob = conditional.logProbability(vector_values)\n",
|
||||
" print(f\"\\nLog Probability P(x0|x1=1.0): {log_prob}\")\n",
|
||||
" prob = conditional.evaluate(vector_values)\n",
|
||||
" print(f\"Probability P(x0|x1=1.0): {prob}\")\n",
|
||||
"except AttributeError:\n",
|
||||
" print(\"\\nNote: logProbability/evaluate called on base Conditional pointer, needs derived type.\")\n",
|
||||
" # In C++, you'd typically have a shared_ptr<GaussianConditional>.\n",
|
||||
" # In Python, if you know the type, you might access methods directly,\n",
|
||||
" # but the base class wrapper doesn't expose derived methods.\n",
|
||||
" pass\n",
|
||||
"\n",
|
||||
"# To properly evaluate, you often use the BayesNet/BayesTree directly\n",
|
||||
"bayes_net.logProbability(vector_values)"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"colab": {
|
||||
"provenance": []
|
||||
},
|
||||
"kernelspec": {
|
||||
"display_name": "gtsam",
|
||||
"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.1"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 0
|
||||
}
|
|
@ -0,0 +1,333 @@
|
|||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "dotwriter_intro_md"
|
||||
},
|
||||
"source": [
|
||||
"# DotWriter"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "dotwriter_desc_md"
|
||||
},
|
||||
"source": [
|
||||
"The `DotWriter` class is a helper utility in GTSAM used to customize the generation of Graphviz `.dot` file strings for visualizing factor graphs, Bayes nets, and Bayes trees.\n",
|
||||
"\n",
|
||||
"It allows you to control aspects like figure size, whether factors are plotted as points, how edges are drawn, and specify explicit positions for variables and factors."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "dotwriter_colab_md"
|
||||
},
|
||||
"source": [
|
||||
"<a href=\"https://colab.research.google.com/github/borglab/gtsam/blob/develop/gtsam/inference/doc/DotWriter.ipynb\" target=\"_parent\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"/></a>"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "dotwriter_pip_code",
|
||||
"tags": [
|
||||
"remove-cell"
|
||||
]
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"%pip install gtsam"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"metadata": {
|
||||
"id": "dotwriter_import_code"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import gtsam\n",
|
||||
"from gtsam import DotWriter\n",
|
||||
"from gtsam import SymbolicFactorGraph # Example graph type\n",
|
||||
"from gtsam import symbol_shorthand\n",
|
||||
"import graphviz # For rendering\n",
|
||||
"import numpy as np\n",
|
||||
"\n",
|
||||
"X = symbol_shorthand.X\n",
|
||||
"L = symbol_shorthand.L"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "dotwriter_create_md"
|
||||
},
|
||||
"source": [
|
||||
"## Creating and Configuring a DotWriter\n",
|
||||
"\n",
|
||||
"You create a `DotWriter` object and can then modify its public member variables to change the output format."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"metadata": {
|
||||
"id": "dotwriter_config_code"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"writer = DotWriter(\n",
|
||||
" figureWidthInches = 8.0,\n",
|
||||
" figureHeightInches = 5.0,\n",
|
||||
" plotFactorPoints = True, # Draw black dots for factors\n",
|
||||
" connectKeysToFactor = True, # Draw edges from variables to factor dots\n",
|
||||
" binaryEdges = False # Don't simplify binary factors to single edges\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"# --- Configuration Options ---\n",
|
||||
"\n",
|
||||
"# Specify explicit positions (used by neato -n)\n",
|
||||
"writer.variablePositions = {\n",
|
||||
" X(0): gtsam.Point2(0, 0),\n",
|
||||
" X(1): gtsam.Point2(2, 0),\n",
|
||||
" X(2): gtsam.Point2(4, 0),\n",
|
||||
" L(1): gtsam.Point2(1, 2),\n",
|
||||
" L(2): gtsam.Point2(3, 2)\n",
|
||||
"}\n",
|
||||
"\n",
|
||||
"# Specify position hints (alternative, uses symbol char and index)\n",
|
||||
"# writer.positionHints = {'x': 0.0, 'l': 2.0} # Puts 'x' vars at y=0, 'l' vars at y=2\n",
|
||||
"\n",
|
||||
"# Specify which variables should be boxes\n",
|
||||
"writer.boxes = {L(1), L(2)}\n",
|
||||
"\n",
|
||||
"# Specify factor positions (less common)\n",
|
||||
"# writer.factorPositions = {3: gtsam.Point2(0.5, 1.0)}"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "dotwriter_usage_md"
|
||||
},
|
||||
"source": [
|
||||
"## Usage with Graph Objects\n",
|
||||
"\n",
|
||||
"The configured `DotWriter` object is passed as an argument to the `.dot()` method of `FactorGraph`, `BayesNet`, or `BayesTree`."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"colab": {
|
||||
"base_uri": "https://localhost:8080/"
|
||||
},
|
||||
"id": "dotwriter_graph_code",
|
||||
"outputId": "bcdef012-3456-789a-bcde-f0123456789a"
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"image/svg+xml": [
|
||||
"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n",
|
||||
"<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"\n",
|
||||
" \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n",
|
||||
"<!-- Generated by graphviz version 2.50.0 (0)\n",
|
||||
" -->\n",
|
||||
"<!-- Pages: 1 -->\n",
|
||||
"<svg width=\"350pt\" height=\"84pt\"\n",
|
||||
" viewBox=\"0.00 0.00 350.00 83.60\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n",
|
||||
"<g id=\"graph0\" class=\"graph\" transform=\"scale(1 1) rotate(0) translate(4 79.6)\">\n",
|
||||
"<polygon fill=\"white\" stroke=\"transparent\" points=\"-4,4 -4,-79.6 346,-79.6 346,4 -4,4\"/>\n",
|
||||
"<!-- var7782220156096217089 -->\n",
|
||||
"<g id=\"node1\" class=\"node\">\n",
|
||||
"<title>var7782220156096217089</title>\n",
|
||||
"<polygon fill=\"none\" stroke=\"black\" points=\"126,-75.6 72,-75.6 72,-39.6 126,-39.6 126,-75.6\"/>\n",
|
||||
"<text text-anchor=\"middle\" x=\"99\" y=\"-53.9\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">l1</text>\n",
|
||||
"</g>\n",
|
||||
"<!-- factor3 -->\n",
|
||||
"<g id=\"node9\" class=\"node\">\n",
|
||||
"<title>factor3</title>\n",
|
||||
"<ellipse fill=\"black\" stroke=\"black\" cx=\"75\" cy=\"-1.8\" rx=\"1.8\" ry=\"1.8\"/>\n",
|
||||
"</g>\n",
|
||||
"<!-- var7782220156096217089--factor3 -->\n",
|
||||
"<g id=\"edge7\" class=\"edge\">\n",
|
||||
"<title>var7782220156096217089--factor3</title>\n",
|
||||
"<path fill=\"none\" stroke=\"black\" d=\"M91.41,-39.58C85.25,-25.79 77.31,-7.97 75.42,-3.73\"/>\n",
|
||||
"</g>\n",
|
||||
"<!-- factor4 -->\n",
|
||||
"<g id=\"node10\" class=\"node\">\n",
|
||||
"<title>factor4</title>\n",
|
||||
"<ellipse fill=\"black\" stroke=\"black\" cx=\"123\" cy=\"-1.8\" rx=\"1.8\" ry=\"1.8\"/>\n",
|
||||
"</g>\n",
|
||||
"<!-- var7782220156096217089--factor4 -->\n",
|
||||
"<g id=\"edge9\" class=\"edge\">\n",
|
||||
"<title>var7782220156096217089--factor4</title>\n",
|
||||
"<path fill=\"none\" stroke=\"black\" d=\"M106.59,-39.58C112.75,-25.79 120.69,-7.97 122.58,-3.73\"/>\n",
|
||||
"</g>\n",
|
||||
"<!-- var7782220156096217090 -->\n",
|
||||
"<g id=\"node2\" class=\"node\">\n",
|
||||
"<title>var7782220156096217090</title>\n",
|
||||
"<polygon fill=\"none\" stroke=\"black\" points=\"342,-75.6 288,-75.6 288,-39.6 342,-39.6 342,-75.6\"/>\n",
|
||||
"<text text-anchor=\"middle\" x=\"315\" y=\"-53.9\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">l2</text>\n",
|
||||
"</g>\n",
|
||||
"<!-- factor5 -->\n",
|
||||
"<g id=\"node11\" class=\"node\">\n",
|
||||
"<title>factor5</title>\n",
|
||||
"<ellipse fill=\"black\" stroke=\"black\" cx=\"243\" cy=\"-1.8\" rx=\"1.8\" ry=\"1.8\"/>\n",
|
||||
"</g>\n",
|
||||
"<!-- var7782220156096217090--factor5 -->\n",
|
||||
"<g id=\"edge11\" class=\"edge\">\n",
|
||||
"<title>var7782220156096217090--factor5</title>\n",
|
||||
"<path fill=\"none\" stroke=\"black\" d=\"M292.22,-39.58C273.76,-25.79 249.92,-7.97 244.25,-3.73\"/>\n",
|
||||
"</g>\n",
|
||||
"<!-- factor6 -->\n",
|
||||
"<g id=\"node12\" class=\"node\">\n",
|
||||
"<title>factor6</title>\n",
|
||||
"<ellipse fill=\"black\" stroke=\"black\" cx=\"279\" cy=\"-1.8\" rx=\"1.8\" ry=\"1.8\"/>\n",
|
||||
"</g>\n",
|
||||
"<!-- var7782220156096217090--factor6 -->\n",
|
||||
"<g id=\"edge13\" class=\"edge\">\n",
|
||||
"<title>var7782220156096217090--factor6</title>\n",
|
||||
"<path fill=\"none\" stroke=\"black\" d=\"M303.61,-39.58C294.38,-25.79 282.46,-7.97 279.62,-3.73\"/>\n",
|
||||
"</g>\n",
|
||||
"<!-- var8646911284551352320 -->\n",
|
||||
"<g id=\"node3\" class=\"node\">\n",
|
||||
"<title>var8646911284551352320</title>\n",
|
||||
"<ellipse fill=\"none\" stroke=\"black\" cx=\"27\" cy=\"-57.6\" rx=\"27\" ry=\"18\"/>\n",
|
||||
"<text text-anchor=\"middle\" x=\"27\" y=\"-53.9\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">x0</text>\n",
|
||||
"</g>\n",
|
||||
"<!-- factor0 -->\n",
|
||||
"<g id=\"node6\" class=\"node\">\n",
|
||||
"<title>factor0</title>\n",
|
||||
"<ellipse fill=\"black\" stroke=\"black\" cx=\"27\" cy=\"-1.8\" rx=\"1.8\" ry=\"1.8\"/>\n",
|
||||
"</g>\n",
|
||||
"<!-- var8646911284551352320--factor0 -->\n",
|
||||
"<g id=\"edge1\" class=\"edge\">\n",
|
||||
"<title>var8646911284551352320--factor0</title>\n",
|
||||
"<path fill=\"none\" stroke=\"black\" d=\"M27,-39.58C27,-25.79 27,-7.97 27,-3.73\"/>\n",
|
||||
"</g>\n",
|
||||
"<!-- factor1 -->\n",
|
||||
"<g id=\"node7\" class=\"node\">\n",
|
||||
"<title>factor1</title>\n",
|
||||
"<ellipse fill=\"black\" stroke=\"black\" cx=\"100\" cy=\"-1.8\" rx=\"1.8\" ry=\"1.8\"/>\n",
|
||||
"</g>\n",
|
||||
"<!-- var8646911284551352320--factor1 -->\n",
|
||||
"<g id=\"edge2\" class=\"edge\">\n",
|
||||
"<title>var8646911284551352320--factor1</title>\n",
|
||||
"<path fill=\"none\" stroke=\"black\" d=\"M44.67,-43.58C64.25,-29.15 93.78,-7.38 99.15,-3.43\"/>\n",
|
||||
"</g>\n",
|
||||
"<!-- var8646911284551352320--factor3 -->\n",
|
||||
"<g id=\"edge6\" class=\"edge\">\n",
|
||||
"<title>var8646911284551352320--factor3</title>\n",
|
||||
"<path fill=\"none\" stroke=\"black\" d=\"M40.37,-41.61C52.8,-27.68 69.99,-8.41 74.09,-3.81\"/>\n",
|
||||
"</g>\n",
|
||||
"<!-- var8646911284551352321 -->\n",
|
||||
"<g id=\"node4\" class=\"node\">\n",
|
||||
"<title>var8646911284551352321</title>\n",
|
||||
"<ellipse fill=\"none\" stroke=\"black\" cx=\"171\" cy=\"-57.6\" rx=\"27\" ry=\"18\"/>\n",
|
||||
"<text text-anchor=\"middle\" x=\"171\" y=\"-53.9\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">x1</text>\n",
|
||||
"</g>\n",
|
||||
"<!-- var8646911284551352321--factor1 -->\n",
|
||||
"<g id=\"edge3\" class=\"edge\">\n",
|
||||
"<title>var8646911284551352321--factor1</title>\n",
|
||||
"<path fill=\"none\" stroke=\"black\" d=\"M153.81,-43.58C134.77,-29.15 106.05,-7.38 100.83,-3.43\"/>\n",
|
||||
"</g>\n",
|
||||
"<!-- factor2 -->\n",
|
||||
"<g id=\"node8\" class=\"node\">\n",
|
||||
"<title>factor2</title>\n",
|
||||
"<ellipse fill=\"black\" stroke=\"black\" cx=\"178\" cy=\"-1.8\" rx=\"1.8\" ry=\"1.8\"/>\n",
|
||||
"</g>\n",
|
||||
"<!-- var8646911284551352321--factor2 -->\n",
|
||||
"<g id=\"edge4\" class=\"edge\">\n",
|
||||
"<title>var8646911284551352321--factor2</title>\n",
|
||||
"<path fill=\"none\" stroke=\"black\" d=\"M173.21,-39.58C175.01,-25.79 177.33,-7.97 177.88,-3.73\"/>\n",
|
||||
"</g>\n",
|
||||
"<!-- var8646911284551352321--factor4 -->\n",
|
||||
"<g id=\"edge8\" class=\"edge\">\n",
|
||||
"<title>var8646911284551352321--factor4</title>\n",
|
||||
"<path fill=\"none\" stroke=\"black\" d=\"M157.63,-41.61C145.2,-27.68 128.01,-8.41 123.91,-3.81\"/>\n",
|
||||
"</g>\n",
|
||||
"<!-- var8646911284551352321--factor5 -->\n",
|
||||
"<g id=\"edge10\" class=\"edge\">\n",
|
||||
"<title>var8646911284551352321--factor5</title>\n",
|
||||
"<path fill=\"none\" stroke=\"black\" d=\"M188.43,-43.58C207.74,-29.15 236.87,-7.38 242.16,-3.43\"/>\n",
|
||||
"</g>\n",
|
||||
"<!-- var8646911284551352322 -->\n",
|
||||
"<g id=\"node5\" class=\"node\">\n",
|
||||
"<title>var8646911284551352322</title>\n",
|
||||
"<ellipse fill=\"none\" stroke=\"black\" cx=\"243\" cy=\"-57.6\" rx=\"27\" ry=\"18\"/>\n",
|
||||
"<text text-anchor=\"middle\" x=\"243\" y=\"-53.9\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">x2</text>\n",
|
||||
"</g>\n",
|
||||
"<!-- var8646911284551352322--factor2 -->\n",
|
||||
"<g id=\"edge5\" class=\"edge\">\n",
|
||||
"<title>var8646911284551352322--factor2</title>\n",
|
||||
"<path fill=\"none\" stroke=\"black\" d=\"M226.6,-43.02C209.75,-29.08 185.18,-8.74 179.3,-3.87\"/>\n",
|
||||
"</g>\n",
|
||||
"<!-- var8646911284551352322--factor6 -->\n",
|
||||
"<g id=\"edge12\" class=\"edge\">\n",
|
||||
"<title>var8646911284551352322--factor6</title>\n",
|
||||
"<path fill=\"none\" stroke=\"black\" d=\"M253.61,-40.75C262.9,-26.86 275.37,-8.22 278.34,-3.78\"/>\n",
|
||||
"</g>\n",
|
||||
"</g>\n",
|
||||
"</svg>\n"
|
||||
],
|
||||
"text/plain": [
|
||||
"<graphviz.sources.Source at 0x1cdd6cacc20>"
|
||||
]
|
||||
},
|
||||
"execution_count": 4,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# Create the same graph as in VariableIndex example\n",
|
||||
"graph = SymbolicFactorGraph()\n",
|
||||
"graph.push_factor(X(0)) # Factor 0\n",
|
||||
"graph.push_factor(X(0), X(1)) # Factor 1\n",
|
||||
"graph.push_factor(X(1), X(2)) # Factor 2\n",
|
||||
"graph.push_factor(X(0), L(1)) # Factor 3\n",
|
||||
"graph.push_factor(X(1), L(1)) # Factor 4\n",
|
||||
"graph.push_factor(X(1), L(2)) # Factor 5\n",
|
||||
"graph.push_factor(X(2), L(2)) # Factor 6\n",
|
||||
"\n",
|
||||
"# Generate dot string using the configured writer\n",
|
||||
"dot_string = graph.dot(writer=writer)\n",
|
||||
"\n",
|
||||
"# Render the graph\n",
|
||||
"graphviz.Source(dot_string)"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"colab": {
|
||||
"provenance": []
|
||||
},
|
||||
"kernelspec": {
|
||||
"display_name": "gtsam",
|
||||
"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.1"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 0
|
||||
}
|
|
@ -0,0 +1,170 @@
|
|||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "edgekey_intro_md"
|
||||
},
|
||||
"source": [
|
||||
"# EdgeKey"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "edgekey_desc_md"
|
||||
},
|
||||
"source": [
|
||||
"An `EdgeKey` is a utility class in GTSAM used to encode a pair of 32-bit unsigned integers into a single 64-bit `gtsam.Key`. This can be useful for representing edges in a graph or other paired relationships where each element of the pair fits within 32 bits."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "edgekey_colab_md"
|
||||
},
|
||||
"source": [
|
||||
"<a href=\"https://colab.research.google.com/github/borglab/gtsam/blob/develop/gtsam/inference/doc/EdgeKey.ipynb\" target=\"_parent\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"/></a>"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "edgekey_pip_code",
|
||||
"tags": [
|
||||
"remove-cell"
|
||||
]
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"%pip install gtsam"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"metadata": {
|
||||
"id": "edgekey_import_code"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import gtsam\n",
|
||||
"from gtsam import EdgeKey"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "edgekey_init_md"
|
||||
},
|
||||
"source": [
|
||||
"## Initialization\n",
|
||||
"\n",
|
||||
"An `EdgeKey` can be created by providing two 32-bit unsigned integers (`i` and `j`). It can also be created by decoding an existing `gtsam.Key` (integer), assuming it was encoded using the `EdgeKey` format."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"metadata": {
|
||||
"colab": {
|
||||
"base_uri": "https://localhost:8080/"
|
||||
},
|
||||
"id": "edgekey_create_code",
|
||||
"outputId": "cdef1234-5678-90ab-cdef-1234567890ab"
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"EdgeKey from (10, 20): {10, 20}\n",
|
||||
"\n",
|
||||
"EdgeKey from key 42949672980: {10, 20}\n",
|
||||
"\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# Create EdgeKey from integers i=10, j=20\n",
|
||||
"ekey1 = EdgeKey(10, 20)\n",
|
||||
"print(f\"EdgeKey from (10, 20): {ekey1}\") # Uses __str__ which calls operator std::string\n",
|
||||
"\n",
|
||||
"# Get the underlying integer key\n",
|
||||
"key1 = ekey1.key()\n",
|
||||
"\n",
|
||||
"# Reconstruct EdgeKey from the key\n",
|
||||
"ekey2 = EdgeKey(key1)\n",
|
||||
"print(f\"EdgeKey from key {key1}: {ekey2}\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "edgekey_props_md"
|
||||
},
|
||||
"source": [
|
||||
"## Properties and Usage\n",
|
||||
"\n",
|
||||
"You can access the original `i` and `j` values and the combined `Key`."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 4,
|
||||
"metadata": {
|
||||
"colab": {
|
||||
"base_uri": "https://localhost:8080/"
|
||||
},
|
||||
"id": "edgekey_access_code",
|
||||
"outputId": "def12345-6789-0abc-def1-234567890abc"
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"EdgeKey: {123, 456}\n",
|
||||
"\n",
|
||||
" i: 123\n",
|
||||
" j: 456\n",
|
||||
" Key: 528280977864\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"edge = EdgeKey(123, 456)\n",
|
||||
"\n",
|
||||
"print(f\"EdgeKey: {edge}\")\n",
|
||||
"print(f\" i: {edge.i()}\")\n",
|
||||
"print(f\" j: {edge.j()}\")\n",
|
||||
"print(f\" Key: {edge.key()}\")"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"colab": {
|
||||
"provenance": []
|
||||
},
|
||||
"kernelspec": {
|
||||
"display_name": "gtsam",
|
||||
"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.1"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 0
|
||||
}
|
|
@ -0,0 +1,286 @@
|
|||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "etree_intro_md"
|
||||
},
|
||||
"source": [
|
||||
"# EliminationTree"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "etree_desc_md"
|
||||
},
|
||||
"source": [
|
||||
"An `EliminationTree` represents the computational structure of sequential variable elimination (like Gaussian elimination) on a `FactorGraph` given a specific `Ordering`.\n",
|
||||
"\n",
|
||||
"Each node in the tree corresponds to a variable being eliminated. The children of a node represent variables that were eliminated earlier and produced factors involving the parent variable. The factors originally involving the variable at a node are stored at that node.\n",
|
||||
"\n",
|
||||
"Eliminating an `EliminationTree` yields a `BayesNet`.\n",
|
||||
"\n",
|
||||
"While fundamental to the theory, direct manipulation of `EliminationTree` objects in Python is less common than using the `eliminateSequential` method on a `FactorGraph`, which uses the `EliminationTree` internally."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "etree_colab_md"
|
||||
},
|
||||
"source": [
|
||||
"<a href=\"https://colab.research.google.com/github/borglab/gtsam/blob/develop/gtsam/inference/doc/EliminationTree.ipynb\" target=\"_parent\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"/></a>"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "etree_pip_code",
|
||||
"tags": [
|
||||
"remove-cell"
|
||||
]
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"%pip install gtsam"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"metadata": {
|
||||
"id": "etree_import_code"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import gtsam\n",
|
||||
"import numpy as np\n",
|
||||
"\n",
|
||||
"# EliminationTree is templated, need concrete types\n",
|
||||
"from gtsam import GaussianFactorGraph, Ordering, GaussianEliminationTree, GaussianBayesNet\n",
|
||||
"from gtsam import symbol_shorthand\n",
|
||||
"\n",
|
||||
"X = symbol_shorthand.X\n",
|
||||
"L = symbol_shorthand.L"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "etree_create_md"
|
||||
},
|
||||
"source": [
|
||||
"## Creating an EliminationTree\n",
|
||||
"\n",
|
||||
"An `EliminationTree` is constructed from a `FactorGraph` and an `Ordering`."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"metadata": {
|
||||
"colab": {
|
||||
"base_uri": "https://localhost:8080/"
|
||||
},
|
||||
"id": "etree_create_code",
|
||||
"outputId": "f0123456-789a-bcde-f012-3456789abcde"
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Elimination Tree: -(x2)\n",
|
||||
"Elimination Tree: | -(l2)\n",
|
||||
"Elimination Tree: | -\n",
|
||||
" A[l2] = [\n",
|
||||
"\t-1\n",
|
||||
"]\n",
|
||||
" A[x2] = [\n",
|
||||
"\t1\n",
|
||||
"]\n",
|
||||
" b = [ 0 ]\n",
|
||||
" Noise model: unit (1) \n",
|
||||
"Elimination Tree: | | -(x1)\n",
|
||||
"Elimination Tree: | | -\n",
|
||||
" A[x1] = [\n",
|
||||
"\t-1\n",
|
||||
"]\n",
|
||||
" A[x2] = [\n",
|
||||
"\t1\n",
|
||||
"]\n",
|
||||
" b = [ 0 ]\n",
|
||||
" Noise model: unit (1) \n",
|
||||
"Elimination Tree: | | -\n",
|
||||
" A[l2] = [\n",
|
||||
"\t-1\n",
|
||||
"]\n",
|
||||
" A[x1] = [\n",
|
||||
"\t1\n",
|
||||
"]\n",
|
||||
" b = [ 0 ]\n",
|
||||
" Noise model: unit (1) \n",
|
||||
"Elimination Tree: | | | -(l1)\n",
|
||||
"Elimination Tree: | | | -\n",
|
||||
" A[l1] = [\n",
|
||||
"\t-1\n",
|
||||
"]\n",
|
||||
" A[x1] = [\n",
|
||||
"\t1\n",
|
||||
"]\n",
|
||||
" b = [ 0 ]\n",
|
||||
" Noise model: unit (1) \n",
|
||||
"Elimination Tree: | | | | -(x0)\n",
|
||||
"Elimination Tree: | | | | -\n",
|
||||
" A[x0] = [\n",
|
||||
"\t-1\n",
|
||||
"]\n",
|
||||
" b = [ 0 ]\n",
|
||||
" Noise model: unit (1) \n",
|
||||
"Elimination Tree: | | | | -\n",
|
||||
" A[x0] = [\n",
|
||||
"\t-1\n",
|
||||
"]\n",
|
||||
" A[x1] = [\n",
|
||||
"\t1\n",
|
||||
"]\n",
|
||||
" b = [ 0 ]\n",
|
||||
" Noise model: unit (1) \n",
|
||||
"Elimination Tree: | | | | -\n",
|
||||
" A[l1] = [\n",
|
||||
"\t-1\n",
|
||||
"]\n",
|
||||
" A[x0] = [\n",
|
||||
"\t1\n",
|
||||
"]\n",
|
||||
" b = [ 0 ]\n",
|
||||
" Noise model: unit (1) \n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# Create a graph (same as BayesTree example)\n",
|
||||
"graph = GaussianFactorGraph()\n",
|
||||
"model = gtsam.noiseModel.Isotropic.Sigma(1, 1.0)\n",
|
||||
"graph.add(X(0), -np.eye(1), np.zeros(1), model)\n",
|
||||
"graph.add(X(0), -np.eye(1), X(1), np.eye(1), np.zeros(1), model)\n",
|
||||
"graph.add(X(1), -np.eye(1), X(2), np.eye(1), np.zeros(1), model)\n",
|
||||
"graph.add(L(1), -np.eye(1), X(0), np.eye(1), np.zeros(1), model)\n",
|
||||
"graph.add(L(1), -np.eye(1), X(1), np.eye(1), np.zeros(1), model)\n",
|
||||
"graph.add(L(2), -np.eye(1), X(1), np.eye(1), np.zeros(1), model)\n",
|
||||
"graph.add(L(2), -np.eye(1), X(2), np.eye(1), np.zeros(1), model)\n",
|
||||
"\n",
|
||||
"# Define an ordering\n",
|
||||
"ordering = Ordering([X(0), L(1), X(1), L(2), X(2)])\n",
|
||||
"\n",
|
||||
"# Construct the Elimination Tree\n",
|
||||
"elimination_tree = GaussianEliminationTree(graph, ordering)\n",
|
||||
"\n",
|
||||
"elimination_tree.print(\"Elimination Tree: \")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "etree_eliminate_md"
|
||||
},
|
||||
"source": [
|
||||
"## Elimination\n",
|
||||
"\n",
|
||||
"The primary use of an `EliminationTree` is to perform sequential elimination to produce a `BayesNet`."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"metadata": {
|
||||
"colab": {
|
||||
"base_uri": "https://localhost:8080/"
|
||||
},
|
||||
"id": "etree_eliminate_code",
|
||||
"outputId": "01234567-89ab-cdef-0123-456789abcdef"
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"BayesNet from EliminationTree:\n",
|
||||
"\n",
|
||||
"size: 5\n",
|
||||
"conditional 0: p(x0 | l1 x1)\n",
|
||||
" R = [ 1.73205 ]\n",
|
||||
" S[l1] = [ -0.57735 ]\n",
|
||||
" S[x1] = [ -0.57735 ]\n",
|
||||
" d = [ 0 ]\n",
|
||||
" logNormalizationConstant: -0.369632\n",
|
||||
" No noise model\n",
|
||||
"conditional 1: p(l1 | x1)\n",
|
||||
" R = [ 1.29099 ]\n",
|
||||
" S[x1] = [ -1.0328 ]\n",
|
||||
" d = [ 0 ]\n",
|
||||
" logNormalizationConstant: -0.663526\n",
|
||||
" No noise model\n",
|
||||
"conditional 2: p(x1 | l2 x2)\n",
|
||||
" R = [ 1.61245 ]\n",
|
||||
" S[l2] = [ -0.620174 ]\n",
|
||||
" S[x2] = [ -0.620174 ]\n",
|
||||
" d = [ 0 ]\n",
|
||||
" logNormalizationConstant: -0.441183\n",
|
||||
" No noise model\n",
|
||||
"conditional 3: p(l2 | x2)\n",
|
||||
" R = [ 1.27098 ]\n",
|
||||
" S[x2] = [ -1.08941 ]\n",
|
||||
" d = [ 0 ]\n",
|
||||
" logNormalizationConstant: -0.679152\n",
|
||||
" No noise model\n",
|
||||
"conditional 4: p(x2)\n",
|
||||
" R = [ 0.654654 ]\n",
|
||||
" d = [ 0 ]\n",
|
||||
" mean: 1 elements\n",
|
||||
" x2: 0\n",
|
||||
" logNormalizationConstant: -1.34259\n",
|
||||
" No noise model\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# The eliminate function needs to be specified (e.g., EliminateGaussian)\n",
|
||||
"# In Python, this is usually handled internally by graph.eliminateSequential\n",
|
||||
"# but the C++ EliminationTree has an eliminate method.\n",
|
||||
"\n",
|
||||
"# Let's call the graph's eliminateSequential which uses the tree internally\n",
|
||||
"bayes_net, remaining_graph = graph.eliminatePartialSequential(ordering)\n",
|
||||
"\n",
|
||||
"print(\"BayesNet from EliminationTree:\")\n",
|
||||
"bayes_net.print()"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"colab": {
|
||||
"provenance": []
|
||||
},
|
||||
"kernelspec": {
|
||||
"display_name": "gtsam",
|
||||
"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.1"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 0
|
||||
}
|
|
@ -0,0 +1,205 @@
|
|||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "factor_intro_md"
|
||||
},
|
||||
"source": [
|
||||
"# Factor"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "factor_desc_md"
|
||||
},
|
||||
"source": [
|
||||
"`gtsam.Factor` is the abstract base class for all factors in GTSAM, including nonlinear factors, Gaussian factors, discrete factors, and conditionals. It defines the basic interface common to all factors, primarily centered around the set of variables (keys) the factor involves.\n",
|
||||
"\n",
|
||||
"You typically do not instantiate `gtsam.Factor` directly but rather work with its derived classes like `gtsam.NonlinearFactor`, `gtsam.JacobianFactor`, `gtsam.DiscreteFactor`, etc.\n",
|
||||
"\n",
|
||||
"The `error` function of a factor is typically related to a probability or likelihood $P(X)$ or $\\phi(X)$ via the negative log-likelihood:\n",
|
||||
"\n",
|
||||
"$$\n",
|
||||
"\\text{error}(X) = - \\log \\phi(X) + K\n",
|
||||
"$$\n",
|
||||
"or equivalently:\n",
|
||||
"$$\n",
|
||||
"\\phi(X) \\propto \\exp(-\\text{error}(X))\n",
|
||||
"$$\n",
|
||||
"where $X$ are the variables involved in the factor, $\\phi(X)$ is the potential function (proportional to probability or likelihood), and $K$ is some constant. Minimizing the error corresponds to maximizing the probability/likelihood represented by the factor."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "factor_colab_md"
|
||||
},
|
||||
"source": [
|
||||
"<a href=\"https://colab.research.google.com/github/borglab/gtsam/blob/develop/gtsam/inference/doc/Factor.ipynb\" target=\"_parent\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"/></a>"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "factor_pip_code",
|
||||
"tags": [
|
||||
"remove-cell"
|
||||
]
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"%pip install gtsam"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"metadata": {
|
||||
"id": "factor_import_code"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import gtsam\n",
|
||||
"from gtsam.utils.test_case import GtsamTestCase\n",
|
||||
"\n",
|
||||
"# We need a concrete factor type for demonstration\n",
|
||||
"from gtsam import PriorFactorPose2, BetweenFactorPose2, Pose2, Point3\n",
|
||||
"from gtsam import symbol_shorthand\n",
|
||||
"\n",
|
||||
"X = symbol_shorthand.X"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "factor_interface_md"
|
||||
},
|
||||
"source": [
|
||||
"## Basic Interface\n",
|
||||
"\n",
|
||||
"All factors provide methods to access the keys of the variables they involve."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"metadata": {
|
||||
"colab": {
|
||||
"base_uri": "https://localhost:8080/"
|
||||
},
|
||||
"id": "factor_keys_code",
|
||||
"outputId": "01234567-89ab-cdef-0123-456789abcdef"
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Prior factor keys: [8646911284551352320] (x0)\n",
|
||||
"Prior factor size: 1\n",
|
||||
"Between factor keys: [8646911284551352320, 8646911284551352321] (x0, x1)\n",
|
||||
"Between factor size: 2\n",
|
||||
"Is prior factor empty? False\n",
|
||||
"Prior Factor: PriorFactor on x0\n",
|
||||
" prior mean: (0, 0, 0)\n",
|
||||
" noise model: diagonal sigmas [0.1; 0.1; 0.05];\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"noise_model = gtsam.noiseModel.Diagonal.Sigmas(Point3(0.1, 0.1, 0.05))\n",
|
||||
"\n",
|
||||
"# Create some concrete factors\n",
|
||||
"prior_factor = PriorFactorPose2(X(0), Pose2(0, 0, 0), noise_model)\n",
|
||||
"between_factor = BetweenFactorPose2(X(0), X(1), Pose2(1, 0, 0), noise_model)\n",
|
||||
"\n",
|
||||
"# Access keys (methods inherited from gtsam.Factor)\n",
|
||||
"prior_keys = prior_factor.keys()\n",
|
||||
"print(f\"Prior factor keys: {prior_keys} ({gtsam.DefaultKeyFormatter(prior_keys[0])})\")\n",
|
||||
"print(f\"Prior factor size: {prior_factor.size()}\")\n",
|
||||
"\n",
|
||||
"between_keys = between_factor.keys()\n",
|
||||
"print(f\"Between factor keys: {between_keys} ({gtsam.DefaultKeyFormatter(between_keys[0])}, {gtsam.DefaultKeyFormatter(between_keys[1])})\")\n",
|
||||
"print(f\"Between factor size: {between_factor.size()}\")\n",
|
||||
"\n",
|
||||
"print(f\"Is prior factor empty? {prior_factor.empty()}\")\n",
|
||||
"\n",
|
||||
"# Factors can be printed\n",
|
||||
"prior_factor.print(\"Prior Factor: \")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "factor_error_md"
|
||||
},
|
||||
"source": [
|
||||
"## Error Function\n",
|
||||
"\n",
|
||||
"A key method for many factor types (especially nonlinear and Gaussian) is `error(Values)`. This evaluates the negative log-likelihood of the factor given a specific assignment of variable values. For optimization, the goal is typically to find the `Values` that minimize the total error (sum of errors from all factors)."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"metadata": {
|
||||
"colab": {
|
||||
"base_uri": "https://localhost:8080/"
|
||||
},
|
||||
"id": "factor_error_code",
|
||||
"outputId": "12345678-9abc-def0-1234-56789abcdef0"
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Error at ground truth: 0.0\n",
|
||||
"Error with incorrect x1: 50.0\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"values = gtsam.Values()\n",
|
||||
"values.insert(X(0), Pose2(0, 0, 0))\n",
|
||||
"values.insert(X(1), Pose2(1, 0, 0))\n",
|
||||
"\n",
|
||||
"# Evaluate error (example with BetweenFactor)\n",
|
||||
"error1 = between_factor.error(values)\n",
|
||||
"print(f\"Error at ground truth: {error1}\")\n",
|
||||
"\n",
|
||||
"# Change a value and recalculate error\n",
|
||||
"values.update(X(1), Pose2(0, 0, 0))\n",
|
||||
"error2 = between_factor.error(values)\n",
|
||||
"print(f\"Error with incorrect x1: {error2:.1f}\")"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"colab": {
|
||||
"provenance": []
|
||||
},
|
||||
"kernelspec": {
|
||||
"display_name": "gtsam",
|
||||
"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.1"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 0
|
||||
}
|
|
@ -0,0 +1,352 @@
|
|||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "fg_intro_md"
|
||||
},
|
||||
"source": [
|
||||
"# FactorGraph"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "fg_desc_md"
|
||||
},
|
||||
"source": [
|
||||
"A `FactorGraph` represents a factor graph, a bipartite graph connecting variables and factors. In GTSAM, the `FactorGraph` class (and its templated instantiations like `GaussianFactorGraph`, `NonlinearFactorGraph`, etc.) primarily stores a collection of factors.\n",
|
||||
"\n",
|
||||
"This class serves as the base for different types of factor graphs. You typically work with specific instantiations like `gtsam.GaussianFactorGraph` or `gtsam.NonlinearFactorGraph`.\n",
|
||||
"\n",
|
||||
"The total probability $P(X)$ represented by a factor graph is proportional to the product of its individual factor potentials $\\phi_i$:\n",
|
||||
"$$\n",
|
||||
"P(X) \\propto \\prod_i \\phi_i(X_i)\n",
|
||||
"$$\n",
|
||||
"where $X_i$ are the variables involved in factor $i$. In terms of error (negative log-likelihood):\n",
|
||||
"$$\n",
|
||||
"P(X) \\propto \\exp\\left(-\\sum_i \\text{error}_i(X_i)\\right)\n",
|
||||
"$$\n",
|
||||
"The total error for the graph given an assignment $X$ is the sum of the errors of the individual factors:\n",
|
||||
"$$\n",
|
||||
"\\text{error}(X) = \\sum_i \\text{error}_i(X_i)\n",
|
||||
"$$"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "fg_colab_md"
|
||||
},
|
||||
"source": [
|
||||
"<a href=\"https://colab.research.google.com/github/borglab/gtsam/blob/develop/gtsam/inference/doc/FactorGraph.ipynb\" target=\"_parent\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"/></a>"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "fg_pip_code",
|
||||
"tags": [
|
||||
"remove-cell"
|
||||
]
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"%pip install gtsam"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"metadata": {
|
||||
"id": "fg_import_code"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import gtsam\n",
|
||||
"import numpy as np\n",
|
||||
"import graphviz\n",
|
||||
"\n",
|
||||
"# Example uses NonlinearFactorGraph, but concepts apply to others\n",
|
||||
"from gtsam import NonlinearFactorGraph, PriorFactorPose2, BetweenFactorPose2, Pose2, Point3\n",
|
||||
"from gtsam import symbol_shorthand\n",
|
||||
"\n",
|
||||
"X = symbol_shorthand.X"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "fg_init_md"
|
||||
},
|
||||
"source": [
|
||||
"## Initialization and Adding Factors\n",
|
||||
"\n",
|
||||
"A `FactorGraph` is typically created empty and factors are added individually or from containers."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"metadata": {
|
||||
"colab": {
|
||||
"base_uri": "https://localhost:8080/"
|
||||
},
|
||||
"id": "fg_create_code",
|
||||
"outputId": "23456789-abcd-ef01-2345-6789abcdef01"
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Graph size after adding factors: 2\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"graph = NonlinearFactorGraph()\n",
|
||||
"\n",
|
||||
"# Define noise models\n",
|
||||
"prior_noise = gtsam.noiseModel.Diagonal.Sigmas(Point3(0.1, 0.1, 0.05))\n",
|
||||
"odometry_noise = gtsam.noiseModel.Diagonal.Sigmas(Point3(0.2, 0.2, 0.1))\n",
|
||||
"\n",
|
||||
"# Create factors\n",
|
||||
"factor1 = PriorFactorPose2(X(0), Pose2(0, 0, 0), prior_noise)\n",
|
||||
"factor2 = BetweenFactorPose2(X(0), X(1), Pose2(1, 0, 0), odometry_noise)\n",
|
||||
"factor3 = BetweenFactorPose2(X(1), X(2), Pose2(1, 0, 0), odometry_noise)\n",
|
||||
"\n",
|
||||
"# Add factors to the graph\n",
|
||||
"graph.add(factor1) # add is synonym for push_back\n",
|
||||
"graph.push_back(factor2)\n",
|
||||
"\n",
|
||||
"print(f\"Graph size after adding factors: {graph.size()}\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "fg_access_md"
|
||||
},
|
||||
"source": [
|
||||
"## Accessing Factors and Properties"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"metadata": {
|
||||
"colab": {
|
||||
"base_uri": "https://localhost:8080/"
|
||||
},
|
||||
"id": "fg_access_code",
|
||||
"outputId": "3456789a-bcde-f012-3456-789abcdef012"
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Is graph empty? False\n",
|
||||
"Number of factors (size): 2\n",
|
||||
"Number of non-null factors (nrFactors): 2\n",
|
||||
"Factor at index 1: \n",
|
||||
"BetweenFactor(x0,x1)\n",
|
||||
" measured: (1, 0, 0)\n",
|
||||
" noise model: diagonal sigmas [0.2; 0.2; 0.1];\n",
|
||||
"Keys involved in the graph: x0x1\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"print(f\"Is graph empty? {graph.empty()}\")\n",
|
||||
"print(f\"Number of factors (size): {graph.size()}\")\n",
|
||||
"print(f\"Number of non-null factors (nrFactors): {graph.nrFactors()}\") # Useful if factors were removed\n",
|
||||
"\n",
|
||||
"# Access factor by index\n",
|
||||
"retrieved_factor = graph.at(1)\n",
|
||||
"print(\"Factor at index 1: \")\n",
|
||||
"retrieved_factor.print()\n",
|
||||
"\n",
|
||||
"# Get all unique keys involved in the graph\n",
|
||||
"all_keys = graph.keys() # Returns a KeySet\n",
|
||||
"print(f\"Keys involved in the graph: {all_keys}\")\n",
|
||||
"\n",
|
||||
"# Iterate through factors\n",
|
||||
"# for i, factor in enumerate(graph):\n",
|
||||
"# if factor:\n",
|
||||
"# print(f\"Factor {i} keys: {factor.keys()}\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "fg_error_md"
|
||||
},
|
||||
"source": [
|
||||
"## Graph Error\n",
|
||||
"\n",
|
||||
"The `error(Values)` method calculates the total error of the graph for a given assignment of variable values. This is the sum of the errors from each individual factor."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 4,
|
||||
"metadata": {
|
||||
"colab": {
|
||||
"base_uri": "https://localhost:8080/"
|
||||
},
|
||||
"id": "fg_error_code",
|
||||
"outputId": "456789ab-cdef-0123-4567-89abcdef0123"
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Total graph error at ground truth: 0.0\n",
|
||||
"Total graph error with incorrect x2: 0.0\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"values = gtsam.Values()\n",
|
||||
"values.insert(X(0), Pose2(0, 0, 0))\n",
|
||||
"values.insert(X(1), Pose2(1, 0, 0))\n",
|
||||
"values.insert(X(2), Pose2(2, 0, 0))\n",
|
||||
"\n",
|
||||
"total_error1 = graph.error(values)\n",
|
||||
"print(f\"Total graph error at ground truth: {total_error1}\")\n",
|
||||
"\n",
|
||||
"# Introduce an error\n",
|
||||
"values.update(X(2), Pose2(1, 0, 0))\n",
|
||||
"total_error2 = graph.error(values)\n",
|
||||
"print(f\"Total graph error with incorrect x2: {total_error2:.1f}\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "fg_viz_md"
|
||||
},
|
||||
"source": [
|
||||
"## Graph Visualization\n",
|
||||
"\n",
|
||||
"Factor graphs can be visualized using Graphviz via the `dot()` method."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 5,
|
||||
"metadata": {
|
||||
"colab": {
|
||||
"base_uri": "https://localhost:8080/"
|
||||
},
|
||||
"id": "fg_dot_code",
|
||||
"outputId": "56789abc-def0-1234-5678-9abcdef01234"
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"image/svg+xml": [
|
||||
"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n",
|
||||
"<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"\n",
|
||||
" \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n",
|
||||
"<!-- Generated by graphviz version 2.50.0 (0)\n",
|
||||
" -->\n",
|
||||
"<!-- Pages: 1 -->\n",
|
||||
"<svg width=\"134pt\" height=\"84pt\"\n",
|
||||
" viewBox=\"0.00 0.00 134.00 83.60\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n",
|
||||
"<g id=\"graph0\" class=\"graph\" transform=\"scale(1 1) rotate(0) translate(4 79.6)\">\n",
|
||||
"<polygon fill=\"white\" stroke=\"transparent\" points=\"-4,4 -4,-79.6 130,-79.6 130,4 -4,4\"/>\n",
|
||||
"<!-- var8646911284551352320 -->\n",
|
||||
"<g id=\"node1\" class=\"node\">\n",
|
||||
"<title>var8646911284551352320</title>\n",
|
||||
"<ellipse fill=\"none\" stroke=\"black\" cx=\"27\" cy=\"-57.6\" rx=\"27\" ry=\"18\"/>\n",
|
||||
"<text text-anchor=\"middle\" x=\"27\" y=\"-53.9\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">x0</text>\n",
|
||||
"</g>\n",
|
||||
"<!-- factor0 -->\n",
|
||||
"<g id=\"node3\" class=\"node\">\n",
|
||||
"<title>factor0</title>\n",
|
||||
"<ellipse fill=\"black\" stroke=\"black\" cx=\"27\" cy=\"-1.8\" rx=\"1.8\" ry=\"1.8\"/>\n",
|
||||
"</g>\n",
|
||||
"<!-- var8646911284551352320--factor0 -->\n",
|
||||
"<g id=\"edge1\" class=\"edge\">\n",
|
||||
"<title>var8646911284551352320--factor0</title>\n",
|
||||
"<path fill=\"none\" stroke=\"black\" d=\"M27,-39.58C27,-25.79 27,-7.97 27,-3.73\"/>\n",
|
||||
"</g>\n",
|
||||
"<!-- factor1 -->\n",
|
||||
"<g id=\"node4\" class=\"node\">\n",
|
||||
"<title>factor1</title>\n",
|
||||
"<ellipse fill=\"black\" stroke=\"black\" cx=\"74\" cy=\"-1.8\" rx=\"1.8\" ry=\"1.8\"/>\n",
|
||||
"</g>\n",
|
||||
"<!-- var8646911284551352320--factor1 -->\n",
|
||||
"<g id=\"edge2\" class=\"edge\">\n",
|
||||
"<title>var8646911284551352320--factor1</title>\n",
|
||||
"<path fill=\"none\" stroke=\"black\" d=\"M40.09,-41.61C52.26,-27.68 69.09,-8.41 73.11,-3.81\"/>\n",
|
||||
"</g>\n",
|
||||
"<!-- var8646911284551352321 -->\n",
|
||||
"<g id=\"node2\" class=\"node\">\n",
|
||||
"<title>var8646911284551352321</title>\n",
|
||||
"<ellipse fill=\"none\" stroke=\"black\" cx=\"99\" cy=\"-57.6\" rx=\"27\" ry=\"18\"/>\n",
|
||||
"<text text-anchor=\"middle\" x=\"99\" y=\"-53.9\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">x1</text>\n",
|
||||
"</g>\n",
|
||||
"<!-- var8646911284551352321--factor1 -->\n",
|
||||
"<g id=\"edge3\" class=\"edge\">\n",
|
||||
"<title>var8646911284551352321--factor1</title>\n",
|
||||
"<path fill=\"none\" stroke=\"black\" d=\"M91.36,-40.17C84.93,-26.32 76.46,-8.1 74.44,-3.76\"/>\n",
|
||||
"</g>\n",
|
||||
"</g>\n",
|
||||
"</svg>\n"
|
||||
],
|
||||
"text/plain": [
|
||||
"<graphviz.sources.Source at 0x17b3cbfcc20>"
|
||||
]
|
||||
},
|
||||
"execution_count": 5,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"graphviz.Source(graph.dot(values))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "fg_elim_md"
|
||||
},
|
||||
"source": [
|
||||
"## Elimination\n",
|
||||
"\n",
|
||||
"A key purpose of factor graphs is inference via variable elimination. `FactorGraph` itself doesn't perform elimination, but its derived classes (like `GaussianFactorGraph`, `SymbolicFactorGraph`) inherit `eliminateSequential` and `eliminateMultifrontal` methods from `EliminateableFactorGraph`."
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"colab": {
|
||||
"provenance": []
|
||||
},
|
||||
"kernelspec": {
|
||||
"display_name": "gtsam",
|
||||
"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.1"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 0
|
||||
}
|
|
@ -0,0 +1,278 @@
|
|||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "isam_intro_md"
|
||||
},
|
||||
"source": [
|
||||
"# ISAM"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "isam_desc_md"
|
||||
},
|
||||
"source": [
|
||||
"`gtsam.ISAM` (Incremental Smoothing and Mapping) is a class that inherits from `BayesTree` and adds an `update` method. This method allows for efficient incremental updates to the solution when new factors (e.g., new measurements) are added to the problem.\n",
|
||||
"\n",
|
||||
"Instead of re-eliminating the entire factor graph from scratch, iSAM identifies the part of the Bayes tree affected by the new factors, removes that part, and re-eliminates only the necessary variables, merging the results back into the existing tree.\n",
|
||||
"\n",
|
||||
"Like `BayesTree`, it's templated (e.g., `GaussianISAM` which inherits from `GaussianBayesTree`). For practical applications requiring incremental updates, `ISAM2` is often preferred due to further optimizations like fluid relinearization and support for variable removal, but `ISAM` demonstrates the core incremental update concept based on the Bayes tree."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "isam_colab_md"
|
||||
},
|
||||
"source": [
|
||||
"<a href=\"https://colab.research.google.com/github/borglab/gtsam/blob/develop/gtsam/inference/doc/ISAM.ipynb\" target=\"_parent\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"/></a>"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "isam_pip_code",
|
||||
"tags": [
|
||||
"remove-cell"
|
||||
]
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"%pip install gtsam"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"metadata": {
|
||||
"id": "isam_import_code"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import gtsam\n",
|
||||
"import numpy as np\n",
|
||||
"\n",
|
||||
"# Use Gaussian variants for demonstration\n",
|
||||
"from gtsam import GaussianFactorGraph, Ordering, GaussianISAM, GaussianBayesTree\n",
|
||||
"from gtsam import symbol_shorthand\n",
|
||||
"\n",
|
||||
"X = symbol_shorthand.X\n",
|
||||
"L = symbol_shorthand.L"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "isam_create_md"
|
||||
},
|
||||
"source": [
|
||||
"## Initialization\n",
|
||||
"\n",
|
||||
"An `ISAM` object can be created empty or initialized from an existing `BayesTree`."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"metadata": {
|
||||
"colab": {
|
||||
"base_uri": "https://localhost:8080/"
|
||||
},
|
||||
"id": "isam_init_code",
|
||||
"outputId": "89abcdef-0123-4567-89ab-cdef01234567"
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Initial BayesTree:\n",
|
||||
": cliques: 1, variables: 1\n",
|
||||
"- p(x0)\n",
|
||||
" R = [ 1 ]\n",
|
||||
" d = [ 0 ]\n",
|
||||
" mean: 1 elements\n",
|
||||
" x0: 0\n",
|
||||
" logNormalizationConstant: -0.918939\n",
|
||||
" No noise model\n",
|
||||
"ISAM from BayesTree:\n",
|
||||
"GaussianISAM: : cliques: 1, variables: 1\n",
|
||||
"GaussianISAM: - p(x0)\n",
|
||||
" R = [ 1 ]\n",
|
||||
" d = [ 0 ]\n",
|
||||
" mean: 1 elements\n",
|
||||
" x0: 0\n",
|
||||
" logNormalizationConstant: -0.918939\n",
|
||||
" No noise model\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# Create an empty ISAM object\n",
|
||||
"isam1 = GaussianISAM()\n",
|
||||
"\n",
|
||||
"# Create from an existing Bayes Tree (e.g., from an initial batch solve)\n",
|
||||
"initial_graph = GaussianFactorGraph()\n",
|
||||
"model = gtsam.noiseModel.Isotropic.Sigma(1, 1.0)\n",
|
||||
"initial_graph.add(X(0), -np.eye(1), np.zeros(1), model) # Prior on x0\n",
|
||||
"\n",
|
||||
"initial_bayes_tree = initial_graph.eliminateMultifrontal(Ordering([X(0)]))\n",
|
||||
"print(\"Initial BayesTree:\")\n",
|
||||
"initial_bayes_tree.print()\n",
|
||||
"\n",
|
||||
"isam2 = GaussianISAM(initial_bayes_tree)\n",
|
||||
"print(\"ISAM from BayesTree:\")\n",
|
||||
"isam2.print()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "isam_update_md"
|
||||
},
|
||||
"source": [
|
||||
"## Incremental Update\n",
|
||||
"\n",
|
||||
"The core functionality is the `update(newFactors)` method."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 4,
|
||||
"metadata": {
|
||||
"colab": {
|
||||
"base_uri": "https://localhost:8080/"
|
||||
},
|
||||
"id": "isam_update_code",
|
||||
"outputId": "9abcdef0-1234-5678-9abc-def012345678"
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"ISAM after first update (x0, x1):\n",
|
||||
"GaussianISAM: : cliques: 1, variables: 2\n",
|
||||
"GaussianISAM: - p(x1 x0 )\n",
|
||||
" R = [ 1 -1 ]\n",
|
||||
" [ 0 1 ]\n",
|
||||
" d = [ 0 0 ]\n",
|
||||
" mean: 2 elements\n",
|
||||
" x0: 0\n",
|
||||
" x1: 0\n",
|
||||
" logNormalizationConstant: -1.83788\n",
|
||||
" No noise model\n",
|
||||
"\n",
|
||||
"ISAM after second update (x0, x1, x2):\n",
|
||||
"GaussianISAM: : cliques: 2, variables: 3\n",
|
||||
"GaussianISAM: - p(x0 x1 )\n",
|
||||
" R = [ 1.41421 -0.707107 ]\n",
|
||||
" [ 0 0.707107 ]\n",
|
||||
" d = [ 0 0 ]\n",
|
||||
" mean: 2 elements\n",
|
||||
" x0: 0\n",
|
||||
" x1: 0\n",
|
||||
" logNormalizationConstant: -1.83788\n",
|
||||
" No noise model\n",
|
||||
"GaussianISAM: | - p(x2 | x1)\n",
|
||||
" R = [ 1 ]\n",
|
||||
" S[x1] = [ -1 ]\n",
|
||||
" d = [ 0 ]\n",
|
||||
" logNormalizationConstant: -0.918939\n",
|
||||
" No noise model\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# Start with the ISAM object containing the prior on x0\n",
|
||||
"isam = GaussianISAM(initial_bayes_tree)\n",
|
||||
"model = gtsam.noiseModel.Isotropic.Sigma(1, 1.0)\n",
|
||||
"\n",
|
||||
"# --- First Update ---\n",
|
||||
"new_factors1 = GaussianFactorGraph()\n",
|
||||
"new_factors1.add(X(0), -np.eye(1), X(1), np.eye(1), np.zeros(1), model) # x0 -> x1\n",
|
||||
"isam.update(new_factors1)\n",
|
||||
"\n",
|
||||
"print(\"ISAM after first update (x0, x1):\")\n",
|
||||
"isam.print()\n",
|
||||
"\n",
|
||||
"# --- Second Update ---\n",
|
||||
"new_factors2 = GaussianFactorGraph()\n",
|
||||
"new_factors2.add(X(1), -np.eye(1), X(2), np.eye(1), np.zeros(1), model) # x1 -> x2\n",
|
||||
"isam.update(new_factors2)\n",
|
||||
"\n",
|
||||
"print(\"\\nISAM after second update (x0, x1, x2):\")\n",
|
||||
"isam.print()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "isam_solve_md"
|
||||
},
|
||||
"source": [
|
||||
"## Solution and Marginals\n",
|
||||
"\n",
|
||||
"Since `ISAM` inherits from `BayesTree`, you can use the same methods like `optimize()` and `marginalFactor()` after performing updates."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 5,
|
||||
"metadata": {
|
||||
"colab": {
|
||||
"base_uri": "https://localhost:8080/"
|
||||
},
|
||||
"id": "isam_solve_code",
|
||||
"outputId": "abcdef01-2345-6789-abcd-ef0123456789"
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Optimized Solution after updates:\n",
|
||||
"VectorValues: 3 elements\n",
|
||||
" x0: 0\n",
|
||||
" x1: 0\n",
|
||||
" x2: 0\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# Get the solution from the final ISAM state\n",
|
||||
"solution = isam.optimize()\n",
|
||||
"print(\"Optimized Solution after updates:\")\n",
|
||||
"solution.print()"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"colab": {
|
||||
"provenance": []
|
||||
},
|
||||
"kernelspec": {
|
||||
"display_name": "gtsam",
|
||||
"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.1"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 0
|
||||
}
|
|
@ -0,0 +1,169 @@
|
|||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "jtree_intro_md"
|
||||
},
|
||||
"source": [
|
||||
"# JunctionTree"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "jtree_desc_md"
|
||||
},
|
||||
"source": [
|
||||
"A `JunctionTree` is an intermediate data structure used in GTSAM's multifrontal variable elimination. It is a `ClusterTree` where each node (cluster) corresponds to a clique in the chordal graph formed during elimination.\n",
|
||||
"\n",
|
||||
"Key differences from related structures:\n",
|
||||
"* **vs. EliminationTree:** Junction tree nodes can represent the elimination of multiple variables simultaneously (a 'frontal' set), whereas elimination tree nodes typically represent single variable eliminations.\n",
|
||||
"* **vs. BayesTree:** A JunctionTree node contains the original factors associated with the variables being eliminated in that clique. A BayesTree node contains the *result* of eliminating those factors (i.e., a conditional density $P(\\text{Frontals} | \\text{Separator})$).\n",
|
||||
"\n",
|
||||
"Like `EliminationTree`, direct manipulation of `JunctionTree` objects in Python is uncommon. It's primarily an internal structure used by `eliminateMultifrontal` when producing a `BayesTree`."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "jtree_colab_md"
|
||||
},
|
||||
"source": [
|
||||
"<a href=\"https://colab.research.google.com/github/borglab/gtsam/blob/develop/gtsam/inference/doc/JunctionTree.ipynb\" target=\"_parent\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"/></a>"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "jtree_pip_code",
|
||||
"tags": [
|
||||
"remove-cell"
|
||||
]
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"%pip install gtsam"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"metadata": {
|
||||
"id": "jtree_import_code"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import gtsam\n",
|
||||
"import numpy as np\n",
|
||||
"\n",
|
||||
"# JunctionTree is templated, need concrete types\n",
|
||||
"from gtsam import GaussianFactorGraph, Ordering, VariableIndex\n",
|
||||
"from gtsam import symbol_shorthand\n",
|
||||
"\n",
|
||||
"X = symbol_shorthand.X\n",
|
||||
"L = symbol_shorthand.L"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "jtree_create_md"
|
||||
},
|
||||
"source": [
|
||||
"## Creating a JunctionTree\n",
|
||||
"\n",
|
||||
"A `JunctionTree` is typically constructed from an `EliminationTree` as part of the multifrontal elimination process. The direct constructor might not be exposed in Python, as it's usually created internally."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"metadata": {
|
||||
"colab": {
|
||||
"base_uri": "https://localhost:8080/"
|
||||
},
|
||||
"id": "jtree_create_code",
|
||||
"outputId": "12345678-9abc-def0-1234-56789abcdef0"
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Resulting BayesTree (structure mirrors JunctionTree):\n",
|
||||
": cliques: 2, variables: 5\n",
|
||||
"- p(x1 l2 x2 )\n",
|
||||
" R = [ 1.61245 -0.620174 -0.620174 ]\n",
|
||||
" [ 0 1.27098 -1.08941 ]\n",
|
||||
" [ 0 0 0.654654 ]\n",
|
||||
" d = [ 0 0 0 ]\n",
|
||||
" mean: 3 elements\n",
|
||||
" l2: 0\n",
|
||||
" x1: 0\n",
|
||||
" x2: 0\n",
|
||||
" logNormalizationConstant: -2.46292\n",
|
||||
" No noise model\n",
|
||||
"| - p(l1 x0 | x1)\n",
|
||||
" R = [ 1.41421 -0.707107 ]\n",
|
||||
" [ 0 1.58114 ]\n",
|
||||
" S[x1] = [ -0.707107 ]\n",
|
||||
" [ -0.948683 ]\n",
|
||||
" d = [ 0 0 ]\n",
|
||||
" logNormalizationConstant: -1.03316\n",
|
||||
" No noise model\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# Create a graph (same as BayesTree example)\n",
|
||||
"graph = GaussianFactorGraph()\n",
|
||||
"model = gtsam.noiseModel.Isotropic.Sigma(1, 1.0)\n",
|
||||
"graph.add(X(0), -np.eye(1), np.zeros(1), model)\n",
|
||||
"graph.add(X(0), -np.eye(1), X(1), np.eye(1), np.zeros(1), model)\n",
|
||||
"graph.add(X(1), -np.eye(1), X(2), np.eye(1), np.zeros(1), model)\n",
|
||||
"graph.add(L(1), -np.eye(1), X(0), np.eye(1), np.zeros(1), model)\n",
|
||||
"graph.add(L(1), -np.eye(1), X(1), np.eye(1), np.zeros(1), model)\n",
|
||||
"graph.add(L(2), -np.eye(1), X(1), np.eye(1), np.zeros(1), model)\n",
|
||||
"graph.add(L(2), -np.eye(1), X(2), np.eye(1), np.zeros(1), model)\n",
|
||||
"\n",
|
||||
"ordering = Ordering.ColamdGaussianFactorGraph(graph)\n",
|
||||
"\n",
|
||||
"# Perform multifrontal elimination, which uses a JunctionTree internally\n",
|
||||
"bayes_tree, remaining_graph = graph.eliminatePartialMultifrontal(ordering)\n",
|
||||
"\n",
|
||||
"# The resulting BayesTree reflects the structure of the intermediate JunctionTree\n",
|
||||
"print(\"Resulting BayesTree (structure mirrors JunctionTree):\")\n",
|
||||
"bayes_tree.print()\n",
|
||||
"\n",
|
||||
"# Accessing the JunctionTree directly isn't typical in Python workflows.\n",
|
||||
"# Its structure is implicitly captured by the BayesTree cliques."
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"colab": {
|
||||
"provenance": []
|
||||
},
|
||||
"kernelspec": {
|
||||
"display_name": "gtsam",
|
||||
"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.1"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 0
|
||||
}
|
|
@ -0,0 +1,204 @@
|
|||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "key_intro_md"
|
||||
},
|
||||
"source": [
|
||||
"# Key"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "key_desc_md"
|
||||
},
|
||||
"source": [
|
||||
"A `Key` in GTSAM is simply a `typedef` for `std::uint64_t`. It serves as a unique identifier for variables within a factor graph or values within a `Values` container. While you can use raw integer keys, GTSAM provides helper classes like `Symbol` and `LabeledSymbol` to create semantically meaningful keys that encode type and index information within the 64-bit integer."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "key_colab_md"
|
||||
},
|
||||
"source": [
|
||||
"<a href=\"https://colab.research.google.com/github/borglab/gtsam/blob/develop/gtsam/inference/doc/Key.ipynb\" target=\"_parent\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"/></a>"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "key_pip_code",
|
||||
"tags": [
|
||||
"remove-cell"
|
||||
]
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"%pip install gtsam"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"metadata": {
|
||||
"id": "key_import_code"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import gtsam\n",
|
||||
"from gtsam import Symbol, LabeledSymbol\n",
|
||||
"import numpy as np"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "key_usage_md"
|
||||
},
|
||||
"source": [
|
||||
"## Basic Usage\n",
|
||||
"\n",
|
||||
"Keys are typically created using `Symbol` or `LabeledSymbol` and then implicitly or explicitly cast to the `Key` type (integer)."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"metadata": {
|
||||
"colab": {
|
||||
"base_uri": "https://localhost:8080/"
|
||||
},
|
||||
"id": "key_create_code",
|
||||
"outputId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Symbol Key (x0): 8646911284551352320\n",
|
||||
"Type: <class 'int'>\n",
|
||||
"LabeledSymbol Key (aB1): 7008163970141913089\n",
|
||||
"Type: <class 'int'>\n",
|
||||
"Plain Integer Key: 12345\n",
|
||||
"Type: <class 'int'>\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"sym = Symbol('x', 0)\n",
|
||||
"key_from_symbol = sym.key() # Or just 'sym' where a Key is expected\n",
|
||||
"print(f\"Symbol Key (x0): {key_from_symbol}\")\n",
|
||||
"print(f\"Type: {type(key_from_symbol)}\")\n",
|
||||
"\n",
|
||||
"lsym = LabeledSymbol(ord('a'), ord('B'), 1)\n",
|
||||
"key_from_labeled_symbol = lsym.key()\n",
|
||||
"print(f\"LabeledSymbol Key (aB1): {key_from_labeled_symbol}\")\n",
|
||||
"print(f\"Type: {type(key_from_labeled_symbol)}\")\n",
|
||||
"\n",
|
||||
"# You can also use plain integers, but it's less descriptive\n",
|
||||
"plain_key = 12345\n",
|
||||
"print(f\"Plain Integer Key: {plain_key}\")\n",
|
||||
"print(f\"Type: {type(plain_key)}\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "key_formatter_md"
|
||||
},
|
||||
"source": [
|
||||
"## Key Formatting\n",
|
||||
"\n",
|
||||
"When printing GTSAM objects that contain keys (like Factor Graphs or Values), you can specify a `KeyFormatter` to control how keys are displayed. The default formatter tries to interpret keys as `Symbol`s."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 4,
|
||||
"metadata": {
|
||||
"colab": {
|
||||
"base_uri": "https://localhost:8080/"
|
||||
},
|
||||
"id": "key_format_code",
|
||||
"outputId": "b2c3d4e5-f6a7-8901-bcde-f12345678901"
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Default Formatter:\n",
|
||||
" Symbol Key: x0\n",
|
||||
" LabeledSymbol Key: a18577348\n",
|
||||
" Plain Key: 12345\n",
|
||||
"Custom Formatter:\n",
|
||||
" Symbol Key: KEY[x0]\n",
|
||||
" LabeledSymbol Key: KEY[a18577348]\n",
|
||||
" Plain Key: KEY[12345]\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"print(\"Default Formatter:\")\n",
|
||||
"print(f\" Symbol Key: {gtsam.DefaultKeyFormatter(key_from_symbol)}\")\n",
|
||||
"print(f\" LabeledSymbol Key: {gtsam.DefaultKeyFormatter(key_from_labeled_symbol)}\")\n",
|
||||
"print(f\" Plain Key: {gtsam.DefaultKeyFormatter(plain_key)}\")\n",
|
||||
"\n",
|
||||
"# Example of a custom formatter\n",
|
||||
"def my_formatter(key):\n",
|
||||
" # Try interpreting as LabeledSymbol, then Symbol, then default\n",
|
||||
" try:\n",
|
||||
" lsym = gtsam.LabeledSymbol(key)\n",
|
||||
" if lsym.label() != 0: # Check if it's likely a valid LabeledSymbol\n",
|
||||
" return f\"KEY[{lsym.string()}]\"\n",
|
||||
" except:\n",
|
||||
" pass\n",
|
||||
" try:\n",
|
||||
" sym = gtsam.Symbol(key)\n",
|
||||
" if sym.chr() != 0: # Check if it's likely a valid Symbol\n",
|
||||
" return f\"KEY[{sym.string()}]\"\n",
|
||||
" except:\n",
|
||||
" pass\n",
|
||||
" return f\"KEY[{key}]\"\n",
|
||||
"\n",
|
||||
"print(\"Custom Formatter:\")\n",
|
||||
"print(f\" Symbol Key: {my_formatter(key_from_symbol)}\")\n",
|
||||
"print(f\" LabeledSymbol Key: {my_formatter(key_from_labeled_symbol)}\")\n",
|
||||
"print(f\" Plain Key: {my_formatter(plain_key)}\")\n",
|
||||
"\n",
|
||||
"# KeyVectors, KeyLists, KeySets can also be printed using formatters\n",
|
||||
"key_vector = gtsam.KeyVector([key_from_symbol, key_from_labeled_symbol, plain_key])\n",
|
||||
"# key_vector.print(\"My Vector: \", my_formatter) # .print() method uses formatter directly"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"colab": {
|
||||
"provenance": []
|
||||
},
|
||||
"kernelspec": {
|
||||
"display_name": "gtsam",
|
||||
"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.1"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 0
|
||||
}
|
|
@ -0,0 +1,212 @@
|
|||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "lsymbol_intro_md"
|
||||
},
|
||||
"source": [
|
||||
"# LabeledSymbol"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "lsymbol_desc_md"
|
||||
},
|
||||
"source": [
|
||||
"A `LabeledSymbol` is a specialized version of `gtsam.Symbol` designed primarily for multi-robot applications or scenarios where an additional label is needed besides the type character and index. It encodes a type character (`unsigned char`), a label character (`unsigned char`), and an index (`uint64_t`) into a single 64-bit `gtsam.Key`."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "lsymbol_colab_md"
|
||||
},
|
||||
"source": [
|
||||
"<a href=\"https://colab.research.google.com/github/borglab/gtsam/blob/develop/gtsam/inference/doc/LabeledSymbol.ipynb\" target=\"_parent\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"/></a>"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "lsymbol_pip_code",
|
||||
"tags": [
|
||||
"remove-cell"
|
||||
]
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"%pip install gtsam"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"metadata": {
|
||||
"id": "lsymbol_import_code"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import gtsam\n",
|
||||
"from gtsam import LabeledSymbol"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "lsymbol_init_md"
|
||||
},
|
||||
"source": [
|
||||
"## Initialization\n",
|
||||
"\n",
|
||||
"A `LabeledSymbol` can be created by providing a type character, a label character, and an index. It can also be created by decoding an existing `gtsam.Key` (integer)."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"colab": {
|
||||
"base_uri": "https://localhost:8080/"
|
||||
},
|
||||
"id": "lsymbol_create_code",
|
||||
"outputId": "f1a2b3c4-d5e6-7890-f1a2-bcdef1234567"
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"LabeledSymbol from char/label/index: : xA7\n",
|
||||
"\n",
|
||||
"LabeledSymbol from key 8646911284551352320: : x\n",
|
||||
"\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# Create LabeledSymbol 'x' from robot 'A' with index 7\n",
|
||||
"# The underlying C++ expects chars, so we have to convert single-character strings with ord()\n",
|
||||
"lsym1 = LabeledSymbol(ord('x'), ord('A'), 7)\n",
|
||||
"print(f\"LabeledSymbol from char/label/index: {lsym1}\")\n",
|
||||
"\n",
|
||||
"# Get the underlying integer key\n",
|
||||
"key1 = lsym1.key()\n",
|
||||
"\n",
|
||||
"# Reconstruct LabeledSymbol from the key\n",
|
||||
"# Note: Decoding a key assumes it was encoded as a LabeledSymbol.\n",
|
||||
"# If you decode a standard Symbol key, the label might be garbage.\n",
|
||||
"x0_key = gtsam.Symbol('x', 0).key()\n",
|
||||
"lsym2 = LabeledSymbol(x0_key)\n",
|
||||
"print(f\"LabeledSymbol from key {x0_key}: {lsym2}\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "lsymbol_props_md"
|
||||
},
|
||||
"source": [
|
||||
"## Properties and Usage\n",
|
||||
"\n",
|
||||
"You can access the type character, label character, index, and underlying integer key."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 8,
|
||||
"metadata": {
|
||||
"colab": {
|
||||
"base_uri": "https://localhost:8080/"
|
||||
},
|
||||
"id": "lsymbol_access_code",
|
||||
"outputId": "a2b3c4d5-e6f7-8901-a2b3-cdef12345678"
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"LabeledSymbol: : lB3\n",
|
||||
"\n",
|
||||
" Char (Type): 108\n",
|
||||
" Label (Robot): 66\n",
|
||||
" Index: 3\n",
|
||||
" Key: 7800797504559120387\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"robotB_landmark = LabeledSymbol(ord('l'), ord('B'), 3)\n",
|
||||
"\n",
|
||||
"print(f\"LabeledSymbol: {robotB_landmark}\")\n",
|
||||
"print(f\" Char (Type): {robotB_landmark.chr()}\")\n",
|
||||
"print(f\" Label (Robot): {robotB_landmark.label()}\")\n",
|
||||
"print(f\" Index: {robotB_landmark.index()}\")\n",
|
||||
"print(f\" Key: {robotB_landmark.key()}\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "lsymbol_shorthand_md"
|
||||
},
|
||||
"source": [
|
||||
"## Shorthand Function\n",
|
||||
"\n",
|
||||
"GTSAM provides a convenient shorthand function `gtsam.mrsymbol(c, label, j)`."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"colab": {
|
||||
"base_uri": "https://localhost:8080/"
|
||||
},
|
||||
"id": "lsymbol_shorthand_code",
|
||||
"outputId": "b3c4d5e6-f7a8-9012-b3c4-def123456789"
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"LabeledSymbol(ord('p'), ord('C'), 2).key() == gtsam.mrsymbol(ord('p'), ord('C'), 2): True\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"pc2_key = gtsam.mrsymbol(ord('p'), ord('C'), 2)\n",
|
||||
"\n",
|
||||
"print(f\"LabeledSymbol(ord('p'), ord('C'), 2).key() == gtsam.mrsymbol(ord('p'), ord('C'), 2): {LabeledSymbol(ord('p'), ord('C'), 2).key() == pc2_key}\")"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"colab": {
|
||||
"provenance": []
|
||||
},
|
||||
"kernelspec": {
|
||||
"display_name": "gtsam",
|
||||
"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.1"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 0
|
||||
}
|
|
@ -0,0 +1,243 @@
|
|||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "ordering_intro_md"
|
||||
},
|
||||
"source": [
|
||||
"# Ordering"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "ordering_desc_md"
|
||||
},
|
||||
"source": [
|
||||
"An `Ordering` specifies the order in which variables are eliminated during inference (e.g., Gaussian elimination, multifrontal QR). The choice of ordering significantly impacts the computational cost and fill-in (sparsity) of the resulting Bayes net or Bayes tree.\n",
|
||||
"\n",
|
||||
"GTSAM provides several algorithms to compute good orderings automatically (like COLAMD, METIS) or allows you to specify a custom ordering."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "ordering_colab_md"
|
||||
},
|
||||
"source": [
|
||||
"<a href=\"https://colab.research.google.com/github/borglab/gtsam/blob/develop/gtsam/inference/doc/Ordering.ipynb\" target=\"_parent\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"/></a>"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "ordering_pip_code",
|
||||
"tags": [
|
||||
"remove-cell"
|
||||
]
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"%pip install gtsam"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 15,
|
||||
"metadata": {
|
||||
"id": "ordering_import_code"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import gtsam\n",
|
||||
"from gtsam import Ordering, VariableIndex\n",
|
||||
"# Need a graph type for automatic ordering\n",
|
||||
"from gtsam import SymbolicFactorGraph\n",
|
||||
"from gtsam import symbol_shorthand\n",
|
||||
"\n",
|
||||
"X = symbol_shorthand.X\n",
|
||||
"L = symbol_shorthand.L"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "ordering_create_md"
|
||||
},
|
||||
"source": [
|
||||
"## Creating an Ordering\n",
|
||||
"\n",
|
||||
"Orderings can be created manually or computed automatically from a factor graph."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 16,
|
||||
"metadata": {
|
||||
"colab": {
|
||||
"base_uri": "https://localhost:8080/"
|
||||
},
|
||||
"id": "ordering_manual_code",
|
||||
"outputId": "6789abcd-ef01-2345-6789-abcdef012345"
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Manual Ordering: Position 0: x1, l1, x2, l2, x0\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# Manual creation (list of keys)\n",
|
||||
"manual_ordering = Ordering([X(1), L(1), X(2), L(2), X(0)])\n",
|
||||
"manual_ordering.print(\"Manual Ordering: \")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 18,
|
||||
"metadata": {
|
||||
"colab": {
|
||||
"base_uri": "https://localhost:8080/"
|
||||
},
|
||||
"id": "ordering_auto_code",
|
||||
"outputId": "789abcde-f012-3456-789a-bcdef0123456"
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"COLAMD Ordering: Position 0: l1, x0, x1, l2, x2\n",
|
||||
"Constrained COLAMD (x0, x2 last): Position 0: l2, l1, x1, x2, x0\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# Automatic creation requires a factor graph\n",
|
||||
"# Let's use a simple SymbolicFactorGraph for structure\n",
|
||||
"graph = SymbolicFactorGraph()\n",
|
||||
"graph.push_factor(X(0))\n",
|
||||
"graph.push_factor(X(0), X(1))\n",
|
||||
"graph.push_factor(X(1), X(2))\n",
|
||||
"graph.push_factor(X(0), L(1))\n",
|
||||
"graph.push_factor(X(1), L(1))\n",
|
||||
"graph.push_factor(X(1), L(2))\n",
|
||||
"graph.push_factor(X(2), L(2))\n",
|
||||
"\n",
|
||||
"# COLAMD (Column Approximate Minimum Degree) ordering\n",
|
||||
"colamd_ordering = Ordering.ColamdSymbolicFactorGraph(graph)\n",
|
||||
"colamd_ordering.print(\"COLAMD Ordering: \")\n",
|
||||
"\n",
|
||||
"# Constrained COLAMD (force x0 and x2 to be eliminated last)\n",
|
||||
"constrained_ordering = Ordering.ColamdConstrainedLastSymbolicFactorGraph(graph, gtsam.KeyVector([X(0), X(2)]))\n",
|
||||
"constrained_ordering.print(\"Constrained COLAMD (x0, x2 last): \")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "ordering_access_md"
|
||||
},
|
||||
"source": [
|
||||
"## Accessing Elements\n",
|
||||
"\n",
|
||||
"An `Ordering` behaves like a vector of keys."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 19,
|
||||
"metadata": {
|
||||
"colab": {
|
||||
"base_uri": "https://localhost:8080/"
|
||||
},
|
||||
"id": "ordering_access_code",
|
||||
"outputId": "89abcdef-0123-4567-89ab-cdef01234567"
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Ordering size: 5\n",
|
||||
"Key at position 0: l1\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"print(f\"Ordering size: {colamd_ordering.size()}\")\n",
|
||||
"\n",
|
||||
"# Access by index\n",
|
||||
"key_at_0 = colamd_ordering.at(0)\n",
|
||||
"print(f\"Key at position 0: {gtsam.DefaultKeyFormatter(key_at_0)}\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "ordering_append_md"
|
||||
},
|
||||
"source": [
|
||||
"## Appending Keys\n",
|
||||
"\n",
|
||||
"You can append keys using `push_back`."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 20,
|
||||
"metadata": {
|
||||
"colab": {
|
||||
"base_uri": "https://localhost:8080/"
|
||||
},
|
||||
"id": "ordering_append_code",
|
||||
"outputId": "9abcdef0-1234-5678-9abc-def012345678"
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Appended Ordering: Position 0: l1, x0, x1, l2, x2, l0, x3\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"appended_ordering = Ordering(colamd_ordering)\n",
|
||||
"appended_ordering.push_back(L(0))\n",
|
||||
"appended_ordering.push_back(X(3))\n",
|
||||
"\n",
|
||||
"appended_ordering.print(\"Appended Ordering: \")"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"colab": {
|
||||
"provenance": []
|
||||
},
|
||||
"kernelspec": {
|
||||
"display_name": "gtsam",
|
||||
"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.1"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 0
|
||||
}
|
|
@ -0,0 +1,212 @@
|
|||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "symbol_intro_md"
|
||||
},
|
||||
"source": [
|
||||
"# Symbol"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "symbol_desc_md"
|
||||
},
|
||||
"source": [
|
||||
"A `Symbol` is a GTSAM class used to create semantically meaningful keys (`gtsam.Key`) for variables. It combines a character (`unsigned char`) and an index (`uint64_t`) into a single 64-bit integer key. This allows for easy identification of variable types and their indices, e.g., 'x' for poses and 'l' for landmarks, like `x0`, `x1`, `l0`."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "symbol_colab_md"
|
||||
},
|
||||
"source": [
|
||||
"<a href=\"https://colab.research.google.com/github/borglab/gtsam/blob/develop/gtsam/inference/doc/Symbol.ipynb\" target=\"_parent\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"/></a>"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "symbol_pip_code",
|
||||
"tags": [
|
||||
"remove-cell"
|
||||
]
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"%pip install gtsam"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"metadata": {
|
||||
"id": "symbol_import_code"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import gtsam\n",
|
||||
"from gtsam import Symbol"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "symbol_init_md"
|
||||
},
|
||||
"source": [
|
||||
"## Initialization\n",
|
||||
"\n",
|
||||
"A `Symbol` can be created by providing a character and an index. It can also be created by decoding an existing `gtsam.Key` (integer)."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"metadata": {
|
||||
"colab": {
|
||||
"base_uri": "https://localhost:8080/"
|
||||
},
|
||||
"id": "symbol_create_code",
|
||||
"outputId": "c1d2e3f4-a5b6-7890-bcde-f12345678901"
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Symbol from char/index: x5\n",
|
||||
"Symbol from key 8646911284551352325: x5\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# Create Symbol 'x' with index 5\n",
|
||||
"sym1 = Symbol('x', 5)\n",
|
||||
"print(f\"Symbol from char/index: {sym1.string()}\")\n",
|
||||
"\n",
|
||||
"# Get the underlying integer key\n",
|
||||
"key1 = sym1.key()\n",
|
||||
"\n",
|
||||
"# Reconstruct Symbol from the key\n",
|
||||
"sym2 = Symbol(key1)\n",
|
||||
"print(f\"Symbol from key {key1}: {sym2.string()}\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "symbol_props_md"
|
||||
},
|
||||
"source": [
|
||||
"## Properties and Usage\n",
|
||||
"\n",
|
||||
"You can access the character, index, and underlying integer key."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"metadata": {
|
||||
"colab": {
|
||||
"base_uri": "https://localhost:8080/"
|
||||
},
|
||||
"id": "symbol_access_code",
|
||||
"outputId": "d2e3f4a5-b6c7-8901-cdef-123456789012"
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Symbol: l10\n",
|
||||
" Char: 108\n",
|
||||
" Index: 10\n",
|
||||
" Key: 7782220156096217098\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"landmark_sym = Symbol('l', 10)\n",
|
||||
"\n",
|
||||
"print(f\"Symbol: {landmark_sym.string()}\")\n",
|
||||
"print(f\" Char: {landmark_sym.chr()}\")\n",
|
||||
"print(f\" Index: {landmark_sym.index()}\")\n",
|
||||
"print(f\" Key: {landmark_sym.key()}\")\n",
|
||||
"\n",
|
||||
"# Symbols are often used directly where Keys are expected in GTSAM functions,\n",
|
||||
"# as they implicitly convert.\n",
|
||||
"# e.g., values.insert(landmark_sym, gtsam.Point3(1,2,3))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "symbol_shorthand_md"
|
||||
},
|
||||
"source": [
|
||||
"## Shorthand Functions\n",
|
||||
"\n",
|
||||
"GTSAM provides convenient shorthand functions `gtsam.symbol_shorthand.X(j)`, `gtsam.symbol_shorthand.L(j)`, etc., which are equivalent to `gtsam.Symbol('x', j)`, `gtsam.Symbol('l', j)`."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 4,
|
||||
"metadata": {
|
||||
"colab": {
|
||||
"base_uri": "https://localhost:8080/"
|
||||
},
|
||||
"id": "symbol_shorthand_code",
|
||||
"outputId": "e3f4a5b6-c7d8-9012-def0-234567890123"
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Symbol('x', 0).key() == gtsam.symbol_shorthand.X(0): True\n",
|
||||
"Symbol('l', 1).key() == gtsam.symbol_shorthand.L(1): True\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"from gtsam import symbol_shorthand\n",
|
||||
"\n",
|
||||
"x0_key = symbol_shorthand.X(0)\n",
|
||||
"l1_key = symbol_shorthand.L(1)\n",
|
||||
"\n",
|
||||
"print(f\"Symbol('x', 0).key() == gtsam.symbol_shorthand.X(0): {Symbol('x', 0).key() == x0_key}\")\n",
|
||||
"print(f\"Symbol('l', 1).key() == gtsam.symbol_shorthand.L(1): {Symbol('l', 1).key() == l1_key}\")"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"colab": {
|
||||
"provenance": []
|
||||
},
|
||||
"kernelspec": {
|
||||
"display_name": "gtsam",
|
||||
"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.1"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 0
|
||||
}
|
|
@ -0,0 +1,226 @@
|
|||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "vindex_intro_md"
|
||||
},
|
||||
"source": [
|
||||
"# VariableIndex"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "vindex_desc_md"
|
||||
},
|
||||
"source": [
|
||||
"A `VariableIndex` provides an efficient way to look up which factors in a `FactorGraph` involve a particular variable (Key). It stores, for each variable, a list of the indices of the factors that include that variable.\n",
|
||||
"\n",
|
||||
"This structure is often computed internally by GTSAM algorithms (like ordering methods or elimination) but can also be created explicitly if needed, for example, to improve performance when multiple operations need this information."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "vindex_colab_md"
|
||||
},
|
||||
"source": [
|
||||
"<a href=\"https://colab.research.google.com/github/borglab/gtsam/blob/develop/gtsam/inference/doc/VariableIndex.ipynb\" target=\"_parent\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"/></a>"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "vindex_pip_code",
|
||||
"tags": [
|
||||
"remove-cell"
|
||||
]
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"%pip install gtsam-develop"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"metadata": {
|
||||
"id": "vindex_import_code"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import gtsam\n",
|
||||
"from gtsam import VariableIndex, Ordering\n",
|
||||
"# Need a graph type for creation\n",
|
||||
"from gtsam import SymbolicFactorGraph\n",
|
||||
"from gtsam import symbol_shorthand\n",
|
||||
"\n",
|
||||
"X = symbol_shorthand.X\n",
|
||||
"L = symbol_shorthand.L"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "vindex_create_md"
|
||||
},
|
||||
"source": [
|
||||
"## Creating a VariableIndex\n",
|
||||
"\n",
|
||||
"A `VariableIndex` is typically created from an existing `FactorGraph`."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"metadata": {
|
||||
"colab": {
|
||||
"base_uri": "https://localhost:8080/"
|
||||
},
|
||||
"id": "vindex_create_code",
|
||||
"outputId": "abcdef01-2345-6789-abcd-ef0123456789"
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"VariableIndex: nEntries = 13, nFactors = 7\n",
|
||||
"var l1: 3 4\n",
|
||||
"var l2: 5 6\n",
|
||||
"var x0: 0 1 3\n",
|
||||
"var x1: 1 2 4 5\n",
|
||||
"var x2: 2 6\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# Create a simple SymbolicFactorGraph\n",
|
||||
"graph = SymbolicFactorGraph()\n",
|
||||
"graph.push_factor(X(0)) # Factor 0\n",
|
||||
"graph.push_factor(X(0), X(1)) # Factor 1\n",
|
||||
"graph.push_factor(X(1), X(2)) # Factor 2\n",
|
||||
"graph.push_factor(X(0), L(1)) # Factor 3\n",
|
||||
"graph.push_factor(X(1), L(1)) # Factor 4\n",
|
||||
"graph.push_factor(X(1), L(2)) # Factor 5\n",
|
||||
"graph.push_factor(X(2), L(2)) # Factor 6\n",
|
||||
"\n",
|
||||
"# Create VariableIndex from the graph\n",
|
||||
"variable_index = VariableIndex(graph)\n",
|
||||
"\n",
|
||||
"# Print the index\n",
|
||||
"variable_index.print(\"VariableIndex: \")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "vindex_access_md"
|
||||
},
|
||||
"source": [
|
||||
"## Accessing Information\n",
|
||||
"\n",
|
||||
"You can query the number of variables, factors, and entries, and look up the factors associated with a specific variable."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 5,
|
||||
"metadata": {
|
||||
"colab": {
|
||||
"base_uri": "https://localhost:8080/"
|
||||
},
|
||||
"id": "vindex_access_code",
|
||||
"outputId": "bcdef012-3456-789a-bcde-f0123456789a"
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Number of variables (size): 5\n",
|
||||
"Number of factors (nFactors): 7\n",
|
||||
"Number of variable-factor entries (nEntries): 13\n",
|
||||
"Factors involving x1: [1, 2, 4, 5]\n",
|
||||
"Factors involving l1: [3, 4]\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"print(f\"Number of variables (size): {variable_index.size()}\")\n",
|
||||
"print(f\"Number of factors (nFactors): {variable_index.nFactors()}\")\n",
|
||||
"print(f\"Number of variable-factor entries (nEntries): {variable_index.nEntries()}\")\n",
|
||||
"\n",
|
||||
"# Get factors involving a specific variable\n",
|
||||
"factors_x1 = variable_index.at(X(1)) # Returns a FactorIndices (FastVector<size_t>)\n",
|
||||
"print(f\"Factors involving x1: {factors_x1}\")\n",
|
||||
"\n",
|
||||
"# Use key directly\n",
|
||||
"factors_l1 = variable_index.at(L(1))\n",
|
||||
"print(f\"Factors involving l1: {factors_l1}\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "vindex_use_md"
|
||||
},
|
||||
"source": [
|
||||
"## Usage in Algorithms\n",
|
||||
"\n",
|
||||
"`VariableIndex` is primarily used as input to other algorithms, particularly ordering methods like `Ordering.Colamd`."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 6,
|
||||
"metadata": {
|
||||
"colab": {
|
||||
"base_uri": "https://localhost:8080/"
|
||||
},
|
||||
"id": "vindex_use_code",
|
||||
"outputId": "cdef0123-4567-89ab-cdef-0123456789ab"
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"COLAMD Ordering from VariableIndex: Position 0: l1, x0, x1, l2, x2\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# Compute COLAMD ordering directly from the VariableIndex\n",
|
||||
"colamd_ordering = Ordering.Colamd(variable_index)\n",
|
||||
"colamd_ordering.print(\"COLAMD Ordering from VariableIndex: \")"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"colab": {
|
||||
"provenance": []
|
||||
},
|
||||
"kernelspec": {
|
||||
"display_name": "gtsam",
|
||||
"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.1"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 0
|
||||
}
|
|
@ -122,6 +122,7 @@ class Ordering {
|
|||
template <
|
||||
FACTOR_GRAPH = {gtsam::NonlinearFactorGraph, gtsam::DiscreteFactorGraph,
|
||||
gtsam::SymbolicFactorGraph, gtsam::GaussianFactorGraph, gtsam::HybridGaussianFactorGraph}>
|
||||
|
||||
static gtsam::Ordering Colamd(const FACTOR_GRAPH& graph);
|
||||
static gtsam::Ordering Colamd(const gtsam::VariableIndex& variableIndex);
|
||||
|
||||
|
@ -196,6 +197,9 @@ class VariableIndex {
|
|||
VariableIndex(const T& factorGraph);
|
||||
VariableIndex(const gtsam::VariableIndex& other);
|
||||
|
||||
gtsam::FactorIndices& at(gtsam::Key variable) const;
|
||||
bool empty(gtsam::Key variable) const;
|
||||
|
||||
// Testable
|
||||
bool equals(const gtsam::VariableIndex& other, double tol) const;
|
||||
void print(string s = "VariableIndex: ",
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
# Inference
|
||||
|
||||
The `inference` module provides the foundational classes and algorithms for probabilistic graphical models in GTSAM, focusing on variable elimination and the resulting structures like Bayes Nets and Bayes Trees.
|
||||
|
||||
## Core Concepts
|
||||
|
||||
- [Key](doc/Key.ipynb): Base type (`uint64_t`) for uniquely identifying variables.
|
||||
- [Symbol](doc/Symbol.ipynb): A Key type encoding a character and an index (e.g., `x0`).
|
||||
- [LabeledSymbol](doc/LabeledSymbol.ipynb): A `Symbol` variant with an additional label character, useful for multi-robot scenarios (e.g., `xA0`).
|
||||
- [EdgeKey](doc/EdgeKey.ipynb): A Key type encoding a pair of 32-bit integers.
|
||||
- [Factor](doc/Factor.ipynb): Abstract base class for all factors (relationships between variables).
|
||||
- [FactorGraph](doc/FactorGraph.ipynb): Base class representing a collection of factors.
|
||||
- [Conditional](doc/Conditional.ipynb): Abstract base class for conditional distributions/densities resulting from elimination ( $P(\text{Frontals} | \text{Parents})$ ).
|
||||
|
||||
## Elimination Algorithms & Control
|
||||
|
||||
- [Ordering](doc/Ordering.ipynb): Specifies the order in which variables are eliminated, crucial for efficiency.
|
||||
- [VariableIndex](doc/VariableIndex.ipynb): Maps variables to the factors they appear in, used for efficient elimination ordering and construction.
|
||||
- [EliminateableFactorGraph](https://github.com/borglab/gtsam/blob/develop/gtsam/inference/EliminateableFactorGraph.h): A mixin class providing `eliminateSequential` and `eliminateMultifrontal` methods to concrete factor graph types (like `GaussianFactorGraph`, `SymbolicFactorGraph`).
|
||||
|
||||
## Elimination Results & Structures
|
||||
|
||||
- [BayesNet](doc/BayesNet.ipynb): Represents the result of sequential variable elimination as a directed acyclic graph (DAG) of conditionals.
|
||||
- [EliminationTree](doc/EliminationTree.ipynb): Tree structure representing the dependencies and computations during sequential elimination.
|
||||
- [ClusterTree](doc/ClusterTree.ipynb): Base class for tree structures where nodes are clusters of factors (e.g., JunctionTree).
|
||||
- [JunctionTree](doc/JunctionTree.ipynb): A cluster tree representing the cliques formed during multifrontal elimination, holding the factors before they are eliminated into conditionals.
|
||||
- [BayesTreeCliqueBase](https://github.com/borglab/gtsam/blob/develop/gtsam/inference/BayesTreeCliqueBase.h): Abstract base class for the nodes (cliques) within a BayesTree.
|
||||
- [BayesTree](doc/BayesTree.ipynb): Represents the result of multifrontal variable elimination as a tree of cliques, where each clique contains the conditional $P(\text{Frontals} | \text{Separator})$.
|
||||
|
||||
## Incremental Inference
|
||||
|
||||
- [ISAM](doc/ISAM.ipynb): Incremental Smoothing and Mapping algorithm based on updating a BayesTree (original version, often superseded by ISAM2 in `nonlinear`).
|
||||
|
||||
## Visualization
|
||||
|
||||
- [DotWriter](doc/DotWriter.ipynb): Helper class to customize the generation of Graphviz `.dot` files for visualizing graphs and trees.
|
|
@ -687,15 +687,37 @@ virtual class GaussianBayesTree {
|
|||
gtsam::GaussianBayesNet* jointBayesNet(size_t key1, size_t key2) const;
|
||||
};
|
||||
|
||||
#include <gtsam/linear/GaussianEliminationTree.h>
|
||||
virtual class GaussianEliminationTree {
|
||||
GaussianEliminationTree(const gtsam::GaussianFactorGraph& factorGraph,
|
||||
const gtsam::VariableIndex& structure, const gtsam::Ordering& order);
|
||||
GaussianEliminationTree(const gtsam::GaussianFactorGraph& factorGraph,
|
||||
const gtsam::Ordering& order);
|
||||
|
||||
bool equals(const This& other, double tol) const;
|
||||
|
||||
void print(const string name = "GaussianEliminationTree: ",
|
||||
const gtsam::KeyFormatter& formatter = gtsam::DefaultKeyFormatter) const;
|
||||
};
|
||||
|
||||
#include <gtsam/linear/GaussianISAM.h>
|
||||
class GaussianISAM {
|
||||
//Constructor
|
||||
GaussianISAM();
|
||||
GaussianISAM(const gtsam::GaussianBayesTree& bayesTree);
|
||||
|
||||
gtsam::VectorValues optimize() const;
|
||||
gtsam::VectorValues optimizeGradientSearch() const;
|
||||
|
||||
gtsam::GaussianConditional* marginalFactor(size_t key) const;
|
||||
|
||||
//Standard Interface
|
||||
void update(const gtsam::GaussianFactorGraph& newFactors);
|
||||
void saveGraph(string s) const;
|
||||
void clear();
|
||||
|
||||
void print(const string name = "GaussianISAM: ",
|
||||
const gtsam::KeyFormatter& formatter = gtsam::DefaultKeyFormatter) const;
|
||||
};
|
||||
|
||||
#include <gtsam/linear/IterativeSolver.h>
|
||||
|
|
3
myst.yml
3
myst.yml
|
@ -13,6 +13,9 @@ project:
|
|||
- file: ./gtsam/geometry/geometry.md
|
||||
children:
|
||||
- pattern: ./gtsam/geometry/doc/*
|
||||
- file: ./gtsam/inference/inference.md
|
||||
children:
|
||||
- pattern: ./gtsam/inference/doc/*
|
||||
- file: ./gtsam/nonlinear/nonlinear.md
|
||||
children:
|
||||
- pattern: ./gtsam/nonlinear/doc/*
|
||||
|
|
|
@ -43,8 +43,7 @@
|
|||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# This needs gtbook:\n",
|
||||
"% pip install --quiet gtbook"
|
||||
"%pip install --quiet gtsam-develop"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -201,3 +201,5 @@ public:
|
|||
private:
|
||||
T *m_ptr;
|
||||
};
|
||||
|
||||
#endif /* __OBJECT_H */
|
||||
|
|
Loading…
Reference in New Issue