Added simple matrix-math eliminate and shortcut functions, and a simple matrix-math test of the feasibility of correcting root shortcut joint marginals.
parent
c3f38349b4
commit
00b12c7dc1
|
@ -0,0 +1,45 @@
|
|||
function [ RS, J ] = eliminate(Ab, js)
|
||||
%ELIMINATE This is a simple scalar-level function for eliminating the
|
||||
%matrix Ab into a conditional part RS and a marginal part J. The scalars
|
||||
%in js are the ones eliminated (corresponding to columns of Ab). Note that
|
||||
%the returned matrices RS and J will both be the same width as Ab and will
|
||||
%contain columns of all zeros - that is, the column indices will stay the
|
||||
%same in all matrices, unlike in GTSAM where matrix data is only stored for
|
||||
%involved variables.
|
||||
|
||||
if size(Ab,1) < size(Ab,2)-1
|
||||
Ab = [ Ab; zeros(size(Ab,2)-1-size(Ab,1), size(Ab,2)) ];
|
||||
end
|
||||
|
||||
% Permute columns
|
||||
origCols = 1:size(Ab,2);
|
||||
jsFront = js;
|
||||
jsBack = setdiff(origCols, js);
|
||||
jsPermuted = [ jsFront jsBack ];
|
||||
Abpermuted = Ab(:,jsPermuted);
|
||||
|
||||
% Eliminate (this sparse stuff prevents qr from introducing a permutation
|
||||
R = full(qr(sparse(Abpermuted)));
|
||||
|
||||
% Find row split
|
||||
firstRowOfMarginal = numel(jsFront) + 1;
|
||||
for i = size(R,1) : -1 : 1
|
||||
firstNnz = find(R(i,:), 1, 'first');
|
||||
if ~isempty(firstNnz)
|
||||
if firstNnz > numel(jsFront)
|
||||
firstRowOfMarginal = i;
|
||||
else
|
||||
break;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
% Undo permutation
|
||||
Runpermuted(:,jsPermuted) = R;
|
||||
|
||||
% Split up
|
||||
RS = Runpermuted(1:firstRowOfMarginal-1, :);
|
||||
J = Runpermuted(firstRowOfMarginal:size(Ab,2)-1, :);
|
||||
|
||||
end
|
||||
|
|
@ -0,0 +1,76 @@
|
|||
% This script tests the math of correcting joint marginals with root
|
||||
% shortcuts, using only simple matrix math and avoiding any GTSAM calls.
|
||||
% It turns out that it is not possible to correct root shortcuts for
|
||||
% joinoint marginals, thus actual_ij_1_2__ will not equal
|
||||
% expected_ij_1_2__.
|
||||
|
||||
%% Check that we get the BayesTree structure we are expecting
|
||||
fg = gtsam.SymbolicFactorGraph;
|
||||
fg.push_factor(1,3,7,10);
|
||||
fg.push_factor(2,5,7,10);
|
||||
fg.push_factor(3,4,7,8);
|
||||
fg.push_factor(5,6,7,8);
|
||||
fg.push_factor(7,8,9,10);
|
||||
fg.push_factor(10,11);
|
||||
fg.push_factor(11);
|
||||
fg.push_factor(7,8,9);
|
||||
fg.push_factor(7,8);
|
||||
fg.push_factor(5,6);
|
||||
fg.push_factor(3,4);
|
||||
|
||||
bt = gtsam.SymbolicMultifrontalSolver(fg).eliminate;
|
||||
bt
|
||||
|
||||
%%
|
||||
% P( 10 11)
|
||||
% P( 7 8 9 | 10)
|
||||
% P( 5 6 | 7 8 10)
|
||||
% P( 2 | 5 7 10)
|
||||
% P( 3 4 | 7 8 10)
|
||||
% P( 1 | 3 7 10)
|
||||
A = [ ...
|
||||
% 1 2 3 4 5 6 7 8 9 10 11 b
|
||||
1 0 2 0 0 0 3 0 0 4 0 5
|
||||
0 6 0 0 7 0 8 0 0 9 0 10
|
||||
0 0 11 12 0 0 13 14 0 15 0 16
|
||||
0 0 0 0 17 18 19 20 0 21 0 22
|
||||
0 0 0 0 0 0 23 24 25 26 0 27
|
||||
0 0 0 0 0 0 0 0 0 28 29 30
|
||||
0 0 0 0 0 0 0 0 0 0 31 32
|
||||
0 0 0 0 0 0 33 34 35 0 0 36
|
||||
0 0 0 0 0 0 37 38 0 0 0 39
|
||||
0 0 0 0 40 41 0 0 0 0 0 42
|
||||
0 0 43 44 0 0 0 0 0 0 0 45
|
||||
%0 0 0 0 46 0 0 0 0 0 0 47
|
||||
%0 0 48 0 0 0 0 0 0 0 0 49
|
||||
];
|
||||
|
||||
% Compute shortcuts
|
||||
shortcut3_7__10_11 = shortcut(A, [3,7], [10,11]);
|
||||
shortcut5_7__10_11 = shortcut(A, [5,7], [10,11]);
|
||||
|
||||
% Factor into pieces
|
||||
% Factor p(5,7|10,11) into p(5|7,10,11) p(7|10,11)
|
||||
[ si_si__sij_R, si_sij__R ] = eliminate(shortcut3_7__10_11, [3]);
|
||||
[ sj_sj__sij_R, sj_sij__R ] = eliminate(shortcut5_7__10_11, [5]);
|
||||
|
||||
% Get root marginal
|
||||
R__ = A([6,7], :);
|
||||
|
||||
% Get clique conditionals
|
||||
i_1__3_7_10 = A(1, :);
|
||||
j_2__5_7_10 = A(2, :);
|
||||
|
||||
% Check
|
||||
expected_ij_1_2__ = shortcut(A, [1,2], [])
|
||||
|
||||
% Compute joint
|
||||
ij_1_2_3_5_7_10_11 = [
|
||||
i_1__3_7_10
|
||||
j_2__5_7_10
|
||||
si_si__sij_R
|
||||
sj_sj__sij_R
|
||||
si_sij__R
|
||||
R__
|
||||
];
|
||||
actual_ij_1_2__ = shortcut(ij_1_2_3_5_7_10_11, [1,2], [])
|
|
@ -0,0 +1,20 @@
|
|||
function R = shortcut(Ab, frontals, separators)
|
||||
%SHORTCUT This is a simple scalar-level function for computing a "shortcut"
|
||||
%of frontals conditioned on separators. Note that the input matrix Ab is
|
||||
%assumed to have a RHS vector in its right-most column, thus this rightmost
|
||||
%column index should not be listed in either frontals or separators. This
|
||||
%function computes p(frontals | separators), marginalizing out all other
|
||||
%variables (cooresponding to columns) in Ab.
|
||||
|
||||
% First marginalize out all others
|
||||
cols = 1:size(Ab,2)-1;
|
||||
toMarginalizeOut = setdiff(cols, [ frontals separators ]);
|
||||
[ cond marg ] = eliminate(Ab, toMarginalizeOut);
|
||||
|
||||
% Now eliminate the frontals to get the conditional
|
||||
[ cond marg ] = eliminate(marg, frontals);
|
||||
|
||||
R = cond;
|
||||
|
||||
end
|
||||
|
Loading…
Reference in New Issue