A TableFactor is an alternative to a DecisionTreeFactor, using a sparse matrix to represent factors with many zeros. It stores a discrete potential indexed by an ordered sequence of discrete keys and supports efficient lookup of the stored entries.
import gtsam
import numpy as np
from gtsam.symbol_shorthand import M, X
from IPython.display import Markdown, displayConstructing a table¶
The order of DiscreteKeys determines how the flat value sequence maps to assignments. The example has two binary variables and therefore four table entries.
A = (gtsam.symbol("A", 0), 2)
B = (gtsam.symbol("B", 0), 2)
keys = gtsam.DiscreteKeys()
keys.push_back(A)
keys.push_back(B)
factor = gtsam.TableFactor(keys, [0.1, 0.9, 0.8, 0.2])
factor.print("Dense potential")Lookup and error¶
evaluate(values) returns the stored potential. error(values) returns its negative logarithm, the additive objective used by discrete optimization. keys(), size(), and empty() inspect the factor scope.
values = gtsam.DiscreteValues()
values[A[0]] = 0
values[B[0]] = 1
potential = factor.evaluate(values)
error = factor.error(values)
print("potential:", potential)
print("error:", error)
assert np.isclose(potential, 0.9)
assert np.isclose(error, -np.log(0.9))Converting from a decision tree¶
Constructing from DecisionTreeFactor preserves the potential while changing its storage. This is useful after symbolic operations have created a compact tree but a dense downstream calculation is preferred.
tree_factor = gtsam.DecisionTreeFactor([A, B], "1 0 0 2")
dense_factor = gtsam.TableFactor(tree_factor)
for assignment, expected in tree_factor.enumerate():
assert np.isclose(dense_factor.evaluate(assignment), expected)
print("all four table entries preserved")